about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2015-01-08 21:04:04 +0000
committerEric Wong <e@80x24.org>2015-01-08 23:51:37 +0000
commit4ffa14b8d8aa58276ffcf4ed839a6f4c6c1c836d (patch)
tree75701bb9e27147deee1b644c154547f89e1f2ea5
downloadolddoc-4ffa14b8d8aa58276ffcf4ed839a6f4c6c1c836d.tar.gz
Template based on Darkfish, but heavily stripped down.
-rw-r--r--.document4
-rw-r--r--.gitignore17
-rw-r--r--.olddoc.yml9
-rw-r--r--COPYING674
-rw-r--r--Documentation/.gitignore4
-rw-r--r--Documentation/GNUmakefile53
-rw-r--r--Documentation/olddoc.1.txt21
-rw-r--r--Documentation/olddoc.5.txt26
-rw-r--r--GNUmakefile59
-rw-r--r--INSTALL9
-rw-r--r--README89
-rw-r--r--Rakefile30
-rw-r--r--TODO1
-rwxr-xr-xbin/olddoc16
-rw-r--r--lib/olddoc.rb21
-rw-r--r--lib/olddoc/changelog.rb28
-rw-r--r--lib/olddoc/gemspec.rb17
-rw-r--r--lib/olddoc/history.rb57
-rw-r--r--lib/olddoc/merge.rb26
-rw-r--r--lib/olddoc/news_atom.rb51
-rw-r--r--lib/olddoc/news_rdoc.rb36
-rw-r--r--lib/olddoc/prepare.rb27
-rw-r--r--lib/olddoc/readme.rb27
-rw-r--r--lib/oldweb.rb303
-rw-r--r--lib/oldweb/_head.rhtml7
-rw-r--r--lib/oldweb/_sidebar_classes.rhtml27
-rw-r--r--lib/oldweb/_sidebar_extends.rhtml13
-rw-r--r--lib/oldweb/_sidebar_includes.rhtml12
-rw-r--r--lib/oldweb/_sidebar_installed.rhtml10
-rw-r--r--lib/oldweb/_sidebar_methods.rhtml6
-rw-r--r--lib/oldweb/_sidebar_navigation.rhtml6
-rw-r--r--lib/oldweb/_sidebar_pages.rhtml17
-rw-r--r--lib/oldweb/_sidebar_parent.rhtml13
-rw-r--r--lib/oldweb/_sidebar_sections.rhtml8
-rw-r--r--lib/oldweb/_sidebar_table_of_contents.rhtml15
-rw-r--r--lib/oldweb/_tail.rhtml25
-rw-r--r--lib/oldweb/class.rhtml79
-rw-r--r--lib/oldweb/page.rhtml5
-rw-r--r--lib/oldweb/servlet_not_found.rhtml5
-rw-r--r--lib/oldweb/servlet_root.rhtml39
-rw-r--r--lib/oldweb/table_of_contents.rhtml52
-rw-r--r--lib/rdoc/discover.rb5
-rw-r--r--olddoc.gemspec21
43 files changed, 1970 insertions, 0 deletions
diff --git a/.document b/.document
new file mode 100644
index 0000000..f96be54
--- /dev/null
+++ b/.document
@@ -0,0 +1,4 @@
+NEWS
+README
+olddoc_1
+olddoc_5
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cce615b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+/GIT-VERSION-FILE
+ChangeLog
+olddoc_1
+olddoc_5
+LATEST
+/NEWS
+/NEWS.atom.xml
+/pkg
+*.tar.gz
+*.log
+/man
+*.gem
+*.gz
+.manifest
+.gem-manifest
+.tgz-manifest
+/doc
diff --git a/.olddoc.yml b/.olddoc.yml
new file mode 100644
index 0000000..0b37154
--- /dev/null
+++ b/.olddoc.yml
@@ -0,0 +1,9 @@
+---
+cgit_url: http://bogomips.org/olddoc.git
+git_url: git://80x24.org/olddoc.git
+rdoc_url: http://80x24.org/olddoc/
+merge_html:
+  olddoc_1: Documentation/olddoc.1.html
+  olddoc_5: Documentation/olddoc.5.html
+public_email: olddoc-public@80x24.org
+private_email: olddoc@80x24.org
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  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.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  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.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     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
+state 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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU 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 Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
new file mode 100644
index 0000000..c618f1a
--- /dev/null
+++ b/Documentation/.gitignore
@@ -0,0 +1,4 @@
+*.html_fragment
+*.1
+*.5
+*.html
diff --git a/Documentation/GNUmakefile b/Documentation/GNUmakefile
new file mode 100644
index 0000000..5e47833
--- /dev/null
+++ b/Documentation/GNUmakefile
@@ -0,0 +1,53 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+all::
+
+INSTALL = install
+PANDOC = pandoc
+PANDOC_OPTS = -f markdown --email-obfuscation=none
+pandoc = $(PANDOC) $(PANDOC_OPTS)
+pandoc_html = $(pandoc) --toc -t html --no-wrap
+
+
+man1 := olddoc.1
+man5 := olddoc.5
+man7 :=
+
+html1 := $(addsuffix .html, $(man1))
+html5 := $(addsuffix .html, $(man5))
+html7 := $(addsuffix .html, $(man7))
+
+all:: man
+
+man: $(man1) $(man5) $(man7)
+html: $(html1) $(html5) $(html7)
+
+prefix ?= $(HOME)
+mandir ?= $(prefix)/share/man
+man1dir = $(mandir)/man1
+man5dir = $(mandir)/man5
+man7dir = $(mandir)/man7
+
+gem-man: man
+        $(INSTALL) -d -m 755 ../man
+        test -z "$(man1)" || $(INSTALL) -m 644 $(man1) ../man
+        test -z "$(man5)" || $(INSTALL) -m 644 $(man5) ../man
+        test -z "$(man7)" || $(INSTALL) -m 644 $(man7) ../man
+
+install-man: man
+        $(INSTALL) -d -m 755 $(DESTDIR)$(mandir)
+        test -z "$(man1)" || $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
+        test -z "$(man5)" || $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir)
+        test -z "$(man7)" || $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
+        test -z "$(man1)" || $(INSTALL) -m 644 $(man1) $(DESTDIR)$(man1dir)
+        test -z "$(man5)" || $(INSTALL) -m 644 $(man5) $(DESTDIR)$(man5dir)
+        test -z "$(man7)" || $(INSTALL) -m 644 $(man7) $(DESTDIR)$(man7dir)
+
+%: %.txt
+        $(pandoc) -s -t man < $< > $@+ && mv $@+ $@
+
+%.html : %.txt
+        $(pandoc_html) < $< > $@+ && mv $@+ $@
+
+clean::
+        $(RM) $(man1) $(man5) $(man7) $(html1) $(html5) $(html7)
diff --git a/Documentation/olddoc.1.txt b/Documentation/olddoc.1.txt
new file mode 100644
index 0000000..e7b31d8
--- /dev/null
+++ b/Documentation/olddoc.1.txt
@@ -0,0 +1,21 @@
+% olddoc(1) olddoc user manual
+
+# NAME
+
+olddoc - old-fashioned RDoc HTML generator
+
+# SYNOPSIS
+
+`olddoc` prepare
+
+`rdoc` -f oldweb
+
+# DESCRIPTION
+
+olddoc features oldweb, and old-fashioned RDoc HTML generator.
+You can also use "olddoc prepare" to generate NEWS files from
+git tags and ChangeLog entries from "git log".
+
+# SEE ALSO
+
+olddoc(5)
diff --git a/Documentation/olddoc.5.txt b/Documentation/olddoc.5.txt
new file mode 100644
index 0000000..0b95578
--- /dev/null
+++ b/Documentation/olddoc.5.txt
@@ -0,0 +1,26 @@
+% olddoc(1) olddoc user manual
+
+# NAME
+
+.olddoc.yml - olddoc config file format
+
+# SYNOPSIS
+
+A YAML file in the top-level project directory named ".olddoc.yml"
+
+# DESCRIPTION
+
+As olddoc favors consistency over configuration, there is minimal
+configuration to deal with.
+
+# KEYS
+
+`rdoc_url`, `cgit_url` should be obvious
+
+`merge_html` is a key-value mapping of (empty) RDoc source files to an
+HTML file that will be merged into RDoc after-the-fact.  It is useful
+for merging non-RDoc generated HTML into the project.
+
+# SEE ALSO
+
+olddoc(1)
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 0000000..b6007d8
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,59 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+all::
+pkg = olddoc
+RUBY = ruby
+VERSION := $(shell $(RUBY) -Ilib -rolddoc -e 'puts Olddoc::VERSION')
+
+check-warnings:
+        @(for i in $$(git ls-files '*.rb'| grep -v '^setup\.rb$$'); \
+          do $(RUBY) -d -W2 -c $$i; done) | grep -v '^Syntax OK$$' || :
+
+pkggem := pkg/$(pkg)-$(VERSION).gem
+fix-perms:
+        git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
+        git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
+gem-man:
+        $(MAKE) -C Documentation/ gem-man
+
+pkg_extra := NEWS ChangeLog
+
+.manifest: fix-perms
+        $(RUBY) -I lib bin/olddoc prepare
+        rm -rf man
+        (git ls-files; \
+         for i in $(pkg_extra); do echo $$i; done) | \
+         LC_ALL=C sort > $@+
+        cmp $@+ $@ || mv $@+ $@; rm -f $@+
+
+placeholders := olddoc_5 olddoc_1
+
+$(placeholders):
+        echo olddoc_placeholder > $@
+
+.gem-manifest: .manifest gem-man $(placeholders)
+        (ls man/*.?; cat .manifest) | LC_ALL=C sort > $@+
+        cmp $@+ $@ || mv $@+ $@; rm -f $@+
+
+doc: $(placeholders)
+        $(MAKE) -C Documentation html
+        rm -rf doc
+        olddoc prepare
+        rdoc --debug -f oldweb
+        olddoc merge
+        ln NEWS.atom.xml doc/
+
+gem: $(pkggem)
+
+install-gem: $(pkggem)
+        gem install $(CURDIR)/$<
+
+$(pkggem): fix-perms .gem-manifest
+        VERSION=$(VERSION) gem build $(pkg).gemspec
+        mkdir -p pkg
+        mv $(@F) $@
+
+package: $(pkggem)
+
+.PHONY: all .FORCE-GIT-VERSION-FILE NEWS ChangeLog
+.PHONY: check-warnings fix-perms doc
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..c864693
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,9 @@
+= olddoc installation
+
+olddoc requires Ruby 1.9.3 (or later) and rdoc 4.2 or later to install.
+Once you have Ruby installed, installation via RubyGems should take care
+of the dependency for you:
+
+        gem install olddoc
+
+See README for usage instructions.
diff --git a/README b/README
new file mode 100644
index 0000000..3faff28
--- /dev/null
+++ b/README
@@ -0,0 +1,89 @@
+= olddoc - old-fashioned Ruby documentation generator
+
+olddoc contains old-fashioned document generators for those who do not
+wish to impose bloated, new-fangled web cruft on their readers.
+
+olddoc contains oldweb, an HTML generator without any images, frames,
+CSS, or JavaScript.  It is designed for users of text-based browsers
+and/or low-bandwidth connections.  oldweb focuses on text as it is
+the lowest common denominator for accessibility and compatibility
+with people and hardware.
+
+== Reasons
+
+* No CSS.  Encouraging users to use CSS leads to problems like
+  copy-paste hijacking: http://thejh.net/misc/website-terminal-copy-paste
+  External CSS also increases page load time as it often blocks page
+  rendering.  Asynchronous loading of CSS also causes accessibility
+  problems as links/buttons may move as a user attempts to click.
+
+* No JavaScript.  There is a constant barrage of security and
+  client-side performance problems associated with it.  It's also
+  unreasonable to expect users to rely on LibreJS and inspect every
+  piece of JS they run.
+
+* No frames.  Frames are an accessibility hassle and unfriendly
+  to users of tiny screens on mobile devices and text-based browsers.
+
+* No images.  Not everyone can view or afford bandwidth to load images.
+  This also reduces the potential for security vulnerabilities as less
+  code gets run.  Furthermore, loading the wrong image in a public
+  place can get you arrested (or worse).
+
+Encourage readers to simplify and speed up their browsing experience.
+They can disable CSS, JavaScript, and images in their browser without
+missing out!
+
+== Usage
+
+        gem install olddoc
+        cd $ANY_RDOC_USING_RUBY_PROJECT
+        rdoc -f oldweb
+
+You can also use olddoc to generate NEWS and ChangeLog entries
+assuming you have a README file and .olddoc.yml
+
+        olddoc prepare
+
+And "olddoc merge" to merge instances of "olddoc_placeholder" in
+an HTML file with HTML fragments generated with other tools
+such as pandoc(1).  This requries an appropriately configured
+.olddoc.yml with a "merge_html" section see olddoc(5)
+
+== Source code
+
+        git clone git://80x24.org/olddoc
+
+Please use git-format-patch(1) and git-send-email(1) distributed with
+the git(7) suite for generating and sending patches.  Please format
+pull requests with the git-request-pull(1) script (also distributed
+with git(7)) and send them via email to <olddoc-public@80x24.org>
+
+== Contact
+
+All feedback (comments, results, feature requests, bug reports, patches,
+pull-requests) via plain-text mail to the mailing list is very much
+appreciated.
+
+Please send plain-text mail to the list at <olddoc-public@80x24.org>
+HTML will not be read.  olddoc is for GUI-phobes, by GUI-phobes.
+Mailing list archives available at http://80x24.org/olddoc-public/
+No subscription is necessary to post to the mailing list.
+
+== License
+
+olddoc is copyrighted Free Software by all contributors, see logs
+in revision control for names and email addresses of all of them.
+
+olddoc 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 3 of the License, or (at your
+option) any later version.
+
+olddoc 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, see https://www.gnu.org/licenses/gpl-3.0.txt
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..ad483bd
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,30 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+require 'tempfile'
+include Rake::DSL
+task :rsync_docs do
+  dest = ENV["RSYNC_DEST"] || "80x24.org:/srv/80x24/olddoc/"
+  top = %w(INSTALL README COPYING)
+
+  # git-set-file-times is distributed with rsync,
+  # Also available at: http://yhbt.net/git-set-file-times
+  # on Debian systems: /usr/share/doc/rsync/scripts/git-set-file-times.gz
+  sh("git", "set-file-times", 'Documentation', *top)
+
+  do_gzip = lambda do |txt|
+    gz = "#{txt}.gz"
+    tmp = "#{gz}.#$$"
+    sh("gzip --rsyncable -9 < #{txt} > #{tmp}")
+    st = File.stat(txt)
+    File.utime(st.atime, st.mtime, tmp) # make nginx gzip_static happy
+    File.rename(tmp, gz)
+    gz
+  end
+
+  files = `git ls-files Documentation/*.txt`.split(/\n/)
+  files.concat(top)
+  files.concat(%w(NEWS NEWS.atom.xml ChangeLog))
+  gzfiles = files.map { |txt| do_gzip.call(txt) }
+  files.concat(gzfiles)
+  sh("rsync --chmod=Fugo=r -av #{files.join(' ')} #{dest}")
+end
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..f00310b
--- /dev/null
+++ b/TODO
@@ -0,0 +1 @@
+* manpage generator
diff --git a/bin/olddoc b/bin/olddoc
new file mode 100755
index 0000000..f7e80fb
--- /dev/null
+++ b/bin/olddoc
@@ -0,0 +1,16 @@
+#!/usr/bin/env ruby
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+$stderr.sync = $stdout.sync = true
+tasks = %w(prepare merge)
+usage = "Usage: #{File.basename($0)} [#{tasks.join('|')}]"
+require 'olddoc'
+opts = Olddoc.config
+case ARGV[0]
+when "prepare"
+  Olddoc::Prepare.new(opts).run
+when "merge"
+  Olddoc::Merge.new(opts).run
+else
+  warn "#{$0.inspect} #{ARGV.inspect} not understood"
+  abort usage
+end
diff --git a/lib/olddoc.rb b/lib/olddoc.rb
new file mode 100644
index 0000000..f230cbf
--- /dev/null
+++ b/lib/olddoc.rb
@@ -0,0 +1,21 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+module Olddoc
+  VERSION = '1.0.0'
+
+  autoload :Changelog, 'olddoc/changelog'
+  autoload :Gemspec, 'olddoc/gemspec'
+  autoload :History, 'olddoc/history'
+  autoload :Merge, 'olddoc/merge'
+  autoload :NewsAtom, 'olddoc/news_atom'
+  autoload :NewsRdoc, 'olddoc/news_rdoc'
+  autoload :Prepare, 'olddoc/prepare'
+  autoload :Readme, 'olddoc/readme'
+
+  def self.config(path = ".olddoc.yml")
+    File.readable?(path) and return YAML.load(File.read(path))
+    warn "#{path} not found in current directory"
+    {}
+  end
+end
+require_relative 'oldweb'
diff --git a/lib/olddoc/changelog.rb b/lib/olddoc/changelog.rb
new file mode 100644
index 0000000..7a7fe96
--- /dev/null
+++ b/lib/olddoc/changelog.rb
@@ -0,0 +1,28 @@
+# helper method for generating the ChangeLog in RDoc format atomically
+require 'tempfile'
+
+module Olddoc::Changelog
+  include Olddoc::History
+
+  def changelog
+    fp = Tempfile.new('ChangeLog', '.')
+    fp.write "ChangeLog from #@cgit_uri"
+    cmd = %w(git log)
+    if @changelog_start && tags[0]
+      range = "#@changelog_start..#{tags[0][:tag]}"
+      fp.write(" (#{range})")
+      cmd << range
+    end
+    fp.write("\n\n")
+    prefix = "   "
+    IO.popen(cmd.join(' ')) do |io|
+      io.each { |line|
+        fp.write prefix
+        fp.write line
+      }
+    end
+    fp.chmod(0666 & ~File.umask)
+    File.rename(fp.path, 'ChangeLog')
+    fp.close!
+  end
+end
diff --git a/lib/olddoc/gemspec.rb b/lib/olddoc/gemspec.rb
new file mode 100644
index 0000000..73382ab
--- /dev/null
+++ b/lib/olddoc/gemspec.rb
@@ -0,0 +1,17 @@
+# helper methods for gemspecs
+module Olddoc::Gemspec
+  include Olddoc::Readme
+
+  def extra_rdoc_files(manifest)
+    File.readlines('.document').map! do |x|
+      x.chomp!
+      if File.directory?(x)
+        manifest.grep(%r{\A#{x}/})
+      elsif File.file?(x)
+        x
+      else
+        nil
+      end
+    end.flatten.compact
+  end
+end
diff --git a/lib/olddoc/history.rb b/lib/olddoc/history.rb
new file mode 100644
index 0000000..b817d2d
--- /dev/null
+++ b/lib/olddoc/history.rb
@@ -0,0 +1,57 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+require 'uri'
+
+module Olddoc::History
+  def initialize_history
+    @tags = @old_summaries = nil
+  end
+
+  # returns a cgit URI for a given +tag_name+
+  def tag_uri(tag_name)
+    uri = @cgit_uri.dup
+    uri.path += "/tag/"
+    uri.query = "id=#{tag_name}"
+    uri
+  end
+
+  def tags
+    timefmt = '%Y-%m-%dT%H:%M:%SZ'
+    @tags ||= `git tag -l`.split(/\n/).map do |tag|
+      next if tag == "v0.0.0"
+      if %r{\Av[\d\.]+} =~ tag
+        type = `git cat-file -t #{tag}`.chomp
+        user_type = { "tag" => "tagger", "commit" => "committer" }[type]
+        user_type or abort "unable to determine what to do with #{type}=#{tag}"
+        header, subject, body = `git cat-file #{type} #{tag}`.split(/\n\n/, 3)
+        body ||= "initial" unless old_summaries.include?(tag)
+        header = header.split(/\n/)
+
+        tagger = header.grep(/\A#{user_type} /).first
+        time = Time.at(tagger.split(/ /)[-2].to_i).utc
+        {
+          :time => time.strftime(timefmt),
+          :ruby_time => time,
+          :tagger_name => %r{^#{user_type} ([^<]+)}.match(tagger)[1].strip,
+          :tagger_email => %r{<([^>]+)>}.match(tagger)[1].strip,
+          :id => `git rev-parse refs/tags/#{tag}`.chomp!,
+          :tag => tag,
+          :subject => subject.strip,
+          :body => (old = old_summaries[tag]) ? "#{old}\n#{body}" : body,
+        }
+      end
+    end.compact.sort { |a,b| b[:time] <=> a[:time] }
+  end
+
+  def old_summaries
+    @old_summaries ||= if File.exist?(".CHANGELOG.old")
+      File.readlines(".CHANGELOG.old").inject({}) do |hash, line|
+        version, summary = line.split(/ - /, 2)
+        hash[version] = summary
+        hash
+      end
+    else
+      {}
+    end
+  end
+end
diff --git a/lib/olddoc/merge.rb b/lib/olddoc/merge.rb
new file mode 100644
index 0000000..da5bd07
--- /dev/null
+++ b/lib/olddoc/merge.rb
@@ -0,0 +1,26 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+
+class Olddoc::Merge
+  def initialize(opts)
+    @merge_html = opts["merge_html"] || {}
+  end
+
+  # FIXME: generate manpages directly from rdoc instead of relying on
+  # pandoc to do it via markdown.
+  def run
+    @merge_html.each do |file, source|
+      rdoc_html = "doc/#{file}.html"
+      fragment = File.read(source)
+      File.open(rdoc_html, "a+") { |fp|
+        html = fp.read
+        if html.sub!(%r{\s*<p>\s*olddoc_placeholder\s*</p>\s*}sm, fragment)
+          fp.truncate(0)
+          fp.write(html)
+        else
+          warn "olddoc_placeholder not found in #{rdoc_html}"
+        end
+      }
+    end
+  end
+end
diff --git a/lib/olddoc/news_atom.rb b/lib/olddoc/news_atom.rb
new file mode 100644
index 0000000..6a92b3e
--- /dev/null
+++ b/lib/olddoc/news_atom.rb
@@ -0,0 +1,51 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+require 'builder'
+
+module Olddoc::NewsAtom
+  include Olddoc::History
+  include Olddoc::Readme
+
+  # generates an Atom feed based on git tags in the document directory
+  def news_atom_xml
+    project_name, short_desc, _ = readme_metadata
+    new_tags = tags[0,10]
+    atom_uri = @rdoc_uri.dup
+    atom_uri.path += "NEWS.atom.xml"
+    news_uri = @rdoc_uri.dup
+    news_uri.path += "NEWS.html"
+    x = Builder::XmlMarkup.new
+    x.feed(xmlns: "http://www.w3.org/2005/Atom") do
+      x.id(atom_uri.to_s)
+      x.title("#{project_name} news")
+      x.subtitle(short_desc)
+      x.link(rel: 'alternate', type: 'text/html', href: news_uri.to_s)
+      x.updated(new_tags.empty? ? '1970-01-01:00:00:00Z' : new_tags[0][:time])
+      new_tags.each do |tag|
+        x.entry do
+          x.title(tag[:subject])
+          x.updated(tag[:time])
+          x.published(tag[:time])
+          x.author do
+            x.name(tag[:tagger_name])
+            x.email(tag[:tagger_email])
+          end
+          uri = tag_uri(tag[:tag]).to_s
+          x.link(rel: "alternate", type: 'text/html', href: uri)
+          x.id(uri)
+          x.content(type: :xhtml) { x.pre(tag[:body]) }
+        end # entry
+      end # new_tags
+    end # feed
+    [ x.target!, new_tags ]
+  end
+
+  def news_atom(dest = "NEWS.atom.xml")
+    xml, new_tags = news_atom_xml
+    File.open(dest, "w") { |fp| fp.write(xml) }
+    unless new_tags.empty?
+      time = new_tags[0][:ruby_time]
+      File.utime(time, time, dest)
+    end
+  end
+end
diff --git a/lib/olddoc/news_rdoc.rb b/lib/olddoc/news_rdoc.rb
new file mode 100644
index 0000000..cc51bec
--- /dev/null
+++ b/lib/olddoc/news_rdoc.rb
@@ -0,0 +1,36 @@
+# -*- encoding: utf-8 -*-
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+
+require 'tempfile'
+
+module Olddoc::NewsRdoc
+  include Olddoc::History
+
+  def puts_tag(fp, tag)
+    time = tag[:time].tr('T', ' ').gsub!(/:\d\dZ/, ' UTC')
+    fp.puts "=== #{tag[:subject]} / #{time}"
+    fp.puts ""
+
+    body = tag[:body]
+    fp.puts tag[:body].gsub(/^/smu, "  ").gsub(/[ \t]+$/smu, "")
+    fp.puts ""
+  end
+
+  # generates a NEWS file in the top-level directory based on git tags
+  def news_rdoc
+    news = Tempfile.new('NEWS', '.')
+    tags.each { |tag| puts_tag(news, tag) }
+    File.open("LATEST", "wb") { |latest|
+      if tags.empty?
+        latest.puts "Currently unreleased"
+        news.puts "No news yet."
+      else
+        puts_tag(latest, tags[0])
+      end
+    }
+    news.chmod(0666 & ~File.umask)
+    File.rename(news.path, 'NEWS')
+    news.close!
+  end
+end
diff --git a/lib/olddoc/prepare.rb b/lib/olddoc/prepare.rb
new file mode 100644
index 0000000..f760bd3
--- /dev/null
+++ b/lib/olddoc/prepare.rb
@@ -0,0 +1,27 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+
+require 'uri'
+class Olddoc::Prepare
+  include Olddoc::NewsRdoc
+  include Olddoc::NewsAtom
+  include Olddoc::Changelog
+  include Olddoc::Readme
+
+  def initialize(opts)
+    rdoc_url = opts['rdoc_url']
+    cgit_url = opts['cgit_url']
+    rdoc_url && cgit_url or
+      abort "rdoc_url and cgit_url required in .olddoc.yml for `prepare'"
+    @rdoc_uri = URI.parse(rdoc_url)
+    @cgit_uri = URI.parse(cgit_url)
+    @changelog_start = opts['changelog_start']
+    @name, @short_desc = readme_metadata
+  end
+
+  def run
+    news_rdoc
+    changelog
+    news_atom
+  end
+end
diff --git a/lib/olddoc/readme.rb b/lib/olddoc/readme.rb
new file mode 100644
index 0000000..18f0205
--- /dev/null
+++ b/lib/olddoc/readme.rb
@@ -0,0 +1,27 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# helpers for parsing the top-level README file
+module Olddoc::Readme
+
+  def readme_path
+    'README'
+  end
+
+  # returns a one-paragraph summary from the README
+  def readme_description
+    File.read(readme_path).split(/\n\n/)[1]
+  end
+
+  # parses the README file in the top-level directory for project metadata
+  def readme_metadata
+    l = File.readlines(readme_path)[0].strip!
+    l.gsub!(/^=\s+/, '') or abort "#{l.inspect} doesn't start with '='"
+    title = l.dup
+    if l.gsub!(/^(\w+\!)\s+/, '') # Rainbows!
+      return $1, l, title
+    else
+      return (l.split(/\s*[:-]\s*/, 2)).push(title)
+    end
+  end
+end
diff --git a/lib/oldweb.rb b/lib/oldweb.rb
new file mode 100644
index 0000000..d045693
--- /dev/null
+++ b/lib/oldweb.rb
@@ -0,0 +1,303 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+# Loosely derived from Darkfish in the main rdoc distribution
+require 'rdoc'
+require 'erb'
+require 'pathname'
+require 'yaml'
+require 'cgi'
+require 'uri'
+
+class Oldweb
+  RDoc::RDoc.add_generator(self)
+  include ERB::Util
+  attr_reader :class_dir
+  attr_reader :file_dir
+
+  # description of the generator
+  DESCRIPTION = 'minimal HTML generator'
+
+  # version of this generator
+  VERSION = '1'
+
+  def initialize(store, options)
+    # just because we're capable of generating UTF-8 to get human names
+    # right does not mean we should overuse it for quotation marks and such,
+    # our clients may not have the necessary fonts.
+    RDoc::Text::TO_HTML_CHARACTERS[Encoding::UTF_8] =
+      RDoc::Text::TO_HTML_CHARACTERS[Encoding::ASCII]
+
+    @store = store
+    @options = options
+    @base_dir = Pathname.pwd.expand_path
+    @dry_run = options.dry_run
+    @file_output = true
+    @template_dir = Pathname.new(File.join(File.dirname(__FILE__), 'oldweb'))
+    @template_cache = {}
+    @classes = nil
+    @context = nil
+    @files = nil
+    @methods = nil
+    @modsort = nil
+    @class_dir = nil
+    @file_dir = nil
+    @outputdir = nil
+    @old_vcs_url = nil
+    @git_tag = nil
+
+    # olddoc-specific stuff
+    # infer title from README
+    if options.title == 'RDoc Documentation' && File.readable?('README')
+      line = File.open('README') { |fp| fp.gets.strip }
+      line.sub!(/\A=+\s*/, '')
+      options.title = line
+    end
+
+    # load olddoc config
+    cfg = '.olddoc.yml'
+    if File.readable?(cfg)
+      @old_cfg = YAML.load(File.read(cfg))
+    else
+      @old_cfg = {}
+      warn "#{cfg} not readable"
+    end
+    %w(toc_max).each { |k| v = @old_cfg[k] and @old_cfg[k] = v.to_i }
+    @old_cfg['toc_max'] ||= 6
+
+    ni = {}
+    noindex = @old_cfg['noindex'] and noindex.each { |k| ni[k] = true }
+    @old_cfg['noindex'] = ni
+
+    if cgit_url = @old_cfg['cgit_url']
+      cgit_url += '/tree/%s' # path name
+      tag = @git_tag and cgit_url << "id=#{URI.escape(tag)}"
+      cgit_url << '#n%d' # lineno
+      @old_vcs_url = cgit_url
+    end
+  end
+
+  def generate
+    setup
+    generate_class_files
+    generate_file_files
+    generate_table_of_contents
+    src = Dir["#@outputdir/README*.html"].first
+    begin
+      dst = "#@outputdir/index.html"
+      File.link(src, dst)
+    rescue SystemCallError
+      IO.copy_stream(src, dst)
+    end if src
+  end
+
+  def rel_path(out_file)
+    rel_prefix = @outputdir.relative_path_from(out_file.dirname)
+    rel_prefix == '.' ? '' : "#{rel_prefix}/"
+  end
+
+  # called standalone by servelet
+  def generate_class(klass, template_file = nil)
+    setup
+    current = klass
+    template_file ||= @template_dir + 'class.rhtml'
+    out_file = @outputdir + klass.path
+    rel_prefix = rel_path(out_file)
+    @title = "#{klass.type} #{klass.full_name}"
+    @suppress_warning = [ rel_prefix, current ]
+    render_template(template_file, out_file) { |io| binding }
+  end
+
+  # Generate a documentation file for each class and module
+  def generate_class_files
+    setup
+    template_file = @template_dir + 'class.rhtml'
+    current = nil
+
+    @classes.each do |klass|
+      current = klass
+      generate_class(klass, template_file)
+    end
+  rescue => e
+    e!(e, "error generating #{current.path}: #{e.message} (#{e.class})")
+  end
+
+  # Generate a documentation file for each file
+  def generate_file_files
+    setup
+    @files.each do |file|
+      generate_page(file) if file.text?
+    end
+  end
+
+  # Generate a page file for +file+
+  def generate_page(file, out_file = @outputdir + file.path)
+    setup
+    template_file = @template_dir + 'page.rhtml'
+    rel_prefix = rel_path(out_file)
+    current = file
+
+    @title = "#{file.page_name} - #{@options.title}"
+
+    # use the first header as title instead of page_name if there is one
+    File.open("#{@options.root}/#{file.absolute_name}") do |f|
+      line = f.gets.strip
+      line.sub!(/^=+\s*/, '') and @title = line
+    end
+
+    @suppress_warning = [ current, rel_prefix ]
+
+    render_template(template_file, out_file) { |io| binding }
+  rescue => e
+    e!(e, "error generating #{out_file}: #{e.message} (#{e.class})")
+  end
+
+  # Generates the 404 page for the RDoc servlet
+  def generate_servlet_not_found(message)
+    setup
+    template_file = @template_dir + 'servlet_not_found.rhtml'
+    rel_prefix = ''
+    @suppress_warning = rel_prefix
+    @title = 'Not Found'
+    render_template(template_file) { |io| binding }
+  rescue => e
+    e!(e, "error generating servlet_not_found: #{e.message} (#{e.class})")
+  end
+
+  # Generates the servlet root page for the RDoc servlet
+  def generate_servlet_root(installed)
+    setup
+
+    template_file = @template_dir + 'servlet_root.rhtml'
+
+    rel_prefix = ''
+    @suppress_warning = rel_prefix
+
+    @title = 'Local RDoc Documentation'
+    render_template(template_file) { |io| binding }
+  rescue => e
+    e!(e, "error generating servlet_root: #{e.message} (#{e.class})")
+  end
+
+  def generate_table_of_contents
+    setup
+    template_file = @template_dir + 'table_of_contents.rhtml'
+    out_file = @outputdir + 'table_of_contents.html'
+    rel_prefix = rel_path(out_file)
+    @suppress_warning = rel_prefix
+    @title = "Table of Contents - #{@options.title}"
+    render_template(template_file, out_file) { |io| binding }
+  rescue => e
+    e!(e, "error generating table_of_contents.html: #{e.message} (#{e.class})")
+  end
+
+  def setup
+    return if @outputdir
+    @outputdir = Pathname.new(@options.op_dir).expand_path(@base_dir)
+    return unless @store
+    @classes = @store.all_classes_and_modules.sort
+    @files = @store.all_files.sort
+    @methods = @classes.map(&:method_list).flatten.sort
+    @modsort = @classes.select(&:display?).sort
+  end
+
+  # Creates a template from its components and the +body_file+.
+  def assemble_template(body_file)
+    body = body_file.read
+    head = @template_dir + '_head.rhtml'
+    tail = @template_dir + '_tail.rhtml'
+    "<html><head>#{head.read.strip}</head><body\n" \
+      "id=\"top\">#{body.strip}#{tail.read.strip}</body></html>"
+  end
+
+  # Renders the ERb contained in +file_name+ relative to the template
+  # directory and returns the result based on the current context.
+  def render(file_name)
+    template_file = @template_dir + file_name
+    template = template_for(template_file, false, RDoc::ERBPartial)
+    template.filename = template_file.to_s
+    template.result(@context)
+  end
+
+  # Load and render the erb template in the given +template_file+ and write
+  # it out to +out_file+.
+  # Both +template_file+ and +out_file+ should be Pathname-like objects.
+  # An io will be yielded which must be captured by binding in the caller.
+  def render_template(template_file, out_file = nil) # :yield: io
+    io_output = out_file && !@dry_run && @file_output
+    erb_klass = io_output ? RDoc::ERBIO : ERB
+    template = template_for(template_file, true, erb_klass)
+
+    if io_output
+      out_file.dirname.mkpath
+      out_file.open('w', 0644) do |io|
+        io.set_encoding(@options.encoding)
+        @context = yield io
+        template_result(template, @context, template_file)
+      end
+    else
+      @context = yield nil
+      template_result(template, @context, template_file)
+    end
+  end
+
+  # Creates the result for +template+ with +context+.  If an error is raised a
+  # Pathname +template_file+ will indicate the file where the error occurred.
+  def template_result(template, context, template_file)
+    template.filename = template_file.to_s
+    template.result(context)
+  rescue NoMethodError => e
+    e!(e, "Error while evaluating #{template_file.expand_path}: #{e.message}")
+  end
+
+  def template_for(file, page = true, klass = ERB)
+    template = @template_cache[file]
+
+    return template if template
+
+    if page
+      template = assemble_template(file)
+      erbout = 'io'
+    else
+      template = file.read
+      template = template.encode(@options.encoding)
+      file_var = File.basename(file).sub(/\..*/, '')
+      erbout = "_erbout_#{file_var}"
+    end
+
+    template = klass.new(template, nil, '<>', erbout)
+    @template_cache[file] = template
+  end
+
+  def e!(e, msg)
+    raise RDoc::Error, msg, e.backtrace
+  end
+
+  def method_srclink(m)
+    url = @old_vcs_url or return ""
+    line = m.line or return ""
+    path = URI.escape(m.file_name)
+    %Q(<a href="#{url % [ path, line ]}">source</a>)
+  end
+
+  # reach into RDoc internals to generate less HTML
+  module LessHtml
+    def accept_verbatim(verbatim)
+      @res << "\n<pre>#{CGI.escapeHTML(verbatim.text.rstrip)}</pre>\n"
+    end
+
+    def accept_heading(heading)
+      level = [6, heading.level].min
+      label = heading.label(@code_object)
+      @res << "<h#{level}"
+      @res << (@options.output_decoration ? "\nid=\"#{label}\">" : ">")
+      @res << to_html(heading.text)
+      @res << "</h#{level}>"
+    end
+  end
+end
+
+class RDoc::Markup::ToHtml # :nodoc:
+  remove_method :accept_heading
+  remove_method :accept_verbatim
+  include Oldweb::LessHtml
+end
diff --git a/lib/oldweb/_head.rhtml b/lib/oldweb/_head.rhtml
new file mode 100644
index 0000000..9a9242c
--- /dev/null
+++ b/lib/oldweb/_head.rhtml
@@ -0,0 +1,7 @@
+<meta charset="<%= @options.charset %>"><title><%= h @title %></title><%
+if rdoc_url = @old_cfg['rdoc_url'] %><link
+rel="alternate"
+title="Atom feed"
+href="<%= rdoc_url %>NEWS.atom.xml"
+type="application/atom+xml" /><%
+end %>
diff --git a/lib/oldweb/_sidebar_classes.rhtml b/lib/oldweb/_sidebar_classes.rhtml
new file mode 100644
index 0000000..66f7fbf
--- /dev/null
+++ b/lib/oldweb/_sidebar_classes.rhtml
@@ -0,0 +1,27 @@
+<%
+@modsort.delete_if do |c|
+  c.full_name == "unknown" || @old_cfg["noindex"].include?(c.full_name)
+end
+unless @modsort.empty?
+  # To save space and reduce visual noise, we want to display:
+  #   Top Sub1 Sub2 Sub3
+  # Instead of
+  #   Top Top::Sub1 Top::Sub2 Top::Sub3
+  top_mod = nil
+  @modsort.each do |mod| %><%
+    parts = mod.full_name.split('::')
+    if parts[0] != top_mod && parts.size == 1
+      top_mod = parts[0]
+      %><%= '<br />' if mod != @modsort[0] %><%
+    elsif parts[0] != top_mod
+      top_mod = nil
+      %><%= '<br />' if mod != @modsort[0] %><%= parts[0] %> <%
+    else
+      parts.shift
+    end
+%><a
+href="<%= rel_prefix %><%= mod.path %>"><%= parts.join('::') %></a>
+<%
+  end
+end
+%><br />
diff --git a/lib/oldweb/_sidebar_extends.rhtml b/lib/oldweb/_sidebar_extends.rhtml
new file mode 100644
index 0000000..8dab782
--- /dev/null
+++ b/lib/oldweb/_sidebar_extends.rhtml
@@ -0,0 +1,13 @@
+<%
+unless klass.extends.empty?
+%><p><b>Extended with:</b> <%
+  klass.each_extend do |ext|
+    unless String === ext.module
+%><a
+href="<%= klass.aref_to ext.module.path %>"><%= ext.module.full_name %></a><%
+    else
+%><%= ext.name %><%
+    end
+  end
+end
+%>
diff --git a/lib/oldweb/_sidebar_includes.rhtml b/lib/oldweb/_sidebar_includes.rhtml
new file mode 100644
index 0000000..46a1d1d
--- /dev/null
+++ b/lib/oldweb/_sidebar_includes.rhtml
@@ -0,0 +1,12 @@
+<%
+unless klass.includes.empty?
+%><p><b>Included modules:</b> <%
+  klass.each_include do |inc|
+    unless String === inc.module %><a
+href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a><%
+    else %><%=
+      inc.name %><%
+    end
+  end
+end
+%>
diff --git a/lib/oldweb/_sidebar_installed.rhtml b/lib/oldweb/_sidebar_installed.rhtml
new file mode 100644
index 0000000..74d3bab
--- /dev/null
+++ b/lib/oldweb/_sidebar_installed.rhtml
@@ -0,0 +1,10 @@
+<h3>Documentation</h3><ul><%
+installed.each do |name, href, exists, type, _|
+  next if type == :extra %><li><%
+  if exists
+  %><a
+href="<%= href %>"><%= h name %></a><%
+  else
+  %><%= h name %><%
+  end
+end %></ul>
diff --git a/lib/oldweb/_sidebar_methods.rhtml b/lib/oldweb/_sidebar_methods.rhtml
new file mode 100644
index 0000000..f84fe9c
--- /dev/null
+++ b/lib/oldweb/_sidebar_methods.rhtml
@@ -0,0 +1,6 @@
+<% unless klass.method_list.empty? %>
+<h3 id="method-list-section">Methods</h3><%
+klass.each_method do |meth| %>
+<a href="#<%= meth.aref %>"><%=
+meth.singleton ? '::' : '#' %><%= h meth.name %></a><%
+end %><% end %>
diff --git a/lib/oldweb/_sidebar_navigation.rhtml b/lib/oldweb/_sidebar_navigation.rhtml
new file mode 100644
index 0000000..a7ea935
--- /dev/null
+++ b/lib/oldweb/_sidebar_navigation.rhtml
@@ -0,0 +1,6 @@
+<br /><a
+href="<%= rel_prefix %>table_of_contents.html#pages">Pages</a>
+<a
+href="<%= rel_prefix %>table_of_contents.html#classes">Classes</a>
+<a
+href="<%= rel_prefix %>table_of_contents.html#methods">Methods</a>
diff --git a/lib/oldweb/_sidebar_pages.rhtml b/lib/oldweb/_sidebar_pages.rhtml
new file mode 100644
index 0000000..cdc23f4
--- /dev/null
+++ b/lib/oldweb/_sidebar_pages.rhtml
@@ -0,0 +1,17 @@
+<%
+simple_files = @files.select(&:text?)
+unless simple_files.empty?
+  current_name = nil
+  if defined?(current) && current.respond_to?(:page_name)
+    current_name = current.page_name
+  end
+  simple_files.each do |f|
+    next if @old_cfg["noindex"].include?(f.page_name)
+    b = (current_name == f.page_name)
+%><a
+href="<%= rel_prefix %><%= f.path %>"><%=
+b ? '<b>' : '' %><%= h f.page_name %><%= b ? '</b>' : ''%></a>
+<%
+  end
+end
+%><br />
diff --git a/lib/oldweb/_sidebar_parent.rhtml b/lib/oldweb/_sidebar_parent.rhtml
new file mode 100644
index 0000000..9323101
--- /dev/null
+++ b/lib/oldweb/_sidebar_parent.rhtml
@@ -0,0 +1,13 @@
+<%
+# having Object as parent is boring
+if klass.type == 'class' && klass.superclass != 'Object'
+%><p><b>Parent:</b> <%
+  if klass.superclass and not String === klass.superclass
+%><a
+href="<%= klass.aref_to klass.superclass.path %>"><%=
+    klass.superclass.full_name %></a><%
+  else
+%><%= klass.superclass %><%
+  end
+end
+%>
diff --git a/lib/oldweb/_sidebar_sections.rhtml b/lib/oldweb/_sidebar_sections.rhtml
new file mode 100644
index 0000000..b6e9458
--- /dev/null
+++ b/lib/oldweb/_sidebar_sections.rhtml
@@ -0,0 +1,8 @@
+<%
+unless klass.sections.length == 1
+%><p><b>Sections:</b> <%
+  klass.sort_sections.each do |section| %><a
+href="#<%= section.aref %>"><%= h section.title %></a><%
+  end
+end
+%>
diff --git a/lib/oldweb/_sidebar_table_of_contents.rhtml b/lib/oldweb/_sidebar_table_of_contents.rhtml
new file mode 100644
index 0000000..890b0cc
--- /dev/null
+++ b/lib/oldweb/_sidebar_table_of_contents.rhtml
@@ -0,0 +1,15 @@
+<%
+comment = current.respond_to?(:comment_location) ? current.comment_location :
+          current.comment
+table = current.parse(comment).table_of_contents
+if table.length > 1
+%><%
+  table.each_with_index do |heading, i|
+    next if heading.level > @old_cfg['toc_max']
+%><a
+href="#<%= heading.label(current) %>"><%=
+    i == 0 ? "top" : heading.plain_html %></a>
+<%
+  end %><br /><%
+end
+%>
diff --git a/lib/oldweb/_tail.rhtml b/lib/oldweb/_tail.rhtml
new file mode 100644
index 0000000..d1fc7e5
--- /dev/null
+++ b/lib/oldweb/_tail.rhtml
@@ -0,0 +1,25 @@
+<%
+public_email = @old_cfg['public_email']
+private_email = @old_cfg['private_email']
+ml_url = @old_cfg['ml_url']
+git_doc = 'https://kernel.org/pub/software/scm/git/docs/'
+se_url = "#{git_doc}git-send-email.html"
+rp_url = "#{git_doc}git-request-pull.html"
+
+if public_email && private_email && ml_url %><hr /><p>
+We love to hear from you!<br />
+Email patches (using <a
+href="<%= se_url %>">git send-email</a>),
+pull requests (formatted using <a
+href="<%= rp_url %>">git request-pull</a>), questions, bug reports,
+suggestions, etc. to us publically at:<br /><a
+href="mailto:<%= public_email %>"><%= public_email %></a><br />
+Mail archives are available at: <a
+href="<%= ml_url %>"><%= ml_url %></a><br />
+Please send plain-text email only and do not waste bandwidth on HTML mail,
+HTML mail will not be read.<br />
+Quote as little as reasonable and do not <a
+href="http://catb.org/jargon/html/T/top-post.html">top post</a>.<br />
+For sensitive topics, email us privately at:
+<a
+href="mailto:<%= private_email %>"><%= private_email %></a><% end %>
diff --git a/lib/oldweb/class.rhtml b/lib/oldweb/class.rhtml
new file mode 100644
index 0000000..107ce41
--- /dev/null
+++ b/lib/oldweb/class.rhtml
@@ -0,0 +1,79 @@
+<%=
+render('_sidebar_pages.rhtml') <<
+render('_sidebar_classes.rhtml') <<
+render('_sidebar_methods.rhtml')
+%><h1
+id="<%= h klass.aref %>"><%= klass.type %> <%= klass.full_name %></h1><%=
+klass.description.strip
+%><%
+nd = '(Not documented)'
+klass.each_section do |section, constants, attributes|
+  constants = constants.select(&:display?)
+  attributes = attributes.select(&:display?)
+  if section.title
+%><h2
+id="<%= section.aref %>"><%= section.title %></h2><%
+  end
+  if section.comment %><p><%= section.description.strip %></p><%
+  end
+  unless constants.empty? %><h3>Constants</h3><%
+    constants.each { |const|
+      %><h4
+id="<%= const.name %>"><%= const.name %></h4><%=
+      const.comment ? const.description.strip : nd %><%
+    } %><%
+  end
+  unless attributes.empty? %><h3>Attributes</h3><%
+    attributes.each do |attrib|
+%><h4
+id="<%= attrib.aref %>"><%=
+      h(attrib.name) %> [<%= attrib.rw %>]</h4><%=
+      attrib.comment ? attrib.description.strip : nd %><%
+    end
+  end
+  klass.methods_by_type(section).each do |type, visibilities|
+    next if visibilities.empty?
+    visibilities.each do |visibility, methods|
+      next if methods.empty? %><h3
+id="<%= visibility %>-<%= type %>-<%= section.aref %>-method-details">
+<%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3><%
+      methods.each do |method|
+      %><pre id="<%= method.aref %>"><b><%
+        if method.call_seq %><%= h method.call_seq %><%
+        else
+          %><%= h method.name %> <%= h method.param_seq %><%
+        end %></b><%= method_srclink(method) %></pre><%=
+          method.comment ? method.description.strip : nd %><%
+        if method.calls_super %>Calls superclass method<%=
+           method.superclass_method ?
+           method.formatter.link(method.superclass_method.full_name,
+                                 method.superclass_method.full_name) : nil
+        %><%
+        end
+        unless method.aliases.empty?
+        %> Also aliased as: <%=
+          method.aliases.map do |aka|
+            if aka.parent # HACK lib/rexml/encodings
+              %{<a href="#{klass.aref_to(aka.path)}">#{h aka.name}</a>}
+            else
+              h aka.name
+            end
+          end.join ", " %><%
+        end
+        if method.is_alias_for
+       %><br />Alias for:
+<a
+href="<%= klass.aref_to method.is_alias_for.path %>"><%=
+          h method.is_alias_for.name %></a><%
+        end
+      end
+    end
+  end
+end
+%><%=
+render('_sidebar_sections.rhtml').strip <<
+render('_sidebar_parent.rhtml').strip <<
+render('_sidebar_includes.rhtml').strip <<
+render('_sidebar_extends.rhtml').strip <<
+render('_sidebar_navigation.rhtml').strip
+%>
diff --git a/lib/oldweb/page.rhtml b/lib/oldweb/page.rhtml
new file mode 100644
index 0000000..9049ee5
--- /dev/null
+++ b/lib/oldweb/page.rhtml
@@ -0,0 +1,5 @@
+<%=
+render('_sidebar_pages.rhtml') <<
+render('_sidebar_classes.rhtml') <<
+file.description.strip
+%>
diff --git a/lib/oldweb/servlet_not_found.rhtml b/lib/oldweb/servlet_not_found.rhtml
new file mode 100644
index 0000000..3264d9e
--- /dev/null
+++ b/lib/oldweb/servlet_not_found.rhtml
@@ -0,0 +1,5 @@
+<%=
+  render('_sidebar_navigation.rhtml') <<
+  render('_sidebar_pages.rhtml') <<
+  render('_sidebar_classes.rhtml')
+%><h1>Not Found</h1><%= message %>
diff --git a/lib/oldweb/servlet_root.rhtml b/lib/oldweb/servlet_root.rhtml
new file mode 100644
index 0000000..839198f
--- /dev/null
+++ b/lib/oldweb/servlet_root.rhtml
@@ -0,0 +1,39 @@
+<h2><a href="<%= rel_prefix %>">Home</a></h2><%=
+render '_sidebar_installed.rhtml'
+%><h1>Local RDoc Documentation</h1>
+<p>Here you can browse local documentation from the ruby standard library and
+  your installed gems.
+<% extra_dirs = installed.select { |_, _, _, type,| type == :extra } %>
+<% unless extra_dirs.empty? %>
+<h2>Extra Documentation Directories</h2>
+  <p>The following additional documentation directories are available:</p>
+  <ol>
+  <% extra_dirs.each do |name, href, exists, _, path| %>
+    <li>
+    <% if exists %>
+      <a href="<%= href %>"><%= h name %></a> (<%= h path %>)
+    <% else %>
+      <%= h name %> (<%= h path %>; not available)
+    <% end %>
+  <% end %>
+  </ol>
+<% end %>
+<%
+gems = installed.select { |_, _, _, type,| type == :gem }
+missing = gems.reject { |_, _, exists,| exists }
+unless missing.empty? %>
+<h2>Missing Gem Documentation</h2>
+<p>You are missing documentation for some of your installed gems.
+You can install missing documentation for gems by running
+<kbd>gem rdoc --all</kbd>.  After installing the missing documentation you
+only need to reload this page.  The newly created documentation will
+automatically appear.
+<p>You can also install documentation for a specific gem by running one of
+the following commands.
+<ul>
+<% names = missing.map { |name,| name.sub(/-([^-]*)$/, '') }.uniq %>
+<% names.each do |name| %>
+  <li><kbd>gem rdoc <%=h name %></kbd>
+<% end %>
+</ul>
+<% end %>
diff --git a/lib/oldweb/table_of_contents.rhtml b/lib/oldweb/table_of_contents.rhtml
new file mode 100644
index 0000000..ed455a8
--- /dev/null
+++ b/lib/oldweb/table_of_contents.rhtml
@@ -0,0 +1,52 @@
+<h1><%= h @title %></h1><%
+simple_files = @files.select(&:text?)
+unless simple_files.empty?
+%><h2 id="pages">Pages</h2>
+<ul><%
+  simple_files.sort.each do |file| %><li><a
+href="<%= file.path %>"><%= h file.page_name %></a>
+<%
+    # HACK table_of_contents should not exist on Document
+    table = file.parse(file.comment).table_of_contents
+    unless table.empty?
+%><ul><%
+      table.each do |heading|
+      %><li><a
+href="<%= file.path %>#<%= heading.aref %>"><%= heading.plain_html %></a>
+<%    end
+%></ul><%
+    end
+%><%
+  end
+%></ul><%
+end
+%><h2
+id="classes">Classes and Modules</h2><ul><%
+@modsort.each do |klass| %><li
+class="<%= klass.type %>"><a
+href="<%= klass.path %>"><%= klass.full_name %></a>
+<%
+  table = []
+  table.concat klass.parse(klass.comment_location).table_of_contents
+  table.concat klass.section_contents
+
+  unless table.empty?
+    %><ul><%
+    table.each do |item|
+    %><li><a
+href="<%= klass.path %>#<%= item.aref %>"><%= item.plain_html %></a>
+<%
+    end %></ul><%
+  end
+%><%
+end
+%></ul><h2
+id="methods">Methods</h2><ul><%
+  @store.all_classes_and_modules.map do |mod|
+    mod.method_list
+  end.flatten.sort.each do |method|
+%><li><a
+href="<%= method.path %>"><%= h method.pretty_name %></a>
+- <%= method.parent.full_name %><%
+end
+%></ul>
diff --git a/lib/rdoc/discover.rb b/lib/rdoc/discover.rb
new file mode 100644
index 0000000..e497514
--- /dev/null
+++ b/lib/rdoc/discover.rb
@@ -0,0 +1,5 @@
+begin
+  gem 'rdoc', '~> 4.1'
+  require_relative '../olddoc'
+rescue Gem::LoadError
+end unless defined?(Olddoc)
diff --git a/olddoc.gemspec b/olddoc.gemspec
new file mode 100644
index 0000000..17b5fa8
--- /dev/null
+++ b/olddoc.gemspec
@@ -0,0 +1,21 @@
+# Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+$LOAD_PATH << 'lib'
+require 'olddoc'
+extend Olddoc::Gemspec
+name, summary, title = readme_metadata
+Gem::Specification.new do |s|
+  manifest = File.read('.gem-manifest').split(/\n/)
+  s.name = 'olddoc'
+  s.version = Olddoc::VERSION
+  s.executables = %w(olddoc)
+  s.authors = ["#{s.name} hackers"]
+  s.summary = summary
+  s.description = readme_description
+  s.email = Olddoc.config['private_email']
+  s.files = manifest
+  s.add_dependency('rdoc', '~> 4.2')
+  s.add_dependency('builder', '~> 3.2')
+  s.homepage = Olddoc.config['rdoc_url']
+  s.licenses = 'GPLv3+'
+end