packages feed

darcs-cabalized (empty) → 2.0.2

raw patch · 208 files changed

+67536/−0 lines, 208 filesdep +HUnitdep +QuickCheckdep +arraysetup-changedbinary-added

Dependencies added: HUnit, QuickCheck, array, base, bytestring, containers, directory, html, mtl, old-time, parsec, process, regex-compat, unix

Files

+ COPYING view
@@ -0,0 +1,339 @@+		    GNU GENERAL PUBLIC LICENSE+		       Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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.,+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General+Public License instead of this License.
+ Setup.lhs view
@@ -0,0 +1,5 @@+#!/usr/bin/env runhaskell+> module Main where+> import Distribution.Simple+> main :: IO ()+> main = defaultMainWithHooks defaultUserHooks
+ aclocal.m4 view
@@ -0,0 +1,518 @@+# Copyright 2005,2008 David Roundy++# Redistribution and use in source and binary forms of this file, with or+# without modification, are permitted provided that redistributions of+# source code must retain the above copyright notice.++# TRY_COMPILE_GHC(PROGRAM, [ACTION-IF-TRUE], [ACTION-IF-FALSE])+# -----------+# Compile and link using ghc.+AC_DEFUN([TRY_COMPILE_GHC],[+cat << \EOF > conftest.hs+[$1]+-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if AC_TRY_COMMAND($GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS) && test -s conftest+then+dnl Don't remove the temporary files here, so they can be examined.+  ifelse([$2], , :, [$2])+else+  echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD+  cat conftest.hs >&AS_MESSAGE_LOG_FD+  echo "end of failed program." >&AS_MESSAGE_LOG_FD+ifelse([$3], , , [ rm -f Main.hi Main.o+  $3+])dnl+fi])++# TRY_RUN_GHC(PROGRAM, [ACTION-IF-TRUE], [ACTION-IF-FALSE])+# -----------+# Compile, link and run using ghc.+AC_DEFUN([TRY_RUN_GHC],[+  TRY_COMPILE_GHC([$1],+    AS_IF([AC_TRY_COMMAND(./conftest)],[$2],[$3]),+    [$3])+])++# GHC_CHECK_ONE_MODULE(MODULE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])+# -----------+# Compile and link using ghc.+AC_DEFUN([GHC_CHECK_ONE_MODULE],[+TRY_COMPILE_GHC([import $1+main = seq ($2) (putStr "Hello world.\n")+                ],[$3],[$4])++])++# GHC_CHECK_MODULE(MODULE, PACKAGE, CODE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])+# -----------+# Compile and link using ghc.+AC_DEFUN([GHC_CHECK_MODULE],[+AC_MSG_CHECKING([for module $1])+GHC_CHECK_ONE_MODULE([$1], [$3], [AC_MSG_RESULT([yes])+$4], [+  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package $2"+  GHC_CHECK_ONE_MODULE([$1], [$3], [AC_MSG_RESULT([in package $2])+$4],[+    GHCFLAGS=$check_module_save_GHCFLAGS+    AC_MSG_RESULT(no; and neither in package $2)+    $5])+  ])+])++# GHC_COMPILE_FFI(IMPORT, TYPE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])+# -----------+# Compile and link ffi code using ghc.+AC_DEFUN([GHC_COMPILE_FFI],[+TRY_COMPILE_GHC([{-# OPTIONS -fffi -Werror #-}+module Main where++foreign import ccall unsafe "$1" fun :: $2++main = fun `seq` putStrLn "hello world"+],[$3],[$4])])++# GHC_CHECK_LIBRARY(LIBRARY, IMPORT, TYPE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])+# -----------+# Compile and link with C library using ghc.+AC_DEFUN([GHC_CHECK_LIBRARY],[+AC_MSG_CHECKING([for library $1])+GHC_COMPILE_FFI([$2], [$3], [AC_MSG_RESULT([yes])+$4], [+  check_library_save_LIBS=$LIBS+  LIBS="$LIBS -l$1"+  GHC_COMPILE_FFI([$2], [$3], [AC_MSG_RESULT([in -l$1])+  $4],[+    LIBS=$check_library_save_LIBS+    AC_MSG_RESULT(no; and not with -l$1 either)+    $5])+  ])+])++# INIT_WORKAROUND+# ---------------+# Initialize src/Workaround.hs module.+AC_DEFUN([INIT_WORKAROUND],[+rm -f src/Workaround.hs.beginning src/Workaround.hs.ending+touch src/Workaround.hs.ending+cat << \EOF > src/Workaround.hs.prefix+{-# OPTIONS -w #-}+{- Workaround.hs++This file was created automatically by configure.  We disable warnings to+avoid issues with duplicate imports.++-}++module Workaround(+EOF+cat << \EOF > src/Workaround.hs.beginning+ ) where++EOF+])++# OUTPUT_WORKAROUND+# -----------------+# Create the src/Workaround.hs module.+AC_DEFUN([OUTPUT_WORKAROUND],[+cat src/Workaround.hs.prefix src/Workaround.hs.beginning src/Workaround.hs.ending > src/Workaround.hs+rm -f src/Workaround.hs.beginning src/Workaround.hs.ending src/Workaround.hs.prefix+])++# IMPORT_WORKAROUND(CODE)+# -----------------------+# Import a module into src/Workaround.hs+AC_DEFUN([IMPORT_WORKAROUND],[+cat << \EOF >> src/Workaround.hs.beginning+$1+EOF+])++# EXPORT_WORKAROUND(CODE)+# -----------------------+# Export from src/Workaround.hs+AC_DEFUN([EXPORT_WORKAROUND],[+cat << \EOF >> src/Workaround.hs.prefix+$1+EOF+])++# CODE_WORKAROUND(CODE)+# ---------------------+# Import a module into src/Workaround.hs+AC_DEFUN([CODE_WORKAROUND],[+cat << \EOF >> src/Workaround.hs.ending+$1+EOF+])++# WORKAROUND_POSIXSIGNALS(IMPORTS)+# -----------------------+# Work around missing POSIX signals code.+AC_DEFUN([WORKAROUND_POSIXSIGNALS],[+  EXPORT_WORKAROUND([$1])+  GHC_CHECK_MODULE(System.Posix.Signals($1), unix, undefined,+    [IMPORT_WORKAROUND([import System.Posix.Signals($1)])],+    GHC_CHECK_MODULE(Posix($1), util, undefined,+      [IMPORT_WORKAROUND([import Posix($1)])],+      [CODE_WORKAROUND([[++-- Dummy implementation of POSIX signals++data Handler = Default | Ignore | Catch (IO ())+type Signal = Int++installHandler :: Signal -> Handler -> Maybe () -> IO ()+installHandler _ _ _ = return ()++raiseSignal :: Signal -> IO ()+raiseSignal _ = return ()++sigINT, {- sigKILL, -} sigHUP, {- sigQUIT, -} sigABRT, sigALRM, sigTERM, sigPIPE :: Signal+sigINT = 0+-- not used: sigKILL = 0+sigHUP = 0+-- not used: sigQUIT = 0+sigABRT = 0+sigTERM = 0+sigPIPE = 0+sigALRM = 0++-- not used: raiseSignal :: Signal -> IO ()+-- not used: raiseSignal _ = return ()++]])]+    )+  )+])++# WORKAROUND_bracketOnError+# -----------------------+# Work around missing bracketOnError+AC_DEFUN([WORKAROUND_bracketOnError],[+  EXPORT_WORKAROUND([           bracketOnError, ])+  GHC_CHECK_MODULE(Control.Exception( bracketOnError ), base ,+    bracketOnError (return ()) (const $ return ()) (const $ return ()),+    [IMPORT_WORKAROUND([import Control.Exception( bracketOnError )])],+    [IMPORT_WORKAROUND([import qualified Control.Exception( catch, throw, block, unblock )])+     CODE_WORKAROUND([[++-- | Like bracket, but only performs the final action if there was an+-- exception raised by the in-between computation.+-- From GHC 6.6 (with twiddling for qualified block, catch, etc)+bracketOnError+	:: IO a		-- ^ computation to run first (\"acquire resource\")+	-> (a -> IO b)  -- ^ computation to run last (\"release resource\")+	-> (a -> IO c)	-- ^ computation to run in-between+	-> IO c		-- returns the value from the in-between computation+bracketOnError before after thing =+  Control.Exception.block (do+    a <- before+    Control.Exception.catch+	(Control.Exception.unblock (thing a))+	(\e -> do { after a; Control.Exception.throw e })+  )+]])+])+])++# WORKAROUND_createLink+# -----------------------+# Work around missing POSIX createLink code.+AC_DEFUN([WORKAROUND_createLink],[+  EXPORT_WORKAROUND([           createLink, ])+  GHC_CHECK_MODULE(System.Posix.Files( createLink ), unix, createLink "a" "b",+    [IMPORT_WORKAROUND([import System.Posix.Files( createLink )])],+    GHC_CHECK_MODULE(Posix( createLink ), util, createLink "a" "b",+      [IMPORT_WORKAROUND([import Posix( createLink )])],+      [CODE_WORKAROUND([[++-- Dummy implementation of createLink.++createLink :: FilePath -> FilePath -> IO ()+createLink _ _ = fail "Dummy create link error should be caught."+]])]+    )+  )+])++# WORKAROUND_createDirectoryIfMissing+# ------------------------------+# Work around missing createDirectoryIfMissing.+AC_DEFUN([WORKAROUND_createDirectoryIfMissing],[+  EXPORT_WORKAROUND([           createDirectoryIfMissing, ])+  AC_MSG_CHECKING([createDirectoryIfMissing])+  TRY_COMPILE_GHC([+import System.Directory(createDirectoryIfMissing)+main = createDirectoryIfMissing True ""+    ],+    [AC_MSG_RESULT([has createDirectoryIfMissing])+     IMPORT_WORKAROUND([import System.Directory(createDirectoryIfMissing)])],+    [AC_MSG_RESULT([doesn't have createDirectoryIfMissing])+      IMPORT_WORKAROUND([import System.Directory ( doesDirectoryExist, createDirectory )])+      CODE_WORKAROUND([[+createDirectoryIfMissing+  :: Bool     -- ^ Create its parents too?+  -> FilePath -- ^ The path to the directory you want to make+  -> IO ()+createDirectoryIfMissing parents file = do+  b <- doesDirectoryExist file+  case (b,parents, file) of+    (_,     _, "") -> return ()+    (True,  _,  _) -> return ()+    (_,  True,  _) -> mapM_ (createDirectoryIfMissing False) (tail (pathParents file))+    (_, False,  _) -> createDirectory file+ where    pathParents :: FilePath -> [FilePath]+          pathParents p =+              root'' : map ((++) root') (dropEmptyPath $ inits path')+              where+#ifdef WIN32+                 (root,path) = case break (== ':') p of+                    (rel,    "") -> ("",rel)+                    (drv,_:rel) -> (drv++":",rel)+#else+                 (root,path) = ("",p)+#endif+                 (root',root'',path') = case path of+                   (c:path'') | isPathSeparator c -> (root++[pathSeparator],root++[pathSeparator],path'')+                   _                              -> (root                 ,root++"."            ,path)+          +                 dropEmptyPath ("":paths) = paths+                 dropEmptyPath paths      = paths+          +                 inits :: String -> [String]+                 inits [] =  [""]+                 inits cs =+                   case pre of+                     "."  -> inits suf+                     ".." -> map (joinFileName pre) (dropEmptyPath $ inits suf)+                     _    -> "" : map (joinFileName pre) (inits suf)+                   where+                     (pre,suf) = case break isPathSeparator cs of+                        (pre',"")     -> (pre', "")+                        (pre',_:suf') -> (pre',suf')+                 isPathSeparator :: Char -> Bool+                 isPathSeparator ch = ch == pathSeparator || ch == '/'+                 pathSeparator :: Char+#ifdef WIN32+                 pathSeparator = '\\'+#else+                 pathSeparator = '/'+#endif+                 joinFileName :: String -> String -> FilePath+                 joinFileName ""  fname = fname+                 joinFileName "." fname = fname+                 joinFileName dir ""    = dir+                 joinFileName dir fname+                   | isPathSeparator (last dir) = dir++fname+                   | otherwise                  = dir++pathSeparator:fname+      ]])+    ]+  )+])++# WORKAROUND_getCurrentDirectory+# ------------------------------+# Work around getCurrentDirectory that uses '\\' rather than '/'.+AC_DEFUN([WORKAROUND_getCurrentDirectory],[+  EXPORT_WORKAROUND([           getCurrentDirectory, ])+  AC_MSG_CHECKING([getCurrentDirectory])+  TRY_RUN_GHC([+import System.Directory(getCurrentDirectory, setCurrentDirectory)+main = do setCurrentDirectory "src"+          d <- getCurrentDirectory+          case reverse $ take 4 $ reverse d of+              "/src" -> return ()+    ],+    [AC_MSG_RESULT([uses /])+     IMPORT_WORKAROUND([import System.Directory(getCurrentDirectory)])]+     GHC_SEPARATOR='/',+    [AC_MSG_RESULT([uses \\])+      IMPORT_WORKAROUND([import qualified System.Directory(getCurrentDirectory)])+      GHC_SEPARATOR='\\'+      CODE_WORKAROUND([[+{-+System.Directory.getCurrentDirectory returns a path with backslashes in it+under windows, and some of the code gets confused by that, so we override+getCurrentDirectory and translates '\\' to '/'+-}++getCurrentDirectory :: IO FilePath+getCurrentDirectory = do d <- System.Directory.getCurrentDirectory+                         return $ map rb d+    where rb '\\' = '/'+          rb c = c+      ]])+    ]+  )+])++# WORKAROUND_renameFile+# -----------------------+# Work around buggy renameFile.+AC_DEFUN([WORKAROUND_renameFile],[+  EXPORT_WORKAROUND([           renameFile, ])+  AC_MSG_CHECKING([renameFile])+  TRY_RUN_GHC([+import System.Directory ( renameFile )++main = do writeFile "conftest.data" "orig_data"+          writeFile "conftest.newdata" "new_data"+          renameFile "conftest.newdata" "conftest.data"+    ],+    [AC_MSG_RESULT([okay])+     IMPORT_WORKAROUND([import System.Directory ( renameFile )])],+    AC_MSG_RESULT([buggy!])+    IMPORT_WORKAROUND([import qualified System.Directory( renameFile, removeFile )])+    IMPORT_WORKAROUND([import qualified System.IO.Error])+    IMPORT_WORKAROUND([import qualified Control.Exception ( block )])+    CODE_WORKAROUND([+{-+System.Directory.renameFile incorrectly fails when the new file already+exists.  This code works around that bug at the cost of losing atomic+writes.+-}++renameFile :: FilePath -> FilePath -> IO ()+renameFile old new = Control.Exception.block $+   do System.Directory.removeFile new+        `System.IO.Error.catch`+         (\e -> if System.IO.Error.isDoesNotExistError e+                   then return ()+                   else System.IO.Error.ioError e)+      System.Directory.renameFile old new+     ])+  )+])++# WORKAROUND_fileModes+# --------------------+# Figure out how to set unix permissions on a file (or creates a dummy+# function for this).++AC_DEFUN([WORKAROUND_fileModes],[+  EXPORT_WORKAROUND([           fileMode, getFileStatus, setFileMode, ])+  GHC_CHECK_MODULE(System.Posix.Files( fileMode, getFileStatus, setFileMode ), unix, getFileStatus "",+    IMPORT_WORKAROUND([import System.Posix.Files(fileMode,getFileStatus,setFileMode)]),+    CODE_WORKAROUND([+fileMode :: () -> ()+fileMode _ = ()+getFileStatus :: FilePath -> IO ()+getFileStatus _ = return ()+setFileMode :: FilePath -> () -> IO ()+setFileMode _ _ = return ()+])+  )+])++# WORKAROUND_executable+# --------------------+# Figure out how to make a file executable (or test if it is).++AC_DEFUN([WORKAROUND_executable],[+  EXPORT_WORKAROUND([           setExecutable, ])+  GHC_CHECK_MODULE(System.Posix.Files( fileMode, getFileStatus, setFileMode, setFileCreationMask ),+                   unix, getFileStatus "",+    IMPORT_WORKAROUND([+import System.Posix.Files (fileMode,getFileStatus, setFileMode, nullFileMode,+                           setFileCreationMask,+                           ownerReadMode, ownerWriteMode, ownerExecuteMode,+                           groupReadMode, groupWriteMode, groupExecuteMode,+                           otherReadMode, otherWriteMode, otherExecuteMode)+import Data.Bits ( (.&.), (.|.), complement )++setExecutable :: FilePath -> Bool -> IO ()+setExecutable f ex =+  do st <- getFileStatus f+     umask <- setFileCreationMask 0+     setFileCreationMask umask+     let rw = fileMode st .&.+              (ownerReadMode .|. ownerWriteMode .|.+               groupReadMode .|. groupWriteMode .|.+               otherReadMode .|. otherWriteMode)+         total = if ex then rw .|.+                           ((ownerExecuteMode .|. groupExecuteMode .|. otherExecuteMode)+                            .&. complement umask)+                       else rw+     setFileMode f total+]),+    CODE_WORKAROUND([+setExecutable :: FilePath -> Bool -> IO ()+setExecutable _ _ = return ()+])+  )+])++# WORKAROUND_openFd+# -----------------------+# Work around changing openFd function+AC_DEFUN([WORKAROUND_openFd],[+  EXPORT_WORKAROUND([           openFd, ])+  AC_MSG_CHECKING([GHC.Handle.openFd])+  TRY_RUN_GHC([+import GHC.Handle ( openFd )+import IO ( IOMode(..))++main = openFd 1 Nothing "stdout" WriteMode True False+    ],+     AC_MSG_RESULT([okay])+     IMPORT_WORKAROUND([import GHC.Handle( openFd )]),+     AC_MSG_RESULT([NOT old API])+     AC_MSG_CHECKING([GHC.Handle.openFd new API])+     TRY_RUN_GHC([+import GHC.Handle ( openFd )+import IO ( IOMode(..))++main = openFd 1 Nothing False "stdout" WriteMode True+      ],+      AC_MSG_RESULT([okay])+      IMPORT_WORKAROUND([import qualified GHC.Handle ( openFd )+import System.IO ( Handle, IOMode )+import System.Posix.Internals ( FDType )+])+      CODE_WORKAROUND([[+{-+Work around change in the GHC.Handle.openFd API.+-}+openFd :: Int -> Maybe FDType -> FilePath -> IOMode -> Bool -> Bool -> IO Handle+openFd fd x y z a b = GHC.Handle.openFd fd x b y z a+        ]]),+       AC_MSG_RESULT([NOT 'new' API])+       AC_MSG_CHECKING([GHC.Handle.fdToHandle' API])+       TRY_RUN_GHC([+import GHC.Handle ( fdToHandle' )+import IO ( IOMode(..) )++main = fdToHandle' 1 Nothing False "stdout" WriteMode True+       ],+       AC_MSG_RESULT([okay])+       IMPORT_WORKAROUND([import qualified GHC.Handle ( fdToHandle' )+import System.IO ( Handle, IOMode )+import System.Posix.Internals ( FDType )+])+       CODE_WORKAROUND([[+{-+Work around renaming of GHC.Handle.openFd and change in its API.+-}+openFd :: Int -> Maybe FDType -> FilePath -> IOMode -> Bool -> Bool -> IO Handle+openFd fd x y z a b = GHC.Handle.fdToHandle' (fromIntegral fd) x b y z a+        ]]),+       AC_MSG_RESULT([failed])+       AC_MSG_ERROR([Couldnt figure out how to call GHC.Handle.openFd!])+    )+  )+)])++
+ autoconf.mk view
@@ -0,0 +1,129 @@+#+# System properties as determined by Autoconf.+#+# autoconf.mk.  Generated from autoconf.mk.in by configure.+#+prefix		:= /home/gwern/bin+exec_prefix	:= ${prefix}+bindir		:= ${exec_prefix}/bin+sbindir		:= ${exec_prefix}/sbin+datarootdir	:= ${prefix}/share+mandir		:= ${datarootdir}/man+datadir		:= ${datarootdir}+sysconfdir	:= ${prefix}/etc+libexecdir	:= ${exec_prefix}/libexec+PACKAGE_TARNAME := darcs+docdir		:= ${datarootdir}/doc/${PACKAGE_TARNAME}++DARCS_VERSION	:= 2.0.2+DEFS		:= -DPACKAGE_NAME=\"darcs\" -DPACKAGE_TARNAME=\"darcs\" -DPACKAGE_VERSION=\"2.0.2\" -DPACKAGE_STRING=\"darcs\ 2.0.2\" -DPACKAGE_BUGREPORT=\"bugs@darcs.net\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_HTTP=1+CPPFLAGS	:=  -DHAVE_BYTESTRING -DHAVE_CURSES -DPACKAGE_NAME=\"darcs\" -DPACKAGE_TARNAME=\"darcs\" -DPACKAGE_VERSION=\"2.0.2\" -DPACKAGE_STRING=\"darcs\ 2.0.2\" -DPACKAGE_BUGREPORT=\"bugs@darcs.net\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_HTTP=1+CFLAGS		:=  -O2+OPTCCFLAGS      := $(addprefix -optc,$(CFLAGS) $(CPPFLAGS)) $(addprefix -opta,$(CFLAGS))+LDFLAGS		:= +OPTLLDFLAGS     := $(addprefix -optl,$(LDFLAGS))+LIBS            := -lcurses  -lz+OPTLLIBS        := $(filter-out -%,$(LIBS)) $(addprefix -optl,$(filter -%,$(LIBS)))+GHCFLAGS	:=  -threaded -package regex-compat -package HTTP -package QuickCheck -package html -O2 -funbox-strict-fields  -DHAVE_BYTESTRING -DHAVE_CURSES -DPACKAGE_NAME=\"darcs\" -DPACKAGE_TARNAME=\"darcs\" -DPACKAGE_VERSION=\"2.0.2\" -DPACKAGE_STRING=\"darcs\ 2.0.2\" -DPACKAGE_BUGREPORT=\"bugs@darcs.net\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_HTTP=1+USE_GNULIBSHA1  := @USE_GNULIBSHA1@+HAVE_HTTP       := True+HAVE_CURSES     := True+HAVE_LIBCURL    := @HAVE_LIBCURL@+HAVE_LIBWWW     := @HAVE_LIBWWW@+HAVE_MAPI       := False+HAVE_TERMIO_H   := @HAVE_TERMIO_H@+SYS             := other+WXFLAGS		:= @WXFLAGS@++GHC		:= ghc+INSTALL		:= /usr/bin/install -c+INSTALL_DATA   	:= ${INSTALL} -m 644+LATEX		:= latex+PDFLATEX	:= pdflatex+DVIPS		:= dvips+MAKEMANUAL      := latex2html -split +1 -dir doc/manual src/darcs.tex+PREPROCHTML	:= --html+MAKENSIS	:= +HADDOCK_VERSION := 2++all : config darcs doc/darcs.1 AUTHORS ChangeLog doc/manual/darcs.ps doc/manual/darcs.pdf doc/manual/patch-theory.pdf doc/manual/index.html microbench++install: all installbin installdocs++ifeq ('yes', 'yes')+release/STATE src/ThisVersion.lhs doc/index.html: _darcs/hashed_inventory src/ThisVersion.lhs.in \+				release/determine_release_state.pl \+                                doc/index.html.in config.status+	perl release/determine_release_state.pl $(DARCS_VERSION) > release/STATE+src/Context.hs: _darcs/hashed_inventory stringify config.command+	PATH=".:$$PATH" darcs changes --context | cat config.command - \+		| ./stringify Context context > $@+else+src/ThisVersion.lhs doc/index.html: release/STATE src/ThisVersion.lhs.in \+				release/determine_release_state.pl \+                                doc/index.html.in config.status+	perl release/determine_release_state.pl $(DARCS_VERSION)+release/STATE:+	echo -n $(DARCS_VERSION) '(unknown)' > $@+src/Context.hs: stringify+	test -f $@ || echo unknown | ./stringify Context context > $@+endif++darcs-stable.tar.gz: dist+	ln -sf "darcs-$(DARCS_VERSION).tar.gz" $@+.PHONY: darcs-stable.tar.gz++.SUFFIXES:++ghcflags_deslash=$(GHCFLAGS_$(subst /,__,$(1)))+ghcflags_fancy=$(if $(call ghcflags_deslash,$(1)),$(call ghcflags_deslash,$(1)),$(GHCFLAGS))++ifdef VERBOSE+ANNOUNCE_GHC=$(GHC)+else+ANNOUNCE_GHC=@echo [ghc] $@; $(GHC)+endif++%.o : %.lhs+	$(ANNOUNCE_GHC) $(call ghcflags_fancy,$@) -c $<++# stupid rule to do nothing to make a .hi file from a .o file.+%.hi : %.o++%.o : %.hs+	$(ANNOUNCE_GHC) $(call ghcflags_fancy,$@) -c $<+	@touch $*.hi++%.o : %.c+	$(ANNOUNCE_GHC) $(CPPFLAGS) $(OPTCCFLAGS) -c $<++% : src/%.lhs+	rm -f Main.hi Main.o+	$(ANNOUNCE_GHC) $(GHCFLAGS) $(OPTLLDFLAGS) -o $@ $^ $(OPTLLIBS)++% : src/%.hs+	rm -f Main.hi Main.o+	$(ANNOUNCE_GHC) $(GHCFLAGS) $(OPTLLDFLAGS) -o $@ $^ $(OPTLLIBS)++%.hs : %.hsc+	hsc2hs $<++%.hi : %.o+	@:++%.dvi : %.tex+	(cd `dirname $<` && $(LATEX) `basename $<`)+	while grep >/dev/null "Rerun to get cross-references right" $*.log; do \+	    (cd `dirname $<` && $(LATEX) `basename $<`); \+	done+++%.pdf : %.tex+	(cd `dirname $<` && $(PDFLATEX) `basename $<`)+	while grep >/dev/null "Rerun to get cross-references right" $*.log; do \+	    (cd `dirname $<` && $(PDFLATEX) `basename $<`); \+	done++%.ps : %.dvi+	$(DVIPS) -t letter -o $@ $<+
+ autoconf.mk.in view
@@ -0,0 +1,129 @@+#+# System properties as determined by Autoconf.+#+# @configure_input@+#+prefix		:= @prefix@+exec_prefix	:= @exec_prefix@+bindir		:= @bindir@+sbindir		:= @sbindir@+datarootdir	:= @datarootdir@+mandir		:= @mandir@+datadir		:= @datadir@+sysconfdir	:= @sysconfdir@+libexecdir	:= @libexecdir@+PACKAGE_TARNAME := @PACKAGE_TARNAME@+docdir		:= @docdir@++DARCS_VERSION	:= @DARCS_VERSION@+DEFS		:= @DEFS@+CPPFLAGS	:= @CPPFLAGS@ @DEFS@+CFLAGS		:= @CFLAGS@+OPTCCFLAGS      := $(addprefix -optc,$(CFLAGS) $(CPPFLAGS)) $(addprefix -opta,$(CFLAGS))+LDFLAGS		:= @LDFLAGS@+OPTLLDFLAGS     := $(addprefix -optl,$(LDFLAGS))+LIBS            := @LIBS@+OPTLLIBS        := $(filter-out -%,$(LIBS)) $(addprefix -optl,$(filter -%,$(LIBS)))+GHCFLAGS	:= @GHCFLAGS@ @CPPFLAGS@ @DEFS@+USE_GNULIBSHA1  := @USE_GNULIBSHA1@+HAVE_HTTP       := @HAVE_HTTP@+HAVE_CURSES     := @HAVE_CURSES@+HAVE_LIBCURL    := @HAVE_LIBCURL@+HAVE_LIBWWW     := @HAVE_LIBWWW@+HAVE_MAPI       := @HAVE_MAPI@+HAVE_TERMIO_H   := @HAVE_TERMIO_H@+SYS             := @SYS@+WXFLAGS		:= @WXFLAGS@++GHC		:= @GHC@+INSTALL		:= @INSTALL@+INSTALL_DATA   	:= @INSTALL_DATA@+LATEX		:= @LATEX@+PDFLATEX	:= @PDFLATEX@+DVIPS		:= @DVIPS@+MAKEMANUAL      := @MAKEMANUAL@+PREPROCHTML	:= @PREPROCHTML@+MAKENSIS	:= @MAKENSIS@+HADDOCK_VERSION := @HADDOCK_VERSION@++all : config @TARGETS@ microbench++install: all @INSTALLWHAT@++ifeq ('@I_AM_IN_REPO@', 'yes')+release/STATE src/ThisVersion.lhs doc/index.html: _darcs/hashed_inventory src/ThisVersion.lhs.in \+				release/determine_release_state.pl \+                                doc/index.html.in config.status+	perl release/determine_release_state.pl $(DARCS_VERSION) > release/STATE+src/Context.hs: _darcs/hashed_inventory stringify config.command+	PATH=".:$$PATH" darcs changes --context | cat config.command - \+		| ./stringify Context context > $@+else+src/ThisVersion.lhs doc/index.html: release/STATE src/ThisVersion.lhs.in \+				release/determine_release_state.pl \+                                doc/index.html.in config.status+	perl release/determine_release_state.pl $(DARCS_VERSION)+release/STATE:+	echo -n $(DARCS_VERSION) '(unknown)' > $@+src/Context.hs: stringify+	test -f $@ || echo unknown | ./stringify Context context > $@+endif++darcs-stable.tar.gz: dist+	ln -sf "darcs-$(DARCS_VERSION).tar.gz" $@+.PHONY: darcs-stable.tar.gz++.SUFFIXES:++ghcflags_deslash=$(GHCFLAGS_$(subst /,__,$(1)))+ghcflags_fancy=$(if $(call ghcflags_deslash,$(1)),$(call ghcflags_deslash,$(1)),$(GHCFLAGS))++ifdef VERBOSE+ANNOUNCE_GHC=$(GHC)+else+ANNOUNCE_GHC=@echo [ghc] $@; $(GHC)+endif++%.o : %.lhs+	$(ANNOUNCE_GHC) $(call ghcflags_fancy,$@) -c $<++# stupid rule to do nothing to make a .hi file from a .o file.+%.hi : %.o++%.o : %.hs+	$(ANNOUNCE_GHC) $(call ghcflags_fancy,$@) -c $<+	@touch $*.hi++%.o : %.c+	$(ANNOUNCE_GHC) $(CPPFLAGS) $(OPTCCFLAGS) -c $<++% : src/%.lhs+	rm -f Main.hi Main.o+	$(ANNOUNCE_GHC) $(GHCFLAGS) $(OPTLLDFLAGS) -o $@ $^ $(OPTLLIBS)++% : src/%.hs+	rm -f Main.hi Main.o+	$(ANNOUNCE_GHC) $(GHCFLAGS) $(OPTLLDFLAGS) -o $@ $^ $(OPTLLIBS)++%.hs : %.hsc+	hsc2hs $<++%.hi : %.o+	@:++%.dvi : %.tex+	(cd `dirname $<` && $(LATEX) `basename $<`)+	while grep >/dev/null "Rerun to get cross-references right" $*.log; do \+	    (cd `dirname $<` && $(LATEX) `basename $<`); \+	done+++%.pdf : %.tex+	(cd `dirname $<` && $(PDFLATEX) `basename $<`)+	while grep >/dev/null "Rerun to get cross-references right" $*.log; do \+	    (cd `dirname $<` && $(PDFLATEX) `basename $<`); \+	done++%.ps : %.dvi+	$(DVIPS) -t letter -o $@ $<+
+ configure view
@@ -0,0 +1,9034 @@+#! /bin/sh+# Guess values for system-dependent variables and create Makefiles.+# Generated by GNU Autoconf 2.61 for darcs 2.0.2.+#+# Report bugs to <bugs@darcs.net>.+#+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,+# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.+# This configure script is free software; the Free Software Foundation+# gives unlimited permission to copy, distribute and modify it.+## --------------------- ##+## M4sh Initialization.  ##+## --------------------- ##++# Be more Bourne compatible+DUALCASE=1; export DUALCASE # for MKS sh+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then+  emulate sh+  NULLCMD=:+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which+  # is contrary to our usage.  Disable this feature.+  alias -g '${1+"$@"}'='"$@"'+  setopt NO_GLOB_SUBST+else+  case `(set -o) 2>/dev/null` in+  *posix*) set -o posix ;;+esac++fi+++++# PATH needs CR+# Avoid depending upon Character Ranges.+as_cr_letters='abcdefghijklmnopqrstuvwxyz'+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'+as_cr_Letters=$as_cr_letters$as_cr_LETTERS+as_cr_digits='0123456789'+as_cr_alnum=$as_cr_Letters$as_cr_digits++# The user is always right.+if test "${PATH_SEPARATOR+set}" != set; then+  echo "#! /bin/sh" >conf$$.sh+  echo  "exit 0"   >>conf$$.sh+  chmod +x conf$$.sh+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then+    PATH_SEPARATOR=';'+  else+    PATH_SEPARATOR=:+  fi+  rm -f conf$$.sh+fi++# Support unset when possible.+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then+  as_unset=unset+else+  as_unset=false+fi+++# IFS+# We need space, tab and new line, in precisely that order.  Quoting is+# there to prevent editors from complaining about space-tab.+# (If _AS_PATH_WALK were called with IFS unset, it would disable word+# splitting by setting IFS to empty value.)+as_nl='+'+IFS=" ""	$as_nl"++# Find who we are.  Look in the path if we contain no directory separator.+case $0 in+  *[\\/]* ) as_myself=$0 ;;+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break+done+IFS=$as_save_IFS++     ;;+esac+# We did not find ourselves, most probably we were run as `sh COMMAND'+# in which case we are not to be found in the path.+if test "x$as_myself" = x; then+  as_myself=$0+fi+if test ! -f "$as_myself"; then+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2+  { (exit 1); exit 1; }+fi++# Work around bugs in pre-3.0 UWIN ksh.+for as_var in ENV MAIL MAILPATH+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var+done+PS1='$ '+PS2='> '+PS4='+ '++# NLS nuisances.+for as_var in \+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \+  LC_TELEPHONE LC_TIME+do+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then+    eval $as_var=C; export $as_var+  else+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var+  fi+done++# Required to use basename.+if expr a : '\(a\)' >/dev/null 2>&1 &&+   test "X`expr 00001 : '.*\(...\)'`" = X001; then+  as_expr=expr+else+  as_expr=false+fi++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then+  as_basename=basename+else+  as_basename=false+fi+++# Name of the executable.+as_me=`$as_basename -- "$0" ||+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \+	 X"$0" : 'X\(//\)$' \| \+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||+echo X/"$0" |+    sed '/^.*\/\([^/][^/]*\)\/*$/{+	    s//\1/+	    q+	  }+	  /^X\/\(\/\/\)$/{+	    s//\1/+	    q+	  }+	  /^X\/\(\/\).*/{+	    s//\1/+	    q+	  }+	  s/.*/./; q'`++# CDPATH.+$as_unset CDPATH+++if test "x$CONFIG_SHELL" = x; then+  if (eval ":") 2>/dev/null; then+  as_have_required=yes+else+  as_have_required=no+fi++  if test $as_have_required = yes && 	 (eval ":+(as_func_return () {+  (exit \$1)+}+as_func_success () {+  as_func_return 0+}+as_func_failure () {+  as_func_return 1+}+as_func_ret_success () {+  return 0+}+as_func_ret_failure () {+  return 1+}++exitcode=0+if as_func_success; then+  :+else+  exitcode=1+  echo as_func_success failed.+fi++if as_func_failure; then+  exitcode=1+  echo as_func_failure succeeded.+fi++if as_func_ret_success; then+  :+else+  exitcode=1+  echo as_func_ret_success failed.+fi++if as_func_ret_failure; then+  exitcode=1+  echo as_func_ret_failure succeeded.+fi++if ( set x; as_func_ret_success y && test x = \"\$1\" ); then+  :+else+  exitcode=1+  echo positional parameters were not saved.+fi++test \$exitcode = 0) || { (exit 1); exit 1; }++(+  as_lineno_1=\$LINENO+  as_lineno_2=\$LINENO+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }+") 2> /dev/null; then+  :+else+  as_candidate_shells=+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  case $as_dir in+	 /*)+	   for as_base in sh bash ksh sh5; do+	     as_candidate_shells="$as_candidate_shells $as_dir/$as_base"+	   done;;+       esac+done+IFS=$as_save_IFS+++      for as_shell in $as_candidate_shells $SHELL; do+	 # Try only shells that exist, to save several forks.+	 if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&+		{ ("$as_shell") 2> /dev/null <<\_ASEOF+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then+  emulate sh+  NULLCMD=:+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which+  # is contrary to our usage.  Disable this feature.+  alias -g '${1+"$@"}'='"$@"'+  setopt NO_GLOB_SUBST+else+  case `(set -o) 2>/dev/null` in+  *posix*) set -o posix ;;+esac++fi+++:+_ASEOF+}; then+  CONFIG_SHELL=$as_shell+	       as_have_required=yes+	       if { "$as_shell" 2> /dev/null <<\_ASEOF+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then+  emulate sh+  NULLCMD=:+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which+  # is contrary to our usage.  Disable this feature.+  alias -g '${1+"$@"}'='"$@"'+  setopt NO_GLOB_SUBST+else+  case `(set -o) 2>/dev/null` in+  *posix*) set -o posix ;;+esac++fi+++:+(as_func_return () {+  (exit $1)+}+as_func_success () {+  as_func_return 0+}+as_func_failure () {+  as_func_return 1+}+as_func_ret_success () {+  return 0+}+as_func_ret_failure () {+  return 1+}++exitcode=0+if as_func_success; then+  :+else+  exitcode=1+  echo as_func_success failed.+fi++if as_func_failure; then+  exitcode=1+  echo as_func_failure succeeded.+fi++if as_func_ret_success; then+  :+else+  exitcode=1+  echo as_func_ret_success failed.+fi++if as_func_ret_failure; then+  exitcode=1+  echo as_func_ret_failure succeeded.+fi++if ( set x; as_func_ret_success y && test x = "$1" ); then+  :+else+  exitcode=1+  echo positional parameters were not saved.+fi++test $exitcode = 0) || { (exit 1); exit 1; }++(+  as_lineno_1=$LINENO+  as_lineno_2=$LINENO+  test "x$as_lineno_1" != "x$as_lineno_2" &&+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }++_ASEOF+}; then+  break+fi++fi++      done++      if test "x$CONFIG_SHELL" != x; then+  for as_var in BASH_ENV ENV+        do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var+        done+        export CONFIG_SHELL+        exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}+fi+++    if test $as_have_required = no; then+  echo This script requires a shell more modern than all the+      echo shells that I found on your system.  Please install a+      echo modern shell, or manually run the script under such a+      echo shell if you do have one.+      { (exit 1); exit 1; }+fi+++fi++fi++++(eval "as_func_return () {+  (exit \$1)+}+as_func_success () {+  as_func_return 0+}+as_func_failure () {+  as_func_return 1+}+as_func_ret_success () {+  return 0+}+as_func_ret_failure () {+  return 1+}++exitcode=0+if as_func_success; then+  :+else+  exitcode=1+  echo as_func_success failed.+fi++if as_func_failure; then+  exitcode=1+  echo as_func_failure succeeded.+fi++if as_func_ret_success; then+  :+else+  exitcode=1+  echo as_func_ret_success failed.+fi++if as_func_ret_failure; then+  exitcode=1+  echo as_func_ret_failure succeeded.+fi++if ( set x; as_func_ret_success y && test x = \"\$1\" ); then+  :+else+  exitcode=1+  echo positional parameters were not saved.+fi++test \$exitcode = 0") || {+  echo No shell found that supports shell functions.+  echo Please tell autoconf@gnu.org about your system,+  echo including any error possibly output before this+  echo message+}++++  as_lineno_1=$LINENO+  as_lineno_2=$LINENO+  test "x$as_lineno_1" != "x$as_lineno_2" &&+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {++  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO+  # uniformly replaced by the line number.  The first 'sed' inserts a+  # line-number line after each line using $LINENO; the second 'sed'+  # does the real work.  The second script uses 'N' to pair each+  # line-number line with the line containing $LINENO, and appends+  # trailing '-' during substitution so that $LINENO is not a special+  # case at line end.+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the+  # scripts with optimization help from Paolo Bonzini.  Blame Lee+  # E. McMahon (1931-1989) for sed's syntax.  :-)+  sed -n '+    p+    /[$]LINENO/=+  ' <$as_myself |+    sed '+      s/[$]LINENO.*/&-/+      t lineno+      b+      :lineno+      N+      :loop+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/+      t loop+      s/-\n.*//+    ' >$as_me.lineno &&+  chmod +x "$as_me.lineno" ||+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2+   { (exit 1); exit 1; }; }++  # Don't try to exec as it changes $[0], causing all sort of problems+  # (the dirname of $[0] is not the place where we might find the+  # original and so on.  Autoconf is especially sensitive to this).+  . "./$as_me.lineno"+  # Exit status is that of the last command.+  exit+}+++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then+  as_dirname=dirname+else+  as_dirname=false+fi++ECHO_C= ECHO_N= ECHO_T=+case `echo -n x` in+-n*)+  case `echo 'x\c'` in+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.+  *)   ECHO_C='\c';;+  esac;;+*)+  ECHO_N='-n';;+esac++if expr a : '\(a\)' >/dev/null 2>&1 &&+   test "X`expr 00001 : '.*\(...\)'`" = X001; then+  as_expr=expr+else+  as_expr=false+fi++rm -f conf$$ conf$$.exe conf$$.file+if test -d conf$$.dir; then+  rm -f conf$$.dir/conf$$.file+else+  rm -f conf$$.dir+  mkdir conf$$.dir+fi+echo >conf$$.file+if ln -s conf$$.file conf$$ 2>/dev/null; then+  as_ln_s='ln -s'+  # ... but there are two gotchas:+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.+  # In both cases, we have to default to `cp -p'.+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||+    as_ln_s='cp -p'+elif ln conf$$.file conf$$ 2>/dev/null; then+  as_ln_s=ln+else+  as_ln_s='cp -p'+fi+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file+rmdir conf$$.dir 2>/dev/null++if mkdir -p . 2>/dev/null; then+  as_mkdir_p=:+else+  test -d ./-p && rmdir ./-p+  as_mkdir_p=false+fi++if test -x / >/dev/null 2>&1; then+  as_test_x='test -x'+else+  if ls -dL / >/dev/null 2>&1; then+    as_ls_L_option=L+  else+    as_ls_L_option=+  fi+  as_test_x='+    eval sh -c '\''+      if test -d "$1"; then+        test -d "$1/.";+      else+	case $1 in+        -*)set "./$1";;+	esac;+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in+	???[sx]*):;;*)false;;esac;fi+    '\'' sh+  '+fi+as_executable_p=$as_test_x++# Sed expression to map a string onto a valid CPP name.+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"++# Sed expression to map a string onto a valid variable name.+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"++++exec 7<&0 </dev/null 6>&1++# Name of the host.+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,+# so uname gets run too.+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`++#+# Initializations.+#+ac_default_prefix=/usr/local+ac_clean_files=+ac_config_libobj_dir=.+LIBOBJS=+cross_compiling=no+subdirs=+MFLAGS=+MAKEFLAGS=+SHELL=${CONFIG_SHELL-/bin/sh}++# Identity of this package.+PACKAGE_NAME='darcs'+PACKAGE_TARNAME='darcs'+PACKAGE_VERSION='2.0.2'+PACKAGE_STRING='darcs 2.0.2'+PACKAGE_BUGREPORT='bugs@darcs.net'++ac_unique_file="src/darcs.lhs"+# Factoring default headers for most tests.+ac_includes_default="\+#include <stdio.h>+#ifdef HAVE_SYS_TYPES_H+# include <sys/types.h>+#endif+#ifdef HAVE_SYS_STAT_H+# include <sys/stat.h>+#endif+#ifdef STDC_HEADERS+# include <stdlib.h>+# include <stddef.h>+#else+# ifdef HAVE_STDLIB_H+#  include <stdlib.h>+# endif+#endif+#ifdef HAVE_STRING_H+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H+#  include <memory.h>+# endif+# include <string.h>+#endif+#ifdef HAVE_STRINGS_H+# include <strings.h>+#endif+#ifdef HAVE_INTTYPES_H+# include <inttypes.h>+#endif+#ifdef HAVE_STDINT_H+# include <stdint.h>+#endif+#ifdef HAVE_UNISTD_H+# include <unistd.h>+#endif"++ac_subst_vars='SHELL+PATH_SEPARATOR+PACKAGE_NAME+PACKAGE_TARNAME+PACKAGE_VERSION+PACKAGE_STRING+PACKAGE_BUGREPORT+exec_prefix+prefix+program_transform_name+bindir+sbindir+libexecdir+datarootdir+datadir+sysconfdir+sharedstatedir+localstatedir+includedir+oldincludedir+docdir+infodir+htmldir+dvidir+pdfdir+psdir+libdir+localedir+mandir+DEFS+ECHO_C+ECHO_N+ECHO_T+LIBS+build_alias+host_alias+target_alias+DARCS_VERSION+DARCS+I_AM_IN_REPO+INSTALL_PROGRAM+INSTALL_SCRIPT+INSTALL_DATA+CC+CFLAGS+LDFLAGS+CPPFLAGS+ac_ct_CC+EXEEXT+OBJEXT+CPP+GREP+EGREP+SYS+GHC+GHCFLAGS+HAVE_HTTP+GHC_SEPARATOR+USE_MMAP+LATEX+PDFLATEX+DVIPS+LATEX2HTML+HTLATEX+HEVEA+TARGETS+MAKEMANUAL+INSTALLWHAT+PREPROCHTML+SENDMAIL+HAVE_SENDMAIL+HAVE_MAPI+USE_COLOR+HAVE_CURSES+DIFF+MAKENSIS+BIGENDIAN+HADDOCK+HADDOCK_VERSION+LIBOBJS+LTLIBOBJS'+ac_subst_files=''+      ac_precious_vars='build_alias+host_alias+target_alias+CC+CFLAGS+LDFLAGS+LIBS+CPPFLAGS+CPP'+++# Initialize some variables set by options.+ac_init_help=+ac_init_version=false+# The variables have the same names as the options, with+# dashes changed to underlines.+cache_file=/dev/null+exec_prefix=NONE+no_create=+no_recursion=+prefix=NONE+program_prefix=NONE+program_suffix=NONE+program_transform_name=s,x,x,+silent=+site=+srcdir=+verbose=+x_includes=NONE+x_libraries=NONE++# Installation directory options.+# These are left unexpanded so users can "make install exec_prefix=/foo"+# and all the variables that are supposed to be based on exec_prefix+# by default will actually change.+# Use braces instead of parens because sh, perl, etc. also accept them.+# (The list follows the same order as the GNU Coding Standards.)+bindir='${exec_prefix}/bin'+sbindir='${exec_prefix}/sbin'+libexecdir='${exec_prefix}/libexec'+datarootdir='${prefix}/share'+datadir='${datarootdir}'+sysconfdir='${prefix}/etc'+sharedstatedir='${prefix}/com'+localstatedir='${prefix}/var'+includedir='${prefix}/include'+oldincludedir='/usr/include'+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'+infodir='${datarootdir}/info'+htmldir='${docdir}'+dvidir='${docdir}'+pdfdir='${docdir}'+psdir='${docdir}'+libdir='${exec_prefix}/lib'+localedir='${datarootdir}/locale'+mandir='${datarootdir}/man'++ac_prev=+ac_dashdash=+for ac_option+do+  # If the previous option needs an argument, assign it.+  if test -n "$ac_prev"; then+    eval $ac_prev=\$ac_option+    ac_prev=+    continue+  fi++  case $ac_option in+  *=*)	ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;+  *)	ac_optarg=yes ;;+  esac++  # Accept the important Cygnus configure options, so we can diagnose typos.++  case $ac_dashdash$ac_option in+  --)+    ac_dashdash=yes ;;++  -bindir | --bindir | --bindi | --bind | --bin | --bi)+    ac_prev=bindir ;;+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)+    bindir=$ac_optarg ;;++  -build | --build | --buil | --bui | --bu)+    ac_prev=build_alias ;;+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)+    build_alias=$ac_optarg ;;++  -cache-file | --cache-file | --cache-fil | --cache-fi \+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)+    ac_prev=cache_file ;;+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)+    cache_file=$ac_optarg ;;++  --config-cache | -C)+    cache_file=config.cache ;;++  -datadir | --datadir | --datadi | --datad)+    ac_prev=datadir ;;+  -datadir=* | --datadir=* | --datadi=* | --datad=*)+    datadir=$ac_optarg ;;++  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \+  | --dataroo | --dataro | --datar)+    ac_prev=datarootdir ;;+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)+    datarootdir=$ac_optarg ;;++  -disable-* | --disable-*)+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`+    # Reject names that are not valid shell variable names.+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2+   { (exit 1); exit 1; }; }+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`+    eval enable_$ac_feature=no ;;++  -docdir | --docdir | --docdi | --doc | --do)+    ac_prev=docdir ;;+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)+    docdir=$ac_optarg ;;++  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)+    ac_prev=dvidir ;;+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)+    dvidir=$ac_optarg ;;++  -enable-* | --enable-*)+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`+    # Reject names that are not valid shell variable names.+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2+   { (exit 1); exit 1; }; }+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`+    eval enable_$ac_feature=\$ac_optarg ;;++  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \+  | --exec | --exe | --ex)+    ac_prev=exec_prefix ;;+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \+  | --exec=* | --exe=* | --ex=*)+    exec_prefix=$ac_optarg ;;++  -gas | --gas | --ga | --g)+    # Obsolete; use --with-gas.+    with_gas=yes ;;++  -help | --help | --hel | --he | -h)+    ac_init_help=long ;;+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)+    ac_init_help=recursive ;;+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)+    ac_init_help=short ;;++  -host | --host | --hos | --ho)+    ac_prev=host_alias ;;+  -host=* | --host=* | --hos=* | --ho=*)+    host_alias=$ac_optarg ;;++  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)+    ac_prev=htmldir ;;+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \+  | --ht=*)+    htmldir=$ac_optarg ;;++  -includedir | --includedir | --includedi | --included | --include \+  | --includ | --inclu | --incl | --inc)+    ac_prev=includedir ;;+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \+  | --includ=* | --inclu=* | --incl=* | --inc=*)+    includedir=$ac_optarg ;;++  -infodir | --infodir | --infodi | --infod | --info | --inf)+    ac_prev=infodir ;;+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)+    infodir=$ac_optarg ;;++  -libdir | --libdir | --libdi | --libd)+    ac_prev=libdir ;;+  -libdir=* | --libdir=* | --libdi=* | --libd=*)+    libdir=$ac_optarg ;;++  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \+  | --libexe | --libex | --libe)+    ac_prev=libexecdir ;;+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \+  | --libexe=* | --libex=* | --libe=*)+    libexecdir=$ac_optarg ;;++  -localedir | --localedir | --localedi | --localed | --locale)+    ac_prev=localedir ;;+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)+    localedir=$ac_optarg ;;++  -localstatedir | --localstatedir | --localstatedi | --localstated \+  | --localstate | --localstat | --localsta | --localst | --locals)+    ac_prev=localstatedir ;;+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)+    localstatedir=$ac_optarg ;;++  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)+    ac_prev=mandir ;;+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)+    mandir=$ac_optarg ;;++  -nfp | --nfp | --nf)+    # Obsolete; use --without-fp.+    with_fp=no ;;++  -no-create | --no-create | --no-creat | --no-crea | --no-cre \+  | --no-cr | --no-c | -n)+    no_create=yes ;;++  -no-recursion | --no-recursion | --no-recursio | --no-recursi \+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)+    no_recursion=yes ;;++  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \+  | --oldin | --oldi | --old | --ol | --o)+    ac_prev=oldincludedir ;;+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)+    oldincludedir=$ac_optarg ;;++  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)+    ac_prev=prefix ;;+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)+    prefix=$ac_optarg ;;++  -program-prefix | --program-prefix | --program-prefi | --program-pref \+  | --program-pre | --program-pr | --program-p)+    ac_prev=program_prefix ;;+  -program-prefix=* | --program-prefix=* | --program-prefi=* \+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)+    program_prefix=$ac_optarg ;;++  -program-suffix | --program-suffix | --program-suffi | --program-suff \+  | --program-suf | --program-su | --program-s)+    ac_prev=program_suffix ;;+  -program-suffix=* | --program-suffix=* | --program-suffi=* \+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)+    program_suffix=$ac_optarg ;;++  -program-transform-name | --program-transform-name \+  | --program-transform-nam | --program-transform-na \+  | --program-transform-n | --program-transform- \+  | --program-transform | --program-transfor \+  | --program-transfo | --program-transf \+  | --program-trans | --program-tran \+  | --progr-tra | --program-tr | --program-t)+    ac_prev=program_transform_name ;;+  -program-transform-name=* | --program-transform-name=* \+  | --program-transform-nam=* | --program-transform-na=* \+  | --program-transform-n=* | --program-transform-=* \+  | --program-transform=* | --program-transfor=* \+  | --program-transfo=* | --program-transf=* \+  | --program-trans=* | --program-tran=* \+  | --progr-tra=* | --program-tr=* | --program-t=*)+    program_transform_name=$ac_optarg ;;++  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)+    ac_prev=pdfdir ;;+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)+    pdfdir=$ac_optarg ;;++  -psdir | --psdir | --psdi | --psd | --ps)+    ac_prev=psdir ;;+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)+    psdir=$ac_optarg ;;++  -q | -quiet | --quiet | --quie | --qui | --qu | --q \+  | -silent | --silent | --silen | --sile | --sil)+    silent=yes ;;++  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)+    ac_prev=sbindir ;;+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \+  | --sbi=* | --sb=*)+    sbindir=$ac_optarg ;;++  -sharedstatedir | --sharedstatedir | --sharedstatedi \+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \+  | --sharedst | --shareds | --shared | --share | --shar \+  | --sha | --sh)+    ac_prev=sharedstatedir ;;+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \+  | --sha=* | --sh=*)+    sharedstatedir=$ac_optarg ;;++  -site | --site | --sit)+    ac_prev=site ;;+  -site=* | --site=* | --sit=*)+    site=$ac_optarg ;;++  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)+    ac_prev=srcdir ;;+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)+    srcdir=$ac_optarg ;;++  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \+  | --syscon | --sysco | --sysc | --sys | --sy)+    ac_prev=sysconfdir ;;+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)+    sysconfdir=$ac_optarg ;;++  -target | --target | --targe | --targ | --tar | --ta | --t)+    ac_prev=target_alias ;;+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)+    target_alias=$ac_optarg ;;++  -v | -verbose | --verbose | --verbos | --verbo | --verb)+    verbose=yes ;;++  -version | --version | --versio | --versi | --vers | -V)+    ac_init_version=: ;;++  -with-* | --with-*)+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`+    # Reject names that are not valid shell variable names.+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&+      { echo "$as_me: error: invalid package name: $ac_package" >&2+   { (exit 1); exit 1; }; }+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`+    eval with_$ac_package=\$ac_optarg ;;++  -without-* | --without-*)+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`+    # Reject names that are not valid shell variable names.+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&+      { echo "$as_me: error: invalid package name: $ac_package" >&2+   { (exit 1); exit 1; }; }+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`+    eval with_$ac_package=no ;;++  --x)+    # Obsolete; use --with-x.+    with_x=yes ;;++  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \+  | --x-incl | --x-inc | --x-in | --x-i)+    ac_prev=x_includes ;;+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)+    x_includes=$ac_optarg ;;++  -x-libraries | --x-libraries | --x-librarie | --x-librari \+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)+    ac_prev=x_libraries ;;+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)+    x_libraries=$ac_optarg ;;++  -*) { echo "$as_me: error: unrecognized option: $ac_option+Try \`$0 --help' for more information." >&2+   { (exit 1); exit 1; }; }+    ;;++  *=*)+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`+    # Reject names that are not valid shell variable names.+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2+   { (exit 1); exit 1; }; }+    eval $ac_envvar=\$ac_optarg+    export $ac_envvar ;;++  *)+    # FIXME: should be removed in autoconf 3.0.+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}+    ;;++  esac+done++if test -n "$ac_prev"; then+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`+  { echo "$as_me: error: missing argument to $ac_option" >&2+   { (exit 1); exit 1; }; }+fi++# Be sure to have absolute directory names.+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \+		datadir sysconfdir sharedstatedir localstatedir includedir \+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \+		libdir localedir mandir+do+  eval ac_val=\$$ac_var+  case $ac_val in+    [\\/$]* | ?:[\\/]* )  continue;;+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;+  esac+  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2+   { (exit 1); exit 1; }; }+done++# There might be people who depend on the old broken behavior: `$host'+# used to hold the argument of --host etc.+# FIXME: To remove some day.+build=$build_alias+host=$host_alias+target=$target_alias++# FIXME: To remove some day.+if test "x$host_alias" != x; then+  if test "x$build_alias" = x; then+    cross_compiling=maybe+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.+    If a cross compiler is detected then cross compile mode will be used." >&2+  elif test "x$build_alias" != "x$host_alias"; then+    cross_compiling=yes+  fi+fi++ac_tool_prefix=+test -n "$host_alias" && ac_tool_prefix=$host_alias-++test "$silent" = yes && exec 6>/dev/null+++ac_pwd=`pwd` && test -n "$ac_pwd" &&+ac_ls_di=`ls -di .` &&+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||+  { echo "$as_me: error: Working directory cannot be determined" >&2+   { (exit 1); exit 1; }; }+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||+  { echo "$as_me: error: pwd does not report name of working directory" >&2+   { (exit 1); exit 1; }; }+++# Find the source files, if location was not specified.+if test -z "$srcdir"; then+  ac_srcdir_defaulted=yes+  # Try the directory containing this script, then the parent directory.+  ac_confdir=`$as_dirname -- "$0" ||+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \+	 X"$0" : 'X\(//\)[^/]' \| \+	 X"$0" : 'X\(//\)$' \| \+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||+echo X"$0" |+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{+	    s//\1/+	    q+	  }+	  /^X\(\/\/\)[^/].*/{+	    s//\1/+	    q+	  }+	  /^X\(\/\/\)$/{+	    s//\1/+	    q+	  }+	  /^X\(\/\).*/{+	    s//\1/+	    q+	  }+	  s/.*/./; q'`+  srcdir=$ac_confdir+  if test ! -r "$srcdir/$ac_unique_file"; then+    srcdir=..+  fi+else+  ac_srcdir_defaulted=no+fi+if test ! -r "$srcdir/$ac_unique_file"; then+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."+  { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2+   { (exit 1); exit 1; }; }+fi+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"+ac_abs_confdir=`(+	cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2+   { (exit 1); exit 1; }; }+	pwd)`+# When building in place, set srcdir=.+if test "$ac_abs_confdir" = "$ac_pwd"; then+  srcdir=.+fi+# Remove unnecessary trailing slashes from srcdir.+# Double slashes in file names in object file debugging info+# mess up M-x gdb in Emacs.+case $srcdir in+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;+esac+for ac_var in $ac_precious_vars; do+  eval ac_env_${ac_var}_set=\${${ac_var}+set}+  eval ac_env_${ac_var}_value=\$${ac_var}+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}+  eval ac_cv_env_${ac_var}_value=\$${ac_var}+done++#+# Report the --help message.+#+if test "$ac_init_help" = "long"; then+  # Omit some internal or obsolete options to make the list less imposing.+  # This message is too long to be a string in the A/UX 3.1 sh.+  cat <<_ACEOF+\`configure' configures darcs 2.0.2 to adapt to many kinds of systems.++Usage: $0 [OPTION]... [VAR=VALUE]...++To assign environment variables (e.g., CC, CFLAGS...), specify them as+VAR=VALUE.  See below for descriptions of some of the useful variables.++Defaults for the options are specified in brackets.++Configuration:+  -h, --help              display this help and exit+      --help=short        display options specific to this package+      --help=recursive    display the short help of all the included packages+  -V, --version           display version information and exit+  -q, --quiet, --silent   do not print \`checking...' messages+      --cache-file=FILE   cache test results in FILE [disabled]+  -C, --config-cache      alias for \`--cache-file=config.cache'+  -n, --no-create         do not create output files+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']++Installation directories:+  --prefix=PREFIX         install architecture-independent files in PREFIX+			  [$ac_default_prefix]+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX+			  [PREFIX]++By default, \`make install' will install all the files in+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify+an installation prefix other than \`$ac_default_prefix' using \`--prefix',+for instance \`--prefix=\$HOME'.++For better control, use the options below.++Fine tuning of the installation directories:+  --bindir=DIR           user executables [EPREFIX/bin]+  --sbindir=DIR          system admin executables [EPREFIX/sbin]+  --libexecdir=DIR       program executables [EPREFIX/libexec]+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]+  --libdir=DIR           object code libraries [EPREFIX/lib]+  --includedir=DIR       C header files [PREFIX/include]+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]+  --datarootdir=DIR      read-only arch.-independent data root [PREFIX/share]+  --datadir=DIR          read-only architecture-independent data [DATAROOTDIR]+  --infodir=DIR          info documentation [DATAROOTDIR/info]+  --localedir=DIR        locale-dependent data [DATAROOTDIR/locale]+  --mandir=DIR           man documentation [DATAROOTDIR/man]+  --docdir=DIR           documentation root [DATAROOTDIR/doc/darcs]+  --htmldir=DIR          html documentation [DOCDIR]+  --dvidir=DIR           dvi documentation [DOCDIR]+  --pdfdir=DIR           pdf documentation [DOCDIR]+  --psdir=DIR            ps documentation [DOCDIR]+_ACEOF++  cat <<\_ACEOF+_ACEOF+fi++if test -n "$ac_init_help"; then+  case $ac_init_help in+     short | recursive ) echo "Configuration of darcs 2.0.2:";;+   esac+  cat <<\_ACEOF++Optional Features:+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]+  --enable-profile        enable profiling+  --disable-threaded      don't compile with threaded runtime+  --disable-bytestring    do not use bytestring, even if it is present+  --disable-optimize      disable optimization+  --enable-hpc            enable Haskell Program Coverage+  --disable-mmap          do not use mmap (use this flag if you get bus+                          errors)+  --enable-debug-ps       enable PackedString debug mode+  --disable-color         do not use ansi color escapes+  --enable-curl-debug     enable libcurl debug mode+  --enable-libwww-debug   enable libwww debug mode+  --without-curses        do not use libcurses++Optional Packages:+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)+  --without-docs          do not try to build docs+  --with-sendmail=PATHTOSENDMAIL+  --with-static-libs      link with static versions of libraries+  --with-type-witnesses   use GADT type witnesses (EXPERIMENTAL!)++  --without-libcurl       do not use libcurl+  --with-curl=<DIR>       use curl installed in directory <DIR>+  --with-curl-pipelining  use curl pipelining (requires libcurl >= 7.18.0)+  --with-libwww           use libwww++Some influential environment variables:+  CC          C compiler command+  CFLAGS      C compiler flags+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a+              nonstandard directory <lib dir>+  LIBS        libraries to pass to the linker, e.g. -l<library>+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if+              you have headers in a nonstandard directory <include dir>+  CPP         C preprocessor++Use these variables to override the choices made by `configure' or to help+it to find libraries and programs with nonstandard names/locations.++Report bugs to <bugs@darcs.net>.+_ACEOF+ac_status=$?+fi++if test "$ac_init_help" = "recursive"; then+  # If there are subdirs, report their specific --help.+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue+    test -d "$ac_dir" || continue+    ac_builddir=.++case "$ac_dir" in+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;+*)+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`+  # A ".." for each directory in $ac_dir_suffix.+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`+  case $ac_top_builddir_sub in+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;+  esac ;;+esac+ac_abs_top_builddir=$ac_pwd+ac_abs_builddir=$ac_pwd$ac_dir_suffix+# for backward compatibility:+ac_top_builddir=$ac_top_build_prefix++case $srcdir in+  .)  # We are building in place.+    ac_srcdir=.+    ac_top_srcdir=$ac_top_builddir_sub+    ac_abs_top_srcdir=$ac_pwd ;;+  [\\/]* | ?:[\\/]* )  # Absolute name.+    ac_srcdir=$srcdir$ac_dir_suffix;+    ac_top_srcdir=$srcdir+    ac_abs_top_srcdir=$srcdir ;;+  *) # Relative name.+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix+    ac_top_srcdir=$ac_top_build_prefix$srcdir+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;+esac+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix++    cd "$ac_dir" || { ac_status=$?; continue; }+    # Check for guested configure.+    if test -f "$ac_srcdir/configure.gnu"; then+      echo &&+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive+    elif test -f "$ac_srcdir/configure"; then+      echo &&+      $SHELL "$ac_srcdir/configure" --help=recursive+    else+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2+    fi || ac_status=$?+    cd "$ac_pwd" || { ac_status=$?; break; }+  done+fi++test -n "$ac_init_help" && exit $ac_status+if $ac_init_version; then+  cat <<\_ACEOF+darcs configure 2.0.2+generated by GNU Autoconf 2.61++Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.+This configure script is free software; the Free Software Foundation+gives unlimited permission to copy, distribute and modify it.+_ACEOF+  exit+fi+cat >config.log <<_ACEOF+This file contains any messages produced by compilers while+running configure, to aid debugging if configure makes a mistake.++It was created by darcs $as_me 2.0.2, which was+generated by GNU Autoconf 2.61.  Invocation command line was++  $ $0 $@++_ACEOF+exec 5>>config.log+{+cat <<_ASUNAME+## --------- ##+## Platform. ##+## --------- ##++hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`+uname -m = `(uname -m) 2>/dev/null || echo unknown`+uname -r = `(uname -r) 2>/dev/null || echo unknown`+uname -s = `(uname -s) 2>/dev/null || echo unknown`+uname -v = `(uname -v) 2>/dev/null || echo unknown`++/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`++/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`++_ASUNAME++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  echo "PATH: $as_dir"+done+IFS=$as_save_IFS++} >&5++cat >&5 <<_ACEOF+++## ----------- ##+## Core tests. ##+## ----------- ##++_ACEOF+++# Keep a trace of the command line.+# Strip out --no-create and --no-recursion so they do not pile up.+# Strip out --silent because we don't want to record it for future runs.+# Also quote any args containing shell meta-characters.+# Make two passes to allow for proper duplicate-argument suppression.+ac_configure_args=+ac_configure_args0=+ac_configure_args1=+ac_must_keep_next=false+for ac_pass in 1 2+do+  for ac_arg+  do+    case $ac_arg in+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \+    | -silent | --silent | --silen | --sile | --sil)+      continue ;;+    *\'*)+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;+    esac+    case $ac_pass in+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;+    2)+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"+      if test $ac_must_keep_next = true; then+	ac_must_keep_next=false # Got value, back to normal.+      else+	case $ac_arg in+	  *=* | --config-cache | -C | -disable-* | --disable-* \+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \+	  | -with-* | --with-* | -without-* | --without-* | --x)+	    case "$ac_configure_args0 " in+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;+	    esac+	    ;;+	  -* ) ac_must_keep_next=true ;;+	esac+      fi+      ac_configure_args="$ac_configure_args '$ac_arg'"+      ;;+    esac+  done+done+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }++# When interrupted or exit'd, cleanup temporary files, and complete+# config.log.  We remove comments because anyway the quotes in there+# would cause problems or look ugly.+# WARNING: Use '\'' to represent an apostrophe within the trap.+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.+trap 'exit_status=$?+  # Save into config.log some information that might help in debugging.+  {+    echo++    cat <<\_ASBOX+## ---------------- ##+## Cache variables. ##+## ---------------- ##+_ASBOX+    echo+    # The following way of writing the cache mishandles newlines in values,+(+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do+    eval ac_val=\$$ac_var+    case $ac_val in #(+    *${as_nl}*)+      case $ac_var in #(+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;+      esac+      case $ac_var in #(+      _ | IFS | as_nl) ;; #(+      *) $as_unset $ac_var ;;+      esac ;;+    esac+  done+  (set) 2>&1 |+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(+    *${as_nl}ac_space=\ *)+      sed -n \+	"s/'\''/'\''\\\\'\'''\''/g;+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"+      ;; #(+    *)+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"+      ;;+    esac |+    sort+)+    echo++    cat <<\_ASBOX+## ----------------- ##+## Output variables. ##+## ----------------- ##+_ASBOX+    echo+    for ac_var in $ac_subst_vars+    do+      eval ac_val=\$$ac_var+      case $ac_val in+      *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;+      esac+      echo "$ac_var='\''$ac_val'\''"+    done | sort+    echo++    if test -n "$ac_subst_files"; then+      cat <<\_ASBOX+## ------------------- ##+## File substitutions. ##+## ------------------- ##+_ASBOX+      echo+      for ac_var in $ac_subst_files+      do+	eval ac_val=\$$ac_var+	case $ac_val in+	*\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;+	esac+	echo "$ac_var='\''$ac_val'\''"+      done | sort+      echo+    fi++    if test -s confdefs.h; then+      cat <<\_ASBOX+## ----------- ##+## confdefs.h. ##+## ----------- ##+_ASBOX+      echo+      cat confdefs.h+      echo+    fi+    test "$ac_signal" != 0 &&+      echo "$as_me: caught signal $ac_signal"+    echo "$as_me: exit $exit_status"+  } >&5+  rm -f core *.core core.conftest.* &&+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&+    exit $exit_status+' 0+for ac_signal in 1 2 13 15; do+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal+done+ac_signal=0++# confdefs.h avoids OS command line length limits that DEFS can exceed.+rm -f -r conftest* confdefs.h++# Predefined preprocessor variables.++cat >>confdefs.h <<_ACEOF+#define PACKAGE_NAME "$PACKAGE_NAME"+_ACEOF+++cat >>confdefs.h <<_ACEOF+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"+_ACEOF+++cat >>confdefs.h <<_ACEOF+#define PACKAGE_VERSION "$PACKAGE_VERSION"+_ACEOF+++cat >>confdefs.h <<_ACEOF+#define PACKAGE_STRING "$PACKAGE_STRING"+_ACEOF+++cat >>confdefs.h <<_ACEOF+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"+_ACEOF+++# Let the site file select an alternate cache file if it wants to.+# Prefer explicitly selected file to automatically selected ones.+if test -n "$CONFIG_SITE"; then+  set x "$CONFIG_SITE"+elif test "x$prefix" != xNONE; then+  set x "$prefix/share/config.site" "$prefix/etc/config.site"+else+  set x "$ac_default_prefix/share/config.site" \+	"$ac_default_prefix/etc/config.site"+fi+shift+for ac_site_file+do+  if test -r "$ac_site_file"; then+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5+echo "$as_me: loading site script $ac_site_file" >&6;}+    sed 's/^/| /' "$ac_site_file" >&5+    . "$ac_site_file"+  fi+done++if test -r "$cache_file"; then+  # Some versions of bash will fail to source /dev/null (special+  # files actually), so we avoid doing that.+  if test -f "$cache_file"; then+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5+echo "$as_me: loading cache $cache_file" >&6;}+    case $cache_file in+      [\\/]* | ?:[\\/]* ) . "$cache_file";;+      *)                      . "./$cache_file";;+    esac+  fi+else+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5+echo "$as_me: creating cache $cache_file" >&6;}+  >$cache_file+fi++# Check that the precious variables saved in the cache have kept the same+# value.+ac_cache_corrupted=false+for ac_var in $ac_precious_vars; do+  eval ac_old_set=\$ac_cv_env_${ac_var}_set+  eval ac_new_set=\$ac_env_${ac_var}_set+  eval ac_old_val=\$ac_cv_env_${ac_var}_value+  eval ac_new_val=\$ac_env_${ac_var}_value+  case $ac_old_set,$ac_new_set in+    set,)+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}+      ac_cache_corrupted=: ;;+    ,set)+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}+      ac_cache_corrupted=: ;;+    ,);;+    *)+      if test "x$ac_old_val" != "x$ac_new_val"; then+	{ echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}+	{ echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5+echo "$as_me:   former value:  $ac_old_val" >&2;}+	{ echo "$as_me:$LINENO:   current value: $ac_new_val" >&5+echo "$as_me:   current value: $ac_new_val" >&2;}+	ac_cache_corrupted=:+      fi;;+  esac+  # Pass precious variables to config.status.+  if test "$ac_new_set" = set; then+    case $ac_new_val in+    *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;+    *) ac_arg=$ac_var=$ac_new_val ;;+    esac+    case " $ac_configure_args " in+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;+    esac+  fi+done+if $ac_cache_corrupted; then+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5+echo "$as_me: error: changes in the environment can compromise the build" >&2;}+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}+   { (exit 1); exit 1; }; }+fi++++++++++++++++++++++++++ac_ext=c+ac_cpp='$CPP $CPPFLAGS'+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'+ac_compiler_gnu=$ac_cv_c_compiler_gnu++++++ac_cmdline_args="$*"+ac_config_commands="$ac_config_commands config.command"++++DARCS_VERSION=$PACKAGE_VERSION++++# Extract the first word of "darcs", so it can be a program name with args.+set dummy darcs; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_DARCS+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$DARCS"; then+  ac_cv_prog_DARCS="$DARCS" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_DARCS="darcs"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+DARCS=$ac_cv_prog_DARCS+if test -n "$DARCS"; then+  { echo "$as_me:$LINENO: result: $DARCS" >&5+echo "${ECHO_T}$DARCS" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++{ echo "$as_me:$LINENO: checking if we're in a darcs repository" >&5+echo $ECHO_N "checking if we're in a darcs repository... $ECHO_C" >&6; }+if test ! -z "$DARCS" && test -e "_darcs/hashed_inventory"; then+  I_AM_IN_REPO=yes+else+  I_AM_IN_REPO=no+fi+{ echo "$as_me:$LINENO: result: $I_AM_IN_REPO" >&5+echo "${ECHO_T}$I_AM_IN_REPO" >&6; }++++CFLAGS=$CFLAGS+++++ac_aux_dir=+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do+  if test -f "$ac_dir/install-sh"; then+    ac_aux_dir=$ac_dir+    ac_install_sh="$ac_aux_dir/install-sh -c"+    break+  elif test -f "$ac_dir/install.sh"; then+    ac_aux_dir=$ac_dir+    ac_install_sh="$ac_aux_dir/install.sh -c"+    break+  elif test -f "$ac_dir/shtool"; then+    ac_aux_dir=$ac_dir+    ac_install_sh="$ac_aux_dir/shtool install -c"+    break+  fi+done+if test -z "$ac_aux_dir"; then+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5+echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}+   { (exit 1); exit 1; }; }+fi++# These three variables are undocumented and unsupported,+# and are intended to be withdrawn in a future Autoconf release.+# They can cause serious problems if a builder's source tree is in a directory+# whose full name contains unusual characters.+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.+++# Find a good install program.  We prefer a C program (faster),+# so one script is as good as another.  But avoid the broken or+# incompatible versions:+# SysV /etc/install, /usr/sbin/install+# SunOS /usr/etc/install+# IRIX /sbin/install+# AIX /bin/install+# AmigaOS /C/install, which installs bootblocks on floppy discs+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag+# AFS /usr/afsws/bin/install, which mishandles nonexistent args+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"+# OS/2's system install, which has a completely different semantic+# ./install, which can be erroneously created by make from ./install.sh.+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }+if test -z "$INSTALL"; then+if test "${ac_cv_path_install+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  # Account for people who put trailing slashes in PATH elements.+case $as_dir/ in+  ./ | .// | /cC/* | \+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \+  /usr/ucb/* ) ;;+  *)+    # OSF1 and SCO ODT 3.0 have their own names for install.+    # Don't use installbsd from OSF since it installs stuff as root+    # by default.+    for ac_prog in ginstall scoinst install; do+      for ac_exec_ext in '' $ac_executable_extensions; do+	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then+	  if test $ac_prog = install &&+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then+	    # AIX install.  It has an incompatible calling convention.+	    :+	  elif test $ac_prog = install &&+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then+	    # program-specific install script used by HP pwplus--don't use.+	    :+	  else+	    ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"+	    break 3+	  fi+	fi+      done+    done+    ;;+esac+done+IFS=$as_save_IFS+++fi+  if test "${ac_cv_path_install+set}" = set; then+    INSTALL=$ac_cv_path_install+  else+    # As a last resort, use the slow shell script.  Don't cache a+    # value for INSTALL within a source directory, because that will+    # break other packages using the cache if that directory is+    # removed, or if the value is a relative name.+    INSTALL=$ac_install_sh+  fi+fi+{ echo "$as_me:$LINENO: result: $INSTALL" >&5+echo "${ECHO_T}$INSTALL" >&6; }++# Use test -z because SunOS4 sh mishandles braces in ${var-val}.+# It thinks the first close brace ends the variable substitution.+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'++test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'++test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'++++ac_ext=c+ac_cpp='$CPP $CPPFLAGS'+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'+ac_compiler_gnu=$ac_cv_c_compiler_gnu+if test -n "$ac_tool_prefix"; then+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.+set dummy ${ac_tool_prefix}gcc; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_CC+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$CC"; then+  ac_cv_prog_CC="$CC" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_CC="${ac_tool_prefix}gcc"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+CC=$ac_cv_prog_CC+if test -n "$CC"; then+  { echo "$as_me:$LINENO: result: $CC" >&5+echo "${ECHO_T}$CC" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++fi+if test -z "$ac_cv_prog_CC"; then+  ac_ct_CC=$CC+  # Extract the first word of "gcc", so it can be a program name with args.+set dummy gcc; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$ac_ct_CC"; then+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_ac_ct_CC="gcc"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+ac_ct_CC=$ac_cv_prog_ac_ct_CC+if test -n "$ac_ct_CC"; then+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5+echo "${ECHO_T}$ac_ct_CC" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi++  if test "x$ac_ct_CC" = x; then+    CC=""+  else+    case $cross_compiling:$ac_tool_warned in+yes:)+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools+whose name does not start with the host triplet.  If you think this+configuration is useful to you, please write to autoconf@gnu.org." >&5+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools+whose name does not start with the host triplet.  If you think this+configuration is useful to you, please write to autoconf@gnu.org." >&2;}+ac_tool_warned=yes ;;+esac+    CC=$ac_ct_CC+  fi+else+  CC="$ac_cv_prog_CC"+fi++if test -z "$CC"; then+          if test -n "$ac_tool_prefix"; then+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.+set dummy ${ac_tool_prefix}cc; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_CC+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$CC"; then+  ac_cv_prog_CC="$CC" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_CC="${ac_tool_prefix}cc"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+CC=$ac_cv_prog_CC+if test -n "$CC"; then+  { echo "$as_me:$LINENO: result: $CC" >&5+echo "${ECHO_T}$CC" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++  fi+fi+if test -z "$CC"; then+  # Extract the first word of "cc", so it can be a program name with args.+set dummy cc; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_CC+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$CC"; then+  ac_cv_prog_CC="$CC" # Let the user override the test.+else+  ac_prog_rejected=no+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then+       ac_prog_rejected=yes+       continue+     fi+    ac_cv_prog_CC="cc"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++if test $ac_prog_rejected = yes; then+  # We found a bogon in the path, so make sure we never use it.+  set dummy $ac_cv_prog_CC+  shift+  if test $# != 0; then+    # We chose a different compiler from the bogus one.+    # However, it has the same basename, so the bogon will be chosen+    # first if we set CC to just the basename; use the full file name.+    shift+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"+  fi+fi+fi+fi+CC=$ac_cv_prog_CC+if test -n "$CC"; then+  { echo "$as_me:$LINENO: result: $CC" >&5+echo "${ECHO_T}$CC" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++fi+if test -z "$CC"; then+  if test -n "$ac_tool_prefix"; then+  for ac_prog in cl.exe+  do+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.+set dummy $ac_tool_prefix$ac_prog; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_CC+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$CC"; then+  ac_cv_prog_CC="$CC" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+CC=$ac_cv_prog_CC+if test -n "$CC"; then+  { echo "$as_me:$LINENO: result: $CC" >&5+echo "${ECHO_T}$CC" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++    test -n "$CC" && break+  done+fi+if test -z "$CC"; then+  ac_ct_CC=$CC+  for ac_prog in cl.exe+do+  # Extract the first word of "$ac_prog", so it can be a program name with args.+set dummy $ac_prog; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$ac_ct_CC"; then+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_ac_ct_CC="$ac_prog"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+ac_ct_CC=$ac_cv_prog_ac_ct_CC+if test -n "$ac_ct_CC"; then+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5+echo "${ECHO_T}$ac_ct_CC" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++  test -n "$ac_ct_CC" && break+done++  if test "x$ac_ct_CC" = x; then+    CC=""+  else+    case $cross_compiling:$ac_tool_warned in+yes:)+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools+whose name does not start with the host triplet.  If you think this+configuration is useful to you, please write to autoconf@gnu.org." >&5+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools+whose name does not start with the host triplet.  If you think this+configuration is useful to you, please write to autoconf@gnu.org." >&2;}+ac_tool_warned=yes ;;+esac+    CC=$ac_ct_CC+  fi+fi++fi+++test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH+See \`config.log' for more details." >&5+echo "$as_me: error: no acceptable C compiler found in \$PATH+See \`config.log' for more details." >&2;}+   { (exit 1); exit 1; }; }++# Provide some information about the compiler.+echo "$as_me:$LINENO: checking for C compiler version" >&5+ac_compiler=`set X $ac_compile; echo $2`+{ (ac_try="$ac_compiler --version >&5"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compiler --version >&5") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }+{ (ac_try="$ac_compiler -v >&5"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compiler -v >&5") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }+{ (ac_try="$ac_compiler -V >&5"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compiler -V >&5") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }++cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++int+main ()+{++  ;+  return 0;+}+_ACEOF+ac_clean_files_save=$ac_clean_files+ac_clean_files="$ac_clean_files a.out a.exe b.out"+# Try to create an executable without -o first, disregard a.out.+# It will help us diagnose broken compilers, and finding out an intuition+# of exeext.+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`+#+# List of possible output files, starting from the most likely.+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)+# only as a last resort.  b.out is created by i960 compilers.+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'+#+# The IRIX 6 linker writes into existing files which may not be+# executable, retaining their permissions.  Remove them first so a+# subsequent execution test works.+ac_rmfiles=+for ac_file in $ac_files+do+  case $ac_file in+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;+  esac+done+rm -f $ac_rmfiles++if { (ac_try="$ac_link_default"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_link_default") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; then+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'+# in a Makefile.  We should not override ac_cv_exeext if it was cached,+# so that the user can short-circuit this test for compilers unknown to+# Autoconf.+for ac_file in $ac_files ''+do+  test -f "$ac_file" || continue+  case $ac_file in+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj )+	;;+    [ab].out )+	# We found the default executable, but exeext='' is most+	# certainly right.+	break;;+    *.* )+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;+	then :; else+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`+	fi+	# We set ac_cv_exeext here because the later test for it is not+	# safe: cross compilers may not add the suffix if given an `-o'+	# argument, so we may need to know it at that point already.+	# Even if this section looks crufty: it has the advantage of+	# actually working.+	break;;+    * )+	break;;+  esac+done+test "$ac_cv_exeext" = no && ac_cv_exeext=++else+  ac_file=''+fi++{ echo "$as_me:$LINENO: result: $ac_file" >&5+echo "${ECHO_T}$ac_file" >&6; }+if test -z "$ac_file"; then+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++{ { echo "$as_me:$LINENO: error: C compiler cannot create executables+See \`config.log' for more details." >&5+echo "$as_me: error: C compiler cannot create executables+See \`config.log' for more details." >&2;}+   { (exit 77); exit 77; }; }+fi++ac_exeext=$ac_cv_exeext++# Check that the compiler produces executables we can run.  If not, either+# the compiler is broken, or we cross compile.+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0+# If not cross compiling, check that we can run a simple program.+if test "$cross_compiling" != yes; then+  if { ac_try='./$ac_file'+  { (case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_try") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+    cross_compiling=no+  else+    if test "$cross_compiling" = maybe; then+	cross_compiling=yes+    else+	{ { echo "$as_me:$LINENO: error: cannot run C compiled programs.+If you meant to cross compile, use \`--host'.+See \`config.log' for more details." >&5+echo "$as_me: error: cannot run C compiled programs.+If you meant to cross compile, use \`--host'.+See \`config.log' for more details." >&2;}+   { (exit 1); exit 1; }; }+    fi+  fi+fi+{ echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++rm -f a.out a.exe conftest$ac_cv_exeext b.out+ac_clean_files=$ac_clean_files_save+# Check that the compiler produces executables we can run.  If not, either+# the compiler is broken, or we cross compile.+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5+echo "${ECHO_T}$cross_compiling" >&6; }++{ echo "$as_me:$LINENO: checking for suffix of executables" >&5+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }+if { (ac_try="$ac_link"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_link") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; then+  # If both `conftest.exe' and `conftest' are `present' (well, observable)+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will+# work properly (i.e., refer to `conftest.exe'), while it won't with+# `rm'.+for ac_file in conftest.exe conftest conftest.*; do+  test -f "$ac_file" || continue+  case $ac_file in+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`+	  break;;+    * ) break;;+  esac+done+else+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link+See \`config.log' for more details." >&5+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link+See \`config.log' for more details." >&2;}+   { (exit 1); exit 1; }; }+fi++rm -f conftest$ac_cv_exeext+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5+echo "${ECHO_T}$ac_cv_exeext" >&6; }++rm -f conftest.$ac_ext+EXEEXT=$ac_cv_exeext+ac_exeext=$EXEEXT+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }+if test "${ac_cv_objext+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++int+main ()+{++  ;+  return 0;+}+_ACEOF+rm -f conftest.o conftest.obj+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; then+  for ac_file in conftest.o conftest.obj conftest.*; do+  test -f "$ac_file" || continue;+  case $ac_file in+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;;+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`+       break;;+  esac+done+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile+See \`config.log' for more details." >&5+echo "$as_me: error: cannot compute suffix of object files: cannot compile+See \`config.log' for more details." >&2;}+   { (exit 1); exit 1; }; }+fi++rm -f conftest.$ac_cv_objext conftest.$ac_ext+fi+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5+echo "${ECHO_T}$ac_cv_objext" >&6; }+OBJEXT=$ac_cv_objext+ac_objext=$OBJEXT+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }+if test "${ac_cv_c_compiler_gnu+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++int+main ()+{+#ifndef __GNUC__+       choke me+#endif++  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  ac_compiler_gnu=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_compiler_gnu=no+fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+ac_cv_c_compiler_gnu=$ac_compiler_gnu++fi+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }+GCC=`test $ac_compiler_gnu = yes && echo yes`+ac_test_CFLAGS=${CFLAGS+set}+ac_save_CFLAGS=$CFLAGS+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }+if test "${ac_cv_prog_cc_g+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  ac_save_c_werror_flag=$ac_c_werror_flag+   ac_c_werror_flag=yes+   ac_cv_prog_cc_g=no+   CFLAGS="-g"+   cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++int+main ()+{++  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  ac_cv_prog_cc_g=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	CFLAGS=""+      cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++int+main ()+{++  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  :+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_c_werror_flag=$ac_save_c_werror_flag+	 CFLAGS="-g"+	 cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++int+main ()+{++  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  ac_cv_prog_cc_g=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5+++fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+   ac_c_werror_flag=$ac_save_c_werror_flag+fi+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }+if test "$ac_test_CFLAGS" = set; then+  CFLAGS=$ac_save_CFLAGS+elif test $ac_cv_prog_cc_g = yes; then+  if test "$GCC" = yes; then+    CFLAGS="-g -O2"+  else+    CFLAGS="-g"+  fi+else+  if test "$GCC" = yes; then+    CFLAGS="-O2"+  else+    CFLAGS=+  fi+fi+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }+if test "${ac_cv_prog_cc_c89+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  ac_cv_prog_cc_c89=no+ac_save_CC=$CC+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <stdarg.h>+#include <stdio.h>+#include <sys/types.h>+#include <sys/stat.h>+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */+struct buf { int x; };+FILE * (*rcsopen) (struct buf *, struct stat *, int);+static char *e (p, i)+     char **p;+     int i;+{+  return p[i];+}+static char *f (char * (*g) (char **, int), char **p, ...)+{+  char *s;+  va_list v;+  va_start (v,p);+  s = g (p, va_arg (v,int));+  va_end (v);+  return s;+}++/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has+   function prototypes and stuff, but not '\xHH' hex character constants.+   These don't provoke an error unfortunately, instead are silently treated+   as 'x'.  The following induces an error, until -std is added to get+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an+   array size at least.  It's necessary to write '\x00'==0 to get something+   that's true only with -std.  */+int osf4_cc_array ['\x00' == 0 ? 1 : -1];++/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters+   inside strings and character constants.  */+#define FOO(x) 'x'+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];++int test (int i, double x);+struct s1 {int (*f) (int a);};+struct s2 {int (*f) (double a);};+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);+int argc;+char **argv;+int+main ()+{+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];+  ;+  return 0;+}+_ACEOF+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"+do+  CC="$ac_save_CC $ac_arg"+  rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  ac_cv_prog_cc_c89=$ac_arg+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5+++fi++rm -f core conftest.err conftest.$ac_objext+  test "x$ac_cv_prog_cc_c89" != "xno" && break+done+rm -f conftest.$ac_ext+CC=$ac_save_CC++fi+# AC_CACHE_VAL+case "x$ac_cv_prog_cc_c89" in+  x)+    { echo "$as_me:$LINENO: result: none needed" >&5+echo "${ECHO_T}none needed" >&6; } ;;+  xno)+    { echo "$as_me:$LINENO: result: unsupported" >&5+echo "${ECHO_T}unsupported" >&6; } ;;+  *)+    CC="$CC $ac_cv_prog_cc_c89"+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;+esac+++ac_ext=c+ac_cpp='$CPP $CPPFLAGS'+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'+ac_compiler_gnu=$ac_cv_c_compiler_gnu+++ac_ext=c+ac_cpp='$CPP $CPPFLAGS'+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'+ac_compiler_gnu=$ac_cv_c_compiler_gnu+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }+# On Suns, sometimes $CPP names a directory.+if test -n "$CPP" && test -d "$CPP"; then+  CPP=+fi+if test -z "$CPP"; then+  if test "${ac_cv_prog_CPP+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+      # Double quotes because CPP needs to be expanded+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"+    do+      ac_preproc_ok=false+for ac_c_preproc_warn_flag in '' yes+do+  # Use a header file that comes with gcc, so configuring glibc+  # with a fresh cross-compiler works.+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since+  # <limits.h> exists even on freestanding compilers.+  # On the NeXT, cc -E runs the code through the compiler's parser,+  # not just through cpp. "Syntax error" is here to catch this case.+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#ifdef __STDC__+# include <limits.h>+#else+# include <assert.h>+#endif+		     Syntax error+_ACEOF+if { (ac_try="$ac_cpp conftest.$ac_ext"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } >/dev/null && {+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||+	 test ! -s conftest.err+       }; then+  :+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++  # Broken: fails on valid input.+continue+fi++rm -f conftest.err conftest.$ac_ext++  # OK, works on sane cases.  Now check whether nonexistent headers+  # can be detected and how.+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <ac_nonexistent.h>+_ACEOF+if { (ac_try="$ac_cpp conftest.$ac_ext"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } >/dev/null && {+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||+	 test ! -s conftest.err+       }; then+  # Broken: success on invalid input.+continue+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++  # Passes both tests.+ac_preproc_ok=:+break+fi++rm -f conftest.err conftest.$ac_ext++done+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.+rm -f conftest.err conftest.$ac_ext+if $ac_preproc_ok; then+  break+fi++    done+    ac_cv_prog_CPP=$CPP++fi+  CPP=$ac_cv_prog_CPP+else+  ac_cv_prog_CPP=$CPP+fi+{ echo "$as_me:$LINENO: result: $CPP" >&5+echo "${ECHO_T}$CPP" >&6; }+ac_preproc_ok=false+for ac_c_preproc_warn_flag in '' yes+do+  # Use a header file that comes with gcc, so configuring glibc+  # with a fresh cross-compiler works.+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since+  # <limits.h> exists even on freestanding compilers.+  # On the NeXT, cc -E runs the code through the compiler's parser,+  # not just through cpp. "Syntax error" is here to catch this case.+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#ifdef __STDC__+# include <limits.h>+#else+# include <assert.h>+#endif+		     Syntax error+_ACEOF+if { (ac_try="$ac_cpp conftest.$ac_ext"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } >/dev/null && {+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||+	 test ! -s conftest.err+       }; then+  :+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++  # Broken: fails on valid input.+continue+fi++rm -f conftest.err conftest.$ac_ext++  # OK, works on sane cases.  Now check whether nonexistent headers+  # can be detected and how.+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <ac_nonexistent.h>+_ACEOF+if { (ac_try="$ac_cpp conftest.$ac_ext"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } >/dev/null && {+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||+	 test ! -s conftest.err+       }; then+  # Broken: success on invalid input.+continue+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++  # Passes both tests.+ac_preproc_ok=:+break+fi++rm -f conftest.err conftest.$ac_ext++done+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.+rm -f conftest.err conftest.$ac_ext+if $ac_preproc_ok; then+  :+else+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check+See \`config.log' for more details." >&5+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check+See \`config.log' for more details." >&2;}+   { (exit 1); exit 1; }; }+fi++ac_ext=c+ac_cpp='$CPP $CPPFLAGS'+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'+ac_compiler_gnu=$ac_cv_c_compiler_gnu+++{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5+echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; }+if test "${ac_cv_path_GREP+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  # Extract the first word of "grep ggrep" to use in msg output+if test -z "$GREP"; then+set dummy grep ggrep; ac_prog_name=$2+if test "${ac_cv_path_GREP+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  ac_path_GREP_found=false+# Loop through the user's path and test for each of PROGNAME-LIST+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_prog in grep ggrep; do+  for ac_exec_ext in '' $ac_executable_extensions; do+    ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"+    { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue+    # Check for GNU ac_path_GREP and select it if it is found.+  # Check for GNU $ac_path_GREP+case `"$ac_path_GREP" --version 2>&1` in+*GNU*)+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;+*)+  ac_count=0+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"+  while :+  do+    cat "conftest.in" "conftest.in" >"conftest.tmp"+    mv "conftest.tmp" "conftest.in"+    cp "conftest.in" "conftest.nl"+    echo 'GREP' >> "conftest.nl"+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break+    ac_count=`expr $ac_count + 1`+    if test $ac_count -gt ${ac_path_GREP_max-0}; then+      # Best one so far, save it but keep looking for a better one+      ac_cv_path_GREP="$ac_path_GREP"+      ac_path_GREP_max=$ac_count+    fi+    # 10*(2^10) chars as input seems more than enough+    test $ac_count -gt 10 && break+  done+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;+esac+++    $ac_path_GREP_found && break 3+  done+done++done+IFS=$as_save_IFS+++fi++GREP="$ac_cv_path_GREP"+if test -z "$GREP"; then+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}+   { (exit 1); exit 1; }; }+fi++else+  ac_cv_path_GREP=$GREP+fi+++fi+{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5+echo "${ECHO_T}$ac_cv_path_GREP" >&6; }+ GREP="$ac_cv_path_GREP"+++{ echo "$as_me:$LINENO: checking for egrep" >&5+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }+if test "${ac_cv_path_EGREP+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1+   then ac_cv_path_EGREP="$GREP -E"+   else+     # Extract the first word of "egrep" to use in msg output+if test -z "$EGREP"; then+set dummy egrep; ac_prog_name=$2+if test "${ac_cv_path_EGREP+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  ac_path_EGREP_found=false+# Loop through the user's path and test for each of PROGNAME-LIST+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_prog in egrep; do+  for ac_exec_ext in '' $ac_executable_extensions; do+    ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"+    { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue+    # Check for GNU ac_path_EGREP and select it if it is found.+  # Check for GNU $ac_path_EGREP+case `"$ac_path_EGREP" --version 2>&1` in+*GNU*)+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;+*)+  ac_count=0+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"+  while :+  do+    cat "conftest.in" "conftest.in" >"conftest.tmp"+    mv "conftest.tmp" "conftest.in"+    cp "conftest.in" "conftest.nl"+    echo 'EGREP' >> "conftest.nl"+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break+    ac_count=`expr $ac_count + 1`+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then+      # Best one so far, save it but keep looking for a better one+      ac_cv_path_EGREP="$ac_path_EGREP"+      ac_path_EGREP_max=$ac_count+    fi+    # 10*(2^10) chars as input seems more than enough+    test $ac_count -gt 10 && break+  done+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;+esac+++    $ac_path_EGREP_found && break 3+  done+done++done+IFS=$as_save_IFS+++fi++EGREP="$ac_cv_path_EGREP"+if test -z "$EGREP"; then+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}+   { (exit 1); exit 1; }; }+fi++else+  ac_cv_path_EGREP=$EGREP+fi+++   fi+fi+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }+ EGREP="$ac_cv_path_EGREP"+++{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; }+if test "${ac_cv_header_stdc+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <stdlib.h>+#include <stdarg.h>+#include <string.h>+#include <float.h>++int+main ()+{++  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  ac_cv_header_stdc=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_cv_header_stdc=no+fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext++if test $ac_cv_header_stdc = yes; then+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <string.h>++_ACEOF+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |+  $EGREP "memchr" >/dev/null 2>&1; then+  :+else+  ac_cv_header_stdc=no+fi+rm -f conftest*++fi++if test $ac_cv_header_stdc = yes; then+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <stdlib.h>++_ACEOF+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |+  $EGREP "free" >/dev/null 2>&1; then+  :+else+  ac_cv_header_stdc=no+fi+rm -f conftest*++fi++if test $ac_cv_header_stdc = yes; then+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.+  if test "$cross_compiling" = yes; then+  :+else+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <ctype.h>+#include <stdlib.h>+#if ((' ' & 0x0FF) == 0x020)+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))+#else+# define ISLOWER(c) \+		   (('a' <= (c) && (c) <= 'i') \+		     || ('j' <= (c) && (c) <= 'r') \+		     || ('s' <= (c) && (c) <= 'z'))+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))+#endif++#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))+int+main ()+{+  int i;+  for (i = 0; i < 256; i++)+    if (XOR (islower (i), ISLOWER (i))+	|| toupper (i) != TOUPPER (i))+      return 2;+  return 0;+}+_ACEOF+rm -f conftest$ac_exeext+if { (ac_try="$ac_link"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_link") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'+  { (case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_try") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  :+else+  echo "$as_me: program exited with status $ac_status" >&5+echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++( exit $ac_status )+ac_cv_header_stdc=no+fi+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext+fi+++fi+fi+{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5+echo "${ECHO_T}$ac_cv_header_stdc" >&6; }+if test $ac_cv_header_stdc = yes; then++cat >>confdefs.h <<\_ACEOF+#define STDC_HEADERS 1+_ACEOF++fi++# On IRIX 5.3, sys/types and inttypes.h are conflicting.++++++++++for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \+		  inttypes.h stdint.h unistd.h+do+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`+{ echo "$as_me:$LINENO: checking for $ac_header" >&5+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+$ac_includes_default++#include <$ac_header>+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  eval "$as_ac_Header=yes"+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	eval "$as_ac_Header=no"+fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+fi+ac_res=`eval echo '${'$as_ac_Header'}'`+	       { echo "$as_me:$LINENO: result: $ac_res" >&5+echo "${ECHO_T}$ac_res" >&6; }+if test `eval echo '${'$as_ac_Header'}'` = yes; then+  cat >>confdefs.h <<_ACEOF+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1+_ACEOF++fi++done+++if test "${ac_cv_header_windows_h+set}" = set; then+  { echo "$as_me:$LINENO: checking for windows.h" >&5+echo $ECHO_N "checking for windows.h... $ECHO_C" >&6; }+if test "${ac_cv_header_windows_h+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+fi+{ echo "$as_me:$LINENO: result: $ac_cv_header_windows_h" >&5+echo "${ECHO_T}$ac_cv_header_windows_h" >&6; }+else+  # Is the header compilable?+{ echo "$as_me:$LINENO: checking windows.h usability" >&5+echo $ECHO_N "checking windows.h usability... $ECHO_C" >&6; }+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+$ac_includes_default+#include <windows.h>+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  ac_header_compiler=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_header_compiler=no+fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5+echo "${ECHO_T}$ac_header_compiler" >&6; }++# Is the header present?+{ echo "$as_me:$LINENO: checking windows.h presence" >&5+echo $ECHO_N "checking windows.h presence... $ECHO_C" >&6; }+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <windows.h>+_ACEOF+if { (ac_try="$ac_cpp conftest.$ac_ext"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } >/dev/null && {+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||+	 test ! -s conftest.err+       }; then+  ac_header_preproc=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++  ac_header_preproc=no+fi++rm -f conftest.err conftest.$ac_ext+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5+echo "${ECHO_T}$ac_header_preproc" >&6; }++# So?  What about this header?+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in+  yes:no: )+    { echo "$as_me:$LINENO: WARNING: windows.h: accepted by the compiler, rejected by the preprocessor!" >&5+echo "$as_me: WARNING: windows.h: accepted by the compiler, rejected by the preprocessor!" >&2;}+    { echo "$as_me:$LINENO: WARNING: windows.h: proceeding with the compiler's result" >&5+echo "$as_me: WARNING: windows.h: proceeding with the compiler's result" >&2;}+    ac_header_preproc=yes+    ;;+  no:yes:* )+    { echo "$as_me:$LINENO: WARNING: windows.h: present but cannot be compiled" >&5+echo "$as_me: WARNING: windows.h: present but cannot be compiled" >&2;}+    { echo "$as_me:$LINENO: WARNING: windows.h:     check for missing prerequisite headers?" >&5+echo "$as_me: WARNING: windows.h:     check for missing prerequisite headers?" >&2;}+    { echo "$as_me:$LINENO: WARNING: windows.h: see the Autoconf documentation" >&5+echo "$as_me: WARNING: windows.h: see the Autoconf documentation" >&2;}+    { echo "$as_me:$LINENO: WARNING: windows.h:     section \"Present But Cannot Be Compiled\"" >&5+echo "$as_me: WARNING: windows.h:     section \"Present But Cannot Be Compiled\"" >&2;}+    { echo "$as_me:$LINENO: WARNING: windows.h: proceeding with the preprocessor's result" >&5+echo "$as_me: WARNING: windows.h: proceeding with the preprocessor's result" >&2;}+    { echo "$as_me:$LINENO: WARNING: windows.h: in the future, the compiler will take precedence" >&5+echo "$as_me: WARNING: windows.h: in the future, the compiler will take precedence" >&2;}+    ( cat <<\_ASBOX+## ----------------------------- ##+## Report this to bugs@darcs.net ##+## ----------------------------- ##+_ASBOX+     ) | sed "s/^/$as_me: WARNING:     /" >&2+    ;;+esac+{ echo "$as_me:$LINENO: checking for windows.h" >&5+echo $ECHO_N "checking for windows.h... $ECHO_C" >&6; }+if test "${ac_cv_header_windows_h+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  ac_cv_header_windows_h=$ac_header_preproc+fi+{ echo "$as_me:$LINENO: result: $ac_cv_header_windows_h" >&5+echo "${ECHO_T}$ac_cv_header_windows_h" >&6; }++fi+if test $ac_cv_header_windows_h = yes; then+  SYS=windows+else+  SYS=other+fi++++++# Extract the first word of "ghc", so it can be a program name with args.+set dummy ghc; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_GHC+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$GHC"; then+  ac_cv_prog_GHC="$GHC" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_GHC="ghc"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+GHC=$ac_cv_prog_GHC+if test -n "$GHC"; then+  { echo "$as_me:$LINENO: result: $GHC" >&5+echo "${ECHO_T}$GHC" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++if test -z "$GHC"; then+    { { echo "$as_me:$LINENO: error: Cannot find ghc in your path; please set the GHC environment variable!!" >&5+echo "$as_me: error: Cannot find ghc in your path; please set the GHC environment variable!!" >&2;}+   { (exit 1); exit 1; }; }+fi++echo found `$GHC --version`++++cat << \EOF > conftest.hs+main = putStr "Hello world!\n"+-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  :+else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { { echo "$as_me:$LINENO: error: Compile failed." >&5+echo "$as_me: error: Compile failed." >&2;}+   { (exit 1); exit 1; }; }+fi++++{ echo "$as_me:$LINENO: checking whether to profile" >&5+echo $ECHO_N "checking whether to profile... $ECHO_C" >&6; }+# Check whether --enable-profile was given.+if test "${enable_profile+set}" = set; then+  enableval=$enable_profile; profile=$enableval+else+  profile=no+fi++{ echo "$as_me:$LINENO: result: $profile" >&5+echo "${ECHO_T}$profile" >&6; }++if test "$profile" = yes; then+   GHCFLAGS="$GHCFLAGS -prof -auto-all"+fi++{ echo "$as_me:$LINENO: checking whether to use the threaded runtime" >&5+echo $ECHO_N "checking whether to use the threaded runtime... $ECHO_C" >&6; }+# Check whether --enable-threaded was given.+if test "${enable_threaded+set}" = set; then+  enableval=$enable_threaded; { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+else+  MYOLDGHCFLAGS=$GHCFLAGS+               GHCFLAGS="$GHCFLAGS -threaded"++cat << \EOF > conftest.hs+main = putStr "Hello world!\n"+-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }+else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: failed, threaded runtime disabled" >&5+echo "${ECHO_T}failed, threaded runtime disabled" >&6; }+                 { echo "$as_me:$LINENO: WARNING: Unable to compile with threaded runtime!" >&5+echo "$as_me: WARNING: Unable to compile with threaded runtime!" >&2;}+                 GHCFLAGS=$MYOLDGHCFLAGS+fi+fi++++rm -f src/Workaround.hs.beginning src/Workaround.hs.ending+touch src/Workaround.hs.ending+cat << \EOF > src/Workaround.hs.prefix+{-# OPTIONS -w #-}+{- Workaround.hs++This file was created automatically by configure.  We disable warnings to+avoid issues with duplicate imports.++-}++module Workaround(+EOF+cat << \EOF > src/Workaround.hs.beginning+ ) where++EOF++++++cat << \EOF >> src/Workaround.hs.prefix+           openFd,+EOF++  { echo "$as_me:$LINENO: checking GHC.Handle.openFd" >&5+echo $ECHO_N "checking GHC.Handle.openFd... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs++import GHC.Handle ( openFd )+import IO ( IOMode(..))++main = openFd 1 Nothing "stdout" WriteMode True False++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  if { ac_try='./conftest'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  { echo "$as_me:$LINENO: result: okay" >&5+echo "${ECHO_T}okay" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import GHC.Handle( openFd )+EOF++else+  { echo "$as_me:$LINENO: result: NOT old API" >&5+echo "${ECHO_T}NOT old API" >&6; }+     { echo "$as_me:$LINENO: checking GHC.Handle.openFd new API" >&5+echo $ECHO_N "checking GHC.Handle.openFd new API... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs++import GHC.Handle ( openFd )+import IO ( IOMode(..))++main = openFd 1 Nothing False "stdout" WriteMode True++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  if { ac_try='./conftest'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  { echo "$as_me:$LINENO: result: okay" >&5+echo "${ECHO_T}okay" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified GHC.Handle ( openFd )+import System.IO ( Handle, IOMode )+import System.Posix.Internals ( FDType )++EOF+++cat << \EOF >> src/Workaround.hs.ending++{-+Work around change in the GHC.Handle.openFd API.+-}+openFd :: Int -> Maybe FDType -> FilePath -> IOMode -> Bool -> Bool -> IO Handle+openFd fd x y z a b = GHC.Handle.openFd fd x b y z a++EOF++else+  { echo "$as_me:$LINENO: result: NOT 'new' API" >&5+echo "${ECHO_T}NOT 'new' API" >&6; }+       { echo "$as_me:$LINENO: checking GHC.Handle.fdToHandle' API" >&5+echo $ECHO_N "checking GHC.Handle.fdToHandle' API... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs++import GHC.Handle ( fdToHandle' )+import IO ( IOMode(..) )++main = fdToHandle' 1 Nothing False "stdout" WriteMode True++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  if { ac_try='./conftest'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  { echo "$as_me:$LINENO: result: okay" >&5+echo "${ECHO_T}okay" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified GHC.Handle ( fdToHandle' )+import System.IO ( Handle, IOMode )+import System.Posix.Internals ( FDType )++EOF+++cat << \EOF >> src/Workaround.hs.ending++{-+Work around renaming of GHC.Handle.openFd and change in its API.+-}+openFd :: Int -> Maybe FDType -> FilePath -> IOMode -> Bool -> Bool -> IO Handle+openFd fd x y z a b = GHC.Handle.fdToHandle' (fromIntegral fd) x b y z a++EOF++else+  { echo "$as_me:$LINENO: result: failed" >&5+echo "${ECHO_T}failed" >&6; }+       { { echo "$as_me:$LINENO: error: Couldnt figure out how to call GHC.Handle.openFd!" >&5+echo "$as_me: error: Couldnt figure out how to call GHC.Handle.openFd!" >&2;}+   { (exit 1); exit 1; }; }++fi++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: failed" >&5+echo "${ECHO_T}failed" >&6; }+       { { echo "$as_me:$LINENO: error: Couldnt figure out how to call GHC.Handle.openFd!" >&5+echo "$as_me: error: Couldnt figure out how to call GHC.Handle.openFd!" >&2;}+   { (exit 1); exit 1; }; }++fi+++fi++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: NOT 'new' API" >&5+echo "${ECHO_T}NOT 'new' API" >&6; }+       { echo "$as_me:$LINENO: checking GHC.Handle.fdToHandle' API" >&5+echo $ECHO_N "checking GHC.Handle.fdToHandle' API... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs++import GHC.Handle ( fdToHandle' )+import IO ( IOMode(..) )++main = fdToHandle' 1 Nothing False "stdout" WriteMode True++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  if { ac_try='./conftest'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  { echo "$as_me:$LINENO: result: okay" >&5+echo "${ECHO_T}okay" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified GHC.Handle ( fdToHandle' )+import System.IO ( Handle, IOMode )+import System.Posix.Internals ( FDType )++EOF+++cat << \EOF >> src/Workaround.hs.ending++{-+Work around renaming of GHC.Handle.openFd and change in its API.+-}+openFd :: Int -> Maybe FDType -> FilePath -> IOMode -> Bool -> Bool -> IO Handle+openFd fd x y z a b = GHC.Handle.fdToHandle' (fromIntegral fd) x b y z a++EOF++else+  { echo "$as_me:$LINENO: result: failed" >&5+echo "${ECHO_T}failed" >&6; }+       { { echo "$as_me:$LINENO: error: Couldnt figure out how to call GHC.Handle.openFd!" >&5+echo "$as_me: error: Couldnt figure out how to call GHC.Handle.openFd!" >&2;}+   { (exit 1); exit 1; }; }++fi++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: failed" >&5+echo "${ECHO_T}failed" >&6; }+       { { echo "$as_me:$LINENO: error: Couldnt figure out how to call GHC.Handle.openFd!" >&5+echo "$as_me: error: Couldnt figure out how to call GHC.Handle.openFd!" >&2;}+   { (exit 1); exit 1; }; }++fi+++fi+++fi++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: NOT old API" >&5+echo "${ECHO_T}NOT old API" >&6; }+     { echo "$as_me:$LINENO: checking GHC.Handle.openFd new API" >&5+echo $ECHO_N "checking GHC.Handle.openFd new API... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs++import GHC.Handle ( openFd )+import IO ( IOMode(..))++main = openFd 1 Nothing False "stdout" WriteMode True++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  if { ac_try='./conftest'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  { echo "$as_me:$LINENO: result: okay" >&5+echo "${ECHO_T}okay" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified GHC.Handle ( openFd )+import System.IO ( Handle, IOMode )+import System.Posix.Internals ( FDType )++EOF+++cat << \EOF >> src/Workaround.hs.ending++{-+Work around change in the GHC.Handle.openFd API.+-}+openFd :: Int -> Maybe FDType -> FilePath -> IOMode -> Bool -> Bool -> IO Handle+openFd fd x y z a b = GHC.Handle.openFd fd x b y z a++EOF++else+  { echo "$as_me:$LINENO: result: NOT 'new' API" >&5+echo "${ECHO_T}NOT 'new' API" >&6; }+       { echo "$as_me:$LINENO: checking GHC.Handle.fdToHandle' API" >&5+echo $ECHO_N "checking GHC.Handle.fdToHandle' API... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs++import GHC.Handle ( fdToHandle' )+import IO ( IOMode(..) )++main = fdToHandle' 1 Nothing False "stdout" WriteMode True++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  if { ac_try='./conftest'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  { echo "$as_me:$LINENO: result: okay" >&5+echo "${ECHO_T}okay" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified GHC.Handle ( fdToHandle' )+import System.IO ( Handle, IOMode )+import System.Posix.Internals ( FDType )++EOF+++cat << \EOF >> src/Workaround.hs.ending++{-+Work around renaming of GHC.Handle.openFd and change in its API.+-}+openFd :: Int -> Maybe FDType -> FilePath -> IOMode -> Bool -> Bool -> IO Handle+openFd fd x y z a b = GHC.Handle.fdToHandle' (fromIntegral fd) x b y z a++EOF++else+  { echo "$as_me:$LINENO: result: failed" >&5+echo "${ECHO_T}failed" >&6; }+       { { echo "$as_me:$LINENO: error: Couldnt figure out how to call GHC.Handle.openFd!" >&5+echo "$as_me: error: Couldnt figure out how to call GHC.Handle.openFd!" >&2;}+   { (exit 1); exit 1; }; }++fi++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: failed" >&5+echo "${ECHO_T}failed" >&6; }+       { { echo "$as_me:$LINENO: error: Couldnt figure out how to call GHC.Handle.openFd!" >&5+echo "$as_me: error: Couldnt figure out how to call GHC.Handle.openFd!" >&2;}+   { (exit 1); exit 1; }; }++fi+++fi++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: NOT 'new' API" >&5+echo "${ECHO_T}NOT 'new' API" >&6; }+       { echo "$as_me:$LINENO: checking GHC.Handle.fdToHandle' API" >&5+echo $ECHO_N "checking GHC.Handle.fdToHandle' API... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs++import GHC.Handle ( fdToHandle' )+import IO ( IOMode(..) )++main = fdToHandle' 1 Nothing False "stdout" WriteMode True++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  if { ac_try='./conftest'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  { echo "$as_me:$LINENO: result: okay" >&5+echo "${ECHO_T}okay" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified GHC.Handle ( fdToHandle' )+import System.IO ( Handle, IOMode )+import System.Posix.Internals ( FDType )++EOF+++cat << \EOF >> src/Workaround.hs.ending++{-+Work around renaming of GHC.Handle.openFd and change in its API.+-}+openFd :: Int -> Maybe FDType -> FilePath -> IOMode -> Bool -> Bool -> IO Handle+openFd fd x y z a b = GHC.Handle.fdToHandle' (fromIntegral fd) x b y z a++EOF++else+  { echo "$as_me:$LINENO: result: failed" >&5+echo "${ECHO_T}failed" >&6; }+       { { echo "$as_me:$LINENO: error: Couldnt figure out how to call GHC.Handle.openFd!" >&5+echo "$as_me: error: Couldnt figure out how to call GHC.Handle.openFd!" >&2;}+   { (exit 1); exit 1; }; }++fi++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: failed" >&5+echo "${ECHO_T}failed" >&6; }+       { { echo "$as_me:$LINENO: error: Couldnt figure out how to call GHC.Handle.openFd!" >&5+echo "$as_me: error: Couldnt figure out how to call GHC.Handle.openFd!" >&2;}+   { (exit 1); exit 1; }; }++fi+++fi+++fi++++++cat << \EOF >> src/Workaround.hs.prefix+installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,+EOF+++{ echo "$as_me:$LINENO: checking for module System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)" >&5+echo $ECHO_N "checking for module System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)+main = seq (undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package unix"+++cat << \EOF > conftest.hs+import System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)+main = seq (undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package unix" >&5+echo "${ECHO_T}in package unix" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package unix" >&5+echo "${ECHO_T}no; and neither in package unix" >&6; }++{ echo "$as_me:$LINENO: checking for module Posix(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)" >&5+echo $ECHO_N "checking for module Posix(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Posix(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)+main = seq (undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import Posix(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package util"+++cat << \EOF > conftest.hs+import Posix(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)+main = seq (undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package util" >&5+echo "${ECHO_T}in package util" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import Posix(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package util" >&5+echo "${ECHO_T}no; and neither in package util" >&6; }++cat << \EOF >> src/Workaround.hs.ending+++-- Dummy implementation of POSIX signals++data Handler = Default | Ignore | Catch (IO ())+type Signal = Int++installHandler :: Signal -> Handler -> Maybe () -> IO ()+installHandler _ _ _ = return ()++raiseSignal :: Signal -> IO ()+raiseSignal _ = return ()++sigINT, {- sigKILL, -} sigHUP, {- sigQUIT, -} sigABRT, sigALRM, sigTERM, sigPIPE :: Signal+sigINT = 0+-- not used: sigKILL = 0+sigHUP = 0+-- not used: sigQUIT = 0+sigABRT = 0+sigTERM = 0+sigPIPE = 0+sigALRM = 0++-- not used: raiseSignal :: Signal -> IO ()+-- not used: raiseSignal _ = return ()+++EOF+++fi++++fi+++++fi++++fi+++++++for ac_header in siginfo.h+do+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then+  { echo "$as_me:$LINENO: checking for $ac_header" >&5+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+fi+ac_res=`eval echo '${'$as_ac_Header'}'`+	       { echo "$as_me:$LINENO: result: $ac_res" >&5+echo "${ECHO_T}$ac_res" >&6; }+else+  # Is the header compilable?+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+$ac_includes_default+#include <$ac_header>+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  ac_header_compiler=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_header_compiler=no+fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5+echo "${ECHO_T}$ac_header_compiler" >&6; }++# Is the header present?+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <$ac_header>+_ACEOF+if { (ac_try="$ac_cpp conftest.$ac_ext"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } >/dev/null && {+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||+	 test ! -s conftest.err+       }; then+  ac_header_preproc=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++  ac_header_preproc=no+fi++rm -f conftest.err conftest.$ac_ext+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5+echo "${ECHO_T}$ac_header_preproc" >&6; }++# So?  What about this header?+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in+  yes:no: )+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}+    ac_header_preproc=yes+    ;;+  no:yes:* )+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}+    ( cat <<\_ASBOX+## ----------------------------- ##+## Report this to bugs@darcs.net ##+## ----------------------------- ##+_ASBOX+     ) | sed "s/^/$as_me: WARNING:     /" >&2+    ;;+esac+{ echo "$as_me:$LINENO: checking for $ac_header" >&5+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  eval "$as_ac_Header=\$ac_header_preproc"+fi+ac_res=`eval echo '${'$as_ac_Header'}'`+	       { echo "$as_me:$LINENO: result: $ac_res" >&5+echo "${ECHO_T}$ac_res" >&6; }++fi+if test `eval echo '${'$as_ac_Header'}'` = yes; then+  cat >>confdefs.h <<_ACEOF+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1+_ACEOF++fi++done+++++{ echo "$as_me:$LINENO: checking for module Text.Regex( mkRegex, matchRegex, Regex )" >&5+echo $ECHO_N "checking for module Text.Regex( mkRegex, matchRegex, Regex )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Text.Regex( mkRegex, matchRegex, Regex )+main = seq (mkRegex undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package text"+++cat << \EOF > conftest.hs+import Text.Regex( mkRegex, matchRegex, Regex )+main = seq (mkRegex undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package text" >&5+echo "${ECHO_T}in package text" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package text" >&5+echo "${ECHO_T}no; and neither in package text" >&6; }++{ echo "$as_me:$LINENO: checking for module Text.Regex( mkRegex, matchRegex, Regex )" >&5+echo $ECHO_N "checking for module Text.Regex( mkRegex, matchRegex, Regex )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Text.Regex( mkRegex, matchRegex, Regex )+main = seq (mkRegex undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package regex-compat"+++cat << \EOF > conftest.hs+import Text.Regex( mkRegex, matchRegex, Regex )+main = seq (mkRegex undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package regex-compat" >&5+echo "${ECHO_T}in package regex-compat" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package regex-compat" >&5+echo "${ECHO_T}no; and neither in package regex-compat" >&6; }+    { { echo "$as_me:$LINENO: error: Cannot find Test.Regex; try installing the package text or regex-compat?" >&5+echo "$as_me: error: Cannot find Test.Regex; try installing the package text or regex-compat?" >&2;}+   { (exit 1); exit 1; }; }++fi++++fi+++++fi++++fi+++++++{ echo "$as_me:$LINENO: checking for module Network.HTTP( urlEncode )" >&5+echo $ECHO_N "checking for module Network.HTTP( urlEncode )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Network.HTTP( urlEncode )+main = seq (urlEncode undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }+HAVE_HTTP=True+                  cat >>confdefs.h <<\_ACEOF+#define HAVE_HTTP 1+_ACEOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package HTTP"+++cat << \EOF > conftest.hs+import Network.HTTP( urlEncode )+main = seq (urlEncode undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package HTTP" >&5+echo "${ECHO_T}in package HTTP" >&6; }+HAVE_HTTP=True+                  cat >>confdefs.h <<\_ACEOF+#define HAVE_HTTP 1+_ACEOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package HTTP" >&5+echo "${ECHO_T}no; and neither in package HTTP" >&6; }+    HAVE_HTTP=False+fi++++fi+++++++++{ echo "$as_me:$LINENO: checking for module Test.QuickCheck( quickCheck )" >&5+echo $ECHO_N "checking for module Test.QuickCheck( quickCheck )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Test.QuickCheck( quickCheck )+main = seq (quickCheck True) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package QuickCheck"+++cat << \EOF > conftest.hs+import Test.QuickCheck( quickCheck )+main = seq (quickCheck True) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package QuickCheck" >&5+echo "${ECHO_T}in package QuickCheck" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package QuickCheck" >&5+echo "${ECHO_T}no; and neither in package QuickCheck" >&6; }+    { { echo "$as_me:$LINENO: error: Cannot find Test.QuickCheck; try installing package quickcheck?" >&5+echo "$as_me: error: Cannot find Test.QuickCheck; try installing package quickcheck?" >&2;}+   { (exit 1); exit 1; }; }+fi++++fi++++++{ echo "$as_me:$LINENO: checking for module Data.ByteString.Internal( fromForeignPtr )" >&5+echo $ECHO_N "checking for module Data.ByteString.Internal( fromForeignPtr )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Data.ByteString.Internal( fromForeignPtr )+main = seq (fromForeignPtr) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }+bytestringfound=yes+else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package bytestring"+++cat << \EOF > conftest.hs+import Data.ByteString.Internal( fromForeignPtr )+main = seq (fromForeignPtr) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package bytestring" >&5+echo "${ECHO_T}in package bytestring" >&6; }+bytestringfound=yes+else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package bytestring" >&5+echo "${ECHO_T}no; and neither in package bytestring" >&6; }+    bytestringfound=no+fi++++fi++++if test $bytestringfound = "yes"; then+  { echo "$as_me:$LINENO: checking whether to use ByteString" >&5+echo $ECHO_N "checking whether to use ByteString... $ECHO_C" >&6; }+  # Check whether --enable-bytestring was given.+if test "${enable_bytestring+set}" = set; then+  enableval=$enable_bytestring; bytestring=$enableval+else+  bytestring=yes+fi++  { echo "$as_me:$LINENO: result: $bytestring" >&5+echo "${ECHO_T}$bytestring" >&6; }+  # If we aren't instructed to avoid bytestring, and we did successfully find bytestring...+  if test $bytestring = "yes"; then+     CPPFLAGS="$CPPFLAGS -DHAVE_BYTESTRING"+  fi+fi++++{ echo "$as_me:$LINENO: checking for module Control.Monad.Error" >&5+echo $ECHO_N "checking for module Control.Monad.Error... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Control.Monad.Error+main = seq (strMsg "foo" :: String) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package mtl"+++cat << \EOF > conftest.hs+import Control.Monad.Error+main = seq (strMsg "foo" :: String) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package mtl" >&5+echo "${ECHO_T}in package mtl" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package mtl" >&5+echo "${ECHO_T}no; and neither in package mtl" >&6; }+    { { echo "$as_me:$LINENO: error: Cannot find Control.Monad.Error; try installing package mtl?" >&5+echo "$as_me: error: Cannot find Control.Monad.Error; try installing package mtl?" >&2;}+   { (exit 1); exit 1; }; }+fi++++fi+++++++{ echo "$as_me:$LINENO: checking for module Text.ParserCombinators.Parsec" >&5+echo $ECHO_N "checking for module Text.ParserCombinators.Parsec... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Text.ParserCombinators.Parsec+main = seq (errorPos undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package parsec"+++cat << \EOF > conftest.hs+import Text.ParserCombinators.Parsec+main = seq (errorPos undefined) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package parsec" >&5+echo "${ECHO_T}in package parsec" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package parsec" >&5+echo "${ECHO_T}no; and neither in package parsec" >&6; }+    { { echo "$as_me:$LINENO: error: Cannot find Text.ParserCombinators.Parsec; try installing package parsec?" >&5+echo "$as_me: error: Cannot find Text.ParserCombinators.Parsec; try installing package parsec?" >&2;}+   { (exit 1); exit 1; }; }+fi++++fi+++++++{ echo "$as_me:$LINENO: checking for module Text.Html" >&5+echo $ECHO_N "checking for module Text.Html... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Text.Html+main = seq (text "foo") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package html"+++cat << \EOF > conftest.hs+import Text.Html+main = seq (text "foo") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package html" >&5+echo "${ECHO_T}in package html" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package html" >&5+echo "${ECHO_T}no; and neither in package html" >&6; }+    { { echo "$as_me:$LINENO: error: Cannot find Text.Html; try installing package html?" >&5+echo "$as_me: error: Cannot find Text.Html; try installing package html?" >&2;}+   { (exit 1); exit 1; }; }+fi++++fi+++++++{ echo "$as_me:$LINENO: checking for module Data.Map" >&5+echo $ECHO_N "checking for module Data.Map... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Data.Map+main = seq (empty) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package containers"+++cat << \EOF > conftest.hs+import Data.Map+main = seq (empty) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package containers" >&5+echo "${ECHO_T}in package containers" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package containers" >&5+echo "${ECHO_T}no; and neither in package containers" >&6; }+    { { echo "$as_me:$LINENO: error: Cannot find Data.Map; try installing package containers?" >&5+echo "$as_me: error: Cannot find Data.Map; try installing package containers?" >&2;}+   { (exit 1); exit 1; }; }+fi++++fi++++++++cat << \EOF >> src/Workaround.hs.prefix+           getCurrentDirectory,+EOF++  { echo "$as_me:$LINENO: checking getCurrentDirectory" >&5+echo $ECHO_N "checking getCurrentDirectory... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs++import System.Directory(getCurrentDirectory, setCurrentDirectory)+main = do setCurrentDirectory "src"+          d <- getCurrentDirectory+          case reverse $ take 4 $ reverse d of+              "/src" -> return ()++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  if { ac_try='./conftest'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  { echo "$as_me:$LINENO: result: uses /" >&5+echo "${ECHO_T}uses /" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Directory(getCurrentDirectory)+EOF++     GHC_SEPARATOR='/'+else+  { echo "$as_me:$LINENO: result: uses \\" >&5+echo "${ECHO_T}uses \\" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified System.Directory(getCurrentDirectory)+EOF++      GHC_SEPARATOR='\\'++cat << \EOF >> src/Workaround.hs.ending++{-+System.Directory.getCurrentDirectory returns a path with backslashes in it+under windows, and some of the code gets confused by that, so we override+getCurrentDirectory and translates '\\' to '/'+-}++getCurrentDirectory :: IO FilePath+getCurrentDirectory = do d <- System.Directory.getCurrentDirectory+                         return $ map rb d+    where rb '\\' = '/'+          rb c = c++EOF++++fi++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: uses \\" >&5+echo "${ECHO_T}uses \\" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified System.Directory(getCurrentDirectory)+EOF++      GHC_SEPARATOR='\\'++cat << \EOF >> src/Workaround.hs.ending++{-+System.Directory.getCurrentDirectory returns a path with backslashes in it+under windows, and some of the code gets confused by that, so we override+getCurrentDirectory and translates '\\' to '/'+-}++getCurrentDirectory :: IO FilePath+getCurrentDirectory = do d <- System.Directory.getCurrentDirectory+                         return $ map rb d+    where rb '\\' = '/'+          rb c = c++EOF++++fi++++++++cat << \EOF >> src/Workaround.hs.prefix+           createLink,+EOF+++{ echo "$as_me:$LINENO: checking for module System.Posix.Files( createLink )" >&5+echo $ECHO_N "checking for module System.Posix.Files( createLink )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import System.Posix.Files( createLink )+main = seq (createLink "a" "b") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Posix.Files( createLink )+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package unix"+++cat << \EOF > conftest.hs+import System.Posix.Files( createLink )+main = seq (createLink "a" "b") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package unix" >&5+echo "${ECHO_T}in package unix" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Posix.Files( createLink )+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package unix" >&5+echo "${ECHO_T}no; and neither in package unix" >&6; }++{ echo "$as_me:$LINENO: checking for module Posix( createLink )" >&5+echo $ECHO_N "checking for module Posix( createLink )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Posix( createLink )+main = seq (createLink "a" "b") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import Posix( createLink )+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package util"+++cat << \EOF > conftest.hs+import Posix( createLink )+main = seq (createLink "a" "b") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package util" >&5+echo "${ECHO_T}in package util" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import Posix( createLink )+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package util" >&5+echo "${ECHO_T}no; and neither in package util" >&6; }++cat << \EOF >> src/Workaround.hs.ending+++-- Dummy implementation of createLink.++createLink :: FilePath -> FilePath -> IO ()+createLink _ _ = fail "Dummy create link error should be caught."++EOF+++fi++++fi+++++fi++++fi+++++++++cat << \EOF >> src/Workaround.hs.prefix+           createDirectoryIfMissing,+EOF++  { echo "$as_me:$LINENO: checking createDirectoryIfMissing" >&5+echo $ECHO_N "checking createDirectoryIfMissing... $ECHO_C" >&6; }++cat << \EOF > conftest.hs++import System.Directory(createDirectoryIfMissing)+main = createDirectoryIfMissing True ""++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: has createDirectoryIfMissing" >&5+echo "${ECHO_T}has createDirectoryIfMissing" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Directory(createDirectoryIfMissing)+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: doesn't have createDirectoryIfMissing" >&5+echo "${ECHO_T}doesn't have createDirectoryIfMissing" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Directory ( doesDirectoryExist, createDirectory )+EOF+++cat << \EOF >> src/Workaround.hs.ending++createDirectoryIfMissing+  :: Bool     -- ^ Create its parents too?+  -> FilePath -- ^ The path to the directory you want to make+  -> IO ()+createDirectoryIfMissing parents file = do+  b <- doesDirectoryExist file+  case (b,parents, file) of+    (_,     _, "") -> return ()+    (True,  _,  _) -> return ()+    (_,  True,  _) -> mapM_ (createDirectoryIfMissing False) (tail (pathParents file))+    (_, False,  _) -> createDirectory file+ where    pathParents :: FilePath -> [FilePath]+          pathParents p =+              root'' : map ((++) root') (dropEmptyPath $ inits path')+              where+#ifdef WIN32+                 (root,path) = case break (== ':') p of+                    (rel,    "") -> ("",rel)+                    (drv,_:rel) -> (drv++":",rel)+#else+                 (root,path) = ("",p)+#endif+                 (root',root'',path') = case path of+                   (c:path'') | isPathSeparator c -> (root++[pathSeparator],root++[pathSeparator],path'')+                   _                              -> (root                 ,root++"."            ,path)++                 dropEmptyPath ("":paths) = paths+                 dropEmptyPath paths      = paths++                 inits :: String -> [String]+                 inits [] =  [""]+                 inits cs =+                   case pre of+                     "."  -> inits suf+                     ".." -> map (joinFileName pre) (dropEmptyPath $ inits suf)+                     _    -> "" : map (joinFileName pre) (inits suf)+                   where+                     (pre,suf) = case break isPathSeparator cs of+                        (pre',"")     -> (pre', "")+                        (pre',_:suf') -> (pre',suf')+                 isPathSeparator :: Char -> Bool+                 isPathSeparator ch = ch == pathSeparator || ch == '/'+                 pathSeparator :: Char+#ifdef WIN32+                 pathSeparator = '\\'+#else+                 pathSeparator = '/'+#endif+                 joinFileName :: String -> String -> FilePath+                 joinFileName ""  fname = fname+                 joinFileName "." fname = fname+                 joinFileName dir ""    = dir+                 joinFileName dir fname+                   | isPathSeparator (last dir) = dir++fname+                   | otherwise                  = dir++pathSeparator:fname++EOF++++fi++++++cat << \EOF >> src/Workaround.hs.prefix+           renameFile,+EOF++  { echo "$as_me:$LINENO: checking renameFile" >&5+echo $ECHO_N "checking renameFile... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs++import System.Directory ( renameFile )++main = do writeFile "conftest.data" "orig_data"+          writeFile "conftest.newdata" "new_data"+          renameFile "conftest.newdata" "conftest.data"++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  if { ac_try='./conftest'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  { echo "$as_me:$LINENO: result: okay" >&5+echo "${ECHO_T}okay" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Directory ( renameFile )+EOF++else+  { echo "$as_me:$LINENO: result: buggy!" >&5+echo "${ECHO_T}buggy!" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified System.Directory( renameFile, removeFile )+EOF+++cat << \EOF >> src/Workaround.hs.beginning+import qualified System.IO.Error+EOF+++cat << \EOF >> src/Workaround.hs.beginning+import qualified Control.Exception ( block )+EOF+++cat << \EOF >> src/Workaround.hs.ending++{-+System.Directory.renameFile incorrectly fails when the new file already+exists.  This code works around that bug at the cost of losing atomic+writes.+-}++renameFile :: FilePath -> FilePath -> IO ()+renameFile old new = Control.Exception.block $+   do System.Directory.removeFile new+        `System.IO.Error.catch`+         (\e -> if System.IO.Error.isDoesNotExistError e+                   then return ()+                   else System.IO.Error.ioError e)+      System.Directory.renameFile old new++EOF+++fi++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o+  { echo "$as_me:$LINENO: result: buggy!" >&5+echo "${ECHO_T}buggy!" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified System.Directory( renameFile, removeFile )+EOF+++cat << \EOF >> src/Workaround.hs.beginning+import qualified System.IO.Error+EOF+++cat << \EOF >> src/Workaround.hs.beginning+import qualified Control.Exception ( block )+EOF+++cat << \EOF >> src/Workaround.hs.ending++{-+System.Directory.renameFile incorrectly fails when the new file already+exists.  This code works around that bug at the cost of losing atomic+writes.+-}++renameFile :: FilePath -> FilePath -> IO ()+renameFile old new = Control.Exception.block $+   do System.Directory.removeFile new+        `System.IO.Error.catch`+         (\e -> if System.IO.Error.isDoesNotExistError e+                   then return ()+                   else System.IO.Error.ioError e)+      System.Directory.renameFile old new++EOF+++fi+++++++cat << \EOF >> src/Workaround.hs.prefix+           bracketOnError,+EOF+++{ echo "$as_me:$LINENO: checking for module Control.Exception( bracketOnError )" >&5+echo $ECHO_N "checking for module Control.Exception( bracketOnError )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import Control.Exception( bracketOnError )+main = seq (bracketOnError (return ()) (const $ return ()) (const $ return ())) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import Control.Exception( bracketOnError )+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package base "+++cat << \EOF > conftest.hs+import Control.Exception( bracketOnError )+main = seq (bracketOnError (return ()) (const $ return ()) (const $ return ())) (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package base " >&5+echo "${ECHO_T}in package base " >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import Control.Exception( bracketOnError )+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package base " >&5+echo "${ECHO_T}no; and neither in package base " >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import qualified Control.Exception( catch, throw, block, unblock )+EOF+++cat << \EOF >> src/Workaround.hs.ending+++-- | Like bracket, but only performs the final action if there was an+-- exception raised by the in-between computation.+-- From GHC 6.6 (with twiddling for qualified block, catch, etc)+bracketOnError+	:: IO a		-- ^ computation to run first (\"acquire resource\")+	-> (a -> IO b)  -- ^ computation to run last (\"release resource\")+	-> (a -> IO c)	-- ^ computation to run in-between+	-> IO c		-- returns the value from the in-between computation+bracketOnError before after thing =+  Control.Exception.block (do+    a <- before+    Control.Exception.catch+	(Control.Exception.unblock (thing a))+	(\e -> do { after a; Control.Exception.throw e })+  )++EOF+++fi++++fi+++++++++cat << \EOF >> src/Workaround.hs.prefix+           fileMode, getFileStatus, setFileMode,+EOF+++{ echo "$as_me:$LINENO: checking for module System.Posix.Files( fileMode, getFileStatus, setFileMode )" >&5+echo $ECHO_N "checking for module System.Posix.Files( fileMode, getFileStatus, setFileMode )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import System.Posix.Files( fileMode, getFileStatus, setFileMode )+main = seq (getFileStatus "") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Posix.Files(fileMode,getFileStatus,setFileMode)+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package unix"+++cat << \EOF > conftest.hs+import System.Posix.Files( fileMode, getFileStatus, setFileMode )+main = seq (getFileStatus "") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package unix" >&5+echo "${ECHO_T}in package unix" >&6; }++cat << \EOF >> src/Workaround.hs.beginning+import System.Posix.Files(fileMode,getFileStatus,setFileMode)+EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package unix" >&5+echo "${ECHO_T}no; and neither in package unix" >&6; }++cat << \EOF >> src/Workaround.hs.ending++fileMode :: () -> ()+fileMode _ = ()+getFileStatus :: FilePath -> IO ()+getFileStatus _ = return ()+setFileMode :: FilePath -> () -> IO ()+setFileMode _ _ = return ()++EOF+++fi++++fi++++++++cat << \EOF >> src/Workaround.hs.prefix+           setExecutable,+EOF+++{ echo "$as_me:$LINENO: checking for module System.Posix.Files( fileMode, getFileStatus, setFileMode, setFileCreationMask )" >&5+echo $ECHO_N "checking for module System.Posix.Files( fileMode, getFileStatus, setFileMode, setFileCreationMask )... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+import System.Posix.Files( fileMode, getFileStatus, setFileMode, setFileCreationMask )+main = seq (getFileStatus "") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++cat << \EOF >> src/Workaround.hs.beginning++import System.Posix.Files (fileMode,getFileStatus, setFileMode, nullFileMode,+                           setFileCreationMask,+                           ownerReadMode, ownerWriteMode, ownerExecuteMode,+                           groupReadMode, groupWriteMode, groupExecuteMode,+                           otherReadMode, otherWriteMode, otherExecuteMode)+import Data.Bits ( (.&.), (.|.), complement )++setExecutable :: FilePath -> Bool -> IO ()+setExecutable f ex =+  do st <- getFileStatus f+     umask <- setFileCreationMask 0+     setFileCreationMask umask+     let rw = fileMode st .&.+              (ownerReadMode .|. ownerWriteMode .|.+               groupReadMode .|. groupWriteMode .|.+               otherReadMode .|. otherWriteMode)+         total = if ex then rw .|.+                           ((ownerExecuteMode .|. groupExecuteMode .|. otherExecuteMode)+                            .&. complement umask)+                       else rw+     setFileMode f total++EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_module_save_GHCFLAGS=$GHCFLAGS+  GHCFLAGS="$GHCFLAGS -package unix"+++cat << \EOF > conftest.hs+import System.Posix.Files( fileMode, getFileStatus, setFileMode, setFileCreationMask )+main = seq (getFileStatus "") (putStr "Hello world.\n")++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in package unix" >&5+echo "${ECHO_T}in package unix" >&6; }++cat << \EOF >> src/Workaround.hs.beginning++import System.Posix.Files (fileMode,getFileStatus, setFileMode, nullFileMode,+                           setFileCreationMask,+                           ownerReadMode, ownerWriteMode, ownerExecuteMode,+                           groupReadMode, groupWriteMode, groupExecuteMode,+                           otherReadMode, otherWriteMode, otherExecuteMode)+import Data.Bits ( (.&.), (.|.), complement )++setExecutable :: FilePath -> Bool -> IO ()+setExecutable f ex =+  do st <- getFileStatus f+     umask <- setFileCreationMask 0+     setFileCreationMask umask+     let rw = fileMode st .&.+              (ownerReadMode .|. ownerWriteMode .|.+               groupReadMode .|. groupWriteMode .|.+               otherReadMode .|. otherWriteMode)+         total = if ex then rw .|.+                           ((ownerExecuteMode .|. groupExecuteMode .|. otherExecuteMode)+                            .&. complement umask)+                       else rw+     setFileMode f total++EOF++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    GHCFLAGS=$check_module_save_GHCFLAGS+    { echo "$as_me:$LINENO: result: no; and neither in package unix" >&5+echo "${ECHO_T}no; and neither in package unix" >&6; }++cat << \EOF >> src/Workaround.hs.ending++setExecutable :: FilePath -> Bool -> IO ()+setExecutable _ _ = return ()++EOF+++fi++++fi+++++++{ echo "$as_me:$LINENO: checking whether to optimize" >&5+echo $ECHO_N "checking whether to optimize... $ECHO_C" >&6; }+# Check whether --enable-optimize was given.+if test "${enable_optimize+set}" = set; then+  enableval=$enable_optimize; optimize=$enableval+else+  optimize=yes+fi++{ echo "$as_me:$LINENO: result: $optimize" >&5+echo "${ECHO_T}$optimize" >&6; }++if test "$optimize" = yes; then+   GHCFLAGS="$GHCFLAGS -O2 -funbox-strict-fields"+   if test "$CFLAGS" = ""; then+      CFLAGS="$CFLAGS -O2"+   fi+fi+++{ echo "$as_me:$LINENO: checking whether to use Haskell Program Coverage" >&5+echo $ECHO_N "checking whether to use Haskell Program Coverage... $ECHO_C" >&6; }+# Check whether --enable-hpc was given.+if test "${enable_hpc+set}" = set; then+  enableval=$enable_hpc; hpc=$enableval+else+  hpc=no+fi++{ echo "$as_me:$LINENO: result: $hpc" >&5+echo "${ECHO_T}$hpc" >&6; }++if test "$hpc" = yes; then+   GHCFLAGS="$GHCFLAGS -fhpc"+fi+++{ echo "$as_me:$LINENO: checking whether to use mmap" >&5+echo $ECHO_N "checking whether to use mmap... $ECHO_C" >&6; }+# Check whether --enable-mmap was given.+if test "${enable_mmap+set}" = set; then+  enableval=$enable_mmap; enable_mmap=$enableval+else+  enable_mmap=yes+fi++if test "$SYS" = "windows"; then+  { echo "$as_me:$LINENO: result: no (Windows)" >&5+echo "${ECHO_T}no (Windows)" >&6; }+else+  { echo "$as_me:$LINENO: result: $enable_mmap" >&5+echo "${ECHO_T}$enable_mmap" >&6; }+fi+USE_MMAP="True"+if test "$enable_mmap" = "no" || test "$SYS" = "windows" ; then+    USE_MMAP="False"+fi+++TARGETS="darcs doc/darcs.1"+INSTALLWHAT="installbin"+BUILDDOC="no"++if test -d "_darcs"; then+  TARGETS="$TARGETS AUTHORS ChangeLog"+fi+++{ echo "$as_me:$LINENO: checking whether to do PackedString debugging" >&5+echo $ECHO_N "checking whether to do PackedString debugging... $ECHO_C" >&6; }+# Check whether --enable-debug-ps was given.+if test "${enable_debug_ps+set}" = set; then+  enableval=$enable_debug_ps; debugps=$enableval+else+  debugps=no+fi++{ echo "$as_me:$LINENO: result: $debugps" >&5+echo "${ECHO_T}$debugps" >&6; }+++if test "$debugps" = yes; then+   GHCFLAGS="$GHCFLAGS -DDEBUG_PS"+fi+++{ echo "$as_me:$LINENO: checking whether to build docs" >&5+echo $ECHO_N "checking whether to build docs... $ECHO_C" >&6; }++# Check whether --with-docs was given.+if test "${with_docs+set}" = set; then+  withval=$with_docs;+else+  with_docs=yes+fi++{ echo "$as_me:$LINENO: result: $with_docs" >&5+echo "${ECHO_T}$with_docs" >&6; }++if test "$with_docs" = "yes"; then+	# Extract the first word of "latex", so it can be a program name with args.+set dummy latex; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_LATEX+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$LATEX"; then+  ac_cv_prog_LATEX="$LATEX" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_LATEX="latex"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+LATEX=$ac_cv_prog_LATEX+if test -n "$LATEX"; then+  { echo "$as_me:$LINENO: result: $LATEX" >&5+echo "${ECHO_T}$LATEX" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++	if test -z "$LATEX"; then+	{ echo "$as_me:$LINENO: WARNING: Cannot find latex in your path!" >&5+echo "$as_me: WARNING: Cannot find latex in your path!" >&2;}+	fi+	# Extract the first word of "pdflatex", so it can be a program name with args.+set dummy pdflatex; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_PDFLATEX+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$PDFLATEX"; then+  ac_cv_prog_PDFLATEX="$PDFLATEX" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_PDFLATEX="pdflatex"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+PDFLATEX=$ac_cv_prog_PDFLATEX+if test -n "$PDFLATEX"; then+  { echo "$as_me:$LINENO: result: $PDFLATEX" >&5+echo "${ECHO_T}$PDFLATEX" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++	if test -z "$PDFLATEX"; then+	{ echo "$as_me:$LINENO: WARNING: Cannot find pdflatex in your path!" >&5+echo "$as_me: WARNING: Cannot find pdflatex in your path!" >&2;}+	fi+	# Extract the first word of "dvips", so it can be a program name with args.+set dummy dvips; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_DVIPS+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$DVIPS"; then+  ac_cv_prog_DVIPS="$DVIPS" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_DVIPS="dvips"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+DVIPS=$ac_cv_prog_DVIPS+if test -n "$DVIPS"; then+  { echo "$as_me:$LINENO: result: $DVIPS" >&5+echo "${ECHO_T}$DVIPS" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++	if test -z "$DVIPS"; then+	{ echo "$as_me:$LINENO: WARNING: Cannot find dvips in your path!" >&5+echo "$as_me: WARNING: Cannot find dvips in your path!" >&2;}+	fi+	if test ! '(' '(' -z "$LATEX" ')' -o '(' -z "$DVIPS" ')' ')'; then+	TARGETS="$TARGETS doc/manual/darcs.ps"+	INSTALLWHAT="$INSTALLWHAT installdocs"+	BUILDDOC="yes"+	fi+	if test ! '(' -z "$PDFLATEX" ')'; then+	TARGETS="$TARGETS doc/manual/darcs.pdf doc/manual/patch-theory.pdf"+	fi+	# Extract the first word of "latex2html", so it can be a program name with args.+set dummy latex2html; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_LATEX2HTML+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$LATEX2HTML"; then+  ac_cv_prog_LATEX2HTML="$LATEX2HTML" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_LATEX2HTML="latex2html"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+LATEX2HTML=$ac_cv_prog_LATEX2HTML+if test -n "$LATEX2HTML"; then+  { echo "$as_me:$LINENO: result: $LATEX2HTML" >&5+echo "${ECHO_T}$LATEX2HTML" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++	if test -z "$LATEX2HTML"; then+	{ echo "$as_me:$LINENO: WARNING: Cannot find latex2html in your path!" >&5+echo "$as_me: WARNING: Cannot find latex2html in your path!" >&2;}+	PREPROCHTML=""+	# Extract the first word of "htlatex", so it can be a program name with args.+set dummy htlatex; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_HTLATEX+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$HTLATEX"; then+  ac_cv_prog_HTLATEX="$HTLATEX" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_HTLATEX="htlatex"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+HTLATEX=$ac_cv_prog_HTLATEX+if test -n "$HTLATEX"; then+  { echo "$as_me:$LINENO: result: $HTLATEX" >&5+echo "${ECHO_T}$HTLATEX" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++	if test -z "$HTLATEX"; then+		{ echo "$as_me:$LINENO: WARNING: Cannot find htlatex in your path either!" >&5+echo "$as_me: WARNING: Cannot find htlatex in your path either!" >&2;}+		# Extract the first word of "hevea", so it can be a program name with args.+set dummy hevea; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_HEVEA+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$HEVEA"; then+  ac_cv_prog_HEVEA="$HEVEA" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_HEVEA="hevea"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+HEVEA=$ac_cv_prog_HEVEA+if test -n "$HEVEA"; then+  { echo "$as_me:$LINENO: result: $HEVEA" >&5+echo "${ECHO_T}$HEVEA" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++		if test -z "$HEVEA"; then+		{ echo "$as_me:$LINENO: WARNING: Cannot find hevea in your path either!" >&5+echo "$as_me: WARNING: Cannot find hevea in your path either!" >&2;}+		MAKEMANUAL="touch doc/manual/index.html; echo Cannot make manual!"+		else+		TARGETS="$TARGETS doc/manual/index.html"+		MAKEMANUAL="$HEVEA -o doc/manual/index.html src/darcs.tex"+		fi+	else+		TARGETS="$TARGETS doc/manual/index.html"+		MAKEMANUAL="cd doc/manual && $HTLATEX ../../src/darcs.tex && ln -sf darcs.html index.html"+	fi+	else+	TARGETS="$TARGETS doc/manual/index.html"+	MAKEMANUAL="$LATEX2HTML -split +1 -dir doc/manual src/darcs.tex"+		PREPROCHTML="--html"+	fi+else+	BUILDDOC="no"+fi+++++++++# Check whether --with-sendmail was given.+if test "${with_sendmail+set}" = set; then+  withval=$with_sendmail;+SENDMAIL=$with_sendmail+HAVE_SENDMAIL="True"++else++STUPID_PATH=/usr/sbin:/usr/lib+# Extract the first word of "sendmail", so it can be a program name with args.+set dummy sendmail; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_path_SENDMAIL+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  case $SENDMAIL in+  [\\/]* | ?:[\\/]*)+  ac_cv_path_SENDMAIL="$SENDMAIL" # Let the user override the test with a path.+  ;;+  *)+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+as_dummy="$PATH:$STUPID_PATH"+for as_dir in $as_dummy+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_path_SENDMAIL="$as_dir/$ac_word$ac_exec_ext"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++  test -z "$ac_cv_path_SENDMAIL" && ac_cv_path_SENDMAIL=""""+  ;;+esac+fi+SENDMAIL=$ac_cv_path_SENDMAIL+if test -n "$SENDMAIL"; then+  { echo "$as_me:$LINENO: result: $SENDMAIL" >&5+echo "${ECHO_T}$SENDMAIL" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++if test -z "$SENDMAIL"; then+    SENDMAIL=""+    HAVE_SENDMAIL="False"+else+    HAVE_SENDMAIL="True"+fi++fi++++++{ echo "$as_me:$LINENO: checking for MAPISendMail in -lmapi32" >&5+echo $ECHO_N "checking for MAPISendMail in -lmapi32... $ECHO_C" >&6; }+if test "${ac_cv_lib_mapi32_MAPISendMail+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  ac_check_lib_save_LIBS=$LIBS+LIBS="-lmapi32  $LIBS"+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++/* Override any GCC internal prototype to avoid an error.+   Use char because int might match the return type of a GCC+   builtin and then its argument prototype would still apply.  */+#ifdef __cplusplus+extern "C"+#endif+char MAPISendMail ();+int+main ()+{+return MAPISendMail ();+  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext conftest$ac_exeext+if { (ac_try="$ac_link"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_link") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest$ac_exeext &&+       $as_test_x conftest$ac_exeext; then+  ac_cv_lib_mapi32_MAPISendMail=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_cv_lib_mapi32_MAPISendMail=no+fi++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \+      conftest$ac_exeext conftest.$ac_ext+LIBS=$ac_check_lib_save_LIBS+fi+{ echo "$as_me:$LINENO: result: $ac_cv_lib_mapi32_MAPISendMail" >&5+echo "${ECHO_T}$ac_cv_lib_mapi32_MAPISendMail" >&6; }+if test $ac_cv_lib_mapi32_MAPISendMail = yes; then+  HAVE_MAPI="True"+else+  HAVE_MAPI="False"+fi++++if test "$HAVE_SENDMAIL" = "False" -a "$HAVE_MAPI" = "False"; then+    { echo "$as_me:$LINENO: WARNING: Can't find sendmail or mapi so you won't be able to push by email!" >&5+echo "$as_me: WARNING: Can't find sendmail or mapi so you won't be able to push by email!" >&2;}+fi+++# Check whether --enable-color was given.+if test "${enable_color+set}" = set; then+  enableval=$enable_color;+fi+++USE_COLOR="True"+if test "$enable_color" = "no"; then+    USE_COLOR="False"+fi+++++# Check whether --with-static-libs was given.+if test "${with_static_libs+set}" = set; then+  withval=$with_static_libs;+fi++if test "x$with_static_libs" = "xyes"; then+    LDFLAGS="-static $LDFLAGS"+fi+++{ echo "$as_me:$LINENO: checking for gadt type witnesses" >&5+echo $ECHO_N "checking for gadt type witnesses... $ECHO_C" >&6; }++# Check whether --with-type-witnesses was given.+if test "${with_type_witnesses+set}" = set; then+  withval=$with_type_witnesses; with_typew=yes++else+  with_typew=no+fi+++if test "$with_typew" = "yes"; then+ GHCFLAGS="$GHCFLAGS -fglasgow-exts"+ cat >>confdefs.h <<\_ACEOF+#define GADT_WITNESSES 1+_ACEOF++ { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }+else+ { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi++++{ echo "$as_me:$LINENO: checking for library z" >&5+echo $ECHO_N "checking for library z... $ECHO_C" >&6; }+++cat << \EOF > conftest.hs+{-# OPTIONS -fffi -Werror #-}+module Main where++foreign import ccall unsafe "zlib.h deflate" fun :: Int -> Int -> Int++main = fun `seq` putStrLn "hello world"++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++  check_library_save_LIBS=$LIBS+  LIBS="$LIBS -lz"+++cat << \EOF > conftest.hs+{-# OPTIONS -fffi -Werror #-}+module Main where++foreign import ccall unsafe "zlib.h deflate" fun :: Int -> Int -> Int++main = fun `seq` putStrLn "hello world"++-- this file generated by TRY-COMPILE-GHC+EOF+rm -f Main.hi Main.o+# Convert LDFLAGS and LIBS to the format GHC wants them in+GHCLDFLAGS=""+for f in $LDFLAGS ; do+  GHCLDFLAGS="$GHCLDFLAGS -optl$f"+done+GHCLIBS=""+for l in $LIBS ; do+  GHCLIBS="$GHCLIBS -optl$l"+done+if { ac_try='$GHC $GHCFLAGS $GHCLDFLAGS -o conftest conftest.hs $GHCLIBS'+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5+  (eval $ac_try) 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; } && test -s conftest+then+  { echo "$as_me:$LINENO: result: in -lz" >&5+echo "${ECHO_T}in -lz" >&6; }++else+  echo "configure: failed program was:" >&5+  cat conftest.hs >&5+  echo "end of failed program." >&5+ rm -f Main.hi Main.o++    LIBS=$check_library_save_LIBS+    { echo "$as_me:$LINENO: result: no; and not with -lz either" >&5+echo "${ECHO_T}no; and not with -lz either" >&6; }+    { { echo "$as_me:$LINENO: error: Cannot find system's zlib library; please set the LDFLAGS environment variable!" >&5+echo "$as_me: error: Cannot find system's zlib library; please set the LDFLAGS environment variable!" >&2;}+   { (exit 1); exit 1; }; }+fi++fi+++++# Check whether --with-libcurl was given.+if test "${with_libcurl+set}" = set; then+  withval=$with_libcurl;+fi++++# Check whether --with-curl was given.+if test "${with_curl+set}" = set; then+  withval=$with_curl;+fi+++CURLLIBS=+CURL_CONFIG="curl-config"++if test "$with_libcurl" != "no"; then+ if test "$with_curl" != ""; then+   CURL_CONFIG="$with_curl/bin/curl-config"+ fi++ { echo "$as_me:$LINENO: checking for libcurl" >&5+echo $ECHO_N "checking for libcurl... $ECHO_C" >&6; }+ if eval $CURL_CONFIG --version 2>/dev/null >/dev/null; then+   ver=`$CURL_CONFIG --version | sed -e "s/libcurl //g"`+   opt="--libs"+   CURLCFLAGS=`$CURL_CONFIG --cflags`+   if test "x$with_static_libs" = "xyes"; then+       CURLCFLAGS="$CURLFLAGS -DCURL_STATICLIB"+       opt="--static-libs"+   fi+   CURLLIBS=`$CURL_CONFIG $opt | sed "s_-arch [^ ][^ ]*__"`+   { echo "$as_me:$LINENO: result: $ver" >&5+echo "${ECHO_T}$ver" >&6; }+ else+   { echo "$as_me:$LINENO: result: FAILED" >&5+echo "${ECHO_T}FAILED" >&6; }+   { echo "$as_me:$LINENO: WARNING: curl-config was not found" >&5+echo "$as_me: WARNING: curl-config was not found" >&2;}+ fi+fi++if test "$CURLLIBS" != ""; then+    # we enable curl+    CPPFLAGS="$CPPFLAGS -DHAVE_CURL"++    CFLAGS="$CFLAGS $CURLCFLAGS"+    LIBS="$LIBS $CURLLIBS"+    old_LIBS="$LIBS"++{ echo "$as_me:$LINENO: checking for curl_global_init in -lcurl" >&5+echo $ECHO_N "checking for curl_global_init in -lcurl... $ECHO_C" >&6; }+if test "${ac_cv_lib_curl_curl_global_init+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  ac_check_lib_save_LIBS=$LIBS+LIBS="-lcurl  $LIBS"+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++/* Override any GCC internal prototype to avoid an error.+   Use char because int might match the return type of a GCC+   builtin and then its argument prototype would still apply.  */+#ifdef __cplusplus+extern "C"+#endif+char curl_global_init ();+int+main ()+{+return curl_global_init ();+  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext conftest$ac_exeext+if { (ac_try="$ac_link"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_link") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest$ac_exeext &&+       $as_test_x conftest$ac_exeext; then+  ac_cv_lib_curl_curl_global_init=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_cv_lib_curl_curl_global_init=no+fi++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \+      conftest$ac_exeext conftest.$ac_ext+LIBS=$ac_check_lib_save_LIBS+fi+{ echo "$as_me:$LINENO: result: $ac_cv_lib_curl_curl_global_init" >&5+echo "${ECHO_T}$ac_cv_lib_curl_curl_global_init" >&6; }+if test $ac_cv_lib_curl_curl_global_init = yes; then+  cat >>confdefs.h <<_ACEOF+#define HAVE_LIBCURL 1+_ACEOF++  LIBS="-lcurl $LIBS"++else+  { { echo "$as_me:$LINENO: error: Cannot actually use libcurl; try specifying --without-libcurl." >&5+echo "$as_me: error: Cannot actually use libcurl; try specifying --without-libcurl." >&2;}+   { (exit 1); exit 1; }; }+fi++    { echo "$as_me:$LINENO: checking for curl_multi_timeout in -lcurl" >&5+echo $ECHO_N "checking for curl_multi_timeout in -lcurl... $ECHO_C" >&6; }+if test "${ac_cv_lib_curl_curl_multi_timeout+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  ac_check_lib_save_LIBS=$LIBS+LIBS="-lcurl  $LIBS"+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++/* Override any GCC internal prototype to avoid an error.+   Use char because int might match the return type of a GCC+   builtin and then its argument prototype would still apply.  */+#ifdef __cplusplus+extern "C"+#endif+char curl_multi_timeout ();+int+main ()+{+return curl_multi_timeout ();+  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext conftest$ac_exeext+if { (ac_try="$ac_link"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_link") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest$ac_exeext &&+       $as_test_x conftest$ac_exeext; then+  ac_cv_lib_curl_curl_multi_timeout=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_cv_lib_curl_curl_multi_timeout=no+fi++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \+      conftest$ac_exeext conftest.$ac_ext+LIBS=$ac_check_lib_save_LIBS+fi+{ echo "$as_me:$LINENO: result: $ac_cv_lib_curl_curl_multi_timeout" >&5+echo "${ECHO_T}$ac_cv_lib_curl_curl_multi_timeout" >&6; }+if test $ac_cv_lib_curl_curl_multi_timeout = yes; then+  CPPFLAGS="$CPPFLAGS -DCURL_MULTI_TIMEOUT"+fi++    LIBS="$old_LIBS"++    # Check if we want pipelining enabled...++# Check whether --with-curl_pipelining was given.+if test "${with_curl_pipelining+set}" = set; then+  withval=$with_curl_pipelining;+fi+++    if test "$with_curl_pipelining" == "yes"; then+      { echo "$as_me:$LINENO: checking for libcurl pipelining" >&5+echo $ECHO_N "checking for libcurl pipelining... $ECHO_C" >&6; }+      let vernum=0x0`$CURL_CONFIG --vernum`+      let minver=0x071200+      if test $vernum -ge $minver; then+        CPPFLAGS="$CPPFLAGS -DCURL_PIPELINING"+        CURL_PIPELINING=True+        { echo "$as_me:$LINENO: result: yes" >&5+echo "${ECHO_T}yes" >&6; }+      else+        { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+        { echo "$as_me:$LINENO: WARNING: Requires libcurl version >= 7.18.0" >&5+echo "$as_me: WARNING: Requires libcurl version >= 7.18.0" >&2;}+      fi+    fi++    # Check if we want curl debug enabled...+    { echo "$as_me:$LINENO: checking whether to do libcurl debugging" >&5+echo $ECHO_N "checking whether to do libcurl debugging... $ECHO_C" >&6; }+    # Check whether --enable-curl-debug was given.+if test "${enable_curl_debug+set}" = set; then+  enableval=$enable_curl_debug; curl_debug=$enableval+else+  curl_debug=no+fi++    { echo "$as_me:$LINENO: result: $curl_debug" >&5+echo "${ECHO_T}$curl_debug" >&6; }+    if test "$curl_debug" = "yes"; then+      CPPFLAGS="$CPPFLAGS -DCURL_DEBUG"+    fi+fi++++# Check whether --with-libwww was given.+if test "${with_libwww+set}" = set; then+  withval=$with_libwww;+fi+++if test "$with_libwww" == "yes"; then+ { echo "$as_me:$LINENO: checking for libwww" >&5+echo $ECHO_N "checking for libwww... $ECHO_C" >&6; }+ if eval libwww-config --version 2>/dev/null >/dev/null; then+   CPPFLAGS="$CPPFLAGS -DHAVE_LIBWWW"+   WWWVERSION=`libwww-config --version`+   LIBS="$LIBS `libwww-config --libs`"+   CFLAGS="$CFLAGS `libwww-config --cflags`"+   { echo "$as_me:$LINENO: result: $WWWVERSION" >&5+echo "${ECHO_T}$WWWVERSION" >&6; }++   # Check if we want libwww debug enabled...+   { echo "$as_me:$LINENO: checking whether to do libwww debugging" >&5+echo $ECHO_N "checking whether to do libwww debugging... $ECHO_C" >&6; }+   # Check whether --enable-libwww-debug was given.+if test "${enable_libwww_debug+set}" = set; then+  enableval=$enable_libwww_debug; libwww_debug=$enableval+else+  libwww_debug=no+fi++   { echo "$as_me:$LINENO: result: $libwww_debug" >&5+echo "${ECHO_T}$libwww_debug" >&6; }+   if test "$libwww_debug" = "yes"; then+     CPPFLAGS="$CPPFLAGS -DLIBWWW_DEBUG"+   fi+ else+   { echo "$as_me:$LINENO: result: FAILED" >&5+echo "${ECHO_T}FAILED" >&6; }+   { echo "$as_me:$LINENO: WARNING: libwww-config was not found" >&5+echo "$as_me: WARNING: libwww-config was not found" >&2;}+ fi+fi+++# Check whether --enable-libcurses was given.+if test "${enable_libcurses+set}" = set; then+  enableval=$enable_libcurses;+fi+++HAVE_CURSES=False+if test "$with_libcurses" != "no"; then+  # term.h is documented to require curses.h and actually needs it on+  # Solaris, for instance, though not on GNU/Linux.+  { echo "$as_me:$LINENO: checking for term.h" >&5+echo $ECHO_N "checking for term.h... $ECHO_C" >&6; }+if test "${ac_cv_header_term_h+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <curses.h>+++#include <term.h>+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  ac_cv_header_term_h=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_cv_header_term_h=no+fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+fi+{ echo "$as_me:$LINENO: result: $ac_cv_header_term_h" >&5+echo "${ECHO_T}$ac_cv_header_term_h" >&6; }+if test $ac_cv_header_term_h = yes; then+  { echo "$as_me:$LINENO: checking for library containing tgetent" >&5+echo $ECHO_N "checking for library containing tgetent... $ECHO_C" >&6; }+if test "${ac_cv_search_tgetent+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  ac_func_search_save_LIBS=$LIBS+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */++/* Override any GCC internal prototype to avoid an error.+   Use char because int might match the return type of a GCC+   builtin and then its argument prototype would still apply.  */+#ifdef __cplusplus+extern "C"+#endif+char tgetent ();+int+main ()+{+return tgetent ();+  ;+  return 0;+}+_ACEOF+for ac_lib in '' curses ncurses; do+  if test -z "$ac_lib"; then+    ac_res="none required"+  else+    ac_res=-l$ac_lib+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"+  fi+  rm -f conftest.$ac_objext conftest$ac_exeext+if { (ac_try="$ac_link"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_link") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest$ac_exeext &&+       $as_test_x conftest$ac_exeext; then+  ac_cv_search_tgetent=$ac_res+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5+++fi++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \+      conftest$ac_exeext+  if test "${ac_cv_search_tgetent+set}" = set; then+  break+fi+done+if test "${ac_cv_search_tgetent+set}" = set; then+  :+else+  ac_cv_search_tgetent=no+fi+rm conftest.$ac_ext+LIBS=$ac_func_search_save_LIBS+fi+{ echo "$as_me:$LINENO: result: $ac_cv_search_tgetent" >&5+echo "${ECHO_T}$ac_cv_search_tgetent" >&6; }+ac_res=$ac_cv_search_tgetent+if test "$ac_res" != no; then+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"+  HAVE_CURSES=True+fi++fi+++  if test "$HAVE_CURSES" != "True"; then+    { echo "$as_me:$LINENO: WARNING: Cannot find term.h, disabling color." >&5+echo "$as_me: WARNING: Cannot find term.h, disabling color." >&2;}+  else+    # The precondition for this is: we both have curses available and not disabled+    CPPFLAGS="$CPPFLAGS -DHAVE_CURSES"+  fi+fi++++for ac_prog in gdiff gnudiff diff+do+  # Extract the first word of "$ac_prog", so it can be a program name with args.+set dummy $ac_prog; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_DIFF+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$DIFF"; then+  ac_cv_prog_DIFF="$DIFF" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_DIFF="$ac_prog"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+DIFF=$ac_cv_prog_DIFF+if test -n "$DIFF"; then+  { echo "$as_me:$LINENO: result: $DIFF" >&5+echo "${ECHO_T}$DIFF" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++  test -n "$DIFF" && break+done++++for ac_prog in makensis.exe+do+  # Extract the first word of "$ac_prog", so it can be a program name with args.+set dummy $ac_prog; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_path_MAKENSIS+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  case $MAKENSIS in+  [\\/]* | ?:[\\/]*)+  ac_cv_path_MAKENSIS="$MAKENSIS" # Let the user override the test with a path.+  ;;+  *)+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_path_MAKENSIS="$as_dir/$ac_word$ac_exec_ext"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++  ;;+esac+fi+MAKENSIS=$ac_cv_path_MAKENSIS+if test -n "$MAKENSIS"; then+  { echo "$as_me:$LINENO: result: $MAKENSIS" >&5+echo "${ECHO_T}$MAKENSIS" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++  test -n "$MAKENSIS" && break+done++++{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; }+if test "${ac_cv_c_bigendian+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  # See if sys/param.h defines the BYTE_ORDER macro.+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <sys/types.h>+#include <sys/param.h>++int+main ()+{+#if  ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \+	&& BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN)+ bogus endian macros+#endif++  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  # It does; now see whether it defined to BIG_ENDIAN or not.+cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+#include <sys/types.h>+#include <sys/param.h>++int+main ()+{+#if BYTE_ORDER != BIG_ENDIAN+ not big endian+#endif++  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  ac_cv_c_bigendian=yes+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	ac_cv_c_bigendian=no+fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++	# It does not; compile a test program.+if test "$cross_compiling" = yes; then+  # try to guess the endianness by grepping values into an object file+  ac_cv_c_bigendian=unknown+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };+short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }+short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };+short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }+int+main ()+{+ _ascii (); _ebcdic ();+  ;+  return 0;+}+_ACEOF+rm -f conftest.$ac_objext+if { (ac_try="$ac_compile"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_compile") 2>conftest.er1+  ac_status=$?+  grep -v '^ *+' conftest.er1 >conftest.err+  rm -f conftest.er1+  cat conftest.err >&5+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && {+	 test -z "$ac_c_werror_flag" ||+	 test ! -s conftest.err+       } && test -s conftest.$ac_objext; then+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then+  ac_cv_c_bigendian=yes+fi+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then+  if test "$ac_cv_c_bigendian" = unknown; then+    ac_cv_c_bigendian=no+  else+    # finding both strings is unlikely to happen, but who knows?+    ac_cv_c_bigendian=unknown+  fi+fi+else+  echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5+++fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+else+  cat >conftest.$ac_ext <<_ACEOF+/* confdefs.h.  */+_ACEOF+cat confdefs.h >>conftest.$ac_ext+cat >>conftest.$ac_ext <<_ACEOF+/* end confdefs.h.  */+$ac_includes_default+int+main ()+{++  /* Are we little or big endian?  From Harbison&Steele.  */+  union+  {+    long int l;+    char c[sizeof (long int)];+  } u;+  u.l = 1;+  return u.c[sizeof (long int) - 1] == 1;++  ;+  return 0;+}+_ACEOF+rm -f conftest$ac_exeext+if { (ac_try="$ac_link"+case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_link") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'+  { (case "(($ac_try" in+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;+  *) ac_try_echo=$ac_try;;+esac+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5+  (eval "$ac_try") 2>&5+  ac_status=$?+  echo "$as_me:$LINENO: \$? = $ac_status" >&5+  (exit $ac_status); }; }; then+  ac_cv_c_bigendian=no+else+  echo "$as_me: program exited with status $ac_status" >&5+echo "$as_me: failed program was:" >&5+sed 's/^/| /' conftest.$ac_ext >&5++( exit $ac_status )+ac_cv_c_bigendian=yes+fi+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext+fi+++fi++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+fi+{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5+echo "${ECHO_T}$ac_cv_c_bigendian" >&6; }+case $ac_cv_c_bigendian in+  yes)+    BIGENDIAN="True" ;;+  no)+    BIGENDIAN="False" ;;+  *)+    { { echo "$as_me:$LINENO: error: unknown endianness+presetting ac_cv_c_bigendian=no (or yes) will help" >&5+echo "$as_me: error: unknown endianness+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}+   { (exit 1); exit 1; }; } ;;+esac+++++# Extract the first word of "haddock", so it can be a program name with args.+set dummy haddock; ac_word=$2+{ echo "$as_me:$LINENO: checking for $ac_word" >&5+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }+if test "${ac_cv_prog_HADDOCK+set}" = set; then+  echo $ECHO_N "(cached) $ECHO_C" >&6+else+  if test -n "$HADDOCK"; then+  ac_cv_prog_HADDOCK="$HADDOCK" # Let the user override the test.+else+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  for ac_exec_ext in '' $ac_executable_extensions; do+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then+    ac_cv_prog_HADDOCK="haddock"+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5+    break 2+  fi+done+done+IFS=$as_save_IFS++fi+fi+HADDOCK=$ac_cv_prog_HADDOCK+if test -n "$HADDOCK"; then+  { echo "$as_me:$LINENO: result: $HADDOCK" >&5+echo "${ECHO_T}$HADDOCK" >&6; }+else+  { echo "$as_me:$LINENO: result: no" >&5+echo "${ECHO_T}no" >&6; }+fi+++{ echo "$as_me:$LINENO: checking haddock version" >&5+echo $ECHO_N "checking haddock version... $ECHO_C" >&6; }+if test "$HADDOCK" = ""; then+   HADDOCK_VERSION=0+else+   HADDOCK_VERSION=`haddock --version | head -n 1 | sed 's/^.* \([0-9][0-9]*\)\..*/\1/g'`+fi++{ echo "$as_me:$LINENO: result: version $HADDOCK_VERSION" >&5+echo "${ECHO_T}version $HADDOCK_VERSION" >&6; }+if test "$HADDOCK_VERSION" -lt 2; then+   { echo "$as_me:$LINENO: WARNING: You need haddock 2.0.0 or later to build API docs" >&5+echo "$as_me: WARNING: You need haddock 2.0.0 or later to build API docs" >&2;}+fi+++if test -z "${datarootdir}"; then+   datarootdir=${datarootdir:-'${prefix}/share'}++fi+if test -z "${docdir}"; then+   docdir=${docdir:-'${datarootdir}/doc/${PACKAGE_TARNAME}'}++fi++++cat src/Workaround.hs.prefix src/Workaround.hs.beginning src/Workaround.hs.ending > src/Workaround.hs+rm -f src/Workaround.hs.beginning src/Workaround.hs.ending src/Workaround.hs.prefix++ac_config_files="$ac_config_files autoconf.mk src/Autoconf.lhs tools/cgi/darcs.cgi tools/cgi/README tools/cgi/cgi.conf darcs.buildinfo"++cat >confcache <<\_ACEOF+# This file is a shell script that caches the results of configure+# tests run on this system so they can be shared between configure+# scripts and configure runs, see configure's option --config-cache.+# It is not useful on other systems.  If it contains results you don't+# want to keep, you may remove or edit it.+#+# config.status only pays attention to the cache file if you give it+# the --recheck option to rerun configure.+#+# `ac_cv_env_foo' variables (set or unset) will be overridden when+# loading this file, other *unset* `ac_cv_foo' will be assigned the+# following values.++_ACEOF++# The following way of writing the cache mishandles newlines in values,+# but we know of no workaround that is simple, portable, and efficient.+# So, we kill variables containing newlines.+# Ultrix sh set writes to stderr and can't be redirected directly,+# and sets the high bit in the cache file unless we assign to the vars.+(+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do+    eval ac_val=\$$ac_var+    case $ac_val in #(+    *${as_nl}*)+      case $ac_var in #(+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;+      esac+      case $ac_var in #(+      _ | IFS | as_nl) ;; #(+      *) $as_unset $ac_var ;;+      esac ;;+    esac+  done++  (set) 2>&1 |+    case $as_nl`(ac_space=' '; set) 2>&1` in #(+    *${as_nl}ac_space=\ *)+      # `set' does not quote correctly, so add quotes (double-quote+      # substitution turns \\\\ into \\, and sed turns \\ into \).+      sed -n \+	"s/'/'\\\\''/g;+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"+      ;; #(+    *)+      # `set' quotes correctly as required by POSIX, so do not add quotes.+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"+      ;;+    esac |+    sort+) |+  sed '+     /^ac_cv_env_/b end+     t clear+     :clear+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/+     t end+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/+     :end' >>confcache+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else+  if test -w "$cache_file"; then+    test "x$cache_file" != "x/dev/null" &&+      { echo "$as_me:$LINENO: updating cache $cache_file" >&5+echo "$as_me: updating cache $cache_file" >&6;}+    cat confcache >$cache_file+  else+    { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5+echo "$as_me: not updating unwritable cache $cache_file" >&6;}+  fi+fi+rm -f confcache++test "x$prefix" = xNONE && prefix=$ac_default_prefix+# Let make expand exec_prefix.+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'++# Transform confdefs.h into DEFS.+# Protect against shell expansion while executing Makefile rules.+# Protect against Makefile macro expansion.+#+# If the first sed substitution is executed (which looks for macros that+# take arguments), then branch to the quote section.  Otherwise,+# look for a macro that doesn't take arguments.+ac_script='+t clear+:clear+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\)/-D\1=\2/g+t quote+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)/-D\1=\2/g+t quote+b any+:quote+s/[	 `~#$^&*(){}\\|;'\''"<>?]/\\&/g+s/\[/\\&/g+s/\]/\\&/g+s/\$/$$/g+H+:any+${+	g+	s/^\n//+	s/\n/ /g+	p+}+'+DEFS=`sed -n "$ac_script" confdefs.h`+++ac_libobjs=+ac_ltlibobjs=+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue+  # 1. Remove the extension, and $U if already installed.+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'+  ac_i=`echo "$ac_i" | sed "$ac_script"`+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR+  #    will be set to the directory where LIBOBJS objects are built.+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'+done+LIBOBJS=$ac_libobjs++LTLIBOBJS=$ac_ltlibobjs++++: ${CONFIG_STATUS=./config.status}+ac_clean_files_save=$ac_clean_files+ac_clean_files="$ac_clean_files $CONFIG_STATUS"+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5+echo "$as_me: creating $CONFIG_STATUS" >&6;}+cat >$CONFIG_STATUS <<_ACEOF+#! $SHELL+# Generated by $as_me.+# Run this file to recreate the current configuration.+# Compiler output produced by configure, useful for debugging+# configure, is in config.log if it exists.++debug=false+ac_cs_recheck=false+ac_cs_silent=false+SHELL=\${CONFIG_SHELL-$SHELL}+_ACEOF++cat >>$CONFIG_STATUS <<\_ACEOF+## --------------------- ##+## M4sh Initialization.  ##+## --------------------- ##++# Be more Bourne compatible+DUALCASE=1; export DUALCASE # for MKS sh+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then+  emulate sh+  NULLCMD=:+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which+  # is contrary to our usage.  Disable this feature.+  alias -g '${1+"$@"}'='"$@"'+  setopt NO_GLOB_SUBST+else+  case `(set -o) 2>/dev/null` in+  *posix*) set -o posix ;;+esac++fi+++++# PATH needs CR+# Avoid depending upon Character Ranges.+as_cr_letters='abcdefghijklmnopqrstuvwxyz'+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'+as_cr_Letters=$as_cr_letters$as_cr_LETTERS+as_cr_digits='0123456789'+as_cr_alnum=$as_cr_Letters$as_cr_digits++# The user is always right.+if test "${PATH_SEPARATOR+set}" != set; then+  echo "#! /bin/sh" >conf$$.sh+  echo  "exit 0"   >>conf$$.sh+  chmod +x conf$$.sh+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then+    PATH_SEPARATOR=';'+  else+    PATH_SEPARATOR=:+  fi+  rm -f conf$$.sh+fi++# Support unset when possible.+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then+  as_unset=unset+else+  as_unset=false+fi+++# IFS+# We need space, tab and new line, in precisely that order.  Quoting is+# there to prevent editors from complaining about space-tab.+# (If _AS_PATH_WALK were called with IFS unset, it would disable word+# splitting by setting IFS to empty value.)+as_nl='+'+IFS=" ""	$as_nl"++# Find who we are.  Look in the path if we contain no directory separator.+case $0 in+  *[\\/]* ) as_myself=$0 ;;+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR+for as_dir in $PATH+do+  IFS=$as_save_IFS+  test -z "$as_dir" && as_dir=.+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break+done+IFS=$as_save_IFS++     ;;+esac+# We did not find ourselves, most probably we were run as `sh COMMAND'+# in which case we are not to be found in the path.+if test "x$as_myself" = x; then+  as_myself=$0+fi+if test ! -f "$as_myself"; then+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2+  { (exit 1); exit 1; }+fi++# Work around bugs in pre-3.0 UWIN ksh.+for as_var in ENV MAIL MAILPATH+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var+done+PS1='$ '+PS2='> '+PS4='+ '++# NLS nuisances.+for as_var in \+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \+  LC_TELEPHONE LC_TIME+do+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then+    eval $as_var=C; export $as_var+  else+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var+  fi+done++# Required to use basename.+if expr a : '\(a\)' >/dev/null 2>&1 &&+   test "X`expr 00001 : '.*\(...\)'`" = X001; then+  as_expr=expr+else+  as_expr=false+fi++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then+  as_basename=basename+else+  as_basename=false+fi+++# Name of the executable.+as_me=`$as_basename -- "$0" ||+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \+	 X"$0" : 'X\(//\)$' \| \+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||+echo X/"$0" |+    sed '/^.*\/\([^/][^/]*\)\/*$/{+	    s//\1/+	    q+	  }+	  /^X\/\(\/\/\)$/{+	    s//\1/+	    q+	  }+	  /^X\/\(\/\).*/{+	    s//\1/+	    q+	  }+	  s/.*/./; q'`++# CDPATH.+$as_unset CDPATH++++  as_lineno_1=$LINENO+  as_lineno_2=$LINENO+  test "x$as_lineno_1" != "x$as_lineno_2" &&+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {++  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO+  # uniformly replaced by the line number.  The first 'sed' inserts a+  # line-number line after each line using $LINENO; the second 'sed'+  # does the real work.  The second script uses 'N' to pair each+  # line-number line with the line containing $LINENO, and appends+  # trailing '-' during substitution so that $LINENO is not a special+  # case at line end.+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the+  # scripts with optimization help from Paolo Bonzini.  Blame Lee+  # E. McMahon (1931-1989) for sed's syntax.  :-)+  sed -n '+    p+    /[$]LINENO/=+  ' <$as_myself |+    sed '+      s/[$]LINENO.*/&-/+      t lineno+      b+      :lineno+      N+      :loop+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/+      t loop+      s/-\n.*//+    ' >$as_me.lineno &&+  chmod +x "$as_me.lineno" ||+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2+   { (exit 1); exit 1; }; }++  # Don't try to exec as it changes $[0], causing all sort of problems+  # (the dirname of $[0] is not the place where we might find the+  # original and so on.  Autoconf is especially sensitive to this).+  . "./$as_me.lineno"+  # Exit status is that of the last command.+  exit+}+++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then+  as_dirname=dirname+else+  as_dirname=false+fi++ECHO_C= ECHO_N= ECHO_T=+case `echo -n x` in+-n*)+  case `echo 'x\c'` in+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.+  *)   ECHO_C='\c';;+  esac;;+*)+  ECHO_N='-n';;+esac++if expr a : '\(a\)' >/dev/null 2>&1 &&+   test "X`expr 00001 : '.*\(...\)'`" = X001; then+  as_expr=expr+else+  as_expr=false+fi++rm -f conf$$ conf$$.exe conf$$.file+if test -d conf$$.dir; then+  rm -f conf$$.dir/conf$$.file+else+  rm -f conf$$.dir+  mkdir conf$$.dir+fi+echo >conf$$.file+if ln -s conf$$.file conf$$ 2>/dev/null; then+  as_ln_s='ln -s'+  # ... but there are two gotchas:+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.+  # In both cases, we have to default to `cp -p'.+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||+    as_ln_s='cp -p'+elif ln conf$$.file conf$$ 2>/dev/null; then+  as_ln_s=ln+else+  as_ln_s='cp -p'+fi+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file+rmdir conf$$.dir 2>/dev/null++if mkdir -p . 2>/dev/null; then+  as_mkdir_p=:+else+  test -d ./-p && rmdir ./-p+  as_mkdir_p=false+fi++if test -x / >/dev/null 2>&1; then+  as_test_x='test -x'+else+  if ls -dL / >/dev/null 2>&1; then+    as_ls_L_option=L+  else+    as_ls_L_option=+  fi+  as_test_x='+    eval sh -c '\''+      if test -d "$1"; then+        test -d "$1/.";+      else+	case $1 in+        -*)set "./$1";;+	esac;+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in+	???[sx]*):;;*)false;;esac;fi+    '\'' sh+  '+fi+as_executable_p=$as_test_x++# Sed expression to map a string onto a valid CPP name.+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"++# Sed expression to map a string onto a valid variable name.+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"+++exec 6>&1++# Save the log message, to keep $[0] and so on meaningful, and to+# report actual input values of CONFIG_FILES etc. instead of their+# values after options handling.+ac_log="+This file was extended by darcs $as_me 2.0.2, which was+generated by GNU Autoconf 2.61.  Invocation command line was++  CONFIG_FILES    = $CONFIG_FILES+  CONFIG_HEADERS  = $CONFIG_HEADERS+  CONFIG_LINKS    = $CONFIG_LINKS+  CONFIG_COMMANDS = $CONFIG_COMMANDS+  $ $0 $@++on `(hostname || uname -n) 2>/dev/null | sed 1q`+"++_ACEOF++cat >>$CONFIG_STATUS <<_ACEOF+# Files that config.status was made for.+config_files="$ac_config_files"+config_commands="$ac_config_commands"++_ACEOF++cat >>$CONFIG_STATUS <<\_ACEOF+ac_cs_usage="\+\`$as_me' instantiates files from templates according to the+current configuration.++Usage: $0 [OPTIONS] [FILE]...++  -h, --help       print this help, then exit+  -V, --version    print version number and configuration settings, then exit+  -q, --quiet      do not print progress messages+  -d, --debug      don't remove temporary files+      --recheck    update $as_me by reconfiguring in the same conditions+  --file=FILE[:TEMPLATE]+		   instantiate the configuration file FILE++Configuration files:+$config_files++Configuration commands:+$config_commands++Report bugs to <bug-autoconf@gnu.org>."++_ACEOF+cat >>$CONFIG_STATUS <<_ACEOF+ac_cs_version="\\+darcs config.status 2.0.2+configured by $0, generated by GNU Autoconf 2.61,+  with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"++Copyright (C) 2006 Free Software Foundation, Inc.+This config.status script is free software; the Free Software Foundation+gives unlimited permission to copy, distribute and modify it."++ac_pwd='$ac_pwd'+srcdir='$srcdir'+INSTALL='$INSTALL'+_ACEOF++cat >>$CONFIG_STATUS <<\_ACEOF+# If no file are specified by the user, then we need to provide default+# value.  By we need to know if files were specified by the user.+ac_need_defaults=:+while test $# != 0+do+  case $1 in+  --*=*)+    ac_option=`expr "X$1" : 'X\([^=]*\)='`+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`+    ac_shift=:+    ;;+  *)+    ac_option=$1+    ac_optarg=$2+    ac_shift=shift+    ;;+  esac++  case $ac_option in+  # Handling of the options.+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)+    ac_cs_recheck=: ;;+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )+    echo "$ac_cs_version"; exit ;;+  --debug | --debu | --deb | --de | --d | -d )+    debug=: ;;+  --file | --fil | --fi | --f )+    $ac_shift+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"+    ac_need_defaults=false;;+  --he | --h |  --help | --hel | -h )+    echo "$ac_cs_usage"; exit ;;+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \+  | -silent | --silent | --silen | --sile | --sil | --si | --s)+    ac_cs_silent=: ;;++  # This is an error.+  -*) { echo "$as_me: error: unrecognized option: $1+Try \`$0 --help' for more information." >&2+   { (exit 1); exit 1; }; } ;;++  *) ac_config_targets="$ac_config_targets $1"+     ac_need_defaults=false ;;++  esac+  shift+done++ac_configure_extra_args=++if $ac_cs_silent; then+  exec 6>/dev/null+  ac_configure_extra_args="$ac_configure_extra_args --silent"+fi++_ACEOF+cat >>$CONFIG_STATUS <<_ACEOF+if \$ac_cs_recheck; then+  echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6+  CONFIG_SHELL=$SHELL+  export CONFIG_SHELL+  exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion+fi++_ACEOF+cat >>$CONFIG_STATUS <<\_ACEOF+exec 5>>config.log+{+  echo+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX+## Running $as_me. ##+_ASBOX+  echo "$ac_log"+} >&5++_ACEOF+cat >>$CONFIG_STATUS <<_ACEOF+#+# INIT-COMMANDS+#+date="`date`"; args="$ac_cmdline_args"++_ACEOF++cat >>$CONFIG_STATUS <<\_ACEOF++# Handling of arguments.+for ac_config_target in $ac_config_targets+do+  case $ac_config_target in+    "config.command") CONFIG_COMMANDS="$CONFIG_COMMANDS config.command" ;;+    "autoconf.mk") CONFIG_FILES="$CONFIG_FILES autoconf.mk" ;;+    "src/Autoconf.lhs") CONFIG_FILES="$CONFIG_FILES src/Autoconf.lhs" ;;+    "tools/cgi/darcs.cgi") CONFIG_FILES="$CONFIG_FILES tools/cgi/darcs.cgi" ;;+    "tools/cgi/README") CONFIG_FILES="$CONFIG_FILES tools/cgi/README" ;;+    "tools/cgi/cgi.conf") CONFIG_FILES="$CONFIG_FILES tools/cgi/cgi.conf" ;;+    "darcs.buildinfo") CONFIG_FILES="$CONFIG_FILES darcs.buildinfo" ;;++  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}+   { (exit 1); exit 1; }; };;+  esac+done+++# If the user did not use the arguments to specify the items to instantiate,+# then the envvar interface is used.  Set only those that are not.+# We use the long form for the default assignment because of an extremely+# bizarre bug on SunOS 4.1.3.+if $ac_need_defaults; then+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands+fi++# Have a temporary directory for convenience.  Make it in the build tree+# simply because there is no reason against having it here, and in addition,+# creating and moving files from /tmp can sometimes cause problems.+# Hook for its removal unless debugging.+# Note that there is a small window in which the directory will not be cleaned:+# after its creation but before its name has been assigned to `$tmp'.+$debug ||+{+  tmp=+  trap 'exit_status=$?+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status+' 0+  trap '{ (exit 1); exit 1; }' 1 2 13 15+}+# Create a (secure) tmp directory for tmp files.++{+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&+  test -n "$tmp" && test -d "$tmp"+}  ||+{+  tmp=./conf$$-$RANDOM+  (umask 077 && mkdir "$tmp")+} ||+{+   echo "$me: cannot create a temporary directory in ." >&2+   { (exit 1); exit 1; }+}++#+# Set up the sed scripts for CONFIG_FILES section.+#++# No need to generate the scripts if there are no CONFIG_FILES.+# This happens for instance when ./config.status config.h+if test -n "$CONFIG_FILES"; then++_ACEOF++++ac_delim='%!_!# '+for ac_last_try in false false false false false :; do+  cat >conf$$subs.sed <<_ACEOF+SHELL!$SHELL$ac_delim+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim+PACKAGE_NAME!$PACKAGE_NAME$ac_delim+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim+PACKAGE_STRING!$PACKAGE_STRING$ac_delim+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim+exec_prefix!$exec_prefix$ac_delim+prefix!$prefix$ac_delim+program_transform_name!$program_transform_name$ac_delim+bindir!$bindir$ac_delim+sbindir!$sbindir$ac_delim+libexecdir!$libexecdir$ac_delim+datarootdir!$datarootdir$ac_delim+datadir!$datadir$ac_delim+sysconfdir!$sysconfdir$ac_delim+sharedstatedir!$sharedstatedir$ac_delim+localstatedir!$localstatedir$ac_delim+includedir!$includedir$ac_delim+oldincludedir!$oldincludedir$ac_delim+docdir!$docdir$ac_delim+infodir!$infodir$ac_delim+htmldir!$htmldir$ac_delim+dvidir!$dvidir$ac_delim+pdfdir!$pdfdir$ac_delim+psdir!$psdir$ac_delim+libdir!$libdir$ac_delim+localedir!$localedir$ac_delim+mandir!$mandir$ac_delim+DEFS!$DEFS$ac_delim+ECHO_C!$ECHO_C$ac_delim+ECHO_N!$ECHO_N$ac_delim+ECHO_T!$ECHO_T$ac_delim+LIBS!$LIBS$ac_delim+build_alias!$build_alias$ac_delim+host_alias!$host_alias$ac_delim+target_alias!$target_alias$ac_delim+DARCS_VERSION!$DARCS_VERSION$ac_delim+DARCS!$DARCS$ac_delim+I_AM_IN_REPO!$I_AM_IN_REPO$ac_delim+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim+INSTALL_DATA!$INSTALL_DATA$ac_delim+CC!$CC$ac_delim+CFLAGS!$CFLAGS$ac_delim+LDFLAGS!$LDFLAGS$ac_delim+CPPFLAGS!$CPPFLAGS$ac_delim+ac_ct_CC!$ac_ct_CC$ac_delim+EXEEXT!$EXEEXT$ac_delim+OBJEXT!$OBJEXT$ac_delim+CPP!$CPP$ac_delim+GREP!$GREP$ac_delim+EGREP!$EGREP$ac_delim+SYS!$SYS$ac_delim+GHC!$GHC$ac_delim+GHCFLAGS!$GHCFLAGS$ac_delim+HAVE_HTTP!$HAVE_HTTP$ac_delim+GHC_SEPARATOR!$GHC_SEPARATOR$ac_delim+USE_MMAP!$USE_MMAP$ac_delim+LATEX!$LATEX$ac_delim+PDFLATEX!$PDFLATEX$ac_delim+DVIPS!$DVIPS$ac_delim+LATEX2HTML!$LATEX2HTML$ac_delim+HTLATEX!$HTLATEX$ac_delim+HEVEA!$HEVEA$ac_delim+TARGETS!$TARGETS$ac_delim+MAKEMANUAL!$MAKEMANUAL$ac_delim+INSTALLWHAT!$INSTALLWHAT$ac_delim+PREPROCHTML!$PREPROCHTML$ac_delim+SENDMAIL!$SENDMAIL$ac_delim+HAVE_SENDMAIL!$HAVE_SENDMAIL$ac_delim+HAVE_MAPI!$HAVE_MAPI$ac_delim+USE_COLOR!$USE_COLOR$ac_delim+HAVE_CURSES!$HAVE_CURSES$ac_delim+DIFF!$DIFF$ac_delim+MAKENSIS!$MAKENSIS$ac_delim+BIGENDIAN!$BIGENDIAN$ac_delim+HADDOCK!$HADDOCK$ac_delim+HADDOCK_VERSION!$HADDOCK_VERSION$ac_delim+LIBOBJS!$LIBOBJS$ac_delim+LTLIBOBJS!$LTLIBOBJS$ac_delim+_ACEOF++  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 81; then+    break+  elif $ac_last_try; then+    { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}+   { (exit 1); exit 1; }; }+  else+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "+  fi+done++ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`+if test -n "$ac_eof"; then+  ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`+  ac_eof=`expr $ac_eof + 1`+fi++cat >>$CONFIG_STATUS <<_ACEOF+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end+_ACEOF+sed '+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g+s/^/s,@/; s/!/@,|#_!!_#|/+:n+t n+s/'"$ac_delim"'$/,g/; t+s/$/\\/; p+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n+' >>$CONFIG_STATUS <conf$$subs.sed+rm -f conf$$subs.sed+cat >>$CONFIG_STATUS <<_ACEOF+:end+s/|#_!!_#|//g+CEOF$ac_eof+_ACEOF+++# VPATH may cause trouble with some makes, so we remove $(srcdir),+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and+# trailing colons and then remove the whole line if VPATH becomes empty+# (actually we leave an empty line to preserve line numbers).+if test "x$srcdir" = x.; then+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{+s/:*\$(srcdir):*/:/+s/:*\${srcdir}:*/:/+s/:*@srcdir@:*/:/+s/^\([^=]*=[	 ]*\):*/\1/+s/:*$//+s/^[^=]*=[	 ]*$//+}'+fi++cat >>$CONFIG_STATUS <<\_ACEOF+fi # test -n "$CONFIG_FILES"+++for ac_tag in  :F $CONFIG_FILES      :C $CONFIG_COMMANDS+do+  case $ac_tag in+  :[FHLC]) ac_mode=$ac_tag; continue;;+  esac+  case $ac_mode$ac_tag in+  :[FHL]*:*);;+  :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5+echo "$as_me: error: Invalid tag $ac_tag." >&2;}+   { (exit 1); exit 1; }; };;+  :[FH]-) ac_tag=-:-;;+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;+  esac+  ac_save_IFS=$IFS+  IFS=:+  set x $ac_tag+  IFS=$ac_save_IFS+  shift+  ac_file=$1+  shift++  case $ac_mode in+  :L) ac_source=$1;;+  :[FH])+    ac_file_inputs=+    for ac_f+    do+      case $ac_f in+      -) ac_f="$tmp/stdin";;+      *) # Look for the file first in the build tree, then in the source tree+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,+	 # because $ac_f cannot contain `:'.+	 test -f "$ac_f" ||+	   case $ac_f in+	   [\\/$]*) false;;+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;+	   esac ||+	   { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5+echo "$as_me: error: cannot find input file: $ac_f" >&2;}+   { (exit 1); exit 1; }; };;+      esac+      ac_file_inputs="$ac_file_inputs $ac_f"+    done++    # Let's still pretend it is `configure' which instantiates (i.e., don't+    # use $as_me), people would be surprised to read:+    #    /* config.h.  Generated by config.status.  */+    configure_input="Generated from "`IFS=:+	  echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."+    if test x"$ac_file" != x-; then+      configure_input="$ac_file.  $configure_input"+      { echo "$as_me:$LINENO: creating $ac_file" >&5+echo "$as_me: creating $ac_file" >&6;}+    fi++    case $ac_tag in+    *:-:* | *:-) cat >"$tmp/stdin";;+    esac+    ;;+  esac++  ac_dir=`$as_dirname -- "$ac_file" ||+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \+	 X"$ac_file" : 'X\(//\)[^/]' \| \+	 X"$ac_file" : 'X\(//\)$' \| \+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||+echo X"$ac_file" |+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{+	    s//\1/+	    q+	  }+	  /^X\(\/\/\)[^/].*/{+	    s//\1/+	    q+	  }+	  /^X\(\/\/\)$/{+	    s//\1/+	    q+	  }+	  /^X\(\/\).*/{+	    s//\1/+	    q+	  }+	  s/.*/./; q'`+  { as_dir="$ac_dir"+  case $as_dir in #(+  -*) as_dir=./$as_dir;;+  esac+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {+    as_dirs=+    while :; do+      case $as_dir in #(+      *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(+      *) as_qdir=$as_dir;;+      esac+      as_dirs="'$as_qdir' $as_dirs"+      as_dir=`$as_dirname -- "$as_dir" ||+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \+	 X"$as_dir" : 'X\(//\)[^/]' \| \+	 X"$as_dir" : 'X\(//\)$' \| \+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||+echo X"$as_dir" |+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{+	    s//\1/+	    q+	  }+	  /^X\(\/\/\)[^/].*/{+	    s//\1/+	    q+	  }+	  /^X\(\/\/\)$/{+	    s//\1/+	    q+	  }+	  /^X\(\/\).*/{+	    s//\1/+	    q+	  }+	  s/.*/./; q'`+      test -d "$as_dir" && break+    done+    test -z "$as_dirs" || eval "mkdir $as_dirs"+  } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5+echo "$as_me: error: cannot create directory $as_dir" >&2;}+   { (exit 1); exit 1; }; }; }+  ac_builddir=.++case "$ac_dir" in+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;+*)+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`+  # A ".." for each directory in $ac_dir_suffix.+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`+  case $ac_top_builddir_sub in+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;+  esac ;;+esac+ac_abs_top_builddir=$ac_pwd+ac_abs_builddir=$ac_pwd$ac_dir_suffix+# for backward compatibility:+ac_top_builddir=$ac_top_build_prefix++case $srcdir in+  .)  # We are building in place.+    ac_srcdir=.+    ac_top_srcdir=$ac_top_builddir_sub+    ac_abs_top_srcdir=$ac_pwd ;;+  [\\/]* | ?:[\\/]* )  # Absolute name.+    ac_srcdir=$srcdir$ac_dir_suffix;+    ac_top_srcdir=$srcdir+    ac_abs_top_srcdir=$srcdir ;;+  *) # Relative name.+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix+    ac_top_srcdir=$ac_top_build_prefix$srcdir+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;+esac+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix+++  case $ac_mode in+  :F)+  #+  # CONFIG_FILE+  #++  case $INSTALL in+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;+  esac+_ACEOF+++# Neutralize VPATH when `$srcdir' = `.'.+# Shell code in configure.ac might set extrasub.+# FIXME: do we really want to maintain this feature?+cat >>$CONFIG_STATUS <<_ACEOF+  sed "$ac_vpsub+$extrasub+_ACEOF+cat >>$CONFIG_STATUS <<\_ACEOF+:t+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b+s&@configure_input@&$configure_input&;t t+s&@top_builddir@&$ac_top_builddir_sub&;t t+s&@srcdir@&$ac_srcdir&;t t+s&@abs_srcdir@&$ac_abs_srcdir&;t t+s&@top_srcdir@&$ac_top_srcdir&;t t+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t+s&@builddir@&$ac_builddir&;t t+s&@abs_builddir@&$ac_abs_builddir&;t t+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t+s&@INSTALL@&$ac_INSTALL&;t t+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out+++  rm -f "$tmp/stdin"+  case $ac_file in+  -) cat "$tmp/out"; rm -f "$tmp/out";;+  *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;+  esac+ ;;+++  :C)  { echo "$as_me:$LINENO: executing $ac_file commands" >&5+echo "$as_me: executing $ac_file commands" >&6;}+ ;;+  esac+++  case $ac_file$ac_mode in+    "config.command":C)  echo > config.command "# configured $date"+                     echo >>config.command "./configure $args"+		     chmod +x config.command+                    ;;++  esac+done # for ac_tag+++{ (exit 0); exit 0; }+_ACEOF+chmod +x $CONFIG_STATUS+ac_clean_files=$ac_clean_files_save+++# configure is writing to config.log, and then calls config.status.+# config.status does its own redirection, appending to config.log.+# Unfortunately, on DOS this fails, as config.log is still kept open+# by configure, so config.status won't be able to write to it; its+# output is simply discarded.  So we exec the FD to /dev/null,+# effectively closing config.log, so it can be properly (re)opened and+# appended to by config.status.  When coming back to configure, we+# need to make the FD available again.+if test "$no_create" != yes; then+  ac_cs_success=:+  ac_config_status_args=+  test "$silent" = yes &&+    ac_config_status_args="$ac_config_status_args --quiet"+  exec 5>/dev/null+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false+  exec 5>>config.log+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which+  # would make configure fail if this is the last instruction.+  $ac_cs_success || { (exit 1); exit 1; }+fi+++cat <<EOF++The build is configured as follows:++    bindir          = $bindir+    sbindir         = $sbindir+    mandir          = $mandir+    datadir         = $datadir+    sysconfdir      = $sysconfdir+    libexecdir      = $libexecdir++    Build Manual    = $BUILDDOC++If you want to adjust any of these values, edit autoconf.mk and+src/Autoconf.lhs -- or run configure with appropriate settings.++EOF+
+ configure.ac view
@@ -0,0 +1,607 @@+dnl This file is in the public domain.++dnl Process this file with Autoconf to produce a configure script.++dnl Remove the datarootdir/docdir tests below if this is increased:+AC_PREREQ([2.59])+AC_INIT([darcs], [2.0.2], [bugs@darcs.net])+AC_CONFIG_SRCDIR([src/darcs.lhs])++dnl Write our invocation date/time and flags into a file so that+dnl Darcs knows how it was built.++ac_cmdline_args="$*"+AC_CONFIG_COMMANDS([config.command],+                   [ echo > config.command "# configured $date"+                     echo >>config.command "./configure $args"+		     chmod +x config.command+                   ],+                   [date="`date`"; args="$ac_cmdline_args"])++dnl The following is now the authoritative location of the version+dnl number. All references to the darcs version number should+dnl originate here. From Haskell this is easily done by importing+dnl the module "Autoconf ( darcs_version )".+dnl+dnl The version string must not contain any spaces. The version+dnl state will automatically be set to any of:+dnl+dnl    "prerelease #n"+dnl    "release candidate #n"+dnl    "release"+dnl    "unstable branch"+dnl    "stable branch"+dnl    "unknown branch"+dnl+dnl The new darcs custom is to increase the version number+dnl directly after a release, since the checking for a tag+dnl indicates whether the number is really correct.++DARCS_VERSION=$PACKAGE_VERSION+AC_SUBST(DARCS_VERSION)++dnl See if we are in a darcs repo and also have darcs available,+dnl and whether we're in a repository...++AC_CHECK_PROG(DARCS, darcs, darcs)+AC_MSG_CHECKING([if we're in a darcs repository])+if test ! -z "$DARCS" && test -e "_darcs/hashed_inventory"; then+  I_AM_IN_REPO=yes+else+  I_AM_IN_REPO=no+fi+AC_MSG_RESULT($I_AM_IN_REPO)+AC_SUBST(I_AM_IN_REPO)++dnl Get rid of the lousy '-g -O2' defaults++CFLAGS=$CFLAGS++dnl Find gcc++dnl AC_PROG_CC+dnl AC_PROG_CPP++dnl Make sure a decent "install" is installed.++AC_PROG_INSTALL++dnl Check to see if we are compiling under Windows++AC_CHECK_HEADER(windows.h, [SYS=windows], [SYS=other])+AC_SUBST(SYS)++dnl Find ghc++AC_CHECK_PROG(GHC, ghc, ghc)+if test -z "$GHC"; then+    AC_MSG_ERROR([Cannot find ghc in your path; please set the GHC environment variable!!])+fi+AC_SUBST(GHCFLAGS)+echo found `$GHC --version`++dnl Make sure compiler actually works:++TRY_COMPILE_GHC([main = putStr "Hello world!\n"],,+                AC_MSG_ERROR(Compile failed.))++dnl Before anything else, we need to decide what core compiler features to+dnl use, becaues this affects all the tests below (e.g. some packages may+dnl not be available with profiling)++dnl Make default to not profile...++AC_MSG_CHECKING([whether to profile])+AC_ARG_ENABLE(profile,+              AS_HELP_STRING([--enable-profile],[enable profiling]),+              profile=$enableval,profile=no)+AC_MSG_RESULT($profile)++if test "$profile" = yes; then+   GHCFLAGS="$GHCFLAGS -prof -auto-all"+fi++dnl See if we want to use -threaded to get more responsive progress reporting.+AC_MSG_CHECKING([whether to use the threaded runtime])+AC_ARG_ENABLE(threaded,AS_HELP_STRING([--disable-threaded],+              [don't compile with threaded runtime]),[AC_MSG_RESULT([no])],+              [MYOLDGHCFLAGS=$GHCFLAGS+               GHCFLAGS="$GHCFLAGS -threaded"+               TRY_COMPILE_GHC([main = putStr "Hello world!\n"],+                [AC_MSG_RESULT([yes])],+                [AC_MSG_RESULT([failed, threaded runtime disabled])+                 AC_MSG_WARN([Unable to compile with threaded runtime!])+                 GHCFLAGS=$MYOLDGHCFLAGS])])++INIT_WORKAROUND++dnl Figure out how to convert a file descriptor to a Handle++WORKAROUND_openFd++dnl Handle posix signals nicely:++WORKAROUND_POSIXSIGNALS([installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,])++AC_CHECK_HEADERS([siginfo.h])++dnl Look for Text.Regex++GHC_CHECK_MODULE(Text.Regex( mkRegex, matchRegex, Regex ), text, mkRegex undefined,,+  GHC_CHECK_MODULE(Text.Regex( mkRegex, matchRegex, Regex ), regex-compat, mkRegex undefined,,+    AC_MSG_ERROR(Cannot find Test.Regex; try installing the package text or regex-compat?)+  )+)++dnl Look for native http library++GHC_CHECK_MODULE(Network.HTTP( urlEncode ), HTTP, urlEncode undefined,+                 [HAVE_HTTP=True+                  AC_DEFINE([HAVE_HTTP])],[HAVE_HTTP=False])++AC_SUBST(HAVE_HTTP)++dnl See if we need a package for QuickCheck++GHC_CHECK_MODULE(Test.QuickCheck( quickCheck ), QuickCheck, quickCheck True,,+                 AC_MSG_ERROR(Cannot find Test.QuickCheck; try installing package quickcheck?))++dnl See if we have an adequate version of bytestring+GHC_CHECK_MODULE(Data.ByteString.Internal( fromForeignPtr ),+                 bytestring,+                 fromForeignPtr,+                 [bytestringfound=yes],+                 [bytestringfound=no])+if test $bytestringfound = "yes"; then+  AC_MSG_CHECKING([whether to use ByteString])+  AC_ARG_ENABLE(bytestring,+                AS_HELP_STRING([--disable-bytestring], [do not use bytestring, even if it is present]),+                bytestring=$enableval,+                bytestring=yes)+  AC_MSG_RESULT($bytestring)+  # If we aren't instructed to avoid bytestring, and we did successfully find bytestring...+  if test $bytestring = "yes"; then+     CPPFLAGS="$CPPFLAGS -DHAVE_BYTESTRING"+  fi+fi++dnl See if we need the util or mtl packages for Control.Monad++GHC_CHECK_MODULE(Control.Monad.Error, mtl, strMsg "foo" :: String,,+                 AC_MSG_ERROR(Cannot find Control.Monad.Error; try installing package mtl?))++dnl See if we need a package for parsec...++GHC_CHECK_MODULE(Text.ParserCombinators.Parsec, parsec, errorPos undefined,,+                 AC_MSG_ERROR(Cannot find Text.ParserCombinators.Parsec; try installing package parsec?))++dnl Check if we need package html++GHC_CHECK_MODULE(Text.Html, html, text "foo",,+                 AC_MSG_ERROR(Cannot find Text.Html; try installing package html?))++dnl Check if we need package containers++GHC_CHECK_MODULE(Data.Map, containers, empty,,+                 AC_MSG_ERROR(Cannot find Data.Map; try installing package containers?))++dnl Deal with systems on which getCurrentDirectory uses '\\' rather than '/':++WORKAROUND_getCurrentDirectory+AC_SUBST(GHC_SEPARATOR)++dnl Deal with systems without createLink++WORKAROUND_createLink++dnl Deal with GHCs without createDirectoryIfMissing++WORKAROUND_createDirectoryIfMissing++dnl Handle systems with a buggy renameFile++WORKAROUND_renameFile++dnl Deal with systems without bracketWithError++WORKAROUND_bracketOnError++dnl Handle systems that don't do POSIX file modes++WORKAROUND_fileModes++WORKAROUND_executable++dnl Make default to have optimizations on...++AC_MSG_CHECKING([whether to optimize])+AC_ARG_ENABLE(optimize,+              AS_HELP_STRING([--disable-optimize],[disable optimization]),+              optimize=$enableval, optimize=yes)+AC_MSG_RESULT($optimize)++if test "$optimize" = yes; then+   GHCFLAGS="$GHCFLAGS -O2 -funbox-strict-fields"+   if test "$CFLAGS" = ""; then+      CFLAGS="$CFLAGS -O2"+   fi+fi++dnl Make default to not use hpc++AC_MSG_CHECKING([whether to use Haskell Program Coverage])+AC_ARG_ENABLE(hpc,+              AS_HELP_STRING([--enable-hpc],[enable Haskell Program Coverage]),+              hpc=$enableval,hpc=no)+AC_MSG_RESULT($hpc)++if test "$hpc" = yes; then+   GHCFLAGS="$GHCFLAGS -fhpc"+fi++dnl See if we want to use mmap... defaults to yes, except under+dnl Windows, where this is always disabled.++AC_MSG_CHECKING([whether to use mmap])+AC_ARG_ENABLE(mmap, AS_HELP_STRING([--disable-mmap],+              [do not use mmap (use this flag if you get bus errors)]),+              enable_mmap=$enableval,enable_mmap=yes)+if test "$SYS" = "windows"; then+  AC_MSG_RESULT(no (Windows))+else+  AC_MSG_RESULT($enable_mmap)+fi+USE_MMAP="True"+if test "$enable_mmap" = "no" || test "$SYS" = "windows" ; then+    USE_MMAP="False"+fi+AC_SUBST(USE_MMAP)++TARGETS="darcs doc/darcs.1"+INSTALLWHAT="installbin"+BUILDDOC="no"++dnl Check whether to generate the AUTHORS and ChangeLog files...+if test -d "_darcs"; then+  TARGETS="$TARGETS AUTHORS ChangeLog"+fi++dnl Check whether to use crazy PackedString debugging...++AC_MSG_CHECKING([whether to do PackedString debugging])+AC_ARG_ENABLE(debug-ps,+              [  --enable-debug-ps       enable PackedString debug mode],+               debugps=$enableval, debugps=no)+AC_MSG_RESULT($debugps)+++if test "$debugps" = yes; then+   GHCFLAGS="$GHCFLAGS -DDEBUG_PS"+fi++dnl Find latex and friends++AC_MSG_CHECKING([whether to build docs])+AC_ARG_WITH(docs,+	AS_HELP_STRING([--without-docs],+                           [do not try to build docs]),+           ,with_docs=yes)+AC_MSG_RESULT($with_docs)++if test "$with_docs" = "yes"; then+	AC_CHECK_PROG(LATEX, latex, latex)+	if test -z "$LATEX"; then+	AC_MSG_WARN([Cannot find latex in your path!])+	fi+	AC_CHECK_PROG(PDFLATEX, pdflatex, pdflatex)+	if test -z "$PDFLATEX"; then+	AC_MSG_WARN([Cannot find pdflatex in your path!])+	fi+	AC_CHECK_PROG(DVIPS, dvips, dvips)+	if test -z "$DVIPS"; then+	AC_MSG_WARN([Cannot find dvips in your path!])+	fi+	if test ! '(' '(' -z "$LATEX" ')' -o '(' -z "$DVIPS" ')' ')'; then+	TARGETS="$TARGETS doc/manual/darcs.ps"+	INSTALLWHAT="$INSTALLWHAT installdocs"+	BUILDDOC="yes"+	fi+	if test ! '(' -z "$PDFLATEX" ')'; then+	TARGETS="$TARGETS doc/manual/darcs.pdf doc/manual/patch-theory.pdf"+	fi+	AC_CHECK_PROG(LATEX2HTML, latex2html, latex2html)+	if test -z "$LATEX2HTML"; then+	AC_MSG_WARN([Cannot find latex2html in your path!])+	PREPROCHTML=""+	AC_CHECK_PROG(HTLATEX, htlatex, htlatex)+	if test -z "$HTLATEX"; then+		AC_MSG_WARN([Cannot find htlatex in your path either!])+		AC_CHECK_PROG(HEVEA, hevea, hevea)+		if test -z "$HEVEA"; then+		AC_MSG_WARN([Cannot find hevea in your path either!])+		MAKEMANUAL="touch doc/manual/index.html; echo Cannot make manual!"+		else+		TARGETS="$TARGETS doc/manual/index.html"+		MAKEMANUAL="$HEVEA -o doc/manual/index.html src/darcs.tex"+		fi+	else+		TARGETS="$TARGETS doc/manual/index.html"+		MAKEMANUAL="cd doc/manual && $HTLATEX ../../src/darcs.tex && ln -sf darcs.html index.html"+	fi+	else+	TARGETS="$TARGETS doc/manual/index.html"+	MAKEMANUAL="$LATEX2HTML -split +1 -dir doc/manual src/darcs.tex"+	dnl the following tells "preproc" to generate "rawhtml" sections for latex2html.+	PREPROCHTML="--html"+	fi+else+	BUILDDOC="no"+fi++AC_SUBST(TARGETS)+AC_SUBST(MAKEMANUAL)+AC_SUBST(INSTALLWHAT)+AC_SUBST(PREPROCHTML)++dnl Look for sendmail...++AC_ARG_WITH(sendmail, [  --with-sendmail=PATHTOSENDMAIL],+[+SENDMAIL=$with_sendmail+HAVE_SENDMAIL="True"+],[+STUPID_PATH=/usr/sbin:/usr/lib+AC_PATH_PROG(SENDMAIL, sendmail, "", $PATH:$STUPID_PATH)+if test -z "$SENDMAIL"; then+    SENDMAIL=""+    HAVE_SENDMAIL="False"+else+    HAVE_SENDMAIL="True"+fi+])+AC_SUBST(SENDMAIL)+AC_SUBST(HAVE_SENDMAIL)++dnl Look for MAPISendMail++AC_CHECK_LIB(mapi32, MAPISendMail, HAVE_MAPI="True", HAVE_MAPI="False")+AC_SUBST(HAVE_MAPI)++if test "$HAVE_SENDMAIL" = "False" -a "$HAVE_MAPI" = "False"; then+    AC_MSG_WARN([Can't find sendmail or mapi so you won't be able to push by email!])+fi++dnl Allow use of color in output to be disabled++AC_ARG_ENABLE(color, AS_HELP_STRING([--disable-color],[do not use ansi color escapes]))++dnl export color flag+USE_COLOR="True"+if test "$enable_color" = "no"; then+    USE_COLOR="False"+fi+AC_SUBST(USE_COLOR)++dnl Try to link with static versions of libraries.++AC_ARG_WITH(static-libs, [  --with-static-libs      link with static versions of libraries])+if test "x$with_static_libs" = "xyes"; then+    LDFLAGS="-static $LDFLAGS"+fi++dnl Check whether to use existential type witnesses++AC_MSG_CHECKING([for gadt type witnesses])+AC_ARG_WITH(type-witnesses,+            AS_HELP_STRING([--with-type-witnesses],+                           [use GADT type witnesses (EXPERIMENTAL!)])+            ,with_typew=yes+            ,with_typew=no)++if test "$with_typew" = "yes"; then+ GHCFLAGS="$GHCFLAGS -fglasgow-exts"+ AC_DEFINE([GADT_WITNESSES])+ AC_MSG_RESULT([yes])+else+ AC_MSG_RESULT([no])+fi++dnl look for zlib library and header.+dnl Use GHC_CHECK_LIBRARY and not AC_CHECK_HEADER / AC_CHECK_LIB because GHC may+dnl use a different library and header than the system GCC (on Windows, issue 813)++GHC_CHECK_LIBRARY([z],[zlib.h deflate],[Int -> Int -> Int],[],+   [AC_MSG_ERROR(Cannot find system's zlib library; please set the LDFLAGS environment variable!)])++dnl Find libcurl and other libraries needed by hscurl.c++AC_ARG_WITH(libcurl,+            AS_HELP_STRING([--without-libcurl],[do not use libcurl]))++AC_ARG_WITH(curl, AS_HELP_STRING([--with-curl=<DIR>],[use curl installed in directory <DIR>]))++CURLLIBS=+CURL_CONFIG="curl-config"++if test "$with_libcurl" != "no"; then+ if test "$with_curl" != ""; then+   CURL_CONFIG="$with_curl/bin/curl-config"+ fi++ AC_MSG_CHECKING([for libcurl])+ if eval $CURL_CONFIG --version 2>/dev/null >/dev/null; then+   ver=`$CURL_CONFIG --version | sed -e "s/libcurl //g"`+   opt="--libs"+   CURLCFLAGS=`$CURL_CONFIG --cflags`+   if test "x$with_static_libs" = "xyes"; then+       CURLCFLAGS="$CURLFLAGS -DCURL_STATICLIB"+       opt="--static-libs"+   fi+   CURLLIBS=`$CURL_CONFIG $opt | sed "s_-arch @<:@^ @:>@@<:@^ @:>@*__"`+   AC_MSG_RESULT($ver)+ else+   AC_MSG_RESULT(FAILED)+   AC_MSG_WARN([curl-config was not found])+ fi+fi++if test "$CURLLIBS" != ""; then+    # we enable curl+    CPPFLAGS="$CPPFLAGS -DHAVE_CURL"++    CFLAGS="$CFLAGS $CURLCFLAGS"+    LIBS="$LIBS $CURLLIBS"+    old_LIBS="$LIBS"+    AC_CHECK_LIB(curl, curl_global_init,+                 [],+                 AC_MSG_ERROR(Cannot actually use libcurl; try specifying --without-libcurl.))+    AC_CHECK_LIB(curl, curl_multi_timeout,+                 CPPFLAGS="$CPPFLAGS -DCURL_MULTI_TIMEOUT")+    LIBS="$old_LIBS"++    # Check if we want pipelining enabled...+    AC_ARG_WITH(curl_pipelining,+            AS_HELP_STRING([--with-curl-pipelining],[use curl pipelining (requires libcurl >= 7.18.0)]))++    if test "$with_curl_pipelining" == "yes"; then+      AC_MSG_CHECKING([for libcurl pipelining])+      let vernum=0x0`$CURL_CONFIG --vernum`+      let minver=0x071200+      if test $vernum -ge $minver; then+        CPPFLAGS="$CPPFLAGS -DCURL_PIPELINING"+        CURL_PIPELINING=True+        AC_MSG_RESULT([yes])+      else+        AC_MSG_RESULT([no])+        AC_MSG_WARN([Requires libcurl version >= 7.18.0])+      fi+    fi++    # Check if we want curl debug enabled...+    AC_MSG_CHECKING([whether to do libcurl debugging])+    AC_ARG_ENABLE(curl-debug,+                  AS_HELP_STRING([--enable-curl-debug],[enable libcurl debug mode]),+                  curl_debug=$enableval, curl_debug=no)+    AC_MSG_RESULT($curl_debug)+    if test "$curl_debug" = "yes"; then+      CPPFLAGS="$CPPFLAGS -DCURL_DEBUG"+    fi+fi++dnl Find libwww and other libraries needed by hswww.c++AC_ARG_WITH(libwww,+            AS_HELP_STRING([--with-libwww],[use libwww]))++if test "$with_libwww" == "yes"; then+ AC_MSG_CHECKING([for libwww])+ if eval libwww-config --version 2>/dev/null >/dev/null; then+   CPPFLAGS="$CPPFLAGS -DHAVE_LIBWWW"+   WWWVERSION=`libwww-config --version`+   LIBS="$LIBS `libwww-config --libs`"+   CFLAGS="$CFLAGS `libwww-config --cflags`"+   AC_MSG_RESULT($WWWVERSION)++   # Check if we want libwww debug enabled...+   AC_MSG_CHECKING([whether to do libwww debugging])+   AC_ARG_ENABLE(libwww-debug,+                 AS_HELP_STRING([--enable-libwww-debug],[enable libwww debug mode]),+                 libwww_debug=$enableval, libwww_debug=no)+   AC_MSG_RESULT($libwww_debug)+   if test "$libwww_debug" = "yes"; then+     CPPFLAGS="$CPPFLAGS -DLIBWWW_DEBUG"+   fi+ else+   AC_MSG_RESULT(FAILED)+   AC_MSG_WARN([libwww-config was not found])+ fi+fi++dnl Check for libcurses...++AC_ARG_ENABLE(libcurses, [  --without-curses        do not use libcurses])++HAVE_CURSES=False+if test "$with_libcurses" != "no"; then+  # term.h is documented to require curses.h and actually needs it on+  # Solaris, for instance, though not on GNU/Linux.+  AC_CHECK_HEADER(term.h,+      [AC_SEARCH_LIBS(tgetent, [curses ncurses], [HAVE_CURSES=True])], ,+      [#include <curses.h>+      ])+  if test "$HAVE_CURSES" != "True"; then+    AC_MSG_WARN([Cannot find term.h, disabling color.])+  else+    # The precondition for this is: we both have curses available and not disabled+    CPPFLAGS="$CPPFLAGS -DHAVE_CURSES"+  fi+fi+AC_SUBST(HAVE_CURSES)++dnl Look for a suitable diff command++AC_CHECK_PROGS(DIFF, [gdiff gnudiff diff])++dnl Look for NullSoft Installer System++AC_PATH_PROGS(MAKENSIS, [makensis.exe])++dnl Check endianness++AC_C_BIGENDIAN([BIGENDIAN="True"],[BIGENDIAN="False"])+AC_SUBST(BIGENDIAN)++dnl Check for a haddock 2.0.0 or more recent++AC_CHECK_PROG(HADDOCK, haddock, haddock)+AC_MSG_CHECKING([haddock version])+if test "$HADDOCK" = ""; then+   HADDOCK_VERSION=0+else+   HADDOCK_VERSION=`haddock --version | head -n 1 | sed 's/^.* \(@<:@0-9@:>@@<:@0-9@:>@*\)\..*/\1/g'`+fi+AC_SUBST(HADDOCK_VERSION)+AC_MSG_RESULT(version $HADDOCK_VERSION)+if test "$HADDOCK_VERSION" -lt 2; then+   AC_MSG_WARN([You need haddock 2.0.0 or later to build API docs])+fi++dnl Write results++dnl Remove these two tests when autoconf >2.59 can be required.+if test -z "${datarootdir}"; then+   datarootdir=${datarootdir:-'${prefix}/share'}+   AC_SUBST(datarootdir)+fi+if test -z "${docdir}"; then+   docdir=${docdir:-'${datarootdir}/doc/${PACKAGE_TARNAME}'}+   AC_SUBST(docdir)+fi++AC_DEFUN([AC_DATAROOTDIR_CHECKED])+OUTPUT_WORKAROUND+AC_CONFIG_FILES([autoconf.mk src/Autoconf.lhs+           tools/cgi/darcs.cgi tools/cgi/README tools/cgi/cgi.conf+           darcs.buildinfo])+AC_OUTPUT++cat <<[EOF]++The build is configured as follows:++    bindir          = $bindir+    sbindir         = $sbindir+    mandir          = $mandir+    datadir         = $datadir+    sysconfdir      = $sysconfdir+    libexecdir      = $libexecdir++    Build Manual    = $BUILDDOC++If you want to adjust any of these values, edit autoconf.mk and+src/Autoconf.lhs -- or run configure with appropriate settings.++[EOF]++dnl Responsibility shifts to the user after this point.
+ darcs-cabalized.cabal view
@@ -0,0 +1,154 @@+Name:           darcs-cabalized+version:        2.0.2+License:        GPL+License-file:   COPYING+Author:         David Roundy <droundy@darcs.net>, <darcs-devel@darcs.net>, et al.+Maintainer:     <gwern0@gmail.com>++Stability:      Experimental+Category:       Development+Synopsis:       David's Advanced Version Control System+Description:    Darcs is a revision control system, along the lines of CVS or arch.+                That means that it keeps track of various revisions and branches of+                your project, allows for changes to propagate from one branch to another.+                Darcs is intended to be an _advanced_ revision control system.+                Darcs has two particularly distinctive features which differ from other,+                centralized, revision control systems:+                .+                * each copy of the source is a fully functional branch, and+                .+                * underlying darcs is a consistent and powerful theory of patches.+                .+                The Darcs repository can be found at <http://darcs.net/>.+                .+                This is an unofficial package of Darcs, using Cabal; problems with it may well+                be the fault of the packager and not the Darcs project.+Homepage:       http://darcs.net/++Build-Type:     Configure+Cabal-Version:  >= 1.2+Tested-with:    GHC==6.8.2++data-files:      src/darcs_print.pdf, src/darcs_print.ps, src/patch-theory.pdf,+                 src/best_practices.tex, src/building_darcs.tex, src/configuring_darcs.tex,+                 src/features.tex, src/gpl.tex, src/switching.tex,+                 tools/cgi/README, tools/cgi/README.in+extra-source-files:+                 -- C sources and headers. Are these redundant with c-sources:?+                 src/Crypt/sha2.c, src/Crypt/sha2.h, src/atomic_create.c,+                 src/atomic_create.h, src/c_compat.c, src/compat.h,+                 src/fpstring.c, src/fpstring.h, src/gadts.h,+                 src/hscurl.c, src/hscurl.h,+                 src/hslibwww.c, src/hslibwww.h,+                 src/impossible.h, src/maybe_relink.c, src/maybe_relink.h,+                 src/umask.c, src/umask.h,+                 -- Build files; we include the autoconf files just in case+                 -- the user wishes to re-autoconf on her system.+                 darcs.buildinfo, darcs.buildinfo.in, configure, configure.ac,+                 autoconf.mk, autoconf.mk.in, aclocal.m4, src/Autoconf.lhs.in,+                 src/ThisVersion.lhs.in,+                 -- Windows files+                 src/win32/send_email.c, src/win32/send_email.h, src/win32/sys/mman.h,+                 src/win32/CtrlC.hs, src/win32/System/Posix/Files.hsc,+                 src/win32/System/Posix/IO.hsc, src/win32/System/Posix.hs,+                 -- TODO: factor out these standalone executables to other sections+                 src/preproc.hs, src/darcsman.hs, src/unit.lhs, src/make_changelog.hs,+                 -- The tools directory would make a sensible 'darcs-tools' package+                 tools/zsh_completion_new, tools/update_roundup.pl,+                 tools/zsh_completion_old, tools/cgi/cgi.conf,+                 tools/cgi/darcs.cgi.in, tools/cgi/darcs.cgi,+                 tools/cgi/cgi.conf.in, tools/cgi/xslt/repos.xslt,+                 tools/cgi/xslt/errors.xslt, tools/cgi/xslt/browse.xslt,+                 tools/cgi/xslt/common.xslt, tools/cgi/xslt/annotate.xslt,+                 tools/cgi/xslt/styles.css, tools/cgi/xslt/rss.xslt,+                 tools/cgi/xslt/patches.xslt, tools/cgi/xslt/errors.xml,+                 tools/cgi/README.in, tools/cygwin-wrapper.bash,+                 tools/upload.cgi, tools/darcs_completion+extra-tmp-files: darcs.buildinfo, autoconf.mk, configure++flag small_base+    description: Choose the new smaller, split-up base package. Defaults to True.++flag no_curses+     description: Disable curses support. Defaults to False.+     default:     False++Executable          darcs+    main-is:        darcs.lhs+    hs-source-dirs: src++    build-depends: regex-compat, mtl, parsec, html, QuickCheck, HUnit+    if flag(small_base)+        build-depends: base >= 3, unix, old-time, directory, process, containers, array, bytestring+    else+        build-depends: base < 3++    -- We need optimizations and warnings, regardless of what Hackage says+    ghc-options:      -Wall -O2 -funbox-strict-fields+    ghc-prof-options: -prof -auto-all++    -- the CPP and CC options are supplied from darcs.buildinfo+    extensions:     CPP, ForeignFunctionInterface++    other-modules:  FileSystem, Ssh,+                    FastPackedString, Workaround,+                    Crypt.SHA256, URL, Context, HTTP,+                    Darcs.Patch.ReadMonads, Darcs.URL,+                    Darcs.FilePathUtils, Darcs.External, Darcs.RepoPath,+                    Darcs.Email, Darcs.Compat,+                    IsoDate, ThisVersion, Exec,+                    CommandLine, Autoconf,+                    ThisVersion, DateMatcher, OldDate,+                    Printer, Lcs, RegChars, FileName,+                    Darcs.Sealed, Darcs.Resolution, Darcs.TheCommands,+                    Darcs.ColorPrinter, Darcs.Utils, Darcs.ArgumentDefaults,+                    Darcs.Patch, Darcs.PrintPatch, Darcs.SignalHandler,+                    Darcs.Lock, Darcs.FilePathMonad, Darcs.Patch.Check,+                    Darcs.Patch.Patchy, Darcs.Patch.Prim, Darcs.Patch.Commute,+                    Darcs.Patch.Properties, Darcs.Patch.Viewing, Darcs.Patch.Apply,+                    Darcs.Patch.Core, Darcs.Patch.Real, Darcs.Patch.Bundle,+                    Darcs.Patch.Choices, Darcs.Patch.TouchesFiles, Darcs.Patch.Permutations,+                    Darcs.Patch.QuickCheck, Darcs.Patch.MatchData, Darcs.Patch.Ordered,+                    Darcs.Patch.Test, Darcs.Patch.Set, Darcs.Patch.Show,+                    Darcs.Patch.Unit, Darcs.Patch.Info, Darcs.Patch.Match,+                    Darcs.Patch.Read, Darcs.Patch.Non, Darcs.Patch.Depends,+                    Darcs.Population, Darcs.Repository.Prefs, Darcs.Repository.Internal,+                    Darcs.Repository.DarcsRepo, Darcs.Repository.Pristine, Darcs.Repository.Motd,+                    Darcs.Repository.HashedRepo, Darcs.Repository.InternalTypes, Darcs.Repository.Format,+                    Darcs.Repository.Checkpoint, Darcs.Repository.ApplyPatches, Darcs.Repository.HashedIO,+                    Darcs.Global, Darcs.Bug, Darcs.HopefullyPrivate,+                    Darcs.Commands.ShowContents, Darcs.Commands.Check, Darcs.Commands.Record,+                    Darcs.Commands.Remove, Darcs.Commands.Mv, Darcs.Commands.Convert,+                    Darcs.Commands.ShowRepo, Darcs.Commands.Apply, Darcs.Commands.Help,+                    Darcs.Commands.Tag, Darcs.Commands.Unrevert, Darcs.Commands.Optimize,+                    Darcs.Commands.ShowBug, Darcs.Commands.TransferMode, Darcs.Commands.ShowFiles,+                    Darcs.Commands.Dist, Darcs.Commands.Repair, Darcs.Commands.AmendRecord,+                    Darcs.Commands.Push, Darcs.Commands.ShowTags, Darcs.Commands.ShowAuthors,+                    Darcs.Commands.Replace, Darcs.Commands.Changes, Darcs.Commands.WhatsNew,+                    Darcs.Commands.Add, Darcs.Commands.Get, Darcs.Commands.Init,+                    Darcs.Commands.Put, Darcs.Commands.TrackDown, Darcs.Commands.Unrecord,+                    Darcs.Commands.Rollback, Darcs.Commands.Revert, Darcs.Commands.Annotate,+                    Darcs.Commands.Pull, Darcs.Commands.Diff, Darcs.Commands.Send,+                    Darcs.Commands.Show, Darcs.Commands.SetPref, Darcs.Commands.MarkConflicts,+                    Darcs.Arguments, Darcs.CommandsAux, Darcs.Test,+                    Darcs.Repository, Darcs.CheckFileSystem, Darcs.Flags,+                    Darcs.RemoteApply, Darcs.Progress, Darcs.Hopefully,+                    Darcs.SlurpDirectory, Darcs.Commands, Darcs.Diff,+                    Darcs.Show, Darcs.Match, Darcs.SelectChanges,+                    Darcs.PopulationData, Darcs.IO, English,+                    UTF8, SHA1, Autoconf++    c-sources:      src/atomic_create.c+                    src/c_compat.c+                    src/fpstring.c+                    src/maybe_relink.c+                    src/umask.c+                    src/Crypt/sha2.c+                    src/hscurl.c+    include-dirs:   src++    -- zlib is mandatory; we need extra-libraries to fix FFI link errors+    if flag(no_curses)+       extra-libraries: z+    else+       extra-libraries: z, curses
+ darcs.buildinfo view
@@ -0,0 +1,6 @@+-- darcs.buildinfo.  Generated from darcs.buildinfo.in by configure.+-- System-dependent values used by Distribution.Simple.defaultUserHooks+executable: darcs+CPP-options:  -DHAVE_BYTESTRING -DHAVE_CURSES+ld-options: +cc-options: -DPACKAGE_VERSION="2.0.2"
+ darcs.buildinfo.in view
@@ -0,0 +1,6 @@+-- @configure_input@+-- System-dependent values used by Distribution.Simple.defaultUserHooks+executable: darcs+CPP-options: @CPPFLAGS@+ld-options: @LDFLAGS@+cc-options: -DPACKAGE_VERSION="@PACKAGE_VERSION@"
+ src/Autoconf.lhs view
@@ -0,0 +1,80 @@+%+% System dependent information generated by Autoconf.+%+% src/Autoconf.lhs.  Generated from Autoconf.lhs.in by configure.+%+\begin{code}+{-# OPTIONS -cpp #-}+module Autoconf ( darcsconfdir, datadir, libexecdir, have_libcurl, have_libwww, have_HTTP,+                  use_color, use_mmap, darcs_version, sendmail_path, have_sendmail,+                  have_mapi, diff_program,+                  path_separator, big_endian,+                ) where++import ThisVersion ( darcs_version )++{-# INLINE darcsconfdir #-}+darcsconfdir :: String+darcsconfdir = "${prefix}/etc/darcs"++{-# INLINE datadir #-}+datadir :: String+datadir = "${datarootdir}"++{-# INLINE libexecdir #-}+libexecdir :: String+libexecdir = "${exec_prefix}/libexec"++{-# INLINE have_libcurl #-}+have_libcurl :: Bool+#ifdef HAVE_CURL+have_libcurl = True+#else+have_libcurl = False+#endif++{-# INLINE have_libwww #-}+have_libwww :: Bool+#ifdef HAVE_LIBWWW+have_libwww = True+#else+have_libwww = False+#endif++{-# INLINE have_HTTP #-}+have_HTTP :: Bool+have_HTTP = True++{-# INLINE use_color #-}+use_color :: Bool+use_color = True++{-# INLINE use_mmap #-}+use_mmap :: Bool+use_mmap = True++{-# INLINE sendmail_path #-}+sendmail_path :: String+sendmail_path = "/usr/sbin//sendmail"++{-# INLINE have_sendmail #-}+have_sendmail :: Bool+have_sendmail = True++{-# INLINE have_mapi #-}+have_mapi :: Bool+have_mapi = False++{-# INLINE diff_program #-}+diff_program :: String+diff_program = "diff"++{-# INLINE path_separator #-}+path_separator :: Char+path_separator = '/'++{-# INLINE big_endian #-}+big_endian :: Bool+big_endian = False+\end{code}+
+ src/Autoconf.lhs.in view
@@ -0,0 +1,80 @@+%+% System dependent information generated by Autoconf.+%+% @configure_input@+%+\begin{code}+{-# OPTIONS -cpp #-}+module Autoconf ( darcsconfdir, datadir, libexecdir, have_libcurl, have_libwww, have_HTTP,+                  use_color, use_mmap, darcs_version, sendmail_path, have_sendmail,+                  have_mapi, diff_program,+                  path_separator, big_endian,+                ) where++import ThisVersion ( darcs_version )++{-# INLINE darcsconfdir #-}+darcsconfdir :: String+darcsconfdir = "@sysconfdir@/darcs"++{-# INLINE datadir #-}+datadir :: String+datadir = "@datadir@"++{-# INLINE libexecdir #-}+libexecdir :: String+libexecdir = "@libexecdir@"++{-# INLINE have_libcurl #-}+have_libcurl :: Bool+#ifdef HAVE_CURL+have_libcurl = True+#else+have_libcurl = False+#endif++{-# INLINE have_libwww #-}+have_libwww :: Bool+#ifdef HAVE_LIBWWW+have_libwww = True+#else+have_libwww = False+#endif++{-# INLINE have_HTTP #-}+have_HTTP :: Bool+have_HTTP = @HAVE_HTTP@++{-# INLINE use_color #-}+use_color :: Bool+use_color = @USE_COLOR@++{-# INLINE use_mmap #-}+use_mmap :: Bool+use_mmap = @USE_MMAP@++{-# INLINE sendmail_path #-}+sendmail_path :: String+sendmail_path = "@SENDMAIL@"++{-# INLINE have_sendmail #-}+have_sendmail :: Bool+have_sendmail = @HAVE_SENDMAIL@++{-# INLINE have_mapi #-}+have_mapi :: Bool+have_mapi = @HAVE_MAPI@++{-# INLINE diff_program #-}+diff_program :: String+diff_program = "@DIFF@"++{-# INLINE path_separator #-}+path_separator :: Char+path_separator = '@GHC_SEPARATOR@'++{-# INLINE big_endian #-}+big_endian :: Bool+big_endian = @BIGENDIAN@+\end{code}+
+ src/CommandLine.lhs view
@@ -0,0 +1,127 @@+%  Copyright (C) 2005 Benedikt Schmidt+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++A parser for commandlines, returns an arg list and expands+format strings given in a translation table. Additionally+the commandline can end with "%<" specifying that the command+expects input on stdin.++\begin{code}+module CommandLine ( parseCmd, addUrlencoded ) where+import Text.ParserCombinators.Parsec+import Data.Char ( ord, intToDigit, toUpper )+import Data.List ( find )+\end{code}++\begin{code}+-- | assoc list mapping characters to strings+-- eg (c,s) means that %c is replaced by s+type FTable = [(Char,String)]+commandline :: FTable -> Parser ([String], Bool)+commandline ftable = consumeAll (do l <- sepEndBy1 (arg ftable) +                                                   (try separator)+                                    redir <- formatRedir+                                    spaces+                                    return (l,redir))++escape:: Parser String+arg, format, quotedArg, unquotedArg, quoteContent :: FTable -> Parser String+arg ftable = (quotedArg ftable <|> unquotedArg ftable)++unquotedArg ftable = do (try $ format ftable)+                          <|> (many1 $ noneOf [' ', '\t', '"', '%'])++quotedArg ftable = between (char '"') (char '"') $ quoteContent ftable++quoteContent ftable = do s1 <- escape+                               <|> (try $ format ftable)+                               <|> (many1 (noneOf ['"', '\\', '%']))+                         s2 <- quoteContent ftable+                         return $ s1 ++ s2+                     <|> return ""++formatRedir :: Parser Bool+formatRedir = do string "%<"+                 return True+            <|> return False++format ftable = do char '%'+                   c <- oneOf  (map fst ftable)+                   return $ expandFormat ftable c++escape = do char '\\'+            c <- anyChar+            return [c]++consumeAll :: Parser a -> Parser a+consumeAll p = do r <- p+                  eof+                  return r+                +separator :: Parser ()+separator = do skipMany1 space++expandFormat :: FTable -> Char -> String+expandFormat ftable c = case find ((==c) . fst) ftable of+                          Just (_,s) -> s+                          Nothing -> error "impossible"++-- | parse a commandline returning a list of strings +-- (intended to be used as argv) and a bool value which+-- specifies if the command expects input on stdin+-- format specifiers with a mapping in ftable are accepted+-- and replaced by the given strings. E.g. if the ftable is+-- [('s',"Some subject")], then "%s" is replaced by "Some subject"+parseCmd :: FTable -> String -> Either ParseError ([String],Bool)+parseCmd ftable s = parse (commandline ftable) "" s++urlEncode :: String -> String+urlEncode s = concat $ map escapeC s+    where escapeC x = if allowed x then [x] else '%':(intToHex $ ord x)+          intToHex i = map intToDigit [i `div` 16, i `mod` 16]    +          allowed x = x `elem` ['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9']+                      ++ "!'()*-.~"++-- | for every mapping (c,s), add a mapping with uppercase c+-- and the urlencoded string s+addUrlencoded :: FTable -> FTable+addUrlencoded ftable =+  ftable ++(map (\ (c,x) -> (toUpper c, urlEncode x)) ftable)+\end{code}+Some tests for the parser.++formatTable = [('s',"<insert subject here>"),+               ('a',"<insert author here>")]++testParser :: (Show a, Eq a) => Parser a -> String -> a -> a+testParser p s ok = case parse p "" s of+                    Left e -> error $ "Parser failed with: " ++ (show e)+                    Right res -> if res == ok+                                 then res+                                 else error $ "Parser failed: got "+                                        ++ (show res) ++ ", expected "+                                        ++ (show ok)++testCases = [("a b",(["a","b"], False)),+             ("a b %<",(["a","b"], True)),+             ("a b %< ",(["a","b"], True)),+             ("\"arg0 contains spaces \\\"quotes\\\"\" b",+              (["arg0 contains spaces \"quotes\"","b"],False)),+             ("a %s %<",(["a","<insert subject here>"], True))]++runTests = map (uncurry $ testParser (commandline formatTable)) testCases
+ src/Context.hs view
@@ -0,0 +1,3 @@+module Context (context) where+context :: String+context = "# configured Fri Jun 27 08:23:23 EDT 2008\n./configure /home/gwern/bin/share/config.site /home/gwern/bin/etc/config.site\n\nContext:\n\n[make pull less verbose when --verbose flag is given.\nDavid Roundy <droundy@darcs.net>**20080624170035] \n\n[fix makefile to remember to regenerate version information after running configure.\nDavid Roundy <droundy@darcs.net>**20080624170001] \n\n[TAG 2.0.2\nDavid Roundy <droundy@darcs.net>**20080624012041] \n\n[bump version number again (brown bag!)\nDavid Roundy <droundy@darcs.net>**20080624011914] \n\n[add script to check that \"make dist\" actually works.\nDavid Roundy <droundy@darcs.net>**20080624011817] \n\n[fix buggy and inconsistent release-determining scripts.\nDavid Roundy <droundy@darcs.net>**20080624011759] \n\n[ignore boring changelog entry patches when constructing ChangeLog.\nDavid Roundy <droundy@darcs.net>**20080623224504] \n\n[add changelog entry for fix of version-numbering bug.\nDavid Roundy <droundy@darcs.net>**20080623223901] \n\n[fix bug in determine_release_state.pl.\nDavid Roundy <droundy@darcs.net>**20080623223739] \n\n[TAG 2.0.1\nDavid Roundy <droundy@darcs.net>**20080623214707] \n\n[bump version to 2.0.1.\nDavid Roundy <droundy@darcs.net>**20080623214646] \n\n[determine_release_state.pl: use regexp to determine patch count if \"darcs changes\" does not support --count argument.\nDmitry Kurochkin <dmitry.kurochkin@gmail.com>**20080621122305] \n\n[Delete haddock documentation on constructor arguments; see Issue935\nMichael De La Rue <gneqbgqnepfqbgarg.yeuhc@spamgourmet.com>**20080622182644] \n\n[Add configure options for libcurl and libwww debugging.\nDmitry Kurochkin <dmitry.kurochkin@gmail.com>**20080620221237] \n\n[aclocal.m4: add library to $LIBS instead of $GHCFLAGS in GHC_CHECK_LIBRARY.\nDmitry Kurochkin <dmitry.kurochkin@gmail.com>**20080620214538] \n\n[resolve issue930: remove broken link from webpage.\nDavid Roundy <droundy@darcs.net>**20080620172635] \n\n[add threadWaitRead trick as suggested by Simon (issue916).\nDavid Roundy <droundy@darcs.net>**20080620172119\n Apparently this should solve the ctrl-C issues on posix systems, but\n windows remains only partially-solved (it requires multiple ctrl-C's\n to exit).\n] \n\n[resolve issue916: use separate thread for reading from stdin.\nDavid Roundy <droundy@darcs.net>**20080618210110] \n\n[Set up configure to build an rpm spec file for building rpm packages with.\nMichael De La Rue <gneqbgqnepfqbgarg.yeuhc@spamgourmet.com>**20080616231617] \n\n[hscurl.c: fix harmless warning with curl >= 7.18.1.\nDmitry Kurochkin <dmitry.kurochkin@gmail.com>**20080613125607] \n\n[Even more changelog entries for 2.0.1.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080614091045] \n\n[Use changes -s style for unlogged patches (make_changelog).\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080614072632\n This make it easier to tell what a patch is at a glance.\n] \n\n[Still more changelog entries for 2.0.1.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613181548] \n\n[Canonize Benjamin Fraksen.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613171147] \n\n[More changelog entries for 2.0.1.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613165729] \n\n[Clarify intent of ignored changelog entries.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613162537] \n\n[Ignore tags in make_changelog warning about unlogged patches.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613162213] \n\n[Support comments on ignored changelog entries.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613161742\n \n Parsec wibble: the problem was that it would start parsing the\n emptyLine as a 'match' and not backtrack.\n] \n\n[fix potential redundancy in version name.\nDavid Roundy <droundy@darcs.net>**20080613162019] \n\n[Exceptions to GPL granted as of 2008-06-13 morning.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613072749] \n\n[Add test for case-insensitive backup bug.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613070918] \n\n[Fix a backup bug on case-insensitive file systems.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613070213\n \n Avoids this scenario.  The task: move foo to FOO and modify FOO\n 1. FOO (foo) already exists, so I'll back it up\n    (moves FOO [foo] to FOO.darcs-backup0)\n 2. Now I can move foo to FOO\n    foo no longer exists, but that's ok\n    (nothing happens)\n 3. Now I can FOO\n    hey, where did FOO go?\n    (crash!)\n] \n\n[Check for bash before running shell tests.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080612145509\n MSYS, for instance, does not provide bash by default.\n [note: or rather, only under the guise of sh.exe]\n] \n\n[fix issue #918: use simplePrinters for xml output in \"darcs changes\" command\nbenjamin.franksen@bessy.de**20080613110922] \n\n[make darcs send always provide context.\nDavid Roundy <droundy@darcs.net>**20080613155550\n I've just gotten sick of telling folks to add send --unified to their\n defaults file.  It's hard to see who wouldn't want context included.\n] \n\n[ChangeLog entries by Eric.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613151200\n Some ChangeLog entries for 2.0.1\n] \n\n[Add 'ignored' changelog entries (no warnings).\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613150620] \n\n[Resolve issue705: warn about patches which are not changelogged.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613145443\n Mostly by Tommy Pettersson.\n] \n\n[Add ability to ignore patches for ChangeLog.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080613142540\n This would be useful if make_changelog could point out which patches\n are not being changelogged.\n] \n\n[TAG 2.0.1rc2\nDavid Roundy <droundy@darcs.net>**20080613011745] \n\n[bump version number up to 2.0.1rc2.\nDavid Roundy <droundy@darcs.net>**20080613011731] \n\n[Resolve issue913: Use Data.Bytestring for IO, not Data.Bytestring.Char8\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080612125719\n \n This solution comes from Ian Lynagh, who points out that the\n difference between the two is:\n \n Data.Bytestring.Char8\n ---------------------\n writeFile :: FilePath -> ByteString -> IO ()\n writeFile f txt = bracket (openFile f WriteMode) hClose\n    (\\h -> hPut h txt)\n \n Data.Bytestring\n ---------------\n writeFile :: FilePath -> ByteString -> IO ()\n writeFile f txt = bracket (openBinaryFile f WriteMode) hClose\n    (\\h -> hPut h txt)\n \n We want this change because, as the System.IO docs say:\n \n   On Windows, reading a file in text mode (which is the default) will\n   translate CRLF to LF, and writing will translate LF to CRLF. This is\n   usually what you want with text files. With binary files this is\n   undesirable; also, as usual under Microsoft operating systems, text\n   mode treats control-Z as EOF. Binary mode turns off all special\n   treatment of end-of-line and end-of-file characters.\n \n] \n\n[fix OPTLLIBS filtering\nKarel Gardas <kgardas@objectsecurity.com>**20080607210701] \n\n[Darcs.Repository.Prefs: +boring filters for MS Visual Studio (see -users discussion)\ngwern0@gmail.com**20080607080336] \n\n[Demonstrate 'hidden conflicts' bug (old format).\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080606151534] \n\n[add necessary extra-libraries line to fix link errors\ngwern0@gmail.com**20080607033230] \n\n[darcs.cabal: remove a removed module\ngwern0@gmail.com**20080607033210] \n\n[darcs.cabal: +profile options\ngwern0@gmail.com**20080607033156] \n\n[fix regression introduced by using Data.List.isInfixOf.\nDavid Roundy <droundy@darcs.net>**20080606102519] \n\n[resolve issue783: propose 'edit' as a default Windows editor\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080605165812\n \n I think every Windows box has this.  Advantages over notepad are that\n - it's a console app\n - it appears to support Unix newlines\n] \n\n[fix bug in test when there's a space in test directory.\nDavid Roundy <droundy@darcs.net>**20080605151104] \n\n[Makefile: prefix -optl only on $(LIBS) that start with '-'\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080605105539\n \n Otherwise, on Windows, if you try to build --with-static-libs, the\n linker will be passed /usr/local/lib/libcurl.a as an argument, which\n makes gcc complain.\n] \n\n[resolve issue770: catch 'does not exist' when running external programs\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080604143100\n Convert these errors into ExitCode 127 (for Windows)\n] \n\n[translate pull.pl into shell.\nDavid Roundy <droundy@darcs.net>**20080605124106] \n\n[make test suite smarter about cleaning up test directories.\nDavid Roundy <droundy@darcs.net>**20080605124025] \n\n[darcs put now support --{no-,}set-default.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080604214551] \n\n[fix regression in index.html.in.\nDavid Roundy <droundy@darcs.net>**20080605114356] \n\n[TAG 2.0.1rc1\nDavid Roundy <droundy@darcs.net>**20080603124331] \n\n[bump version number.\nDavid Roundy <droundy@darcs.net>**20080603124245] \n\n[try a bit harder to identify windows systems in perl tests.\nDavid Roundy <droundy@darcs.net>**20080603123558] \n\n[fix test for windows (maybe?)\nDavid Roundy <droundy@darcs.net>**20080603122003] \n\n[clean up after test.\nDavid Roundy <droundy@darcs.net>**20080603121601] \n\n[remove  buggy use of tempdir in pull.pl.\nDavid Roundy <droundy@darcs.net>**20080603121347] \n\n[resolve issue873: always optimize inventory when adding a tag to old-format repositories.\nDavid Roundy <droundy@darcs.net>**20080603114707] \n\n[maybe fix windows check in set_scripts_executable.pl?\nDavid Roundy <droundy@darcs.net>**20080603104644] \n\n[skip uniqueoptions.sh test on windows.\nDavid Roundy <droundy@darcs.net>**20080602112250\n since we don't know how to handle newlines on windows.\n] \n\n[skip issue538.sh on windows, since I don't know how to run tests\nDavid Roundy <droundy@darcs.net>**20080602112155\n since ./test.sh isn't accepted on windows.\n] \n\n[avoid using \"./editor\" in test, as this syntax fails under windows.\nDavid Roundy <droundy@darcs.net>**20080602111359] \n\n[exempt issue458.sh test from windows.\nDavid Roundy <droundy@darcs.net>**20080602111043] \n\n[note that we don't support hard links under windows.\nDavid Roundy <droundy@darcs.net>**20080602110601] \n\n[don't redirect output of test to file in repository while running --look-for-adds.\nDavid Roundy <droundy@darcs.net>**20080602105333] \n\n[Remove unwanted verbosity from pull --xml-output\nlele@nautilus.homeip.net**20080601005416] \n\n[Make an undefined a bit more informative\nIan Lynagh <igloo@earth.li>**20080529015202] \n\n[Demonstrate issue885, a regression of \"darcs get --to-match\"\nlele@nautilus.homeip.net**20080529140027] \n\n[avoid repeatedly checking whether stdout is a terminal.\nDavid Roundy <droundy@darcs.net>**20080528160309] \n\n[don't clear progress messages on stdout if it's not a terminal\nBertram Felgenhauer <int-e@gmx.de>**20080526225026\n This helps when the output of the command is processed further by other tools.\n] \n\n[switch pull_compl.sh test to perl.\nDavid Roundy <droundy@darcs.net>**20080526112020] \n\n[Add a partial test for issue525.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080523135851\n I say that this is a partial test because I do not know how to\n reproduce it without amend-record yet.\n] \n\n[Canonize Pekka Pessi once more.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080523104127] \n\n[reduce memory use of put\nDavid Roundy <droundy@darcs.net>**20080523105555\n But apply still hogs memory, so there's not really much point.\n] \n\n[Remove a timezone-sensitive date matching test.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080522194706] \n\n[Resolve issue187: Extend partial date matching to hours, minutes, secs.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080522194248] \n\n[Refactor DateMatcher and add debugging code.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080522193336\n Hopefully, the results are less convoluted.\n] \n\n[Return ParseError instead of String in parseDate.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080522191429\n This helps a little bit for debugging.\n] \n\n[Fix typo.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080522143857] \n\n[bump optimization level up to -O2.\nDavid Roundy <droundy@darcs.net>**20080522160617\n I'm not quite sure why we ever dropped it down... presumably someone was\n impatient with compile times.\n] \n\n[remove unneeded parens and clean up then/else alignment in Lcs.\nDavid Roundy <droundy@darcs.net>**20080522110602] \n\n[making sure hunk is not shifted beyond end of file in shiftBoundaries\nPekka Pessi <pekka@pessi.fi>**20080522062553\n \n fix bug introduced in diffArr - dontShiftLast does not prevent shifting\n] \n\n[add --with-curl=<DIR> configure option to be able to choose appropriate curl installation\nKarel Gardas <kgardas@objectsecurity.com>**20080522085828] \n\n[move threaded and profile tests earlier, and check whether threaded actually works.\nDavid Roundy <droundy@darcs.net>**20080522102402\n This is inspired by Gwern's patch, only trying to do things right (e.g. to\n support a future ghc that works with profiling and the threaded runtime\n together).\n] \n\n[hpc.README for collecting hpc data.  Requires ghc >= 6.8.3, otherwise tests will break.\nChristopher Lane Hinson <lane@downstairspeople.org>**20080521201003] \n\n[Add --enable-hpc to configure.\nChristopher Lane Hinson <lane@downstairspeople.org>**20080429035758] \n\n[Add a list of authors that allow the OpenSSL exception.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080522094603\n \n Issue176 seems to block because Zooko seems to keep losing access\n to his list of authors who have granted permission.  Perhaps it will\n be easier to keep track of as part of the darcs repository.\n] \n\n[Resolve issue763: provide logo without 'darcs' text.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080521153006] \n\n[Get rid of extra newline in uniqueoptions test.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080521140222\n \n Otherwise, on Windows/Cygwin, the test tries to run: darcs \"help\\n\"\n And darcs complains that it cannot find the \"help\\n\" command.\n] \n\n[getChanges with better shifting of first and last hunk with shiftBoundaries\nPekka Pessi <pekka.pessi@nokia.com>**20080521113655\n \n The one-line context left with old dropStart and dropEnd is not always\n enough. As a consequence first and last hunk in the file got treated\n inconsistently by shiftBoundaries.\n \n The refactored code converts lists into PArrays already by getChanges,\n dropStart and dropEnd advance bounds within PArray. \n \n getChanges' handles PArrays, and refactored code introduces minor\n optimizations to hash handling (collisions within one file are not\n propagated to diffArr).\n] \n\n[Generalise test for rollback with no changes.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080521120856] \n\n[Fix UI bug in rollback.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080521120359\n It did not notice if you do not select any changes to roll back.\n] \n\n[resolve issue855: fix bug where we were calling revertRepository when running with --dry-run.\nDavid Roundy <droundy@darcs.net>**20080521131419] \n\n[Undo overoptimistic move of issue855 bug to tests.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080521102935\n \n The test had some errors (some of which I introduced during the move)\n which caused it to pass for the wrong reason.  This patch also\n corrects those bugs so that it fails like it should.\n] \n\n[resolve issue687: don't clean out pristine cache except when optimizing.\nDavid Roundy <droundy@darcs.net>**20080521120834\n The trouble is that we can never tell when someone might be waiting to grab\n one of these older files.  Atomicity doesn't gain us much if we drop the\n old files immediately.  The downside is that now repositories will\n monotonically grow until an optimize is performed.  :(\n] \n\n[simplify setpref.sh\nDavid Roundy <droundy@darcs.net>**20080521113817] \n\n[resolve issue870: it was a bug in the test script.\nDavid Roundy <droundy@darcs.net>**20080521113233] \n\n[Add failing test for issue870.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080521102151] \n\n[Move issue855 bug to tests.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080520152055] \n\n[Resolve issue855: avoid taking lock if using --dry-run\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080519143535] \n\n[add some checks that repo isn't modified when --dry-run is used.\nDavid Roundy <droundy@darcs.net>**20080520143945] \n\n[Add (passing) test for issue709.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080519144425] \n\n[Canonize Pekka Pessi (yet again).\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080519143516] \n\n[Replace presumably non-portable use of fgrep in issue864 bug\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080519143303] \n\n[Add a test for issue855 (push --dry-run)\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080517154246] \n\n[Add a test to show a bug with --look-for-adds that corrupt pending.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080520105715] \n\n[Added bugs/replace-in-moved.sh for bug 864.\nPekka.Pessi@nokia.com**20080519141801] \n\n[Fix import warnings for Windows.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080517160935\n They are caused by Lele's recent patches.\n] \n\n[English: only use singular for 1 (we have 0 foos, but 1 bar, and 2 quuxes)\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080517152737] \n\n[automatically include --xml support on commands supporting --dry-run.\nDavid Roundy <droundy@darcs.net>**20080517123224] \n\n[Honour --xml-output when printing the patches in the \"will do\"/\"would do\" message\nlele@nautilus.homeip.net**20080517110820] \n\n[Wrap ShowRepo output within a <repository> tag, when asked for XML output\nlele@nautilus.homeip.net**20080514174050] \n\n[remove unused GHC_LIBDIR\nDavid Roundy <droundy@darcs.net>**20080516161816] \n\n[we don't need a reminder when there are no patches to pull.\nDavid Roundy <droundy@darcs.net>**20080516115858] \n\n[simplify init_tmp_repo.\nDavid Roundy <droundy@darcs.net>**20080516113713] \n\n[simplify calling of darcs in perl harness.\nDavid Roundy <droundy@darcs.net>**20080516113619] \n\n[clean up shell_harness just a tad.\nDavid Roundy <droundy@darcs.net>**20080516111416] \n\n[fix perl harness to use the right darcs.\nDavid Roundy <droundy@darcs.net>**20080516111316] \n\n[make pull_compl.sh a bit more verbose.\nDavid Roundy <droundy@darcs.net>**20080516110235] \n\n[remove unnecessary defaults-setting in pull_compl.sh\nDavid Roundy <droundy@darcs.net>**20080516105618] \n\n[Fixed problems with --with-static-libs\nPekka Pessi <pekka.pessi@nokia.com>**20080515175414\n \n When linking statically, the libraries must be listed last. \n \n Using LIBS/OPTLLIBS to collect libraries.\n] \n\n[Zapped bash-ism from configure.ac.\nPekka Pessi <pekka.pessi@nokia.com>**20080515150932] \n\n[Not using awk in configure.ac\nPekka Pessi <pekka.pessi@nokia.com>**20080515131700\n \n Plain sed does not grok +, use xx* instead of x+\n] \n\n[Resolve issue738: When pushing, remind user of patches to pull.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080515184714] \n\n[simplify update_roundup.pl.\nDavid Roundy <droundy@darcs.net>**20080515160802\n This change also fixes the bug where a capitalized message such as\n \"Resolved issue123:\" would try to set a capitalized status.  We just don't\n so that much generality, and the generality lead to bugs.\n] \n\n[Resolve issue712: Rename --extended-help to --overview.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080515151414] \n\n[Do not react to darcs help --verbose\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080515143125\n \n It used to be the same as darcs --extended-help, but since we're\n renaming that to be darcs --overview, it seemed silly to be calling\n it 'verbose'\n] \n\n[+strictness comment in FPS.hs\ngwern0@gmail.com**20080515043031] \n\n[Resolve issue845: Pass ssh's stderr to our stderr.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080514135504\n \n This may have the side effect that users get *a lot* of scp output dumped\n on their screen, but false 'hanging' that Zooko reported seems like the\n greater evil.  Note that darcs transfer-mode is not affected by this, so\n the only users that would see the extra output are those who are interacting\n with servers that don't have darcs 2 installed.\n] \n\n[Canonize Pekka Pessi (again).\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080513122318] \n\n[Use nilPS wherever possible\nSpencer Janssen <sjanssen@cse.unl.edu>**20080513122834] \n\n[Remove unused UnsafeCatch module\nSpencer Janssen <sjanssen@cse.unl.edu>**20080416090542] \n\n[pipeDocToPager runs no pager if pager is \"\".\nPekka Pessi <pekka.pessi@nokia.com>**20080512154347\n \n Darcs does not run pager if DARCS_PAGER environment variable has empty value\n (or PAGER, if DARCS_PAGER is not set).\n \n This is like man uses MANPAGER or PAGER environment variables.\n] \n\n[Do pipeDocToPager withoutNonBlock.\nPekka Pessi <pekka.pessi@nokia.com>**20080512154126\n \n Pagers tend to fail if terminal is in non-blocking mode.\n] \n\n[Added withoutNonBlock to Exec.\nPekka Pessi <pekka.pessi@nokia.com>**20080512134145\n \n Now pipeDoc runs pager process without non-blocking IO mode.\n] \n\n[consistently indent index.html and make it validate\nSimon Michael <simon@joyful.com>**20080418012452] \n\n[Do not fix DarcsFlag (Output \"-\").\nPekka Pessi <pekka.pessi@nokia.com>**20080512162005\n \n -o- is used for output to stdout.\n] \n\n[don't inline darcs_version.\nDavid Roundy <droundy@darcs.net>**20080511115315\n There's no need to inline it, and doing so requires extra recompiles every\n time it changes.\n] \n\n[use viewDocWith in printPatchPager and cut view_file function.\nDavid Roundy <droundy@darcs.net>**20080511115112] \n\n[only use pager on longer data.\nDavid Roundy <droundy@darcs.net>**20080511114957\n This change also allows to print Docs to pager with whichever Printers we\n choose.\n] \n\n[Restore creation of temporary file when calling a pager.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080510233252\n \n The way runProcess works now, we have to redirect the pager's stdout (?).\n For the pager, since it's not writing to a terminal, the sane thing for it\n to do is to just behave like cat.\n \n For now we just go back to the old behaviour of calling the pager with a\n temporary file as an argument.  The only difference here is that we\n create the temporary file in /tmp to avoid some of issue770.  This is\n safe because it's only the pager that uses the file, not us.\n] \n\n[resolve Issue803: add files back in that were manually moved on darcs mv.\nDavid Roundy <droundy@darcs.net>**20080509202630] \n\n[tiny wibble to make code a little more symmetric.\nDavid Roundy <droundy@darcs.net>**20080509195930] \n\n[resolve Issue739: compile with threaded runtime by default.\nDavid Roundy <droundy@darcs.net>**20080509195833\n It turns out that the tempfile-removal cleanup wasn't particularly feasible\n without the threaded runtime.\n] \n\n[resolve Issue776: add code to wait for forkIO error-reporting threads to exit.\nDavid Roundy <droundy@darcs.net>**20080509195804] \n\n[make pipeDoc use System.Process.\nDavid Roundy <droundy@darcs.net>**20080509193137\n This one was tricky, because we need to forward stderr and stdout from the\n process.  This ugly because of the limited API provided by System.Process.\n Ideally we'd let the child inherit both stderr and stdout, and we wouldn't\n need to have any of this forkIO and MVar complexity.\n] \n\n[clean up execPipeIgnoreError to use System.Process.\nDavid Roundy <droundy@darcs.net>**20080509165812] \n\n[Create temporary files in the current directory.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080509153406\n We don't know how openBinaryTempFile behaves with an empty string\n as the directory.\n] \n\n[Create temporary files with openBinaryTempFile.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080509145636\n Remove some mkstemp-related code which is no longer used.\n] \n\n[Use System.Directory.getTemporaryDirectory to determine tmp location.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080509143035\n \n This is more portable.  For instance, it understands Windows's\n conventions.\n] \n\n[corrected ratification...\nDavid Roundy <droundy@darcs.net>**20080509155411] \n\n[ratify Eric's use of readFile.\nDavid Roundy <droundy@darcs.net>**20080509150447] \n\n[Fall back to stdout if viewing a file with a pager fails.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080509122756\n \n This is related to issue770.  Note also that there is another\n function Darcs.External.viewDoc which does something similar.\n] \n\n[simplify pull_compl.sh just a tad.\nDavid Roundy <droundy@darcs.net>**20080509120623] \n\n[ignore any errors in clean_pristine.\nDavid Roundy <droundy@darcs.net>**20080508203823\n This will now be triggered when running repair, and should be essentially\n harmless.\n] \n\n[cause check to fail if there are patches that remove non-empty files.\nDavid Roundy <droundy@darcs.net>**20080508201818] \n\n[resolve Issue815: enable rempair of \"rm\" patches that don't remove file contents.\nDavid Roundy <droundy@darcs.net>**20080508201713\n Note that this doesn't fix the underlying bug that allowed these patches to\n be created, but at least it can help users with corrupt repositories.\n] \n\n[support patch fixing in PatchInfoAnd.\nDavid Roundy <droundy@darcs.net>**20080507190933] \n\n[avoid using \"which\" command, which is buggy on SunOS.\nDavid Roundy <droundy@darcs.net>**20080507190521] \n\n[make patchSetToRepository work on hashed repositories.\nDavid Roundy <droundy@darcs.net>**20080507183543] \n\n[move comment to last line of compile attempts in aclocal.m4.\nDavid Roundy <droundy@darcs.net>**20080507145339] \n\n[resolve Issue817: fix bug in conflict-handling with darcs-2 semantics.\nDavid Roundy <droundy@darcs.net>**20080507144950\n This bug was due to the buggy use of a buggy function called\n depends_uponFL.  I've removed this function, and am making this note\n explicit so that noone else (including myself) will make the mistake of\n resurrecting this function from the past.\n] \n\n[update copyright info in aclocal.m4\nDavid Roundy <droundy@darcs.net>**20080507144721] \n\n[make conflict-fight-failure test a little more legible and verbose.\nDavid Roundy <droundy@darcs.net>**20080507134927] \n\n[Canonize Pekka Pessi.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080507130033] \n\n[Demonstrate conflict fight bug #817\nPekka Pessi <first.last@nokia.com>**20080507113647\n \n Too deep conflict fight ends with Inconsistent patch w/ conflictor.\n \n Use make bugs_shell_format2 for demonstration.\n \n] \n\n[Fix space issue in issue803.sh\nlele@nautilus.homeip.net**20080507121137] \n\n[fix weird bug in harness.sh maybe?\nDavid Roundy <droundy@darcs.net>**20080506210002] \n\n[make harness.sh a little more verbose.\nDavid Roundy <droundy@darcs.net>**20080506191708] \n\n[translate whatsnew.pl into shell.\nDavid Roundy <droundy@darcs.net>**20080506145907] \n\n[document running a couple of tests.\nDavid Roundy <droundy@darcs.net>**20080506145001] \n\n[document that we now can just use \"darcs\" in shell tests.\nDavid Roundy <droundy@darcs.net>**20080506144944] \n\n[remove darcs wrapper from tests.\nDavid Roundy <droundy@darcs.net>**20080506144610] \n\n[don't set the IFS variable to null in harness.\nDavid Roundy <droundy@darcs.net>**20080506142954] \n\n[simplify uniqueoptions.sh\nDavid Roundy <droundy@darcs.net>**20080506142716] \n\n[simplify tests a bit more.\nDavid Roundy <droundy@darcs.net>**20080506141913] \n\n[clean up before running issue436.sh.\nDavid Roundy <droundy@darcs.net>**20080506135341] \n\n[fix space issue in test.\nDavid Roundy <droundy@darcs.net>**20080506135217] \n\n[avoid unnecessary complexity in tests.\nDavid Roundy <droundy@darcs.net>**20080506111116] \n\n[modernize steve-and-monica test.\nDavid Roundy <droundy@darcs.net>**20080506110739] \n\n[simplify code to avoid having to worry about spaces in test path.\nDavid Roundy <droundy@darcs.net>**20080506110534] \n\n[fix pull_many_files.pl test to search for GNU tar first\nKarel Gardas <kgardas@objectsecurity.com>**20080506065321] \n\n[darcs.cabal: make clear that this is an unofficial package\ngwern0@gmail.com**20080505214211\n Currently the only 'official' packages are either binary or compile through Autotools the entire way (and not a hybrid like this); and I can't warrant this as perfect, so it'd be dishonest to not mention the unofficialness of this.\n] \n\n[bugfix, --ask-deps needs with_selected_changes_reversed to ask the right questions\nTommy Pettersson <ptp@lysator.liu.se>**20080504161526] \n\n[(re-)add with_selected_changes_reversed to SelectChanges\nTommy Pettersson <ptp@lysator.liu.se>**20080504161412\n This function is needed for the --ask-deps options to Record.\n] \n\n[add test for --ask-deps\nTommy Pettersson <ptp@lysator.liu.se>**20080501095450] \n\n[slightly-prettier way to avoid using system shell's test function.\nDavid Roundy <droundy@darcs.net>**20080505203320] \n\n[simplify workaround for broken cp.\nDavid Roundy <droundy@darcs.net>**20080505201614] \n\n[add testsuite workarounds for Solaris `cp' and `test' commands issues\nKarel Gardas <kgardas@objectsecurity.com>**20080505195605] \n\n[included files reordering to fix build warning on Solaris\nKarel Gardas <kgardas@objectsecurity.com>**20080505185453] \n\n[make issue538 test work with spaces in directories.\nDavid Roundy <droundy@darcs.net>**20080505184459] \n\n[de-tapify issue538.sh test.\nDavid Roundy <droundy@darcs.net>**20080505184239] \n\n[remove recommendation to use TAP output for shell tests.\nDavid Roundy <droundy@darcs.net>**20080505165808] \n\n[resolve Issue832: quote all instances of \"$DARCS\", \"$ACTUAL_DARCS\", \"$PWD\", and \"$HOME\" in the sh tests and test harness, as well as all other shell variables that get expanded in test scripts (a cursory glance suggested that none of them were actually intended to be split on whitespace and so are probably best quoted).\nzooko@zooko.com**20080503181651] \n\n[Make curl_multi_timeout check work for static builds.\nDmitry Kurochkin <dmitry.kurochkin@gmail.com>**20080503212935] \n\n[Move curl_multi_timeout check outside of pipelining check.\nDmitry Kurochkin <dmitry.kurochkin@gmail.com>**20080503212708] \n\n[get rid of stupid debug messages.\nDavid Roundy <droundy@darcs.net>**20080503203650] \n\n[resolve conflict in aclocal.m4\nDavid Roundy <droundy@darcs.net>**20080503195800] \n\n[Do LDFLAGS conversion without calling out to GHC, avoiding nasty characters in GHC commands\nReinier Lamers <tux_rocker@reinier.de>**20080503192456] \n\n[avoid putting a newline into GHCLIBS and/or GHCLDFLAGS.\nDavid Roundy <droundy@darcs.net>**20080503180805] \n\n[even more stupid debug messages.\nDavid Roundy <droundy@darcs.net>**20080503171055] \n\n[insert stupid debug code into configure script.\nDavid Roundy <droundy@darcs.net>**20080503162856] \n\n[resolve issue793: fix regression in 'before X' date matching\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080502213535\n \n It was probably introduced by trying to convert CalendarTimes to\n ClockTimes; when converting a zero CalendarTime to ClockTime, we get\n something before zero.\n] \n\n[resolve issue245: more precise 'Bad token spec' error messages.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080502204426\n I think this resolves issue371 as well.\n] \n\n[Slight tidy up of English module.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080502201151] \n\n[mark issue803.sh test as a currently-failing bug.\nDavid Roundy <droundy@darcs.net>**20080502185438] \n\n[Added test for issue 803\nlele@nautilus.homeip.net**20080501233629] \n\n[darcs.cabal: rm gitlib\ngwern0@gmail.com**20080503014441] \n\n[use bash in test.\nDavid Roundy <droundy@darcs.net>**20080502184149] \n\n[Fix test for issue 538\ntux_rocker@reinier.de**20080502154349] \n\n[Added test for issue 538\ntux_rocker@reinier.de**20080501221528] \n\n[issue 538: set scripts executable before test if user desires\ntux_rocker@reinier.de**20080501203644] \n\n[resolve Issue813: make configure test consult LDFLAGS and LIBS.\nDavid Roundy <droundy@darcs.net>**20080502160200] \n\n[add another test for Issue794.\nDavid Roundy <droundy@darcs.net>**20080502160111] \n\n[Correct how darcs treats identical changes under darcs-2 format\nlele@nautilus.homeip.net**20080502084118] \n\n[prefer catMaybes over list comprehension.\nDavid Roundy <droundy@darcs.net>**20080502153330] \n\n[Move repoformat bug to passing tests.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080501223603] \n\n[resolve issue794: don't stop on first repoformat success.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080501223923\n \n Unfortunately, this bug means that older versions darcs might not be\n aware of potential forwards-compatibility issues, where the new,\n unrecognised lines in repoformat come after a familiar one.\n] \n\n[doc: msmtp -t (for multiple recipients)\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080501224701\n \n When I used --sendmail-command=\"msmtp %t %<\" to send a patch to the darcs\n darcs repository, I got the following error:\n \n   PERM_FAILURE: Probe failed: Illegal To: address (invalid domain name):\n   droundy@darcs.net, darcs-users@darcs.net          \n \n Using -t in sendmail mode causes msmtp to read the recipients from the\n message itself, which I suppose works better than passing them in via\n the command line.\n] \n\n[resolve issue827: correct changes -i behaviour\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080502090907\n \n Promised old behaviour:\n     Shall I view this patch?\n      y - view this patch; keep going\n      n - do not view this patch; keep going [DEFAULT]\n      v - view this patch; keep going\n      q - quit\n \n Actual old behaviour:\n     Shall I view this patch?\n      y - view this patch; stay put \n      n - do not view this patch; keep going [DEFAULT]\n      v - view this patch; stay put \n      q - quit\n \n New behaviour:\n     Shall I view this patch?\n      y - view this patch; keep going \n      n - do not view this patch; keep going [DEFAULT]\n      v - view this patch; stay put \n      q - quit\n] \n\n[Correct changes -i help message.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080502090655] \n\n[Use `curl-config --static-libs` when building with static libs.\nDmitry Kurochkin <dmitry.kurochkin@gmail.com>**20080502115703] \n\n[resolve issue283: Make darcs help <cmd> consistent with darcs <cmd> --help.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080502123521\n \n darcs help <cmd>, no longer print the darcs version.\n] \n\n[reorder test suite around fact that test_unit takes so long.\nDavid Roundy <droundy@darcs.net>**20080501113207] \n\n[remove gitlib.{c,h.in} as it appears to be unused\nJason Dagit <dagit@codersbase.com>**20080501002306] \n\n[refactor \"_darcs\" to darcsdir variable\nJason Dagit <dagit@codersbase.com>**20080501042650] \n\n[change handling of hi files to use silly make rule as ghc docs suggest.\nDavid Roundy <droundy@darcs.net>**20080501105800] \n\n[enable automatic running of additional tests, as Gwern suggested.\nDavid Roundy <droundy@darcs.net>**20080501105606] \n\n[generalize the testing for external libraries.\nDavid Roundy <droundy@darcs.net>**20080430232912] \n\n[Use GHC instead of GCC to check for zlib availability (issue 813)\ntux_rocker@reinier.de**20080430220105] \n\n[resolve issue76: update docs on temp directory creation.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080430175713] \n\n[Add test for issue794.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080430165251] \n\n[doc: encourage new users to use --darcs-2 repositories.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080425172110\n Note that this is sans explanation (in the getting started section).\n Maybe new users might be put off by the mystery flag?\n] \n\n[doc: tell users about darcs-2 handling of identical patches.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080425172104\n Do not bother talking about darcs-1 behaviour.\n] \n\n[add test for darcs show bug.\nDavid Roundy <droundy@darcs.net>**20080430165425] \n\n[fix bug in configure script wrt HTTP package.\nDavid Roundy <droundy@darcs.net>**20080430165350] \n\n[cleanup in ShowAuthors: \"as\" is a bad variable name, since it's also a haskell keyword.\nDavid Roundy <droundy@darcs.net>**20080430161237] \n\n[add very simple test for show authors.\nDavid Roundy <droundy@darcs.net>**20080430161222] \n\n[Ordered.lhs: explain acronyms\ngwern0@gmail.com**20080429203213] \n\n[Prefs.lhs: add cabal intermediates to ignore\ngwern0@gmail.com**20080429201917\n Re-send, not depending on rejected patches.\n] \n\n[darcs.cabal: stringalike module removed\ngwern0@gmail.com**20080429194148] \n\n[remove unused function ephemeral.\nDavid Roundy <droundy@darcs.net>**20080429163057] \n\n[remove unused compress/uncompress functions.\nDavid Roundy <droundy@darcs.net>**20080429162552] \n\n[remove unneeded --verify-hash flag (we always verify hashes).\nDavid Roundy <droundy@darcs.net>**20080429162303] \n\n[remove Stringalike module entirely.\nDavid Roundy <droundy@darcs.net>**20080429155919] \n\n[cut commented code (that would no longer compile).\nDavid Roundy <droundy@darcs.net>**20080429155455] \n\n[eliminate use of Stringalike in ReadMonad and friends.\nDavid Roundy <droundy@darcs.net>**20080429155158] \n\n[simplify ParserM\nDavid Roundy <droundy@darcs.net>**20080429153800] \n\n[make PatchInfo reading specific to PackedString.\nDavid Roundy <droundy@darcs.net>**20080429152300] \n\n[remove unused function test_patch.\nDavid Roundy <droundy@darcs.net>**20080429150504] \n\n[remove unused emptyFileContents.\nDavid Roundy <droundy@darcs.net>**20080429150154] \n\n[remove unused isExecutable function.\nDavid Roundy <droundy@darcs.net>**20080429145721] \n\n[Prefs.lhs: ignore .darcsrepo as well\ngwern0@gmail.com**20080429012932\n Add it now, since we're going to get .darcsrepo at some point.\n] \n\n[Prefs.lhs: ignore zsh-compiled files and Gentoo/X leftover files\ngwern0@gmail.com**20080429010201] \n\n[Prefs.lhs: ignore .git\ngwern0@gmail.com**20080429010115] \n\n[Prefs.lhs: ignore profiling intermediate files\ngwern0@gmail.com**20080429010050] \n\n[Diff.lhs, Prefs.lhs: add docs for 4096 optimization\ngwern0@gmail.com**20080427234109] \n\n[Diff.lhs: has_bin only inspects first 4096 characters\ngwern0@gmail.com**20080427233947\n This is an optimization for large files, it saves running has_funky on gigs and gigs of data when pretty much all binary files give the truth away within a few characters.\n] \n\n[fpstring.c: switch a memchr for memrchr\ngwern0@gmail.com**20080425200153\n See <http://bugs.darcs.net/issue814>; memrchr speeds up is_funky quite a bit and thus helps whatsnew -s. It doesn't seem to break (any more) tests.\n] \n\n[configure: more precise error messages about packages.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080424120226] \n\n[SlurpDirectory.lhs: remove apparently pointless aliases\ngwern0@gmail.com**20080428010950] \n\n[implement primitive fixing of removal of non-empty files.\nDavid Roundy <droundy@darcs.net>**20080428165532] \n\n[add framework for patch-fixing repair.\nDavid Roundy <droundy@darcs.net>**20080428153041] \n\n[correct mmap type signatures\nJason Dagit <dagit@codersbase.com>**20080428190837] \n\n[grammar fix\nFerenc Wagner <wferi@niif.hu>**20080426173243] \n\n[add checks for removal of non-empty files.\nDavid Roundy <droundy@darcs.net>**20080426120904] \n\n[remove git section from building_darcs.tex\nDavid Roundy <droundy@darcs.net>**20080424134245\n Thanks to Nicolas Pouillard for pointing this out.\n] \n\n[clean up genslurp_helper a tad.\nDavid Roundy <droundy@darcs.net>**20080423214457\n I'm removing an unneeded unsafeInterleaveIO and am reformatting some of the\n indentation to make it clearer which else goes with which if.\n] \n\n[remove unneeded redundant adding of -lcurses (done by AC_SEARCH_LIBS).\nDavid Roundy <droundy@darcs.net>**20080423214404] \n\n[Give a clear error message when no suitable haddock is installed\ntux_rocker@reinier.de**20080423172834] \n\n[simplify configure a bit: if we're defining CPP symbols, no need to also use AC_SUBST.\nDavid Roundy <droundy@darcs.net>**20080423152121] \n\n[simplify makefile a bit.\nDavid Roundy <droundy@darcs.net>**20080423150529] \n\n[darcs.cabal: Darcs.ColourPrinter -> Darcs.ColorPrinter module name\ngwern0@gmail.com**20080423182655] \n\n[give proper error message when slurping fails to identify a file or directory.\nDavid Roundy <droundy@darcs.net>**20080423141737] \n\n[default to not coloring hunks.\nDavid Roundy <droundy@darcs.net>**20080423141725] \n\n[Use the lineColoring to prettify hunks with colors.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080420135252] \n\n[Add line coloring support in Printer and ColourPrinter.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080420135238] \n\n[Export Printer.(<?>).\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080420135208] \n\n[Add two colors (cyan and magenta), but not use them yet.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080420122811] \n\n[Refactor a little the color handling.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080420122500] \n\n[slim down the makefile based on Gwern's changes to the configure script.\nDavid Roundy <droundy@darcs.net>**20080423131854] \n\n[Little style change.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080420122143] \n\n[Define unDoc as field of Doc.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080416075954] \n\n[Replace colour by color to uniformise a bit.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080416074742] \n\n[Canonize G. Branwen, P. Rockai, L. Komolodin and R. Lamers.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080422152346\n All anonymous patches get assigned to Gwern. \n] \n\n[doc tweak\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080422151420] \n\n[resolve issue809: doc: darcs get is not lazy by default.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080422150809] \n\n[doc: darcs-2 is no longer experimental.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080422150736] \n\n[Rename ColourPrinter to ColorPrinter.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080421154043\n We might as well standardize on American spelling in the code.\n] \n\n[eliminate duplicate get_remote_repo in favor of list comprehensions.\nDavid Roundy <droundy@darcs.net>**20080421145642] \n\n[resolve issue792: Account for --remote-repo in defaultrepo code\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080421144023] \n\n[Extend command_argdefaults to accept [DarcsFlag].\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080421143950] \n\n[Add a --remote-repodir flag (yet unused).\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080421134352] \n\n[Account for pre-existing api-doc.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080421135155] \n\n[Create the api-doc dir if it does not exist.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080421134800] \n\n[resolve issue795: Make 'darcs changes -i' behave more like other jobs.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080421105247\n \n Old behaviour:\n  Shall I continue to view changes?\n    y - do not view this patch; keep going [DEFAULT]\n    n - quit\n    v - view this patch; keep going\n    q - quit\n \n New behaviour:\n   Shall I view this patch?\n    y - view this patch; keep going\n    n - do not view this patch; keep going [DEFAULT]\n    v - view this patch; keep going\n    q - quit\n] \n\n[Undo a false refactor in SelectChanges.\nEric Kow <E.Y.Kow@brighton.ac.uk>**20080421104106\n \n The new old code makes it clearer that text_view is only used by\n 'view changes'\n] \n\n[Fix pluralization of patches using English module.\nDavid Roundy <droundy@darcs.net>**20080421121716] \n\n[optimized get --to-match handling for darcs 1 repositories\ntux_rocker@reinier.de**20080420152608] \n\n[cabalize\ngwern0@gmail.com**20080420225632] \n\n[+darcs.buildinfo, and configure.ac enablement\ngwern0@gmail.com**20080420223937] \n\n[configure.ac: export -lcurses for cabal\ngwern0@gmail.com**20080420221056] \n\n[configure.ac: move HAVE_CURL around\ngwern0@gmail.com**20080420220800\n The dependency was inverted; we want to set HAVE_CURL before we test for Curl pipelining.\n] \n\n[configure.ac: export Curses as well\ngwern0@gmail.com**20080420214353] \n\n[configure.ac: export -DHAVE_LIBWWW for CPP\ngwern0@gmail.com**20080420213108] \n\n[configure.ac: +mention why threaded is not default/doc\ngwern0@gmail.com**20080420023752] \n\n[stringify.hs: rw to avoid multi-line string literal\ngwern0@gmail.com**20080419025648\n The reason we want to avoid multi-line string literals is because GHC and CPP can break them quite badly if accidentally applied.\n In addition, no one is going to read Context.hs - it exists solely to be compiled. So removing the multi-line business in favor of one long string which will look exactly the same in the compiled binary causes no problems. And it can fix a big one - if Context.hs can't be compiled, obviously Darcs cannot.\n] \n\n[replace '{-# OPTIONS' with '{-# OPTIONS_GHC'\ngwern0@gmail.com**20080419024027\n These OPTIONS pragmas use GHC-isms; best practice is to make them GHC specific if they are GHC specific.\n Specifically: -fglasgow-exts is obviously GHC only. -cpp is used only by GHC AFAIK - hugs uses some hugscpp, YHC uses '--cpp' as does presumably NHC, JHC doesn't support cpp, and no idea about the others.\n However, this patch omits modifying \"src/Darcs/ColourPrinter.lhs\", \"src/Workaround.hs\", and \"src/win32/CtrlC.hs\" because I was uncertain whether '-fno-warn-orphans', '-w', and '-ffi' are actually GHC-only.\n] \n\n[rearrange bytestring tests so if it's not present we're quieter.\nDavid Roundy <droundy@darcs.net>**20080418212319] \n\n[configure.ac: restructure curl\ngwern0@gmail.com**20080419020619\n We want to make sure HAVE_CURL shows up in CPP flags.\n] \n\n[configure.ac: fix bytestring checking\ngwern0@gmail.com**20080418205704\n This changes bytestring to be default. However it checks twice: if either --disable-bytestring is set or bytestring can't be found, it won't pass on CPP -DHAVE_BYTESTRING. So this should work for Dr. Roundy's lack of bytestring.\n] \n\n[remove unneeded check for termio.h.\nDavid Roundy <droundy@darcs.net>**20080417172427] \n\n[configure.ac: rm line\ngwern0@gmail.com**20080416184604\n I can't even figure out how long ago Control.Monad was in a 'util' package.\n] \n\n[we don't need Darcs.Patch.Check for darcs itself.\nDavid Roundy <droundy@darcs.net>**20080417150720] \n\n[remove hackish attempt to set GC parameters based on available memory.\nDavid Roundy <droundy@darcs.net>**20080416164105] \n\n[define forM_ since it is absent on GHC 6.4.1\nzooko@zooko.com**20080409234512] \n\n[make darcs build on win32 by conditionally compiling out a few bits that are unused or meaningless on win32\nzooko@zooko.com**20080410204830] \n\n[Don't let other configure flags change the type witnesses\nLennart Kolmodin <kolmodin@gentoo.org>**20080415210614\n For example, when using --with-docs the type witnesses would be turned on,\n while with --without-docs they would not. This patch adresses this issue.\n] \n\n[eliminate use of Haskell 98 library modules.\nDavid Roundy <droundy@darcs.net>**20080415214217] \n\n[add type witness declarations to Resolution\nDavid Roundy <droundy@darcs.net>**20080415165457] \n\n[move -cpp option into source files.\nDavid Roundy <droundy@darcs.net>**20080415144719] \n\n[Issue a warning when using --old-fashioned-inventory with a darcs-2 repository.\nNicolas Pouillard <nicolas.pouillard@gmail.com>**20080414232715] \n\n[FastPackedString.hs: FastPackedString.hs: redefine linePS/unlinesPS\ngwern0@gmail.com**20080414150839\n Turns out that my definitions were wrong - they differed and added a newline where the old FPS versions didn't. So I've rewritten the wrapper versions around ByteString, and checked them against the old ones with QuickCheck. With these fixes, a bytestring darcs seems to pass all the tests as a fps darcs.\n] \n\n[remove unused Setup.lhs.\nDavid Roundy <droundy@darcs.net>**20080414190738] \n\n[roll back implementation of joke oops command.\nDavid Roundy <droundy@darcs.net>**20080414133342\n Apparently it didn't actually work...\n \n rolling back:\n \n Tue Apr  8 07:58:56 PDT 2008  David Roundy <droundy@darcs.net>\n   * resolve issue786:  implement oops command.\n \n     M ./src/Darcs/Commands/Tag.lhs -5 +47\n     M ./src/Darcs/TheCommands.lhs -1 +2\n] \n\n[just remove concatLenPS\nDavid Roundy <droundy@darcs.net>**20080411205303\n It is never used in a performance-critical situation, so I'm voting to just\n trash it.  I'd rather have fewer unsafe operations.\n] \n\n[FastPackedString.hs: simplify concatLenPS, although this removes its strictness properties\n**20080411035327] \n\n[FastPackedString.hs: remove wfindPS\n**20080411035046\n With better imports from bytestring, I believe it to be superfluous, and dangerous to leave around.\n] \n\n[FastPackedString.hs: grmmr/sp\n**20080411034730] \n\n[FastPackedString.hs: rw linesPS using ByteString split\n**20080411032229] \n\n[doc updates\ngwern0@gmail.com**20080409170824\n Convert all uses of 'http://darcs.net/repos/stable' to just darcs.net, since unstable and stable were merged together, and the old URL is a 404 for darcs getting. This is a real problem, see for example <http://reddit.com/info/6ewbq/comments/c03o6d5>.\n] \n\n[fix typo in show_bug_help\nMatyas Janos <mjanos5@gmail.com>**20080408232600] \n\n[Raise a configure error when no Text.Regex module can be found.\nnicolas.pouillard@gmail.com**20080409085522] \n\n[update README url links\ngwern0@gmail.com**20080407201333] \n\n[add a bit more debugging info to repository identification.\nDavid Roundy <droundy@darcs.net>**20080408151912] \n\n[resolve issue385: don't worry if we can't get local changes.\nDavid Roundy <droundy@darcs.net>**20080408151823] \n\n[add test for issue385.\nDavid Roundy <droundy@darcs.net>**20080408151808] \n\n[resolve issue786:  implement oops command.\nDavid Roundy <droundy@darcs.net>**20080408145856] \n\n[fix URL in network test.\nDavid Roundy <droundy@darcs.net>**20080408145407] \n\n[fix manual bug.\nDavid Roundy <droundy@darcs.net>**20080407191736] \n\n[add new show bug command (hidden) to see what darcs will report if we encounter a bug.\nDavid Roundy <droundy@darcs.net>**20080407175410] \n\n[automatically work out the version of the stable release.\nDavid Roundy <droundy@darcs.net>**20080407171850] \n\n[set prefs again (they got lost on convert).\nDavid Roundy <droundy@darcs.net>**20080407171559] \n\n[update darcs repository URL.\nDavid Roundy <droundy@darcs.net>**20080407164601] \n\n[fix up website for new release.\nDavid Roundy <droundy@darcs.net>**20080407164010] \n\n[simplify determine_release_state.pl.\nDavid Roundy <droundy@darcs.net>**20080407153000] \n\n[make determine_release_state.pl use changes --count.\nDavid Roundy <droundy@darcs.net>**20080407152347] \n\n[add --count output option to changes.\nDavid Roundy <droundy@darcs.net>**20080407151825] \n\n[TAG 2.0.0\nDavid Roundy <droundy@darcs.net>**20080407150638] \n"
+ src/Crypt/SHA256.hs view
@@ -0,0 +1,42 @@+{-# OPTIONS_GHC -fffi -cpp #-}+-- |+-- Module:    Data.Digest.SHA256+-- Copyright: Zooko O'Whielacronx+-- License:   GPL+--+-- Stability: experimental++-- ByteString-based, zero-copying binding to Crypto++'s sha interface++-- thanks to Don Stewart <dons@galois.com>, Matthew Sackman+-- <matthew@wellquite.org>, Brian O'Sullivan, lispy, Adam Langley++module Crypt.SHA256 ( sha256sum ) where++import FastPackedString ( PackedString, unsafeWithCStringLenPS )+import Foreign+import Foreign.C.Types+import Numeric (showHex)+import Foreign.C.String ( withCString )++sha256sum :: PackedString -> String+sha256sum p = unsafePerformIO $+              withCString (take 64 $ repeat 'x') $ \digestCString ->+              unsafeWithCStringLenPS p $ \(ptr,n) ->+              do let digest = castPtr digestCString :: Ptr Word8+                 c_sha256 ptr (fromIntegral n) digest+                 go digest 0 []+  where -- print it in 0-padded hex format+        go :: Ptr Word8 -> Int -> [String] -> IO String+        go q n acc | seq q n >= 32 = return $ concat (reverse acc)+                   | otherwise = do w <- peekElemOff q n+                                    go q (n+1) (draw w : acc)+        draw w = case showHex w [] of+                 [x] -> ['0', x]+                 x   -> x++-- void sha256sum(const unsigned char *d, size_t n, unsigned char *md);+--+foreign import ccall unsafe "sha2.h sha256" c_sha256+    :: Ptr CChar -> CSize -> Ptr Word8 -> IO ()+
+ src/Crypt/sha2.c view
@@ -0,0 +1,950 @@+/*+ * FIPS 180-2 SHA-224/256/384/512 implementation+ * Last update: 02/02/2007+ * Issue date:  04/30/2005+ *+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ *    notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ *    notice, this list of conditions and the following disclaimer in the+ *    documentation and/or other materials provided with the distribution.+ * 3. Neither the name of the project nor the names of its contributors+ *    may be used to endorse or promote products derived from this software+ *    without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ * SUCH DAMAGE.+ */++#if 0+#define UNROLL_LOOPS /* Enable loops unrolling */+#endif++#include <string.h>++#include "sha2.h"++#define SHFR(x, n)    (x >> n)+#define ROTR(x, n)   ((x >> n) | (x << ((sizeof(x) << 3) - n)))+#define ROTL(x, n)   ((x << n) | (x >> ((sizeof(x) << 3) - n)))+#define CH(x, y, z)  ((x & y) ^ (~x & z))+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))++#define SHA256_F1(x) (ROTR(x,  2) ^ ROTR(x, 13) ^ ROTR(x, 22))+#define SHA256_F2(x) (ROTR(x,  6) ^ ROTR(x, 11) ^ ROTR(x, 25))+#define SHA256_F3(x) (ROTR(x,  7) ^ ROTR(x, 18) ^ SHFR(x,  3))+#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))++#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))+#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))+#define SHA512_F3(x) (ROTR(x,  1) ^ ROTR(x,  8) ^ SHFR(x,  7))+#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x,  6))++#define UNPACK32(x, str)                      \+{                                             \+    *((str) + 3) = (uint8) ((x)      );       \+    *((str) + 2) = (uint8) ((x) >>  8);       \+    *((str) + 1) = (uint8) ((x) >> 16);       \+    *((str) + 0) = (uint8) ((x) >> 24);       \+}++#define PACK32(str, x)                        \+{                                             \+    *(x) =   ((uint32) *((str) + 3)      )    \+           | ((uint32) *((str) + 2) <<  8)    \+           | ((uint32) *((str) + 1) << 16)    \+           | ((uint32) *((str) + 0) << 24);   \+}++#define UNPACK64(x, str)                      \+{                                             \+    *((str) + 7) = (uint8) ((x)      );       \+    *((str) + 6) = (uint8) ((x) >>  8);       \+    *((str) + 5) = (uint8) ((x) >> 16);       \+    *((str) + 4) = (uint8) ((x) >> 24);       \+    *((str) + 3) = (uint8) ((x) >> 32);       \+    *((str) + 2) = (uint8) ((x) >> 40);       \+    *((str) + 1) = (uint8) ((x) >> 48);       \+    *((str) + 0) = (uint8) ((x) >> 56);       \+}++#define PACK64(str, x)                        \+{                                             \+    *(x) =   ((uint64) *((str) + 7)      )    \+           | ((uint64) *((str) + 6) <<  8)    \+           | ((uint64) *((str) + 5) << 16)    \+           | ((uint64) *((str) + 4) << 24)    \+           | ((uint64) *((str) + 3) << 32)    \+           | ((uint64) *((str) + 2) << 40)    \+           | ((uint64) *((str) + 1) << 48)    \+           | ((uint64) *((str) + 0) << 56);   \+}++/* Macros used for loops unrolling */++#define SHA256_SCR(i)                         \+{                                             \+    w[i] =  SHA256_F4(w[i -  2]) + w[i -  7]  \+          + SHA256_F3(w[i - 15]) + w[i - 16]; \+}++#define SHA512_SCR(i)                         \+{                                             \+    w[i] =  SHA512_F4(w[i -  2]) + w[i -  7]  \+          + SHA512_F3(w[i - 15]) + w[i - 16]; \+}++#define SHA256_EXP(a, b, c, d, e, f, g, h, j)               \+{                                                           \+    t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \+         + sha256_k[j] + w[j];                              \+    t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]);       \+    wv[d] += t1;                                            \+    wv[h] = t1 + t2;                                        \+}++#define SHA512_EXP(a, b, c, d, e, f, g ,h, j)               \+{                                                           \+    t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \+         + sha512_k[j] + w[j];                              \+    t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]);       \+    wv[d] += t1;                                            \+    wv[h] = t1 + t2;                                        \+}++uint32 sha224_h0[8] =+            {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,+             0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4};++uint32 sha256_h0[8] =+            {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,+             0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};++uint64 sha384_h0[8] =+            {0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL,+             0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL,+             0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,+             0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL};++uint64 sha512_h0[8] =+            {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,+             0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,+             0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,+             0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};++uint32 sha256_k[64] =+            {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,+             0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,+             0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,+             0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,+             0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,+             0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,+             0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,+             0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,+             0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,+             0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,+             0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,+             0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,+             0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,+             0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,+             0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,+             0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};++uint64 sha512_k[80] =+            {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,+             0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,+             0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,+             0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,+             0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,+             0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,+             0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,+             0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,+             0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,+             0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,+             0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,+             0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,+             0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,+             0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,+             0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,+             0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,+             0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,+             0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,+             0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,+             0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,+             0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,+             0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,+             0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,+             0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,+             0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,+             0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,+             0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,+             0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,+             0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,+             0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,+             0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,+             0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,+             0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,+             0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,+             0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,+             0x113f9804bef90daeULL, 0x1b710b35131c471bULL,+             0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,+             0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,+             0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,+             0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};++/* SHA-256 functions */++void sha256_transf(sha256_ctx *ctx, const unsigned char *message,+                   unsigned int block_nb)+{+    uint32 w[64];+    uint32 wv[8];+    uint32 t1, t2;+    const unsigned char *sub_block;+    int i;++#ifndef UNROLL_LOOPS+    int j;+#endif++    for (i = 0; i < (int) block_nb; i++) {+        sub_block = message + (i << 6);++#ifndef UNROLL_LOOPS+        for (j = 0; j < 16; j++) {+            PACK32(&sub_block[j << 2], &w[j]);+        }++        for (j = 16; j < 64; j++) {+            SHA256_SCR(j);+        }++        for (j = 0; j < 8; j++) {+            wv[j] = ctx->h[j];+        }++        for (j = 0; j < 64; j++) {+            t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6])+                + sha256_k[j] + w[j];+            t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);+            wv[7] = wv[6];+            wv[6] = wv[5];+            wv[5] = wv[4];+            wv[4] = wv[3] + t1;+            wv[3] = wv[2];+            wv[2] = wv[1];+            wv[1] = wv[0];+            wv[0] = t1 + t2;+        }++        for (j = 0; j < 8; j++) {+            ctx->h[j] += wv[j];+        }+#else+        PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]);+        PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]);+        PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]);+        PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]);+        PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]);+        PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]);+        PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]);+        PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]);++        SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19);+        SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23);+        SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27);+        SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31);+        SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35);+        SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39);+        SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43);+        SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47);+        SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51);+        SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55);+        SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59);+        SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63);++        wv[0] = ctx->h[0]; wv[1] = ctx->h[1];+        wv[2] = ctx->h[2]; wv[3] = ctx->h[3];+        wv[4] = ctx->h[4]; wv[5] = ctx->h[5];+        wv[6] = ctx->h[6]; wv[7] = ctx->h[7];++        SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1);+        SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3);+        SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5);+        SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7);+        SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9);+        SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11);+        SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13);+        SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15);+        SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17);+        SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19);+        SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21);+        SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23);+        SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25);+        SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27);+        SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29);+        SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31);+        SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33);+        SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35);+        SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37);+        SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39);+        SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41);+        SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43);+        SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45);+        SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47);+        SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49);+        SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51);+        SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53);+        SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55);+        SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57);+        SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59);+        SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61);+        SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63);++        ctx->h[0] += wv[0]; ctx->h[1] += wv[1];+        ctx->h[2] += wv[2]; ctx->h[3] += wv[3];+        ctx->h[4] += wv[4]; ctx->h[5] += wv[5];+        ctx->h[6] += wv[6]; ctx->h[7] += wv[7];+#endif /* !UNROLL_LOOPS */+    }+}++void sha256(const unsigned char *message, unsigned int len, unsigned char *digest)+{+    sha256_ctx ctx;++    sha256_init(&ctx);+    sha256_update(&ctx, message, len);+    sha256_final(&ctx, digest);+}++void sha256_init(sha256_ctx *ctx)+{+#ifndef UNROLL_LOOPS+    int i;+    for (i = 0; i < 8; i++) {+        ctx->h[i] = sha256_h0[i];+    }+#else+    ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1];+    ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3];+    ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5];+    ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7];+#endif /* !UNROLL_LOOPS */++    ctx->len = 0;+    ctx->tot_len = 0;+}++void sha256_update(sha256_ctx *ctx, const unsigned char *message,+                   unsigned int len)+{+    unsigned int block_nb;+    unsigned int new_len, rem_len, tmp_len;+    const unsigned char *shifted_message;++    tmp_len = SHA256_BLOCK_SIZE - ctx->len;+    rem_len = len < tmp_len ? len : tmp_len;++    memcpy(&ctx->block[ctx->len], message, rem_len);++    if (ctx->len + len < SHA256_BLOCK_SIZE) {+        ctx->len += len;+        return;+    }++    new_len = len - rem_len;+    block_nb = new_len / SHA256_BLOCK_SIZE;++    shifted_message = message + rem_len;++    sha256_transf(ctx, ctx->block, 1);+    sha256_transf(ctx, shifted_message, block_nb);++    rem_len = new_len % SHA256_BLOCK_SIZE;++    memcpy(ctx->block, &shifted_message[block_nb << 6],+           rem_len);++    ctx->len = rem_len;+    ctx->tot_len += (block_nb + 1) << 6;+}++void sha256_final(sha256_ctx *ctx, unsigned char *digest)+{+    unsigned int block_nb;+    unsigned int pm_len;+    unsigned int len_b;++#ifndef UNROLL_LOOPS+    int i;+#endif++    block_nb = (1 + ((SHA256_BLOCK_SIZE - 9)+                     < (ctx->len % SHA256_BLOCK_SIZE)));++    len_b = (ctx->tot_len + ctx->len) << 3;+    pm_len = block_nb << 6;++    memset(ctx->block + ctx->len, 0, pm_len - ctx->len);+    ctx->block[ctx->len] = 0x80;+    UNPACK32(len_b, ctx->block + pm_len - 4);++    sha256_transf(ctx, ctx->block, block_nb);++#ifndef UNROLL_LOOPS+    for (i = 0 ; i < 8; i++) {+        UNPACK32(ctx->h[i], &digest[i << 2]);+    }+#else+   UNPACK32(ctx->h[0], &digest[ 0]);+   UNPACK32(ctx->h[1], &digest[ 4]);+   UNPACK32(ctx->h[2], &digest[ 8]);+   UNPACK32(ctx->h[3], &digest[12]);+   UNPACK32(ctx->h[4], &digest[16]);+   UNPACK32(ctx->h[5], &digest[20]);+   UNPACK32(ctx->h[6], &digest[24]);+   UNPACK32(ctx->h[7], &digest[28]);+#endif /* !UNROLL_LOOPS */+}++/* SHA-512 functions */++void sha512_transf(sha512_ctx *ctx, const unsigned char *message,+                   unsigned int block_nb)+{+    uint64 w[80];+    uint64 wv[8];+    uint64 t1, t2;+    const unsigned char *sub_block;+    int i, j;++    for (i = 0; i < (int) block_nb; i++) {+        sub_block = message + (i << 7);++#ifndef UNROLL_LOOPS+        for (j = 0; j < 16; j++) {+            PACK64(&sub_block[j << 3], &w[j]);+        }++        for (j = 16; j < 80; j++) {+            SHA512_SCR(j);+        }++        for (j = 0; j < 8; j++) {+            wv[j] = ctx->h[j];+        }++        for (j = 0; j < 80; j++) {+            t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6])+                + sha512_k[j] + w[j];+            t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);+            wv[7] = wv[6];+            wv[6] = wv[5];+            wv[5] = wv[4];+            wv[4] = wv[3] + t1;+            wv[3] = wv[2];+            wv[2] = wv[1];+            wv[1] = wv[0];+            wv[0] = t1 + t2;+        }++        for (j = 0; j < 8; j++) {+            ctx->h[j] += wv[j];+        }+#else+        PACK64(&sub_block[  0], &w[ 0]); PACK64(&sub_block[  8], &w[ 1]);+        PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]);+        PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]);+        PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]);+        PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]);+        PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]);+        PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]);+        PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]);++        SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19);+        SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23);+        SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27);+        SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31);+        SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35);+        SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39);+        SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43);+        SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47);+        SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51);+        SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55);+        SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59);+        SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63);+        SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67);+        SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71);+        SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75);+        SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79);++        wv[0] = ctx->h[0]; wv[1] = ctx->h[1];+        wv[2] = ctx->h[2]; wv[3] = ctx->h[3];+        wv[4] = ctx->h[4]; wv[5] = ctx->h[5];+        wv[6] = ctx->h[6]; wv[7] = ctx->h[7];++        j = 0;++        do {+            SHA512_EXP(0,1,2,3,4,5,6,7,j); j++;+            SHA512_EXP(7,0,1,2,3,4,5,6,j); j++;+            SHA512_EXP(6,7,0,1,2,3,4,5,j); j++;+            SHA512_EXP(5,6,7,0,1,2,3,4,j); j++;+            SHA512_EXP(4,5,6,7,0,1,2,3,j); j++;+            SHA512_EXP(3,4,5,6,7,0,1,2,j); j++;+            SHA512_EXP(2,3,4,5,6,7,0,1,j); j++;+            SHA512_EXP(1,2,3,4,5,6,7,0,j); j++;+        } while (j < 80);++        ctx->h[0] += wv[0]; ctx->h[1] += wv[1];+        ctx->h[2] += wv[2]; ctx->h[3] += wv[3];+        ctx->h[4] += wv[4]; ctx->h[5] += wv[5];+        ctx->h[6] += wv[6]; ctx->h[7] += wv[7];+#endif /* !UNROLL_LOOPS */+    }+}++void sha512(const unsigned char *message, unsigned int len,+            unsigned char *digest)+{+    sha512_ctx ctx;++    sha512_init(&ctx);+    sha512_update(&ctx, message, len);+    sha512_final(&ctx, digest);+}++void sha512_init(sha512_ctx *ctx)+{+#ifndef UNROLL_LOOPS+    int i;+    for (i = 0; i < 8; i++) {+        ctx->h[i] = sha512_h0[i];+    }+#else+    ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1];+    ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3];+    ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5];+    ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7];+#endif /* !UNROLL_LOOPS */++    ctx->len = 0;+    ctx->tot_len = 0;+}++void sha512_update(sha512_ctx *ctx, const unsigned char *message,+                   unsigned int len)+{+    unsigned int block_nb;+    unsigned int new_len, rem_len, tmp_len;+    const unsigned char *shifted_message;++    tmp_len = SHA512_BLOCK_SIZE - ctx->len;+    rem_len = len < tmp_len ? len : tmp_len;++    memcpy(&ctx->block[ctx->len], message, rem_len);++    if (ctx->len + len < SHA512_BLOCK_SIZE) {+        ctx->len += len;+        return;+    }++    new_len = len - rem_len;+    block_nb = new_len / SHA512_BLOCK_SIZE;++    shifted_message = message + rem_len;++    sha512_transf(ctx, ctx->block, 1);+    sha512_transf(ctx, shifted_message, block_nb);++    rem_len = new_len % SHA512_BLOCK_SIZE;++    memcpy(ctx->block, &shifted_message[block_nb << 7],+           rem_len);++    ctx->len = rem_len;+    ctx->tot_len += (block_nb + 1) << 7;+}++void sha512_final(sha512_ctx *ctx, unsigned char *digest)+{+    unsigned int block_nb;+    unsigned int pm_len;+    unsigned int len_b;++#ifndef UNROLL_LOOPS+    int i;+#endif++    block_nb = 1 + ((SHA512_BLOCK_SIZE - 17)+                     < (ctx->len % SHA512_BLOCK_SIZE));++    len_b = (ctx->tot_len + ctx->len) << 3;+    pm_len = block_nb << 7;++    memset(ctx->block + ctx->len, 0, pm_len - ctx->len);+    ctx->block[ctx->len] = 0x80;+    UNPACK32(len_b, ctx->block + pm_len - 4);++    sha512_transf(ctx, ctx->block, block_nb);++#ifndef UNROLL_LOOPS+    for (i = 0 ; i < 8; i++) {+        UNPACK64(ctx->h[i], &digest[i << 3]);+    }+#else+    UNPACK64(ctx->h[0], &digest[ 0]);+    UNPACK64(ctx->h[1], &digest[ 8]);+    UNPACK64(ctx->h[2], &digest[16]);+    UNPACK64(ctx->h[3], &digest[24]);+    UNPACK64(ctx->h[4], &digest[32]);+    UNPACK64(ctx->h[5], &digest[40]);+    UNPACK64(ctx->h[6], &digest[48]);+    UNPACK64(ctx->h[7], &digest[56]);+#endif /* !UNROLL_LOOPS */+}++/* SHA-384 functions */++void sha384(const unsigned char *message, unsigned int len,+            unsigned char *digest)+{+    sha384_ctx ctx;++    sha384_init(&ctx);+    sha384_update(&ctx, message, len);+    sha384_final(&ctx, digest);+}++void sha384_init(sha384_ctx *ctx)+{+#ifndef UNROLL_LOOPS+    int i;+    for (i = 0; i < 8; i++) {+        ctx->h[i] = sha384_h0[i];+    }+#else+    ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1];+    ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3];+    ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5];+    ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7];+#endif /* !UNROLL_LOOPS */++    ctx->len = 0;+    ctx->tot_len = 0;+}++void sha384_update(sha384_ctx *ctx, const unsigned char *message,+                   unsigned int len)+{+    unsigned int block_nb;+    unsigned int new_len, rem_len, tmp_len;+    const unsigned char *shifted_message;++    tmp_len = SHA384_BLOCK_SIZE - ctx->len;+    rem_len = len < tmp_len ? len : tmp_len;++    memcpy(&ctx->block[ctx->len], message, rem_len);++    if (ctx->len + len < SHA384_BLOCK_SIZE) {+        ctx->len += len;+        return;+    }++    new_len = len - rem_len;+    block_nb = new_len / SHA384_BLOCK_SIZE;++    shifted_message = message + rem_len;++    sha512_transf(ctx, ctx->block, 1);+    sha512_transf(ctx, shifted_message, block_nb);++    rem_len = new_len % SHA384_BLOCK_SIZE;++    memcpy(ctx->block, &shifted_message[block_nb << 7],+           rem_len);++    ctx->len = rem_len;+    ctx->tot_len += (block_nb + 1) << 7;+}++void sha384_final(sha384_ctx *ctx, unsigned char *digest)+{+    unsigned int block_nb;+    unsigned int pm_len;+    unsigned int len_b;++#ifndef UNROLL_LOOPS+    int i;+#endif++    block_nb = (1 + ((SHA384_BLOCK_SIZE - 17)+                     < (ctx->len % SHA384_BLOCK_SIZE)));++    len_b = (ctx->tot_len + ctx->len) << 3;+    pm_len = block_nb << 7;++    memset(ctx->block + ctx->len, 0, pm_len - ctx->len);+    ctx->block[ctx->len] = 0x80;+    UNPACK32(len_b, ctx->block + pm_len - 4);++    sha512_transf(ctx, ctx->block, block_nb);++#ifndef UNROLL_LOOPS+    for (i = 0 ; i < 6; i++) {+        UNPACK64(ctx->h[i], &digest[i << 3]);+    }+#else+    UNPACK64(ctx->h[0], &digest[ 0]);+    UNPACK64(ctx->h[1], &digest[ 8]);+    UNPACK64(ctx->h[2], &digest[16]);+    UNPACK64(ctx->h[3], &digest[24]);+    UNPACK64(ctx->h[4], &digest[32]);+    UNPACK64(ctx->h[5], &digest[40]);+#endif /* !UNROLL_LOOPS */+}++/* SHA-224 functions */++void sha224(const unsigned char *message, unsigned int len,+            unsigned char *digest)+{+    sha224_ctx ctx;++    sha224_init(&ctx);+    sha224_update(&ctx, message, len);+    sha224_final(&ctx, digest);+}++void sha224_init(sha224_ctx *ctx)+{+#ifndef UNROLL_LOOPS+    int i;+    for (i = 0; i < 8; i++) {+        ctx->h[i] = sha224_h0[i];+    }+#else+    ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1];+    ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3];+    ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5];+    ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7];+#endif /* !UNROLL_LOOPS */++    ctx->len = 0;+    ctx->tot_len = 0;+}++void sha224_update(sha224_ctx *ctx, const unsigned char *message,+                   unsigned int len)+{+    unsigned int block_nb;+    unsigned int new_len, rem_len, tmp_len;+    const unsigned char *shifted_message;++    tmp_len = SHA224_BLOCK_SIZE - ctx->len;+    rem_len = len < tmp_len ? len : tmp_len;++    memcpy(&ctx->block[ctx->len], message, rem_len);++    if (ctx->len + len < SHA224_BLOCK_SIZE) {+        ctx->len += len;+        return;+    }++    new_len = len - rem_len;+    block_nb = new_len / SHA224_BLOCK_SIZE;++    shifted_message = message + rem_len;++    sha256_transf(ctx, ctx->block, 1);+    sha256_transf(ctx, shifted_message, block_nb);++    rem_len = new_len % SHA224_BLOCK_SIZE;++    memcpy(ctx->block, &shifted_message[block_nb << 6],+           rem_len);++    ctx->len = rem_len;+    ctx->tot_len += (block_nb + 1) << 6;+}++void sha224_final(sha224_ctx *ctx, unsigned char *digest)+{+    unsigned int block_nb;+    unsigned int pm_len;+    unsigned int len_b;++#ifndef UNROLL_LOOPS+    int i;+#endif++    block_nb = (1 + ((SHA224_BLOCK_SIZE - 9)+                     < (ctx->len % SHA224_BLOCK_SIZE)));++    len_b = (ctx->tot_len + ctx->len) << 3;+    pm_len = block_nb << 6;++    memset(ctx->block + ctx->len, 0, pm_len - ctx->len);+    ctx->block[ctx->len] = 0x80;+    UNPACK32(len_b, ctx->block + pm_len - 4);++    sha256_transf(ctx, ctx->block, block_nb);++#ifndef UNROLL_LOOPS+    for (i = 0 ; i < 7; i++) {+        UNPACK32(ctx->h[i], &digest[i << 2]);+    }+#else+   UNPACK32(ctx->h[0], &digest[ 0]);+   UNPACK32(ctx->h[1], &digest[ 4]);+   UNPACK32(ctx->h[2], &digest[ 8]);+   UNPACK32(ctx->h[3], &digest[12]);+   UNPACK32(ctx->h[4], &digest[16]);+   UNPACK32(ctx->h[5], &digest[20]);+   UNPACK32(ctx->h[6], &digest[24]);+#endif /* !UNROLL_LOOPS */+}++#ifdef TEST_VECTORS++/* FIPS 180-2 Validation tests */++#include <stdio.h>+#include <stdlib.h>++void test(const unsigned char *vector, unsigned char *digest,+          unsigned int digest_size)+{+    unsigned char output[2 * SHA512_DIGEST_SIZE + 1];+    int i;++    output[2 * digest_size] = '\0';++    for (i = 0; i < (int) digest_size ; i++) {+       sprintf((char *) output + 2 * i, "%02x", digest[i]);+    }++    printf("H: %s\n", output);+    if (strcmp((char *) vector, (char *) output)) {+        fprintf(stderr, "Test failed.\n");+        exit(EXIT_FAILURE);+    }+}++int main()+{+    static const unsigned char *vectors[4][3] =+    {   /* SHA-224 */+        {+        "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",+        "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525",+        "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67",+        },+        /* SHA-256 */+        {+        "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",+        "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",+        "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0",+        },+        /* SHA-384 */+        {+        "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed"+        "8086072ba1e7cc2358baeca134c825a7",+        "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712"+        "fcc7c71a557e2db966c3e9fa91746039",+        "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b"+        "07b8b3dc38ecc4ebae97ddd87f3d8985",+        },+        /* SHA-512 */+        {+        "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"+        "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",+        "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"+        "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909",+        "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+        "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"+        }+    };++    static const unsigned char message1[] = "abc";+    static const unsigned char message2a[] = "abcdbcdecdefdefgefghfghighijhi"+                                             "jkijkljklmklmnlmnomnopnopq";+    static const unsigned char message2b[] =+                                      "abcdefghbcdefghicdefghijdefghijkefghij"+                                      "klfghijklmghijklmnhijklmnoijklmnopjklm"+                                      "nopqklmnopqrlmnopqrsmnopqrstnopqrstu";+    unsigned char *message3;+    unsigned int message3_len  = 1000000;+    unsigned char digest[SHA512_DIGEST_SIZE];++    message3 = malloc(message3_len);+    if (message3 == NULL) {+        fprintf(stderr, "Can't allocate memory\n");+        return -1;+    }+    memset(message3, 'a', message3_len);++    printf("SHA-2 FIPS 180-2 Validation tests\n\n");+    printf("SHA-224 Test vectors\n");++    sha224(message1, strlen((char *) message1), digest);+    test(vectors[0][0], digest, SHA224_DIGEST_SIZE);+    sha224(message2a, strlen((char *) message2a), digest);+    test(vectors[0][1], digest, SHA224_DIGEST_SIZE);+    sha224(message3, message3_len, digest);+    test(vectors[0][2], digest, SHA224_DIGEST_SIZE);+    printf("\n");++    printf("SHA-256 Test vectors\n");++    sha256(message1, strlen((char *) message1), digest);+    test(vectors[1][0], digest, SHA256_DIGEST_SIZE);+    sha256(message2a, strlen((char *) message2a), digest);+    test(vectors[1][1], digest, SHA256_DIGEST_SIZE);+    sha256(message3, message3_len, digest);+    test(vectors[1][2], digest, SHA256_DIGEST_SIZE);+    printf("\n");++    printf("SHA-384 Test vectors\n");++    sha384(message1, strlen((char *) message1), digest);+    test(vectors[2][0], digest, SHA384_DIGEST_SIZE);+    sha384(message2b, strlen((char *) message2b), digest);+    test(vectors[2][1], digest, SHA384_DIGEST_SIZE);+    sha384(message3, message3_len, digest);+    test(vectors[2][2], digest, SHA384_DIGEST_SIZE);+    printf("\n");++    printf("SHA-512 Test vectors\n");++    sha512(message1, strlen((char *) message1), digest);+    test(vectors[3][0], digest, SHA512_DIGEST_SIZE);+    sha512(message2b, strlen((char *) message2b), digest);+    test(vectors[3][1], digest, SHA512_DIGEST_SIZE);+    sha512(message3, message3_len, digest);+    test(vectors[3][2], digest, SHA512_DIGEST_SIZE);+    printf("\n");++    printf("All tests passed.\n");++    return 0;+}++#endif /* TEST_VECTORS */+
+ src/Crypt/sha2.h view
@@ -0,0 +1,108 @@+/*+ * FIPS 180-2 SHA-224/256/384/512 implementation+ * Last update: 02/02/2007+ * Issue date:  04/30/2005+ *+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ *    notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ *    notice, this list of conditions and the following disclaimer in the+ *    documentation and/or other materials provided with the distribution.+ * 3. Neither the name of the project nor the names of its contributors+ *    may be used to endorse or promote products derived from this software+ *    without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ * SUCH DAMAGE.+ */++#ifndef SHA2_H+#define SHA2_H++#define SHA224_DIGEST_SIZE ( 224 / 8)+#define SHA256_DIGEST_SIZE ( 256 / 8)+#define SHA384_DIGEST_SIZE ( 384 / 8)+#define SHA512_DIGEST_SIZE ( 512 / 8)++#define SHA256_BLOCK_SIZE  ( 512 / 8)+#define SHA512_BLOCK_SIZE  (1024 / 8)+#define SHA384_BLOCK_SIZE  SHA512_BLOCK_SIZE+#define SHA224_BLOCK_SIZE  SHA256_BLOCK_SIZE++#ifndef SHA2_TYPES+#define SHA2_TYPES+typedef unsigned char uint8;+typedef unsigned int  uint32;+typedef unsigned long long uint64;+#endif++#ifdef __cplusplus+extern "C" {+#endif++typedef struct {+    unsigned int tot_len;+    unsigned int len;+    unsigned char block[2 * SHA256_BLOCK_SIZE];+    uint32 h[8];+} sha256_ctx;++typedef struct {+    unsigned int tot_len;+    unsigned int len;+    unsigned char block[2 * SHA512_BLOCK_SIZE];+    uint64 h[8];+} sha512_ctx;++typedef sha512_ctx sha384_ctx;+typedef sha256_ctx sha224_ctx;++void sha224_init(sha224_ctx *ctx);+void sha224_update(sha224_ctx *ctx, const unsigned char *message,+                   unsigned int len);+void sha224_final(sha224_ctx *ctx, unsigned char *digest);+void sha224(const unsigned char *message, unsigned int len,+            unsigned char *digest);++void sha256_init(sha256_ctx * ctx);+void sha256_update(sha256_ctx *ctx, const unsigned char *message,+                   unsigned int len);+void sha256_final(sha256_ctx *ctx, unsigned char *digest);+void sha256(const unsigned char *message, unsigned int len,+            unsigned char *digest);++void sha384_init(sha384_ctx *ctx);+void sha384_update(sha384_ctx *ctx, const unsigned char *message,+                   unsigned int len);+void sha384_final(sha384_ctx *ctx, unsigned char *digest);+void sha384(const unsigned char *message, unsigned int len,+            unsigned char *digest);++void sha512_init(sha512_ctx *ctx);+void sha512_update(sha512_ctx *ctx, const unsigned char *message,+                   unsigned int len);+void sha512_final(sha512_ctx *ctx, unsigned char *digest);+void sha512(const unsigned char *message, unsigned int len,+            unsigned char *digest);++#ifdef __cplusplus+}+#endif++#endif /* !SHA2_H */+
+ src/Darcs/ArgumentDefaults.lhs view
@@ -0,0 +1,151 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.ArgumentDefaults ( get_default_flag,+                        ) where+import Control.Monad (+               liftM,+             )+import Data.Maybe ( catMaybes )++import Darcs.Arguments+import Darcs.Repository.Prefs++get_default_flag :: String -> DarcsOption -> IO [DarcsFlag]+\end{code}++\paragraph{defaults}\label{defaults}++Default values for darcs commands can be configured on a per-repository+basis by editing (and possibly creating) the \verb!_darcs/prefs/defaults!+file.  Each line of this file has the following form:+\begin{verbatim}+COMMAND FLAG VALUE+\end{verbatim}+where \verb!COMMAND! is either the name of the command to which the default+applies, or \verb!ALL! to indicate that the default applies to all commands+accepting that flag.  The \verb!FLAG! term is the name of the long argument+option without the ``\verb!--!'', i.e.\ \verb!verbose! rather than+\verb!--verbose!.  Finally, the \verb!VALUE! option can be omitted if the+flag is one such as \verb!verbose! that doesn't involve a value.+If the value has spaces in it, use single quotes, not double quotes, to surround it. +Each line only takes one flag.  To set multiple defaults for the same+command (or for \verb!ALL! commands), use multiple lines.++Note that the use of \verb|ALL| easily can have unpredicted consequences,+especially if commands in newer versions of darcs accepts flags that they+didn't in previous versions. A command like \verb|obliterate| could be+devastating with the ``wrong'' flags (for example --all). Only use safe+flags with \verb|ALL|.++\begin{tabular}{ll}+{\tt \verb!~/.darcs/defaults!} & provides defaults for this user account \\+{\tt \verb!repo/_darcs/prefs/defaults!} & provides defaults for one project,\\+  & overrules changes per user \\+\end{tabular}++For example, if your system clock is bizarre, you could instruct darcs to+always ignore the file modification times by adding the following line to+your \verb!_darcs/prefs/defaults! file.  (Note that this would have to be+done for each repository!)+\begin{verbatim}+ALL ignore-times+\end{verbatim}++If you never want to run a test when recording to a particular repository+(but still want to do so when running+\verb'check' on that repository), and like to name+all your patches ``Stupid patch'', you could use the following:+\begin{verbatim}+record no-test+record patch-name Stupid patch+\end{verbatim}++If you would like a command to be run every time patches are recorded+in a particular repository (for example if you have one central+repository, that all developers contribute to), then you can set apply+to always run a command when apply is successful.  For example, if you+need to make sure that the files in the repository have the correct+access rights you might use the following.  There are two things+to note about using darcs this way:+\begin{itemize}+\item Without the second line you will get errors, because the sub+      process that runs apply cannot prompt interactively.+\item Whatever script is run by the post apply command should not be+      be added to the repository with \verb!darcs add!; doing so would+      allow people to modify that file and then run arbitrary scripts on+      your main repository, possibly damaging or violating security.+\end{itemize}+\begin{verbatim}+apply posthook chmod -R a+r *+apply run-posthook+\end{verbatim}++Similarly, if you need a command to run automatically before darcs+performs an action you can use a prehook.  Using prehooks it could be+possible to canonicalize line endings before recording patches.++There are some options which are meant specifically for use in+\verb!_darcs/prefs/defaults!. One of them is \verb!--disable!. As the name+suggests, this option will disable every command that got it as argument. So,+if you are afraid that you could damage your repositories by inadvertent use of+a command like amend-record, add the following line to+\verb!_darcs/prefs/defaults!:+\begin{verbatim}+amend-record disable+\end{verbatim}++Also, a global preferences file can be created with the name+\verb!.darcs/defaults! in your home directory. Options present there will+be added to the repository-specific preferences.+If they conflict with repository-specific options, the repository-specific+ones will take precedence.++\begin{code}+get_default_flag com flag = do+    repo_defs   <- default_content $ get_preflist "defaults"+    global_defs <- default_content $ get_global   "defaults"+    case get_flag_from repo_defs of+      [] -> return $ get_flag_from global_defs+      f  -> return $ f+  where+    get_flag_from defs =+        case gda com flag defs of+          [] -> gda "ALL" flag defs+          f  -> f++gda :: String -> DarcsOption -> [(String,String,String)] -> [DarcsFlag]+gda com opt all_defs = gda' $ filter (\ (c,_,_)-> c == com) all_defs+    where gda' defs = concatMap (choose_option opt) defs+          choose_option (DarcsNoArgOption _ fls c _) (_,f,_)+              | f `elem` fls = [c]+          choose_option (DarcsArgOption _ fls c _ _) (_,f,d)+              | f `elem` fls = [c d]+          choose_option (DarcsMultipleChoiceOption os) p =+              concatMap (\o -> choose_option o p) os+          choose_option _ _ = []++default_content :: IO [String] -> IO [(String,String,String)]+default_content = liftM (catMaybes . map (doline.words))+    where doline (c:a:r) = Just (c, drop_dashdash a, unwords r)+          doline _ = Nothing+          drop_dashdash ('-':'-':a) = a+          drop_dashdash a = a++\end{code}+
+ src/Darcs/Arguments.lhs view
@@ -0,0 +1,1271 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.Arguments ( DarcsFlag( .. ), isa, flagToString,+                         definePatches, defineChanges, fix_filepaths,+                        fix_flag, fix_filepath, unfix_filepaths,+                        getRepoPath, getRepoPaths, rejectNonRepo, areFileArgs,+                        DarcsOption( .. ), option_from_darcsoption,+                        help, list_options, list_files,+                        help_on_match,+                        any_verbosity, disable, restrict_paths,+                        notest, test, working_repo_dir,+                        remote_repo, get_remote_repo,+                        leave_test_dir,+                        possibly_remote_repo_dir, get_repodir, get_repourl,+                        list_registered_files, list_unregistered_files,+                        author, get_author, get_easy_author, get_sendmail_cmd,+                        patchname_option, distname_option,+                        logfile, rmlogfile, from_opt, subject, get_subject,+                        target, cc, get_cc, output, output_auto_name,+                        recursive, inventory_choices, get_inventory_choices,+                        askdeps, ignoretimes, lookforadds,+                        ask_long_comment, sendmail_cmd,+                        sign, verify, edit_description,+                        reponame, tagname, creatorhash,+                        apply_conflict_options, reply,+                        pull_conflict_options, use_external_merge,+                        no_deps, nocompress,+                        uncompress_nocompress, repo_combinator,+                        options_latex, reorder_patches,+                        noskip_boring, allow_caseonly,+                        applyas, human_readable,+                        changes_reverse, only_to_files,+                        changes_format, match_one_context, match_one_nontag,+                        send_to_context,+                        get_context,+                        pipe_interactive, all_interactive,+                        all_pipe_interactive,+                        summary, unified, tokens,+                        checkpoint, partial, partial_check,+                        diff_cmd_flag, diffflags, unidiff, xmloutput,+                        force_replace, dry_run, dry_run_noxml,+                        print_dry_run_message_and_exit, showFriendly,+                        match_one, match_several, match_range,+                        match_several_or_range, happy_forwarding,+                        match_several_or_last,+                        set_default,+                        fancy_move_add, pristine_tree,+                        set_scripts_executable,+                        sibling, flagsToSiblings, relink, relink_pristine, nolinks,+                        files, directories, pending,+                        posthook_cmd, posthook_prompt,+                        get_posthook_cmd, +                        prehook_cmd, prehook_prompt,+                        get_prehook_cmd, nullFlag,+                        ssh_cm, umask_option,+                        store_in_memory,+                        patch_select_flag+                      ) where+import System.Console.GetOpt+import System.Directory ( doesDirectoryExist )+import Data.List ( (\\), nub )+import Data.Maybe ( listToMaybe )+import System.Exit ( ExitCode(ExitFailure, ExitSuccess), exitWith )+import Data.Maybe ( catMaybes )+import Control.Monad ( liftM, when, unless )+import Data.Char ( isDigit )+#ifndef WIN32+import Printer ( renderString )+import System.Posix.Env ( setEnv )+import Darcs.Patch ( list_touched_files )+import Darcs.Progress ( beginTedious, endTedious, tediousSize, finishedOneIO )+#endif++import Darcs.Hopefully ( PatchInfoAnd, info )+import Darcs.Patch ( RepoPatch, Patchy, showNicely, description )+import Darcs.Patch.Info ( to_xml )+import Darcs.Patch.Ordered ( FL, mapFL )+import qualified Darcs.Patch ( summary )+import Darcs.Utils ( askUser, maybeGetEnv, firstNotBlank, firstJustIO )+import Darcs.Repository.Prefs ( boring_file_filter, get_preflist, get_global )+import Darcs.URL ( is_url )+import Darcs.FilePathUtils ( DarcsPath(RepoDP)+                           , darcsPath, unfixedDarcsPath+                           , repoPath , unfixedRepoPath+                           , make_absolute, drop_paths )+import Darcs.RepoPath ( AbsolutePath, SubPath, toPath, toFilePath )+import Darcs.Patch.MatchData ( patch_match )+import Darcs.Flags ( DarcsFlag(..) )+import Darcs.Repository ( slurp_pending, withRepository, ($-) )+import Darcs.Repository.HashedRepo ( slurp_all_but_darcs )+import Darcs.SlurpDirectory ( list_slurpy )+import Darcs.Global ( darcsdir )+import Printer ( Doc, putDocLn, text, vsep, ($$), vcat )+\end{code}++\begin{code}+get_content :: DarcsFlag -> Maybe String+get_content (SignAs s) = Just s+get_content (SignSSL s) = Just s+get_content (Toks s) = Just s+get_content (Target s) = Just s+get_content (Output s) = Just s+get_content (Author s) = Just s+get_content (SendmailCmd s) = Just s+get_content (PatchName s) = Just s+get_content (DistName s) = Just s+get_content (Verify s) = Just s+get_content (VerifySSL s) = Just s+get_content (ApplyAs s) = Just s+get_content (TagName s) = Just s+get_content (DiffFlags s) = Just s+get_content (ExternalMerge s) = Just s+get_content (RepoDir s) = Just s+get_content (WorkDir s) = Just s+get_content (PosthookCmd s) = Just s+get_content (PrehookCmd s)  = Just s+get_content _ = Nothing++isa :: DarcsFlag -> (String -> DarcsFlag) -> Bool+a `isa` b = case get_content a of+            Nothing -> False+            Just s -> a == b s++data DarcsOption+    = DarcsArgOption [Char] [String] (String->DarcsFlag) String String+    | DarcsNoArgOption [Char] [String] DarcsFlag String+    | DarcsMultipleChoiceOption [DarcsOption]+option_from_darcsoption :: DarcsOption -> [OptDescr DarcsFlag]+option_from_darcsoption (DarcsNoArgOption a b c h)+    = [Option a b (NoArg c) h]+option_from_darcsoption (DarcsArgOption a b c n h)+    = [Option a b (ReqArg c n) h]+option_from_darcsoption (DarcsMultipleChoiceOption os)+    = concat $ map option_from_darcsoption os++concat_options :: [DarcsOption] -> DarcsOption+concat_options os = DarcsMultipleChoiceOption $ concatMap from_option os+ where+  from_option (DarcsMultipleChoiceOption xs) = xs+  from_option x = [x]+\end{code}++\begin{code}+extract_fix_path :: [DarcsFlag] -> Maybe (AbsolutePath, FilePath)+extract_fix_path [] = Nothing+extract_fix_path ((FixFilePath repo fix):_)  = Just (repo, fix)+extract_fix_path (_:fs) = extract_fix_path fs++fix_filepaths :: [DarcsFlag] -> [String] -> [DarcsPath]+fix_filepaths opts args =+  let fix = case extract_fix_path opts of+            Nothing    -> map unfixedDarcsPath+            Just (r,f) -> map (darcsPath r f)+  in nub $ fix $ filter (not.null) args++fix_flag :: AbsolutePath -> DarcsFlag -> DarcsFlag+fix_flag fix (Sibling s) = Sibling $ toFilePath $ make_absolute fix s+fix_flag _ (Output "-") = Output $ "-"+fix_flag fix (Output s) = Output $ toFilePath $ make_absolute fix s+fix_flag fix (Verify s) = Verify $ toFilePath $ make_absolute fix s+fix_flag fix (LogFile s) = LogFile $ toFilePath $ make_absolute fix s+fix_flag fix (VerifySSL s) = VerifySSL $ toFilePath $ make_absolute fix s+fix_flag _ (Context "") = Context ""+fix_flag fix (Context s) = Context $ toFilePath $ make_absolute fix s+fix_flag _ f = f++fix_filepath :: [DarcsFlag] -> FilePath -> DarcsPath+fix_filepath fs f =+  case extract_fix_path fs of+  Nothing -> unfixedDarcsPath f+  Just (repo,fix) -> darcsPath repo fix f++unfix_filepaths :: [DarcsFlag] -> [FilePath] -> [FilePath]+unfix_filepaths flags f =+  case extract_fix_path flags of+  Nothing  -> f+  Just (_,fix) -> drop_paths fix f++getRepoPaths :: [DarcsFlag] -> [FilePath] -> IO [SubPath]+getRepoPaths flags fs =+ do let (good, bad) = partitionEither $ map fixit $ filter (not.null) fs+    unless (null bad) $+      putStrLn $ "Ignoring non-repository paths: " ++ unwords bad+    return $ nub good+ where+    fixit p = maybe (Left p) Right $+                case extract_fix_path flags of+                Nothing -> unfixedRepoPath p+                Just (r,fx) -> repoPath r fx p++partitionEither :: [Either a b] -> ([b],[a])+partitionEither es = ( [b | Right b <- es]+                     , [a | Left  a <- es] )++rejectNonRepo :: [DarcsPath] -> IO [SubPath]+rejectNonRepo dps =+  case filter nonRepoDP dps of+   [] -> return $ getRepoPath dps+   xs -> do putStrLn $ "Doing nothing."+                     ++ "These files are not relative to the repository: "+                     ++ unwords (map toPath xs)+            exitWith (ExitFailure 1)++nonRepoDP :: DarcsPath -> Bool+nonRepoDP (RepoDP _) = False+nonRepoDP _ = True++getRepoPath :: [DarcsPath] -> [SubPath]+getRepoPath [] = []+getRepoPath (RepoDP r : ds) = r : getRepoPath ds+getRepoPath (_ : ds) = getRepoPath ds++-- as opposed to just '.'+areFileArgs :: [SubPath] -> Bool+areFileArgs rps = concatMap toFilePath rps /= ""+\end{code}++\begin{code}+list_options :: DarcsOption+list_options = DarcsNoArgOption [] ["list-options"] ListOptions+               "simply list the command's arguments"++flagToString :: [DarcsOption] -> DarcsFlag -> Maybe String+flagToString x f = maybeHead $ catMaybes $ map f2o x+    where f2o (DarcsArgOption _ (s:_) c _ _) = do arg <- get_content f+                                                  if c arg == f+                                                      then return $ unwords [('-':'-':s), arg]+                                                      else Nothing+          f2o (DarcsNoArgOption _ (s:_) f' _) | f == f' = Just ('-':'-':s)+          f2o (DarcsMultipleChoiceOption xs) = maybeHead $ catMaybes $ map f2o xs+          f2o _ = Nothing+          maybeHead (a:_) = Just a+          maybeHead [] = Nothing++reponame :: DarcsOption+tagname :: DarcsOption+no_deps :: DarcsOption+checkpoint :: DarcsOption+partial :: DarcsOption+partial_check :: DarcsOption+tokens :: DarcsOption+working_repo_dir :: DarcsOption+possibly_remote_repo_dir :: DarcsOption+disable :: DarcsOption+restrict_paths :: DarcsOption++pipe_interactive, all_pipe_interactive, all_interactive, all_patches, interactive, pipe,+  human_readable, diffflags, allow_caseonly, noskip_boring,+  ask_long_comment, match_one_nontag, changes_reverse, creatorhash,+  changes_format, match_one_context, happy_forwarding, send_to_context,+  diff_cmd_flag, store_in_memory, use_external_merge,+  pull_conflict_options, target, cc, apply_conflict_options, reply, xmloutput,+  distname_option, patchname_option, edit_description,+  output, output_auto_name, unidiff, repo_combinator,+  unified, summary, uncompress_nocompress, subject,+  nocompress, match_several_or_range, match_several_or_last,+  author, askdeps, lookforadds, ignoretimes, test, notest, help, force_replace,+  help_on_match,+  match_one, match_range, match_several, fancy_move_add, sendmail_cmd,+  logfile, rmlogfile, leave_test_dir, from_opt, set_default, pristine_tree++      :: DarcsOption++recursive :: String -> DarcsOption++sign, applyas, verify :: DarcsOption+\end{code}++\section{Common options to darcs commands}++\begin{options}+--help+\end{options}+Every \verb|COMMAND| accepts \verb!--help! as an argument, which tells it to+provide a bit of help.  Among other things, this help always provides an+accurate listing of the options available with that command, and is+guaranteed never to be out of sync with the version of darcs you actually+have installed (unlike this manual, which could be for an entirely+different version of darcs).+\begin{verbatim}+% darcs COMMAND --help+\end{verbatim}+\begin{code}+help = DarcsNoArgOption ['h'] ["help"] Help+       "shows brief description of command and its arguments"++help_on_match = DarcsNoArgOption [] ["match"] HelpOnMatch+       "shows a summary of how to use patch matching rules"+\end{code}++\begin{options}+--disable+\end{options}+Every {\tt COMMAND} accepts the \verb!--disable! option, which can be used in+\verb!_darcs/prefs/defaults! to disable some commands in the repository. This+can be helpful if you want to protect the repository from accidental use of+advanced commands like obliterate, unpull, unrecord or amend-record.+\begin{code}+disable = DarcsNoArgOption [] ["disable"] Disable+        "disable this command"+\end{code}++\begin{options}+--verbose, --quiet, --normal-verbosity+\end{options}+Most commands also accept the \verb!--verbose! option, which tells darcs to+provide additional output.  The amount of verbosity varies from command to+command.  Commands that accept \verb!--verbose\verb! also accept \verb!--quiet\verb!,+which surpresses non-error output, and \verb!--normal-verbosity\verb! which can be+used to restore the default verbosity if \verb!--verbose! or \verb!--quiet! is in+the defaults file.++\begin{options}+--debug+\end{options}+Many commands also accept the \verb!--debug! option, which causes darcs to generate+additional output that may be useful for debugging its behavior, but which otherwise+would not be interesting.+\begin{code}+any_verbosity :: [DarcsOption]+any_verbosity =[DarcsMultipleChoiceOption+                [DarcsNoArgOption [] ["debug"] Debug+                 "give only debug output",+                 DarcsNoArgOption [] ["debug-verbose"] DebugVerbose+                 "give debug and verbose output",+                 DarcsNoArgOption ['v'] ["verbose"] Verbose+                 "give verbose output",+                 DarcsNoArgOption ['q'] ["quiet"] Quiet+                 "suppress informational output",+                 DarcsNoArgOption [] ["standard-verbosity"] NormalVerbosity+                 "neither verbose nor quiet output"],+                 DarcsNoArgOption [] ["timings"] Timings "provide debugging timings information"]+\end{code}++\begin{options}+--repodir+\end{options}+Another common option is the \verb!--repodir! option, which allows you to+specify the directory of the repository in which to perform the command.+This option is used with commands, such as whatsnew, that ordinarily would+be performed within a repository directory, and allows you to use those+commands without actually being in the repository directory when calling the+command.  This is useful when running darcs in a pipe, as might be the case+when running \verb'apply' from a mailer.++\begin{code}+working_repo_dir = DarcsArgOption [] ["repodir"] WorkDir "DIRECTORY"+             "specify the repository directory in which to run"+possibly_remote_repo_dir = DarcsArgOption [] ["repo"] RepoDir "URL"+             "specify the repository URL"+get_repodir :: [DarcsFlag] -> String+get_repodir [] = "."+get_repodir (WorkDir r:_) = r+get_repodir (RepoDir r:_) = r+get_repodir (_:fs) = get_repodir fs++get_repourl :: [DarcsFlag] -> Maybe String+get_repourl [] = Nothing+get_repourl (RepoDir d:_) | is_url d = Just d+get_repourl (_:fs) = get_repourl fs+\end{code}++\begin{options}+--remote-repo+\end{options}++Some commands, such as \verb'pull' require a remote repository to be specified,+either from the command line or as a default.  The \verb!--remote-repo!+provides an alternative way to supply this remote repository path.  This flag+can be seen as temporarily ``replacing'' the default repository. Setting it+causes the command to ignore the default repository (it also does not affect,+i.e. overwrite the default repository).  On the other hand, if any other+repositories are supplied as command line arguments, this flag will be ignored+(and the default repository may be overwritten).++\begin{code}+remote_repo :: DarcsOption+remote_repo = DarcsArgOption [] ["remote-repo"] RemoteRepo "URL"+             "specify the remote repository URL to work with"++get_remote_repo :: [DarcsFlag] -> Maybe String+get_remote_repo (RemoteRepo r : _) = Just r+get_remote_repo (_:fs) = get_remote_repo fs+get_remote_repo [] = Nothing+\end{code}++\input{Darcs/Match.lhs}+\input{Darcs/Patch/Match.lhs}++\begin{code}+patchname_option = DarcsArgOption ['m'] ["patch-name"] PatchName "PATCHNAME"+                   "name of patch"++send_to_context = DarcsArgOption [] ["context"] Context "FILENAME"+                  "send to context stored in FILENAME"++match_one_context =+    DarcsMultipleChoiceOption+    [DarcsArgOption [] ["to-match"] mp "PATTERN"+     "select changes up to a patch matching PATTERN",+     DarcsArgOption [] ["to-patch"] OnePatch "REGEXP"+     "select changes up to a patch matching REGEXP",+     __tag,+     DarcsArgOption [] ["context"] Context "FILENAME"+     "version specified by the context in FILENAME"+    ]+    where mp s = OnePattern (patch_match s)++match_one = concat_options [__match, __patch, __tag]+match_one_nontag = concat_options [__match, __patch]+match_several    = concat_options [__matches, __patches, __tags]+match_range            = concat_options [match_to, match_from, __match, __patch, __last]+match_several_or_range = concat_options [match_to, match_from, __last, __matches, __patches, __tags]+match_several_or_last  = concat_options [match_from, __last, __matches, __patches, __tags]++match_to, match_from :: DarcsOption+match_to = DarcsMultipleChoiceOption+            [DarcsArgOption [] ["to-match"] uptop "PATTERN"+             "select changes up to a patch matching PATTERN",+             DarcsArgOption [] ["to-patch"] UpToPatch "REGEXP"+             "select changes up to a patch matching REGEXP",+             DarcsArgOption [] ["to-tag"] UpToTag "REGEXP"+             "select changes up to a tag matching REGEXP"]+    where uptop s = UpToPattern (patch_match s)+match_from = DarcsMultipleChoiceOption+              [DarcsArgOption [] ["from-match"] fromp "PATTERN"+               "select changes starting with a patch matching PATTERN",+               DarcsArgOption [] ["from-patch"] AfterPatch "REGEXP"+               "select changes starting with a patch matching REGEXP",+               DarcsArgOption [] ["from-tag"] AfterTag "REGEXP"+               "select changes starting with a tag matching REGEXP"]+    where fromp s = AfterPattern (patch_match s)++__tag, __tags, __patch, __patches, __match, __matches, __last :: DarcsOption++__tag = DarcsArgOption ['t'] ["tag"] OneTag "REGEXP"+       "select tag matching REGEXP"+__tags = DarcsArgOption ['t'] ["tags"] OneTag "REGEXP"+        "select tags matching REGEXP"++__patch = DarcsArgOption ['p'] ["patch"] OnePatch "REGEXP"+         "select a single patch matching REGEXP"+__patches = DarcsArgOption ['p'] ["patches"] SeveralPatch "REGEXP"+           "select patches matching REGEXP"++__match = DarcsArgOption [] ["match"] mp "PATTERN"+         "select a single patch matching PATTERN"+  where mp s = OnePattern (patch_match s)+__matches = DarcsArgOption [] ["matches"] mp "PATTERN"+           "select patches matching PATTERN"+  where mp s = SeveralPattern (patch_match s)++__last = DarcsArgOption [] ["last"] lastn "NUMBER"+         "select the last NUMBER patches"+    where lastn s = if and (map isDigit s)+                    then LastN (read s)+                    else LastN (-1)++get_context :: [DarcsFlag] -> Maybe FilePath+get_context xs = listToMaybe [ c | Context c <- xs ]+\end{code}++\begin{code}+notest = DarcsMultipleChoiceOption+         [DarcsNoArgOption [] ["no-test"] NoTest "don't run the test script",+          DarcsNoArgOption [] ["test"] Test "run the test script"]+test = DarcsMultipleChoiceOption+          [DarcsNoArgOption [] ["test"] Test "run the test script",+           DarcsNoArgOption [] ["no-test"] NoTest "don't run the test script"]+leave_test_dir = DarcsMultipleChoiceOption+                 [DarcsNoArgOption [] ["leave-test-directory"]+                  LeaveTestDir "don't remove the test directory",+                  DarcsNoArgOption [] ["remove-test-directory"]+                  NoLeaveTestDir "remove the test directory"]+\end{code}++\begin{options}+--ignore-times+\end{options}+Darcs optimizes its operations by keeping track of the modification times+of your files.  This dramatically speeds up commands such as+\verb!whatsnew! and \verb!record! which would otherwise require reading+every file in the repository and comparing it with a reference version.  However,+there are times when this can cause problems, such as when running a series+of darcs commands from a script, in which case often a file will be+modified twice in the same second, which can lead to the second+modification going unnoticed.  The solution to such predicaments is the+\verb!--ignore-times! option, which instructs darcs not to trust the file+modification times, but instead to check each file's contents explicitly.+\begin{code}+ignoretimes = DarcsNoArgOption [] ["ignore-times"] IgnoreTimes+              "don't trust the file modification times"+lookforadds =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption ['l'] ["look-for-adds"] LookForAdds+     "look for (non-boring) files that could be added",+     DarcsNoArgOption [] ["dont-look-for-adds"] NoLookForAdds+     "don't look for any files that could be added [DEFAULT]"]++fancy_move_add =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["date-trick"] FancyMoveAdd+     "add files with date appended to avoid conflict [EXPERIMENTAL] ",+     DarcsNoArgOption [] ["no-date-trick"] NoFancyMoveAdd+     "don't use experimental date appending trick [DEFAULT]"]++pristine_tree =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["plain-pristine-tree"] PristinePlain+     "use a plain pristine tree [DEFAULT]",+     DarcsNoArgOption [] ["no-pristine-tree"] PristineNone+     "use no pristine tree"]++\end{code}++\begin{code}+askdeps =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["ask-deps"] AskDeps+     "ask for extra dependencies",+     DarcsNoArgOption [] ["no-ask-deps"] NoAskDeps+     "don't ask for extra dependencies"]++ask_long_comment =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["edit-long-comment"] EditLongComment+     "edit the long comment by default",+     DarcsNoArgOption [] ["skip-long-comment"] NoEditLongComment+     "don't give a long comment",+     DarcsNoArgOption [] ["prompt-long-comment"] PromptLongComment+     "prompt for whether to edit the long comment"]+\end{code}++\begin{options}+--author+\end{options}+\label{env:DARCS_EMAIL}+Several commands need to be able to identify you.  Conventionally, you+provide an email address for this purpose, which can include comments,+e.g.\ \verb!David Roundy <droundy@abridgegame.org>!.  The easiest way to do+this is+to define an environment variable \verb!EMAIL! or \verb!DARCS_EMAIL! (with+the latter overriding the former).  You can also override this using the+\verb!--author! flag to any command.  Alternatively, you could set your+email address on a per-repository basis using the ``defaults'' mechanism+for ``ALL'' commands, as described in Appendix~\ref{repository_format}.+Or, you could specify the author on a per-repository basis using the+\verb!_darcs/prefs/author! file as described in section~\ref{author_prefs}.++Also, a global author file can be created in your home directory with the name+\verb!.darcs/author!.  This file overrides the+contents of the environment variables, but a repository-specific author+file overrides the global author file.++\begin{code}+logfile = DarcsArgOption [] ["logfile"] LogFile "FILE"+          "give patch name and comment in file"++rmlogfile = DarcsNoArgOption [] ["delete-logfile"] RmLogFile+            "delete the logfile when done"++author = DarcsArgOption ['A'] ["author"] Author "EMAIL" "specify author id"+from_opt = DarcsArgOption [] ["from"] Author "EMAIL" "specify email address"++get_author :: [DarcsFlag] -> IO String+get_author (Author a:_) = return a+get_author (Pipe:_) = do askUser "Who is the author? "+get_author (_:flags) = get_author flags+get_author [] = do+  easy_author <- get_easy_author+  case easy_author of+    Just a -> return a+    Nothing -> do+      aminrepo <- doesDirectoryExist (darcsdir++"/prefs")+      if aminrepo then do+          putStr "Darcs needs to know what name (conventionally an email "+          putStr "address) to use as the\npatch author, e.g. 'Fred Bloggs "+          putStr "<fred@bloggs.invalid>'.  If you provide one\nnow "+          putStr ("it will be stored in the file '"++darcsdir++"/prefs/author' and ")+          putStr "used as a default\nin the future.  To change your preferred "+          putStr "author address, simply delete or edit\nthis file.\n\n"+          add <- askUser "What is your email address? "+          writeFile (darcsdir++"/prefs/author") add+          return add+        else do askUser "What is your email address (e.g. John Doe <a@b.com>)? "++get_easy_author :: IO (Maybe String)+get_easy_author = firstJustIO [ get_preflist "author" >>= return . firstNotBlank,+                                get_global "author" >>= return .firstNotBlank,+                                maybeGetEnv "DARCS_EMAIL",+                                maybeGetEnv "EMAIL" ]+\end{code}++\begin{options}+--dont-compress, --compress+\end{options}+By default, darcs commands that write patches to disk will compress the+patch files.  If you don't want this, you can choose the+\verb!--dont-compress! option, which causes darcs not to compress the patch+file.++\begin{code}+nocompress = concat_options [__compress, __dont_compress]+uncompress_nocompress = concat_options [__compress, __dont_compress, __uncompress]++__compress, __dont_compress, __uncompress :: DarcsOption+__compress = DarcsNoArgOption [] ["compress"] Compress+            "create compressed patches"+__dont_compress = DarcsNoArgOption [] ["dont-compress"] NoCompress+                  "don't create compressed patches"+__uncompress = DarcsNoArgOption [] ["uncompress"] UnCompress+               "uncompress patches"+\end{code}++\begin{code}+summary = DarcsMultipleChoiceOption+          [DarcsNoArgOption ['s'] ["summary"] Summary "summarize changes",+           DarcsNoArgOption [] ["no-summary"] NoSummary "don't summarize changes"]+unified = DarcsNoArgOption ['u'] ["unified"] Unified+          "output patch in a darcs-specific format similar to diff -u"+unidiff = DarcsNoArgOption ['u'] ["unified"] Unified+          "pass -u option to diff"+diff_cmd_flag = DarcsArgOption [] ["diff-command"]+       DiffCmd "COMMAND" "specify diff command (ignores --diff-opts)"+store_in_memory = DarcsNoArgOption [] ["store-in-memory"] StoreInMemory+          "do patch application in memory rather than on disk"+\end{code}++\begin{code}+target = DarcsArgOption [] ["to"] Target "EMAIL" "specify destination email"+cc = DarcsArgOption [] ["cc"] Cc "EMAIL" "mail results to additional EMAIL(s). Requires --reply"+get_cc :: [DarcsFlag] -> String+get_cc fs = lt $ catMaybes $ map whatcc fs+            where whatcc (Cc t) = Just t+                  whatcc _ = Nothing+                  lt [t] = t+                  lt [t,""] = t+                  lt (t:ts) = t++" , "++lt ts+                  lt [] = ""+\end{code}++\begin{code}+subject = DarcsArgOption [] ["subject"] Subject "SUBJECT" "specify mail subject"+get_subject :: [DarcsFlag] -> Maybe String+get_subject (Subject s:_) = Just s+get_subject (_:fs) = get_subject fs+get_subject [] = Nothing+\end{code}++\begin{code}+output = DarcsArgOption ['o'] ["output"] Output "FILE"+         "specify output filename"+\end{code}++\begin{code}+output_auto_name = DarcsNoArgOption ['O'] ["output-auto-name"] OutputAutoName+         "output to automatically named file"+\end{code}++\begin{code}+edit_description =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["edit-description"] EditDescription+                          "edit the patch bundle description",+     DarcsNoArgOption [] ["dont-edit-description"] NoEditDescription+                      "don't edit the patch bundle description"]+\end{code}++\begin{code}+distname_option = DarcsArgOption ['d'] ["dist-name"] DistName "DISTNAME"+                  "name of version"+\end{code}++\begin{code}+recursive h+    = DarcsMultipleChoiceOption+      [DarcsNoArgOption ['r'] ["recursive"] Recursive h,+       DarcsNoArgOption [] ["not-recursive"] NoRecursive ("don't "++h)]+\end{code}++\begin{code}+inventory_choices :: DarcsOption+inventory_choices =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["hashed"] UseHashedInventory+                          "Some new features. Compatible with older repos",+     DarcsNoArgOption [] ["darcs-2"] UseFormat2+                          "All features. Related repos must use same format [EXPERIMENTAL]",+     DarcsNoArgOption [] ["old-fashioned-inventory"] UseOldFashionedInventory+                          "Minimal features. What older repos use. [DEFAULT]"]++get_inventory_choices :: DarcsOption+get_inventory_choices =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["hashed"] UseHashedInventory+                          "Convert darcs-1 format to hashed format",+     DarcsNoArgOption [] ["old-fashioned-inventory"] UseOldFashionedInventory+                          "Convert from hashed to darcs-1 format"]+\end{code}++\begin{code}+xmloutput = DarcsNoArgOption [] ["xml-output"] XMLOutput+        "generate XML formatted output"+\end{code}++\begin{code}+creatorhash = DarcsArgOption [] ["creator-hash"] CreatorHash "HASH"+              "specify hash of creator patch (see docs)"+\end{code}++\begin{code}+sign = DarcsMultipleChoiceOption+       [DarcsNoArgOption [] ["sign"] Sign+        "sign the patch with your gpg key",+        DarcsArgOption [] ["sign-as"] SignAs "KEYID"+        "sign the patch with a given keyid",+        DarcsArgOption [] ["sign-ssl"] SignSSL "IDFILE"+        "sign the patch using openssl with a given private key",+        DarcsNoArgOption [] ["dont-sign"] NoSign+        "don't sign the patch"]+applyas = DarcsMultipleChoiceOption+           [DarcsArgOption [] ["apply-as"] ApplyAs "USERNAME"+            "apply patch as another user using sudo",+            DarcsNoArgOption [] ["apply-as-myself"] NonApply+            "don't use sudo to apply as another user [DEFAULT]"]+happy_forwarding = DarcsNoArgOption [] ["happy-forwarding"] HappyForwarding+                   "forward unsigned messages without extra header"+set_default = DarcsMultipleChoiceOption+              [DarcsNoArgOption [] ["set-default"] SetDefault+               "set default repository [DEFAULT]",+               DarcsNoArgOption [] ["no-set-default"] NoSetDefault+               "don't set default repository"]+\end{code}++\begin{code}+verify = DarcsMultipleChoiceOption+         [DarcsArgOption [] ["verify"] Verify "PUBRING"+          "verify that the patch was signed by a key in PUBRING",+          DarcsArgOption [] ["verify-ssl"] VerifySSL "KEYS"+          "verify using openSSL with authorized keys from file KEYS",+          DarcsNoArgOption [] ["no-verify"] NonVerify+          "don't verify patch signature"]+\end{code}++\begin{code}+reponame = DarcsArgOption [] ["repo-name"] WorkDir "DIRECTORY"+           "path of output directory"+tagname = DarcsArgOption ['t'] ["tag"] TagName "TAGNAME"+          "name of version to checkpoint"+no_deps = DarcsNoArgOption [] ["no-deps"] DontGrabDeps+                       "don't automatically fulfill dependencies"+checkpoint = DarcsNoArgOption [] ["checkpoint"] CheckPoint+             "create a checkpoint file (see get --partial)"+tokens = DarcsArgOption [] ["token-chars"] Toks "\"[CHARS]\""+         "define token to contain these characters"++partial       = concat_options [__partial, __lazy, __ephemeral, __complete]+partial_check = concat_options [__complete, __partial]++__partial, __lazy, __ephemeral, __complete :: DarcsOption+__partial = DarcsNoArgOption [] ["partial"] Partial+            "get partial repository using checkpoint (old-fashioned format only)"+__lazy = DarcsNoArgOption [] ["lazy"] Lazy+              "get patch files only as needed"+__ephemeral = DarcsNoArgOption [] ["ephemeral"] Ephemeral+              "don't save patch files in the repository"+__complete = DarcsNoArgOption [] ["complete"] Complete+             "get a complete copy of the repository"+\end{code}++\begin{code}+force_replace = DarcsMultipleChoiceOption+                [DarcsNoArgOption ['f'] ["force"] ForceReplace+                 "proceed with replace even if 'new' token already exists",+                 DarcsNoArgOption [] ["no-force"]+                 NonForce "don't force the replace if it looks scary"]+\end{code}++\begin{code}+reply = DarcsArgOption [] ["reply"] Reply "FROM" "reply to email-based patch using FROM address"+apply_conflict_options+    = DarcsMultipleChoiceOption+      [DarcsNoArgOption [] ["mark-conflicts"]+       MarkConflicts "mark conflicts",+       DarcsNoArgOption [] ["allow-conflicts"]+       AllowConflicts "allow conflicts, but don't mark them",+       DarcsNoArgOption [] ["no-resolve-conflicts"] NoAllowConflicts+       "equivalent to --dont-allow-conflicts, for backwards compatibility",+       DarcsNoArgOption [] ["dont-allow-conflicts"]+       NoAllowConflicts "fail on patches that create conflicts [DEFAULT]"]+pull_conflict_options+    = DarcsMultipleChoiceOption+      [DarcsNoArgOption [] ["mark-conflicts"]+       MarkConflicts "mark conflicts [DEFAULT]",+       DarcsNoArgOption [] ["allow-conflicts"]+       AllowConflicts "allow conflicts, but don't mark them",+       DarcsNoArgOption [] ["dont-allow-conflicts"]+       NoAllowConflicts "fail on patches that create conflicts"]+use_external_merge = DarcsArgOption [] ["external-merge"]+                     ExternalMerge "COMMAND" "use external tool to merge conflicts"+\end{code}++\begin{options}+--dry-run+\end{options}+The \verb!--dry-run! option will cause darcs not to actually take the specified+action, but only print what would have happened.  Not all commands accept+\verb!--dry-run!, but those that do should accept the \verb!--summary!  option.++\begin{options}+--summary, --no-summary+\end{options}+The \verb!--summary! option shows a summary of the patches that would have been+pulled/pushed/whatever. The format is similar to the output format of+\verb!cvs update! and looks like this:++\begin{verbatim}+A  ./added_but_not_recorded.c+A! ./added_but_not_recorded_conflicts.c+a  ./would_be_added_if_look_for_adds_option_was_used.h++M  ./modified.t -1 +1+M! ./modified_conflicts.t -1 +1++R  ./removed_but_not_recorded.c+R! ./removed_but_not_recorded_conflicts.c++\end{verbatim}++You can probably guess what the flags mean from the clever file names.+\begin{description}+\item{\texttt{A}} is for files that have been added but not recorded yet.+\item{\texttt{a}} is for files found using the \verb!--look-for-adds! option available for+\verb!whatsnew! and \verb!record!. They have not been added yet, but would be+added automatically if \verb!--look-for-adds! were used with the next+\verb!record! command.++\item{\texttt{M}} is for files that have been modified in the working directory but not+recorded yet. The number of added and subtracted lines is also shown.++\item{\texttt{R}}  is for files that have been removed, but the removal is not+recorded yet.+\end{description}+An exclamation mark appears next to any option that has a conflict.++\begin{code}+-- NOTE: I'd rather work to have no uses of dry_run_noxml, so that any time+-- --dry-run is a possibility, automated users can examine the results more+-- easily with --xml.+dry_run_noxml :: DarcsOption+dry_run_noxml = DarcsNoArgOption [] ["dry-run"] DryRun+                "don't actually take the action"++dry_run :: [DarcsOption]+dry_run = [dry_run_noxml, xmloutput]++showFriendly :: Patchy p => [DarcsFlag] -> p C(x y) -> Doc+showFriendly opts p = if Verbose `elem` opts+                      then showNicely p+                      else if Summary `elem` opts+                           then Darcs.Patch.summary p+                           else description p++print_dry_run_message_and_exit :: RepoPatch p => String -> [DarcsFlag] -> FL (PatchInfoAnd p) -> IO ()+print_dry_run_message_and_exit action opts patches =+     do when (DryRun `elem` opts) $ do+          putInfo $ text $ "Would " ++ action ++ " the following changes:"+          putDocLn $ put_mode+          putInfo $ text $ ""+          putInfo $ text $ "Making no changes:  this is a dry run."+          exitWith ExitSuccess+        when (All `elem` opts && Summary `elem` opts) $ do+          putInfo $ text $ "Will " ++ action ++ " the following changes:"+          putDocLn $ put_mode+     where put_mode = if XMLOutput `elem` opts+                      then (text "<patches>" $$+                            vcat (mapFL (to_xml . info) patches) $$+                            text "</patches>")+                      else (vsep $ mapFL (showFriendly opts) patches)+           putInfo = if XMLOutput `elem` opts then \_ -> return () else putDocLn++\end{code}++\input{Darcs/Resolution.lhs}++\begin{code}+noskip_boring = DarcsNoArgOption [] ["boring"]+                Boring "don't skip boring files"+allow_caseonly = DarcsNoArgOption [] ["case-ok"]+                 AllowCaseOnly "don't refuse to add files differing only in case"+diffflags = DarcsArgOption [] ["diff-opts"]+            DiffFlags "OPTIONS" "options to pass to diff"+\end{code}++\begin{code}+changes_format = DarcsMultipleChoiceOption+                 [DarcsNoArgOption [] ["context"]+                  (Context "") "give output suitable for get --context",+                  xmloutput,+                  human_readable,+                  DarcsNoArgOption [] ["count"] Count "output count of changes"+                 ]+changes_reverse = DarcsNoArgOption [] ["reverse"] Reverse+                  "show changes in reverse order"++only_to_files :: DarcsOption+only_to_files = DarcsNoArgOption [] ["only-to-files"] OnlyChangesToFiles+                "show only changes to specified files"++human_readable = DarcsNoArgOption [] ["human-readable"]+                 HumanReadable "give human-readable output"+pipe = DarcsNoArgOption [] ["pipe"] Pipe "expect to receive input from a pipe"++interactive =+    DarcsNoArgOption ['i'] ["interactive"] Interactive+                         "prompt user interactively"+all_patches = DarcsNoArgOption ['a'] ["all"] All "answer yes to all patches"++all_interactive = DarcsMultipleChoiceOption [all_patches, interactive]++all_pipe_interactive+    = DarcsMultipleChoiceOption [all_patches,pipe,interactive]++pipe_interactive =+    DarcsMultipleChoiceOption [pipe, interactive]++repo_combinator =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["intersection"] Intersection+     "take intersection of all repositories",+     DarcsNoArgOption [] ["union"] Union+     "take union of all repositories [DEFAULT]",+     DarcsNoArgOption [] ["complement"] Complement+     "take complement of repositories (in order listed)"]+\end{code}++\begin{code}+list_files :: IO [String]+list_files = do s <- slurp_all_but_darcs "."+                skip_boring <- boring_file_filter+                return (skip_boring $ list_slurpy s)++list_unregistered_files :: IO [String]+list_unregistered_files = withRepository [] $- \repository ->+    do s <- slurp_all_but_darcs "."+       skip_boring <- boring_file_filter+       regs <- slurp_pending repository+       return $ (skip_boring $ list_slurpy s) \\ (list_slurpy regs)++list_registered_files :: IO [String]+list_registered_files =+    list_slurpy `liftM` (withRepository [] slurp_pending)+\end{code}++\begin{code}+options_latex :: [DarcsOption] -> String+options_latex opts = "\\begin{tabular}{lll}\n"+++                     unlines (map option_latex opts)+++                     "\\end{tabular}\n"++latex_help :: String -> String+latex_help h+    = "\\begin{minipage}{7cm}\n\\raggedright\n" ++ h ++ "\\end{minipage}\n"++option_latex :: DarcsOption -> String+option_latex (DarcsNoArgOption a b _ h) =+    show_short_options a ++ show_long_options b ++ latex_help h ++ "\\\\"+option_latex (DarcsArgOption a b _ arg h) =+    show_short_options a +++    show_long_options (map (++(" "++arg)) b) ++ latex_help h ++ "\\\\"+option_latex (DarcsMultipleChoiceOption os) =+    unlines (map option_latex os)++show_short_options :: [Char] -> String+show_short_options [] = "&"+show_short_options [c] = "\\verb!-"++[c]++"! &"+show_short_options (c:cs) = "\\verb!-"++[c]++"!,"++show_short_options cs++show_long_options :: [String] -> String+show_long_options [] = " &"+show_long_options [s] = "\\verb!--" ++ s ++ "! &"+show_long_options (s:ss)+    = "\\verb!--" ++ s ++ "!,"++ show_long_options ss++set_scripts_executable :: DarcsOption+set_scripts_executable = DarcsMultipleChoiceOption+                              [DarcsNoArgOption [] ["set-scripts-executable"] SetScriptsExecutable+                               "make scripts executable",+                               DarcsNoArgOption [] ["dont-set-scripts-executable"] DontSetScriptsExecutable+                               "don't make scripts executable"]++\end{code}++\begin{code}+relink, relink_pristine, sibling :: DarcsOption+relink = DarcsNoArgOption [] ["relink"] Relink+         "relink random internal data to a sibling"++relink_pristine = DarcsNoArgOption [] ["relink-pristine"] RelinkPristine+                  "relink pristine tree (not recommended)"++sibling = DarcsArgOption [] ["sibling"] Sibling "URL"+          "specify a sibling directory"++flagsToSiblings :: [DarcsFlag] -> [String]+flagsToSiblings ((Sibling s) : l) = s : (flagsToSiblings l)+flagsToSiblings (_ : l) = flagsToSiblings l+flagsToSiblings [] = []+\end{code}++\begin{code}+nolinks :: DarcsOption+nolinks = DarcsNoArgOption [] ["nolinks"] NoLinks+          "do not link repository or pristine to sibling"+\end{code}++\begin{code}+reorder_patches :: DarcsOption+reorder_patches = DarcsNoArgOption [] ["reorder-patches"] Reorder+                  "reorder the patches in the repository"+\end{code}++\begin{code}+sendmail_cmd = DarcsArgOption [] ["sendmail-command"] SendmailCmd "COMMAND" "specify sendmail command"++get_sendmail_cmd :: [DarcsFlag] -> String+get_sendmail_cmd (SendmailCmd a:_) = a+get_sendmail_cmd (_:flags) = get_sendmail_cmd flags+get_sendmail_cmd [] = ""+\end{code}++\begin{code}+files :: DarcsOption+files = DarcsMultipleChoiceOption+        [DarcsNoArgOption [] ["files"] Files+         "include files in output [DEFAULT]",+         DarcsNoArgOption [] ["no-files"] NoFiles+         "don't include files in output"]++directories :: DarcsOption+directories = DarcsMultipleChoiceOption+              [DarcsNoArgOption [] ["directories"] Directories+               "include directories in output [DEFAULT]",+               DarcsNoArgOption [] ["no-directories"] NoDirectories+               "don't include directories in output"]++pending :: DarcsOption+pending = DarcsMultipleChoiceOption+              [DarcsNoArgOption [] ["pending"] Pending+               "reflect pending patches in output [DEFAULT]",+               DarcsNoArgOption [] ["no-pending"] NoPending+               "only included recorded patches in output"]++nullFlag :: DarcsOption        -- "null" is already taken+nullFlag = DarcsNoArgOption ['0'] ["null"] NullFlag+       "separate file names by NUL characters"+\end{code}+\begin{options}+--posthook=COMMAND, --no-posthook+\end{options}+To provide a command that should be run whenever a darcs command completes+successfully, use \verb!--posthook! to specify the command.  This is useful+for people who want to have a command run whenever a patch is applied.  Using+\verb!--no-posthook! will disable running the command.  +\begin{options}+--prompt-posthook, --run-posthook+\end{options}+These options control prompting before running the posthook.  Use+\verb!--prompt-posthook! to force prompting before running the+posthook command.  For security reasons, this is the default.  When+defining a posthook for apply, you will need to use+\verb!--run-posthook! or else you will get an error, because the+subprocess which runs the apply command cannot prompt the user.++Some darcs commands export to the posthook command information about the+changes being made.  In particular, three environment variables are defined.+\verb!DARCS_PATCHES! contains a human-readable summary of the patches being+acted upon. The format is the same as "darcs changes".  \verb!DARCS_PATCHES_XML!+Contains the same details, in the same XML format as "darcs changes". Finally,+\verb!DARCS_FILES! contains a list of the files affected, one file per line.+If your repository has filenames including newlines, you'll just have to+cope.  Note, however, that \emph{none} of these environment variables are+defined when running under windows.  Note also that we refuse to pass+environment variables greater in size than 10k, in order to avoid triggering+\verb!E2BIG! errors.++\begin{code}+definePatches :: RepoPatch p => FL (PatchInfoAnd p) -> IO ()+#ifndef WIN32+definePatches ps = do let k = "Defining environment variables"+                      beginTedious k+                      tediousSize k 3+                      finishedOneIO k "DARCS_PATCHES"+                      setEnvCautiously "DARCS_PATCHES" (renderString $ Darcs.Patch.summary ps)+                      finishedOneIO k "DARCS_PATCHES_XML"+                      setEnvCautiously "DARCS_PATCHES_XML"+                                 (renderString $ text "<patches>" $$+                                                 vcat (mapFL (to_xml . info) ps) $$+                                                 text "</patches>")+                      finishedOneIO k "DARCS_FILES"+                      setEnvCautiously "DARCS_FILES" (unlines$ list_touched_files ps)+                      endTedious k++setEnvCautiously :: String -> String -> IO ()+setEnvCautiously e v | toobig (10*1024) v = return ()+                     | otherwise = setEnv e v True+    where toobig :: Int -> [a] -> Bool+          toobig 0 _ = True+          toobig _ [] = False+          toobig n (_:xs) = toobig (n-1) xs+#else+definePatches _ = return ()+#endif++defineChanges :: Patchy p => p -> IO ()+#ifndef WIN32+defineChanges ps = setEnvCautiously "DARCS_FILES" (unlines $ list_touched_files ps)+#else+defineChanges _ = return ()+#endif++posthook_cmd :: DarcsOption+posthook_cmd = DarcsMultipleChoiceOption+               [DarcsArgOption [] ["posthook"] PosthookCmd +                "COMMAND" "specify command to run after this darcs command",+                DarcsNoArgOption [] ["no-posthook"] NoPosthook+                "don't run posthook command"]++posthook_prompt :: DarcsOption+posthook_prompt = DarcsMultipleChoiceOption+                  [DarcsNoArgOption [] ["prompt-posthook"] AskPosthook+                   "prompt before running posthook [DEFAULT]",+                   DarcsNoArgOption [] ["run-posthook"] RunPosthook+                   "run posthook command without prompting"]++get_posthook_cmd :: [DarcsFlag] -> Maybe String+get_posthook_cmd (PosthookCmd a:_) = Just a+get_posthook_cmd (_:flags) = get_posthook_cmd flags+get_posthook_cmd [] = Nothing+\end{code}+\begin{options}+--prehook=COMMAND, --no-prehook+\end{options}+To provide a command that should be run before a darcs command is executed,+ use \verb!--prehook! to specify the command.  An example use is+for people who want to have a command run whenever a patch is to be recorded, such as+translating line endings before recording patches.  Using+\verb!--no-prehook! will disable running the command.  +\begin{options}+--prompt-prehook, --run-prehook+\end{options}+These options control prompting before running the prehook.  Use+\verb!--prompt-prehook! to force prompting before running the+prehook command.  For security reasons, this is the default.+\begin{code}+prehook_cmd :: DarcsOption+prehook_cmd = DarcsMultipleChoiceOption+               [DarcsArgOption [] ["prehook"] PrehookCmd +                "COMMAND" "specify command to run before this darcs command",+                DarcsNoArgOption [] ["no-prehook"] NoPrehook+                "don't run prehook command"]++prehook_prompt :: DarcsOption+prehook_prompt = DarcsMultipleChoiceOption+                  [DarcsNoArgOption [] ["prompt-prehook"] AskPrehook+                   "prompt before running prehook [DEFAULT]",+                   DarcsNoArgOption [] ["run-prehook"] RunPrehook+                   "run prehook command without prompting"]++get_prehook_cmd :: [DarcsFlag] -> Maybe String+get_prehook_cmd (PrehookCmd a:_) = Just a+get_prehook_cmd (_:flags) = get_prehook_cmd flags+get_prehook_cmd [] = Nothing+\end{code}++\begin{options}+--ssh-cm, --no-ssh-cm+\end{options}++For commands which invoke ssh, darcs will normally multiplex ssh+sessions over a single connection as long as your version of ssh has+the ControlMaster feature from OpenSSH versions 3.9 and above.  This+option will avoid darcs trying to use this feature even if your ssh+supports it.+\begin{code}+ssh_cm :: DarcsOption+ssh_cm = DarcsMultipleChoiceOption+         [DarcsNoArgOption [] ["no-ssh-cm"] NoSSHControlMaster+                  "don't use SSH ControlMaster feature [DEFAULT]",+          DarcsNoArgOption [] ["ssh-cm"] SSHControlMaster+                  "use SSH ControlMaster feature"]+\end{code}+\begin{options}+--umask+\end{options}+By default, Darcs will use your current umask.  The option+\verb|--umask| will cause Darcs to switch to a different umask before+writing to the repository.++\begin{code}+umask_option :: DarcsOption+umask_option =+    DarcsArgOption [] ["umask"] UMask "UMASK"+        "specify umask to use when writing"+\end{code}++\begin{options}+--dont-restrict-paths, --restrict-paths+\end{options}+By default darcs is only allowed to manage and modify files and directories+contained inside the current repository and not being part of any darcs+repository's meta data (including the current one). This is mainly for+security, to protect you from spoofed patches modifying arbitrary files+with sensitive data---say, in your home directory---or tempering with any+repository's meta data to switch off this safety guard.++But sometimes you may want to manage a group of ``sub'' repositories'+preference files with a global repository, or use darcs in some other+advanced way. The best way is probably to put+\verb!ALL dont-restrict-paths! in \verb!_darcs/prefs/defaults!. This turns+off all sanity checking for file paths in patches.++Path checking can be temporarily turned on with \verb!--restrict-paths! on+the command line, when pulling or applying unknown patches.++\begin{code}+restrict_paths =+    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["restrict-paths"] RestrictPaths+     "don't allow darcs to touch external files or repo metadata",+     DarcsNoArgOption [] ["dont-restrict-paths"] DontRestrictPaths+     "allow darcs to modify any file or directory (unsafe)"]+\end{code}++\begin{code}+patch_select_flag :: DarcsFlag -> Bool+patch_select_flag All = True+patch_select_flag (PatchName _) = True+patch_select_flag (OnePatch _) = True+patch_select_flag (SeveralPatch _) = True+patch_select_flag (AfterPatch _) = True+patch_select_flag (UpToPatch _) = True+patch_select_flag (TagName _) = True+patch_select_flag (LastN _) = True+patch_select_flag (OneTag _) = True+patch_select_flag (AfterTag _) = True+patch_select_flag (UpToTag _) = True+patch_select_flag (OnePattern _) = True+patch_select_flag (SeveralPattern _) = True+patch_select_flag (AfterPattern _) = True+patch_select_flag (UpToPattern _) = True+patch_select_flag _ = False+\end{code}
+ src/Darcs/Bug.lhs view
@@ -0,0 +1,51 @@+% Reporting bugs in darcs.  See also impossible.h.++\begin{code}+module Darcs.Bug ( _bug, _bugDoc,+                  _bugLoc, _impossible, _fromJust, _withBugLoc,+                 ) where++import System.IO.Unsafe ( unsafePerformIO )+import Text.Regex ( matchRegex, mkRegex )++import HTTP ( fetchUrl )+import Autoconf( darcs_version )+import Printer ( Doc, errorDoc, text, ($$), (<+>) )+\end{code}++\begin{code}+_bug :: BugStuff -> String -> a+_bug bs s = _bugDoc bs (text s)++_bugDoc :: BugStuff -> Doc -> a+_bugDoc bs s = errorDoc $ text "bug in darcs!" $$ s <+> text ("at "++_bugLoc bs) $$+               unsafePerformIO ((mkms . lines) `fmap` (fetchUrl "http://darcs.net/maintenance"+                                                       `catch` \_ -> return ""))+    where mkms [] = text "I'm unable to check http://darcs.net/maintenance to see if this version is supported."+                    $$ text "If it is is supported, please report this to bugs@darcs.net"+                    $$ text "If possible include the output of 'darcs --exact-version'."+          mkms (a:b:r) = case matchRegex (mkRegex a) darcs_version of+                         Nothing -> mkms r+                         Just _ -> case reads b of+                                   [(m,"")] -> text m+                                   _ -> mkms r+          mkms [_] = mkms []+\end{code}++\begin{code}+type BugStuff = (String, Int, String, String)++_bugLoc :: BugStuff -> String+_bugLoc (file, line, date, time) = file++":"++show line++" compiled "++time++" "++date++_impossible :: BugStuff -> a+_impossible bs = _bug bs $ "Impossible case"++_bugLoc bs++_fromJust :: BugStuff -> Maybe a -> a+_fromJust bs mx =+  case mx of Nothing -> _bug bs $ "fromJust error"++_bugLoc bs+             Just x  -> x++_withBugLoc :: BugStuff -> IO a -> IO a+_withBugLoc bs job = job `catch` \err -> error $ _bugLoc bs++"\n"++show err+\end{code}
+ src/Darcs/CheckFileSystem.lhs view
@@ -0,0 +1,62 @@+%  Copyright (C) 2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+module Darcs.CheckFileSystem ( can_I_use_mmap ) where++import System.Directory ( removeFile, removeDirectory, setCurrentDirectory,+                          createDirectory,+                        )+import Control.Exception ( block )++import Darcs.Utils ( withCurrentDirectory )+import Darcs.Lock ( withOpenTemp )++-- Beware that the below test will return true in any directory where we+-- don't have write permission.  This is risky, but means we'll do the+-- right thing in the common case where we're dealing with posix+-- filesystems and directories in which we don't have permission to write.++can_I_remove_open_files :: IO Bool+can_I_remove_open_files = block $ +   (withOpenTemp $ \ (_,f) ->+       (do { removeFile f; return True}) `catch` \_ -> return False)+   `catch` \_ -> return True++can_I_remove_directories_holding_open_files :: IO Bool+can_I_remove_directories_holding_open_files = block $+   (do createDirectory "darcs_testing_for_nfs"+       okay <- (withCurrentDirectory "darcs_testing_for_nfs" $+                do withOpenTemp $ \ (_,f) -> +                       (do removeFile f+                           setCurrentDirectory ".."+                           removeDirectory "darcs_testing_for_nfs"+                           return True+                       ) `catch` \_ -> return False+               ) `catch` \_ -> return True+       removeDirectory "darcs_testing_for_nfs" `catch` \_ -> return ()+       return okay+   ) `catch` \_ -> return True++can_I_use_mmap :: IO Bool+can_I_use_mmap = do a <- can_I_remove_open_files+                    if a then can_I_remove_directories_holding_open_files+                         else return False+\end{code}++
+ src/Darcs/ColorPrinter.lhs view
@@ -0,0 +1,255 @@+\begin{code}+{-# OPTIONS -fno-warn-orphans #-}+module Darcs.ColorPrinter ( errorDoc, traceDoc, assertDoc, fancyPrinters ) where++import Debug.Trace ( trace )+import System.IO ( stderr )+import Darcs.External (getTermNColors)+import Printer (Printer, Printers, Printers'(..), Printable(..), Color(..),+                invisiblePrinter, (<>), (<?>), Doc(Doc,unDoc), unsafeBothText, simplePrinter, hcat,+                unsafeText, unsafeChar, space, unsafePackedString,+                renderStringWith, prefix )+import Data.Char ( isAscii, isPrint, isSpace, isControl, ord, chr, intToDigit )+import Data.Bits ( bit, xor )+import System.Environment ( getEnv )+import FastPackedString ( unpackPS, anyPS, lastPS, initPS,+                          nullPS, spanEndPS )+import System.IO.Unsafe ( unsafePerformIO )+import System.IO ( hIsTerminalDevice, Handle )++dollar, cr :: Doc+dollar = unsafeBothText "$"+cr     = unsafeBothText "\r"++errorDoc :: Doc -> a+errorDoc = error . show++traceDoc :: Doc -> a -> a+traceDoc d = trace (show d)++assertDoc :: Maybe Doc -> a -> a+assertDoc Nothing x = x+assertDoc (Just e) _ = errorDoc e++instance Show Doc where+    show = renderStringWith (fancyPrinters stderr)++-- policy++data Policy = Policy { poColor,    -- overall use of color+                       poEscape,   -- overall use of escaping+                       poLineColor,-- overall use of colored lines (only hunks for now)+                       poAltColor, -- alternative to color (bold, inverse)+                       poIsprint,  -- don't escape isprints+                       po8bit      -- don't escape 8-bit chars+                        :: Bool,+                       poNoEscX,   -- extra chars to never escape+                       poEscX      -- extra chars to always escape+                        :: String,+                       poTrailing, -- escape trailing spaces+                       poCR,       -- ignore \r at end of lines++                       poSpace         -- escape spaces (used with poTrailing)+                        :: Bool+                     }++{-# NOINLINE getPolicy #-}+getPolicy :: Handle -> Policy+getPolicy handle = unsafePerformIO $+ do isTerminal <- hIsTerminalDevice handle+    nColors <- if isTerminal then getTermNColors else return 0++    envDontEscapeAnything  <- getEnvBool "DARCS_DONT_ESCAPE_ANYTHING"+    envDontEscapeIsprint   <- getEnvBool "DARCS_DONT_ESCAPE_ISPRINT"+    envUseIsprint          <- getEnvBool "DARCS_USE_ISPRINT" -- for backwards-compatibility+    envDontEscape8bit      <- getEnvBool "DARCS_DONT_ESCAPE_8BIT"++    envDontEscapeExtra  <- getEnvString "DARCS_DONT_ESCAPE_EXTRA"+    envEscapeExtra      <- getEnvString "DARCS_ESCAPE_EXTRA"++    envDontEscapeTrailingSpace  <- getEnvBool "DARCS_DONT_ESCAPE_TRAILING_SPACES"+    envDontEscapeTrailingCR     <- getEnvBool "DARCS_DONT_ESCAPE_TRAILING_CR"++    envDontColor         <- getEnvBool "DARCS_DONT_COLOR"+    envAlwaysColor       <- getEnvBool "DARCS_ALWAYS_COLOR"+    envAlternativeColor  <- getEnvBool "DARCS_ALTERNATIVE_COLOR"+    envDoColorLines    <- getEnvBool "DARCS_DO_COLOR_LINES"++    let haveColor = envAlwaysColor || (isTerminal && (nColors > 4))+        doColor   = not envDontColor && haveColor++    return Policy { poColor    = doColor,+                    poEscape   = not envDontEscapeAnything,+                    poLineColor= doColor && envDoColorLines,+                    poIsprint  = envDontEscapeIsprint || envUseIsprint,+                    po8bit     = envDontEscape8bit,+                    poNoEscX   = envDontEscapeExtra,+                    poEscX     = envEscapeExtra,+                    poTrailing = not envDontEscapeTrailingSpace,+                    poCR       = envDontEscapeTrailingCR,+                    poAltColor = haveColor && envAlternativeColor,++                    poSpace = False+                  }+ where+  getEnvBool s = safeGetEnv s >>= return.(/= "0")+  safeGetEnv s = getEnv s `catch` \_ -> return "0"+  getEnvString s = getEnv s `catch` \_ -> return ""+++-- printers++fancyPrinters :: Printers+fancyPrinters h = Printers { colorP     = colorPrinter (getPolicy h),+                             invisibleP = invisiblePrinter,+                             hiddenP = colorPrinter (getPolicy h) Green,+                             userchunkP  = userchunkPrinter (getPolicy h),+                             defP       = escapePrinter (getPolicy h),+                             lineColorT = lineColorTrans (getPolicy h),+                             lineColorS = lineColorSuffix (getPolicy h)+                           }++lineColorTrans :: Policy -> Color -> Doc -> Doc+lineColorTrans po | poLineColor po = \c d -> prefix (set_color c) d <?> unsafeBothText reset_color+                  | otherwise      = const id++lineColorSuffix :: Policy -> [Printable] -> [Printable]+lineColorSuffix po | poLineColor po = \d -> S reset_color : d+                   | otherwise      = id++colorPrinter :: Policy -> Color -> Printer+colorPrinter po | poColor po = \c -> unDoc . color po c . Doc . escapePrinter po{poColor=False}+                | otherwise  = const $ escapePrinter po++userchunkPrinter :: Policy -> Printer+userchunkPrinter po p+ | not (poEscape po)   = simplePrinter p+ | not (poTrailing po) = escapePrinter po p+ | otherwise           = unDoc $ pr p+ where+  pr (S s)       = prString s+  pr (Both _ ps) = prPS ps+  pr (PS ps)     = prPS ps++  prPS ps = let (leadPS, trailPS) = spanEndPS isSpace ps+            in if nullPS trailPS+                then Doc $ escapePrinter po p+                else Doc (escapePrinter po (PS leadPS))+                  <> Doc (escapePrinter po{poSpace=True} (PS trailPS))+                  <> mark_escape po dollar++  prString s = let (trail',lead') = span isSpace (reverse s)+                   lead = reverse lead'+                   trail = reverse trail'+               in if (not.null) trail+                   then Doc (escapePrinter po (S lead))+                     <> Doc (escapePrinter po{poSpace=True} (S trail))+                     <> mark_escape po dollar+                   else Doc (escapePrinter po p)++escapePrinter :: Policy -> Printer+escapePrinter po+ | (not.poEscape) po = simplePrinter+ | otherwise         = unDoc . crepr+ where+  crepr p | poCR po && isEndCR p = epr (initPR p) <> cr+          | otherwise            = epr p++  epr (S s)      = escape po s+  epr (PS ps)    = if anyPS (not.no_escape po) ps+                   then escape po (unpackPS ps)+                   else unsafePackedString ps+  epr (Both s _) = escape po s++  isEndCR (S s)        = not (null s) && last s == '\r'+  isEndCR (PS ps)      = not (nullPS ps) && lastPS ps == '\r'+  isEndCR (Both _ ps)  = not (nullPS ps) && lastPS ps == '\r'++  initPR (S s)       = S $ init s+  initPR (PS ps)     = PS $ initPS ps+  initPR (Both s ps) = Both (init s) (initPS ps)+++-- escape assumes the input is in ['\0'..'\255']++escape :: Policy -> String -> Doc+escape _ "" = unsafeText ""+escape po s = hcat (map escapeChar s)+ where+  escapeChar c | no_escape po c = unsafeChar c+  escapeChar ' ' = space+  escapeChar c = (emph.unsafeText.quoteChar) c+  emph = mark_escape po++no_escape :: Policy -> Char -> Bool+no_escape po c | poSpace po && isSpace c = False+no_escape po c | c `elem` poEscX po = False+no_escape po c | c `elem` poNoEscX po = True+no_escape _ '\t' = True  -- tabs will likely be converted to spaces+no_escape _ '\n' = True+no_escape po c = if (poIsprint po) then isPrint c+                                   else isPrintableAscii c+                 ||  c >= '\x80' && po8bit po++isPrintableAscii :: Char -> Bool+isPrintableAscii c = isAscii c && isPrint c+++-- quote++quoteChar :: Char -> String+quoteChar c+ | isControl c && isPrintableAscii cHat = ['^', cHat]+ | otherwise = sHex+ where+  cHat = chr $ (bit 6 `xor`) $ ord c+  sHex = let (q, r) = quotRem (ord c) 16+         in ['\\', intToDigit q, intToDigit r]+++-- make colors and highlightings++mark_escape :: Policy -> Doc -> Doc+mark_escape po | poAltColor po  = make_invert+               | poColor po     = make_color Red+               | otherwise      = make_asciiart++color :: Policy -> Color -> Doc -> Doc+color po | poAltColor po = \_ -> make_bold+         | otherwise     = make_color++make_color, make_color' :: Color -> Doc -> Doc++make_color' = with_color . set_color++-- memoized version of make_color'+make_color Blue    = make_color' Blue+make_color Red     = make_color' Red+make_color Green   = make_color' Green+make_color Cyan    = make_color' Cyan+make_color Magenta = make_color' Magenta++set_color :: Color -> String+set_color Blue    = "\x1B[01;34m" -- bold blue+set_color Red     = "\x1B[01;31m" -- bold red+set_color Green   = "\x1B[01;32m" -- bold green+set_color Cyan    = "\x1B[36m"    -- light cyan+set_color Magenta = "\x1B[35m"    -- light magenta++make_asciiart :: Doc -> Doc+make_asciiart x = unsafeBothText "[_" <> x <> unsafeBothText "_]"++reset_color :: String+reset_color = "\x1B[00m"++with_color :: String -> Doc -> Doc+with_color c =+   let c' = unsafeBothText c+       r' = unsafeBothText reset_color+   in \x -> c' <> x <> r'++make_bold, make_invert :: Doc -> Doc+make_bold   = with_color "\x1B[01m"+make_invert = with_color "\x1B[07m"++\end{code}
+ src/Darcs/Commands.lhs view
@@ -0,0 +1,504 @@+%  Copyright (C) 2002,2003,2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.Commands ( CommandControl( Command_data, Hidden_command, Group_name ),+                       DarcsCommand( DarcsCommand, command_name,+                                     command_help, command_description,+                                     command_basic_options, command_advanced_options,+                                     command_command,+                                     command_prereq,+                                     command_extra_arg_help,+                                     command_extra_args,+                                     command_argdefaults,+                                     command_get_arg_possibilities,+                                     SuperCommand,+                                     command_sub_commands ),+                       command_alias, command_stub,+                       disambiguate_commands, CommandArgs(..),+                       get_command_help, +                       usage, extended_usage, extract_commands,+                       run_the_command, command_options, nodefaults,+                       loggers,+                     ) where+import System.Console.GetOpt+import Control.Monad ( when, unless )+import Data.List ( sort, isPrefixOf )+import Control.Exception ( throwIO, Exception ( ExitException ) )+import System.Exit ( ExitCode ( ExitSuccess ), exitWith )+import Darcs.Test ( run_posthook, run_prehook )+import Darcs.Global ( setTimingsMode, setDebugMode, setVerboseMode,+                      setSshControlMasterDisabled )+import Darcs.Progress ( setProgressMode )+import Workaround ( getCurrentDirectory )++import Darcs.SignalHandler ( catchNonSignal )+import Darcs.Arguments+import Darcs.External ( viewDoc )+import Darcs.RepoPath ( mkAbsolutePath )+import Darcs.Utils ( formatPath, putStrLnError )+import Darcs.ArgumentDefaults ( get_default_flag )+import Darcs.Match ( checkMatchSyntax )+import Printer ( text, Doc, putDocLn )+\end{code}++The general format of a darcs command is+\begin{verbatim}+% darcs COMMAND OPTIONS ARGUMENTS ...+\end{verbatim}+Here \verb|COMMAND| is a command such as \verb|add| or \verb|record|, which of+course may have one or more arguments.  Options have the form+\verb!--option! or \verb!-o!, while arguments vary from command to+command.  There are many options which are common to a number of different+commands, which will be summarized here.++If you wish, you may use any unambiguous beginning of a command name as a+shortcut: for \verb!darcs record!, you could type \verb!darcs recor! or+\verb!darcs rec!, but not \verb!darcs re! since that could be confused with+\verb!darcs replace!, \verb!darcs revert! and \verb!darcs remove!.++In some cases, \verb|COMMAND| actually consists of two words, a+super-command and a subcommand.  For example, the ``display the+manifest'' command has the form \verb|darcs query manifest|.++\paragraph{Command overview}++Not all commands modify the ``patches'' of your repository (that+is, the named patches which other users can pull); some commands only+affect the copy of the source tree you're working on (your ``working+directory''), and some affect both. This table summarizes what you should+expect from each one and will hopefully serve as guide when you're having+doubts about which command to use.++\begin{center}+\footnotetext[1]{But it affects the repository and working directory targeted+  by the push}+\footnotetext[2]{As for the other end, see apply}+\begin{tabular}{|c|c|c|}+\hline+affects & patches & working directory\\+\hline+record & yes & no\\+\hline+unrecord & yes & no\\+\hline+rollback & yes & yes\\+\hline+revert & no & yes\\+\hline+unrevert & no & yes\\+\hline+pull & yes & yes\\+\hline+obliterate & yes & yes\\+\hline+apply & yes & yes\\+\hline+push\footnote{But it affects the repository and working directory targeted by+the push} & no & no\\+\hline+send\footnote{As for the other end, see apply} & no & no\\+\hline+put\footnote{Creates a new repository} & no & no\\+\hline+\end{tabular}+\end{center}++\begin{code}+extract_commands, extract_hidden_commands :: [CommandControl] -> [DarcsCommand]+extract_commands cs = concatMap (\x -> case x of { Command_data cmd_d -> [cmd_d]; _ -> []}) cs+extract_hidden_commands cs = concatMap (\x -> case x of { Hidden_command cmd_d -> [cmd_d]; _ -> []}) cs++run_the_command :: String -> [String] -> [CommandControl] -> IO ()+run_the_command cmd args cs =+  either fail rtc $ disambiguate_commands cs cmd args+ where+  rtc (CommandOnly c, as)       = run_command Nothing c  as+  rtc (SuperCommandOnly c,  as) = run_raw_supercommand c as+  rtc (SuperCommandSub c s, as) = run_command (Just c) s as+\end{code}++\input{Darcs/Arguments.lhs}++\begin{code}+data CommandControl = Command_data DarcsCommand+                    | Hidden_command DarcsCommand+                    | Group_name String++data DarcsCommand =+    DarcsCommand {command_name, command_help, command_description :: String,+                  command_extra_args :: Int,+                  command_extra_arg_help :: [String],+                  command_command :: [DarcsFlag] -> [String] -> IO (),+                  command_prereq :: [DarcsFlag] -> IO (Either String FilePath),+                  command_get_arg_possibilities :: IO [String],+                  command_argdefaults :: [DarcsFlag] -> FilePath -> [String] -> IO [String],+                  command_basic_options :: [DarcsOption],+                  command_advanced_options :: [DarcsOption]}+  | SuperCommand {command_name, command_help, command_description :: String,+                  command_prereq :: [DarcsFlag] -> IO (Either String FilePath),+                  command_sub_commands :: [CommandControl]}++command_alloptions :: DarcsCommand -> ([DarcsOption], [DarcsOption])+command_alloptions DarcsCommand { command_basic_options = opts1+                                , command_advanced_options = opts2 }+    = (opts1 ++ [disable, help],+       any_verbosity ++ opts2 +++                [posthook_cmd, posthook_prompt+                ,prehook_cmd, prehook_prompt])++--  Supercommands cannot be disabled.+command_alloptions SuperCommand { } = ([help],[])++--  Obtain options suitable as input to+--  System.Console.Getopt, including the --disable option (which is+--  not listed explicitly in the DarcsCommand definitions).+command_options :: DarcsCommand -> ([OptDescr DarcsFlag], [OptDescr DarcsFlag])+command_options c = (convert basic, convert advanced)+ where (basic, advanced) = command_alloptions c+       convert = concatMap option_from_darcsoption++nodefaults :: [DarcsFlag] -> FilePath -> [String] -> IO [String]+nodefaults _ _ xs = return xs++get_subcommands :: DarcsCommand -> [CommandControl]+get_subcommands c@(SuperCommand {}) = command_sub_commands c+get_subcommands _ = []++command_alias :: String -> DarcsCommand -> DarcsCommand+command_alias n c =+  c { command_name = n+    , command_help = desc ++ "\n" ++ command_help c+    , command_description = desc+    }+ where desc = "Alias for " ++ command_name c++command_stub :: String -> String -> String -> DarcsCommand -> DarcsCommand+command_stub n h d c =+  c { command_name = n+    , command_help = h+    , command_description = d+    , command_command = \_ _ -> putStr h+    }+\end{code}+++\begin{code}+extended_usage :: String+extended_usage = "Usage: darcs COMMAND ..."+    ++ "\n"+    ++ "\nExtended Help:"+    ++ "\n"+    ++ "\nA darcs repository consists of:"+    ++ "\n"+    ++ "\n  - a set of PATCHES"+    ++ "\n  - a WORKING directory"+    ++ "\n"+    ++ "\nHere is a description of which of these components is altered by each"+    ++ "\ncommand, and how it is used or altered:"+    ++ "\n"+    ++ "\n  whatsnew      Show the differences between WORKING and the \"recorded\""+    ++ "\n                version, that is, the result of applying all PATCHES in the"+    ++ "\n                repository.  This difference, we will call LOCAL CHANGES."+    ++ "\n"+    ++ "\n  record        Add a patch to PATCHES representing the LOCAL CHANGES."+    ++ "\n"+    ++ "\n  unrecord      Delete a patch from PATCHES, but *do not* alter WORKING."+    ++ "\n                This works for any patch, not just one that was previously "+    ++ "\n                \"record\"ed"+    ++ "\n"+    ++ "\n  revert        Remove LOCAL CHANGES.  Note that this command is interactive,"+    ++ "\n                so you can use it to revert only some of these changes."+    ++ "\n"+    ++ "\n  unrevert      Undo the last revert operation."+    ++ "\n"+    ++ "\n  obliterate    Delete a patch from PATCHES and unapply it from WORKING."+    ++ "\n                Note that this command works for any patch, not just one that"+    ++ "\n                was previously \"pull\"ed.  If there are no LOCAL CHANGES,"+    ++ "\n                this command is equivalent to \"darcs unrecord; darcs revert\""+    ++ "\n"+    ++ "\n  rollback      Create the new patch that inverts some changes from one or more"+    ++ "\n                patches.  These changes are also inverted in the working"+    ++ "\n                directory."+    ++ "\n"+\end{code}++\begin{code}+usage :: [CommandControl] -> String+usage cs = "Usage: darcs COMMAND ...\n\nCommands:\n" +++           usage_helper cs ++ "\n" +++           "Use 'darcs --overview' for more detailed help on basic commands.\n" +++           "Use 'darcs COMMAND --help' for help on a single command.\n" +++           "Use 'darcs --version' to see the darcs version number.\n" +++           "Use 'darcs --exact-version' to get the exact version of this darcs instance.\n\n" +++           "Check bug reports at http://bugs.darcs.net/\n"++subusage :: DarcsCommand -> String+subusage super =+    (usageInfo+     ("Usage: darcs "++command_name super++" SUBCOMMAND ... " +++      "\n\n"++ command_description super+++      "\n\nSubcommands:\n" ++ usage_helper (get_subcommands super) ++ "\nOptions:")+     (option_from_darcsoption help))+    ++ "\n" ++ command_help super++usage_helper :: [CommandControl] -> String+usage_helper [] = ""+usage_helper (Hidden_command _:cs) = usage_helper cs+usage_helper ((Command_data c):cs) = "  "++pad_spaces (command_name c) 15 +++                      chomp_newline (command_description c)++"\n"++usage_helper cs+usage_helper ((Group_name n):cs) = n ++ "\n" ++ usage_helper cs++chomp_newline :: String -> String+chomp_newline "" = ""+chomp_newline s = if last s == '\n' then init s else s++pad_spaces :: String -> Int -> String+pad_spaces s n = s ++ replicate (n - length s) ' '+\end{code}++\begin{comment}++This is the actual heavy lifter code, which is responsible for parsing the+arguments and then running the command itself.++\end{comment}+\begin{code}+run_command :: Maybe DarcsCommand -> DarcsCommand -> [String] -> IO ()++run_command _ _ args -- Check for "dangerous" typoes...+    | "-all" `elem` args = -- -all indicates --all --look-for-adds!+        fail $ "Are you sure you didn't mean -" ++ "-all rather than -all?"+run_command msuper cmd args =+    case getOpt Permute+             (option_from_darcsoption list_options++options) args of+    (opts,extra,[]) +      | Help `elem` opts -> viewDoc $ text $ get_command_help msuper cmd+      | ListOptions `elem` opts  -> do+           setProgressMode False+           maybe_fix <- command_prereq cmd opts+           repodir   <- mkAbsolutePath `fmap` getCurrentDirectory+           file_args <- case maybe_fix of+                          Right f -> unfix_filepaths [FixFilePath repodir f]+                                        `fmap` command_get_arg_possibilities cmd+                          Left _  -> return []+           putStrLn $ get_command_options cmd ++ unlines file_args+      | otherwise -> consider_running msuper cmd (addVerboseIfDebug opts) extra+    (_,_,ermsgs) -> do fail $ chomp_newline(unlines ermsgs)+    where options = opts1 ++ opts2+          (opts1, opts2) = command_options cmd+          addVerboseIfDebug opts | DebugVerbose `elem` opts = Debug:Verbose:opts+                                 | otherwise = opts++consider_running :: Maybe DarcsCommand -> DarcsCommand+                 -> [DarcsFlag] -> [String] -> IO ()+consider_running msuper cmd opts old_extra = do+ pwd <- mkAbsolutePath `fmap` getCurrentDirectory+ location <- command_prereq cmd opts+ case location of+   Left complaint -> fail $ "Unable to " +++                     formatPath ("darcs " ++ super_name msuper ++ command_name cmd) +++                     " here.\n\n" ++ complaint+   Right fix_path -> do+    specops <- add_command_defaults cmd $ map (fix_flag pwd) opts+    extra <- (command_argdefaults cmd) specops fix_path old_extra+    when (Disable `elem` specops) $+      fail $ "Command "++command_name cmd++" disabled with --disable option!"+    if command_extra_args cmd < 0+      then runWithHooks specops extra+      else if length extra > command_extra_args cmd+           then fail $ "Bad argument: `"++unwords extra++"'\n"+++                       get_command_mini_help msuper cmd+           else if length extra < command_extra_args cmd+                then fail $ "Missing argument:  " +++                            nth_arg (length extra + 1) +++                            "\n" ++ get_command_mini_help msuper cmd+                else runWithHooks specops extra+       where nth_arg n = nth_of n (command_extra_arg_help cmd)+             nth_of 1 (h:_) = h+             nth_of n (_:hs) = nth_of (n-1) hs+             nth_of _ [] = "UNDOCUMENTED"+             runWithHooks os ex = do+               here <- getCurrentDirectory+               checkMatchSyntax os+               -- set any global variables+               when (Timings `elem` os) setTimingsMode+               when (Debug `elem` os) setDebugMode+               when (Verbose `elem` os) setVerboseMode+               when (Quiet `elem` os) $ setProgressMode False+               unless (SSHControlMaster `elem` os) setSshControlMasterDisabled+               -- actually run the command and its hooks+               preHookExitCode <- run_prehook os here+               if preHookExitCode /= ExitSuccess+                  then exitWith preHookExitCode+                  else do let fixFlag = FixFilePath (mkAbsolutePath here) fix_path+                          (command_command cmd) (fixFlag : os) ex+                            `catchNonSignal` +                            (\e -> case e of +                                     ExitException ExitSuccess -> return ()+                                     _ -> throwIO e)+                          postHookExitCode <- run_posthook os here+                          --+                          exitWith postHookExitCode++add_command_defaults :: DarcsCommand -> [DarcsFlag] -> IO [DarcsFlag]+add_command_defaults cmd already =+    acd (command_name cmd) already (opts1 ++ opts2)+    where (opts1, opts2) = command_alloptions cmd++acd :: String -> [DarcsFlag] -> [DarcsOption] -> IO [DarcsFlag]+acd _ flags [] = return flags+acd c flags (dao:dos)+ = case dao of+   DarcsNoArgOption _ _ f _+       -> if f `elem` flags then acd c flags dos+                            else do flags' <- get_default_flag c dao+                                    acd c (flags++flags') dos+   DarcsArgOption _ _ f _ _+       -> if f `isin` flags then acd c flags dos+                            else do flags' <- get_default_flag c dao+                                    acd c (flags++flags') dos+   DarcsMultipleChoiceOption os+       -> if os `arein` flags then acd c flags dos+                              else do flags' <- get_default_flag c dao+                                      acd c (flags++flags') dos+ where f `isin` fs = any (`isa` f) fs+       (DarcsNoArgOption _ _ f _ : dos') `arein` fs+           = f `elem` fs || dos' `arein` fs+       (DarcsArgOption _ _ f _ _ : dos') `arein` fs+           = f `isin` fs || dos' `arein` fs+       (DarcsMultipleChoiceOption os: dos') `arein` fs+           = os `arein` fs || dos' `arein` fs+       [] `arein` _ = False++get_command_options :: DarcsCommand -> String+get_command_options cmd =+    (get_options_options $ opts1 ++ opts2)+    where (opts1, opts2) = command_options cmd++get_options_options :: [OptDescr DarcsFlag] -> String+get_options_options [] = ""+get_options_options (o:os) =+    get_long_option o ++"\n"++ get_options_options os++get_long_option :: OptDescr DarcsFlag -> String+get_long_option (Option _ [] _ _) = ""+get_long_option (Option a (o:os) b c) = "--"++o+++                 get_long_option (Option a os b c)++super_name :: Maybe DarcsCommand -> String+super_name Nothing  = ""+super_name (Just x) = command_name x ++ " "++get_command_mini_help :: Maybe DarcsCommand -> DarcsCommand -> String+get_command_mini_help msuper cmd =+  get_command_help_core msuper cmd +++  "\n\nSee darcs help "+  ++ (maybe "" (\c -> command_name c ++ " ") msuper)+  ++ command_name cmd ++ " for details."++get_command_help :: Maybe DarcsCommand -> DarcsCommand -> String+get_command_help msuper cmd =+    unlines (reverse basicR)+    ++ (if null advanced then ""+        else "\nAdvanced options:\n" ++ unlines (reverse advancedR))+    ++ "\n" ++ command_help cmd+    where -- we could just call usageInfo twice, but then the advanced+          -- options might not line up with the basic ones (no short flags)+          (advancedR, basicR) =+             splitAt (length advanced) $ reverse $ lines combinedUsage+          combinedUsage = usageInfo+            (get_command_help_core msuper cmd ++ subcommands ++ "\n\nOptions:")+            (basic ++ advanced)+          (basic, advanced) = command_options cmd+          subcommands =+            case msuper of+            Nothing -> case get_subcommands cmd of+                       [] -> []+                       s  -> "\n\nSubcommands:\n" ++ (usage_helper s)+            -- we don't want to list subcommands if we're already specifying them+            Just _  -> ""++get_command_help_core :: Maybe DarcsCommand -> DarcsCommand -> String+get_command_help_core msuper cmd =+    "Usage: darcs "++super_name msuper++command_name cmd+++    " [OPTION]... " ++ unwords args_help +++    "\n"++ command_description cmd+    where args_help = case cmd of+            (DarcsCommand _ _ _ _ _ _ _ _ _ _ _) ->+              command_extra_arg_help cmd+            _ -> []+\end{code}++\begin{code}+run_raw_supercommand :: DarcsCommand -> [String] -> IO ()+run_raw_supercommand super [] =+    fail $ "Command '"++ command_name super ++"' requires subcommand!\n\n"+             ++ subusage super+run_raw_supercommand super args =+    case getOpt RequireOrder+             (option_from_darcsoption help+++              option_from_darcsoption list_options) args of+    (opts,_,[]) +      | Help `elem` opts ->+            viewDoc $ text $ get_command_help Nothing super+      | ListOptions `elem` opts -> do +            putStrLn "--help"+            mapM_ (putStrLn . command_name) (extract_commands $ get_subcommands super)+      | otherwise -> +            if Disable `elem` opts+            then fail $ "Command " ++ (command_name super) +++                      " disabled with --disable option!"+            else fail $ "Invalid subcommand!\n\n" ++ subusage super+    (_,_,ermsgs) -> do fail $ chomp_newline(unlines ermsgs)+\end{code}++\begin{code}+data CommandArgs = CommandOnly      DarcsCommand+                 | SuperCommandOnly DarcsCommand+                 | SuperCommandSub  DarcsCommand DarcsCommand++-- Parses a darcs command line with potentially abbreviated commands+disambiguate_commands :: [CommandControl] -> String -> [String]+                      -> Either String (CommandArgs, [String])+disambiguate_commands allcs cmd args =+ do c <- extract cmd allcs+    case (get_subcommands c, args) of+      ([], _)         -> return (CommandOnly c, args)+      (_ ,[])         -> return (SuperCommandOnly c, args)+      (subcs, (a:as)) -> case extract a subcs of+                         Left _   -> return (SuperCommandOnly c, args)+                         Right sc -> return (SuperCommandSub c sc, as)++extract :: String -> [CommandControl] -> Either String DarcsCommand+extract cmd cs =+ case [ c | c <- extract_commands cs, cmd `isPrefixOf` command_name c ] +++      [ h | h <- extract_hidden_commands cs,    cmd == command_name h ] of+   []  -> Left $ "No such command '" ++ cmd ++ "'\n"+   [c] -> Right c+   cs' -> Left $ "Ambiguous command...\n\n" +++                    "The command '"++cmd++"' could mean one of:\n" +++                    unwords (sort $ map command_name cs')+\end{code}++\begin{code}+-- | Output functions equivalent to (putStrLn, hPutStrLn stderr, putDocLn)+loggers :: [DarcsFlag] -> ( String -> IO ()+                          , String -> IO ()+                          , Doc -> IO ())+loggers _ = (putStrLn, putStrLnError, putDocLn)+\end{code}
+ src/Darcs/Commands/Add.lhs view
@@ -0,0 +1,280 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs add}+\begin{code}+module Darcs.Commands.Add ( add ) where++import Data.List ( (\\), nub)++import Darcs.Commands+import Darcs.Arguments (noskip_boring, allow_caseonly,+                       fancy_move_add,+                       recursive, working_repo_dir, dry_run_noxml, umask_option,+                       list_files, list_unregistered_files,+                       DarcsFlag (AllowCaseOnly, Boring, Recursive,+                                  Verbose, Quiet, FancyMoveAdd, DryRun),+                        getRepoPaths,+                      )+import Darcs.Utils ( withCurrentDirectory, nubsort )+import IsoDate ( getIsoDateTime )+import Darcs.Repository ( amInRepository, withRepoLock, ($-),+                    slurp_pending, add_to_pending )+import Darcs.Patch ( Prim, apply_to_slurpy, addfile, adddir, move )+import Darcs.Patch.Ordered ( FL(..), unsafeFL, concatFL, nullFL )+import Darcs.SlurpDirectory ( Slurpy, slurp_has_anycase, slurp_has,+                        isFileReallySymlink, doesDirectoryReallyExist, +                        doesFileReallyExist, slurp_hasdir,+                      )+import FileName ( fp2fn )+import Darcs.FilePathUtils ( (///) )+import Darcs.RepoPath ( toFilePath )+import Control.Monad ( liftM, when )+import Darcs.Repository.Prefs ( darcsdir_filter, boring_file_filter )+import Data.Maybe ( maybeToList )+import System.IO ( hPutStrLn, stderr )+\end{code}++\begin{code}+add_description :: String+add_description =+ "Add one or more new files or directories."+\end{code}++\options{add}++\haskell{add_help}++\begin{code}+add_help :: String+add_help =+ "Add needs to be called whenever you add a new file or directory to your\n"+++ "project.  Of course, it also needs to be called when you first create the\n"+++ "project, to let darcs know which files should be kept track of.\n"+\end{code}++\begin{code}+add :: DarcsCommand+add = DarcsCommand {command_name = "add",+                    command_help = add_help,+                    command_description = add_description,+                    command_extra_args = -1,+                    command_extra_arg_help = ["<FILE or DIRECTORY> ..."],+                    command_command = add_cmd,+                    command_prereq = amInRepository,+                    command_get_arg_possibilities = list_unregistered_files,+                    command_argdefaults = nodefaults,+                    command_advanced_options = [umask_option],+                    command_basic_options =+                    [noskip_boring, allow_caseonly,+                     recursive "add contents of subdirectories",+                     fancy_move_add,+                     working_repo_dir, dry_run_noxml]}+\end{code}++Darcs will refuse to add a file or directory that differs from an existing+one only in case.  This is because the HFS+ file system used on MacOS+treats such files as being one and the same.++You can not add symbolic links to darcs.+If you try to do that, darcs will refuse and print an error message.+Perhaps you want to make symbolic links \emph{to} the files in darcs instead?++\begin{options}+--boring+\end{options}++By default darcs will ignore all files that match any of the boring patterns.+If you want to add such a file anyway you must use the \verb!--boring! option.++\begin{code}+add_cmd :: [DarcsFlag] -> [String] -> IO ()+add_cmd opts args = withRepoLock opts $- \repository ->+ do cur <- slurp_pending repository+    origfiles <- map toFilePath `fmap` getRepoPaths opts args+    parlist <- get_parents cur origfiles+    flist' <- if Recursive `elem` opts+              then expand_dirs origfiles+              else return origfiles+    let flist = nubsort (parlist ++ flist')+    -- refuse to add boring files recursively:+    nboring <- if Boring `elem` opts+               then return $ darcsdir_filter+               else boring_file_filter+    let putInfoLn = if Quiet `elem` opts then \_ -> return () else putStrLn+    sequence_ $ map (putInfoLn . ((msg_skipping msgs ++ " boring file ")++)) $+              flist \\ nboring flist+    date <- getIsoDateTime+    ps <- addp msgs opts date cur $ nboring flist+    when (nullFL ps && not (null args)) $ do+        fail "No files were added"+    when (not gotDryRun) $ add_to_pending repository ps+  where+    gotDryRun = DryRun `elem` opts+    msgs | gotDryRun = dryRunMessages+         | otherwise = normalMessages++addp :: AddMessages -> [DarcsFlag] -> String -> Slurpy -> [FilePath] -> IO (FL Prim)+addp msgs opts date cur0 files = do+    (ps, dups) <-+        foldr+            (\f rest cur accPS accDups -> do+                (cur', mp, mdup) <- addp' cur f+                rest cur' (maybeToList mp ++ accPS) (maybeToList mdup ++ accDups))+            (\_ ps dups -> return (reverse ps, dups))+            files+            cur0 [] []+    let uniq_dups = nub dups+        caseMsg =+            if gotAllowCaseOnly then ":"+                else ";\nnote that to ensure portability we don't allow\n" +++                     "files that differ only in case. Use --case-ok to override this:"+    when (not (null dups)) $ do+       dupMsg <-+         case uniq_dups of+         [f] ->+           do+           isDir <- doesDirectoryReallyExist f+           if isDir+               then return $+                 "The following directory "++msg_is msgs++" already in the repository"+               else return $+                 "The following file "++msg_is msgs++" already in the repository"+         fs   ->+           do+           areDirs <- mapM doesDirectoryReallyExist fs+           if and areDirs+               then return $+                 "The following directories "++msg_are msgs++" already in the repository"+               else+                 (if or areDirs+                      then return $+                        "The following files and directories " +++                        msg_are msgs ++ " already in the repository"+                      else return $+                        "The following files " ++ msg_are msgs ++ " already in the repository")+       putInfo $ dupMsg ++ caseMsg+       mapM_ putInfo uniq_dups+    return $ concatFL $ unsafeFL ps+ where+  addp' :: Slurpy -> FilePath -> IO (Slurpy, Maybe (FL Prim), Maybe FilePath)+  addp' cur f =+    if (if gotAllowCaseOnly+        then slurp_has f cur+        else slurp_has_anycase f cur)+    then do return (cur, Nothing, Just f)+    else do+      isdir <- doesDirectoryReallyExist f+      if isdir+         then trypatch $ myadddir f+         else do isfile <- doesFileReallyExist f+                 if isfile+                    then trypatch $ myaddfile f+                    else do islink <- isFileReallySymlink f+                            if islink then+                               putInfo $ "Sorry, file " ++ f ++ " is a symbolic link, which is unsupported by darcs."+                               else putInfo $ "File "++ f ++" does not exist!"+                            return (cur, Nothing, Nothing)+      where trypatch p =+                case apply_to_slurpy p cur of+                Nothing -> do putInfo $ msg_skipping msgs ++ " '" ++ f ++ "' ... " ++ parent_error+                              return (cur, Nothing, Nothing)+                Just s' -> do putVerbose $ msg_adding msgs++" '"++f++"'"+                              return (s', Just p, Nothing)+            parentdir = get_parentdir f+            have_parentdir = slurp_hasdir (fp2fn parentdir) cur+            parent_error = if have_parentdir+                           then ""+                           else "couldn't add parent directory '"++parentdir+++                                "' to repository."+            myadddir d = if gotFancyMoveAdd+                         then adddir (d++"-"++date) :>:+                              move (d++"-"++date) d :>: NilFL+                         else adddir d :>: NilFL+            myaddfile d = if gotFancyMoveAdd+                          then addfile (d++"-"++date) :>:+                               move (d++"-"++date) d :>: NilFL+                          else addfile d :>: NilFL++  putVerbose = if Verbose `elem` opts || DryRun `elem` opts+               then putStrLn+               else \_ -> return ()+  putInfo = if Quiet `elem` opts then \_ -> return () else hPutStrLn stderr+  gotFancyMoveAdd = FancyMoveAdd `elem` opts+  gotAllowCaseOnly = AllowCaseOnly `elem` opts++data AddMessages =+    AddMessages+    { msg_skipping  :: String+    , msg_adding    :: String+    , msg_is        :: String+    , msg_are       :: String+    }++normalMessages, dryRunMessages :: AddMessages+normalMessages =+    AddMessages+    { msg_skipping  = "Skipping"+    , msg_adding    = "Adding"+    , msg_is        = "is"+    , msg_are       = "are"+    }+dryRunMessages =+    AddMessages+    { msg_skipping  = "Would skip"+    , msg_adding    = "Would add"+    , msg_is        = "would be"+    , msg_are       = "would be"+    }+\end{code}++\begin{options}+--date-trick+\end{options}++The \verb!--date-trick! option allows you to enable an experimental trick+to make add conflicts, in which two users each add a file or directory with+the same name, less problematic.  While this trick is completely safe, it+is not clear to what extent it is beneficial.++\begin{code}+expand_dirs :: [FilePath] -> IO [FilePath]+expand_dirs fs = concat `liftM` mapM expand_one fs+expand_one :: FilePath -> IO [FilePath]+expand_one "" = list_files+expand_one f = do+  isdir <- doesDirectoryReallyExist f+  if not isdir then return [f]+     else do fs <- withCurrentDirectory f list_files+             return $ f: map ((///) f) fs++get_parents :: Slurpy -> [FilePath] -> IO [FilePath]+get_parents cur fs =+  concat `liftM` mapM (get_parent cur) fs+get_parent :: Slurpy -> FilePath -> IO [FilePath]+get_parent cur f =+  if slurp_hasdir (fp2fn parentdir) cur+  then return []+  else do grandparents <- get_parent cur parentdir+          return (grandparents ++ [parentdir])+    where parentdir = get_parentdir f++get_parentdir :: FilePath -> FilePath+get_parentdir f = reverse $ drop 1 $ dropWhile (/='/') $ reverse f++\end{code}+
+ src/Darcs/Commands/AmendRecord.lhs view
@@ -0,0 +1,195 @@+%  Copyright (C) 2004,2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs amend-record}+\begin{code}+module Darcs.Commands.AmendRecord ( amendrecord ) where+import Data.List ( sort )+import Data.Maybe ( isJust )+import System.Exit ( ExitCode(..), exitWith )+import Control.Monad ( when )++import Darcs.Flags ( DarcsFlag(Author, LogFile, PatchName,+                               EditLongComment, PromptLongComment) )+import Darcs.Lock ( world_readable_temp )+import Darcs.RepoPath ( toFilePath )+import Darcs.Hopefully ( PatchInfoAnd, n2pia, hopefully, info )+import Darcs.Repository ( withRepoLock, ($-), withGutsOf,+                    get_unrecorded, get_unrecorded_unsorted, slurp_recorded,+                    tentativelyRemovePatches, tentativelyAddPatch, finalizeRepositoryChanges,+                    sync_repo, amInRepository,+                  )+import Darcs.Patch ( RepoPatch, description, Prim, fromPrims,+                     infopatch, getdeps, adddeps, effect,+                     sort_coalesceFL,+                     canonize )+import Darcs.Patch.Info ( pi_author, pi_name, pi_log,+                          PatchInfo, patchinfo, is_inverted, invert_name,+                        )+import Darcs.Patch.Ordered ( FL(..), (:>)(..), (+>+),+                             nullFL, mapFL_FL, concatFL )+import Darcs.SelectChanges ( with_selected_changes_to_files',+                             with_selected_patch_from_repo )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Commands.Record ( get_date, get_log )+import Darcs.Arguments ( DarcsFlag ( Test, NoTest, All ),+                         areFileArgs, getRepoPaths, defineChanges,+                        all_interactive, ignoretimes,+                        ask_long_comment, author, patchname_option,+                        leave_test_dir, nocompress, lookforadds,+                         working_repo_dir,+                        match_one_nontag, umask_option,+                        notest, list_registered_files,+                        get_easy_author, set_scripts_executable+                      )+import Darcs.Utils ( askUser )+import Printer ( putDocLn )+\end{code}+\begin{code}+amendrecord_description :: String+amendrecord_description =+ "Replace a patch with a better version before it leaves your repository."+\end{code}++\options{amend-record}++\haskell{amend-record_help}+If you provide one or more files or directories as additional arguments to+amend-record, you will only be prompted to changes in those files or+directories.++The old version of the patch is lost and the new patch will include both the+old and the new changes.  This is mostly the same as unrecording the old patch,+fixing the changes and recording a new patch with the same name and+description.++\verb!amend-record! will modify the date of the recorded patch.  +\begin{code}+amendrecord_help :: String+amendrecord_help =+ "Amend-record is used to replace a patch with a newer version with additional\n"+++ "changes.\n\n"+++ "WARNINGS: You should ONLY use amend-record on patches which only exist in a\n"+++ "single repository! Also, running amend-record while another user is pulling\n"+++ "from the same repository may cause repository corruption.\n" +\end{code}+\begin{code}+amendrecord :: DarcsCommand+amendrecord = DarcsCommand {command_name = "amend-record",+                            command_help = amendrecord_help,+                            command_description = amendrecord_description,+                            command_extra_args = -1,+                            command_extra_arg_help = ["[FILE or DIRECTORY]..."],+                            command_command = amendrecord_cmd,+                            command_prereq = amInRepository,+                            command_get_arg_possibilities = list_registered_files,+                            command_argdefaults = nodefaults,+                            command_advanced_options = [nocompress, ignoretimes, umask_option,+                                                        set_scripts_executable],+                            command_basic_options = [match_one_nontag,+                                                     notest,+                                                    leave_test_dir,+                                                    all_interactive,+                                                    author, patchname_option, ask_long_comment,+                                                    lookforadds,+                                                    working_repo_dir]}+\end{code}+\begin{code}+amendrecord_cmd :: [DarcsFlag] -> [String] -> IO ()+amendrecord_cmd origopts args =+    let opts = if NoTest `elem` origopts then origopts else Test:origopts+        edit_metadata = has_edit_metadata opts in+    withRepoLock opts $- \repository -> do+    files  <- sort `fmap` getRepoPaths opts args+    when (areFileArgs files) $+         putStrLn $ "Amending changes in "++unwords (map show files)++":\n"+    with_selected_patch_from_repo "amend" repository opts True $ \ (oldp, _) -> do+        ch <- if All `elem` opts +              then get_unrecorded_unsorted repository+              else get_unrecorded repository+        case ch of+          NilFL | not edit_metadata -> putStrLn "No changes!"+          _ -> do+              date <- get_date opts+              s <- slurp_recorded repository+              with_selected_changes_to_files' "add" (filter (==All) opts)+                s (map toFilePath files) ch $ \ (chs:>_) ->+                  if (nullFL chs && not edit_metadata)+                  then putStrLn "You don't want to record anything!"+                  else do+                       let old_pinf = info oldp+                           prior    = (pi_name old_pinf, pi_log old_pinf)+                           make_log = world_readable_temp "darcs-amend-record"+                           old_author = pi_author old_pinf+                       author_here <- get_easy_author+                       case author_here of+                         Nothing -> return ()+                         Just ah -> let edit_author = isJust (get_author opts)+                                    in if (edit_author || ah == old_author)+                                       then return ()+                                       else do yorn <- askUser $ "You're not "++old_author+                                                                 ++"! Amend anyway? "+                                               case yorn of ('y':_) -> return ()+                                                            _ -> exitWith $ ExitSuccess+                       (new_name, new_log, _) <- get_log opts (Just prior) make_log chs+                       let new_author = case get_author opts of+                                        Just a  -> a+                                        Nothing -> pi_author old_pinf+                           maybe_invert = if is_inverted old_pinf then invert_name else id+                           new_pinf = maybe_invert $ patchinfo date new_name new_author new_log+                           newp = fixp oldp chs new_pinf+                       defineChanges newp+                       withGutsOf repository $ do+                         tentativelyRemovePatches repository opts (hopefully oldp :>: NilFL)+                         tentativelyAddPatch repository opts newp+                         finalizeRepositoryChanges repository+                       sync_repo repository+                       putStrLn "Finished amending patch:"+                       putDocLn $ description newp++has_edit_metadata :: [DarcsFlag] -> Bool+has_edit_metadata (Author _:_) = True+has_edit_metadata (LogFile _:_) = True+has_edit_metadata (PatchName _:_) = True+has_edit_metadata (EditLongComment:_) = True+has_edit_metadata (PromptLongComment:_) = True+has_edit_metadata (_:fs) = has_edit_metadata fs+has_edit_metadata [] = False++get_author :: [DarcsFlag] -> Maybe String+get_author (Author a:_) = Just a+get_author (_:as) = get_author as+get_author []     = Nothing+\end{code}++If you configure darcs to run a test suite, darcs will run this test on the+amended repository to make sure it is valid.  Darcs first creates a pristine+copy of the source tree (in a temporary directory), then it runs the test,+using its return value to decide if the amended change is valid. If the+\verb!--set-scripts-executable! flag is passed to amend-record, darcs will set+scripts executable in the temporary test directory before running the test. ++\begin{code}+fixp :: RepoPatch p => PatchInfoAnd p -> FL Prim -> PatchInfo -> PatchInfoAnd p+fixp oldp chs new_pinf =+    let pdeps = getdeps $ hopefully oldp+        oldchs = effect oldp+        infodepspatch pinfo deps p = adddeps (infopatch pinfo p) deps+    in n2pia $ infodepspatch new_pinf pdeps $ fromPrims $ sort_coalesceFL $+       concatFL $+       mapFL_FL canonize $ oldchs +>+ chs+\end{code}
+ src/Darcs/Commands/Annotate.lhs view
@@ -0,0 +1,430 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs annotate}+\label{annotate}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Annotate ( annotate, created_as_xml ) where++import Control.Monad ( when )+import Data.List ( sort )++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag(..), working_repo_dir,+                         summary, unified, human_readable,+                        xmloutput, creatorhash,+                        getRepoPaths,+                        list_registered_files,+                        match_one,+                      )+import Darcs.SlurpDirectory ( slurp )+import Darcs.Repository ( Repository, PatchSet, amInRepository, withRepository, ($-), read_repo,+                          getMarkedupFile )+import Darcs.Patch ( RepoPatch, Named, LineMark(..), patch2patchinfo, xml_summary )+import qualified Darcs.Patch ( summary )+import Darcs.Patch.Ordered ( mapRL, concatRL )+import FastPackedString ( PackedString, unpackPS )+import Darcs.PrintPatch ( printPatch, contextualPrintPatch )+import Darcs.Patch.Info ( PatchInfo, human_friendly, to_xml, make_filename,+                   showPatchInfo )+import Darcs.PopulationData ( Population(..), PopTree(..), DirMark(..),+                        nameI, modifiedByI, modifiedHowI,+                        createdByI, creationNameI,+                      )+import Darcs.Population ( getRepoPopVersion, lookup_pop, lookup_creation_pop,+                    modified_to_xml,+                  )+import Darcs.Hopefully ( info )+import Darcs.RepoPath ( SubPath, toFilePath )+import Darcs.Match ( match_patch, have_nonrange_match, get_first_match )+import Darcs.Lock ( withTempDir )+import Darcs.Sealed ( Sealed(..), liftSM )+import Printer ( putDocLn, text, errorDoc, ($$), prefix, (<+>),+                 Doc, empty, vcat, (<>), renderString, packedString )+#include "impossible.h"+\end{code}++\options{annotate}++\haskell{annotate_description}+\begin{code}+annotate_description :: String+annotate_description = "Display which patch last modified something."+\end{code}+\haskell{annotate_help}++\begin{code}+annotate_help :: String+annotate_help =+ "Annotate displays which patches created or last modified a directory\n"+++ "file or line. It can also display the contents of a particular patch\n"+++ "in darcs format.\n"+\end{code}++\begin{code}+annotate :: DarcsCommand+annotate = DarcsCommand {command_name = "annotate",+                         command_help = annotate_help,+                         command_description = annotate_description,+                         command_extra_args = -1,+                         command_extra_arg_help = ["[FILE or DIRECTORY]..."],+                         command_command = annotate_cmd,+                         command_prereq = amInRepository,+                         command_get_arg_possibilities = list_registered_files,+                         command_argdefaults = nodefaults,+                         command_advanced_options = [],+                         command_basic_options = [summary,unified,+                                                 human_readable,+                                                 xmloutput,+                                                 match_one, creatorhash,+                                                 working_repo_dir]}+\end{code}++\begin{options}+--human-readable, --summary, --unified, --xml--output+\end{options}++When called with just a patch name, annotate outputs the patch in darcs format,+which is the same as \verb!--human-readable!.++\verb!--xml-output! is the alternative to \verb!--human-readable!.++\verb!--summary! can be used with either the \verb!--xml-output! or the  +\verb!--human-readable! options to alter the results. It is documented+fully in the `common options' portion of the manual. ++Giving the \verb!--unified! flag implies \verb!--human-readable!, and causes+the output to remain in a darcs-specific format that is similar to that produced+by \verb!diff --unified!.+\begin{code}+annotate_cmd :: [DarcsFlag] -> [String] -> IO ()+annotate_cmd opts [] = withRepository opts $- \repository -> do+  when (not $ have_nonrange_match opts) $+      fail $ "Annotate requires either a patch pattern or a " +++               "file or directory argument."+  p <- match_patch opts `liftSM` read_repo repository+  if Summary `elem` opts+     then do putDocLn $ showpi $ patch2patchinfo p+             putDocLn $ show_summary p+     else if Unified `elem` opts+          then withTempDir "context" $ \_ ->+               do get_first_match repository opts+                  c <- slurp "."+                  contextualPrintPatch c p+          else printPatch p+    where showpi = if MachineReadable `elem` opts+                   then showPatchInfo+                   else if XMLOutput `elem` opts+                        then to_xml+                        else human_friendly+          show_summary :: RepoPatch p => Named p -> Doc+          show_summary = if XMLOutput `elem` opts+                         then xml_summary+                         else Darcs.Patch.summary+\end{code}++If a directory name is given, annotate will output details of the last+modifying patch for each file in the directory and the directory itself. The+details look like this:++\begin{verbatim}+ # Created by [bounce handling patch+ # mark**20040526202216]  as ./test/m7/bounce_handling.pl+    bounce_handling.pl+\end{verbatim}++If a patch name and a directory are given, these details are output for the time after+that patch was applied.  If a directory and a tag name are given, the+details of the patches involved in the specified tagged version will be output.+\begin{code}+annotate_cmd opts args@[_] = withRepository opts $- \repository -> do+  Sealed r <- read_repo repository+  (rel_file_or_directory:_) <- getRepoPaths opts args+  let file_or_directory = rel_file_or_directory+  pinfo <- if have_nonrange_match opts+           then return $ patch2patchinfo $ match_patch opts r+           else case mapRL info $ concatRL r of+                [] -> fail "Annotate doesn't yet work right on empty repositories."+                (x:_) -> return x+  pop <- getRepoPopVersion "." pinfo+  let maybe_creation_pi = find_creation_patchinfo opts r+      lookup_thing = case maybe_creation_pi of+                     Nothing -> lookup_pop+                     Just cp -> lookup_creation_pop cp+  if toFilePath file_or_directory == ""+    then case pop of (Pop _ pt) -> annotate_pop opts pinfo pt+    else case lookup_thing (toFilePath file_or_directory) pop of+      Nothing -> fail $ "There is no file or directory named '"+++                 toFilePath file_or_directory++"'"+      Just (Pop _ pt@(PopDir i _))+          | modifiedHowI i == RemovedDir && modifiedByI i /= pinfo ->+              errorDoc $ text ("The directory '" ++ toFilePath rel_file_or_directory +++                               "' was removed by")+                      $$ human_friendly (modifiedByI i)+          | otherwise -> annotate_pop opts pinfo pt+      Just (Pop _ pt@(PopFile i))+          | modifiedHowI i == RemovedFile && modifiedByI i /= pinfo ->+              errorDoc $ text ("The file '" ++ toFilePath rel_file_or_directory +++                               "' was removed by")+                      $$ human_friendly (modifiedByI i)+          | otherwise -> annotate_file repository opts pinfo file_or_directory pt+\end{code}++\begin{code}+annotate_cmd _ _ = fail "annotate accepts at most one argument"+\end{code}++\begin{code}+annotate_pop :: [DarcsFlag] -> PatchInfo -> PopTree -> IO ()+annotate_pop opts pinfo pt = putDocLn $ p2format pinfo pt+    where p2format = if XMLOutput `elem` opts+                     then p2xml+                     else p2s+\end{code}++\begin{code}+indent :: Doc -> [Doc]+-- This is a bit nasty:+indent = map (text . i) . lines . renderString+    where i "" = ""+          i ('#':s) = ('#':s)+          i s = "    "++s++-- Annotate a directory listing+p2s :: PatchInfo -> PopTree -> Doc+p2s pinfo (PopFile inf) =+    created_str+ $$ f <+> file_change+    where f = packedString $ nameI inf+          file_created = text "Created by"+                     <+> showPatchInfo (fromJust $ createdByI inf)+                     <+> text "as"+                     <+> packedString (fromJust $ creationNameI inf)+          created_str = prefix "# " file_created+          file_change = if modifiedByI inf == pinfo+                        then text $ show (modifiedHowI inf)+                        else empty+p2s pinfo (PopDir inf pops) =+    created_str+ $$ dir <+> dir_change+ $$ vcat (map (vcat . indent . p2s pinfo) $ sort pops)+    where dir = packedString (nameI inf) <> text "/"+          dir_created =+              if createdByI inf /= Nothing+              then text "Created by "+               <+> showPatchInfo (fromJust $ createdByI inf)+               <+> text "as"+               <+> packedString (fromJust $ creationNameI inf) <> text "/"+              else text "Root directory"+          created_str = prefix "# " dir_created+          dir_change = if modifiedByI inf == pinfo+                       then text $ show (modifiedHowI inf)+                       else empty+\end{code}++\begin{code}+escapeXML :: String -> Doc+escapeXML = text . strReplace '\'' "&apos;" . strReplace '"' "&quot;" .+  strReplace '>' "&gt;" . strReplace '<' "&lt;" . strReplace '&' "&amp;"++strReplace :: Char -> String -> String -> String+strReplace _ _ [] = []+strReplace x y (z:zs)+  | x == z    = y ++ (strReplace x y zs)+  | otherwise = z : (strReplace x y zs)++created_as_xml :: PatchInfo -> String -> Doc+created_as_xml pinfo as = text "<created_as original_name='"+                       <> escapeXML as+                       <> text "'>"+                    $$    to_xml pinfo+                    $$    text "</created_as>"+--removed_by_xml :: PatchInfo -> String+--removed_by_xml pinfo = "<removed_by>\n"++to_xml pinfo++"</removed_by>\n"++p2xml_open :: PatchInfo -> PopTree -> Doc+p2xml_open _ (PopFile inf) =+    text "<file name='" <> escapeXML f <> text "'>"+ $$ created+ $$ modified+    where f = unpackPS $ nameI inf+          created = case createdByI inf of+                    Nothing -> empty+                    Just ci -> created_as_xml ci+                               (unpackPS $ fromJust $ creationNameI inf)+          modified = modified_to_xml inf+p2xml_open _ (PopDir inf _) =+    text "<directory name='" <> escapeXML f <> text "'>"+ $$ created+ $$ modified+    where f = unpackPS $ nameI inf+          created = case createdByI inf of+                    Nothing -> empty+                    Just ci -> created_as_xml ci+                               (unpackPS $ fromJust $ creationNameI inf)+          modified = modified_to_xml inf++p2xml_close :: PatchInfo -> PopTree -> Doc+p2xml_close _(PopFile _) = text "</file>"+p2xml_close _ (PopDir _ _) = text "</directory>"++p2xml :: PatchInfo -> PopTree -> Doc+p2xml pinf p@(PopFile _) = p2xml_open pinf p $$ p2xml_close pinf p+p2xml pinf p@(PopDir _ pops) = p2xml_open pinf p+                            $$ vcat (map (p2xml pinf) $ sort pops)+                            $$ p2xml_close pinf p+\end{code}++If a file name is given, the last modifying patch details of that file will be output, along+with markup indicating patch details when each line was last (and perhaps next) modified.++\begin{code}+annotate_file :: RepoPatch p => Repository p -> [DarcsFlag] -> PatchInfo -> SubPath -> PopTree -> IO ()+annotate_file repository opts pinfo f (PopFile inf) = do+  if XMLOutput `elem` opts+     then putDocLn $ p2xml_open pinfo (PopFile inf)+     else if createdByI inf /= Nothing+          then putAnn $ text ("File "++toFilePath f++" created by ")+                     <> showPatchInfo ci <> text (" as " ++ createdname)+          else putAnn $ text $ "File "++toFilePath f+  mk <- getMarkedupFile repository ci createdname+  old_pis <- (dropWhile (/= pinfo).mapRL info.concatRL) `liftSM` read_repo repository+  sequence_ $ map (annotate_markedup opts pinfo old_pis) mk+  when (XMLOutput `elem` opts) $  putDocLn $ p2xml_close pinfo (PopFile inf)+  where ci = fromJust $ createdByI inf+        createdname = unpackPS $ fromJust $ creationNameI inf+annotate_file _ _ _ _ _ = impossible++annotate_markedup :: [DarcsFlag] -> PatchInfo -> [PatchInfo]+                  -> (PackedString, LineMark) -> IO ()+annotate_markedup opts | XMLOutput `elem` opts = xml_markedup+                       | otherwise = text_markedup++text_markedup :: PatchInfo -> [PatchInfo] -> (PackedString, LineMark) -> IO ()+text_markedup _ _ (l,None) = putLine ' ' l+text_markedup pinfo old_pis (l,RemovedLine wheni) =+    if wheni == pinfo+    then putLine '-' l+    else if wheni `elem` old_pis+         then return ()+         else putLine ' ' l+text_markedup pinfo old_pis (l,AddedLine wheni) =+    if wheni == pinfo+    then putLine '+' l+    else if wheni `elem` old_pis+         then do putAnn $ text "Following line added by "+                       <> showPatchInfo wheni+                 putLine ' ' l+         else return ()+text_markedup pinfo old_pis (l,AddedRemovedLine whenadd whenrem)+    | whenadd == pinfo = do putAnn $ text "Following line removed by "+                                  <> showPatchInfo whenrem+                            putLine '+' l+    | whenrem == pinfo = do putAnn $ text "Following line added by "+                                  <> showPatchInfo whenadd+                            putLine '-' l+    | whenadd `elem` old_pis && not (whenrem `elem` old_pis) =+        do putAnn $ text "Following line removed by " <> showPatchInfo whenrem+           putAnn $ text "Following line added by " <> showPatchInfo whenadd+           putLine ' ' l+    | otherwise = return ()++putLine :: Char -> PackedString -> IO ()+putLine c s = putStrLn $ c : unpackPS s+putAnn :: Doc -> IO ()+putAnn s = putDocLn $ prefix "# " s++xml_markedup :: PatchInfo -> [PatchInfo] -> (PackedString, LineMark) -> IO ()+xml_markedup _ _ (l,None) = putLine ' ' l+xml_markedup pinfo old_pis (l,RemovedLine wheni) =+    if wheni == pinfo+    then putDocLn $ text "<removed_line>"+                 $$ escapeXML (unpackPS l)+                 $$ text "</removed_line>"+    else if wheni `elem` old_pis+         then return ()+         else putDocLn $ text "<normal_line>"+                      $$ text "<removed_by>"+                      $$ to_xml wheni+                      $$ text "</removed_by>"+                      $$ escapeXML (unpackPS l)+                      $$ text "</normal_line>"+xml_markedup pinfo old_pis (l,AddedLine wheni) =+    if wheni == pinfo+    then putDocLn $ text "<added_line>"+                 $$ escapeXML (unpackPS l)+                 $$ text "</added_line>"+    else if wheni `elem` old_pis+         then putDocLn $ text "<normal_line>"+                      $$ text "<added_by>"+                      $$ to_xml wheni+                      $$ text "</added_by>"+                      $$ escapeXML (unpackPS l)+                      $$ text "</normal_line>"+         else return ()+xml_markedup pinfo old_pis (l,AddedRemovedLine whenadd whenrem)+    | whenadd == pinfo =+        putDocLn $ text "<added_line>"+                $$ text "<removed_by>"+                $$ to_xml whenrem+                $$ text "</removed_by>"+                $$ escapeXML (unpackPS l)+                $$ text "</added_line>"+    | whenrem == pinfo =+        putDocLn $ text "<removed_line>"+                $$ text "<added_by>"+                $$ to_xml whenadd+                $$ text "</added_by>"+                $$ escapeXML (unpackPS l)+                $$ text "</removed_line>"+    | whenadd `elem` old_pis && not (whenrem `elem` old_pis) =+        putDocLn $ text "<normal_line>"+                $$ text "<removed_by>"+                $$ to_xml whenrem+                $$ text "</removed_by>"+                $$ text "<added_by>"+                $$ to_xml whenadd+                $$ text "</added_by>"+                $$ escapeXML (unpackPS l)+                $$ text "</normal_line>"+    | otherwise = return ()+\end{code}++\begin{options}+--creator-hash HASH+\end{options}++The \verb!--creator-hash! option should only be used in combination with a+file or directory to be annotated.  In this case, the name of that file or+directory is interpreted to be its name \emph{at the time it was created},+and the hash given along with \verb!--creator-hash! indicates the patch+that created the file or directory.  This allows you to (relatively) easily+examine a file even if it has been renamed multiple times.++\begin{code}+find_creation_patchinfo :: [DarcsFlag] -> PatchSet p -> Maybe PatchInfo+find_creation_patchinfo [] _ = Nothing+find_creation_patchinfo (CreatorHash h:_) r = find_hash h $ mapRL info $ concatRL r+find_creation_patchinfo (_:fs) r = find_creation_patchinfo fs r++find_hash :: String -> [PatchInfo] -> Maybe PatchInfo+find_hash _ [] = Nothing+find_hash h (pinf:pinfs)+    | take (length h) (make_filename pinf) == h = Just pinf+    | otherwise = find_hash h pinfs+\end{code}
+ src/Darcs/Commands/Apply.lhs view
@@ -0,0 +1,444 @@+%  Copyright (C) 2003-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs apply}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Apply ( apply ) where+import System.Exit ( ExitCode(..), exitWith )+import Prelude hiding ( catch )+import System.IO ( hClose, stdin, stdout, stderr )+import Control.Exception ( catch, throw, Exception( ExitException ) )+import Control.Monad ( when )++import Darcs.Hopefully ( n2pia, conscientiously, info )+import Darcs.SignalHandler ( withSignalsBlocked )+import Darcs.Commands ( DarcsCommand(..) )+import Darcs.CommandsAux ( check_paths )+import Darcs.Arguments ( DarcsFlag( Reply, Interactive, All,+                                    Verbose, HappyForwarding ),+                         definePatches,+                         get_cc, working_repo_dir,+                        notest, nocompress, apply_conflict_options,+                        use_external_merge,+                        ignoretimes, get_sendmail_cmd,+                        reply, verify, list_files,+                        fix_filepath, umask_option,+                        all_interactive, sendmail_cmd,+                        leave_test_dir, happy_forwarding, +                        dry_run, print_dry_run_message_and_exit,+                        set_scripts_executable+                      )+import qualified Darcs.Arguments as DarcsArguments ( cc )+import Darcs.RepoPath ( toPath )+import Darcs.Repository ( SealedPatchSet, withRepoLock, ($-), amInRepository,+                          tentativelyMergePatches, slurp_recorded,+                    sync_repo, read_repo,+                    finalizeRepositoryChanges,+                    applyToWorking,+                  )+import Darcs.Patch ( RepoPatch, description )+import Darcs.Patch.Info ( human_friendly )+import Darcs.Patch.Ordered ( (:\/:)(..), (:>)(..), unsafeUnRL,+                             mapFL, nullFL, mapFL_FL, mapRL, concatRL, reverseRL )+import Darcs.SlurpDirectory ( wait_a_moment )+import FastPackedString ( readFilePS, packString, unpackPS, hGetContentsPS,+                          linesPS, takePS, dropPS, PackedString,+                          lastPS, initPS, nullPS,+                          unlinesPS )+import Darcs.External ( sendEmail, sendEmailDoc, resendEmail,+                  verifyPS )+import Darcs.Email ( read_email )+import Darcs.Lock ( withStdoutTemp, readBinFile )+import Darcs.Patch.Depends ( get_common_and_uncommon_or_missing )+import Darcs.SelectChanges ( with_selected_changes )+import Darcs.Patch.Bundle ( scan_bundle )+import Darcs.Sealed ( Sealed(Sealed) )+import Printer ( packedString, putDocLn, vcat, text, ($$), errorDoc, empty )+#include "impossible.h"+\end{code}+\begin{code}+apply_description :: String+apply_description =+ "Apply patches (from an email bundle) to the repository."+\end{code}++\options{apply}++\haskell{apply_help}+\begin{code}+apply_help :: String+apply_help =+ "Apply is used to apply a bundle of patches to this repository.\n"+++ "Such a bundle may be created using send.\n"+\end{code}+\begin{code}+stdin_magic :: String+stdin_magic = "magic darcs standard input"+stdindefault :: FilePath -> [String] -> IO [String]+stdindefault _ [] = return [stdin_magic]+stdindefault _ x = return x+apply :: DarcsCommand+apply = DarcsCommand {command_name = "apply",+                      command_help = apply_help,+                      command_description = apply_description,+                      command_extra_args = 1,+                      command_extra_arg_help = ["<PATCHFILE>"],+                      command_command = apply_cmd,+                      command_prereq = amInRepository,+                      command_get_arg_possibilities = list_files,+                      command_argdefaults = const stdindefault,+                      command_advanced_options = [reply, DarcsArguments.cc,+                                                  happy_forwarding,+                                                  sendmail_cmd,+                                                  ignoretimes, nocompress,+                                                  set_scripts_executable, umask_option],+                      command_basic_options = [verify,+                                              all_interactive]++dry_run+++                                              [apply_conflict_options,+                                              use_external_merge,+                                              notest,+                                              leave_test_dir,+                                              working_repo_dir]}+\end{code}+\begin{code}+apply_cmd :: [DarcsFlag] -> [String] -> IO ()+apply_cmd _ [""] = fail "Empty filename argument given to apply!"+apply_cmd opts [unfixed_patchesfile] = withRepoLock opts $- \repository -> do+ let patchesfile = toPath $ fix_filepath opts unfixed_patchesfile+ with_patches_file patchesfile $ \ps -> do+  am_verbose <- return $ Verbose `elem` opts+  let from_whom = get_from ps+  Sealed us <- read_repo repository+  either_them <- get_patch_bundle opts ps+  them <- case either_them of+          Right (Sealed t) -> return t+          Left er -> do forwarded <- consider_forwarding opts ps+                        if forwarded+                          then exitWith ExitSuccess+                          else fail er+  (_, us':\/:them') <- case get_common_and_uncommon_or_missing (us, them) of+                         Left pinfo ->+                            if pinfo `elem` mapRL info (concatRL us)+                                then cannotApplyPartialRepo pinfo ""+                                else cannotApplyMissing pinfo+                         Right x -> return x+  when (null $ unsafeUnRL $ head $ unsafeUnRL them') $+       do putStr $ "All these patches have already been applied.  " +++                     "Nothing to do.\n"+          exitWith ExitSuccess+  s <- slurp_recorded repository+  let their_ps = mapFL_FL (n2pia . conscientiously (text ("We cannot apply this patch "+                                                          ++"bundle, since we're missing:") $$))+                 $ reverseRL $ head $ unsafeUnRL them'+  with_selected_changes "apply" fixed_opts s their_ps $+                            \ (to_be_applied:>_) -> do+   print_dry_run_message_and_exit "apply" opts to_be_applied+   when (nullFL to_be_applied) $+        do putStrLn "You don't want to apply any patches, so I'm exiting!"+           exitWith ExitSuccess+   check_paths opts to_be_applied+   redirect_output opts from_whom $ do+    when am_verbose $ putStrLn "We have the following extra patches:"+    when am_verbose $ putDocLn $ vcat $ mapRL description $ head $ unsafeUnRL us'+    when am_verbose $ putStrLn "Will apply the following patches:"+    when am_verbose $ putDocLn $ vcat $ mapFL description to_be_applied+    definePatches to_be_applied+    pw <- tentativelyMergePatches repository "apply" opts+          (reverseRL $ head $ unsafeUnRL us') to_be_applied+    withSignalsBlocked $ do finalizeRepositoryChanges repository+                            wait_a_moment -- so work will be more recent than rec+                            applyToWorking repository opts pw `catch` \e ->+                                fail ("Error applying patch to working dir:\n" ++ show e)+    sync_repo repository+    putStrLn "Finished applying..."+    exitWith ExitSuccess+     where fixed_opts = if Interactive `elem` opts+                        then opts+                        else All : opts+           cannotApplyMissing pinfo+               = errorDoc $ text "Cannot apply this patch bundle, since we're missing:"+                         $$ human_friendly pinfo+           cannotApplyPartialRepo pinfo e+               = errorDoc $ text ("Cannot apply this patch bundle, "+                               ++ "this is a \"--partial repository")+                         $$ text "We don't have the following patch:"+                         $$ human_friendly pinfo $$ text e+apply_cmd _ _ = impossible+\end{code}++Darcs apply accepts a single argument, which is the name of the patch file+to be applied.  If you omit this argument, the patch is read from standard+input.\footnote{One caveat: don't name your patch file ``magic darcs+standard input'', or darcs will read from standard input instead!}  This+allows you to use apply with a pipe from your email program, for example.++\begin{code}+with_patches_file :: FilePath -> (PackedString -> IO a) -> IO a+with_patches_file fn c+    | fn == stdin_magic = do ps <- hGetContentsPS stdin+                             c ps+    | otherwise = do ps <- readFilePS fn+                     c ps+\end{code}++\begin{options}+--verify+\end{options}++If you specify the \verb!--verify PUBRING! option, darcs will check that+the patch was GPG-signed by a key which is in \verb!PUBRING! and will+refuse to apply the patch otherwise.++\begin{code}+get_patch_bundle :: RepoPatch p => [DarcsFlag] -> PackedString+                 -> IO (Either String (SealedPatchSet p))+get_patch_bundle opts fps = do+    mps <- verifyPS opts $ read_email fps+    mops <- verifyPS opts fps+    case (mps, mops) of+      (Nothing, Nothing) ->+          return $ Left "Patch bundle not properly signed, or gpg failed."+      (Just ps, Nothing) -> return $ scan_bundle ps+      (Nothing, Just ps) -> return $ scan_bundle ps+      -- We use careful_scan_bundle only below because in either of the two+      -- above case we know the patch was signed, so it really shouldn't+      -- need stripping of CRs.+      (Just ps1, Just ps2) -> case careful_scan_bundle ps1 of+                              Left _ -> return $ careful_scan_bundle ps2+                              Right x -> return $ Right x+          where careful_scan_bundle ps =+                    case scan_bundle ps of+                    Left e -> case scan_bundle $ stripCrPS ps of+                              Right x -> Right x+                              _ -> Left e+                    x -> x+                stripCrPS :: PackedString -> PackedString+                stripCrPS ps = unlinesPS $ map stripline $ linesPS ps+                stripline p | nullPS p = p+                            | lastPS p == '\r' = initPS p+                            | otherwise = p+\end{code}++\begin{options}+--cc, --reply+\end{options}++If you give the \verb!--reply FROM! option to \verb!darcs apply!, it will send the+results of the application to the sender of the patch.  This only works if+the patch is in the form of email with its headers intact, so that darcs+can actually know the origin of the patch.  The reply email will indicate+whether or not the patch was successfully applied.  The \verb!FROM! flag is+the email address that will be used as the ``from'' address when replying.+If the darcs apply is being done automatically, it is important that this+address not be the same as the address at which the patch was received, in+order to avoid automatic email loops.++If you want to also send the apply email to another address (for example,+to create something like a ``commits'' mailing list), you can use the+\verb!--cc! option to specify additional recipients.  Note that the+\verb!--cc! option \emph{requires} the \verb!--reply! option, which+provides the ``From'' address.++The \verb!--reply! feature of apply is intended primarily for two uses.+When used by itself, it is handy for when you want to apply patches sent to+you by other developers so that they will know when their patch has been+applied.  For example, in my \verb!.muttrc! (the config file for my mailer)+I have:+\begin{verbatim}+macro pager A "<pipe-entry>darcs apply --verbose \+        --reply droundy@abridgegame.org --repodir ~/darcs+\end{verbatim}+which allows me to apply a patch to darcs directly from my mailer, with the+originator of that patch being sent a confirmation when the patch is+successfully applied.  NOTE: In an attempt to make sure no one else+can read your email, mutt seems to set the umask+such that patches created with the above macro are not world-readable, so+use it with care.++When used in combination with the \verb!--verify! option, the+\verb!--reply! option allows for a nice pushable repository.  When these+two options are used together, any patches that don't pass the verify will+be forwarded to the \verb!FROM! address of the \verb!--reply! option.  This+allows you to set up a repository so that anyone who is authorized can push+to it and have it automatically applied, but if a stranger pushes to it,+the patch will be forwarded to you.  Please (for your own sake!)\ be certain+that the \verb!--reply FROM! address is different from the one used to send+patches to a pushable repository, since otherwise an unsigned patch will be+forwarded to the repository in an infinite loop.++If you use \verb!darcs apply --verify PUBRING --reply! to create a+pushable repository by applying patches automatically as they are received by+email, you will also want to use the \verb!--dont-allow-conflicts! option.++\begin{options}+--dont-allow-conflicts+\end{options}+The \verb!--dont-allow-conflicts! flag causes apply to fail when applying a+patch would cause conflicts.  This flag is recommended on repositories+which will be pushed to or sent to.++\begin{options}+--allow-conflicts+\end{options}++\verb!--allow-conflicts! will allow conflicts, but will keep the local and+recorded versions in sync on the repository.  This means the conflict will exist+in both locations until it is resolved.++\begin{options}+--mark-conflicts+\end{options}++\verb!--mark-conflicts! will add conflict markers to illustrate the the+conflict.++\begin{options}+--external-merge+\end{options}++You can use an external interactive merge tool to resolve conflicts with the+flag \verb!--external-merge!.  For more details see+subsection~\ref{resolution}.++\begin{options}+--all, --interactive+\end{options}++If you provide the \verb!--interactive! flag, darcs will+ask you for each change in the patch bundle whether or not you wish to+apply that change.  The opposite is the \verb!--all! flag, which can be+used to override an \verb!interactive! which might be set in your+``defaults'' file.++\begin{options}+--sendmail-command+\end{options}++If you want to use a command different from the default one for sending mail,+you need to specify a command line with the \verb!--sendmail-command! option.+The command line can contain the format specifier \verb!%t! for to+and you can add \verb!%<! to the end of the command line if the command+expects the complete mail on standard input. For example, the command line for+msmtp looks like this:++\begin{verbatim}+msmtp -t %<+\end{verbatim}+++\begin{code}+get_from :: PackedString -> String+get_from ps = readFrom $ linesPS ps+    where readFrom [] = ""+          readFrom (x:xs)+           | takePS 5 x == from_start = unpackPS $ dropPS 5 x+           | otherwise = readFrom xs++redirect_output :: [DarcsFlag] -> String -> IO a -> IO a+redirect_output opts to doit = ro opts+    where+  cc = get_cc opts+  scmd = get_sendmail_cmd opts+  ro [] = doit+  ro (Reply f:_) =+    withStdoutTemp $ \tempf-> do {a <- doit;+                                  hClose stdout;+                                  hClose stderr;+                                  return a;+                                 } `catch` (sendit tempf)+        where sendit tempf e@(ExitException ExitSuccess) =+                do body <- sanitizeFile tempf+                   sendEmail f to "Patch applied" cc scmd body+                   throwIO e+              sendit tempf (ExitException _) =+                do body <- sanitizeFile tempf+                   sendEmail f to "Patch failed!" cc scmd body+                   throwIO $ ExitException ExitSuccess+              sendit tempf e =+                do body <- sanitizeFile tempf+                   sendEmail f to "Darcs error applying patch!" cc scmd $+                             body ++ "\n\nCaught exception:\n"+++                             show e++"\n"+                   throwIO $ ExitException ExitSuccess+  ro (_:fs) = ro fs++-- sanitizeFile is used to clean up the stdout/stderr before sticking it in+-- an email.++sanitizeFile :: FilePath -> IO String+sanitizeFile f = sanitize `fmap` readBinFile f+    where sanitize s = wash $ remove_backspaces "" s+          wash ('\000':s) = "\\NUL" ++ wash s+          wash ('\026':s) = "\\EOF" ++ wash s+          wash (c:cs) = c : wash cs+          wash [] = []+          remove_backspaces rev_sofar "" = reverse rev_sofar+          remove_backspaces (_:rs) ('\008':s) = remove_backspaces rs s+          remove_backspaces "" ('\008':s) = remove_backspaces "" s+          remove_backspaces rs (s:ss) = remove_backspaces (s:rs) ss++throwIO :: Exception -> IO a+throwIO e = return $ throw e+\end{code}++\begin{code}+forwarding_message :: PackedString+forwarding_message = packString $+    "The following patch was either unsigned, or signed by a non-allowed\n"+++    "key, or there was a GPG failure.\n"++consider_forwarding :: [DarcsFlag] -> PackedString -> IO Bool+consider_forwarding opts m = cf opts (get_cc opts)+    where cf [] _ = return False+          cf (Reply t:_) cc =+              case break is_from (linesPS m) of+              (m1, f:m2) ->+                  let m_lines = forwarding_message:m1 ++ m2+                      m' = unlinesPS m_lines+                      f' = unpackPS (dropPS 5 f) in+                      if t == f' || t == init f'+                      then return False -- Refuse possible email loop.+                      else do+                        let scmd = get_sendmail_cmd opts+                        if HappyForwarding `elem` opts+                         then resendEmail t scmd m+                         else sendEmailDoc f' t "A forwarded darcs patch" cc+                                           scmd (Just (empty,empty))+                                           (packedString m')+                        return True+              _ -> return False -- Don't forward emails lacking headers!+          cf (_:fs) cc = cf fs cc+          is_from l = takePS 5 l == from_start++from_start :: PackedString+from_start = packString "From:"+\end{code}++\begin{options}+--no-test, --test+\end{options}++If you specify the \verb!--test! option, apply will run the test (if a test+exists) prior to applying the patch.  If the test fails, the patch is not+applied.  In this case, if the \verb!--reply! option was used, the results+of the test are sent in the reply email.  You can also specify the+\verb!--no-test! option, which will override the \verb!--test! option, and+prevent the test from being run.  This is helpful when setting up a+pushable repository, to keep users from running code.++
+ src/Darcs/Commands/Changes.lhs view
@@ -0,0 +1,262 @@+%  Copyright (C) 2003-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs changes}+\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+-- The pragma above is only for pattern guards.+module Darcs.Commands.Changes ( changes ) where++import Data.List ( sort )+import Data.Maybe ( fromMaybe )+import Control.Monad ( when, unless )++import Darcs.Hopefully ( hopefullyM, info )+import Darcs.Patch.Depends ( slightly_optimize_patchset )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag(Context, MachineReadable, Interactive,+                                   OnlyChangesToFiles, Count,+                                  XMLOutput, Summary, Reverse, Verbose, Debug),+                         getRepoPaths, changes_format,+                        possibly_remote_repo_dir, get_repourl,+                        working_repo_dir, only_to_files,+                        summary, changes_reverse,+                        match_several_or_range,+                        all_interactive, showFriendly,+                        ssh_cm+                      )+import Darcs.RepoPath ( toFilePath )+import FileName ( fp2fn, fn2fp, norm_path )+import Darcs.Repository ( Repository, PatchSet, PatchInfoAnd, get_unrecorded_unsorted,+                          withRepositoryDirectory, ($-), findRepository,+                          read_repo, slurp_recorded )+import Darcs.Patch.Info ( to_xml, showPatchInfo )+import Darcs.Patch.Depends ( get_common_and_uncommon )+import Darcs.Patch.TouchesFiles ( look_touch )+import Darcs.Patch ( RepoPatch, invert, xml_summary, description, apply_to_filepaths,+                     list_touched_files, effect, identity )+import Darcs.Patch.Ordered ( (:\/:)(..), RL(..), unsafeFL, unsafeUnRL, concatRL,+                             EqCheck(..), filterFL )+import Darcs.Match ( first_match, second_match,+               match_a_patchread, have_nonrange_match,+               match_first_patchset, match_second_patchset,+             )+import Darcs.Commands.Annotate ( created_as_xml )+import FastPackedString ( linesPS )+import Printer ( Doc, putDocLnWith, simplePrinters, renderPS,+                 renderString, prefix,+                 packedString, text, vcat, vsep, ($$), empty, errorDoc )+import Darcs.ColorPrinter ( fancyPrinters )+import Darcs.Progress ( setProgressMode, debugMessage )+import Darcs.SelectChanges ( view_changes )+import Darcs.Sealed ( Sealed(..) )+#include "impossible.h"+\end{code}++\options{changes}+\begin{code}+changes_description :: String+changes_description = "Gives a changelog-style summary of the repository history."+\end{code}+\haskell{changes_help}+\begin{code}+changes_help :: String+changes_help =+ "Changes gives a changelog-style summary of the repository history,\n"+++ "including options for altering how the patches are selected and displayed.\n"++changes :: DarcsCommand+changes = DarcsCommand {command_name = "changes",+                        command_help = changes_help,+                        command_description = changes_description,+                        command_extra_args = -1,+                        command_extra_arg_help = ["[FILE or DIRECTORY]..."],+                        command_get_arg_possibilities = return [],+                        command_command = changes_cmd,+                        command_prereq = findRepository,+                        command_argdefaults = nodefaults,+                        command_advanced_options = [ssh_cm],+                        command_basic_options = [match_several_or_range,+                                                 only_to_files,+                                                changes_format,+                                                summary,+                                                changes_reverse,+                                                possibly_remote_repo_dir,+                                                working_repo_dir,+                                                all_interactive]}+\end{code}+++\begin{code}+changes_cmd :: [DarcsFlag] -> [String] -> IO ()+changes_cmd [Context ""] [] = do return ()+changes_cmd opts args | Context "" `elem` opts =+  let repodir = fromMaybe "." (get_repourl opts) in+  withRepositoryDirectory opts repodir $- \repository -> do+  when (args /= []) $ fail "changes --context cannot accept other arguments"+  changes_context repository opts+changes_cmd opts args =+  let repodir = fromMaybe "." (get_repourl opts) in+  withRepositoryDirectory opts repodir $- \repository -> do+  unless (Debug `elem` opts) $ setProgressMode False+  files <- sort `fmap` getRepoPaths opts args+  unrec <- get_unrecorded_unsorted repository+           `catch` \_ -> return identity -- this is triggered when repository is remote+  let filez = map (fn2fp . norm_path . fp2fn) $ apply_to_filepaths (invert unrec) $ map toFilePath files+      filtered_changes p = maybe_reverse $ get_changes_info opts filez p+  debugMessage "About to read the repository..."+  Sealed patches <- read_repo repository+  debugMessage "Done reading the repository."+  if Interactive `elem` opts+    then do let (fp,_,_) = filtered_changes patches+            s <- slurp_recorded repository+            view_changes opts s filez (unsafeFL fp)+    else do when (not (null files) && not (XMLOutput `elem` opts)) $+                 putStrLn $ "Changes to "++unwords filez++":\n"+            debugMessage "About to print the changes..."+            let printers = if XMLOutput `elem` opts then simplePrinters else fancyPrinters+            putDocLnWith printers $ changelog opts $ filtered_changes patches+  where maybe_reverse (xs,b,c) = if Reverse `elem` opts+                                 then (reverse xs, b, c)+                                 else (xs, b, c)+\end{code}++When given one or more files or directories as an argument, changes lists only+those patches which affect those files or the contents of those directories or,+of course, the directories themselves. This includes changes that happened to+files before they were moved or renamed.++\begin{options}+--from-match, --from-patch, --from-tag+\end{options}++If changes is given a \verb!--from-patch!, \verb!--from-match!, or+\verb!--from-tag! option, it outputs only those changes since that tag or+patch.++Without any options to limit the scope of the changes, history will be displayed+going back as far as possible.+++\begin{code}+get_changes_info :: RepoPatch p => [DarcsFlag] -> [FilePath] -> PatchSet p+                 -> ([PatchInfoAnd p], [FilePath], Doc)+get_changes_info opts plain_fs ps =+  case get_common_and_uncommon (p2s,p1s) of+  (_,us:\/:_) -> filter_patches_by_names fs $ filter pf $ unsafeUnRL $ concatRL us+  where fs = map (\x -> "./" ++ x) $ plain_fs+        p1s = if first_match opts then match_first_patchset opts ps+                                  else NilRL:<:NilRL+        p2s = if second_match opts then match_second_patchset opts ps+                                   else ps+        pf = if have_nonrange_match opts+             then match_a_patchread opts+             else \_ -> True++filter_patches_by_names :: RepoPatch p => [FilePath]+                        -> [PatchInfoAnd p]+                        -> ([PatchInfoAnd p],[FilePath], Doc)+filter_patches_by_names _ [] = ([], [], empty)+filter_patches_by_names [] pps = (pps, [], empty)+filter_patches_by_names fs (hp:ps)+    | Just p <- hopefullyM hp =+    case look_touch fs (invert p) of+    (True, []) -> ([hp], fs, empty)+    (True, fs') -> hp -:- filter_patches_by_names fs' ps+    (False, fs') -> filter_patches_by_names fs' ps+filter_patches_by_names _ (hp:_) =+    ([], [], text "Can't find changes prior to:" $$ description hp)++(-:-) :: a -> ([a],b,c) -> ([a],b,c)+x -:- (xs,y,z) = (x:xs,y,z)++changelog :: RepoPatch p => [DarcsFlag] -> ([PatchInfoAnd p], [FilePath], Doc)+          -> Doc+changelog opts (pis, fs, errstring)+    | Count `elem` opts = text $ show $ length pis+    | MachineReadable `elem` opts =+        if renderString errstring == ""+        then vsep $ map (showPatchInfo.info) pis+        else errorDoc errstring+    | XMLOutput `elem` opts =+         text "<changelog>"+      $$ vcat xml_file_names+      $$ vcat actual_xml_changes+      $$ text "</changelog>"+    | Summary `elem` opts || Verbose `elem`  opts =+           vsep (map change_with_summary pis)+        $$ errstring+    | otherwise = vsep (map description pis)+               $$ errstring+    where change_with_summary hp+              | Just p <- hopefullyM hp = if OnlyChangesToFiles `elem` opts+                                          then description hp $$+                                               showFriendly opts (filterFL xx $ effect p)+                                          else showFriendly opts p+              | otherwise = description hp+                            $$ indent (text "[this patch is unavailable]")+              where xx x = case list_touched_files x of+                             [z] | z `elem` fs -> NotEq+                             _ -> IsEq+          xml_with_summary hp+              | Just p <- hopefullyM hp = insert_before_lastline+                                           (to_xml $ info hp) (indent $ xml_summary p)+          xml_with_summary hp = to_xml (info hp)+          indent = prefix "    "+          actual_xml_changes = if Summary `elem` opts+                               then map xml_with_summary pis+                               else map (to_xml.info) pis+          xml_file_names = map (created_as_xml first_change) fs+          first_change = if Reverse `elem` opts+                         then info $ head pis+                         else info $ last pis+++insert_before_lastline :: Doc -> Doc -> Doc+insert_before_lastline a b =+    case reverse $ map packedString $ linesPS $ renderPS a of+    (ll:ls) -> vcat (reverse ls) $$ b $$ ll+    [] -> impossible+\end{code}++\begin{options}+--context, --human-readable, --xml-output+\end{options}++When given the \verb!--context! flag, darcs changes outputs sufficient+information to allow the current state of the repository to be+recreated at a later date.  This information should generally be piped to a+file, and then can be used later in conjunction with+\verb!darcs get --context! to recreate the current version.  Note that+while the \verb!--context! flag may be used in conjunction with+\verb!--xml-output! or \verb!--human-readable!, in neither case will darcs+get be able to read the output.  On the other hand, sufficient information+\emph{will} be output for a knowledgeable human to recreate the current+state of the repository.+\begin{code}+changes_context :: RepoPatch p => Repository p -> [DarcsFlag] -> IO ()+changes_context repository opts = do+  Sealed r <- read_repo repository+  putStrLn "\nContext:\n"+  when (not $ null (unsafeUnRL r) || null (unsafeUnRL $ head $ unsafeUnRL r)) $+    putDocLnWith simplePrinters $ changelog opts' $+                 get_changes_info opts' []+                 (headRL (slightly_optimize_patchset r) :<: NilRL)+    where opts' = MachineReadable : opts+          headRL (x:<:_) = x+          headRL NilRL = impossible+\end{code}
+ src/Darcs/Commands/Check.lhs view
@@ -0,0 +1,166 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs check}+\begin{code}+module Darcs.Commands.Check ( check, check_uniqueness ) where+import Control.Monad ( when )+import System.Directory ( setCurrentDirectory )+import Workaround ( getCurrentDirectory )+import System.Exit ( ExitCode(..), exitWith )+import Data.List ( sort )++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag( Quiet, Verbose, NoTest, LeaveTestDir ),+                        partial_check, notest,+                        leave_test_dir, working_repo_dir,+                      )+import Darcs.Hopefully ( info, piap )+import Darcs.Repository ( Repository, amInRepository, read_repo, withRepository, ($-), slurp_recorded,+                          checkPristineAgainstCwd )+import Darcs.Repository.Checkpoint ( get_checkpoint_by_default )+import Darcs.Repository.ApplyPatches ( apply_patches_with_feedback )+import Darcs.Patch ( RepoPatch, patch2patchinfo, showPatch )+import Darcs.Patch.Ordered ( FL(..), reverseRL, mapRL, concatRL )+import Darcs.Patch.Info ( human_friendly )+import Darcs.SlurpDirectory ( slurp )+import Darcs.Diff ( smart_diff )+import Darcs.Test ( run_test )+import Darcs.Progress ( debugMessage )+import Darcs.Lock ( withTempDir, withPermDir )+import Darcs.Repository.Prefs ( filetype_function )+import Darcs.Patch.Depends ( get_patches_beyond_tag )+import Darcs.Sealed ( Sealed(..), unsafeUnflippedseal )+import Printer ( Doc, putDocLn, text, ($$), (<+>) )+\end{code}++\options{check}++\haskell{check_description}+\begin{code}+check_description :: String+check_description = "Check the repository for consistency."+\end{code}+Check verifies that the patches stored in the repository, when successively+applied to an empty tree, properly recreate the stored pristine tree.++\begin{options}+--complete, --partial+\end{options}++If you have a checkpoint of the repository (as is the case if you got the+repository originally using \verb!darcs get --partial!), by default+\verb'darcs check'+will only verify the contents since the most recent checkpoint.  You can+change this behavior using the \verb!--complete! flag.++\begin{code}+check_help :: String+check_help =+ "Check verifies that the patches stored in the repository, when successively\n"+++ "applied to an empty tree, properly recreate the stored pristine tree.\n"+\end{code}++\begin{code}+check :: DarcsCommand+check = DarcsCommand {command_name = "check",+                      command_help = check_help,+                      command_description = check_description,+                      command_extra_args = 0,+                      command_extra_arg_help = [],+                      command_command = check_cmd,+                      command_prereq = amInRepository,+                      command_get_arg_possibilities = return [],+                      command_argdefaults = nodefaults,+                      command_advanced_options = [],+                      command_basic_options = [partial_check,+                                              notest,+                                              leave_test_dir,+                                              working_repo_dir+                                             ]}+\end{code}++\begin{code}+check_cmd :: [DarcsFlag] -> [String] -> IO ()+check_cmd opts _ = withRepository opts $- \repository -> do+  let putVerbose s = when (Verbose `elem` opts) $ putDocLn s+      putInfo s = when (not $ Quiet `elem` opts) $ putDocLn s+  debugMessage "I'm about to check for uniqueness of patches."+  check_uniqueness putVerbose putInfo repository+  Sealed patches <- read_repo repository -- FIXME: This should be lazy!+  maybe_chk <- get_checkpoint_by_default repository+  ftf <- filetype_function+  cwd <- getCurrentDirectory+  wd "checking" $ \chd -> do+    putVerbose $ text "Checking patches..."+    case maybe_chk of+        Just chk ->+             do let chtg = patch2patchinfo chk+                putVerbose $ text "I am checking from a checkpoint."+                apply_patches_with_feedback [] "Checking patch" $ (chtg `piap` chk)+                    :>: reverseRL (concatRL $ unsafeUnflippedseal $ get_patches_beyond_tag chtg patches)+        Nothing -> apply_patches_with_feedback [] "Checking patch" $+                   reverseRL $ concatRL patches+    is_same <- checkPristineAgainstCwd repository+    if is_same+      then do+        putInfo $ text "The repository is consistent!"+        if NoTest `elem` opts+           then exitWith ExitSuccess+           else do setCurrentDirectory cwd+                   ec <- run_test opts chd+                   exitWith ec+      else do putInfo $ text "Looks like we have a difference..."+              mc <- slurp_recorded repository+              p <- slurp chd+              putInfo $ case smart_diff opts ftf p mc of+                        NilFL -> text "Nothing"+                        patch -> text "Difference: " <+> showPatch patch+              putInfo $ text ""+                     $$ text "Inconsistent repository!"+              exitWith $ ExitFailure 1+    where wd = if LeaveTestDir `elem` opts then withPermDir else withTempDir+\end{code}++\input{Darcs/Test.lhs}++\begin{options}+--no-test+\end{options}++If you just want to check the consistency of your repository without+running the test, you can call darcs check with the \verb!--no-test!+option.++\begin{code}+check_uniqueness :: RepoPatch p => (Doc -> IO ()) -> (Doc -> IO ()) -> Repository p -> IO ()+check_uniqueness putVerbose putInfo repository =+    do putVerbose $ text "Checking that patch names are unique..."+       Sealed r <- read_repo repository+       case has_duplicate $ mapRL info $ concatRL r of+         Nothing -> return ()+         Just pinf -> do putInfo $ text "Error! Duplicate patch name:"+                         putInfo $ human_friendly pinf+                         exitWith $ ExitFailure 1++has_duplicate :: Ord a => [a] -> Maybe a+has_duplicate li = hd $ sort li+    where hd [_] = Nothing+          hd [] = Nothing+          hd (x1:x2:xs) | x1 == x2 = Just x1+                        | otherwise = hd (x2:xs)+\end{code}
+ src/Darcs/Commands/Convert.lhs view
@@ -0,0 +1,238 @@+%  Copyright (C) 2002-2005,2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs convert}+\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Commands.Convert ( convert ) where++import System.Directory ( setCurrentDirectory, doesDirectoryExist, doesFileExist,+                   createDirectory )+import Workaround ( getCurrentDirectory )+import Control.Monad ( when )+import GHC.Base ( unsafeCoerce# )+import Data.Maybe ( catMaybes )++import Darcs.Hopefully ( PatchInfoAnd, n2pia, info, hopefully )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Commands.Init ( initialize )+import Darcs.Arguments ( DarcsFlag( AllowConflicts, WorkDir,+                                    SetScriptsExecutable, UseFormat2, NoUpdateWorking,+                                    Verbose, Quiet, Context ),+                        reponame,+                        set_scripts_executable,+                        ssh_cm )+import Darcs.Repository ( Repository, withRepoLock, ($-), withRepositoryDirectory, read_repo,+                          slurp_recorded, optimizeInventory,+                          tentativelyMergePatches, patchSetToPatches,+                          createPristineDirectoryTree,+                          revertRepositoryChanges, finalizeRepositoryChanges, sync_repo )+import Darcs.Global ( darcsdir )+import Darcs.FilePathUtils ( absolute_dir )+import Darcs.Patch ( RealPatch, Patch, Named, showPatch, patch2patchinfo, fromPrims, infopatch,+                     modernize_patch,+                     adddeps, getdeps, effect, flattenFL, is_merger, patchcontents )+import Darcs.Patch.Ordered ( FL(..), RL(..), EqCheck(..), (=/\=), bunchFL, mapFL, mapFL_FL,+                             concatFL, concatRL, mapRL )+import Darcs.Patch.Depends ( is_tag )+import Darcs.Patch.Info ( pi_rename, pi_tag )+import Darcs.Patch.Commute ( public_unravel )+import Darcs.Patch.Real ( mergeUnravelled )+import Darcs.Repository.Motd ( show_motd )+import Darcs.Utils ( clarify_errors, askUser )+import Darcs.Progress ( progressFL )+import Darcs.Sealed ( Sealed(..), FlippedSeal(..) )+import Printer ( text, putDocLn, ($$), redText, (<+>) )+import Darcs.ColorPrinter ( traceDoc )+import Darcs.SlurpDirectory ( list_slurpy_files )+import Darcs.Lock ( writeBinFile )+import Workaround ( setExecutable )+import FastPackedString ( packString, readFilePS, takePS )++convert_description :: String+convert_description =+ "Convert a repository to darcs-2 format."+\end{code}++\options{convert}++You may specify the name of the repository created by providing a second+argument to convert, which is a directory name.++\begin{code}+convert_help :: String+convert_help =+ "Convert is used to convert a repository to darcs-2 format.\n"+\end{code}+\begin{code}+convert :: DarcsCommand+convert = DarcsCommand {command_name = "convert",+                    command_help = convert_help,+                    command_description = convert_description,+                    command_extra_args = -1,+                    command_extra_arg_help = ["<REPOSITORY>", "[<DIRECTORY>]"],+                    command_command = convert_cmd,+                    command_prereq = \_ -> return $ Right "",+                    command_get_arg_possibilities = return [],+                    command_argdefaults = nodefaults,+                    command_advanced_options = [ssh_cm],+                    command_basic_options = [reponame,set_scripts_executable]}+\end{code}+\begin{code}+convert_cmd :: [DarcsFlag] -> [String] -> IO ()+convert_cmd opts [inrepodir, outname] = convert_cmd (WorkDir outname:opts) [inrepodir]+convert_cmd orig_opts [inrepodir] = do+  putDocLn $ text "WARNING:  You can only run darcs convert" <+> redText "once" <+> text "for" $$+             text "any related set of repositories.  Failure to do this can result in" $$+             text "repository corruption!\n" $$+             text "If you fully understand the implications and promise not to run convert again"+  let vow = "I understand the consequences of my action"+  vow' <- askUser ("then type '" ++ vow ++ "': ")+  when (vow' /= vow) $ fail "User didn't understand the consequences."+  former_dir <- getCurrentDirectory+  let opts = UseFormat2:fix_context orig_opts+      fix_context o@(Context ('/':_):_) = o+      fix_context (Context f:os) = Context (former_dir++"/"++f):os+      fix_context (o:os) = o : fix_context os+      fix_context [] = []+  repodir <- absolute_dir inrepodir+  show_motd opts repodir+  mysimplename <- make_repo_name opts repodir+  createDirectory mysimplename+  setCurrentDirectory mysimplename+  (command_command initialize) opts []+  writeBinFile (darcsdir++"/hashed_inventory") ""+  withRepoLock (NoUpdateWorking:opts) $- \repositoryfoo ->+    withRepositoryDirectory opts repodir $- \themrepobar -> do+      -- We really ought to have special versions of withRepoLock and+      -- withRepositoryDirectory that check at runtime that it's the right+      -- sort of repository and accept a function of (Repository Patch) or+      -- (Repository (FL RealPatch)), but that seems like a lot of work+      -- when these functions would be used exactly once, right here.  So I+      -- go with a horrible evil hack.++      -- The other alternative (which is what we used to do) is to use+      -- "universal" functions to do the conversion, but that's also+      -- unsatisfying.++      let repository = unsafeCoerce# repositoryfoo :: Repository (FL RealPatch)+          themrepo = unsafeCoerce# themrepobar :: Repository Patch+      Sealed theirstuff <- read_repo themrepo+      let patches = mapFL_FL convertNamed $ patchSetToPatches theirstuff+          inOrderTags = iot theirstuff+              where iot ((t:<:NilRL):<:r) = info t : iot r+                    iot (NilRL:<:r) = iot r+                    iot NilRL = []+                    iot ((_:<:x):<:y) = iot (x:<:y)+          outOfOrderTags = catMaybes $ mapRL oot $ concatRL theirstuff+              where oot t = if is_tag (info t) && not (info t `elem` inOrderTags)+                            then Just (info t, getdeps $ hopefully t)+                            else Nothing+          fixDep p = case lookup p outOfOrderTags of+                     Just d -> p : concatMap fixDep d+                     Nothing -> [p]+          convertOne :: Patch -> FL RealPatch+          convertOne x | is_merger x = case mergeUnravelled $ public_unravel $ modernize_patch x of+                                       Just (FlippedSeal y) ->+                                           case effect y =/\= effect x of+                                           IsEq -> y :>: NilFL+                                           NotEq ->+                                               traceDoc (text "lossy conversion:" $$+                                                         showPatch x)+                                               fromPrims (effect x)+                                       Nothing -> traceDoc (text+                                                            "lossy conversion of complicated conflict:" $$+                                                            showPatch x)+                                                  fromPrims (effect x)+                       | otherwise = case flattenFL x of+                                     NilFL -> NilFL+                                     (x':>:NilFL) -> fromPrims $ effect x'+                                     xs -> concatFL $ mapFL_FL convertOne xs+          convertNamed :: Named Patch -> PatchInfoAnd (FL RealPatch)+          convertNamed n = n2pia $+                           adddeps (infopatch (convertInfo $ patch2patchinfo n) $+                                              convertOne $ patchcontents n)+                                   (map convertInfo $ concatMap fixDep $ getdeps n)+          convertInfo n | n `elem` inOrderTags = n+                        | otherwise = maybe n (\t -> pi_rename n ("old tag: "++t)) $ pi_tag n+          applySome xs = do tentativelyMergePatches repository "convert" (AllowConflicts:opts) NilFL xs+                            finalizeRepositoryChanges repository -- this is to clean out pristine.hashed+                            revertRepositoryChanges repository+      sequence_ $ mapFL applySome $ bunchFL 100 $ progressFL "Converting patch" patches+      revertable $ createPristineDirectoryTree repository "."+      when (SetScriptsExecutable `elem` opts) $+               do putVerbose $ text "Making scripts executable"+                  c <- list_slurpy_files `fmap` slurp_recorded repository+                  let setExecutableIfScript f =+                            do contents <- readFilePS f+                               when (takePS 2 contents == packString "#!") $ do+                                 putVerbose $ text ("Making executable: " ++ f)+                                 setExecutable f True+                  mapM_ setExecutableIfScript c+      sync_repo repository+      optimizeInventory repository+      putInfo $ text "Finished converting."+      where am_verbose = Verbose `elem` orig_opts+            am_informative = not $ Quiet `elem` orig_opts+            putVerbose s = when am_verbose $ putDocLn s+            putInfo s = when am_informative $ putDocLn s+            revertable x = x `clarify_errors` unlines+                  ["An error may have left your new working directory an inconsistent",+                   "but recoverable state. You should be able to make the new",+                   "repository consistent again by running darcs revert -a."]++convert_cmd _ _ = fail "You must provide 'convert' with either one or two arguments."+\end{code}++\begin{code}+make_repo_name :: [DarcsFlag] -> FilePath -> IO String+make_repo_name (WorkDir n:_) _ =+    do exists <- doesDirectoryExist n+       file_exists <- doesFileExist n+       if exists || file_exists+          then fail $ "Directory or file named '" ++ n ++ "' already exists."+          else return n+make_repo_name (_:as) d = make_repo_name as d+make_repo_name [] d =+  case dropWhile (=='.') $ reverse $+       takeWhile (\c -> c /= '/' && c /= ':') $+       dropWhile (=='/') $ reverse d of+  "" -> modify_repo_name "anonymous_repo"+  base -> modify_repo_name base++modify_repo_name :: String -> IO String+modify_repo_name name =+    if head name == '/'+    then mrn name (-1)+    else do cwd <- getCurrentDirectory+            mrn (cwd ++ "/" ++ name) (-1)+ where+  mrn :: String -> Int -> IO String+  mrn n i = do+    exists <- doesDirectoryExist thename+    file_exists <- doesFileExist thename+    if not exists && not file_exists+       then do when (i /= -1) $+                    putStrLn $ "Directory '"++ n +++                               "' already exists, creating repository as '"+++                               thename ++"'"+               return thename+       else mrn n $ i+1+    where thename = if i == -1 then n else n++"_"++show i+                        +\end{code}                        
+ src/Darcs/Commands/Diff.lhs view
@@ -0,0 +1,247 @@+%  Copyright (C) 2003-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs diff}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Diff ( diff_command ) where++import System.Directory ( setCurrentDirectory )+import Workaround ( getCurrentDirectory )+import Darcs.Utils ( askUser, withCurrentDirectory )+import Control.Monad ( liftM, when )+import Data.List ( (\\) )++import Autoconf ( diff_program )+import CommandLine ( parseCmd )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag(DiffFlags, Unified, DiffCmd, StoreInMemory,+                                   LastN, AfterPatch),+                        match_range, store_in_memory, +                        diff_cmd_flag, diffflags, unidiff,+                         working_repo_dir, fix_filepaths, getRepoPath,+                      )+import Darcs.Hopefully ( info )+import Darcs.FilePathUtils ( just_dir )+import Darcs.RepoPath ( toFilePath )+import Darcs.Match ( get_first_match, get_second_match, get_first_match_s, get_second_match_s, apply_patches_to_some_files,+               first_match, second_match,+               match_first_patchset, match_second_patchset,+             )+import Darcs.Repository ( PatchSet, withRepository, ($-), read_repo,+                          amInRepository, slurp_recorded_and_unrecorded,+                          createPartialsPristineDirectoryTree )+import Darcs.SlurpDirectory ( get_path_list )+import Darcs.Patch ( RepoPatch )+import Darcs.Patch.Ordered ( mapRL, concatRL )+import Darcs.Patch.Info ( PatchInfo, human_friendly )+import Darcs.External ( execPipeIgnoreError, clonePaths )+import Darcs.Lock ( withTempDir )+import Darcs.Sealed ( Sealed(..) )+import Printer ( Doc, putDocLn, vcat, empty, ($$) )+#include "impossible.h"+\end{code}++\options{diff}+\begin{code}+diff_description :: String+diff_description = "Create a diff between two versions of the repository."+\end{code}+\haskell{diff_help}+\begin{code}+diff_help :: String+diff_help =+ "Diff can be used to create a diff between two versions which are in your\n"+++ "repository.  Specifying just --from-patch will get you a diff against\n"+++ "your working copy.  If you give diff no version arguments, it gives\n"+++ "you the same information as whatsnew except that the patch is\n"+++ "formatted as the output of a diff command\n"++diff_command :: DarcsCommand+diff_command = DarcsCommand {command_name = "diff",+                             command_help = diff_help,+                             command_description = diff_description,+                             command_extra_args = -1,+                             command_extra_arg_help+                                 = ["[FILE or DIRECTORY]..."],+                             command_command = diff_cmd,+                             command_prereq = amInRepository,+                             command_get_arg_possibilities = return [],+                             command_argdefaults = nodefaults,+                             command_advanced_options = [],+                             command_basic_options = [match_range,+                                                     diff_cmd_flag,+                                                     diffflags, unidiff,+                                                     working_repo_dir, store_in_memory]}+\end{code}++\begin{options}+--diff-opts+\end{options}++Diff calls an external ``diff'' command to do the actual work, and passes+any unrecognized flags to this diff command.  Thus you can call+\begin{verbatim}+% darcs diff -t 0.9.8 -t 0.9.10 -- -u+\end{verbatim}+to get a diff in the unified format.  Actually, thanks to the wonders of+getopt you need the ``\verb!--!'' shown above before any arguments to diff.+You can also specify additional arguments to diff using the+\verb!--diff-opts! flag.  The above command would look like this:+\begin{verbatim}+% darcs diff --diff-opts -u -t 0.9.8 -t 0.9.10+\end{verbatim}+This may not seem like an improvement, but it really pays off when you want+to always give diff the same options.  You can do this by adding+\begin{verbatim}+% diff diff-opts -udp+\end{verbatim}+to your \verb!_darcs/prefs/defaults! file.++\begin{code}+get_diff_opts :: [DarcsFlag] -> [String]+get_diff_opts [] = []+get_diff_opts (Unified:fs) = "-u" : get_diff_opts fs+get_diff_opts (DiffFlags f:fs) = f : get_diff_opts fs+get_diff_opts (_:fs) = get_diff_opts fs++has_diff_cmd_flag :: [DarcsFlag] -> Bool+has_diff_cmd_flag (DiffCmd _:_) = True+has_diff_cmd_flag (_:t) = has_diff_cmd_flag t+has_diff_cmd_flag []  = False++-- | Returns the command we should use for diff as a tuple (command, arguments).+-- This will either be whatever the user specified via --diff-command  or the+-- default 'diff_program'.  Note that this potentially involves parsing the+-- user's diff-command, hence the possibility for failure with an exception.+get_diff_cmd_and_args :: [DarcsFlag] -> String -> String+                      -> Either String (String, [String])+get_diff_cmd_and_args opts f1 f2 = helper opts where+  helper (DiffCmd c:_) =+    case parseCmd [ ('1', f1) , ('2', f2) ] c of+    Left err        -> Left $ show err+    Right ([],_)    -> bug $ "parseCmd should never return empty list"+    Right ((h:t),_) -> Right (h,t)+  helper [] = -- if no command specified, use 'diff'+    Right (diff_program, ("-rN":get_diff_opts opts++[f1,f2]))+  helper (_:t) = helper t+\end{code}++If you want to view only the differences to one or more files, you can do+so with a command such as+\begin{verbatim}+% darcs diff foo.c bar.c baz/+\end{verbatim}++\begin{options}+--diff-command+\end{options}++You can use a different program to view differences by including+the flag \verb!--diff-command!, e.g.+\begin{verbatim}+--diff-command 'opendiff %1 %2'.+\end{verbatim}+The \verb!%1! and \verb!%2!  are replaced with the two versions to be+merged.  The above example works with the FileMerge.app tool that comes with+Apple's developer tools.  To use xxdiff, you would use+\begin{verbatim}+--diff-command 'xxdiff %1 %2'+\end{verbatim}+To use \verb!kdiff3!, you can use+\begin{verbatim}+--diff-command 'kdiff3 %1 %2'+\end{verbatim}++Note that the command is split into space-separated words and the first one is+\verb!exec!ed with the rest as arguments---it is not a shell command.  Also+the substitution of the \verb!%! escapes is only done on complete words.+See \ref{resolution} for how you might work around this fact, for example,+with Emacs' Ediff package.++Note also that the \verb!--diff-opts! flag is ignored if you use this option.++\begin{code}+diff_cmd :: [DarcsFlag] -> [String] -> IO ()+diff_cmd opts args = withRepository opts $- \repository -> do+  when (not (null [i | LastN i <- opts])+       && not (null [p | AfterPatch p <- opts])+       ) $+    fail ("using --patch and --last at the same time with the 'diff' command"+         ++ " doesn't make sense. Use --from-patch to create a diff from this"+         ++ " patch to the present, or use just '--patch' to view this specific"+         ++ " patch.")+  formerdir <- getCurrentDirectory+  thename <- return $ just_dir formerdir+  withTempDir ("old-"++thename) $ \odir -> do+    setCurrentDirectory formerdir+    withTempDir ("new-"++thename) $ \ndir -> do+    if first_match opts+       then withCurrentDirectory odir $ first_application repository+       else createPartialsPristineDirectoryTree repository path_list odir+    if second_match opts+       then withCurrentDirectory ndir $ second_application repository+       else do (_, s) <- slurp_recorded_and_unrecorded repository+               let ps = concatMap (get_path_list s) path_list+               clonePaths formerdir ndir ps+    thediff <- withCurrentDirectory (odir ++ "/..") $+                   case path_list of+                   [] -> rundiff (just_dir odir) (just_dir ndir)+                   fs -> vcat `liftM` mapM (\f -> rundiff+                                            (just_dir odir ++ "/" ++ f)+                                            (just_dir ndir ++ "/" ++ f)) fs+    Sealed morepatches <- read_repo repository+    putDocLn $ changelog (get_diff_info opts morepatches)+            $$ thediff+    where rundiff :: String -> String -> IO Doc+          rundiff f1 f2 =+            case get_diff_cmd_and_args opts f1 f2 of+            Left err -> fail err+            Right (d_cmd, d_args) ->+              let other_diff = has_diff_cmd_flag opts in+              do when other_diff $ putStrLn $+                   "Running command '" ++ unwords (d_cmd:d_args) ++ "'"+                 output <- execPipeIgnoreError d_cmd d_args empty+                 when other_diff $ do+                    askUser "Hit return to move on..."+                    return ()+                 return output+          path_list = if null args then [""]+                         else map toFilePath $ getRepoPath $ fix_filepaths opts args+          first_application dir = if StoreInMemory `elem` opts+                                then apply_patches_to_some_files dir path_list $ get_first_match_s opts+                                else get_first_match dir opts+          second_application dir = if StoreInMemory `elem` opts+                                then apply_patches_to_some_files dir path_list $ get_second_match_s opts+                                else get_second_match dir opts+\end{code}++\begin{code}+get_diff_info :: RepoPatch p => [DarcsFlag] -> PatchSet p -> [PatchInfo]+get_diff_info opts ps =+    let pi1s = mapRL info $ concatRL $ if first_match opts+                                       then match_first_patchset opts ps+                                       else ps+        pi2s = mapRL info $ concatRL $ if second_match opts+                                       then match_second_patchset opts ps+                                       else ps+        in pi2s \\ pi1s++changelog :: [PatchInfo] -> Doc+changelog pis = vcat $ map human_friendly pis+\end{code}+
+ src/Darcs/Commands/Dist.lhs view
@@ -0,0 +1,126 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs dist}+\begin{code}+module Darcs.Commands.Dist ( dist ) where+import System.Directory ( setCurrentDirectory )+import Workaround ( getCurrentDirectory )+import System.Exit ( ExitCode(..) )+import System.Cmd ( system )+import Data.Char ( isAlphaNum )+import Control.Monad ( when )++import Darcs.Commands+import Darcs.Arguments+import Darcs.Repository ( amInRepository, withRepoReadLock, ($-), withRecorded )+import Darcs.Repository.Prefs ( get_prefval )+import Darcs.Lock ( withTemp, withTempDir, readBinFile )+import FileName ( own_name, fn2fp, fp2fn )+import Exec ( exec, Redirect(..) )+\end{code}++\options{dist}++\haskell{dist_description}++\begin{code}+dist_description :: String+dist_description =+ "Create a distribution tarball."+\end{code}++\haskell{dist_help} Basically, you will typically use it in a makefile+rule such as+\begin{verbatim}+dist:+    darcs dist --dist-name darcs-`./darcs --version`+\end{verbatim}+\verb!darcs dist! then simply creates a clean copy of the source tree,+which it then tars and gzips.  If you use programs such as autoconf or+automake, you really should run them on the clean tree before tarring it up+and distributing it.  You can do this using the pref value ``predist'',+which is a shell command that is run prior to tarring up the distribution:+\begin{verbatim}+% darcs setpref predist "autoconf && automake"+\end{verbatim}++\begin{code}+dist_help :: String+dist_help =+ "Dist is a handy tool for implementing a \"make dist\" target in your\n"+++ "makefile.  It creates a tarball of the recorded edition of your tree.\n"+\end{code}++\begin{code}+dist :: DarcsCommand+dist = DarcsCommand {command_name = "dist",+                     command_help = dist_help,+                     command_description = dist_description,+                     command_extra_args = 0,+                     command_extra_arg_help = [],+                     command_command = dist_cmd,+                     command_prereq = amInRepository,+                     command_get_arg_possibilities = return [],+                     command_argdefaults = nodefaults,+                     command_advanced_options = [],+                     command_basic_options = [distname_option, working_repo_dir]}+\end{code}++\begin{code}+dist_cmd :: [DarcsFlag] -> [String] -> IO ()+dist_cmd opts _ = withRepoReadLock opts $- \repository -> do+  distname <- get_dist_name opts+  verb <- return $ Verbose `elem` opts+  predist <- get_prefval "predist"+  formerdir <- getCurrentDirectory+  resultfile <- return (formerdir++"/"++distname++".tar.gz")+  withTemp $ \tarfile ->+   withTempDir "darcsdist" $ \tempdir -> do+    setCurrentDirectory (formerdir)+    withRecorded repository (withTempDir (tempdir++"/"++(basename distname))) $ \ddir -> do+     case predist of Nothing -> return ExitSuccess+                     Just pd -> system pd+     setCurrentDirectory (tempdir)+     exec "tar" ["-cf", "-", safename $ basename ddir]+                (Null, File tarfile, AsIs)+     when verb $ withTemp $ \tar_listing -> do+                   exec "tar" ["-tf", "-"]+                        (File tarfile, File tar_listing, Stdout)+                   to <- readBinFile tar_listing+                   putStr to+     exec "gzip" ["-c"]+          (File tarfile, File resultfile, AsIs)+     putStrLn $ "Created dist as "++resultfile+  where+    basename = fn2fp . own_name . fp2fn+    safename n@(c:_) | isAlphaNum c  = n+    safename n = "./" ++ n++guess_repo_name :: IO String+guess_repo_name = do+  pwd <- getCurrentDirectory+  if '/' `elem` pwd+     then return $ reverse $ takeWhile (/='/') $ reverse pwd+     else return "cantguessreponame"++get_dist_name :: [DarcsFlag] -> IO String+get_dist_name (DistName dn:_) = return dn+get_dist_name (_:fs) = get_dist_name fs+get_dist_name _ = guess_repo_name+\end{code}+
+ src/Darcs/Commands/Get.lhs view
@@ -0,0 +1,353 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs get}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Get ( get ) where++import System.Directory ( setCurrentDirectory, doesDirectoryExist, doesFileExist,+                          createDirectory )+import Workaround ( getCurrentDirectory )+import Data.Maybe ( isJust )+import Control.Monad ( when )++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag( WorkDir, Partial, Lazy,+                                    UseFormat2, UseOldFashionedInventory, UseHashedInventory,+                                    SetScriptsExecutable, Quiet, Context, OnePattern ),+                        get_context, pristine_tree, get_inventory_choices, working_repo_dir,+                        partial, reponame,+                        match_one_context, set_default, set_scripts_executable, nolinks,+                        ssh_cm )+import Darcs.Repository ( Repository, withRepository, ($-), withRepoLock, identifyRepositoryFor, read_repo,+                          createPristineDirectoryTree,+                          tentativelyRemovePatches, patchSetToPatches, patchSetToRepository,+                          copyRepository, tentativelyAddToPending,+                          finalizeRepositoryChanges, sync_repo, setScriptsExecutable )+import Darcs.Repository.Format ( identifyRepoFormat, RepoFormat,+                                 RepoProperty ( Darcs2, HashedInventory ), format_has )+import Darcs.Repository.DarcsRepo ( write_inventory )+import qualified Darcs.Repository.DarcsRepo as DR ( read_repo )+import Darcs.Repository ( PatchSet, SealedPatchSet, copy_oldrepo_patches )+import Darcs.Repository.ApplyPatches ( apply_patches )+import Darcs.Repository.Checkpoint ( write_checkpoint_patch, get_checkpoint )+import Darcs.Patch ( RepoPatch, Patch, apply, patch2patchinfo, invert,+                     effect, description )+import Darcs.Patch.Ordered ( (:\/:)(..), RL(..), unsafeUnRL, mapRL, concatRL, reverseRL, lengthFL )+import Darcs.External ( copyFileOrUrl, Cachable(..) )+import Darcs.Patch.Depends ( get_common_and_uncommon, get_patches_beyond_tag )+import Darcs.Repository.Prefs ( set_defaultrepo )+import Darcs.Repository.Motd ( show_motd )+import Darcs.Repository.Pristine ( identifyPristine, createPristineFromWorking, )+import Darcs.Commands.Init ( initialize )+import Darcs.Match ( have_patchset_match, get_one_patchset )+import Darcs.Utils ( catchall, formatPath, withCurrentDirectory )+import Darcs.Progress ( debugMessage )+import Darcs.FilePathUtils ( absolute_dir )+import Printer ( text, vcat, errorDoc, ($$), Doc, putDocLn, )+import Darcs.Lock ( writeBinFile )+import Darcs.Sealed ( Sealed(..), unsafeUnflippedseal )+import Darcs.URL ( is_absolute )+import Darcs.Global ( darcsdir )+#include "impossible.h"+\end{code}+\begin{code}+get_description :: String+get_description =+ "Create a local copy of another repository."+\end{code}++\options{get}++If the remote repository and the current directory are in the same filesystem and+that filesystem supports hard links, get will create hard links for the+patch files, which means that the additional storage space needed will be+minimal.  This is \emph{very} good for your disk usage (and for the speed+of running get), so if you want multiple copies of a repository, I strongly+recommend first running \verb!darcs get! to get yourself one copy, and then+running \verb!darcs get! on that copy to make any more you like.  The only+catch is that the first time you run \verb!darcs push! or \verb!darcs pull!+from any of these second copies, by default they will access your first+copy---which may not be what you want.++You may specify the name of the repository created by providing a second+argument to get, which is a directory name.++\begin{code}+get_help :: String+get_help =+ "Get is used to get a local copy of a repository.\n"+\end{code}+\begin{code}+get :: DarcsCommand+get = DarcsCommand {command_name = "get",+                    command_help = get_help,+                    command_description = get_description,+                    command_extra_args = -1,+                    command_extra_arg_help = ["<REPOSITORY>", "[<DIRECTORY>]"],+                    command_command = get_cmd,+                    command_prereq = contextExists,+                    command_get_arg_possibilities = return [],+                    command_argdefaults = nodefaults,+                    command_advanced_options = [ssh_cm] ++ command_advanced_options initialize,+                    command_basic_options = [reponame,+                                            partial,+                                            match_one_context,+                                            set_default,+                                            set_scripts_executable,+                                            nolinks, pristine_tree,+                                             get_inventory_choices,+                                             working_repo_dir]}+\end{code}+\begin{code}+get_cmd :: [DarcsFlag] -> [String] -> IO ()+get_cmd opts [inrepodir, outname] = get_cmd (WorkDir outname:opts) [inrepodir]+get_cmd orig_opts [inrepodir] = do+  debugMessage "Starting work on get..."+  former_dir <- getCurrentDirectory+  let opts = fix_context former_dir orig_opts+  repodir <- absolute_dir inrepodir+  show_motd opts repodir+  when (Partial `elem` opts) $ debugMessage "Reading checkpoint..."+  mysimplename <- make_repo_name opts repodir+  createDirectory mysimplename+  setCurrentDirectory mysimplename+  rfsource_or_e <- identifyRepoFormat repodir+  rfsource <- case rfsource_or_e of Left e -> fail e+                                    Right x -> return x+  debugMessage $ "Found the format of "++repodir++"..."+  when (format_has Darcs2 rfsource && UseOldFashionedInventory `elem` opts) $+    putInfo $ text "Warning: 'old-fashioned-inventory' is ignored with a darcs-2 repository\n"+  let opts' = if format_has Darcs2 rfsource+              then UseFormat2:filter (/= UseOldFashionedInventory) opts+              else if format_has HashedInventory rfsource &&+                      not (UseOldFashionedInventory `elem` opts)+                   then UseHashedInventory:filter (/= UseFormat2) opts+                   else filter (/= UseFormat2) opts+  (command_command initialize) opts' []+  debugMessage "Finished initializing new directory."+  set_defaultrepo repodir opts++  rf_or_e <- identifyRepoFormat "."+  rf <- case rf_or_e of Left e -> fail e+                        Right x -> return x+  if format_has HashedInventory rf -- refactor this into repository+    then writeBinFile (darcsdir++"/hashed_inventory") ""+    else write_inventory "." (NilRL:<:NilRL :: PatchSet Patch)++  if not (null [p | OnePattern p <- opts]) -- --to-match given+     && not (Partial `elem` opts) && not (Lazy `elem` opts)+    then withRepository opts $- \repository -> do+      debugMessage "Using economical get --to-match handling"+      fromrepo <- identifyRepositoryFor  repository repodir+      patches_to_get <- get_one_patchset fromrepo opts+      patchSetToRepository patches_to_get opts+      debugMessage "Finished converting selected patch set to new repository"+    else copy_repo_and_go_to_chosen_version opts repodir rfsource rf putInfo+        where am_informative = not $ Quiet `elem` orig_opts+              putInfo s = when am_informative $ putDocLn s++get_cmd _ _ = fail "You must provide 'get' with either one or two arguments."++-- called by get_cmd+-- assumes that the target repo of the get is the current directory, and that an inventory in the+-- right format has already been created.+copy_repo_and_go_to_chosen_version :: [DarcsFlag] -> String -> RepoFormat -> RepoFormat -> (Doc -> IO ()) -> IO ()+copy_repo_and_go_to_chosen_version opts repodir rfsource rf putInfo = do+  withRepository opts $- \repository -> do+   if format_has HashedInventory rf || format_has HashedInventory rfsource+     then do debugMessage "Identifying and copying repository..."+             identifyRepositoryFor repository repodir >>= copyRepository+             when (SetScriptsExecutable `elem` opts) setScriptsExecutable+     else copy_repo_old_fashioned repository opts repodir+  withRepository opts $- \repository -> go_to_chosen_version repository putInfo opts+  putInfo $ text "Finished getting."++\end{code}++\begin{code}+make_repo_name :: [DarcsFlag] -> FilePath -> IO String+make_repo_name (WorkDir n:_) _ =+    do exists <- doesDirectoryExist n+       file_exists <- doesFileExist n+       if exists || file_exists+          then fail $ "Directory or file named '" ++ n ++ "' already exists."+          else return n+make_repo_name (_:as) d = make_repo_name as d+make_repo_name [] d =+  case dropWhile (=='.') $ reverse $+       takeWhile (\c -> c /= '/' && c /= ':') $+       dropWhile (=='/') $ reverse d of+  "" -> modify_repo_name "anonymous_repo"+  base -> modify_repo_name base++modify_repo_name :: String -> IO String+modify_repo_name name =+    if head name == '/'+    then mrn name (-1)+    else do cwd <- getCurrentDirectory+            mrn (cwd ++ "/" ++ name) (-1)+ where+  mrn :: String -> Int -> IO String+  mrn n i = do+    exists <- doesDirectoryExist thename+    file_exists <- doesFileExist thename+    if not exists && not file_exists+       then do when (i /= -1) $+                    putStrLn $ "Directory '"++ n +++                               "' already exists, creating repository as '"+++                               thename ++"'"+               return thename+       else mrn n $ i+1+    where thename = if i == -1 then n else n++"_"++show i+\end{code}++\begin{options}+--context, --tag, --to-patch, --to-match+\end{options}+If you want to get a specific version of a repository, you have a few+options.  You can either use the \verb!--tag!, \verb!--to-patch! or+\verb!--to-match! options, or you can use the \verb!--context=FILENAME!+option, which specifies a file containing a context generated with+\verb!darcs changes --context!.  This allows you (for example) to include in+your compiled program an option to output the precise version of the+repository from which it was generated, and then perhaps ask users to+include this information in bug reports.++Note that when specifying \verb!--to-patch! or \verb!--to-match!, you may+get a version of your code that has never before been seen, if the patches+have gotten themselves reordered.  If you ever want to be able to precisely+reproduce a given version, you need either to tag it or create a context+file.++\begin{code}+contextExists :: [DarcsFlag] -> IO (Either String FilePath)+contextExists orig_opts = do+   former_dir <- getCurrentDirectory+   let opts = fix_context former_dir orig_opts+   case get_context opts of+     Nothing -> return $ Right ""+     Just f  -> do exists <- doesFileExist f+                   if exists+                      then return $ Right ""+                      else return . Left $ "Context file "++f++" does not exist"++go_to_chosen_version :: RepoPatch p => Repository p -> (Doc -> IO ())+                     -> [DarcsFlag] -> IO ()+go_to_chosen_version repository putInfo opts =+    when (have_patchset_match opts) $ do+       debugMessage "Going to specified version..."+       Sealed patches <- read_repo repository+       context <- get_one_patchset repository opts+       let (_,us':\/:them') = get_common_and_uncommon (patches, context)+       case them' of+           NilRL:<:NilRL -> return ()+           _ -> errorDoc $ text "Missing these patches from context:"+                        $$ (vcat $ mapRL description $ head $ unsafeUnRL them')+       let ps = patchSetToPatches us'+       putInfo $ text $ "Unapplying " ++ (show $ lengthFL ps) ++ " " +++                   (patch_or_patches $ lengthFL ps)+       withRepoLock opts $- \_ ->+           do tentativelyRemovePatches repository opts ps+              tentativelyAddToPending repository opts $ invert $ effect ps+              finalizeRepositoryChanges repository+              apply opts (invert $ effect ps) `catch` \e ->+                  fail ("Couldn't undo patch in working dir.\n" ++ show e)+              sync_repo repository++patch_or_patches :: Int -> String+patch_or_patches 1 = "patch."+patch_or_patches _ = "patches."++\end{code}++\begin{options}+--partial+\end{options}+Only get the patches since the last checkpoint. This will save time,+bandwidth and disk space, at the expense of losing the history before+the checkpoint.++\begin{options}+--no-pristine-tree+\end{options}+In order to save disk space, you can use {\tt get} with the+\verb|--no-pristine-tree| flag to create a repository with no pristine+tree.  Please see Section~\ref{disk-usage} for more information.+++\begin{code}++copy_repo_old_fashioned :: RepoPatch p => Repository p -> [DarcsFlag] -> String -> IO ()+copy_repo_old_fashioned repository opts repodir = do+  myname <- getCurrentDirectory+  fromrepo <- identifyRepositoryFor repository repodir+  mch <- get_checkpoint fromrepo+  Sealed patches <- read_repo fromrepo+  debugMessage "Getting the inventory..."+  write_inventory "." patches+  debugMessage "Copying patches..."+  copy_oldrepo_patches opts fromrepo "."+  debugMessage "Patches copied"+  Sealed local_patches <- DR.read_repo opts "." :: IO (SealedPatchSet Patch)+  debugMessage "Repo read"+  repo_is_local <- doesDirectoryExist repodir+  debugMessage $ "Repo local: " ++ formatPath (show repo_is_local)+  if repo_is_local && not (Partial `elem` opts)+     then do+       debugMessage "Copying prefs"+       copyFileOrUrl opts+          (repodir++"/"++darcsdir++"/prefs/prefs") (darcsdir++"/prefs/prefs") (MaxAge 600)+          `catchall` return ()+       debugMessage "Writing working directory"+       createPristineDirectoryTree fromrepo myname+       withCurrentDirectory myname $ do+           -- note: SetScriptsExecutable is normally checked in PatchApply+           -- but darcs get on local repositories does not apply patches+           if SetScriptsExecutable `elem` opts+              then setScriptsExecutable+              else return ()+     else do+       setCurrentDirectory myname+       if Partial `elem` opts && isJust mch+          then let p_ch = fromJust mch+                   pi_ch = patch2patchinfo p_ch+                   needed_patches = reverseRL $ concatRL $ unsafeUnflippedseal $+                                    get_patches_beyond_tag pi_ch local_patches+                   in do write_checkpoint_patch p_ch+                         apply opts p_ch `catch`+                             \e -> fail ("Bad checkpoint!\n" ++ show e)+                         apply_patches opts needed_patches+          else apply_patches opts $ reverseRL $ concatRL local_patches+  debugMessage "Writing the pristine"+  pristine <- identifyPristine+  createPristineFromWorking pristine+  setCurrentDirectory myname+  debugMessage "Syncing the repository..."+  sync_repo repository+  debugMessage "Repository synced."++\end{code}++\begin{code}+fix_context :: FilePath -> [DarcsFlag] -> [DarcsFlag]+fix_context _ o@(Context f:_) | is_absolute f = o+fix_context former (Context f:os) = Context (former++"/"++f):os+fix_context former (o:os) = o : fix_context former os+fix_context _ [] = []+\end{code}
+ src/Darcs/Commands/Help.lhs view
@@ -0,0 +1,106 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs help}+\label{help}++You could also call \verb|help| as a command.  This is equivalent to calling+darcs --help.  +the \verb|--help| to that command.  For example, \verb|darcs help query manifest|+is equivalent to \verb|darcs query manifest --help|.++\begin{code}+module Darcs.Commands.Help ( help, command_control_list, print_version ) where+import System.Exit ( ExitCode(..), exitWith )++import Autoconf( darcs_version )+import Darcs.Commands ( CommandControl(Command_data), DarcsCommand(..),+                        disambiguate_commands, CommandArgs(..),+                        get_command_help,+                       nodefaults, +                       usage )+import Darcs.Arguments ( DarcsFlag(..), help_on_match )+import Darcs.External ( viewDoc )+import Darcs.Patch.Match ( helpOnMatchers )+import Printer ( text )+import qualified Darcs.TheCommands as TheCommands+\end{code}++\options{help}++\haskell{help_description}+\begin{code}+help_description :: String+help_description = "Display help for darcs or a single command."+\end{code}+\haskell{help_help} ++\begin{code}+help_help :: String+help_help =+ "help displays usage information for darcs in general or for a single\n" +++ "command (for example, darcs help query manifest).\n\n"+\end{code}++\begin{code}+help :: DarcsCommand+help = DarcsCommand {command_name = "help",+                     command_help = help_help,+                     command_description = help_description,+                     command_extra_args = -1,+                     command_extra_arg_help = ["[<DARCS_COMMAND> [DARCS_SUBCOMMAND]]  "],+                     command_command = help_cmd,+                     command_prereq = \_ -> return $ Right "", +                     command_get_arg_possibilities = return [],+                     command_argdefaults = nodefaults,+                     command_advanced_options = [],+                     command_basic_options = [help_on_match]}+\end{code}++\begin{code}+help_cmd :: [DarcsFlag] -> [String] -> IO ()+help_cmd opts [] =+    do viewDoc $ text $+         case () of _ | HelpOnMatch `elem` opts -> helpOnMatchers+                      | otherwise -> usage command_control_list+       exitWith $ ExitSuccess++help_cmd _ (cmd:args) =+    do let disambiguated = disambiguate_commands command_control_list cmd args+       case disambiguated of+         Left err       -> fail err+         Right (cmds,_) ->+           let msg = case cmds of+                     CommandOnly c       -> get_command_help Nothing  c+                     SuperCommandOnly c  -> get_command_help Nothing  c+                     SuperCommandSub c s -> get_command_help (Just c) s+           in viewDoc $ text msg+       exitWith $ ExitSuccess+\end{code}++\begin{code}+print_version :: IO () +print_version = putStrLn $ "darcs version " ++ darcs_version+\end{code}++\begin{code}+-- avoiding a module import cycle between Help and TheCommands+command_control_list :: [CommandControl] +command_control_list =+  Command_data help : TheCommands.command_control_list+\end{code}+
+ src/Darcs/Commands/Init.lhs view
@@ -0,0 +1,156 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs initialize}\label{initialize}+\begin{code}+module Darcs.Commands.Init ( initialize, initialize_cmd ) where+import System.Directory ( createDirectory )+import System.IO.Error ( isAlreadyExistsError )++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag, pristine_tree, working_repo_dir,+                        inventory_choices )++import Darcs.Patch.Set ( PatchSet )+import Darcs.Patch ( Patch )++import Darcs.Patch.Ordered ( RL(..) )+import Darcs.Repository.Prefs ( write_default_prefs )+import Darcs.Repository.Format ( create_repo_format, writeRepoFormat,+                                 RepoProperty ( HashedInventory ), format_has )+import Darcs.Repository.Pristine ( createPristine, flagsToPristine )+import Darcs.Lock ( writeBinFile )+import Darcs.Repository.DarcsRepo ( write_inventory )+import Darcs.Repository ( amNotInRepository )+import Darcs.Global ( darcsdir )+\end{code}++\options{initialize}++\haskell{initialize_description}++\begin{code}+initialize_description :: String+initialize_description = "Initialize a new source tree as a darcs repository."+\end{code}+Call \verb|initialize| once for each project you work on. Run it from the top+level directory of the project, with the project files already there. +\verb|initialize| will set up all the directories and files darcs needs in order to+start keeping track of revisions for your project.++\begin{code}+initialize_help :: String+initialize_help =+ "Call 'initialize' once for each project you work on. Run it from the top  \n"+++ "level directory of the project, with the project files already there.   \n"+++ "'initialize' will set up all the directories and files darcs needs in order to \n"+++ " start keeping track of revisions for your project.  \n"+\end{code}++\begin{code}+initialize :: DarcsCommand+initialize = DarcsCommand {command_name = "initialize",+                         command_help = initialize_help,+                         command_description = initialize_description,+                         command_extra_args = 0,+                         command_extra_arg_help = [],+                         command_prereq = amNotInRepository,+                         command_command = initialize_cmd,+                         command_get_arg_possibilities = return [],+                         command_argdefaults = nodefaults,+                         command_advanced_options = [],+                         command_basic_options = [pristine_tree, inventory_choices,+                                                  working_repo_dir]}+\end{code}++\verb|initialize| creates a single directory named \verb|_darcs|, with contents+for internal use. The one subdictory of interest to users is+\verb'_darcs/prefs', which will include an empty file \verb'_darcs/prefs/motd'+(see Section~\ref{motd}), as well as files named \verb'boring' and+\verb'binaries', which contain useful defaults as described in Sections+\ref{boring} \emph{et seq.}++\begin{options}+--old-fashioned-inventory+--hashed+--darcs-2+\end{options}++These options describe possible repository formats to use. ++\verb'old-fashioned-inventory' is the default. While it has minimal features, it is the best tested and the limitations+it does have are well known.++\verb'hashed' Offers several features while still being compatible with old-fashioned repositories. The specific features are:++\begin{itemize}  ++\item The hashed format allows for greater atomicity of operations. This makes for greater safety and simultaneously greater efficiency. These benefits, however, have not been fully realized in this release. For instance, with a hashed repository, there is no need for darcs push to require a repository lock, so you could record patches while waiting for a push to finish (for instance, if it's waiting on the test suite).++\item The \verb!_darcs/pristine! directory no longer holds the pristine+cache. This disallows certain hackish short-cuts, but also dramatically+reduces the danger of third-party programs (e.g. DreamWeaver) recursing+into the pristine cache and corrupting darcs repositories.++\item Darcs get can optionally operate in a much faster ``lazy''+fashion, meaning that patches are downloaded only when they are+needed. This gives us much of the benefits of --partial repositories,+without most of their disadvantages. This approach, however, does have+several new dangers. First, some operations may unexpectedly require the+download of large numbers of patches, which could be slow (but you could+always interrupt with \verb!^C!). Secondly, if the source repository disappears,+or you lose network connectivity, some operations may fail.++\item Darcs now supports caching of patches and file contents to reduce bandwidth and save disk space. It greatly speeds up a number of operations, and is essentially transparent. The only reason we don't enable it by default is because it creates a large directory in ~/.darcs/cache without the user's explicit consent.++\end{itemize}++\verb'darcs-2' Enables all available features, and requiring that all repos for a project use the same format. In addition to the features of the \verb'hashed' format described above, the \verb'darcs-2' format also enables the following:++\begin{itemize}++\item It should no longer be possible to confuse darcs or freeze it indefinitely by merging conflicting changes. ++\item Identical primitive changes no longer conflict. This is a long-requested feature, and has far-reaching implications. ++\end{itemize}++\begin{options}+--no-pristine-tree+\end{options}+In order to save disk space, you can use \verb|initialize| with the+\verb|--no-pristine-tree| flag to create a repository with no pristine+tree.  Please see Section~\ref{disk-usage} for more information.++\begin{code}+initialize_cmd :: [DarcsFlag] -> [String] -> IO ()+initialize_cmd opts _ = do+    createDirectory darcsdir `catch`+        (\e-> if isAlreadyExistsError e+              then fail "Tree has already been initialized!"+              else fail $ "Error creating directory `"++darcsdir++"'.")+    createPristine $ flagsToPristine opts+    createDirectory $ darcsdir ++ "/patches"+    createDirectory $ darcsdir ++ "/prefs"+    write_default_prefs+    let rf = create_repo_format opts+    writeRepoFormat rf (darcsdir++"/format")+    if format_has HashedInventory rf+        then writeBinFile (darcsdir++"/hashed_inventory") ""+        else write_inventory "." (NilRL:<:NilRL :: PatchSet Patch) -- YUCK!+\end{code}+
+ src/Darcs/Commands/MarkConflicts.lhs view
@@ -0,0 +1,103 @@+%  Copyright (C) 2002-2003,2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs mark-conflicts}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.MarkConflicts ( markconflicts, resolve ) where+import System.Exit ( ExitCode(..), exitWith )+import Darcs.SignalHandler ( withSignalsBlocked )+import Control.Monad ( when )++import Darcs.Commands ( DarcsCommand(..), nodefaults, command_alias )+import Darcs.Arguments ( DarcsFlag, ignoretimes, working_repo_dir, umask_option )+import Darcs.Repository ( withRepoLock, ($-), amInRepository, add_to_pending,+                    applyToWorking,+                    read_repo, sync_repo, get_unrecorded_unsorted,+                    )+import Darcs.Patch ( invert )+import Darcs.Patch.Ordered ( FL(..) )+import Darcs.Sealed ( Sealed(Sealed) )+import Darcs.Resolution ( patchset_conflict_resolutions )+import Darcs.Utils ( promptYorn )+#include "impossible.h"+\end{code}+\begin{code}+markconflicts_description :: String+markconflicts_description =+ "Mark any conflicts to the working copy for manual resolution."+\end{code}++\options{mark-conflicts}++\haskell{mark-conflicts_help}++\begin{code}+markconflicts_help :: String+markconflicts_help =+ "Mark-conflicts is used to mark and resolve any conflicts that may exist in a\n"+++ "repository.  Note that this trashes any unrecorded changes in the working\n"+++ "copy.\n"+\end{code}+\begin{code}+markconflicts :: DarcsCommand+markconflicts = DarcsCommand {command_name = "mark-conflicts",+                              command_help = markconflicts_help,+                              command_description = markconflicts_description,+                              command_extra_args = 0,+                              command_extra_arg_help = [],+                              command_command = markconflicts_cmd,+                              command_prereq = amInRepository,+                              command_get_arg_possibilities = return [],+                              command_argdefaults = nodefaults,+                              command_advanced_options = [umask_option],+                              command_basic_options = [ignoretimes,+                                                      working_repo_dir]}+\end{code}++\begin{code}+markconflicts_cmd :: [DarcsFlag] -> [String] -> IO ()+markconflicts_cmd opts [] = withRepoLock opts $- \repository -> do+  pend <- get_unrecorded_unsorted repository+  Sealed r <- read_repo repository+  Sealed res <- return $ patchset_conflict_resolutions r+  case res of NilFL -> do putStrLn "No conflicts to mark."+                          exitWith ExitSuccess+              _ -> return ()+  case pend of+    NilFL -> return ()+    _ ->      do yorn <- promptYorn+                         ("This will trash any unrecorded changes"+++                          " in the working directory.\nAre you sure? ")+                 when (yorn /= 'y') $ exitWith ExitSuccess+                 applyToWorking repository opts (invert pend) `catch` \e ->+                    bug ("Can't undo pending changes!" ++ show e)+                 sync_repo repository+  withSignalsBlocked $+    do add_to_pending repository res+       applyToWorking repository opts res `catch` \e ->+           bug ("Problem marking conflicts in mark-conflicts!" ++ show e)+  putStrLn "Finished marking conflicts."+markconflicts_cmd _ _ = impossible+\end{code}++% resolve - not documented because hidden++\begin{code}+resolve :: DarcsCommand+resolve = command_alias "resolve" markconflicts+\end{code}
+ src/Darcs/Commands/Mv.lhs view
@@ -0,0 +1,209 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs mv}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Mv ( mv, move ) where+import Control.Monad ( when, unless )+import Data.Maybe ( catMaybes )+import Darcs.SignalHandler ( withSignalsBlocked )++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag( AllowCaseOnly ),+                         rejectNonRepo, fix_filepaths, working_repo_dir,+                        list_files, allow_caseonly, umask_option,+                      )+import Darcs.FilePathUtils ( (///) )+import Darcs.RepoPath ( toFilePath, sp2fn )+import System.Directory ( renameDirectory )+import Workaround ( renameFile )+import Darcs.Repository ( Repository, withRepoLock, ($-), amInRepository,+                    slurp_pending, add_to_pending,+                  )+import Darcs.Patch.Ordered ( FL(..), unsafeFL )+import qualified Darcs.Patch+import Darcs.Patch ( RepoPatch, Prim )+import Darcs.SlurpDirectory ( Slurpy, slurp, slurp_has, slurp_has_anycase,+                        slurp_remove, slurp_hasdir, slurp_hasfile )+import FileName ( fp2fn, fn2fp, super_name )+#include "impossible.h"+\end{code}++\begin{code}+mv_description :: String+mv_description =+ "Move/rename one or more files or directories."+\end{code}++\options{mv}++\haskell{mv_help} This is why ``mv'' isn't called ``move'', since it is+really almost equivalent to the unix command ``mv''.++\begin{options}+--case-ok+\end{options}++Darcs mv will by default refuse to rename a file if there already exists a+file having the same name apart from case.  This is because doing so could+create a repository that could not be used on file systems that are case+insensitive (such as Apple's HFS+).  You can override this by with the flag+\verb!--case-ok!.++\begin{code}+mv_help :: String+mv_help =+ "Darcs mv needs to be called whenever you want to move files or\n"+++ "directories. Unlike remove, mv actually performs the move itself in your\n"+++ "working copy.\n"+\end{code}++\begin{code}+mv :: DarcsCommand+mv = DarcsCommand {command_name = "mv",+                   command_help = mv_help,+                   command_description = mv_description,+                   command_extra_args = -1,+                   command_extra_arg_help = ["[FILE or DIRECTORY]..."],+                   command_command = mv_cmd,+                   command_prereq = amInRepository,+                   command_get_arg_possibilities = list_files,+                   command_argdefaults = nodefaults,+                   command_advanced_options = [umask_option],+                   command_basic_options = [allow_caseonly, working_repo_dir]}+mv_cmd :: [DarcsFlag] -> [String] -> IO ()+mv_cmd _ [] = fail "You must specify at least two arguments for mv"+mv_cmd _ [_] = fail "You must specify at least two arguments for mv"+\end{code}++\begin{code}+mv_cmd opts args@[_,_] = withRepoLock opts $- \repository -> do+  two_files <- rejectNonRepo $ fix_filepaths opts args+  [old,new] <- return $ case two_files of+                        [_,_] -> two_files+                        [_] -> error "Cannot rename a file or directory onto itself!"+                        xs -> bug $ "Problem in mv_cmd: " ++ show xs+  work <- slurp "."+  let old_fp = toFilePath old+      new_fp = toFilePath new+  if slurp_hasdir (sp2fn new) work && slurp_has old_fp work+   then move_to_dir repository opts [old_fp] new_fp+   else do+    cur <- slurp_pending repository+    addpatch <- check_new_and_old_filenames opts cur work (old_fp,new_fp)+    withSignalsBlocked $ do+      case addpatch of+        Nothing -> add_to_pending repository (Darcs.Patch.move old_fp new_fp :>: NilFL)+        Just p -> add_to_pending repository (p :>: Darcs.Patch.move old_fp new_fp :>: NilFL)+      move_file_or_dir work old_fp new_fp+\end{code}++\begin{code}+mv_cmd opts args =+   withRepoLock opts $- \repository -> do+     relpaths <- map toFilePath `fmap` (rejectNonRepo $ fix_filepaths opts args)+     let moved = init relpaths+         finaldir = last relpaths+     move_to_dir repository opts moved finaldir++move_to_dir :: RepoPatch p => Repository p -> [DarcsFlag] -> [FilePath] -> FilePath -> IO ()+move_to_dir repository opts moved finaldir =+  let movefns = map (reverse.takeWhile (/='/').reverse) moved+      movetargets = map (finaldir///) movefns+      movepatches = map2 Darcs.Patch.move moved movetargets+  in do+    cur <- slurp_pending repository+    work <- slurp "."+    addpatches <- mapM (check_new_and_old_filenames opts cur work) $ zip moved movetargets+    withSignalsBlocked $ do+      add_to_pending repository $ unsafeFL $ catMaybes addpatches ++ movepatches+      sequence_ $ map2 (move_file_or_dir work) moved movetargets++check_new_and_old_filenames+    :: [DarcsFlag] -> Slurpy -> Slurpy -> (FilePath, FilePath) -> IO (Maybe Prim)+check_new_and_old_filenames opts cur work (old,new) = do+  maybe_add_file_thats_been_moved <-+     if slurp_has old work -- We need to move the object+     then do unless (slurp_hasdir (super_name $ fp2fn new) work) $+                    fail $ "The target directory " +++                             (fn2fp $ super_name $ fp2fn new)+++                             " isn't known in working directory, did you forget to add it?"+             when (it_has new work) $ fail $ already_exists "working directory"+             return Nothing+     else do unless (slurp_has new work) $ fail $ doesnt_exist "working directory"+             return $ Just $ Darcs.Patch.addfile old+  if slurp_has old cur+     then do unless (slurp_hasdir (super_name $ fp2fn new) cur) $+                    fail $ "The target directory " +++                             (fn2fp $ super_name $ fp2fn new)+++                             " isn't known in working directory, did you forget to add it?"+             when (it_has new cur) $ fail $ already_exists "repository"+     else fail $ doesnt_exist "repository"+  return maybe_add_file_thats_been_moved+    where it_has f s = +            let ms2 = slurp_remove (fp2fn old) s+            in case ms2 of+               Nothing -> False+               Just s2 -> if AllowCaseOnly `elem` opts +                          then slurp_has f s2+                          else slurp_has_anycase f s2+          already_exists what_slurpy =+              if AllowCaseOnly `elem` opts+              then "A file or dir named "++new++" already exists in "+                       ++ what_slurpy ++ "."+              else "A file or dir named "++new++" (or perhaps differing"+++                       " only in case)\nalready exists in "+++                       what_slurpy ++ ".\n"+++                   "Use --case-ok to allow files differing only in case."+          doesnt_exist what_slurpy =+              "There is no file or dir named " ++ old +++              " in the "++ what_slurpy ++ "."++move_file_or_dir :: Slurpy -> FilePath -> FilePath -> IO ()+move_file_or_dir work old new =+    if slurp_hasfile (fp2fn old) work+       then renameFile old new+       else if slurp_hasdir (fp2fn old) work+            then renameDirectory old new+            else return ()++map2 :: (a -> b -> c) -> [a] -> [b] -> [c]+map2 _ [] [] = []+map2 f (a:as) (b:bs) = f a b : map2 f as bs+map2 _ _ _ = bug "map2 in mv given lists of differing lengths!"+\end{code}+++% move - Note: not a subsection because not to be documented.++\begin{code}+move_description :: String+move_description =+ "Alias for 'mv'"++move_help :: String+move_help =+ "Alias for 'mv'\n" ++ mv_help++move :: DarcsCommand+move = mv {command_name = "move",+           command_help = move_help,+           command_description = move_description }+\end{code}++
+ src/Darcs/Commands/Optimize.lhs view
@@ -0,0 +1,320 @@+%  Copyright (C) 2003-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs optimize}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Optimize ( optimize ) where+import Control.Monad ( when, unless, liftM )+import Data.Maybe ( isJust )+import Text.Regex ( mkRegex, matchRegex )+import System.Directory ( getDirectoryContents, doesDirectoryExist )++import Darcs.Hopefully ( hopefully, info )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag( Compress, UnCompress,+                                    NoCompress, Reorder,+                                    TagName, CheckPoint,+                                    Relink, RelinkPristine ),+                        tagname, checkpoint, reorder_patches,+                        uncompress_nocompress,+                        relink, relink_pristine, sibling,+                        flagsToSiblings,+                        working_repo_dir, umask_option,+                      )+import Darcs.Repository.Prefs ( defaultrepo )+import Darcs.Repository ( Repository, PatchSet, withRepoLock, ($-), withGutsOf,+                          read_repo, optimizeInventory, slurp_recorded,+                          tentativelyReplacePatches, cleanRepository,+                          amInRepository, finalizeRepositoryChanges )+import Darcs.Repository.Checkpoint ( write_checkpoint )+import Darcs.Patch.Ordered ( RL(..), unsafeUnRL, (+<+), mapFL_FL, reverseRL, mapRL, concatRL )+import Darcs.Patch.Info ( PatchInfo, just_name, human_friendly )+import Darcs.Patch ( RepoPatch )+import FastPackedString ( gzReadFilePS )+import Darcs.Patch.Depends ( deep_optimize_patchset, slightly_optimize_patchset,+                 get_patches_beyond_tag, get_patches_in_tag,+               )+import Darcs.Lock ( maybeRelink, gzWriteAtomicFilePS, writeAtomicFilePS )+import Darcs.Utils ( withCurrentDirectory )+import Darcs.Progress ( debugMessage )+import Printer ( putDocLn, text, ($$) )+import Darcs.SlurpDirectory ( slurp, list_slurpy_files )+import Darcs.Repository.Pristine ( identifyPristine, pristineDirectory )+import Darcs.Sealed ( Sealed(..), FlippedSeal(..), unsafeUnseal, liftSM )+import Darcs.Global ( darcsdir )+#include "impossible.h"+\end{code}+\begin{code}+optimize_description :: String+optimize_description =+ "Optimize the repository."+\end{code}++\options{optimize}++\haskell{optimize_help}++\begin{code}+optimize_help :: String+optimize_help =+ "Optimize can help to improve the performance of your repository in a number of cases.\n"+\end{code}+\begin{code}+optimize :: DarcsCommand+optimize = DarcsCommand {command_name = "optimize",+                         command_help = optimize_help,+                         command_description = optimize_description,+                         command_extra_args = 0,+                         command_extra_arg_help = [],+                         command_command = optimize_cmd,+                         command_prereq = amInRepository,+                         command_get_arg_possibilities = return [],+                         command_argdefaults = nodefaults,+                         command_advanced_options = [uncompress_nocompress, umask_option],+                         command_basic_options = [checkpoint,+                                                 tagname,+                                                 working_repo_dir,+                                                 reorder_patches,+                                                 sibling, relink,+                                                 relink_pristine]}+\end{code}+\begin{code}+optimize_cmd :: [DarcsFlag] -> [String] -> IO ()+optimize_cmd origopts _ = withRepoLock opts $- \repository -> do+    cleanRepository repository+    do_reorder opts repository+    do_optimize_inventory repository+    when (CheckPoint `elem` opts) $ do_checkpoint opts repository+    when (Compress `elem` opts || UnCompress `elem` opts) $ optimize_compression opts+    when (Relink `elem` opts || (RelinkPristine `elem` opts)) $+        do_relink opts repository+    putStrLn "Done optimizing!"+  where opts = if UnCompress `elem` origopts then NoCompress:origopts else origopts+is_tag :: PatchInfo -> Bool+is_tag pinfo = take 4 (just_name pinfo) == "TAG "+\end{code}++Optimize always writes out a fresh copy of the inventory that minimizes+the amount of inventory that need be downloaded when people pull from the+repository.++Specifically, it breaks up the inventory on the most recent tag.  This speeds+up most commands when run remotely, both because a smaller file needs to be+transfered (only the most recent inventory).  It also gives a+guarantee that all the patches prior to a given tag are included in that tag,+so less commutation and history traversal is needed.  This latter issue can+become very important in large repositories.++\begin{code}+do_optimize_inventory :: RepoPatch p => Repository p -> IO ()+do_optimize_inventory repository = do+    debugMessage "Writing out a nice copy of the inventory."+    optimizeInventory repository+    debugMessage "Done writing out a nice copy of the inventory."+\end{code}++\begin{options}+--checkpoint, --tag+\end{options}++If you use the \verb!--checkpoint! option, optimize creates a checkpoint patch+for a tag.  You can specify the tag with the \verb!--tag! option, or+just let darcs choose the most recent tag.  Note that optimize+\verb!--checkpoint! will fail when used on a ``partial'' repository.  Also,+the tag that is to be checkpointed must not be preceded by any patches+that are not included in that tag.  If that is the case, no checkpointing+is done.++The created checkpoint is used by the \verb!--partial! flag to +\verb!get! and \verb!check!. This allows for users to retrieve+a working repository with limited history with a savings of disk+space and bandwidth. ++++\begin{code}+do_checkpoint :: RepoPatch p => [DarcsFlag] -> Repository p -> IO ()+do_checkpoint opts repository = do+    mpi <- get_tag opts repository+    case mpi of+      Nothing -> return ()+      Just pinfo -> do putDocLn $ text "Checkpointing tag:"+                               $$ human_friendly pinfo+                       write_checkpoint repository pinfo++get_tag :: RepoPatch p => [DarcsFlag] -> Repository p -> IO (Maybe PatchInfo)+get_tag [] r = do Sealed ps <- read_repo r+                  case filter is_tag $ lasts $ mapRL (mapRL info) ps of+                      [] -> do putStrLn "There is no tag to checkpoint!"+                               return Nothing+                      (pinfo:_) -> return $ Just pinfo+get_tag (TagName t:_) r =+    do Sealed ps <- read_repo r+       case filter (match_tag t) $ lasts $ mapRL (mapRL info) ps of+         (pinfo:_) -> return $ Just pinfo+         _ -> case filter (match_tag t) $+                   lasts $ mapRL (mapRL info) $ deep_optimize_patchset ps of+              (pinfo:_) -> return $ Just pinfo+              _ -> do putStr "Cannot checkpoint any tag "+                      putStr $ "matching '"++t++"'\n"+                      return Nothing+get_tag (_:fs) r = get_tag fs r++lasts :: [[a]] -> [a]+lasts [] = []+lasts (x@(_:_):ls) = last x : lasts ls+lasts ([]:ls) = lasts ls+\end{code}++\begin{code}+mymatch :: String -> PatchInfo -> Bool+mymatch r = match_name $ matchRegex (mkRegex r)+match_name :: (String -> Maybe a) -> PatchInfo -> Bool+match_name ch pinfo = isJust $ ch (just_name pinfo)+match_tag :: String -> PatchInfo -> Bool+match_tag ('^':n) = mymatch $ "^TAG "++n+match_tag n = mymatch $ "^TAG .*"++n+\end{code}++\begin{options}+--compress, --dont-compress, --uncompress+\end{options}++Some compression options are available, and are independent of the+\verb!--checkpoint! option.++By default the patches in the repository are compressed. These use less+disk space, which translates into less bandwidth if the repository is accessed+remotely.++Note that in the darcs-1.0 (also known as ``old fashioned inventory'')+repository format, patches will always have the ``.gz'' extension whether+they are compressed or not.++You may want to uncompress the patches when you've got enough disk space but+are running out of physical memory.++If you give the \verb!--compress! option, optimize will compress all the+patches in the repository.  Similarly, if you give the \verb!--uncompress!,+optimize will decompress all the patches in the repository.+\verb!--dont-compress!  means ``don't compress, but don't uncompress+either''. It would be useful if one of the compression options was provided+as a default and you wanted to override it.++\begin{code}+optimize_compression :: [DarcsFlag] -> IO ()+optimize_compression opts = do+    putStrLn "Optimizing (un)compression of patches..."+    do_compress (darcsdir++"/patches")+    putStrLn "Optimizing (un)compression of inventories..."+    do_compress (darcsdir++"/inventories")+    where do_compress f =+              do isd <- doesDirectoryExist f+                 if isd then withCurrentDirectory f $+                             do fs <- filter notdot `fmap` getDirectoryContents "."+                                mapM_ do_compress fs+                        else if Compress `elem` opts+                             then gzReadFilePS f >>= gzWriteAtomicFilePS f+                             else gzReadFilePS f >>= writeAtomicFilePS f+          notdot ('.':_) = False+          notdot _ = True++\end{code}++\begin{options}+--relink+\end{options}++The \verb|--relink| and \verb|--relink-pristine| options cause Darcs+to relink files from a sibling.  See Section \ref{disk-usage}.+++\begin{code}+do_relink :: RepoPatch p => [DarcsFlag] -> Repository p -> IO ()+do_relink opts repository =+    do some_siblings <- return (flagsToSiblings opts)+       defrepo <-  defaultrepo [] "" []+       siblings <- return (some_siblings ++ defrepo)+       if (siblings == []) +          then putStrLn "No siblings -- no relinking done."+          else do when (Relink `elem` opts) $+                      do debugMessage "Relinking patches..."+                         patches <-+                           (liftM list_slurpy_files) (slurp $ darcsdir++"/patches")+                         maybeRelinkFiles siblings patches (darcsdir++"/patches")+                  when (RelinkPristine `elem` opts) $+                      do pristine <- identifyPristine+                         case (pristineDirectory pristine) of+                             (Just d) -> do+                                 debugMessage "Relinking pristine tree..."+                                 c <- slurp_recorded repository+                                 maybeRelinkFiles+                                     siblings (list_slurpy_files c) d+                             Nothing -> return ()+                  debugMessage "Done relinking."+                  return ()+       return ()++maybeRelinkFiles :: [String] -> [String] -> String -> IO ()+maybeRelinkFiles src dst dir = +    mapM_ (maybeRelinkFile src) (map ((dir ++ "/") ++) dst)++maybeRelinkFile :: [String] -> String -> IO ()+maybeRelinkFile [] _ = return ()+maybeRelinkFile (h:t) f =+    do done <- maybeRelink (h ++ "/" ++ f) f+       unless done $+           maybeRelinkFile t f+       return ()+\end{code}++\begin{options}+--reorder-patches+\end{options}++The \verb|--reorder-patches| option causes Darcs to create an optimal+ordering of its internal patch inventory. This may help to produce shorter+`context' lists when sending patches, and may improve performance for some+other operations as well.  You should not run \verb!--reorder-patches! on a+repository from which someone may be simultaneously pulling or getting, as+this could lead to repository corruption.++\begin{code}+do_reorder :: RepoPatch p => [DarcsFlag] -> Repository p -> IO ()+do_reorder opts _ | not (Reorder `elem` opts) = return ()+do_reorder opts repository = do+    debugMessage "Reordering the inventory."+    psnew <- choose_order `liftSM` read_repo repository+    let ps = mapFL_FL hopefully $ reverseRL $ head $ unsafeUnRL psnew+    withGutsOf repository $ do tentativelyReplacePatches repository opts ps+                               finalizeRepositoryChanges repository+    debugMessage "Done reordering the inventory."++choose_order :: RepoPatch p => PatchSet p -> PatchSet p+choose_order ps | isJust last_tag =+    case slightly_optimize_patchset $ unsafeUnseal $ get_patches_in_tag lt ps of +    ((t:<:NilRL):<:pps) -> case get_patches_beyond_tag lt ps of+                           FlippedSeal (p :<: NilRL) -> (p+<+(t:<:NilRL)) :<: pps+                           _ -> impossible+    _ -> impossible             +    where last_tag = case filter is_tag $ mapRL info $ concatRL ps of+                     (t:_) -> Just t+                     _ -> Nothing+          lt = fromJust last_tag+choose_order ps = ps+\end{code}
+ src/Darcs/Commands/Pull.lhs view
@@ -0,0 +1,275 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs pull}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Pull ( pull ) where+import System.Exit ( ExitCode(..), exitWith )+import Control.Monad ( when )++import Darcs.Commands ( DarcsCommand(..), loggers )+import Darcs.CommandsAux ( check_paths )+import Darcs.Arguments ( DarcsFlag( Verbose, Quiet, DryRun, MarkConflicts, XMLOutput,+                                   Intersection, Complement, AllowConflicts, NoAllowConflicts ),+                         nocompress, ignoretimes, definePatches,+                        no_deps, pull_conflict_options, use_external_merge,+                        match_several, fix_filepaths,+                        all_interactive, repo_combinator,+                        print_dry_run_message_and_exit,+                        test, dry_run,+                        set_default, summary, working_repo_dir, remote_repo,+                        set_scripts_executable, nolinks,+                        ssh_cm, umask_option,+                      )+import Darcs.RepoPath ( toPath )+import Darcs.Repository ( Repository, SealedPatchSet, identifyRepositoryFor, withGutsOf,+                          amInRepository, withRepoLock, ($-), tentativelyMergePatches,+                          sync_repo, finalizeRepositoryChanges, applyToWorking,+                          slurp_recorded, read_repo )+import Darcs.Hopefully ( info )+import Darcs.Patch ( RepoPatch, description )+import Darcs.Patch.Ordered ( (:>)(..), (:\/:)(..), RL(..), unsafeUnRL, concatRL,+                             mapFL, nullFL, reverseRL, mapRL )+import Darcs.Patch.Permutations ( partitionFL )+import Darcs.SlurpDirectory ( wait_a_moment )+import Darcs.Repository.Prefs ( add_to_preflist, defaultrepo, set_defaultrepo, get_preflist )+import Darcs.Repository.Motd (show_motd )+import Darcs.Patch.Depends ( get_common_and_uncommon,+                             patchset_intersection, patchset_union )+import Darcs.SelectChanges ( with_selected_changes )+import Darcs.Utils ( clarify_errors, formatPath )+import Darcs.Sealed ( Sealed(..), seal )+import Printer ( putDocLn, vcat, ($$), text )+#include "impossible.h"+\end{code}+\begin{code}+pull_description :: String+pull_description =+ "Copy and apply patches from another repository to this one."+\end{code}++\options{pull}++\haskell{pull_help}+\begin{code}+pull_help :: String+pull_help =+ "Pull is used to bring changes made in another repository into the current\n"+++ "repository (that is, either the one in the current directory, or the one\n"+++ "specified with the --repodir option). Pull allows you to bring over all or\n"+++ "some of the patches that are in that repository but not in this one. Pull\n"+++ "accepts arguments, which are URLs from which to pull, and when called\n"+++ "without an argument, pull will use the repository from which you have most\n"+++ "recently either pushed or pulled.\n"+\end{code}+\begin{code}+pull :: DarcsCommand+pull = DarcsCommand {command_name = "pull",+                     command_help = pull_help,+                     command_description = pull_description,+                     command_extra_args = -1,+                     command_extra_arg_help = ["[REPOSITORY]..."],+                     command_command = pull_cmd,+                     command_prereq = amInRepository,+                     command_get_arg_possibilities = get_preflist "repos",+                     command_argdefaults = defaultrepo,+                     command_advanced_options = [repo_combinator,+                                                 nocompress, nolinks,+                                                 ignoretimes,+                                                 remote_repo,+                                                 ssh_cm,+                                                 set_scripts_executable,+                                                 umask_option],+                     command_basic_options = [match_several,+                                             all_interactive,+                                             pull_conflict_options,+                                             use_external_merge,+                                             test]++dry_run++[summary,+                                             no_deps,+                                             set_default,+                                             working_repo_dir]}+\end{code}+\begin{code}+pull_cmd :: [DarcsFlag] -> [String] -> IO ()++pull_cmd opts unfixedrepodirs@(_:_) =+  let (logMessage, _, logDocLn) = loggers opts+      putInfo = if (Quiet `elem` opts || XMLOutput `elem` opts) then \_ -> return () else logDocLn+      putVerbose = if Verbose `elem` opts then putDocLn else \_ -> return ()+  in withRepoLock opts $- \repository -> do+  let repodirs = filter (not.null) $ map toPath $ fix_filepaths opts unfixedrepodirs in do+  -- Test to make sure we aren't trying to pull from the current repo+  when (null repodirs) $+        fail "Can't pull from current repository!"+  (Sealed them, Sealed compl) <- read_repos repository opts repodirs+  old_default <- defaultrepo opts "" []+  set_defaultrepo (head repodirs) opts+  mapM_ (add_to_preflist "repos") repodirs+  when (old_default == repodirs) $+      let pulling = if DryRun `elem` opts then "Would pull" else "Pulling"+      in  putInfo $ text $ pulling++" from "++concatMap formatPath repodirs++"..."+  mapM (show_motd opts) repodirs+  Sealed us <- read_repo repository+  (_, us' :\/: them'') <- return $ get_common_and_uncommon (us, them)+  (_,   _ :\/: compl') <- return $ get_common_and_uncommon (us, compl)+  let avoided = mapRL info (concatRL compl')+  ps :> _ <- return $ partitionFL (not . (`elem` avoided) . info) $ reverseRL $ concatRL them''+  do when (Verbose `elem` opts) $+          do case us' of+               (x@(_:<:_):<:_) -> putDocLn $ text "We have the following new (to them) patches:"+                                             $$ (vcat $ mapRL description x)+               _ -> return ()+             when (not $ nullFL ps) $ putDocLn $ text "They have the following patches to pull:"+                                                 $$ (vcat $ mapFL description ps)+     when (nullFL ps) $ do putInfo $ text "No remote changes to pull in!"+                           definePatches ps+                           exitWith ExitSuccess+     s <- slurp_recorded repository+     with_selected_changes "pull" opts s ps $+      \ (to_be_pulled:>_) -> do+      print_dry_run_message_and_exit "pull" opts to_be_pulled+      definePatches to_be_pulled+      when (nullFL to_be_pulled) $ do+          logMessage "You don't want to pull any patches, and that's fine with me!"+          exitWith ExitSuccess+      check_paths opts to_be_pulled+      putVerbose $ text "Getting and merging the following patches:"+      putVerbose $ vcat $ mapFL description to_be_pulled+      let merge_opts | NoAllowConflicts `elem` opts = opts+                     | AllowConflicts   `elem` opts = opts+                     | otherwise                    = MarkConflicts : opts+      pw <- tentativelyMergePatches repository "pull" merge_opts+                 (reverseRL $ head $ unsafeUnRL us') to_be_pulled+      withGutsOf repository $ do finalizeRepositoryChanges repository+                                 -- so work will be more recent than rec:+                                 revertable $ do wait_a_moment+                                                 applyToWorking repository opts pw+      sync_repo repository+      putInfo $ text "Finished pulling and applying."+          where revertable x = x `clarify_errors` unlines+                  ["Error applying patch to the working directory.","",+                   "This may have left your working directory an inconsistent",+                   "but recoverable state. If you had no un-recorded changes",+                   "by using 'darcs revert' you should be able to make your",+                   "working directory consistent again."]+pull_cmd _ [] = fail "No default repository to pull from, please specify one"+\end{code}++\begin{code}++{- Read in the specified pull-from repositories.  Perform+Intersection, Union, or Complement read.  In patch-theory terms+(stated in set algebra, where + is union and & is intersection+and \ is complement):++    Union =         ((R1 + R2 + ... + Rn) \ Rc)+    Intersection =  ((R1 & R2 & ... & Rn) \ Rc)+    Complement =    (R1 \ Rc) \ ((R2 + R3 + ... + Rn) \ Rc)++                        where Rc = local repo+                              R1 = 1st specified pull repo+                              R2, R3, Rn = other specified pull repo++Since Rc is not provided here yet, the result of read_repos is a+tuple: the first patchset(s) to be complemented against Rc and then+the second patchset(s) to be complemented against Rc.+-}++read_repos :: RepoPatch p => Repository p -> [DarcsFlag] -> [String] -> IO (SealedPatchSet p,SealedPatchSet p)+read_repos _ _ [] = impossible+read_repos to_repo opts us =+    do rs <- mapM (\u -> identifyRepositoryFor to_repo u >>= read_repo) us+       return $ if Intersection `elem` opts+                then (patchset_intersection rs, seal NilRL)+                else if Complement `elem` opts+                     then (head rs, patchset_union $ tail rs)+                     else (patchset_union rs, seal NilRL)++\end{code}++\begin{options}+--intersection, --union [DEFAULT], --complement+\end{options}++If you provide more than one repository as an argument to pull, darcs'+behavior is determined by the presence of the \verb!--complement!,+\verb!--intersection!, and \verb!--union!  flags.  ++\begin{itemize}++\item The default (\verb!--union!) behavior is to pull any patches+that are in any of the specified repositories ($ R_1 \bigcup R_2+\bigcup R_3 \ldots$).++\item If you instead specify the \verb!--intersection! flag, darcs+will only pull those patches which are present in all source+repositories ($ R_1 \bigcap R_2 \bigcap R_3 \ldots$).++\item If you specify the \verb!--complement! flag, darcs will only+pull elements in the first repository that do not exist in any of the+remaining repositories\footnote{The first thing darcs will do is+remove duplicates, keeping only the first specification.  This is+noticeable for the complement operation, since mathematically $ S+\backslash S \rightarrow \emptyset $, one would expect that+``\texttt{darcs pull --complement repo1 repo1}'' would result in no+pulls, but the duplicate elimination removes the second+\texttt{repo1}, reducing the above to effectively ``\texttt{darcs pull+repo1}''.  The expected functionality could be seen via+``\texttt{darcs get -a repo1 repo2; darcs pull --complement repo1+repo2}'', but there are easier ways of doing nothing!} ($ R_1+\backslash (R_2 \bigcup R_3 \bigcup \ldots$)).++\end{itemize}+++\begin{options}+--external-merge+\end{options}++You can use an external interactive merge tool to resolve conflicts with the+flag \verb!--external-merge!.  For more details see+subsection~\ref{resolution}.++\begin{options}+--matches, --patches, --tags, --no-deps+\end{options}++The \verb!--patches!, \verb!--matches!, \verb!--tags!, and \verb!--no-deps!+options can be used to select which patches to pull, as described in+subsection~\ref{selecting}.++\begin{options}+--no-test, --test+\end{options}++If you specify the \verb!--test! option, pull will run the test (if a test+exists) on a scratch copy of the repository contents prior to actually performing+the pull.  If the test fails, the pull will be aborted.++\begin{options}+--verbose+\end{options}++Adding the \verb!--verbose! option causes another section to appear in the+output which also displays a summary of patches that you have and the remote+repository lacks. Thus, the following syntax can be used to show you all the patch+differences between two repositories:++\begin{verbatim}+darcs pull --dry-run --verbose+\end{verbatim}
+ src/Darcs/Commands/Push.lhs view
@@ -0,0 +1,257 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs push}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Push ( push ) where+import System.Exit ( exitWith, ExitCode( ExitSuccess, ExitFailure ) )+import Control.Monad ( when )+import Data.Char ( toUpper )+import Darcs.Commands ( DarcsCommand(..) )+import Darcs.Arguments ( DarcsFlag( DryRun, Verbose, Quiet, Sign, SignAs, NoSign, SignSSL ),+                         definePatches,+                        working_repo_dir, summary,+                        print_dry_run_message_and_exit,+                        applyas, match_several, fix_filepath, no_deps,+                        all_interactive, dry_run, nolinks,+                        remote_repo, ssh_cm,+                        set_default, sign+                      )+import Darcs.Hopefully ( hopefully )+import Darcs.RepoPath ( toPath )+import Darcs.Repository ( withRepoReadLock, ($-), identifyRepositoryFor, slurp_recorded,+                          read_repo, amInRepository )+import Darcs.Patch ( description )+import Darcs.Patch.Ordered ( RL(..), (:>)(..), (:\/:)(..),+                             nullFL, reverseRL, mapFL_FL, unsafeUnRL, mapRL, lengthRL )+import Darcs.Repository.Prefs ( defaultrepo, set_defaultrepo, get_preflist )+import Darcs.External ( maybeURLCmd, signString )+import Darcs.URL ( is_url, is_file )+import Darcs.SelectChanges ( with_selected_changes )+import Darcs.Utils ( formatPath )+import Darcs.Patch.Depends ( get_common_and_uncommon )+import Darcs.Patch.Bundle ( make_bundle )+import Printer ( vcat, empty, text, ($$), (<+>), putDocLn, errorDoc )+import Darcs.RemoteApply ( remote_apply, apply_as )+import Darcs.Email ( make_email )+import Darcs.Sealed ( Sealed(..) )+import English (englishNum, Noun(..))+#include "impossible.h"+\end{code}+\begin{code}+push_description :: String+push_description =+ "Copy and apply patches from this repository to another one."+\end{code}++\options{push}+\haskell{push_help}+\begin{code}+push_help :: String+push_help =+ "Push is the opposite of pull.  Push allows you to copy changes from the\n"+++ "current repository into another repository.\n"+\end{code}+\begin{code}+push :: DarcsCommand+push = DarcsCommand {command_name = "push",+                     command_help = push_help,+                     command_description = push_description,+                     command_extra_args = 1,+                     command_extra_arg_help = ["[REPOSITORY]"],+                     command_command = push_cmd,+                     command_prereq = amInRepository,+                     command_get_arg_possibilities = get_preflist "repos",+                     command_argdefaults = defaultrepo,+                     command_advanced_options = [applyas, nolinks, remote_repo, ssh_cm],+                     command_basic_options = [match_several, no_deps,+                                             all_interactive,+                                             sign]++dry_run++[summary,+                                             working_repo_dir,+                                             set_default]}+\end{code}+\begin{code}+push_cmd :: [DarcsFlag] -> [String] -> IO ()+push_cmd opts [""] = push_cmd opts []+push_cmd opts [unfixedrepodir] =+  let am_verbose = Verbose `elem` opts+      am_quiet = Quiet `elem` opts+      putVerbose s = when am_verbose $ putDocLn s+      putInfo s = when (not am_quiet) $ putDocLn s+      repodir = toPath $ fix_filepath opts unfixedrepodir+  in+ do+ -- Test to make sure we aren't trying to push to the current repo+ when (repodir == "") $+       fail "Can't push to current repository!"+       -- absolute '.' also taken into account by fix_filepath+ (bundle,num_to_pull) <- withRepoReadLock opts $- \repository -> do+  if is_url repodir then do+       when (apply_as opts /= Nothing) $+           let msg = text "Cannot --apply-as when pushing to URLs" in+             if DryRun `elem` opts+             then putInfo $ text "NOTE: " <+> msg+                         $$ text ""+             else errorDoc msg+       maybeapply <- maybeURLCmd "APPLY" repodir+       when (maybeapply == Nothing) $+         let lprot = takeWhile (/= ':') repodir+             prot = map toUpper lprot+             msg = text ("Pushing to "++lprot++" URLs is not supported.\n"+++                         "You may be able to hack this to work"+++                         " using DARCS_APPLY_"++prot) in+           if DryRun `elem` opts+           then putInfo $ text "NOTE:" <+> msg+                       $$ text ""+           else errorDoc msg+   else do+       when (want_sign opts) $+        let msg = text "Signing doesn't make sense for local repositories or when pushing over ssh."+        in if DryRun `elem` opts+            then putInfo $ text "NOTE:" <+> msg+            else errorDoc msg+  Sealed them <- identifyRepositoryFor repository repodir >>= read_repo+  old_default <- defaultrepo opts "" []+  set_defaultrepo repodir opts+  when (old_default == [repodir]) $+       let pushing = if DryRun `elem` opts then "Would push" else "Pushing"+       in  putInfo $ text $ pushing++" to "++formatPath repodir++"..."+  Sealed us <- read_repo repository+  case get_common_and_uncommon (us, them) of+    (common, us' :\/: them') -> do+     putVerbose $ text "We have the following patches to push:"+               $$ (vcat $ mapRL description $ head $ unsafeUnRL us')+     firstUs <- case us' of+                   NilRL:<:NilRL -> do putInfo $ text "No recorded local changes to push!"+                                       exitWith ExitSuccess+                   NilRL -> bug "push_cmd: us' is empty!"+                   (x:<:_) -> return x+     s <- slurp_recorded repository+     with_selected_changes "push" opts s (reverseRL firstUs) $+      \ (to_be_pushed:>_) -> do+      definePatches to_be_pushed+      print_dry_run_message_and_exit "push" opts to_be_pushed+      when (nullFL to_be_pushed) $ do+          putInfo $+            text "You don't want to push any patches, and that's fine with me!"+          exitWith ExitSuccess+      let num_to_pull = lengthRL $ head $ unsafeUnRL them'+          bundle = make_bundle []+                     (bug "using slurpy in make_bundle called from Push")+                     common (mapFL_FL hopefully to_be_pushed)+      return (bundle, num_to_pull)+ sbundle <- signString opts bundle+ let body = if is_file repodir+            then sbundle+            else make_email repodir Nothing sbundle Nothing+ rval <- remote_apply opts repodir body+ let pull_reminder =+         if num_to_pull > 0+         then text $ "(By the way, the remote repository has " ++ show num_to_pull ++ " "+                     ++ englishNum num_to_pull (Noun "patch") " to pull.)"+         else empty+ case rval of ExitFailure ec -> do putStrLn $ "Apply failed!"+                                   exitWith (ExitFailure ec)+              ExitSuccess -> putInfo $ text "Push successful." $$ pull_reminder++push_cmd _ _ = impossible+\end{code}+\begin{code}+want_sign :: [DarcsFlag] -> Bool+want_sign opts = case opts of+    []            -> False+    Sign:_        -> True+    (SignAs _):_  -> True+    (SignSSL _):_ -> True+    NoSign:_      -> False+    _:opts'       -> want_sign opts'+\end{code}++For obvious reasons, you can only push to repositories to which you have+write access.  In addition, you can only push to repos that you access+either on the local file system or with ssh.  In order to apply with ssh,+darcs must also be installed on the remote computer.  The command invoked+to run ssh may be configured by the \verb!DARCS_SSH! environment variable+(see subsection~\ref{env:DARCS_SSH}).  The command invoked via ssh is always+\verb!darcs!, i.e.\ the darcs executable must be in the default path on+the remote machine.++Push works by creating a patch bundle, and then running darcs apply in the+target repository using that patch bundle.  This means that the default+options for \emph{apply} in the \emph{target} repository (such as, for+example, \verb!--test!) will affect the behavior of push.  This also means+that push is somewhat less efficient than pull.++When you receive an error message such as+\begin{verbatim}+bash: darcs: command not found+\end{verbatim}+then this means that the darcs on the remote machine could+not be started.  Make sure that the darcs executable is called+\verb!darcs! and is found in the default path.  The default path can+be different in interactive and in non-interactive shells.  Say+\begin{verbatim}+ssh login@remote.machine darcs+\end{verbatim}+to try whether the remote darcs can be found, or+\begin{verbatim}+ssh login@remote.machine 'echo $PATH'+\end{verbatim}+(note the single quotes) to check the default path.++\begin{options}+--apply-as+\end{options}++If you give the \verb!--apply-as! flag, darcs will use sudo to apply the+changes as a different user.  This can be useful if you want to set up a+system where several users can modify the same repository, but you don't+want to allow them full write access.  This isn't secure against skilled+malicious attackers, but at least can protect your repository from clumsy,+inept or lazy users.++\begin{options}+--matches, --patches, --tags, --no-deps+\end{options}++The \verb!--patches!, \verb!--matches!, \verb!--tags!, and \verb!--no-deps!+options can be used to select which patches to push, as described in+subsection~\ref{selecting}.++When there are conflicts, the behavior of push is determined by the default+flags to \verb!apply! in the \emph{target} repository.  Most commonly, for+pushed-to repositories, you'd like to have \verb!--dont-allow-conflicts! as+a default option to apply (by default, it is already the default\ldots).  If+this is the case, when there are conflicts on push, darcs will fail with an+error message.  You can then resolve by pulling the conflicting patch,+recording a resolution and then pushing the resolution together with the+conflicting patch.++Darcs does not have an explicit way to tell you which patch conflicted, only the+file name. You may want to pull all the patches from the remote repository just+to be sure. If you don't want to do this in your working directory,+you can create another darcs working directory for this purpose.++If you want, you could set the target repository to use \verb!--allow-conflicts!.+In this case conflicting patches will be applied, but the conflicts will+not be marked in the working directory.++If, on the other hand, you have \verb!--mark-conflicts! specified as a+default flag for apply in the target repository, when there is a conflict,+it will be marked in the working directory of the target repository.  In+this case, you should resolve the conflict in the target repository itself.
+ src/Darcs/Commands/Put.lhs view
@@ -0,0 +1,180 @@+\subsection{darcs put}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Put ( put ) where+import System.Exit ( ExitCode( ExitSuccess, ExitFailure ), exitWith )+import Control.Monad ( when )+import Data.Maybe ( catMaybes )+import System.Directory ( createDirectory )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag( Quiet, Verbose,+                                    UseFormat2, UseHashedInventory, UseOldFashionedInventory ),+                        applyas, match_one_context, fix_filepath,+                        ssh_cm, flagToString, get_inventory_choices,+                        set_scripts_executable, working_repo_dir, set_default,+                      )+import Darcs.Repository ( withRepoReadLock, ($-), patchSetToPatches, read_repo, amInRepository )+import Darcs.Repository.Format ( identifyRepoFormat,+                                 RepoProperty ( Darcs2, HashedInventory ), format_has )+import Darcs.Patch.Bundle ( make_bundle2 )+import Darcs.Patch.Ordered ( FL(..) )+import Darcs.Match ( have_patchset_match, get_one_patchset )+import Darcs.RepoPath ( toPath )+import Darcs.Repository.Prefs ( get_preflist, set_defaultrepo )+import Darcs.URL ( is_url, is_file, is_relative )+import Darcs.Utils ( withCurrentDirectory )+import Darcs.Progress ( debugMessage )+import Darcs.FilePathUtils ( absolute_dir )+import Darcs.SlurpDirectory ( empty_slurpy )+import Darcs.External ( execSSH )+import Darcs.RemoteApply ( remote_apply )+import Darcs.Commands.Init ( initialize )+import Darcs.Email ( make_email )+import Darcs.Sealed ( Sealed(..), seal )+#include "impossible.h"+\end{code}+\begin{code}+put_description :: String +put_description =+ "Makes a copy of the repository"+\end{code}+\options{put}+\haskell{put_help}+\begin{code}+put_help :: String+put_help = + "Put is the opposite of get. Put copies the content of the current \n" +++ "repository and puts it in a newly created repository.\n"+\end{code}+\begin{code}+put ::DarcsCommand+put = DarcsCommand {command_name = "put",+                    command_help = put_help,+                    command_description = put_description,+                    command_extra_args = 1,+                    command_extra_arg_help = ["<NEW REPOSITORY>"],+                    command_command = put_cmd,+                    command_prereq = amInRepository,+                    command_get_arg_possibilities = get_preflist "repos",+                    command_argdefaults = nodefaults,+                    command_advanced_options = [applyas, ssh_cm],+                    command_basic_options = [match_one_context, set_scripts_executable,+                                             get_inventory_choices,+                                             set_default, working_repo_dir]}+\end{code}+\begin{code}+put_cmd :: [DarcsFlag] -> [String] -> IO ()+put_cmd _ [""] = fail "Empty repository argument given to put."+put_cmd opts [unfixedrepodir] =+  let am_quiet = Quiet `elem` opts+      putInfo s = when (not am_quiet) $ putStrLn s+      putVerbose = when (Verbose `elem` opts) . putStrLn+      repodir = if is_relative unfixedrepodir+                then toPath $ fix_filepath opts unfixedrepodir+                else unfixedrepodir+  in+ do+ -- Test to make sure we aren't trying to push to the current repo+ cur_absolute_repo_dir <- absolute_dir "."+ req_absolute_repo_dir <- absolute_dir repodir+ when (cur_absolute_repo_dir == req_absolute_repo_dir) $+       fail "Can't put to current repository!"+ when (is_url req_absolute_repo_dir) $ error "Can't put to a URL!"++ debugMessage "Creating repository"+ putVerbose "Creating repository"+ rf_or_e <- identifyRepoFormat "."+ rf <- case rf_or_e of Left e -> fail e+                       Right x -> return x+ let initopts = if format_has Darcs2 rf+                then UseFormat2:filter (/= UseOldFashionedInventory) opts+                else if format_has HashedInventory rf &&+                        not (UseOldFashionedInventory `elem` opts)+                     then UseHashedInventory:filter (/= UseFormat2) opts+                     else filter (/= UseFormat2) opts+ if is_file req_absolute_repo_dir+     then do createDirectory req_absolute_repo_dir+             withCurrentDirectory req_absolute_repo_dir $ (command_command initialize) initopts []+     else do -- is_ssh req_absolute_repo_dir+             remoteInit req_absolute_repo_dir initopts++ withCurrentDirectory cur_absolute_repo_dir $+                      withRepoReadLock opts $- \repository -> do+  set_defaultrepo req_absolute_repo_dir opts+  Sealed patchset <- if have_patchset_match opts+                       then do ps <- get_one_patchset repository opts  -- todo: make sure get_one_patchset has the right type+                               return . seal $ ps+                       else read_repo repository+  Sealed patchset2 <- if have_patchset_match opts+                       then do ps <- get_one_patchset repository opts  -- todo: make sure get_one_patchset has the right type+                               return . seal $ ps+                       else read_repo repository+  let patches = patchSetToPatches patchset+      patches2 = patchSetToPatches patchset2+      nullFL NilFL = True+      nullFL _ = False+  when (nullFL patches) $ do+          putInfo "No patches were selected to put. Nothing to be done."+          exitWith ExitSuccess+  let bundle = (make_bundle2 opts empty_slurpy [] patches patches2)+      message = if is_file req_absolute_repo_dir+                then bundle+                else make_email req_absolute_repo_dir Nothing bundle Nothing+  putVerbose "Applying patches in new repository..."+  rval <- remote_apply opts req_absolute_repo_dir message+  case rval of ExitFailure ec -> do putStrLn $ "Apply failed!"+                                    exitWith (ExitFailure ec)+               ExitSuccess -> putInfo "Put successful."+put_cmd _ _ = impossible++remoteInit :: FilePath -> [DarcsFlag] -> IO ()+remoteInit repo opts = do+    let args = catMaybes $ map (flagToString $ command_basic_options initialize) opts+        command = "darcs initialize --repodir='" ++ path ++ "' " ++ unwords args+    exitCode <- execSSH addr command+    when (exitCode /= ExitSuccess) $ +         fail "Couldn't initialize remote repository."+  where (addr,':':path) = break (==':') repo+\end{code}++\emph{WARNING:} Put is far less optimized than get, especially for local+repositories.  We recommend avoiding use of put except for small+repositories.++Put is used when you already have a repository and want to make a copy+of it.  A typical use-case is when you want to branch your project.++Put works by first initializing a repository. If the new repository is+not on the local file system then darcs will login to the remote host+and run \verb!darcs init! there. After the new repository is created+all selected patches will be pushed just as with the command+\verb!push!.++\begin{options}+--apply-as+\end{options}++If you give the \verb!--apply-as! flag, darcs will use sudo to apply the+changes as a different user.  This can be useful if you want to set up a+system where several users can modify the same repository, but you don't+want to allow them full write access.  This isn't secure against skilled+malicious attackers, but at least can protect your repository from clumsy,+inept or lazy users.++\begin{options}+--context, --tag, --to-patch, --to-match+\end{options}+If you want to put a specific version of a repository, you have a few+options.  You can either use the \verb!--tag!, \verb!--to-patch! or+\verb!--to-match! options, or you can use the \verb!--context=FILENAME!+option, which specifies a file containing a context generated with+\verb!darcs changes --context!.  This allows you (for example) to include in+your compiled program an option to output the precise version of the+repository from which it was generated, and then perhaps ask users to+include this information in bug reports.++Note that when specifying \verb!--to-patch! or \verb!--to-match!, you may+get a version of your code that has never before been seen, if the patches+have gotten themselves reordered.  If you ever want to be able to precisely+reproduce a given version, you need either to tag it or create a context+file.
+ src/Darcs/Commands/Record.lhs view
@@ -0,0 +1,479 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs record}+\label{record}+\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+module Darcs.Commands.Record ( record, commit, get_date, get_log, file_exists ) where+import Control.Exception ( handleJust, Exception( ExitException ) )+import Control.Monad ( filterM, when )+import System.IO ( hGetContents, stdin )+import Data.List ( sort, isPrefixOf )+import System.Exit ( ExitCode(..) )+import System.IO ( openBinaryFile, IOMode(AppendMode), hClose, hPutStrLn )+import System.Directory ( doesFileExist, doesDirectoryExist, removeFile )+import Data.Maybe ( isJust )++import Darcs.Lock ( readBinFile, writeBinFile, world_readable_temp )+import Darcs.Hopefully ( info, n2pia )+import Darcs.Repository ( Repository, amInRepository, withRepoLock, ($-),+                          get_unrecorded, get_unrecorded_unsorted, withGutsOf,+                    sync_repo, read_repo,+                    slurp_recorded,+                    tentativelyAddPatch, finalizeRepositoryChanges,+                  )+import Darcs.Patch ( RepoPatch, Patch, Prim, namepatch, summary, anonymous,+                     adddeps, fromPrims )+import Darcs.Patch.Ordered ( FL(..), RL(..), (:>)(..), (+>+),+                             unsafeUnFL, unsafeCompare,+                             reverseRL, mapFL, mapFL_FL, nullFL )+import Darcs.Patch.Info ( PatchInfo )+import Darcs.SlurpDirectory ( slurp_hasfile, slurp_hasdir )+import Darcs.Patch.Choices ( patch_choices_tps, tp_patch,+                             force_first, get_middle_choice, tag )+import Darcs.SelectChanges ( with_selected_changes_to_files',+                             with_selected_changes_reversed )+import Darcs.RepoPath ( SubPath, sp2fn, toFilePath )+import Darcs.SlurpDirectory ( Slurpy, empty_slurpy )+import Darcs.Commands ( DarcsCommand(..), nodefaults, loggers, command_stub )+import Darcs.Arguments ( DarcsFlag( PromptLongComment, Test, NoTest, NoEditLongComment,+                                    EditLongComment, RmLogFile, LogFile, Pipe,+                                    PatchName, AskDeps, All ),+                         get_author, working_repo_dir, lookforadds,+                         getRepoPaths, defineChanges,+                         ask_long_comment, askdeps, patch_select_flag,+                         all_pipe_interactive, leave_test_dir, notest,+                         author, patchname_option, umask_option, ignoretimes,+                         nocompress, rmlogfile, logfile, list_registered_files,+                         set_scripts_executable )+import Darcs.Utils ( askUser, promptYorn, edit_file, clarify_errors )+import Darcs.Progress ( debugMessage, progressFL )+import Darcs.Sealed ( Sealed(..) )+import IsoDate ( getIsoDateTime, cleanLocalDate )+import Printer ( hPutDocLn, text, wrap_text, ($$), renderString )+#include "impossible.h"+\end{code}+\begin{code}+record_description :: String+record_description =+ "Save changes in the working copy to the repository as a patch."+\end{code}++\options{record}++If you provide one or more files or directories as additional arguments+to record, you will only be prompted to changes in those files or+directories.+\begin{code}+record_help :: String+record_help = renderString $ wrap_text 80 $+ "Record is used to name a set of changes and record the patch to the "+++ "repository."+\end{code}+\begin{code}+record :: DarcsCommand+record = DarcsCommand {command_name = "record",+                       command_help = record_help,+                       command_description = record_description,+                       command_extra_args = -1,+                       command_extra_arg_help = ["[FILE or DIRECTORY]..."],+                       command_command = record_cmd,+                       command_prereq = amInRepository,+                       command_get_arg_possibilities = list_registered_files,+                       command_argdefaults = nodefaults,+                       command_advanced_options = [logfile, rmlogfile,+                                                   nocompress, ignoretimes,+                                                   umask_option,+                                                   set_scripts_executable],+                       command_basic_options = [patchname_option, author,+                                               notest,+                                               leave_test_dir,+                                               all_pipe_interactive,+                                               askdeps,+                                               ask_long_comment,+                                               lookforadds,+                                               working_repo_dir]}+\end{code}+\begin{code}+commit_description :: String+commit_description =+ "Does not actually do anything, but offers advice on saving changes"++commit_help :: String+commit_help =+ "This command does not do anything.\n"+++ "If you want to save changes locally, use the 'darcs record' command.\n"+++ "If you want to save a recorded patch to another repository, use the\n"+++ "'darcs push' or 'darcs send' commands instead.\n"++commit :: DarcsCommand+commit = command_stub "commit" commit_help commit_description record+\end{code}+\begin{code}+file_exists :: Slurpy -> SubPath -> IO Bool+file_exists s rp = do file <- doesFileExist fp+                      dir <- doesDirectoryExist fp+                      return (file || dir ||+                              slurp_hasfile (sp2fn rp) s ||+                              slurp_hasdir (sp2fn rp) s)+                   where fp = toFilePath rp++record_cmd :: [DarcsFlag] -> [String] -> IO ()+record_cmd origopts args =+    let (logMessage,_, _) = loggers opts+        opts = if NoTest `elem` origopts then origopts else Test:origopts in+    withRepoLock opts $- \repository -> do+    rec <- if null args then return empty_slurpy+           else slurp_recorded repository+    files <- sort `fmap` getRepoPaths opts args+    existing_files <- filterM (file_exists rec) files+    non_existent_files <- filterM (fmap not . file_exists rec) files+    when (not $ null existing_files) $+         logMessage $ "Recording changes in "++unwords (map show existing_files)++":\n"+    when (not $ null non_existent_files) $+         logMessage $ "Non existent files or directories: "++unwords (map show non_existent_files)++"\n"+    when ((not $ null non_existent_files) && null existing_files) $+         fail "None of the files you specified exist!"+    debugMessage "About to get the unrecorded changes."+    changes <- if All `elem` opts then get_unrecorded_unsorted repository+                                  else get_unrecorded repository+    debugMessage "I've gotten unrecorded."+    case allow_empty_with_askdeps changes of+      Nothing -> do when (Pipe `elem` opts) $ do get_date opts+                                                 return ()+                    if ((not $ null existing_files) || (not $ null non_existent_files))+                       then logMessage "No changes in selected files or directories!"+                       else logMessage "No changes!"+      Just ch -> do_record repository opts existing_files ch+    where allow_empty_with_askdeps NilFL+              | AskDeps `elem` origopts = Just NilFL+              | otherwise = Nothing+          allow_empty_with_askdeps p = Just p++do_record :: RepoPatch p => Repository p -> [DarcsFlag] -> [SubPath] -> FL Prim -> IO ()+do_record repository opts files ps = do+    let make_log = world_readable_temp "darcs-record"+    date <- get_date opts+    my_author <- get_author opts+    debugMessage "I'm slurping the repository."+    s <- slurp_recorded repository+    debugMessage "About to select changes..."+    with_selected_changes_to_files' "record" opts+      s (map toFilePath files) ps $ \ (chs:>_) ->+      if is_empty_but_not_askdeps chs+        then putStrLn "Ok, if you don't want to record anything, that's fine!"+        else handleJust only_successful_exits (\_ -> return ()) $+             do deps <- if AskDeps `elem` opts+                        then ask_about_depends repository chs opts+                        else return []+                when (AskDeps `elem` opts) $ debugMessage "I've asked about dependencies."+                if nullFL chs && null deps+                  then putStrLn "Ok, if you don't want to record anything, that's fine!"+                  else do defineChanges chs+                          (name, my_log, logf) <- get_log opts Nothing make_log chs+                          do_actual_record repository opts name date+                                 my_author my_log logf deps chs+    where is_empty_but_not_askdeps l+              | AskDeps `elem` opts = False+                                      -- a "partial tag" patch; see below.+              | otherwise = nullFL l++do_actual_record :: RepoPatch p => Repository p -> [DarcsFlag] -> String -> String -> String+                 -> [String] -> Maybe String+                 -> [PatchInfo] -> FL Prim -> IO ()+do_actual_record repository opts name date my_author my_log logf deps chs =+              do debugMessage "Writing the patch file..."+                 tentativelyAddPatch repository opts $ n2pia $ adddeps mypatch deps+                 debugMessage "Applying to pristine..."+                 withGutsOf repository (finalizeRepositoryChanges repository)+                                    `clarify_errors` failuremessage+                 debugMessage "Syncing timestamps..."+                 sync_repo repository+                 when (isJust logf) $ removeFile (fromJust logf)+                 logMessage $ "Finished recording patch '"++name++"'"+    where (logMessage,_,_) = loggers opts+          mypatch = namepatch date name my_author my_log $ fromPrims $ progressFL "Writing changes:" chs+          failuremessage = "Failed to record patch '"++name++"'" +++                           case logf of Just lf -> "\nLogfile left in "++lf++"."+                                        Nothing -> ""+\end{code}+Each patch is given a name, which typically would consist of a brief+description of the changes.  This name is later used to describe the patch.+The name must fit on one line (i.e.\ cannot have any embedded newlines).  If+you have more to say, stick it in the log.+\begin{code}+\end{code}++The patch is also flagged with the author of the change, taken by default+from the \verb!DARCS_EMAIL! environment variable, and if that doesn't+exist, from the \verb!EMAIL! environment variable.  The date on which the+patch was recorded is also included.  Currently there is no provision for+keeping track of when a patch enters a given repository.+\begin{code}+get_date :: [DarcsFlag] -> IO String+get_date opts+ | Pipe `elem` opts = do cleanLocalDate `fmap` askUser "What is the date? "+get_date _ = getIsoDateTime+\end{code}+\label{DARCS_EDITOR}+Finally, each changeset should have a full log (which may be empty).  This+log is for detailed notes which are too lengthy to fit in the name.  If you+answer that you do want to create a comment file, darcs will open an editor+so that you can enter the comment in.  The choice of editor proceeds as+follows.  If one of the \verb!$DARCS_EDITOR!, \verb!$VISUAL! or+\verb!$EDITOR! environment variables is defined, its value is used (with+precedence proceeding in the order listed).  If not, ``vi'', ``emacs'',+``emacs~-nw'' and ``nano'' are tried in that order.++\begin{options}+--logfile+\end{options}++If you wish, you may specify the patch name and log using the+\verb!--logfile! flag.  If you do so, the first line of the specified file+will be taken to be the patch name, and the remainder will be the ``long+comment''.  This feature can be especially handy if you have a test that+fails several times on the record (thus aborting the record), so you don't+have to type in the long comment multiple times. The file's contents will+override the \verb!--patch-name! option.++\begin{code}+data PName = FlagPatchName String | PriorPatchName String | NoPatchName++get_log :: [DarcsFlag] -> Maybe (String, [String]) -> IO String -> FL Prim ->+           IO (String, [String], Maybe String)+get_log opts m_old make_log chs = gl opts+    where patchname_specified = patchname_helper opts+          patchname_helper (PatchName n:_) | take 4 n == "TAG " = FlagPatchName $ '.':n+                                           | otherwise          = FlagPatchName n+          patchname_helper (_:fs) = patchname_helper fs+          patchname_helper [] = case m_old of Just (p,_) -> PriorPatchName p+                                              Nothing    -> NoPatchName+          default_log = case m_old of+                          Nothing    -> []+                          Just (_,l) -> l+          gl (Pipe:_) = do p <- case patchname_specified of+                                  FlagPatchName p  -> return p+                                  PriorPatchName p -> return p+                                  NoPatchName      -> prompt_patchname False+                           putStrLn "What is the log?"+                           thelog <- lines `fmap` hGetContents stdin -- ratify hGetContents: stdin not deleted+                           return (p, thelog, Nothing)+          gl (LogFile f:fs) =+              do -- round 1 (patchname)+                 mlp <- lines `fmap` readBinFile f `catch` (\_ -> return [])+                 firstname <- case (patchname_specified, mlp) of+                                (FlagPatchName  p, []) -> return p+                                (_, p:_)               -> return p -- logfile trumps prior!+                                (PriorPatchName p, []) -> return p+                                (NoPatchName, [])      -> prompt_patchname True+                 -- round 2+                 append_info f firstname+                 when (EditLongComment `elem` fs) $ do edit_file f+                                                       return ()+                 (name, thelog, _) <- read_long_comment f firstname+                 when (RmLogFile `elem` opts) $+                      removeFile f `catch` \_ -> return ()+                 return (name, thelog, Nothing)+          gl (EditLongComment:_) =+                  case patchname_specified of+                    FlagPatchName  p -> actually_get_log p+                    PriorPatchName p -> actually_get_log p+                    NoPatchName      -> prompt_patchname True >>= actually_get_log+          gl (NoEditLongComment:_) =+                  case patchname_specified of+                    FlagPatchName  p+                        | Just ("",_) <- m_old ->+                                       return (p, default_log, Nothing) -- rollback -m+                    FlagPatchName  p -> return (p, [], Nothing) -- record (or amend) -m+                    PriorPatchName p -> return (p, default_log, Nothing) -- amend+                    NoPatchName      -> do p <- prompt_patchname True -- record+                                           return (p, [], Nothing)+          gl (PromptLongComment:fs) =+                  case patchname_specified of+                    FlagPatchName p -> prompt_long_comment p -- record (or amend) -m+                    _               -> gl fs+          gl (_:fs) = gl fs+          gl [] = case patchname_specified of+                    FlagPatchName  p -> return (p, [], Nothing)  -- record (or amend) -m+                    PriorPatchName "" -> prompt_patchname True >>= prompt_long_comment+                    PriorPatchName p -> return (p, default_log, Nothing)+                    NoPatchName -> prompt_patchname True >>= prompt_long_comment+          prompt_patchname retry =+            do n <- askUser "What is the patch name? "+               if n == "" || take 4 n == "TAG "+                  then if retry then prompt_patchname retry+                                else fail "Bad patch name!"+                  else return n+          prompt_long_comment oldname =+            do yorn <- promptYorn "Do you want to add a long comment?"+               if yorn == 'y' then actually_get_log oldname+                              else return (oldname, [], Nothing)+          actually_get_log p = do logf <- make_log+                                  writeBinFile logf $ unlines $ p : default_log+                                  append_info logf p+                                  edit_file logf+                                  read_long_comment logf p+          read_long_comment :: FilePath -> String -> IO (String, [String], Maybe String)+          read_long_comment f oldname =+              do t <- (lines.filter (/='\r')) `fmap` readBinFile f+                 case t of [] -> return (oldname, [], Just f)+                           (n:ls) -> return (n, takeWhile+                                             (not.(eod `isPrefixOf`)) ls,+                                             Just f)+          append_info f oldname =+              do fc <- readBinFile f+                 h <- openBinaryFile f AppendMode+                 case fc of+                   _ | null (lines fc) -> hPutStrLn h oldname+                     | last fc /= '\n' -> hPutStrLn h ""+                     | otherwise       -> return ()+                 hPutDocLn h $ text eod+                            $$ text ""+                            $$ wrap_text 75+                               ("Place the long patch description above the "+++                                eod+++                                " marker.  The first line of this file "+++                                "will be the patch name.")+                            $$ text ""+                            $$ text "This patch contains the following changes:"+                            $$ text ""+                            $$ summary (fromPrims chs :: Patch)+                 hClose h+eod :: String+eod = "***END OF DESCRIPTION***"+\end{code}++\begin{options}+--ask-deps+\end{options}++Each patch may depend on any number of previous patches.  If you choose to+make your patch depend on a previous patch, that patch is required to be+applied before your patch can be applied to a repository.  This can be used, for+example, if a piece of code requires a function to be defined, which was+defined in an earlier patch.++If you want to manually define any dependencies for your patch, you can use+the \verb!--ask-deps! flag, and darcs will ask you for the patch's+dependencies.++It is possible to record a patch which has no actual changes but which+has specific dependencies.  This type of patch can be thought of as a+``partial tag''.  The \verb!darcs tag! command will record a patch+with no actual changes but which depends on the entire current+inventory of the repository.  The \verb!darcs record --ask-deps! with+no selected changes will record a patch that depends on only those+patches selected via the \verb!--ask-deps! operation, resulting in a+patch which describes a set of patches; the presence of this primary+patch in a repository implies the presence of (at least) the+depended-upon patches.++\begin{code}+ask_about_depends :: RepoPatch p => Repository p -> FL Prim -> [DarcsFlag] -> IO [PatchInfo]+ask_about_depends repository pa' opts = do+  Sealed pps <- read_repo repository+  let pa = n2pia $ anonymous $ fromPrims pa'+      ps = (reverseRL $ headRL pps)+>+(pa:>:NilFL)+      (pc, tps) = patch_choices_tps ps+      ta = case filter ((pa `unsafeCompare`) . tp_patch) $ unsafeUnFL tps of+                [tp] -> tag tp+                [] -> error "ask_about_depends: []"+                _ -> error "ask_about_depends: many"+      ps' = mapFL_FL tp_patch $ get_middle_choice $ force_first ta pc+  with_selected_changes_reversed "depend on" (filter askdep_allowed opts) empty_slurpy ps'+             $ \(deps:>_) -> return $ mapFL info deps+ where headRL (x:<:_) = x+       headRL NilRL = impossible+       askdep_allowed = not . patch_select_flag+++only_successful_exits :: Exception -> Maybe ()+only_successful_exits (ExitException ExitSuccess) = Just ()+only_successful_exits _ = Nothing+\end{code}++\begin{options}+--no-test,  --test+\end{options}++If you configure darcs to run a test suite, darcs will run this test on the+recorded repository to make sure it is valid.  Darcs first creates a pristine+copy of the source tree (in a temporary directory), then it runs the test,+using its return value to decide if the record is valid.  If it is not valid,+the record will be aborted.  This is a handy way to avoid making stupid+mistakes like forgetting to `darcs add' a new file.  It also can be+tediously slow, so there is an option (\verb!--no-test!) to skip the test.++\begin{options}+--set-scripts-executable+\end{options}++If you pass \verb!--set-scripts-executable! to \verb!darcs record!, darcs will set scripts+executable in the test directory before running the test.++\begin{options}+--pipe+\end{options}++If you run record with the \verb!--pipe! option, you will be prompted for+the patch date, the author, the patch name, and the long comment.+The long comment will+extend until the end of file of stdin is reached (ctrl-D on Unixy systems,+ctrl-Z on systems running a Microsoft OS).+This interface is intended for scripting darcs, in particular for writing+repository conversion scripts.  The prompts are intended mostly as a useful+guide (since scripts won't need them), to help you understand the format in+which to provide the input.++\begin{options}+--interactive+\end{options}++By default, \verb!record! works interactively. Probably the only thing you need+to know about using this is that you can press \verb!?! at the prompt to be+shown a list of the rest of the options and what they do. The rest should be+clear from there. Here's a+``screenshot'' to demonstrate:++\begin{verbatim}+hunk ./hello.pl +2++#!/usr/bin/perl++print "Hello World!\n";+Shall I record this patch? (2/2) [ynWsfqadjk], or ? for help: ?+How to use record...+y: record this patch+n: don't record it+w: wait and decide later, defaulting to no++s: don't record the rest of the changes to this file+f: record the rest of the changes to this file++d: record selected patches+a: record all the remaining patches+q: cancel record++j: skip to next patch+k: back up to previous patch+h or ?: show this help++<Space>: accept the current default (which is capitalized)++\end{verbatim}+What you can't see in that ``screenshot'' is that \verb!darcs! will also try to use+color in your terminal to make the output even easier to read.
+ src/Darcs/Commands/Remove.lhs view
@@ -0,0 +1,141 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs remove}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Remove ( remove, rm, unadd ) where++import Darcs.Commands ( DarcsCommand(..), nodefaults,+                        command_alias, command_stub,+                      )+import Darcs.Arguments ( DarcsFlag, getRepoPaths,+                        list_registered_files,+                        working_repo_dir, umask_option+                      )+import Darcs.RepoPath ( SubPath, toFilePath, sp2fn )+import Darcs.Repository ( Repository, withRepoLock, ($-), amInRepository,+                          slurp_pending, slurp_recorded, get_unrecorded, add_to_pending )+import Darcs.Patch ( RepoPatch, Prim, apply_to_slurpy, adddir, rmdir, addfile, rmfile )+import Darcs.Patch.Ordered ( FL(..), (+>+) )+import Darcs.SlurpDirectory ( slurp_removedir, slurp_removefile )+import Darcs.Repository.Prefs ( filetype_function )+import Darcs.Diff ( smart_diff )+#include "impossible.h"+\end{code}++\begin{code}+remove_description :: String+remove_description =+ "Remove one or more files or directories from the repository."+\end{code}++\options{remove}++\haskell{remove_help}++\begin{code}+remove_help :: String+remove_help =+ "Remove should be called when you want to remove a file from your project,\n"+++ "but don't actually want to delete the file.  Otherwise just delete the\n"+++ "file or directory, and darcs will notice that it has been removed.\n" +++ "Be aware that the file WILL be deleted from any other copy of the\n" +++ "repository to which you later apply the patch.\n"+\end{code}++\begin{code}+remove :: DarcsCommand+remove = DarcsCommand {command_name = "remove",+                       command_help = remove_help,+                       command_description = remove_description,+                       command_extra_args = -1,+                       command_extra_arg_help = ["<FILE or DIRECTORY> ..."],+                       command_command = remove_cmd,+                       command_prereq = amInRepository,+                       command_get_arg_possibilities = list_registered_files,+                       command_argdefaults = nodefaults,+                       command_advanced_options = [umask_option],+                       command_basic_options =+                           [working_repo_dir]}+\end{code}++\begin{code}+remove_cmd :: [DarcsFlag] -> [String] -> IO ()+remove_cmd opts relargs =+    withRepoLock opts $- \repository -> do+    args <- getRepoPaths opts relargs+    p <- make_remove_patch repository args+    add_to_pending repository p++make_remove_patch :: RepoPatch p => Repository p -> [SubPath] -> IO (FL Prim)+make_remove_patch repository files =+                          do s <- slurp_pending repository+                             srecorded <- slurp_recorded repository+                             pend <- get_unrecorded repository+                             let sunrec = fromJust $ apply_to_slurpy pend srecorded+                             wt <- filetype_function+                             mrp wt s sunrec files+    where mrp wt s sunrec (f:fs) =+              case slurp_removedir fn s of+              Just s' ->+                  case slurp_removedir fn sunrec of+                  Just sunrec' -> do rest <- mrp wt s' sunrec' fs+                                     return $ rmdir f_fp :>: rest+                  Nothing -> do rest <- mrp wt s' sunrec fs+                                return $ adddir f_fp :>: rmdir f_fp :>: rest+              Nothing ->+                  case slurp_removefile fn s of+                  Nothing -> fail $ "Can't remove "++f_fp+                  Just s' ->+                      case slurp_removefile fn sunrec of+                      Nothing -> do rest <- mrp wt s' sunrec fs+                                    return $ addfile f_fp :>: rmfile f_fp :>: rest+                      Just sunrec' -> do rest <- mrp wt s' sunrec' fs+                                         let newp = smart_diff [] wt sunrec sunrec'+                                         return $ newp +>+ rest+            where fn = sp2fn f+                  f_fp = toFilePath f+          mrp _ _ _ [] = return NilFL+\end{code}++% rm - Note: not a subsection because not to be documented.++\begin{code}+rm_description :: String+rm_description =+ "Does not actually do anything, but offers advice on removing files"++rm_help :: String+rm_help =+ "This command does not do anything.\n"+++ "If you want to remove a file AND delete it, just delete the file or directory,\n"+++ "and darcs will notice that it has been removed.\n" +++ "If you want to remove a file WITHOUT deleting it, use the 'remove' command\n"++rm :: DarcsCommand+rm = command_stub "rm" rm_help rm_description remove+\end{code}++% unadd - Note: not a subsection because not to be documented.++\begin{code}+unadd :: DarcsCommand+unadd = command_alias "unadd" remove+\end{code}++
+ src/Darcs/Commands/Repair.lhs view
@@ -0,0 +1,135 @@+%  Copyright (C) 2003,2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs repair}+\begin{code}+module Darcs.Commands.Repair ( repair ) where+import Workaround ( getCurrentDirectory )+import System.IO+import System.Exit ( exitWith, ExitCode(..) )+import Control.Monad ( when, )++import Darcs.Commands+import Darcs.Arguments ( DarcsFlag( Verbose, Quiet ),+                        working_repo_dir, umask_option,+                      )+import Darcs.Patch ( RepoPatch, patch2patchinfo )+import Darcs.Patch.Patchy ( applyAndTryToFix )+import Darcs.Patch.Info ( human_friendly )+import Darcs.Patch.Ordered ( FL(..), RL(..), lengthFL, reverseFL, reverseRL, concatRL )+import Darcs.Hopefully ( PatchInfoAnd, info )+import Darcs.Repository ( Repository, withRepoLock, ($-), amInRepository, read_repo,+                          writePatchSet, makePatchLazy,+                          checkPristineAgainstCwd, replacePristine )+import Darcs.Repository.Checkpoint ( get_checkpoint_by_default )+import Darcs.Global ( darcsdir )+import Darcs.Progress ( debugMessage, beginTedious, endTedious, tediousSize, finishedOneIO )+import Darcs.Patch.Depends ( get_patches_beyond_tag )+import Darcs.Lock( withTempDir )+import Darcs.Commands.Check ( check_uniqueness )+import Darcs.Sealed ( Sealed(..), unsafeUnflippedseal )+import Darcs.Utils ( catchall, withCurrentDirectory )+import Printer ( putDocLn, text )+\end{code}++\options{repair}+\begin{code}+repair_description :: String+repair_description = "Repair the corrupted repository."+\end{code}+\haskell{repair_help}++\begin{code}+repair_help :: String+repair_help =+ "Repair attempts to fix corruption that may have entered your\n"+++ "repository.\n"+\end{code}++\begin{code}+repair :: DarcsCommand+repair = DarcsCommand {command_name = "repair",+                       command_help = repair_help,+                       command_description = repair_description,+                       command_extra_args = 0,+                       command_extra_arg_help = [],+                       command_command = repair_cmd,+                       command_prereq = amInRepository,+                       command_get_arg_possibilities = return [],+                       command_argdefaults = nodefaults,+                       command_advanced_options = [umask_option],+                       command_basic_options = [working_repo_dir]}+\end{code}++Repair currently will only repair damage to the pristine tree.+Fortunately this is just the sort of corruption that is most+likely to happen.++\begin{code}+repair_cmd :: [DarcsFlag] -> [String] -> IO ()+repair_cmd opts _ = withRepoLock opts $- \repository -> do+  let putVerbose s = when (Verbose `elem` opts) $ putDocLn s+      putInfo s = when (not $ Quiet `elem` opts) $ putDocLn s+  check_uniqueness putVerbose putInfo repository+  maybe_chk <- get_checkpoint_by_default repository+  formerdir <- getCurrentDirectory+  withTempDir (formerdir++"/"++darcsdir++"/newpristine") $ \newcur -> do+    putVerbose $ text "Applying patches..."+    case maybe_chk of+        Just chk ->+             do let chtg = patch2patchinfo chk+                putVerbose $ text "I am repairing from a checkpoint."+                Sealed patches <- read_repo repository+                applyAndTryToFix chk+                applyAndFix repository+                      (reverseRL $ concatRL $ unsafeUnflippedseal $ get_patches_beyond_tag chtg patches)+                return ()+        Nothing -> do debugMessage "Fixing any broken patches..."+                      Sealed rawpatches <- read_repo repository+                      let psin = reverseRL $ concatRL rawpatches+                      ps <- applyAndFix repository psin+                      withCurrentDirectory formerdir $+                                           writePatchSet (reverseFL ps :<: NilRL) opts+                      debugMessage "Done fixing broken patches..."+    is_same <- checkPristineAgainstCwd repository `catchall` return False+    if is_same+      then do putStrLn "The repository is already consistent, no changes made."+              exitWith ExitSuccess+      else do putStrLn "Fixing pristine tree..."+              replacePristine repository newcur+              exitWith ExitSuccess++applyAndFix :: RepoPatch p => Repository p -> FL (PatchInfoAnd p) -> IO (FL (PatchInfoAnd p))+applyAndFix _ NilFL = return NilFL+applyAndFix r psin = do beginTedious k+                        tediousSize k $ lengthFL psin+                        ps <- aaf psin+                        endTedious k+                        return ps+    where k = "Repairing patch"+          aaf NilFL = return NilFL+          aaf (p:>:ps) = do mp' <- applyAndTryToFix p+                            finishedOneIO k $ show $ human_friendly $ info p+                            p' <- case mp' of+                                  Nothing -> return p+                                  Just (e,pp) -> do putStrLn e+                                                    return pp+                            p'' <- makePatchLazy r p'+                            ps' <- aaf ps+                            return (p'':>:ps')++\end{code}
+ src/Darcs/Commands/Replace.lhs view
@@ -0,0 +1,199 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs replace}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Replace ( replace ) where++import Data.Maybe ( isJust )+import Control.Monad (unless, liftM)++import Darcs.Commands+import Darcs.Arguments+import Darcs.Repository ( withRepoLock, ($-),+                    add_to_pending,+                    amInRepository, slurp_recorded_and_unrecorded,+                    applyToWorking,+                  )+import Darcs.Patch ( Prim, apply_to_slurpy, tokreplace, force_replace_slurpy )+import Darcs.Patch.Ordered ( FL(..), unsafeFL, (+>+), concatFL )+import Darcs.SlurpDirectory ( slurp_hasfile, Slurpy )+import RegChars ( regChars )+import Data.Char ( isSpace )+import Darcs.Diff ( smart_diff )+import Darcs.RepoPath ( SubPath, sp2fn, toFilePath )+import Darcs.Repository.Prefs ( FileType(TextFile) )+#include "impossible.h"+\end{code}++\begin{code}+replace_description :: String+replace_description =+ "Replace a token with a new value for that token."+\end{code}++\options{replace}++\haskell{replace_help}++The default regexp is \verb![A-Za-z_0-9]!), and if one of your tokens+contains a `\verb|-|' or `\verb|.|', you will then (by default) get the ``filename''+regexp, which is \verb![A-Za-z_0-9\-\.]!.++\begin{options}+--token-chars+\end{options}++If you prefer to choose a different set of characters to define your token+(perhaps because you are programming in some other language), you may do so+with the \verb!--token-chars! option.  You may prefer to define tokens in terms+of delimiting characters instead of allowed characters using a flag such as+\verb!--token-chars '[^ \n\t]'!, which would define a token as being+white-space delimited.++If you do choose a non-default token definition, I recommend using+\verb!_darcs/prefs/defaults! to always specify the same+\verb!--token-chars!, since your replace patches will be better behaved (in+terms of commutation and merges) if they have tokens defined in the same+way.++When using darcs replace, the ``new'' token may not already appear in the+file---if that is the case, the replace change would not be invertible.+This limitation holds only on the already-recorded version of the file.++There is a potentially confusing difference, however, when a replace is+used to make another replace possible:+\begin{verbatim}+% darcs replace newtoken aaack ./foo.c+% darcs replace oldtoken newtoken ./foo.c+% darcs record+\end{verbatim}+will be valid, even if \verb!newtoken! and \verb!oldtoken! are both present+in the recorded version of foo.c, while the sequence+\begin{verbatim}+% [manually edit foo.c replacing newtoken with aaack]+% darcs replace oldtoken newtoken ./foo.c+\end{verbatim}+will fail because ``newtoken'' still exists in the recorded version of+\verb!foo.c!.  The reason for the difference is that when recording, a+``replace'' patch always is recorded \emph{before} any manual changes,+which is usually what you want, since often you will introduce new+occurrences of the ``newtoken'' in your manual changes.  In contrast,+multiple ``replace'' changes are recorded in the order in which+they were made.++\begin{code}+replace_help :: String+replace_help =+ "Replace allows you to change a specified token wherever it\n"+++ "occurs in the specified files.  The replace is encoded in a\n"+++ "special patch and will merge as expected with other patches.\n"+++ "Tokens here are defined by a regexp specifying the characters\n"+++ "which are allowed.  By default a token corresponds to a C identifier.\n"+\end{code}++\begin{code}+replace :: DarcsCommand+replace = DarcsCommand {command_name = "replace",+                        command_help = replace_help,+                        command_description = replace_description,+                        command_extra_args = -1,+                        command_extra_arg_help = ["<OLD>","<NEW>",+                                                  "<FILE> ..."],+                        command_command = replace_cmd,+                        command_prereq = amInRepository,+                        command_get_arg_possibilities = list_registered_files,+                        command_argdefaults = nodefaults,+                        command_advanced_options = [ignoretimes, umask_option],+                        command_basic_options =+                            [tokens, force_replace, working_repo_dir]}+\end{code}++\begin{code}+replace_cmd :: [DarcsFlag] -> [String] -> IO ()+replace_cmd opts (old:new:relfs) = withRepoLock opts $- \repository -> do+  fs <- getRepoPaths opts relfs+  toks <- choose_toks opts old new+  let checkToken tok =+        unless (is_tok toks tok) $ fail $ "'"++tok++"' is not a valid token!"+  checkToken old+  checkToken new+  (cur, work) <- slurp_recorded_and_unrecorded repository+  pswork <- (concatFL . unsafeFL) `liftM` sequence (map (repl toks cur work) fs)+  add_to_pending repository pswork+  applyToWorking repository opts pswork `catch` \e ->+      fail $ "Can't do replace on working!\n"+          ++ "Perhaps one of the files already contains '"++ new++"'?\n"+          ++ show e+  where ftf _ = TextFile++        repl :: String -> Slurpy -> Slurpy -> SubPath -> IO (FL Prim)+        repl toks cur work f =+          if not $ slurp_hasfile (sp2fn f) work+          then do putStrLn $ "Skipping file '"++f_fp++"' which isn't in the repository."+                  return NilFL+          else if ForceReplace `elem` opts ||+                  isJust (apply_to_slurpy (tokreplace f_fp toks old new) work) ||+                  isJust (apply_to_slurpy (tokreplace f_fp toks old new) cur)+               then return (get_force_replace f toks work)+               else do putStrLn $ "Skipping file '"++f_fp++"'"+                       putStrLn $ "Perhaps the recorded version of this " +++                                  "file already contains '" ++new++"'?"+                       return NilFL+          where f_fp = toFilePath f++        get_force_replace :: SubPath -> String -> Slurpy -> FL Prim+        get_force_replace f toks s =+            case force_replace_slurpy (tokreplace f_fp toks new old) s of+            Nothing -> bug "weird forcing bug in replace."+            Just s' -> case smart_diff [] ftf s s' of+                       pfix -> pfix +>+ (tokreplace f_fp toks old new :>: NilFL)+            where f_fp = toFilePath f++replace_cmd _ _ = fail "Usage: darcs replace OLD NEW [FILES]"+\end{code}++\begin{code}+default_toks :: String+default_toks = "A-Za-z_0-9"+filename_toks :: String+filename_toks = "A-Za-z_0-9\\-\\."+is_tok :: String -> String -> Bool+is_tok _ "" = False+is_tok toks s = and $ map (regChars toks) s++choose_toks :: [DarcsFlag] -> String -> String -> IO String+choose_toks (Toks t:_) a b+    | any isSpace t = fail $ bad_token_spec $ "Space is not allowed in the spec"+    | length t <= 2 = fail $ bad_token_spec $+                        "It must contain more than 2 characters, because " +++                        "it should be enclosed in square brackets"+    | head t /= '[' || last t /= ']' = fail $ bad_token_spec $+                        "It should be enclosed in square brackets"+    | not (is_tok tok a) = fail $ bad_token_spec $ not_a_token a+    | not (is_tok tok b) = fail $ bad_token_spec $ not_a_token b+    | otherwise          = return tok+    where tok = init $ tail t :: String+          bad_token_spec msg = "Bad token spec: '"++ t ++"' ("++ msg ++")"+          not_a_token x = x ++ " is not a token, according to your spec"+choose_toks (_:fs) a b = choose_toks fs a b+choose_toks [] a b = if is_tok default_toks a && is_tok default_toks b+                     then return default_toks+                     else return filename_toks+\end{code}+
+ src/Darcs/Commands/Revert.lhs view
@@ -0,0 +1,122 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs revert}+\begin{code}+module Darcs.Commands.Revert ( revert ) where+import System.Exit ( ExitCode(..), exitWith )+import Control.Monad ( when )+import Data.List ( sort )++import English (englishNum, This(..), Noun(..))+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag( All, Debug ),+                        ignoretimes, working_repo_dir,+                        all_interactive,+                        getRepoPaths, areFileArgs,+                        list_registered_files, umask_option,+                      )+import Darcs.Utils ( askUser )+import Darcs.RepoPath ( toFilePath )+import Darcs.Repository ( withRepoLock, ($-), withGutsOf,+                    get_unrecorded, get_unrecorded_unsorted,+                    add_to_pending, sync_repo,+                    applyToWorking,+                    amInRepository, slurp_recorded_and_unrecorded,+                  )+import Darcs.Patch ( invert, apply_to_filepaths, commute )+import Darcs.Patch.Ordered ( FL(..), (:>)(..), lengthFL, nullFL, (+>+) )+import Darcs.SelectChanges ( with_selected_last_changes_to_files' )+import Darcs.Patch.TouchesFiles ( choose_touching )+import Darcs.Commands.Unrevert ( write_unrevert )+\end{code}+\begin{code}+revert_description :: String+revert_description =+ "Revert to the recorded version (not always reversible)."+\end{code}++\options{revert}++\haskell{revert_help} The actions of a revert may be reversed using the+unrevert command (see subsection~\ref{unrevert}).  However, if you've made+changes since the revert your mileage may vary, so please be careful.++\begin{code}+revert_help :: String+revert_help =+ "Revert is used to undo changes made to the working copy which have\n"+++ "not yet been recorded.  You will be prompted for which changes you\n"+++ "wish to undo. The last revert can be undone safely using the unrevert\n"+++ "command if the working copy was not modified in the meantime.\n"+\end{code}+\begin{code}+revert :: DarcsCommand+revert = DarcsCommand {command_name = "revert",+                       command_help = revert_help,+                       command_description = revert_description,+                       command_extra_args = -1,+                       command_extra_arg_help = ["[FILE or DIRECTORY]..."],+                       command_command = revert_cmd,+                       command_prereq = amInRepository,+                       command_get_arg_possibilities = list_registered_files,+                       command_argdefaults = nodefaults,+                       command_advanced_options = [ignoretimes, umask_option],+                       command_basic_options = [all_interactive,+                                               working_repo_dir]}+\end{code}+You can give revert optional arguments indicating files or directories.  If+you do so it will only prompt you to revert changes in those files or in+files in those directories.+\begin{code}+revert_cmd :: [DarcsFlag] -> [String] -> IO ()+revert_cmd opts args = withRepoLock opts $- \repository -> do+  files <- sort `fmap` getRepoPaths opts args+  when (areFileArgs files) $+       putStrLn $ "Reverting changes in "++unwords (map show files)++"..\n"+  changes <- if All `elem` opts+                   then get_unrecorded_unsorted repository+                   else get_unrecorded repository+  let pre_changed_files = apply_to_filepaths (invert changes) (map toFilePath files)+  (rec, working_dir) <- slurp_recorded_and_unrecorded repository+  case choose_touching pre_changed_files changes of+    NilFL -> putStrLn "There are no changes to revert!"+    _ -> with_selected_last_changes_to_files' "revert" opts working_dir+               pre_changed_files changes $ \ (norevert:>p) ->+        if nullFL p+        then putStrLn $ "If you don't want to revert after all," +++                        " that's fine with me!"+        else do+             let theseChanges = englishNum (lengthFL p) . This . Noun $ "change"+             yorn <- if All `elem` opts+                     then return "y"+                     else askUser $ "Do you really want to revert " ++ theseChanges "? "+             case yorn of ('y':_) -> return ()+                          _ -> exitWith $ ExitSuccess+             withGutsOf repository $ do+                 add_to_pending repository $ invert p+                 when (Debug `elem` opts) $ putStrLn "About to write the unrevert file."+                 case commute (norevert:>p) of+                   Just (p':>_) -> write_unrevert repository p' rec NilFL+                   Nothing -> write_unrevert repository (norevert+>+p) rec NilFL+                 when (Debug `elem` opts) $ putStrLn "About to apply to the working directory."+                 applyToWorking repository opts (invert p) `catch` \e ->+                     fail ("Unable to apply inverse patch!" ++ show e)+  sync_repo repository+  putStrLn "Finished reverting."+\end{code}+
+ src/Darcs/Commands/Rollback.lhs view
@@ -0,0 +1,158 @@+%  Copyright (C) 2002-2004,2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs rollback}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Rollback ( rollback ) where++import Control.Monad ( when, filterM )+import System.Exit ( exitWith, ExitCode(..) )+import Data.List ( sort )+import Data.Maybe ( isJust )+import System.Directory ( removeFile )++import Darcs.Commands ( DarcsCommand(..), nodefaults, loggers )+import Darcs.Arguments ( DarcsFlag(MarkConflicts), getRepoPaths, get_author,+                         definePatches,+                         working_repo_dir, nocompress,+                         author, patchname_option, ask_long_comment,+                         leave_test_dir, notest, list_registered_files,+                         match_several_or_last, all_interactive, umask_option+                       )+import Darcs.RepoPath ( toFilePath )+import Darcs.Repository ( amInRepository, withRepoLock, ($-), applyToWorking,+                          slurp_recorded_and_unrecorded, read_repo, slurp_recorded,+                          tentativelyMergePatches, withGutsOf,+                          finalizeRepositoryChanges, sync_repo )+import Darcs.Patch ( summary, invert, namepatch, effect, fromPrims )+import Darcs.Patch.Ordered+import Darcs.Hopefully ( n2pia )+import Darcs.Lock ( world_readable_temp )+import Darcs.SlurpDirectory ( empty_slurpy, wait_a_moment )+import Darcs.Match ( first_match )+import Darcs.SelectChanges ( with_selected_last_changes_to_files_reversed,+                             with_selected_last_changes_to_files' )+import Darcs.Commands.Record ( file_exists, get_log )+import Darcs.Commands.Unrecord ( get_last_patches )+import Darcs.Utils ( clarify_errors )+import Darcs.Progress ( debugMessage )+import Darcs.Sealed ( Sealed(..), unsafeUnflippedseal )+import IsoDate ( getIsoDateTime )+#include "impossible.h"+\end{code}++\begin{code}+rollback_description :: String+rollback_description =+ "Record a new patch reversing some recorded changes."+\end{code}++\options{rollback}++\haskell{rollback_help} If you decide you didn't want to roll back a patch+after all, you can reverse its effect by obliterating the rolled-back patch.++Rollback can actually allow you to roll back a subset of the changes made+by the selected patch or patches.  Many of the options available in+rollback behave similarly to the options for unrecord~\ref{unrecord} and+record~\ref{record}.++\begin{code}+rollback_help :: String+rollback_help =+ "Rollback is used to undo the effects of one or more patches without actually\n"+++ "deleting them.  Instead, it creates a new patch reversing selected portions.\n"+++ "of those changes. Unlike obliterate and unrecord (which accomplish a similar\n"+++ "goal) rollback is perfectly safe, since it leaves in the repository a record\n"+++ "of its changes.\n"+\end{code}+\begin{code}+rollback :: DarcsCommand+rollback = DarcsCommand {command_name = "rollback",+                         command_help = rollback_help,+                         command_description = rollback_description,+                         command_extra_args = -1,+                         command_extra_arg_help = ["[FILE or DIRECTORY]..."],+                         command_command = rollback_cmd,+                         command_prereq = amInRepository,+                         command_get_arg_possibilities = list_registered_files,+                         command_argdefaults = nodefaults,+                         command_advanced_options = [nocompress,umask_option],+                         command_basic_options = [match_several_or_last,+                                                  all_interactive,+                                                  author, patchname_option, ask_long_comment,+                                                  notest, leave_test_dir,+                                                  working_repo_dir]}+\end{code}+\begin{code}+rollback_cmd :: [DarcsFlag] -> [String] -> IO ()+rollback_cmd opts args = withRepoLock opts $- \repository -> do+  let (logMessage,_,_) = loggers opts+  rec <- if null args then return empty_slurpy+         else slurp_recorded repository+  files <- sort `fmap` getRepoPaths opts args+  existing_files <- map toFilePath `fmap` filterM (file_exists rec) files+  non_existent_files <- map toFilePath `fmap` filterM (fmap not . file_exists rec) files+  when (not $ null existing_files) $+       logMessage $ "Recording changes in "++unwords existing_files++":\n"+  when (not $ null non_existent_files) $+       logMessage $ "Non existent files or directories: "++unwords non_existent_files++"\n"+  when ((not $ null non_existent_files) && null existing_files) $+       fail "None of the files you specified exist!"+  (recorded, working_dir) <- slurp_recorded_and_unrecorded repository+  Sealed allpatches <- read_repo repository+  let patches = if first_match opts then get_last_patches opts allpatches+                                    else unsafeUnflippedseal $ headRL allpatches+  with_selected_last_changes_to_files_reversed "rollback" opts recorded existing_files+      (reverseRL patches) $+    \ (_ :> ps) ->+    do when (nullFL ps) $ do logMessage "No patches selected!"+                             exitWith ExitSuccess+       definePatches ps+       with_selected_last_changes_to_files' "rollback" opts working_dir+               existing_files (effect ps) $ \ (_:>ps'') ->+         do when (nullFL ps'') $ do logMessage "No changes selected!"+                                    exitWith ExitSuccess+            let make_log = world_readable_temp "darcs-rollback"+                newlog = Just ("", "":"rolling back:":"":lines (show $ summary ps ))+            --tentativelyRemovePatches repository opts (mapFL_FL hopefully ps)+            (name, my_log, logf) <- get_log opts newlog make_log $ invert ps''+            date <- getIsoDateTime+            my_author <- get_author opts+            let rbp = n2pia $ namepatch date name my_author my_log $ fromPrims $ invert ps''+            debugMessage "Adding rollback patch to repository."+            pw <- tentativelyMergePatches repository "rollback" (MarkConflicts : opts)+                  NilFL (rbp :>: NilFL)+            debugMessage "Finalizing rollback changes..."+            withGutsOf repository $ do+              finalizeRepositoryChanges repository+              debugMessage "About to apply rolled-back changes to working directory."+              -- so work will be more recent than rec:+              revertable $ do wait_a_moment+                              applyToWorking repository opts pw+            when (isJust logf) $ removeFile (fromJust logf)+            sync_repo repository+            logMessage $ "Finished rolling back."+          where revertable x = x `clarify_errors` unlines+                  ["Error applying patch to the working directory.","",+                   "This may have left your working directory an inconsistent",+                   "but recoverable state. If you had no un-recorded changes",+                   "by using 'darcs revert' you should be able to make your",+                   "working directory consistent again."]+\end{code}+
+ src/Darcs/Commands/Send.lhs view
@@ -0,0 +1,408 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs send}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Send ( send ) where+import System.Exit ( exitWith, ExitCode( ExitSuccess ) )+import System.IO.Error ( ioeGetErrorString )+import System.IO ( hClose )+import Control.Monad ( when, unless, liftM, guard, mplus )+import Data.Maybe (isJust, isNothing )++import Darcs.Commands ( DarcsCommand(..) )+import Darcs.Arguments ( DarcsFlag( EditDescription, LogFile, RmLogFile,+                                   Target, OutputAutoName, Output, Context,+                                   DryRun, Verbose, Quiet+                                 ),+                         fix_filepath, definePatches,+                        get_cc, get_author, working_repo_dir,+                        edit_description, logfile, rmlogfile,+                        sign, get_subject, no_deps,+                        match_several, set_default, output_auto_name,+                        output, cc, subject, target, author, sendmail_cmd,+                        remote_repo, ssh_cm,+                        all_interactive, get_sendmail_cmd,+                        print_dry_run_message_and_exit,+                        summary,+                        from_opt, dry_run, send_to_context,+                      )+import Darcs.Hopefully ( PatchInfoAnd, hopefully, info )+import Darcs.Repository ( PatchSet, Repository,+                    amInRepository, identifyRepositoryFor, withRepoReadLock, ($-),+                    read_repo, slurp_recorded, prefsUrl )+import Darcs.Patch ( RepoPatch, description, apply_to_slurpy, invert )+import Darcs.Patch.Ordered ( FL(..), RL(..), (:>)(..), (:\/:)(..), unsafeUnRL,+                             mapRL_RL, mapFL, mapRL, reverseRL, mapFL_FL, lengthFL, nullFL )+import Darcs.Patch.Bundle ( make_bundle, scan_context )+import Darcs.Patch.Info ( just_name )+import Darcs.Repository.Prefs ( defaultrepo, set_defaultrepo, get_preflist )+import Darcs.External ( signString, sendEmailDoc, fetchFilePS, Cachable(..), generateEmail )+import FastPackedString ( unpackPS, mmapFilePS )+import Darcs.Lock ( withOpenTemp, writeDocBinFile, readDocBinFile, world_readable_temp, removeFileMayNotExist )+import Darcs.SelectChanges ( with_selected_changes )+import Darcs.Patch.Depends ( get_common_and_uncommon )+import Darcs.Utils ( askUser, catchall, edit_file, formatPath )+import Darcs.Progress ( debugMessage )+import Darcs.Email ( make_email )+import Printer ( Doc, vsep, vcat, text, ($$), putDocLn, putDoc )+import FileName ( patch_filename )+import Darcs.RepoPath ( toPath )+import Darcs.Sealed ( Sealed(..) )+import qualified HTTP+#include "impossible.h"+\end{code}+\begin{code}+send_description :: String+send_description =+ "Send by email a bundle of one or more patches."+\end{code}++\options{send}++\haskell{send_help}+\begin{code}+send_help :: String+send_help =+ "Send is used to prepare a bundle of patches that can be applied to a target\n"+++ "repository.  Send accepts the URL of the repository as an argument.  When\n"+++ "called without an argument, send will use the most recent repository that\n"+++ "was either pushed to, pulled from or sent to.  By default, the patch bundle\n"+++ "is sent by email, although you may save it to a file.\n"+\end{code}++Do not confuse the \verb!--author! options with the return address+that \verb!darcs send! will set for your patch bundle.++For example, if you have two email addresses A and B:+\begin{description}+\item  If you use+\verb!--author A! but your machine is configured to send mail from+address B by default, then the return address on your message will be B.++\item If you use \verb!--from A! and your mail client supports setting the+From: address arbitrarily (some non-Unix-like mail clients, especially,+may not support this), then the return address will be A; if it does+not support this, then the return address will be B.++\item If you supply neither \verb!--from! nor \verb!--author!, then the return+address will be B.+\end{description}++In addition, unless you specify the sendmail command with+\verb!--sendmail-command!, darcs sends email using the default email+command on your computer. This default command is determined by the+\verb!configure! script. Thus, on some non-Unix-like OSes,+\verb!--from! is likely to not work at all.++\begin{code}+send :: DarcsCommand+send = DarcsCommand {command_name = "send",+                     command_help = send_help,+                     command_description = send_description,+                     command_extra_args = 1,+                     command_extra_arg_help = ["[REPOSITORY]"],+                     command_command = send_cmd,+                     command_prereq = amInRepository,+                     command_get_arg_possibilities = get_preflist "repos",+                     command_argdefaults = defaultrepo,+                     command_advanced_options = [logfile, rmlogfile,+                                                 remote_repo,+                                                 send_to_context, ssh_cm],+                     command_basic_options = [match_several, no_deps,+                                             all_interactive,+                                             from_opt, author,+                                             target,cc,subject,+                                             output,output_auto_name,sign]+                                             ++dry_run++[summary,+                                             edit_description,+                                             set_default, working_repo_dir,+                                             sendmail_cmd]}+\end{code}+\begin{code}+send_cmd :: [DarcsFlag] -> [String] -> IO ()+send_cmd input_opts [""] = send_cmd input_opts []+send_cmd input_opts [unfixedrepodir] = withRepoReadLock input_opts $- \repository -> do+  context_ps <- the_context input_opts+  case context_ps of+    Just them -> send_to_them repository input_opts [] "CONTEXT" them+    Nothing -> do+        let repodir = toPath $ fix_filepath input_opts unfixedrepodir+        -- Test to make sure we aren't trying to push to the current repo+        when (repodir == "") $+           fail ("Can't send to current repository! Did you mean send -"++"-context?")+        repo <- identifyRepositoryFor repository repodir+        Sealed them <- read_repo repo+        old_default <- defaultrepo input_opts "" []+        set_defaultrepo repodir input_opts+        when (old_default == [repodir] && not (Quiet `elem` input_opts)) $+             putStrLn $ "Creating patch to "++formatPath repodir++"..."+        wtds <- decide_on_behavior input_opts repo+        send_to_them repository input_opts wtds repodir them+    where the_context [] = return Nothing+          the_context (Context foo:_)+              = (Just . scan_context )`liftM` mmapFilePS foo+          the_context (_:fs) = the_context fs+send_cmd _ _ = impossible++send_to_them :: RepoPatch p => Repository p -> [DarcsFlag] -> [WhatToDo] -> String -> PatchSet p -> IO ()+send_to_them repo opts wtds their_name them = do+  let am_verbose = Verbose `elem` opts+      am_quiet = Quiet `elem` opts+      putVerbose s = when am_verbose $ putDocLn s+      putInfo s = when (not am_quiet) $ putStrLn s+      patch_desc p = just_name $ info p+      make_fname tbs = patch_filename $ patch_desc $ headFL tbs+      headFL (x:>:_) = x+      headFL _ = impossible+  Sealed us <- read_repo repo+  case get_common_and_uncommon (us, them) of+    (common, us' :\/: _) -> do+     putVerbose $ text "We have the following patches to send:"+               $$ (vcat $ mapRL description $ head $ unsafeUnRL us')+     case us' of+         NilRL:<:NilRL -> do putInfo "No recorded local changes to send!"+                             exitWith ExitSuccess+         _ -> return ()+     s <- slurp_recorded repo+     let our_ps = reverseRL $ head $ unsafeUnRL us'+     with_selected_changes "send" opts s our_ps $+      \ (to_be_sent :> _) -> do+      print_dry_run_message_and_exit "send" opts to_be_sent+      when (nullFL to_be_sent) $ do+          putInfo "You don't want to send any patches, and that's fine with me!"+          exitWith ExitSuccess+      definePatches to_be_sent+      bundle <- signString opts $ make_bundle opts+                (fromJust $ apply_to_slurpy+                 (invert $+                  mapRL_RL hopefully $ head $ unsafeUnRL us') s)+                common (mapFL_FL hopefully to_be_sent)+      let outname = get_output opts `mplus` (do guard (OutputAutoName `elem` opts); return $ make_fname to_be_sent)+      case outname of+        Just fname -> do (d,f) <- get_description opts to_be_sent+                         if fname == "-" then putDoc (d $$ bundle)+                                         else writeDocBinFile fname (d $$ bundle)+                         cleanup f+                         putStrLn $ "Wrote patch to " ++ fname ++ "."+        Nothing ->+         let+           auto_subject (p:>:NilFL)  = "darcs patch: " ++ trim (patch_desc p) 57+           auto_subject (p:>:ps) = "darcs patch: " ++ trim (patch_desc p) 43 +++                            " (and " ++ show (lengthFL ps) ++ " more)"+           auto_subject _ = error "Tried to get a name from empty patch list."+           trim st n = if length st <= n then st+                       else take (n-3) st ++ "..."+           in do+           thetargets <- get_targets wtds+           from <- get_author opts+           let thesubject = case get_subject opts of+                            Nothing -> auto_subject to_be_sent+                            Just subj -> subj+           (mailcontents, mailfile) <- get_description opts to_be_sent+           let body = make_email their_name (Just mailcontents) bundle+                        (Just $ make_fname to_be_sent)+               contentAndBundle = Just (mailcontents, bundle)+           (sendEmailDoc from (lt [t | SendMail t <- thetargets]) (thesubject) (get_cc opts)+                          (get_sendmail_cmd opts) contentAndBundle body)+                          `catch` \e -> let+                              msg = "Email body left in " in do+                              when (isJust mailfile) $+                                  putStrLn $ msg ++ (fromJust mailfile) ++ "."+                              fail $ ioeGetErrorString e+           cleanup mailfile+           nbody <- withOpenTemp $ \ (fh,fn) -> do+               generateEmail fh from (lt [t | SendMail t <- thetargets]) thesubject (get_cc opts) body+               hClose fh+               mmapFilePS fn+           putInfo $ "Successfully sent patch bundle to: "++lt [ t | SendMail t <- thetargets ]++"."+           forM_ [ p | Post p <- thetargets] $ \url -> do+             putInfo $ "posting patch to " ++ url+             HTTP.postUrl url (unpackPS nbody) "message/rfc822"++      where cleanup (Just mailfile) = when (isNothing (get_fileopt opts) || (RmLogFile `elem` opts)) $+                                      removeFileMayNotExist mailfile+            cleanup Nothing = return ()+            lt [t] = t+            lt [t,""] = t+            lt (t:ts) = t++" , "++lt ts+            lt [] = ""++\end{code}++\begin{options}+--output, --to, --cc+\end{options}++The \verb!--output!, \verb!--output-auto-name!, and \verb!--to! flags determine+what darcs does with the patch bundle after creating it.  If you provide an+\verb!--output!  argument, the patch bundle is saved to that file.  If you+specify \verb!--output-auto-name!, the patch bundle is saved to a file with an+automatically generated name.  If you give one or more \verb!--to! arguments,+the bundle of patches is sent to those locations. The locations may either be email+addresses or urls that the patch should be submitted to via HTTP.++If you don't provide any of these options, darcs will look at the contents of+the \verb!_darcs/prefs/email! file in the target repository (if it exists), and+send the patch by email to that address.  In this case, you may use the+\verb!--cc! option to specify additional recipients without overriding the+default repository email address.++If there is no email address associated with the repository, darcs will+prompt you for an email address.++\begin{options}+--subject+\end{options}++Use the \verb!--subject! flag to set the subject of the e-mail to be sent.+If you don't provide a subject on the command line, darcs will make one up+based on names of the patches in the patch bundle.+++\begin{code}++forM_ :: (Monad m) => [a] -> (a -> m b) -> m ()+forM_ = (flip mapM_)++data WhatToDo+    = Post String        -- ^ POST the patch via HTTP+    | SendMail String    -- ^ send patch via email+++decide_on_behavior :: RepoPatch p => [DarcsFlag] -> Repository p -> IO [WhatToDo]+decide_on_behavior opts the_remote_repo =+    case the_targets of+    [] ->+          if (isJust $ get_output opts) || (OutputAutoName `elem` opts)+          then return []+          else+          do wtds <- check_post+             unless (null wtds) $ announce_recipients wtds+             return wtds+    ts -> do announce_recipients ts+             return ts+    where the_targets = collect_targets opts+          check_post | HTTP.exists = ((readPost . unpackPS) `liftM`+                           fetchFilePS (prefsUrl the_remote_repo++"/post")+                                       (MaxAge 600))+                          `catchall` who_to_email+                     | otherwise = who_to_email+          who_to_email =+              do email <- (unpackPS `liftM`+                           fetchFilePS (prefsUrl the_remote_repo++"/email")+                                       (MaxAge 600))+                          `catchall` return ""+                 if '@' `elem` email then return . map SendMail $ lines email+                                     else return []+          readPost p = map pp (lines p) where+            pp ('m':'a':'i':'l':'t':'o':':':s) = SendMail s+            pp s = Post s+          putInfoLn s = unless (Quiet `elem` opts) $ putStrLn s+          announce_recipients emails =+            let pn (SendMail s) = s+                pn (Post p) = p+            in if DryRun `elem` opts+            then putInfoLn $ "Patch bundle would be sent to: "++unwords (map pn emails)+            else when (null the_targets) $+                 putInfoLn $ "Patch bundle will be sent to: "++unwords (map pn emails)+\end{code}++\begin{code}+get_output :: [DarcsFlag] -> Maybe String+get_output (Output a:_) = return a+get_output (_:flags) = get_output flags+get_output [] = Nothing+\end{code}++\begin{code}+get_targets :: [WhatToDo] -> IO [WhatToDo]+get_targets [] = do liftM ((:[]) . SendMail) $ askUser "What is the target email address? "+get_targets wtds = return wtds++collect_targets :: [DarcsFlag] -> [WhatToDo]+collect_targets flags = [ f t | Target t <- flags ] where+    f url@('h':'t':'t':'p':':':_) = Post url+    f em = SendMail em+++\end{code}++\begin{options}+--matches, --patches, --tags, --no-deps+\end{options}++The \verb!--patches!, \verb!--matches!, \verb!--tags!, and \verb!--no-deps!+options can be used to select which patches to send, as described in+subsection~\ref{selecting}.++\begin{options}+--edit-description+\end{options}++If you want to include a description or explanation along with the bundle+of patches, you need to specify the \verb!--edit-description! flag, which+will cause darcs to open up an editor with which you can compose a message+to go along with your patches.++\begin{options}+--sendmail-command+\end{options}++If you want to use a command different from the default one for sending email,+you need to specify a command line with the \verb!--sendmail-command! option. The+command line can contain some format specifiers which are replaced by the actual+values. Accepted format specifiers are \verb!%s! for subject, \verb!%t! for to,+\verb!%c! for cc, \verb!%b! for the body of the mail, \verb!%f! for from, \verb!%a!+for the patch bundle and the same specifiers in uppercase for the URL-encoded values.+Additionally you can add \verb!%<! to the end of the command line if the command+expects the complete email message on standard input. E.g.\ the command lines for evolution+and msmtp look like this:++\begin{verbatim}+evolution "mailto:%T?subject=%S&attach=%A&cc=%C&body=%B"+msmtp -t %<+\end{verbatim}++\begin{code}+get_description :: RepoPatch p => [DarcsFlag] -> FL (PatchInfoAnd p) -> IO (Doc, Maybe String)+get_description opts patches =+    case get_filename of+        Just f -> do file <- f+                     when (EditDescription `elem` opts) $ do+                       when (isNothing $ get_fileopt opts) $+                            writeDocBinFile file patchdesc+                       debugMessage $ "About to edit file " ++ file+                       edit_file file+                       return ()+                     doc <- readDocBinFile file+                     return (doc, Just file)+        Nothing -> return (patchdesc, Nothing)+    where patchdesc = vsep $ mapFL description patches+          get_filename = case get_fileopt opts of+                                Just f -> Just $ return f+                                Nothing -> if EditDescription `elem` opts+                                              then Just tempfile+                                              else Nothing+          tempfile = world_readable_temp "darcs-temp-mail"++get_fileopt :: [DarcsFlag] -> Maybe String+get_fileopt (LogFile f:_) = Just f+get_fileopt (_:flags) = get_fileopt flags+get_fileopt [] = Nothing+\end{code}
+ src/Darcs/Commands/SetPref.lhs view
@@ -0,0 +1,120 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs setpref}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.SetPref ( setpref ) where++import System.Exit ( exitWith, ExitCode(..) )+import Control.Monad (when)++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag, working_repo_dir, umask_option )+import Darcs.Repository ( amInRepository, add_to_pending, withRepoLock, ($-) )+import Darcs.Patch ( changepref )+import Darcs.Patch.Ordered ( FL(..) )+import Darcs.Repository.Prefs ( get_prefval, change_prefval, )+#include "impossible.h"+\end{code}++\begin{code}+setpref_description :: String+setpref_description =+ "Set a value for a preference (test, predist, ...)."+\end{code}++\options{setpref}+Usage example:+\begin{verbatim}+% darcs setpref test "echo I am not really testing anything."+\end{verbatim}++\haskell{setpref_help} If you just want to set the pref value in your+repository only, you can just edit ``\verb!_darcs/prefs/prefs!''.  Changes+you make in that file will be preserved.++The ``\verb!_darcs/prefs/prefs!'' holds the only preferences information+that can propagate between repositories by pushes and pulls, and the only+way this happens is when the setprefs command is used.  Note that although+prefs settings are included in patches, they are \emph{not} fully version+controlled.  In particular, depending on the order in which a series of+merges is performed, you may end up with a different final prefs+configuration.  In practice I don't expect this to be a problem, as the+prefs usually won't be changed very often.++\begin{code}+valid_pref_data :: [String]+valid_pref_data = ["test", "predist", "boringfile", "binariesfile"]+\end{code}+The following values are valid preferences options which can be configured+using setpref:+\begin{itemize}+\item ``test'' --- the command to run as a test script.+\item ``predist'' --- a command to run prior to tarring up a distribution+  tarball.  Typically this would consist of autoconf and/or automake.+\item ``boringfile'' --- the name of a file to read instead of the+  ``boring'' prefs file.+\item ``binariesfile'' --- the name of a file to read instead of the+  ``binaries'' prefs file.+\end{itemize}++\begin{code}+setpref_help :: String+setpref_help =+ "Setpref allows you to set a preference value in a way that will\n"+++ "propagate to other repositories.\n\n"+++ "Valid preferences are: "++unwords valid_pref_data++".\n"+\end{code}++\begin{code}+setpref :: DarcsCommand+setpref = DarcsCommand {command_name = "setpref",+                        command_help = setpref_help,+                        command_description = setpref_description,+                        command_extra_args = 2,+                        command_extra_arg_help = ["<PREF>",+                                                  "<VALUE>"],+                        command_command = setpref_cmd,+                        command_prereq = amInRepository,+                        command_get_arg_possibilities = return valid_pref_data,+                        command_argdefaults = nodefaults,+                        command_advanced_options = [umask_option],+                        command_basic_options =+                            [working_repo_dir]}+\end{code}++\begin{code}+setpref_cmd :: [DarcsFlag] -> [String] -> IO ()+setpref_cmd opts [pref,val] = withRepoLock opts $- \repository -> do+  when (' ' `elem` pref) $ do+    putStrLn $ "'"++pref+++               "' is not a valid preference name:  no spaces allowed!"+    exitWith $ ExitFailure 1+  when (not $ pref `elem` valid_pref_data) $ do+    putStrLn $ "'"++pref++"' is not a valid preference name!"+    putStrLn $ "Try one of:  "++unwords valid_pref_data++""+    exitWith $ ExitFailure 1+  oval <- get_prefval pref+  old <- case oval of Just v -> return v+                      Nothing -> return ""+  change_prefval pref old val+  putStrLn $ "Changing value of "++pref++" from '"++old++"' to '"++val++"'"+  add_to_pending repository (changepref pref old val :>: NilFL)+setpref_cmd _ _ = impossible+\end{code}+
+ src/Darcs/Commands/Show.lhs view
@@ -0,0 +1,71 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.Commands.Show ( show_command, list, query ) where++import Darcs.Commands ( DarcsCommand(..),+                        CommandControl(Command_data, Hidden_command),+                        command_alias,+                      )+import Darcs.Commands.ShowAuthors ( show_authors )+import Darcs.Commands.ShowBug ( show_bug )+import Darcs.Commands.ShowContents ( show_contents )+import Darcs.Commands.ShowFiles ( show_files, show_manifest )+import Darcs.Commands.ShowTags ( show_tags )+import Darcs.Commands.ShowRepo ( show_repo )+import Darcs.Repository ( amInRepository )++show_description :: String+show_description = "Show information which is stored by darcs."++show_help :: String+show_help =+ "Use the --help option with the subcommands to obtain help for\n"+++ "subcommands (for example, \"darcs show files --help\").\n"++show_command :: DarcsCommand+show_command = SuperCommand {command_name = "show",+                      command_help = show_help,+                      command_description = show_description,+                      command_prereq = amInRepository,+                      command_sub_commands = [Hidden_command show_bug,+                                              Command_data show_contents,+                                              Command_data show_files, Hidden_command show_manifest,+                                              Command_data show_repo,+                                              Command_data show_authors,+                                              Command_data show_tags]+                     }++query :: DarcsCommand+query = command_alias "query" show_command++list :: DarcsCommand+list = command_alias "list" show_command+\end{code}++\subsection{darcs show}++The show command provides access to several subcommands which can be+used to investigate the state of a repository.++\input{Darcs/Commands/ShowAuthors.lhs}+\input{Darcs/Commands/ShowContents.lhs}+\input{Darcs/Commands/ShowFiles.lhs}+\input{Darcs/Commands/ShowTags.lhs}+\input{Darcs/Commands/ShowRepo.lhs}+
+ src/Darcs/Commands/ShowAuthors.lhs view
@@ -0,0 +1,78 @@+%  Copyright (C) 2008 Eric Kow+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsubsection{darcs show authors}+\begin{code}+module Darcs.Commands.ShowAuthors ( show_authors ) where++import Data.List ( sort, group )++import Darcs.Arguments ( DarcsFlag(..), working_repo_dir )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.External ( viewDoc )+import Darcs.Hopefully ( info )+import Darcs.Repository ( amInRepository, read_repo, withRepository, ($-) )+import Darcs.Patch.Info ( pi_author )+import Darcs.Patch.Ordered ( mapRL, concatRL )+import Darcs.Sealed ( unsafeUnseal )+import Printer ( text )+\end{code}++\options{show authors}++\haskell{show_authors_help}++\begin{code}+show_authors_description :: String+show_authors_description = "Show all authors in the repository."+\end{code}++\begin{code}+show_authors_help :: String+show_authors_help =+ "The authors command writes a list of all patch authors in the repository to\n" +++ "standard output."+\end{code}++\begin{code}+show_authors :: DarcsCommand+show_authors = DarcsCommand {+  command_name = "authors",+  command_help = show_authors_help,+  command_description = show_authors_description,+  command_extra_args = 0,+  command_extra_arg_help = [],+  command_command = authors_cmd,+  command_prereq = amInRepository,+  command_get_arg_possibilities = return [],+  command_argdefaults = nodefaults,+  command_advanced_options = [],+  command_basic_options = [working_repo_dir] }++authors_cmd :: [DarcsFlag] -> [String] -> IO ()+authors_cmd opts _ = withRepository opts $- \repository -> do+  patches <- read_repo repository+  let authors = mapRL process $ concatRL $ unsafeUnseal patches+  viewDoc $ text $ unlines $+   if Verbose `elem` opts+      then authors+      else reverse $ map shownames $ sort $+           map (\s -> (length s,head s)) $ group $ sort authors+  where+    process =  pi_author . info+    shownames (n, a) = show n ++ "\t" ++ a+\end{code}
+ src/Darcs/Commands/ShowBug.lhs view
@@ -0,0 +1,58 @@+%  Copyright (C) 2007 Eric Kow+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs show bug}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.ShowBug ( show_bug ) where++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag, working_repo_dir )+import Darcs.Repository ( findRepository )+#include "impossible.h"+\end{code}++\options{show bug}+\begin{code}+show_bug_description :: String+show_bug_description = "Pretends to be a bug in darcs."+\end{code}+\haskell{show_bug_help}+\begin{code}+show_bug_help :: String+show_bug_help =+  "Show bug can be used to see what darcs would show you if you encountered.\n"+  ++"a bug in darcs.\n"++show_bug :: DarcsCommand+show_bug = DarcsCommand {command_name = "bug",+                         command_help = show_bug_help,+                         command_description = show_bug_description,+                         command_extra_args = 0,+                         command_extra_arg_help = [],+                         command_command = show_bug_cmd,+                         command_prereq = findRepository,+                         command_get_arg_possibilities = return [],+                         command_argdefaults = nodefaults,+                         command_advanced_options = [],+                         command_basic_options = [working_repo_dir]}+\end{code}++\begin{code}+show_bug_cmd :: [DarcsFlag] -> [String] -> IO ()+show_bug_cmd _ _ = bug "This is actually a fake bug in darcs."+\end{code}
+ src/Darcs/Commands/ShowContents.lhs view
@@ -0,0 +1,86 @@+%  Copyright (C) 2007 Eric Kow+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsubsection{darcs show contents}+\begin{code}+module Darcs.Commands.ShowContents ( show_contents ) where++import Control.Monad ( filterM )+import System.Directory( doesFileExist )+import System.IO ( stdout )++import FastPackedString ( readFilePS, hPutPS )+import Workaround ( getCurrentDirectory )+import Darcs.Utils ( withCurrentDirectory )++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag,+                         match_one,+                         working_repo_dir, fix_filepaths, getRepoPath,+                      )+import Darcs.FilePathUtils ( just_dir )+import Darcs.RepoPath ( toFilePath )+import Darcs.Match ( get_nonrange_match_s, have_nonrange_match, apply_patches_to_some_files,+                   )+import Darcs.Repository ( withRepository, ($-), findRepository )+import Darcs.Repository ( createPartialsPristineDirectoryTree )+import Darcs.Lock ( withTempDir )+\end{code}++\options{show contents}+\begin{code}+show_contents_description :: String+show_contents_description = "Outputs a specific version of a file."+\end{code}+\haskell{show_contents_help}+\begin{code}+show_contents_help :: String+show_contents_help =+  "Show contents can be used to display an earlier version of some file(s).\n"+++  "If you give show contents no version arguments, it displays the recorded\n"+++  "version of the file(s).\n"++show_contents :: DarcsCommand+show_contents = DarcsCommand {command_name = "contents",+                              command_help = show_contents_help,+                              command_description = show_contents_description,+                              command_extra_args = -1,+                              command_extra_arg_help+                                    = ["[FILE]..."],+                              command_command = show_contents_cmd,+                              command_prereq = findRepository,+                              command_get_arg_possibilities = return [],+                              command_argdefaults = nodefaults,+                              command_advanced_options = [],+                              command_basic_options = [match_one, working_repo_dir]}+\end{code}++\begin{code}+show_contents_cmd :: [DarcsFlag] -> [String] -> IO ()+show_contents_cmd opts args = withRepository opts $- \repository -> do+  formerdir <- getCurrentDirectory+  thename <- return $ just_dir formerdir+  withTempDir thename $ \dir -> do+     if have_nonrange_match opts+        then withCurrentDirectory dir $+               apply_patches_to_some_files repository path_list $ get_nonrange_match_s opts+        else createPartialsPristineDirectoryTree repository path_list dir+     filterM doesFileExist path_list >>= mapM_ (\f -> readFilePS f >>= hPutPS stdout)+  where+    path_list = if null args then [""]+                   else map toFilePath $ getRepoPath $ fix_filepaths opts args+\end{code}
+ src/Darcs/Commands/ShowFiles.lhs view
@@ -0,0 +1,105 @@+%  Copyright (C) 2005 Florian Weimer+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsubsection{darcs show files}+\label{show-files}+\begin{code}+module Darcs.Commands.ShowFiles ( show_files, show_manifest ) where+import Darcs.Arguments ( DarcsFlag(..), working_repo_dir,+                        files, directories, pending, nullFlag )+import Darcs.Commands ( DarcsCommand(..), nodefaults, command_alias )+import Darcs.Repository ( Repository, amInRepository, slurp_pending, slurp_recorded,+                          withRepository )+import Darcs.Patch ( RepoPatch )+import Darcs.SlurpDirectory ( Slurpy, list_slurpy, list_slurpy_files, list_slurpy_dirs )+\end{code}++\options{show files}++\haskell{show_files_help}++By default (and if the \verb!--pending! option is specified),+the effect of pending patches on the repository is taken into account.+In other words, if you add a file using {\tt darcs add}, it+immediately appears in the output of {\tt query manifest}, even if it+is not yet recorded.  If you specify the \verb!--no-pending! option,+{\tt query manifest} will only list recorded files (and directories).++The \verb!--files! and \verb!--directories! options control whether+files and directories are included in the output.  The+\verb!--no-files!  and \verb!--no-directories! options have the+reverse effect.  The default is to include files, but not directories.++If you specify the \verb!--null! option, the file names are written to+standard output in unescaped form, and separated by ASCII NUL bytes.+This format is suitable for further automatic processing (for example,+using \verb!xargs -0!).++\begin{code}+show_files_description :: String+show_files_description = "Show version-controlled files in the working copy."+\end{code}++\begin{code}+show_files_help :: String+show_files_help =+ "The files command lists the version-controlled files in the\n"+++ "working copy.  The similar manifest command, lists the same\n"+++ "files, excluding any directories.\n"+\end{code}++\begin{code}+show_files :: DarcsCommand+show_files = DarcsCommand {+  command_name = "files",+  command_help = show_files_help,+  command_description = show_files_description,+  command_extra_args = 0,+  command_extra_arg_help = [],+  command_command = manifest_cmd to_list_files,+  command_prereq = amInRepository,+  command_get_arg_possibilities = return [],+  command_argdefaults = nodefaults,+  command_advanced_options = [],+  command_basic_options = [files, directories, pending, nullFlag,+                          working_repo_dir] }++show_manifest :: DarcsCommand+show_manifest = command_alias "manifest" show_files {+  command_command = manifest_cmd to_list_manifest+}++to_list_files, to_list_manifest :: [DarcsFlag] -> Slurpy -> [FilePath]+to_list_files    opts = files_dirs (NoFiles `notElem` opts) (NoDirectories `notElem` opts)+to_list_manifest opts = files_dirs (NoFiles `notElem` opts) (Directories `elem` opts)++files_dirs :: Bool -> Bool -> Slurpy -> [FilePath]+files_dirs False False = \_ -> []+files_dirs False True  = list_slurpy_dirs+files_dirs True  False = list_slurpy_files+files_dirs True  True  = list_slurpy++manifest_cmd :: ([DarcsFlag] -> Slurpy -> [FilePath]) -> [DarcsFlag] -> [String] -> IO ()+manifest_cmd to_list opts _ = do+    list <- (to_list opts) `fmap` withRepository opts slurp+    mapM_ output list+    where slurp :: RepoPatch p => Repository p -> IO Slurpy+          slurp = if NoPending `notElem` opts+                  then slurp_pending else slurp_recorded+          output_null name = do { putStr name ; putChar '\0' }+          output = if NullFlag `elem` opts then output_null else putStrLn+\end{code}
+ src/Darcs/Commands/ShowRepo.lhs view
@@ -0,0 +1,195 @@+%  Copyright (C) 2007 Kevin Quick+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsubsection{darcs show repo}+%%\label{show-repo}++\options{show repo}++The \verb!show repo! displays information about+the current repository: the location, the type, etc.++This is provided as informational output for two purposes: curious+users and scripts invoking darcs.  For the latter, this information+can be parsed to facilitate the script; for example,+\verb!darcs show repo | grep Root: | awk {print $2}!+can be used to locate the+top-level \verb!_darcs! directory from anyplace within a darcs repository+working directory.++\begin{code}+module Darcs.Commands.ShowRepo ( show_repo ) where++import Data.Char ( toLower, isSpace )+import Data.List ( intersperse )+import Control.Monad ( when, unless )+import Text.Html ( tag, stringToHtml )+import FastPackedString ( unpackPS )+import Darcs.Arguments ( DarcsFlag(..), working_repo_dir, files, xmloutput )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Repository ( withRepository, ($-), amInRepository, read_repo )+import Darcs.Repository.Internal ( Repository(..), RepoType(..) )+import Darcs.Repository.Format ( RepoFormat(..) )+import Darcs.Repository.Pristine ( Pristine )+import Darcs.Repository.Prefs ( Cache, get_preflist )+import Darcs.Repository.Motd ( get_motd )+import Darcs.Global ( darcsdir )+import Darcs.Patch ( RepoPatch )+import Darcs.Patch.Ordered ( lengthRL, mapRL_RL, unsafeUnRL )+import Darcs.Sealed ( unsealM )+\end{code}++\begin{code}+show_repo_help :: String+show_repo_help =+ "The repo command displays information about the current repository\n" +++ "(location, type, etc.).  Some of this information is already available\n" +++ "by inspecting files within the "++darcsdir++" directory and some is internal\n" +++ "information that is informational only (i.e. for developers).  This\n" +++ "command collects all of the repository information into a readily\n" +++ "available source.\n"++show_repo_description :: String+show_repo_description = "Show repository summary information"+\end{code}+++\begin{code}+show_repo :: DarcsCommand+show_repo = DarcsCommand { command_name = "repo",+                           command_help = show_repo_help,+                           command_description = show_repo_description,+                           command_extra_args = 0,+                           command_extra_arg_help = [],+                           command_command = repo_cmd,+                           command_prereq = amInRepository,+                           command_get_arg_possibilities = return [],+                           command_argdefaults = nodefaults,+                           command_advanced_options = [],+                           command_basic_options = [working_repo_dir, files, xmloutput] }+\end{code}++\begin{options}+--files, --no-files+\end{options}++If the \verb!--files! option is specified (the default), then the+\verb!show repo! operation will read patch information from the+repository and display the number of patches in the repository.  The+\verb!--no-files! option can be used to suppress this operation (and+improve performance).++\begin{code}+repo_cmd :: [DarcsFlag] -> [String] -> IO ()+repo_cmd opts _ = let put_mode = if XMLOutput `elem` opts then showInfoXML else showInfoUsr+                  in withRepository opts $- \repository -> showRepo (putInfo put_mode) repository+\end{code}++\begin{options}+--human-readable, --xml-output+\end{options}++By default, the \verb!show repo! displays output in human readable+form, but the \verb!--xml-output! option can be used to obtain+XML-formatted to facilitate regular parsing by external tools.++\begin{code}+-- Some convenience functions to output a labelled text string or an+-- XML tag + value (same API).  If no value, output is suppressed+-- entirely.  Borrow some help from Text.Html to perform XML output.++type ShowInfo = String -> String -> String++showInfoXML :: ShowInfo+showInfoXML t i = show $ tag (safeTag t) $ stringToHtml i++safeTag :: String -> String+safeTag [] = []+safeTag (' ':cs) = safeTag cs+safeTag ('#':cs) = "num_" ++ (safeTag cs)+safeTag (c:cs) = toLower c : safeTag cs++-- labelled strings: labels are right-aligned at 14 characters;+-- subsequent lines in multi-line output are indented accordingly.+showInfoUsr :: ShowInfo+showInfoUsr t i = (replicate (14 - length(t)) ' ') ++ t ++ ": " +++                  (concat $ intersperse ('\n' : (replicate 16 ' ')) $ lines i) ++ "\n"++type PutInfo = String -> String -> IO ()+putInfo :: ShowInfo -> PutInfo+putInfo m t i = unless (null i) (putStr $ m t i)+\end{code}+++\begin{code}+-- Primary show-repo operation.  Determines ordering of output for+-- sub-displays.  The `out' argument is one of the above operations to+-- output a labelled text string or an XML tag and contained value.++showRepo :: RepoPatch p => PutInfo -> Repository p -> IO ()+showRepo out r@(Repo loc opts rf rt) = do+         when (XMLOutput `elem` opts) (putStr "<repository>\n")+         showRepoType out rt+         when (Verbose `elem` opts) (out "Show" $ show r)+         showRepoFormat out rf+         out "Root" loc+         showRepoAux out rt+         showRepoPrefs out+         unless (NoFiles `elem` opts) (numPatches r >>= (out "Num Patches" . show ))+         showRepoMOTD out r+         when (XMLOutput `elem` opts) (putStr "</repository>\n")++-- Most of the actual elements being displayed are part of the Show+-- class; that's fine for a Haskeller, but not for the common user, so+-- the routines below work to provide more human-readable information+-- regarding the repository elements.++showRepoType :: PutInfo -> RepoType p -> IO ()+showRepoType out (DarcsRepository _ _) = out "Type" "darcs"++showPristine :: PutInfo -> Pristine -> IO ()+showPristine out p = out "Pristine" $ show p++showCaches :: PutInfo -> Cache -> IO ()+showCaches out c = out "Cache" $ concat $ intersperse ", " $ lines $ show c++showRepoFormat :: PutInfo -> RepoFormat -> IO ()+showRepoFormat out (RF rf) = out "Format" $ concat $ intersperse ", " (map (concat . intersperse "|" . map unpackPS) rf)++showRepoAux :: PutInfo -> RepoType p -> IO ()+showRepoAux out (DarcsRepository pris cs) = showPristine out pris+                                            >> showCaches out cs++showRepoPrefs :: PutInfo -> IO ()+showRepoPrefs out = do+    get_preflist "prefs" >>= mapM_ prefOut+    get_preflist "author" >>= out "Author" . unlines+    get_preflist "defaultrepo" >>= out "Default Remote" . unlines+  where prefOut = uncurry out . (\(p,v) -> (p++" Pref", (dropWhile isSpace v))) . break isSpace++showRepoMOTD :: RepoPatch p => PutInfo -> Repository p -> IO ()+showRepoMOTD out (Repo loc _ _ _) = get_motd loc >>= out "MOTD" . unpackPS+\end{code}+++\begin{code}+-- Support routines to provide information used by the PutInfo operations above.++numPatches :: RepoPatch p => Repository p -> IO Int+numPatches r = read_repo r `unsealM` (return . sum . unsafeUnRL . mapRL_RL lengthRL)++\end{code}
+ src/Darcs/Commands/ShowTags.lhs view
@@ -0,0 +1,91 @@+%  Copyright (C) 2007 Florian Weimer+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsubsection{darcs show tags}+\begin{code}+module Darcs.Commands.ShowTags ( show_tags ) where+import Darcs.Arguments ( DarcsFlag(..), working_repo_dir )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Hopefully ( info )+import Darcs.Repository ( amInRepository, read_repo, withRepository, ($-) )+import Darcs.Patch.Info ( pi_tag )+import Darcs.Patch.Ordered ( mapRL, concatRL )+import Darcs.Sealed ( Sealed(..) )+import System.IO ( stderr, hPutStrLn )+-- import Printer ( renderPS )+\end{code}++\options{show tags}++\haskell{show_tags_help}++Tab characters (ASCII character 9) in tag names are changed to spaces+for better interoperability with shell tools.  A warning is printed if+this happens.++\begin{code}+show_tags_description :: String+show_tags_description = "Show all tags in the repository."+\end{code}++\begin{code}+show_tags_help :: String+show_tags_help =+ "The tags command writes a list of all tags in the repository to standard\n"+++ "output."+\end{code}++\begin{code}+show_tags :: DarcsCommand+show_tags = DarcsCommand {+  command_name = "tags",+  command_help = show_tags_help,+  command_description = show_tags_description,+  command_extra_args = 0,+  command_extra_arg_help = [],+  command_command = tags_cmd,+  command_prereq = amInRepository,+  command_get_arg_possibilities = return [],+  command_argdefaults = nodefaults,+  command_advanced_options = [],+  command_basic_options = [working_repo_dir] }++tags_cmd :: [DarcsFlag] -> [String] -> IO ()+tags_cmd opts _ = withRepository opts $- \repository -> do+  Sealed patches <- read_repo repository+  sequence_ $ mapRL process $ concatRL patches+  where process hp =+            case pi_tag $ info hp of+              Just t -> do+                 t' <- normalize t t False+                 putStrLn t'+              Nothing -> return ()+        normalize :: String -> String -> Bool -> IO String+        normalize _ [] _ = return []+        normalize t (x : xs) flag =+            if x == '\t' then do+                  if flag+                    then return ()+                    else hPutStrLn stderr+                             ("warning: tag with TAB character: " ++ t)+                  rest <- (normalize t xs True)+                  return $ ' ' : rest+            else do+                  rest <- (normalize t xs flag)+                  return $ x : rest++\end{code}
+ src/Darcs/Commands/Tag.lhs view
@@ -0,0 +1,149 @@+%  Copyright (C) 2003-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs tag}+\begin{code}+module Darcs.Commands.Tag ( tag ) where+import Control.Monad ( when )++import Darcs.Commands+import Darcs.Arguments+import Darcs.Utils ( askUser )+import Darcs.Hopefully ( n2pia )+import Darcs.Repository ( amInRepository, withRepoLock, ($-), read_repo,+                    tentativelyAddPatch, finalizeRepositoryChanges, +                  )+import Darcs.Repository.Checkpoint ( write_recorded_checkpoint )+import Darcs.Patch+import Darcs.Patch.Info+import Darcs.Patch.Depends+import Darcs.Commands.Record ( get_date )+import Darcs.Sealed ( liftSM )+\end{code}+\begin{code}+tag_description :: String+tag_description =+ "Tag the contents of the repository with a version name."+\end{code}++\options{tag}++\haskell{tag_help} Tag differs from record in that it doesn't record any+new changes, and it always depends on all patches residing in the+repository when it is tagged.  This means that one can later reproduce this+version of the repository by calling, for example:+\begin{verbatim}+% darcs get --tag "darcs 3.14" REPOLOCATION+\end{verbatim}++\begin{code}+tag_help :: String+tag_help =+ "Tag is used to name a version of this repository (i.e. the whole tree).\n"+\end{code}+\begin{code}+tag :: DarcsCommand+tag = DarcsCommand {command_name = "tag",+                    command_help = tag_help,+                    command_description = tag_description,+                    command_extra_args = -1,+                    command_extra_arg_help = ["[TAGNAME]"],+                    command_command = tag_cmd,+                    command_prereq = amInRepository,+                    command_get_arg_possibilities = return [],+                    command_argdefaults = nodefaults,+                    command_advanced_options = [nocompress,umask_option],+                    command_basic_options = [patchname_option, author,+                                            checkpoint,+                                            pipe_interactive,+                                            working_repo_dir]}+\end{code}+\begin{code}+tag_cmd :: [DarcsFlag] -> [String] -> IO ()+tag_cmd opts args = withRepoLock opts $- \repository -> do+    date <- get_date opts+    the_author <- get_author opts+    deps <- get_tags_right `liftSM` read_repo repository+    name <- if (not . null) args+            then return $ "TAG " ++ unwords args+            else get_patchname opts+    let mypatch = namepatch date name the_author [] identity+        myinfo = patchinfo date name the_author []+       in do+       tentativelyAddPatch repository opts $ n2pia $ adddeps mypatch deps+       finalizeRepositoryChanges repository+       when (CheckPoint `elem` opts) $ write_recorded_checkpoint repository myinfo+       putStrLn $ "Finished tagging patch '"++name++"'"+\end{code}+Each tagged version has a version name.+\begin{code}+get_patchname :: [DarcsFlag] -> IO String+get_patchname (PatchName n:_) = return $ "TAG "++n+get_patchname (_:flags) = get_patchname flags+get_patchname [] = do+    n <- askUser "What is the version name? "+    if n == "" then get_patchname []+               else return $ "TAG "++n+\end{code}+The version is also flagged with the person who tagged it (taken by default+from the `DARCS\_EMAIL' or `EMAIL' environment variable).  The date is also+included in the version information.++A tagged version automatically depends on all patches in the repository.  This+allows you to later reproduce precisely that version.  The tag does this by+depending on all patches in the repository, except for those which are depended+upon by other tags already in the repository.  In the common case of a sequential+series of tags, this means that the tag depends on all patches since the+last tag, plus that tag itself.++\begin{options}+--checkpoint+\end{options}+The \verb!--checkpoint! option allows the tag be used later with the+\verb!--partial! flag to \verb!get! or \verb!check!.++A partial repository only contains patches from after the checkpoint.  A+partial repository works just like a normal repository, but any command that+needs to look at the contents of a missing patch will complain and abort.++\begin{options}+--pipe+\end{options}++If you run tag with the \verb!--pipe! option, you will be prompted for the+tag name and date.  This interface is intended for scripting darcs, in+particular for writing repository conversion scripts.  The prompts are+intended mostly as useful guide (since scripts won't need them), to help+you understand the format in which to provide the input. Here's an example+of what the \verb!--pipe! prompts looks like:++\begin{verbatim}+ What is the date? Mon Nov 15 13:38:01 EST 2004+ Who is the author? David Roundy+ What is the version name? 3.0+ Finished tagging patch 'TAG 3.0'+\end{verbatim}++Using \verb!tag! creates an entry in the repository history just like \verb!record!.+It will show up with \verb!darcs changes! appearing in the format:++\begin{verbatim}+ tagged My Tag Name+\end{verbatim}++To display all tags in the repository, use the ``\verb!darcs query tags!''+command.
+ src/Darcs/Commands/TrackDown.lhs view
@@ -0,0 +1,164 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs trackdown}+\begin{code}+module Darcs.Commands.TrackDown ( trackdown ) where+import Prelude hiding ( init )+import System.Exit ( ExitCode(..) )+import System.Cmd ( system )+import System.IO ( hFlush, stdout )+import Control.Monad( when )++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag(SetScriptsExecutable), working_repo_dir,+                         set_scripts_executable )+import Darcs.Hopefully ( hopefully )+import Darcs.Repository ( amInRepository, read_repo, withRepoReadLock, ($-), withRecorded,+                          setScriptsExecutable )+import Darcs.Patch.Ordered ( unsafeUnRL, concatRL )+import Darcs.Patch ( RepoPatch, Named, description, apply, invert )+import Darcs.Sealed ( Sealed(..) )+import Printer ( putDocLn )+import Darcs.Test ( get_test )+import Darcs.Lock ( withTempDir )+\end{code}++\options{trackdown}++\begin{code}+trackdown_description :: String+trackdown_description = "Locate the most recent version lacking an error."+\end{code}++\haskell{trackdown_help}++\begin{code}+trackdown_help :: String+trackdown_help =+ "Trackdown tries to find the most recent version in the repository which\n"+++ "passes a test.  Given no arguments, it uses the default repository test.\n"+++ "Given one argument, it treats it as a test command.  Given two arguments,\n"+++ "the first is an initialization command with is run only once, and the\n"+++ "second is the test command.\n"+\end{code}++\begin{code}+trackdown :: DarcsCommand+trackdown = DarcsCommand {command_name = "trackdown",+                          command_help = trackdown_help,+                          command_description = trackdown_description,+                          command_extra_args = -1,+                          command_extra_arg_help = ["[[INITIALIZATION]",+                                                    "COMMAND]"],+                          command_command = trackdown_cmd,+                          command_prereq = amInRepository,+                          command_get_arg_possibilities = return [],+                          command_argdefaults = nodefaults,+                          command_advanced_options = [set_scripts_executable],+                          command_basic_options = [working_repo_dir]}+\end{code}++\begin{code}+trackdown_cmd :: [DarcsFlag] -> [String] -> IO ()+trackdown_cmd opts args = withRepoReadLock opts $- \repository -> do+  Sealed patches <- read_repo repository+  (init,test) <- case args of+          [] ->+              do t <- get_test opts+                 return (return ExitSuccess, t)+          [cmd] ->+              do putStrLn $ "Tracking down command:\n"++cmd+                 return $ (return ExitSuccess, system cmd)+          [init,cmd] ->+              do putStrLn $ "Initializing with command:\n"++init+                 putStrLn $ "Tracking down command:\n"++cmd+                 return $ (system init, system cmd)+          _ -> fail "Trackdown expects zero to two arguments."+  withRecorded repository (withTempDir "trackingdown") $ \_ -> do+    when (SetScriptsExecutable `elem` opts) setScriptsExecutable+    init+    track_next opts test $ map (invert . hopefully) $ unsafeUnRL $ concatRL patches+\end{code}++\begin{code}+track_next :: RepoPatch p => [DarcsFlag] -> (IO ExitCode) -> [Named p] -> IO ()+track_next opts test (p:ps) = do+    test_result <- test+    if test_result == ExitSuccess+       then putStrLn "Success!"+       else do apply opts p `catch` \e -> fail ("Bad patch:\n" ++ show e)+               putStrLn "Trying without the patch:"+               putDocLn $ description $ invert p+               hFlush stdout+               track_next opts test ps+track_next _ _ [] = putStrLn "Noone passed the test!"+\end{code}++Trackdown is helpful for locating when something was broken.  It creates+a temporary directory with the latest repository content in it and cd to it.+First, and only once, it runs the initialization command if any,+for example+\begin{verbatim}+'autoconf; ./configure >/dev/null'+\end{verbatim}+Then it runs the test command, for example+\begin{verbatim}+'make && cd tests && sh /tmp/test.sh'+\end{verbatim}+While the test command exits with an error return code, darcs+``unapplies'' one patch from the version controlled files to retrieve+an earlier version, and repeats the test command.  If the test command+finally succeeds, the name of the hunted down patch is found in the+output before the last test run.++FIXME: It is+still rather primitive.  Currently it just goes back over the history in+reverse order trying each version.  I'd like for it to explore different+patch combinations, to try to find the minimum number of patches that you+would need to obliterate in order to make the test succeed.++FIXME: I also would like to add an interface by which you can tell it which+patches it should consider not including.  Without such a feature, the+following command:+\begin{verbatim}+% darcs trackdown 'make && false'+\end{verbatim}+would result in compiling every version in the repository--which is a+rather tedious prospect.++\subsubsection{Example usage}+If you want to find the last version of darcs that had a FIXME note in the+file Record.lhs, you could run+\begin{verbatim}+% darcs trackdown 'grep FIXME Record.lhs'+\end{verbatim}++To find the latest version that compiles, you can run+\begin{verbatim}+% darcs trackdown 'autoconf' './configure && make'+\end{verbatim}++Trackdown can also be used to see how other features of the code changed+with time.  For example+\begin{verbatim}+% darcs trackdown 'autoconf; ./configure' \+   "make darcs > /dev/null && cd ~/darcs && time darcs check && false"+\end{verbatim}+would let you see how long `darcs check' takes to run on each previous+version of darcs that will actually compile.  The ``\verb!&& false!''+ensures that trackdown keeps going.
+ src/Darcs/Commands/TransferMode.lhs view
@@ -0,0 +1,86 @@+%  Copyright (C) 2008 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs changes}+\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+-- The pragma above is only for pattern guards.+module Darcs.Commands.TransferMode ( transfer_mode ) where++import Prelude hiding ( catch )+import Control.Exception ( catch )+import System.IO ( stdout, hFlush )++import Darcs.Utils ( withCurrentDirectory, prettyException )+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag, working_repo_dir )+import Darcs.Repository ( amInRepository )+import Darcs.Progress ( setProgressMode )+import Darcs.Global ( darcsdir )++import FastPackedString ( PackedString, readFilePS, lengthPS, hPutPS )+\end{code}++\options{transfer_mode}+\begin{code}+transfer_mode_description :: String+transfer_mode_description = "Allow access to files in repository."+\end{code}+\haskell{transfer_mode_help}+\begin{code}+transfer_mode_help :: String+transfer_mode_help =+ "Transfer-mode is used internally to grab file contents.\n"++transfer_mode :: DarcsCommand+transfer_mode = DarcsCommand {command_name = "transfer-mode",+                              command_help = transfer_mode_help,+                              command_description = transfer_mode_description,+                              command_extra_args = 0,+                              command_extra_arg_help = [],+                              command_get_arg_possibilities = return [],+                              command_command = transfer_mode_cmd,+                              command_prereq = amInRepository,+                              command_argdefaults = nodefaults,+                              command_advanced_options = [],+                              command_basic_options = [working_repo_dir]}+\end{code}+++\begin{code}+transfer_mode_cmd :: [DarcsFlag] -> [String] -> IO ()+transfer_mode_cmd _ _ = do setProgressMode False+                           putStrLn "Hello user, I am darcs transfer mode"+                           hFlush stdout+                           withCurrentDirectory darcsdir $ transfer++transfer :: IO ()+transfer = do 'g':'e':'t':' ':fn <- getLine+              x <- readfile fn+              case x of+                Right c -> do putStrLn $ "got " ++ fn+                              putStrLn $ show $ lengthPS c+                              hPutPS stdout c+                              hFlush stdout+                Left e -> do putStrLn $ "error " ++ fn+                             putStrLn $ show e+                             hFlush stdout+              transfer++readfile :: String -> IO (Either String PackedString)+readfile fn = (Right `fmap` readFilePS fn) `catch` (\e -> return $ Left (prettyException e))+\end{code}
+ src/Darcs/Commands/Unrecord.lhs view
@@ -0,0 +1,347 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs unrecord}+\label{unrecord}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Unrecord ( unrecord, unpull, obliterate, rempatch, get_last_patches ) where+import Control.Monad ( when )+import System.Exit ( exitWith, ExitCode( ExitSuccess ) )++import Darcs.SlurpDirectory ( wait_a_moment )+import Darcs.Hopefully ( hopefully, info )+import Darcs.Commands ( DarcsCommand(..), nodefaults, loggers, command_alias )+import Darcs.Arguments ( DarcsFlag( Verbose ),+                         working_repo_dir, nocompress, definePatches,+                        match_several_or_last, no_deps,+                        ignoretimes,+                        all_interactive, umask_option,+                      )+import Darcs.Match ( first_match, match_first_patchset, match_a_patchread )+import Darcs.Repository ( PatchSet, PatchInfoAnd, withGutsOf,+                          withRepoLock, ($-), slurp_recorded,+                    tentativelyRemovePatches, finalizeRepositoryChanges,+                    tentativelyAddToPending,+                    applyToWorking,+                    get_unrecorded, read_repo, amInRepository,+                    sync_repo,+                  )+import Darcs.Patch ( RepoPatch, Named, invert, patch2patchinfo, commutex, effect )+import Darcs.Patch.Ordered ( RL(..), (:<)(..), (:>)(..), (:\/:)(..), (+<+),+                             unsafeRL, unsafeUnRL, mapFL_FL, nullFL,+                             concatRL, reverseRL, mapRL, mapRL_RL )+import Darcs.Patch.Depends ( deep_optimize_patchset, get_common_and_uncommon )+import Darcs.SelectChanges ( with_selected_last_changes_reversed )+import Darcs.Progress ( debugMessage )+import Darcs.Sealed ( Sealed(..) )+#include "impossible.h"+\end{code}+\begin{code}+unrecord_description :: String+unrecord_description =+ "Remove recorded patches without changing the working copy."+\end{code}++\options{unrecord}++\haskell{unrecord_help}++Unrecord can be thought of as undo-record.+If a record is followed by an unrecord, everything looks like before+the record; all the previously unrecorded changes are back, and can be+recorded again in a new patch. The unrecorded patch however is actually+removed from your repository, so there is no way to record it again to get+it back.\footnote{The patch file itself is not actually deleted, but its+context is lost, so it cannot be reliably read---your only choice would be+to go in by hand and read its contents.}.++If you want to remove+the changes from the working copy too (where they otherwise will show+up as unrecorded changes again), you'll also need to \verb!darcs revert!.+To do unrecord and revert in one go, you can use \verb!darcs obliterate!.++If you don't revert after unrecording, then the changes made by the+unrecorded patches are left in your working tree.  If these patches are+actually from another repository, interaction (either pushes or pulls) with+that repository may be massively slowed down, as darcs tries to cope with+the fact that you appear to have made a large number of changes that+conflict with those present in the other repository.  So if you really want+to undo the result of a \emph{pull} operation, use obliterate! Unrecord is+primarily intended for when you record a patch, realize it needs just one+more change, but would rather not have a separate patch for just that one+change.++\newcommand{\pullwarning}[1]{+\textbf{WARNING:} #1 should not be run when there is a possibility+that another user may be pulling from the same repository.  Attempting to do so+may cause repository corruption.}++\pullwarning{Unrecord}++\begin{options}+--from-match, --from-patch, --from-tag, --last+\end{options}++Usually you only want to unrecord the latest changes,+and almost never would you want to unrecord changes before a tag---you+would have to have unrecorded the tag as well to do that.+Therefore, and for efficiency, darcs only prompts you for the latest patches,+after some optimal tag.++If you do want to unrecord more patches in one go,+there are the \verb!--from! and \verb!--last! options+to set the earliest patch selectable to unrecord.++\begin{options}+--matches, --patches, --tags, --no-deps+\end{options}++The \verb!--patches!, \verb!--matches!, \verb!--tags!, and \verb!--no-deps!+options can be used to select which patches to unrecord, as described in+subsection~\ref{selecting}.++With these options you can specify+what patch or patches to be prompted for by unrecord.+This is especially useful when you want to unrecord patches with dependencies,+since all the dependent patches (but no others) will be included in the choices.+Or if you use \verb!--no-deps! you won't be asked about patches that can't be+unrecorded due to depending patches.++Selecting patches can be slow, so darcs cuts the search at the last+optimized tag. Use the \verb!--from! or \verb!--last! options to search+more or fewer patches.++\begin{code}+unrecord_help :: String+unrecord_help =+ "Unrecord does the opposite of record in that it makes the changes from\n"+++ "patches active changes again which you may record or revert later.  The\n"+++ "working copy itself will not change.\n"+\end{code}+\begin{code}+unrecord :: DarcsCommand+unrecord = DarcsCommand {command_name = "unrecord",+                         command_help = unrecord_help,+                         command_description = unrecord_description,+                         command_extra_args = 0,+                         command_extra_arg_help = [],+                         command_command = unrecord_cmd,+                         command_prereq = amInRepository,+                         command_get_arg_possibilities = return [],+                         command_argdefaults = nodefaults,+                         command_advanced_options = [nocompress,umask_option],+                         command_basic_options = [match_several_or_last,+                                                 no_deps,+                                                 all_interactive,+                                                 working_repo_dir]}+\end{code}+\begin{code}+unrecord_cmd :: [DarcsFlag] -> [String] -> IO ()+unrecord_cmd opts _ = withRepoLock opts $- \repository -> do+  let (logMessage,_,_) = loggers opts+  recorded <- slurp_recorded repository+  Sealed allpatches <- read_repo repository+  let patches = if first_match opts then get_last_patches opts allpatches+                                    else matchingHead opts allpatches+  with_selected_last_changes_reversed "unrecord" opts recorded+      (reverseRL patches) $+    \ (_ :> to_unrecord) -> do+       when (nullFL to_unrecord) $ do logMessage "No patches selected!"+                                      exitWith ExitSuccess+       when (Verbose `elem` opts) $+            logMessage "About to write out (potentially) modified patches..."+       definePatches to_unrecord+       withGutsOf repository $ do tentativelyRemovePatches repository opts $+                                                           mapFL_FL hopefully to_unrecord+                                  finalizeRepositoryChanges repository+       sync_repo repository+       logMessage "Finished unrecording."++get_last_patches :: RepoPatch p => [DarcsFlag] -> PatchSet p -> RL (PatchInfoAnd p)+get_last_patches opts ps =+  case get_common_and_uncommon (ps,p1s) of+  (_,us :\/: _) -> concatRL us+  where p1s = match_first_patchset opts ps++rempatch :: RepoPatch p => Named p -> PatchSet p -> PatchSet p+rempatch p (pps:<:ppss) =+    case patch2patchinfo p of+    pinfo -> if pinfo `elem` simple_infos+                  -- The following ugly hack is only safe because we don't use+                  -- the actual patches!+                  then (unsafeRL $ filter ((/= pinfo).info) $ unsafeUnRL pps) :<: ppss+                  else deep_optimize_patchset $+                       mapRL_RL (unsafeRL . filter ((/= pinfo).info) . unsafeUnRL) (pps:<:ppss)+    where simple_infos = init $ mapRL info pps+rempatch _ NilRL = impossible+\end{code}++\begin{code}+unpull_description :: String+unpull_description =+ "Opposite of pull; unsafe if patch is not in remote repository."+\end{code}++\begin{code}+unpull_help :: String+unpull_help =+ "Unpull completely removes recorded patches from your local repository.\n"+++ "The changes will be undone in your working copy and the patches will not be\n"+++ "shown in your changes list anymore.\n"+++ "Beware that if the patches are not still present in another repository you\n"+++ "will lose precious code by unpulling!\n"+\end{code}++\begin{code}+unpull :: DarcsCommand+unpull = (command_alias "unpull" obliterate)+                      {command_help = unpull_help,+                       command_description = unpull_description,+                       command_command = unpull_cmd}++unpull_cmd :: [DarcsFlag] -> [String] -> IO ()+unpull_cmd = generic_obliterate_cmd "unpull"+\end{code}++++\subsection{darcs obliterate}++\begin{code}+obliterate_description :: String+obliterate_description =+ "Delete selected patches from the repository. (UNSAFE!)"+\end{code}++\begin{code}+obliterate_help :: String+obliterate_help =+ "Obliterate completely removes recorded patches from your local repository.\n"+++ "The changes will be undone in your working copy and the patches will not be\n"+++ "shown in your changes list anymore.\n"+++ "Beware that you can lose precious code by obliterating!\n"+\end{code}++\options{obliterate}++\haskell{obliterate_help}++Obliterate deletes a patch from the repository \emph{and} removes those+changes from the working directory.  It is therefore a \emph{very+dangerous} command.  When there are no local changes, obliterate is+equivalent to an unrecord followed by a revert, except that revert can be+unreverted.  In the case of tags, obliterate removes the tag itself, not+any other patches.++Note that unpull was the old name for obliterate. Unpull is still an+hidden alias for obliterate.++\pullwarning{Obliterate}++\begin{options}+--from-match, --from-patch, --from-tag, --last+\end{options}++Usually you only want to obliterate the latest changes, and almost never would+you want to obliterate changes before a tag---you would have to have obliterated+the tag as well to do that. Therefore, and for efficiency, darcs only+prompts you for the latest patches, after some optimal tag.++If you do want to obliterate more patches in one go, there are the+\verb!--from! and \verb!--last! options to set the earliest patch+selectable to obliterate.++\begin{options}+--matches, --patches, --tags, --no-deps+\end{options}++The \verb!--patches!, \verb!--matches!, \verb!--tags!, and \verb!--no-deps!+options can be used to select which patches to obliterate, as described in+subsection~\ref{selecting}.++With these options you can specify what patch or patches to be prompted for+by obliterate. This is especially useful when you want to obliterate patches with+dependencies, since all the dependent patches (but no others) will be+included in the choices. Or if you use \verb!--no-deps! you won't be asked+about patches that can't be obliterated due to depending patches.++Selecting patches can be slow, so darcs cuts the search at the last+optimized tag. Use the \verb!--from! or \verb!--last! options to search+more or fewer patches.++\begin{code}+obliterate :: DarcsCommand+obliterate = DarcsCommand {command_name = "obliterate",+                           command_help = obliterate_help,+                           command_description = obliterate_description,+                           command_extra_args = 0,+                           command_extra_arg_help = [],+                           command_command = obliterate_cmd,+                           command_prereq = amInRepository,+                           command_get_arg_possibilities = return [],+                           command_argdefaults = nodefaults,+                           command_advanced_options = [nocompress,ignoretimes,umask_option],+                           command_basic_options = [match_several_or_last,+                                                   no_deps,+                                                   all_interactive,+                                                   working_repo_dir]}+obliterate_cmd :: [DarcsFlag] -> [String] -> IO ()+obliterate_cmd = generic_obliterate_cmd "obliterate"+\end{code}++\begin{code}+generic_obliterate_cmd :: String -> [DarcsFlag] -> [String] -> IO ()+generic_obliterate_cmd cmdname opts _ = withRepoLock opts $- \repository -> do+  let (logMessage,_,_) = loggers opts+  recorded <- slurp_recorded repository+  pend <- get_unrecorded repository+  Sealed allpatches <- read_repo repository+  let patches = if first_match opts then get_last_patches opts allpatches+                                    else matchingHead opts allpatches+  with_selected_last_changes_reversed cmdname opts recorded+      (reverseRL patches) $+    \ (_ :> ps) ->+    case commutex (pend :< effect ps) of+    Nothing -> fail $ "Can't "++ cmdname +++               " patch without reverting some unrecorded change."+    Just (p_after_pending:<_) -> do+        when (nullFL ps) $ do logMessage "No patches selected!"+                              exitWith ExitSuccess+        definePatches ps+        withGutsOf repository $+                             do tentativelyRemovePatches repository opts (mapFL_FL hopefully ps)+                                tentativelyAddToPending repository opts $ invert $ effect ps+                                finalizeRepositoryChanges repository+                                debugMessage "Waiting a bit for timestamps to differ..."+                                wait_a_moment+                                debugMessage "Applying patches to working directory..."+                                applyToWorking repository opts (invert p_after_pending) `catch` \e ->+                                    fail ("Couldn't undo patch in working dir.\n" ++ show e)+        sync_repo repository+        logMessage $ "Finished " ++ present_participle cmdname ++ "."++matchingHead :: [DarcsFlag] -> RL (RL (PatchInfoAnd p)) -> RL (PatchInfoAnd p)+matchingHead opts (x:<:_) | or (mapRL (match_a_patchread opts) x) = x+matchingHead opts (x:<:xs) = x +<+ matchingHead opts xs+matchingHead _ NilRL = NilRL++present_participle :: String -> String+present_participle v | last v == 'e' = init v ++ "ing"+                     | otherwise = v ++ "ing"+\end{code}+
+ src/Darcs/Commands/Unrevert.lhs view
@@ -0,0 +1,144 @@+%  Copyright (C) 2003-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs unrevert}\label{unrevert}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.Unrevert ( unrevert, write_unrevert ) where+import System.Exit ( ExitCode(..), exitWith )++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag( Unified, MarkConflicts ),+                         ignoretimes, working_repo_dir,+                        all_interactive, umask_option,+                      )+import Darcs.Repository ( PatchSet, Repository, withRepoLock, ($-),+                          unrevertUrl, considerMergeToWorking,+                          tentativelyAddToPending, finalizeRepositoryChanges,+                          sync_repo, get_unrecorded,+                          read_repo, amInRepository,+                          slurp_recorded_and_unrecorded,+                          applyToWorking )+import Darcs.Patch ( RepoPatch, Prim, commutex, namepatch, fromPrims )+import Darcs.Patch.Ordered ( RL(..), FL(..), (:<)(..), (:>)(..), (:\/:)(..), reverseRL )+import Darcs.SelectChanges ( with_selected_changes_to_files' )+import Darcs.SlurpDirectory ( Slurpy )+import FastPackedString ( readFilePS )+import Darcs.Lock ( writeDocBinFile, removeFileMayNotExist )+import Darcs.Patch.Depends ( get_common_and_uncommon )+import Darcs.Utils ( askUser, catchall )+import Darcs.Patch.Bundle ( scan_bundle, make_bundle )+import IsoDate ( getIsoDateTime )+import Darcs.SignalHandler ( withSignalsBlocked )+import Darcs.Progress ( debugMessage )+import Darcs.Sealed ( Sealed(Sealed) )+#include "impossible.h"+\end{code}+\begin{code}+unrevert_description :: String+unrevert_description =+ "Undo the last revert (may fail if changes after the revert)."+\end{code}++\options{unrevert}++\haskell{unrevert_help}+\begin{code}+unrevert_help :: String+unrevert_help =+ "Unrevert is used to undo the results of a revert command. It is only\n"+++ "guaranteed to work properly if you haven't made any changes since the\n"+++ "revert was performed.\n"+\end{code}+The command makes a best effort to merge the unreversion with any changes+you have since made.  In fact, unrevert should even work if you've recorded+changes since reverting.+\begin{code}+unrevert :: DarcsCommand+unrevert = DarcsCommand {command_name = "unrevert",+                         command_help = unrevert_help,+                         command_description = unrevert_description,+                         command_extra_args = 0,+                         command_extra_arg_help = [],+                         command_command = unrevert_cmd,+                         command_prereq = amInRepository,+                         command_get_arg_possibilities = return [],+                         command_argdefaults = nodefaults,+                         command_advanced_options = [umask_option],+                         command_basic_options = [ignoretimes,+                                                  all_interactive,+                                                  working_repo_dir]}+\end{code}+\begin{code}+unrevert_cmd :: [DarcsFlag] -> [String] -> IO ()+unrevert_cmd opts [] = withRepoLock opts $- \repository -> do+  Sealed us <- read_repo repository+  them <- unrevert_patch_bundle repository+  (rec, working) <- slurp_recorded_and_unrecorded repository+  unrec <- get_unrecorded repository+  case get_common_and_uncommon (us, them) of+    (_, us' :\/: them') -> do+      pw <- considerMergeToWorking repository "pull" (MarkConflicts:opts)+                 (reverseRL $ headRL us') (reverseRL $ headRL them')+      with_selected_changes_to_files' "unrevert" opts working [] pw $+                            \ (p :> skipped) -> do+        tentativelyAddToPending repository opts p+        withSignalsBlocked $+          do finalizeRepositoryChanges repository+             applyToWorking repository opts p `catch` \e ->+                 fail ("Error applying unrevert to working directory...\n"+                       ++ show e)+             debugMessage "I'm about to write_unrevert."+             write_unrevert repository skipped rec unrec+        sync_repo repository+        debugMessage "Finished unreverting."+      where headRL (x:<:_) = x+            headRL NilRL = impossible+unrevert_cmd _ _ = impossible+\end{code}++\begin{code}+write_unrevert :: RepoPatch p => Repository p -> FL Prim -> Slurpy -> FL Prim -> IO ()+write_unrevert repository NilFL _ _ = removeFileMayNotExist $ unrevertUrl repository+write_unrevert repository ps rec pend = do+  case commutex (ps :< pend) of+    Nothing -> do really <- askUser "You will not be able to unrevert this operation! Proceed? "+                  case really of ('y':_) -> return ()+                                 _ -> exitWith $ ExitSuccess+                  write_unrevert repository NilFL rec pend+    Just (_ :< p') -> do+        Sealed rep <- read_repo repository+        case get_common_and_uncommon (rep,rep) of+            (common,_ :\/: _) -> do+                date <- getIsoDateTime+                writeDocBinFile (unrevertUrl repository) $+                             make_bundle [Unified] rec common+                            (namepatch date "unrevert" "anonymous" []+                                           (fromRepoPrims repository p') :>: NilFL)+                where fromRepoPrims :: RepoPatch p => Repository p -> FL Prim -> p+                      fromRepoPrims _ xs = fromPrims xs+\end{code}++\begin{code}+unrevert_patch_bundle :: RepoPatch p => Repository p -> IO (PatchSet p)+unrevert_patch_bundle repository = do+  pf <- readFilePS (unrevertUrl repository)+        `catchall` fail "There's nothing to unrevert!"+  case scan_bundle pf of+      Right (Sealed ps) -> return ps+      Left err -> fail $ "Couldn't parse unrevert patch:\n" ++ err+\end{code}
+ src/Darcs/Commands/WhatsNew.lhs view
@@ -0,0 +1,145 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\subsection{darcs whatsnew}+\label{whatsnew}+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Commands.WhatsNew ( whatsnew ) where+import System.Exit ( ExitCode(..), exitWith )+import Data.List ( sort )+import Control.Monad ( when )++import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag(..), working_repo_dir, lookforadds,+                        ignoretimes, noskip_boring,+                        unified,+                         areFileArgs, getRepoPaths,+                        list_registered_files,+                      )+import Darcs.Arguments ( summary )+import Darcs.Patch.TouchesFiles ( choose_touching )+import Darcs.RepoPath ( toFilePath )+import Darcs.Repository ( withRepository, ($-), slurp_recorded,+                          get_unrecorded, get_unrecorded_no_look_for_adds, amInRepository )+import Darcs.Repository.Prefs ( filetype_function )+import Darcs.Diff ( smart_diff )+import Darcs.Patch ( summarize, apply_to_slurpy, is_hunk,+                     invert, apply_to_filepaths )+import Darcs.Patch.Permutations ( partitionRL )+import Darcs.Patch.Real ( prim2real )+import Darcs.PrintPatch ( printPatch, contextualPrintPatch )+import Darcs.Patch.Ordered ( FL(..), mapFL_FL, reverseRL, reverseFL, (:>)(..) )+import Printer ( putDocLn, renderString, vcat, text )+#include "impossible.h"+\end{code}++\options{whatsnew}++\haskell{whatsnew_description}+\begin{code}+whatsnew_description :: String+whatsnew_description = "Display unrecorded changes in the working copy."+\end{code}+\haskell{whatsnew_help} \verb!darcs whatsnew! will return a non-zero value if+there are no changes, which can be useful if you just want to see in a+script if anything has been modified.  If you want to see some context+around your changes, you can use the \verb!-u! option, to get output+similar to the unidiff format.++\begin{code}+whatsnew_help :: String+whatsnew_help =+ "whatsnew gives you a view of what changes you've made in your working\n"+++ "copy that haven't yet been recorded.  The changes are displayed in\n"+++ "darcs patch format. Note that --look-for-adds implies --summary usage.\n"+\end{code}++\begin{code}+whatsnew :: DarcsCommand+whatsnew = DarcsCommand {command_name = "whatsnew",+                         command_help = whatsnew_help,+                         command_description = whatsnew_description,+                         command_extra_args = -1,+                         command_extra_arg_help = ["[FILE or DIRECTORY]..."],+                         command_command = whatsnew_cmd,+                         command_prereq = amInRepository,+                         command_get_arg_possibilities = list_registered_files,+                         command_argdefaults = nodefaults,+                         command_advanced_options = [ignoretimes, noskip_boring],+                         command_basic_options = [summary, unified,+                                                 lookforadds,+                                                 working_repo_dir]}+\end{code}++\begin{code}+whatsnew_cmd :: [DarcsFlag] -> [String] -> IO ()+whatsnew_cmd opts' args +  | LookForAdds `elem` opts' && NoSummary `notElem` opts' =+    -- add Summary to the opts since 'darcs whatsnew --look-for-adds'+    -- implies summary+    withRepository (Summary:opts') $- \repository -> do+    files <- getRepoPaths opts' args+    when (areFileArgs files) $+         putStrLn $ "What's new in "++unwords (map show files)++":\n"+    all_changes <- get_unrecorded repository+    chold <- get_unrecorded_no_look_for_adds repository+    s <- slurp_recorded repository+    ftf <- filetype_function+    let pre_changed_files = apply_to_filepaths (invert chold) $ map toFilePath files+        select_files = choose_touching pre_changed_files+        cho = select_files chold+    cho_adds :> _ <- return $ partitionRL is_hunk $ reverseFL cho+    cha :> _ <- return $ partitionRL is_hunk $ reverseFL $ select_files all_changes+    let chn    = smart_diff [LookForAdds,Summary] ftf+                            (fromJust $ apply_to_slurpy (reverseRL cho_adds) s)+                            (fromJust $ apply_to_slurpy (reverseRL cha) s)+    case (chn, cho) of (NilFL, NilFL) -> do putStrLn "No changes!"+                                            exitWith $ ExitFailure 1+                       _ -> return ()+    putDocLn $ summarize cho+    case chn of NilFL -> return ()+                _ -> putDocLn $ lower_as $ renderString $ summarize chn+           where lower_as x = vcat $ map (text . l_as) $ lines x+                 l_as ('A':x) = 'a':x+                 l_as x = x++whatsnew_cmd opts args =  withRepository opts $- \repository -> do+    files <- sort `fmap` getRepoPaths opts args+    when (areFileArgs files) $+         putStrLn $ "What's new in "++unwords (map show files)++":\n"+    changes <- get_unrecorded repository+    case changes of+      NilFL -> do putStrLn "No changes!"+                  exitWith $ ExitFailure 1+      _ ->+          let pre_changed_files = apply_to_filepaths (invert changes) $ map toFilePath files+          in+            case mapFL_FL prim2real $ choose_touching pre_changed_files changes of+            NilFL -> do putStrLn "No changes!"+                        exitWith $ ExitFailure 1+            ch ->      if Summary `elem` opts+                       then putDocLn $ summarize ch+                       else if Unified `elem` opts+                            then do s <- slurp_recorded repository+                                    contextualPrintPatch s ch+                            else printPatch ch+\end{code}++If you give one or more file or directory names as an argument to+\verb!whatsnew!, darcs will output only changes to those files or to files in+those directories.
+ src/Darcs/CommandsAux.lhs view
@@ -0,0 +1,100 @@+%  Copyright (C) 2006 Tommy Pettersson <ptp@lysator.liu.se>+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.CommandsAux ( check_paths, malicious_patches, has_malicious_path,+                        ) where+import Darcs.Flags ( DarcsFlag( RestrictPaths, DontRestrictPaths ) )+import FileName ( breakup, is_explicitly_relative )+import Darcs.Patch ( Patchy, list_touched_files )+import Darcs.Patch.Ordered ( FL, mapFL )+import Darcs.Global ( darcsdir )+import Data.List ( intersect )+\end{code}++\begin{code}+{-+  FILE PATHS++  Darcs will operate on files and directories with the invoking user's+  privileges. The paths for these files and directories are stored in+  patches, which darcs receives in various ways. Even though darcs will not+  create patches with "unexpected" file paths, there are no such guarantees+  for received patches. A spoofed patch could inflict changes on any file+  or directory which the invoking user is privileged to modify.++  There is no one single "apply" function that can check paths, so each+  command is responsible for not applying patches without first checking+  them with one of these function when appropriate.+-}++check_paths :: Patchy p => [DarcsFlag] -> FL p -> IO ()+{-+  A convenience function to call from all darcs command functions before+  applying any patches. It checks for malicious paths in patches, and+  prints an error message and fails if it finds one.+-}+check_paths opts patches+  = if check_is_on  && or (mapFL has_malicious_path patches)+      then fail "Malicious path"+           -- TODO: print patch(es) and path(s)+           -- NOTE: should use safe Doc printer, this can be evil chars+      else return ()+ where+    check_is_on = DontRestrictPaths `notElem` opts  ||+                  RestrictPaths        `elem` opts++malicious_patches :: Patchy p => [p] -> [p]+-- Filter out pathces that contains some malicious file path+malicious_patches to_check = filter has_malicious_path to_check++has_malicious_path :: Patchy p => p -> Bool+has_malicious_path patch =+  let paths = list_touched_files patch in+    any is_malicious_path paths++{-+  What is a malicious path?++  A spoofed path is a malicious path.++  1) Darcs only creates explicitly relative paths (beginning with "./"), so+     any not explicitly relative path is surely spoofed.++  2) Darcs normalizes paths so they never contain "/../", so paths with+     "/../" are surely spoofed.++  A path to a darcs repository's meta data can modify "trusted" patches or+  change safety defaults in that repository, so we check for paths+  containing "/_darcs/" which is the entry to darcs meta data.++  To do?++  * How about get repositories?++  * Would it be worth adding a --semi-safe-paths option for allowing+    changes to certain preference files (_darcs/prefs/) in sub+    repositories'?+-}++is_malicious_path :: String -> Bool+is_malicious_path fp =+    not (is_explicitly_relative fp) ||+    breakup fp `contains_any` [ "..", darcsdir ]+ where+    contains_any a b = not . null $ intersect a b+\end{code}
+ src/Darcs/Compat.hs view
@@ -0,0 +1,123 @@+{-# OPTIONS_GHC -cpp -fffi #-}++module Darcs.Compat (stdout_is_a_pipe, mk_stdout_temp, canonFilename,+               maybeRelink, atomic_create, sloppy_atomic_create) where++import Prelude hiding ( catch )++import Darcs.Utils ( withCurrentDirectory )+#ifdef WIN32+import Darcs.Utils ( showHexLen )+import Data.Bits ( (.&.) )+import System.Random ( randomIO )+#else+import Foreign.C.String ( peekCString )+#endif++import Control.Monad ( liftM, unless )+import Foreign.C.Types ( CInt )+import Foreign.C.String ( CString, withCString )+import Foreign.C.Error ( throwErrno, eEXIST, getErrno )+import System.Directory ( getCurrentDirectory )+import System.IO ( hFlush, stdout, stderr, hSetBuffering,+                   BufferMode(NoBuffering) )+import System.IO.Error ( mkIOError, alreadyExistsErrorType )+import System.Posix.Files ( stdFileMode )+import System.Posix.IO ( openFd, closeFd, stdOutput, stdError, +                         dupTo, defaultFileFlags, exclusive,+                         OpenMode(WriteOnly) )+import System.Posix.Types ( Fd(..) )++import Darcs.SignalHandler ( stdout_is_a_pipe )++canonFilename :: FilePath -> IO FilePath+canonFilename f@(_:':':_) = return f -- absolute windows paths+canonFilename f@('/':_) = return f+canonFilename ('.':'/':f) = do cd <- getCurrentDirectory+                               return $ cd ++ "/" ++ f+canonFilename f = case reverse $ dropWhile (/='/') $ reverse f of+                  "" -> liftM (++('/':f)) getCurrentDirectory+                  rd -> withCurrentDirectory rd $+                          do fd <- getCurrentDirectory+                             return $ fd ++ "/" ++ simplefilename+    where+    simplefilename = reverse $ takeWhile (/='/') $ reverse f++#ifdef WIN32+mkstemp_core :: FilePath -> IO (Fd, String)+mkstemp_core fp+ = do r <- randomIO+      let fp' = fp ++ (showHexLen 6 (r .&. 0xFFFFFF :: Int))+      fd <- openFd fp' WriteOnly (Just stdFileMode) flags+      return (fd, fp')+  where flags = defaultFileFlags { exclusive = True }+#else+mkstemp_core :: String -> IO (Fd, String)+mkstemp_core str = withCString (str++"XXXXXX") $+    \cstr -> do fd <- c_mkstemp cstr+                if fd < 0+                  then throwErrno $ "Failed to create temporary file "++str+                  else do str' <- peekCString cstr+                          fname <- canonFilename str'+                          return (Fd fd, fname)++foreign import ccall unsafe "static stdlib.h mkstemp"+    c_mkstemp :: CString -> IO CInt+#endif++mk_stdout_temp :: String -> IO String+mk_stdout_temp str = do (fd, fn) <- mkstemp_core str+                        hFlush stdout+                        hFlush stderr+                        dupTo fd stdOutput+                        dupTo fd stdError+                        hFlush stdout+                        hFlush stderr+                        hSetBuffering stdout NoBuffering+                        hSetBuffering stderr NoBuffering+                        return fn++++foreign import ccall unsafe "maybe_relink.h maybe_relink" maybe_relink+    :: CString -> CString -> CInt -> IO CInt++-- Checks whether src and dst are identical.  If so, makes dst into a+-- link to src.  Returns True if dst is a link to src (either because+-- we linked it or it already was).  Safe against changes to src if+-- they are not in place, but not to dst.+maybeRelink :: String -> String -> IO Bool+maybeRelink src dst =+    withCString src $ \csrc ->+    withCString dst $ \cdst ->+    do rc <- maybe_relink csrc cdst 1+       (case rc of+        0 -> return True+        1 -> return True+        -1 -> throwErrno ("Relinking " ++ dst)+        -2 -> return False+        -3 -> do putStrLn ("Relinking: race condition avoided on file " +++                            dst)+                 return False+        _ -> fail ("Unexpected situation when relinking " ++ dst))++sloppy_atomic_create :: FilePath -> IO ()+sloppy_atomic_create fp+    = do fd <- openFd fp WriteOnly (Just stdFileMode) flags+         closeFd fd+  where flags = defaultFileFlags { exclusive = True }++atomic_create :: FilePath -> IO ()+atomic_create fp = withCString fp $ \cstr -> do+    rc <- c_atomic_create cstr+    unless (rc >= 0) $+           do errno <- getErrno+              pwd <- getCurrentDirectory+              if errno == eEXIST+                 then ioError $ mkIOError alreadyExistsErrorType+                                          ("atomic_create in "++pwd)+                                          Nothing (Just fp)+                 else throwErrno $ "atomic_create "++fp++" in "++pwd++foreign import ccall unsafe "atomic_create.h atomic_create" c_atomic_create+    :: CString -> IO CInt
+ src/Darcs/Diff.lhs view
@@ -0,0 +1,315 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\chapter{Diff}++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Diff ( smart_diff, sync, cmp+#ifndef GADT_WITNESSES+                  , diff_files+#endif+                  ) where++import System.Posix+     ( setFileTimes )+import System.IO ( IOMode(ReadMode), hFileSize, hClose )+import System.Directory ( doesDirectoryExist, doesFileExist,+                   getDirectoryContents,+                 )+import Control.Monad ( liftM, when )+import Data.List ( sort+#ifndef GADT_WITNESSES+                 , intersperse+#endif+                 )++import FastPackedString ( hGetPS, lengthPS+#ifndef GADT_WITNESSES+                        , PackedString, is_funky, nilPS+                        , linesPS, nullPS, lastPS, takePS,+#endif+                        )++import Darcs.SlurpDirectory ( Slurpy, slurp_name, is_dir, is_file,+                        get_dircontents, get_filecontents,+                        get_mtime, get_length,+                        undefined_time+#ifndef GADT_WITNESSES+                        , FileContents, undefined_size+#endif+                      )+#ifndef GADT_WITNESSES+import Darcs.FilePathUtils ( (///) )+#endif+import Darcs.Patch ( Prim+#ifndef GADT_WITNESSES+                   , hunk, canonize, rmfile, rmdir+                   , addfile, adddir+                   , binary, invert+#endif+                   )+import System.IO ( openBinaryFile )+import Darcs.Repository.Prefs ( FileType(..) )+import Darcs.Flags ( DarcsFlag(..) )+import Darcs.Utils ( catchall )+import Darcs.Patch.Ordered ( FL(..)+#ifndef GADT_WITNESSES+                           , (+>+)+#endif+                           )+#ifndef GADT_WITNESSES+#include "impossible.h"+#endif+\end{code}++The diff function takes a recursive diff of two slurped-up directory trees.+The code involved is actually pretty trivial.  \verb!paranoid_diff! runs a+diff in which we don't make the assumption that files with the same+modification time are identical.++\begin{code}+smart_diff :: [DarcsFlag]+           -> (FilePath -> FileType) -> Slurpy -> Slurpy -> FL Prim C(x y)+#ifdef GADT_WITNESSES+smart_diff = undefined+#else+smart_diff opts wt s1 s2+    = gendiff (ignore_times, look_for_adds, summary) wt [] s1 s2 NilFL+  where ignore_times = IgnoreTimes `elem` opts+        look_for_adds = LookForAdds `elem` opts+        -- NoSummary/Summary both present gives False+        -- Just Summary gives True+        -- Just NoSummary gives False+        -- Neither gives False+        summary = Summary `elem` opts && NoSummary `notElem` opts++mk_filepath :: [FilePath] -> FilePath+mk_filepath fps = concat $ intersperse "/" $ reverse fps++gendiff :: (Bool,Bool,Bool)+        -> (FilePath -> FileType) -> [FilePath] -> Slurpy -> Slurpy+        -> (FL Prim -> FL Prim)+gendiff opts@(isparanoid,_,_) wt fps s1 s2+    | is_file s1 && is_file s2 && maybe_differ =+          case wt n2 of+          TextFile -> diff_files f b1 b2+          BinaryFile -> if b1 /= b2 then (binary f b1 b2:>:)+                                    else id+    | is_dir s1 && is_dir s2 =+          let fps' = case n2 of+                         "." -> fps+                         _ -> n2:fps+          in fps' `seq` recur_diff opts (wt . (n2///)) fps' dc1 dc2+    | otherwise = id+    where n2 = slurp_name s2+          f = mk_filepath (n2:fps)+          b1 = get_filecontents s1+          b2 = get_filecontents s2+          dc1 = get_dircontents s1+          dc2 = get_dircontents s2+          maybe_differ = isparanoid+                      || get_mtime s1 == undefined_time+                      || get_mtime s1 /= get_mtime s2+                      || get_length s1 == undefined_size+                      || get_length s1 /= get_length s2++-- recur_diff or recursive diff+-- First parameter is (IgnoreTimes?, LookforAdds?, Summary?)+recur_diff :: (Bool,Bool,Bool)+           -> (FilePath -> FileType) -> [FilePath] -> [Slurpy] -> [Slurpy]+           -> (FL Prim -> FL Prim)+recur_diff _ _ _ [] [] = id+recur_diff opts@(_,doadd,summary) wt fps (s:ss) (s':ss')+    -- this is the case if a file has been removed in the working directory+    | s < s' = diff_removed wt fps s . recur_diff opts wt fps ss (s':ss')+    -- this next case is when there is a file in the directory that is not+    -- in the repository (ie, not managed by darcs)+    | s > s' = let rest = recur_diff opts wt fps (s:ss) ss'+               in if not doadd then                        rest+                               else diff_added summary wt fps s' . rest+    -- actually compare the files because the names match+    | s == s' = gendiff opts wt fps s s' . recur_diff opts wt fps ss ss'+recur_diff opts wt fps (s:ss) [] =+    diff_removed wt fps s . recur_diff opts wt fps ss []+recur_diff opts@(_,True,summary) wt fps [] (s':ss') =+    diff_added summary wt fps s' . recur_diff opts wt fps [] ss'+recur_diff (_,False,_) _ _ [] _ = id+recur_diff _ _ _ _ _ = impossible++-- creates a diff for a file or directory which needs to be added to the+-- repository+diff_added :: Bool -> (FilePath -> FileType) -> [FilePath] -> Slurpy+           -> (FL Prim -> FL Prim)+diff_added summary wt fps s+    | is_file s = case wt n of+                  TextFile -> (addfile f:>:) .+                              (if summary+                               then id+                               else diff_from_empty id f (get_filecontents s))+                  BinaryFile -> (addfile f:>:) .+                                (if summary then id else+                                (bin_patch f nilPS (get_filecontents s)))+    | otherwise {- is_dir s -} =+        (adddir f:>:)+      . foldr (.) id (map (diff_added summary wt (n:fps)) (get_dircontents s))+    where n = slurp_name s+          f = mk_filepath (n:fps)++get_text :: FileContents -> [PackedString]+get_text = linesPS++empt :: FileContents+empt = nilPS++diff_files :: FilePath -> FileContents -> FileContents+           -> (FL Prim -> FL Prim)+diff_files f o n | get_text o == [nilPS] && get_text n == [nilPS] = id+                 | get_text o == [nilPS] = diff_from_empty id f n+                 | get_text n == [nilPS] = diff_from_empty invert f o+diff_files f o n = if o == n+                   then id+                   else if has_bin o || has_bin n+                        then (binary f o n:>:)+                        else (canonize (hunk f 1 (linesPS o) (linesPS n)) +>+)++diff_from_empty :: (Prim -> Prim) -> FilePath -> FileContents+                -> (FL Prim -> FL Prim)+diff_from_empty inv f b =+    if b == nilPS+    then id+    else let p = if has_bin b+                 then binary f nilPS b+                 else if lastPS b == '\n'+                      then hunk f 1 [] $ init $ linesPS b+                      else hunk f 1 [nilPS] $ linesPS b+         in (inv p:>:)++{- | We take a PackedString which represents a file's contents, and we check to see+whether it is a 'binary' file or a 'textual' file. We define a textual file as any file+which does not contain two magic characters, '\0' (the NULL character on Unix) and '^Z'+(Control-Z, a DOS convention).++Note that to improve performance, we won't examine *all* of the string, because that+falls down on large files, but just the first 4096 characters. -}+has_bin :: FileContents -> Bool+has_bin = is_funky . takePS 4096+#endif+\end{code}++\begin{code}+#ifndef GADT_WITNESSES+bin_patch :: FilePath -> PackedString -> PackedString+          -> FL Prim -> FL Prim+bin_patch f o n | nullPS o && nullPS n = id+                | otherwise = (binary f o n:>:)+#endif+\end{code}++\begin{code}+#ifndef GADT_WITNESSES+diff_removed :: (FilePath -> FileType) -> [FilePath] -> Slurpy+             -> (FL Prim -> FL Prim)+diff_removed wt fps s+    | is_file s = case wt n of+                  TextFile -> diff_files f (get_filecontents s) empt+                            . (rmfile f:>:)+                  BinaryFile -> (bin_patch f+                                 (get_filecontents s) nilPS)+                              . (rmfile f:>:)+    | otherwise {- is_dir s -}+        = foldr (.) (rmdir f:>:)+        $ map (diff_removed wt (n:fps)) (get_dircontents s)+    where n = slurp_name s+          f = mk_filepath (n:fps)+#endif+\end{code}++\begin{code}+sync :: String -> Slurpy -> Slurpy -> IO ()+sync path s1 s2+    | is_file s1 && is_file s2 &&+      (get_mtime s1 == undefined_time || get_mtime s1 /= get_mtime s2) &&+      get_length s1 == get_length s2 &&+      get_filecontents s1 == get_filecontents s2 =+        set_mtime n (get_mtime s2)+    | is_dir s1 && is_dir s2+        = n2 `seq` recur_sync n (get_dircontents s1) (get_dircontents s2)+    | otherwise = return ()+    where n2 = slurp_name s2+          n = path++"/"++n2+          set_mtime fname ctime = setFileTimes fname ctime ctime+                       `catchall` return ()+          recur_sync _ [] _ = return ()+          recur_sync _ _ [] = return ()+          recur_sync p (s:ss) (s':ss')+              | s < s' = recur_sync p ss (s':ss')+              | s > s' = recur_sync p (s:ss) ss'+              | otherwise = do sync p s s'+                               recur_sync p ss ss'+\end{code}+++\begin{code}+cmp :: FilePath -> FilePath -> IO Bool+cmp p1 p2 = do+  dir1 <- doesDirectoryExist p1+  dir2 <- doesDirectoryExist p2+  file1 <- doesFileExist p1+  file2 <- doesFileExist p2+  if dir1 && dir2+     then cmpdir p1 p2+     else if file1 && file2+          then cmpfile p1 p2+          else return False+cmpdir :: FilePath -> FilePath -> IO Bool+cmpdir d1 d2 = do+  fn1 <- liftM (filter (\f->f/="." && f /="..")) $ getDirectoryContents d1+  fn2 <- liftM (filter (\f->f/="." && f /="..")) $ getDirectoryContents d2+  if sort fn1 /= sort fn2+     then return False+     else andIO $ map (\fn-> cmp (d1++"/"++fn) (d2++"/"++fn)) fn1+andIO :: [IO Bool] -> IO Bool+andIO (iob:iobs) = do b <- iob+                      if b then andIO iobs else return False+andIO [] = return True+cmpfile :: FilePath -> FilePath -> IO Bool+cmpfile f1 f2 = do+  h1 <- openBinaryFile f1 ReadMode+  h2 <- openBinaryFile f2 ReadMode+  l1 <- hFileSize h1+  l2 <- hFileSize h2+  if l1 /= l2+     then do hClose h1+             hClose h2+             putStrLn $ "different file lengths for "++f1++" and "++f2+             return False+     else do b <- hcmp h1 h2+             when (not b) $ putStrLn $ "files "++f1++" and "++f2++" differ"+             hClose h1+             hClose h2+             return b+    where hcmp h1 h2 = do c1 <- hGetPS h1 1024+                          c2 <- hGetPS h2 1024+                          if c1 /= c2+                             then return False+                             else if lengthPS c1 == 1024+                                  then hcmp h1 h2+                                  else return True+\end{code}+
+ src/Darcs/Email.hs view
@@ -0,0 +1,129 @@+module Darcs.Email ( make_email, read_email ) where++import Data.Char ( ord, digitToInt, isHexDigit )+import Printer ( Doc, ($$), (<+>), (<>), text, empty, packedString, renderPS)+import FastPackedString ( PackedString, tailPS, nullPS, dropWhitePS,+                          indexPSW, packString, headPS, indexPS,+                          lengthPS, generatePS, dropPS, linesPS,+                          betweenLinesPS )+import System.IO.Unsafe ( unsafePerformIO )+import Foreign.Ptr ( Ptr, plusPtr )+import Foreign.Storable ( poke )+import Data.Word ( Word8 )++line_max :: Int+line_max = 75++qpencode :: PackedString -> PackedString+qpencode s = unsafePerformIO+           -- Really only (3 + 2/75) * length or something in the worst case+           $ generatePS (4 * lengthPS s) (\buf -> encode s line_max buf 0)++encode :: PackedString -> Int -> Ptr Word8 -> Int -> IO Int+encode ps _ _ bufi | nullPS ps = return bufi+encode ps n buf bufi = case indexPSW ps 0 of+  c | c == newline ->+        do poke (buf `plusPtr` bufi) newline+           encode ps' line_max buf (bufi+1)+    | n == 0 && lengthPS ps > 1 ->+        do poke (buf `plusPtr` bufi) equals+           poke (buf `plusPtr` (bufi+1)) newline+           encode ps line_max buf (bufi + 2)+    | (c == tab || c == space) ->+        if nullPS ps' || indexPSW ps' 0 == newline+        then do poke (buf `plusPtr` bufi) c+                poke (buf `plusPtr` (bufi+1)) equals+                poke (buf `plusPtr` (bufi+2)) newline+                encode ps' line_max buf (bufi + 3)+        else do poke (buf `plusPtr` bufi) c+                encode ps' (n - 1) buf (bufi + 1)+    | (c >= bang && c /= equals && c <= tilde) ->+        do poke (buf `plusPtr` bufi) c+           encode ps' (n - 1) buf (bufi + 1)+    | n < 3 ->+        encode ps 0 buf bufi+    | otherwise ->+        do let (x, y) = c `divMod` 16+               h1 = intToUDigit x+               h2 = intToUDigit y+           poke (buf `plusPtr` bufi) equals+           poke (buf `plusPtr` (bufi+1)) h1+           poke (buf `plusPtr` (bufi+2)) h2+           encode ps' (n - 3) buf (bufi + 3)+    where ps' = tailPS ps+          toWord8 :: Int -> Word8+          toWord8 = fromIntegral+          newline = toWord8 $ ord '\n'+          tab     = toWord8 $ ord '\t'+          space   = toWord8 $ ord ' '+          bang    = toWord8 $ ord '!'+          tilde   = toWord8 $ ord '~'+          equals  = toWord8 $ ord '='+          intToUDigit i+            | i >= 0 && i <= 9 = toWord8 (fromEnum '0') + i+            | i >= 10 && i <= 15 = toWord8 (fromEnum 'A') + i - 10+            | otherwise = error $ "intToUDigit: '"++show i++"'not a digit"++qpdecode :: PackedString -> PackedString+qpdecode s = unsafePerformIO+             -- Add 1 as linesPS "\n" -> ["", ""] -> "\n\n"+           $ generatePS (lengthPS s + 1) (\buf -> decode (linesPS s) buf 0)++decode :: [PackedString] -> Ptr Word8 -> Int -> IO Int+decode [] _ bufi = return bufi+decode (ps:pss) buf bufi+ | nullPS (dropWhitePS ps)+    = do poke (buf `plusPtr` bufi) newline+         decode pss buf (bufi+1)+ | is_equals && lengthPS ps >= 3 && isHexDigit c1 && isHexDigit c2+    = do poke (buf `plusPtr` bufi)+              (toWord8 $ digitToInt c1 * 16 + digitToInt c2)+         decode (dropPS 3 ps:pss) buf (bufi+1)+ | is_equals && nullPS (dropWhitePS (tailPS ps)) = decode pss buf bufi+ | otherwise = do poke (buf `plusPtr` bufi) (indexPSW ps 0)+                  decode (tailPS ps:pss) buf (bufi+1)+    where is_equals = headPS ps == '='+          c1 = indexPS ps 1+          c2 = indexPS ps 2+          newline = toWord8 $ ord '\n'+          toWord8 :: Int -> Word8+          toWord8 = fromIntegral++make_email :: String -> (Maybe Doc) -> Doc -> (Maybe String) -> Doc+make_email repodir mcontents bundle mfilename =+    text "DarcsURL:" <+> text repodir+ $$ text "MIME-Version: 1.0"+ $$ text "Content-Type: multipart/mixed; boundary=\"=_\""+ $$ text ""+ $$ text "--=_"+ $$ (case mcontents of+       Just contents ->+            text "Content-Type: text/plain"+         $$ text "Content-Transfer-Encoding: quoted-printable"+         $$ text ""+         $$ packedString (qpencode (renderPS contents))+         $$ text ""+         $$ text "--=_"+       Nothing -> empty)+ $$ text "Content-Type: text/x-darcs-patch" <>+      (case mfilename of+         Just filename -> text "; name=\"" <> text filename <> text "\""+         Nothing -> empty)+ $$ text "Content-Transfer-Encoding: quoted-printable"+ $$ text "Content-Description: A darcs patch for your repository!"+ $$ text ""+ $$ packedString (qpencode (renderPS bundle))+ $$ text "--=_--"+ $$ text ""+ $$ text "."+ $$ text ""+ $$ text ""++read_email :: PackedString -> PackedString+read_email s =+    case betweenLinesPS+         (packString "Content-Description: A darcs patch for your repository!")+         (packString "--=_--") s of+    Nothing -> s -- if it wasn't an email in the first place, just pass along.+    Just s' -> qpdecode s'+
+ src/Darcs/External.hs view
@@ -0,0 +1,702 @@+{-# OPTIONS_GHC -cpp -fffi #-}++module Darcs.External (+    backupByRenaming, backupByCopying,+    copyFileOrUrl, speculateFileOrUrl, copyFilesOrUrls, copyLocal, cloneFile,+    cloneTree, cloneTreeExcept, clonePartialsTree, clonePaths,+    fetchFilePS, gzFetchFilePS,+    sendEmail, generateEmail, sendEmailDoc, resendEmail,+    signString, verifyPS,+    execDocPipe, execPipeIgnoreError,+    getTermNColors,+    pipeDoc, pipeDocSSH, execSSH,+    maybeURLCmd,+    Cachable(Cachable, Uncachable, MaxAge),+    viewDoc, viewDocWith,+  ) where++import Data.List ( intersperse )+import Control.Monad ( liftM, when, zipWithM_ )+import System.Exit ( ExitCode(..) )+import System.Environment ( getEnv )+import System.Cmd ( system )+import System.IO ( hPutStr, hPutStrLn, hGetContents, hClose,+                   openBinaryFile, IOMode( ReadMode ),+                   openBinaryTempFile,+                   hIsTerminalDevice, stdout, stderr, Handle )+import System.IO.Error ( isDoesNotExistError )+import System.IO.Unsafe ( unsafePerformIO )+import System.Posix.Files ( getSymbolicLinkStatus, isRegularFile, isDirectory )+import System.Directory ( createDirectory, getDirectoryContents,+                          doesFileExist, doesDirectoryExist,+                          renameFile, renameDirectory, copyFile )+import System.Process ( runProcess, runInteractiveProcess, waitForProcess )+import Control.Concurrent ( forkIO, newEmptyMVar, putMVar, takeMVar )+import Control.Exception ( bracket, try, finally )+import Data.Char ( toUpper )+import Foreign.C ( CString, withCString, CInt )+import Foreign.Ptr ( nullPtr )+#ifdef HAVE_CURSES+import Foreign.C ( CChar )+import Foreign.Ptr ( Ptr )+import Foreign.Marshal.Alloc (allocaBytes)+import Autoconf ( use_color )+#endif+import Workaround ( createLink, createDirectoryIfMissing )++import Darcs.Flags ( DarcsFlag( SignAs, Sign, SignSSL, NoLinks,+                                Verify, VerifySSL ) )+import Darcs.Utils ( withCurrentDirectory, breakCommand, get_viewer, ortryrunning, )+import Darcs.Progress ( withoutProgress, progressList, debugMessage )+import FastPackedString ( PackedString, readFilePS, gzReadFilePS, writeFilePS,+                          hPutPS, unpackPS, linesPS, unlinesPS,+                          lengthPS, takePS, dropPS, packString,+                          nullPS, nilPS, concatPS, hGetContentsPS+                        )+import Darcs.Lock ( withTemp, withOpenTemp, tempdir_loc, canonFilename, writeDocBinFile,+                    removeFileMayNotExist, )+import CommandLine ( parseCmd, addUrlencoded )+import Autoconf ( have_libcurl, have_libwww, have_HTTP, have_sendmail, have_mapi, sendmail_path, darcs_version )+import qualified URL ( copyUrl, copyUrlFirst, waitUrl )+import qualified HTTP ( copyUrl, exists )+import Ssh ( getSSH, copySSH, copySSHs, SSHCmd(..) )+import URL ( Cachable(..) )+import Exec ( exec, Redirect(..), withoutNonBlock )+import FileName ( fn2fp, fp2fn, norm_path )+import Darcs.URL ( is_file, is_url, is_ssh )+import Darcs.Utils ( catchall )+import Printer ( Doc, Printers, putDocLnWith, hPutDoc, hPutDocLn, hPutDocWith, ($$), (<+>), renderPS,+                 simplePrinters,+                 text, empty, packedString, vcat, renderString )+#include "impossible.h"++backupByRenaming :: FilePath -> IO ()+backupByRenaming = backupBy rename+ where rename x y = do+         isD <- doesDirectoryExist x+         if isD then renameDirectory x y else renameFile x y++backupByCopying :: FilePath -> IO ()+backupByCopying = backupBy copy+ where+  copy x y = do+    isD <- doesDirectoryExist x+    if isD then do createDirectory y+                   cloneTree (do_norm x) (do_norm y)+           else copyFile x y+  do_norm f = fn2fp $ norm_path $ fp2fn f++backupBy :: (FilePath -> FilePath -> IO ()) -> FilePath -> IO ()+backupBy backup f =+           do hasBF <- doesFileExist f+              hasBD <- doesDirectoryExist f+              when (hasBF || hasBD) $ helper (0::Int)+  where+  helper i = do existsF <- doesFileExist next+                existsD <- doesDirectoryExist next+                if (existsF || existsD)+                   then helper (i + 1)+                   else do putStrLn $ "Backing up " ++ f ++ "(" ++ suffix ++ ")"+                           backup f next+             where next = f ++ suffix+                   suffix = "-darcs-backup" ++ show i++fetchFilePS :: String -> Cachable -> IO PackedString+fetchFilePS fou _ | is_file fou = readFilePS fou+fetchFilePS fou cache = withTemp $ \t -> do copyFileOrUrl [] fou t cache+                                            readFilePS t++gzFetchFilePS :: String -> Cachable -> IO PackedString+gzFetchFilePS fou _ | is_file fou = gzReadFilePS fou+gzFetchFilePS fou cache = withTemp $ \t-> do copyFileOrUrl [] fou t cache+                                             gzReadFilePS t+++copyFileOrUrl :: [DarcsFlag] -> FilePath -> FilePath -> Cachable -> IO ()+copyFileOrUrl opts fou out _     | is_file fou = copyLocal opts fou out+copyFileOrUrl _    fou out cache | is_url  fou = copyRemote fou out cache+copyFileOrUrl _    fou out _     | is_ssh  fou = copySSH fou out+copyFileOrUrl _    fou _   _     = fail $ "unknown transport protocol: " ++ fou++speculateFileOrUrl :: String -> FilePath -> IO ()+speculateFileOrUrl fou out | is_url fou = speculateRemote fou out+                           | otherwise = return ()++copyLocal  :: [DarcsFlag] -> String -> FilePath -> IO ()+copyLocal opts fou out | NoLinks `elem` opts = cloneFile fou out+                       | otherwise = createLink fou out `catchall` cloneFile fou out++clonePaths :: FilePath -> FilePath -> [FilePath] -> IO ()+clonePaths source dest = mapM_ (clonePath source dest)++clonePath :: FilePath -> FilePath -> FilePath -> IO ()+clonePath source dest path+ = do let source' = source ++ "/" ++ path+          dest' = dest ++ "/" ++ path+      fs <- getSymbolicLinkStatus source'+      if isDirectory fs then do+          createDirectoryIfMissing True dest'+       else if isRegularFile fs then do+          createDirectoryIfMissing True (dest ++ "/" ++ basename path)+          cloneFile source' dest'+       else fail ("clonePath: Bad file " ++ source')+   `catch` fail ("clonePath: Bad file " ++ source ++ "/" ++ path)+ where basename = reverse . dropWhile ('/' /=) . dropWhile ('/' ==) . reverse++clonePartialsTree :: FilePath -> FilePath -> [FilePath] -> IO ()+clonePartialsTree source dest = mapM_ (clonePartialTree source dest)++clonePartialTree :: FilePath -> FilePath -> FilePath -> IO ()+clonePartialTree source dest "" = cloneTree source dest+clonePartialTree source dest pref+ = do createDirectoryIfMissing True (dest ++ "/" ++ basename pref)+      cloneSubTree (source ++ "/" ++ pref) (dest ++ "/" ++ pref)+ where basename = reverse . dropWhile ('/' /=) . dropWhile ('/' ==) . reverse++cloneTree :: FilePath -> FilePath -> IO ()+cloneTree = cloneTreeExcept []++cloneTreeExcept :: [FilePath] -> FilePath -> FilePath -> IO ()+cloneTreeExcept except source dest =+ do fs <- getSymbolicLinkStatus source+    if isDirectory fs then do+        fps <- getDirectoryContents source+        let fps' = filter (`notElem` (".":"..":except)) fps+            mk_source fp = source ++ "/" ++ fp+            mk_dest   fp = dest   ++ "/" ++ fp+        zipWithM_ cloneSubTree (map mk_source fps') (map mk_dest fps')+     else fail ("cloneTreeExcept: Bad source " ++ source)+   `catch` fail ("cloneTreeExcept: Bad source " ++ source)++cloneSubTree :: FilePath -> FilePath -> IO ()+cloneSubTree source dest =+ do fs <- getSymbolicLinkStatus source+    if isDirectory fs then do+        createDirectory dest+        fps <- getDirectoryContents source+        let fps' = filter (`notElem` [".", ".."]) fps+            mk_source fp = source ++ "/" ++ fp+            mk_dest   fp = dest   ++ "/" ++ fp+        zipWithM_ cloneSubTree (map mk_source fps') (map mk_dest fps')+     else if isRegularFile fs then do+        cloneFile source dest+     else fail ("cloneSubTree: Bad source "++ source)+    `catch` (\e -> if isDoesNotExistError e+                   then return ()+                   else ioError e)++cloneFile :: FilePath -> FilePath -> IO ()+cloneFile = copyFile++maybeURLCmd :: String -> String -> IO(Maybe(String))+maybeURLCmd what url =+  do let prot = map toUpper $ takeWhile (/= ':') url+     liftM Just (getEnv ("DARCS_" ++ what ++ "_" ++ prot))+             `catch` \_ -> return Nothing++speculateRemote :: String -> FilePath -> IO () -- speculations are always Cachable+speculateRemote u v =+    do maybeget <- maybeURLCmd "GET" u+       case maybeget of+         Just _ -> return () -- can't pipeline these+         Nothing -> if have_libwww || have_libcurl+                    then URL.copyUrl u v Cachable+                    else return ()++copyRemote :: String -> FilePath -> Cachable -> IO ()+copyRemote u v cache =+    do maybeget <- maybeURLCmd "GET" u+       case maybeget of+         Nothing -> copyRemoteNormal u v cache+         Just get ->+           do let (cmd,args) = breakCommand get+              r <- exec cmd (args++[u]) (Null, File v, AsIs)+              when (r /= ExitSuccess) $+                  fail $ "(" ++ get ++ ") failed to fetch: " ++ u++copyRemoteNormal :: String -> FilePath -> Cachable -> IO ()+copyRemoteNormal u v cache = if have_libwww || have_libcurl+                             then URL.copyUrlFirst u v cache >> URL.waitUrl u+                             else if HTTP.exists+                                  then HTTP.copyUrl u v cache+                                  else copyRemoteCmd u v++copyFilesOrUrls :: [DarcsFlag]->FilePath->[String]->FilePath->Cachable->IO ()+copyFilesOrUrls opts dou ns out _ | is_file dou = copyLocals opts dou ns out+copyFilesOrUrls _ dou ns out c    | is_url  dou = copyRemotes dou ns out c+copyFilesOrUrls _ dou ns out _    | is_ssh  dou = copySSHs dou ns out+copyFilesOrUrls _ dou _  _   _    = fail $ "unknown transport protocol: "++dou+++copyLocals :: [DarcsFlag] -> String -> [String] -> FilePath -> IO ()+copyLocals opts u ns d =+    doWithPatches (\n -> copyLocal opts (u++"/"++n) (d++"/"++n)) ns++copyRemotes :: String -> [String] -> FilePath -> Cachable -> IO()+copyRemotes u ns d cache =+    do maybeget <- maybeURLCmd "GET" u+       maybemget <- maybeURLCmd "MGET" u+       case (maybeget, maybemget) of+         (Nothing, _) -> copyRemotesNormal u ns d cache+         (Just _, Nothing) -> doWithPatches (\n -> copyRemote (u++"/"++n) (d++"/"++n) cache) ns+         (Just _, Just mget) -> mgetRemotes mget u ns d++stringToInt :: String -> Int -> Int+stringToInt num def = case reads num of [(x,"")] -> x+                                        _ -> def++mgetRemotes :: String -> String -> [String] -> FilePath -> IO()+mgetRemotes _ _ [] _ = return ()+mgetRemotes mget u ns d = do+    mgetmax <- getEnv "DARCS_MGETMAX" `catch` \_ -> return ""+    let (nsnow, nslater) = splitAt (stringToInt mgetmax 200) ns+        (cmd, args) = breakCommand mget+        urls = map (\n -> u++"/"++n) nsnow+    withCurrentDirectory d $ do+        r <- exec cmd (args++urls) (Null,Null,AsIs)+        when (r /= ExitSuccess) $+            fail $ unlines $+                ["(" ++ mget ++ ") failed to fetch files.",+                     "source directory: " ++ d,+                     "source files:"] ++ (upto 5 nsnow) +++                     ["still to go:"] ++ (upto 5 nslater)+    mgetRemotes mget u nslater d+    where+    upto :: Integer -> [String] -> [String]+    upto _ [] = []+    upto 0 l = [ "(" ++ (show (length l)) ++ " more)" ]+    upto n (h : t) = h : (upto (n - 1) t)++copyRemotesNormal :: String -> [String] -> FilePath -> Cachable -> IO()+copyRemotesNormal u ns d cache =+    if have_libwww || have_libcurl+    then do mapM_ (\n -> URL.copyUrl (u++"/"++n) (d++"/"++n) cache) ns+            doWithPatches (\n -> URL.waitUrl (u++"/"++n)) ns+    else if have_HTTP+         then doWithPatches (\n -> copyRemote (u++"/"++n) (d++"/"++n) cache) ns+         else wgetRemotes u ns d++-- Argh, this means darcs get will fail if we don't have libcurl and don't+-- have wget.  :(+wgetRemotes :: String -> [String] -> FilePath -> IO ()+wgetRemotes u ns d = do wget_command <- getEnv "DARCS_WGET" `catch`+                                               \_ -> return "wget"+                        let (wget, wget_args) = breakCommand wget_command+                            input = unlines $ map (\n -> u++"/"++n) ns+                        withCurrentDirectory d $ withOpenTemp $ \(th,tn) ->+                            do hPutStr th input+                               hClose th+                               r <- exec wget (wget_args++["-i",tn])+                                         (Null,Null,AsIs)+                               when (r /= ExitSuccess) $+                                    fail $ unlines $+                                             ["(wget) failed to fetch files.",+                                              "source directory: " ++ d,+                                              "source files:"] ++ ns++copyRemoteCmd :: String -> FilePath -> IO ()+copyRemoteCmd s tmp = do+    let cmd = get_ext_cmd+    r <- stupidexec (cmd tmp s) (Null,Null,AsIs)+    when (r /= ExitSuccess) $+         fail $ "failed to fetch: " ++ s ++" " ++ show r+    where stupidexec [] = bug "stupidexec without a command"+          stupidexec xs = exec (head xs) (tail xs)++doWithPatches :: (String -> IO ()) -> [String] -> IO ()+doWithPatches f patches = mapM_ (\p -> seq p $ f p) $ progressList "Copying patch" patches++{-# NOINLINE get_ext_cmd #-}+get_ext_cmd :: String -> String -> [String]+-- Only need to find the command once..+get_ext_cmd = unsafePerformIO get_ext_cmd'++-- Would be better to read possible command lines from config-file..+get_ext_cmd' :: IO (String -> String -> [String])+get_ext_cmd' = try_cmd cmds+    where cmds = [("wget", (("--version",0),+                          -- use libcurl for proper cache control+                          \t s -> ["wget", "-q",+                                   "--header=Pragma: no-cache",+                                   "--header=Cache-Control: no-cache",+                                   "-O",t,s])),+                  ("curl", (("--version",2),+                            \t s -> ["curl", "-s", "-f", "-L",+                                     "-H", "Pragma: no-cache",+                                     "-H", "Cache-Control: no-cache",+                                     "-o",t,s]))]+          try_cmd [] = fail $ "I need one of: " ++ cs+              where cs = concat $ intersperse ", " (map fst cmds)+          try_cmd ((c,(ok_check,f)):cs) = do+            True <- can_execute ok_check c+            return f+           `catch` (\_ -> try_cmd cs)++-- | Run a command on a remote location without passing it any input or+--   reading its output.  Return its ExitCode+execSSH :: String -> String -> IO ExitCode+execSSH remoteAddr command =+    do (ssh, ssh_args) <- getSSH SSH remoteAddr+       debugMessage $ unwords (ssh:ssh_args++[remoteAddr,command])+       withoutProgress $ do hid <- runProcess ssh (ssh_args++[remoteAddr,command])+                                   Nothing Nothing Nothing Nothing Nothing+                            waitForProcess hid++pipeDoc :: String -> [String] -> Doc -> IO ExitCode+pipeDoc c args inp = withoutNonBlock $ withoutProgress $+    do debugMessage $ unwords (c:args)+       (i,o,e,pid) <- runInteractiveProcess c args Nothing Nothing+       mvare <- newEmptyMVar+       forkIO ((hGetContents e >>= -- ratify hGetContents: it's immediately consumed+                hPutStr stderr)+               `finally` putMVar mvare ())+       mvaro <- newEmptyMVar+       forkIO ((hGetContents o >>= -- ratify hGetContents: it's immediately consumed+                hPutStr stdout)+               `finally` putMVar mvaro ())+       hPutDoc i inp+       hClose i+       rval <- waitForProcess pid+       takeMVar mvare+       takeMVar mvaro+       when (rval == ExitFailure 127) $+            putStrLn $ "Command not found:\n   "++ show (c:args)+       return rval++pipeDocSSH :: String -> [String] -> Doc -> IO ExitCode+pipeDocSSH remoteAddr args input =+    do (ssh, ssh_args) <- getSSH SSH remoteAddr+       pipeDoc ssh (ssh_args++ (remoteAddr:args)) input++sendEmail :: String -> String -> String -> String -> String -> String -> IO ()+sendEmail f t s cc scmd body =+  sendEmailDoc f t s cc scmd Nothing (text body)+++generateEmail+    :: Handle  -- ^ handle to write email to+    -> String  -- ^ From+    -> String  -- ^ To+    -> String  -- ^ Subject+    -> String  -- ^ CC+    -> Doc     -- ^ body+    -> IO ()+generateEmail h f t s cc body = do+     hPutDocLn h $+           text "To:"      <+> text t+        $$ text "From:"    <+> text f+        $$ text "Subject:" <+> text s+        $$ formated_cc+        $$ text "X-Mail-Originator: Darcs Version Control System"+        $$ text ("X-Darcs-Version: " ++ darcs_version)+        $$ body+  where formated_cc = if cc == ""+                      then empty+                      else text "Cc:" <+> text cc++-- | Send an email, optionally containing a patch bundle+--   (more precisely, its description and the bundle itself)+sendEmailDoc :: String -> String -> String -> String -> String+             -> Maybe (Doc, Doc) -> Doc -> IO ()+sendEmailDoc _ "" _ "" _ _ _ = return ()+sendEmailDoc f "" s cc scmd mbundle body =+  sendEmailDoc f cc s "" scmd mbundle body+sendEmailDoc f t s cc scmd mbundle body =+  if have_sendmail || scmd /= "" then do+    withOpenTemp $ \(h,fn) -> do+     generateEmail h f t s cc body+     hClose h+     ftable' <- case mbundle of+                Just (content,bundle) ->+                  withOpenTemp $ \(hat,at) -> do+                    hPutDocLn hat $ bundle+                    hClose hat+                    return [ ('b', renderString content) , ('a', at) ]+                Nothing ->+                    return [ ('b', renderString body) ]+     let ftable = [ ('t',addressOnly t),('c',cc),('f',f),('s',s) ] ++ ftable'+     r <- execSendmail ftable scmd fn+     when (r /= ExitSuccess) $ fail ("failed to send mail to: " ++ t+                                     ++ "\nPerhaps sendmail is not configured.")+  else if have_mapi then do+     r <- withCString t $ \tp ->+           withCString f $ \fp ->+            withCString cc $ \ccp ->+             withCString s $ \sp ->+              withOpenTemp $ \(h,fn) -> do+               hPutDoc h body+               hClose h+               writeDocBinFile "mailed_patch" body+               cfn <- canonFilename fn+               withCString cfn $ \pcfn ->+                c_send_email fp tp ccp sp nullPtr pcfn+     when (r /= 0) $ fail ("failed to send mail to: " ++ t)+  else fail $ "no mail facility (sendmail or mapi) located at configure time!"+  where addressOnly a =+          case dropWhile (/= '<') a of+          ('<':a2) -> takeWhile (/= '>') a2+          _        -> a++resendEmail :: String -> String -> PackedString -> IO ()+resendEmail "" _ _ = return ()+resendEmail t scmd body =+  case (have_sendmail || scmd /= "", have_mapi) of+   (True, _) -> do+    withOpenTemp $ \(h,fn) -> do+     hPutStrLn h $ "To: "++ t+     hPutStrLn h $ find_from (linesPS body)+     hPutStrLn h $ find_subject (linesPS body)+     hPutDocLn h $ fixit $ linesPS body+     hClose h+     let ftable = [('t',t)]+     r <-  execSendmail ftable scmd fn+     when (r /= ExitSuccess) $ fail ("failed to send mail to: " ++ t)+   (_, True) -> fail "Don't know how to resend email with MAPI"+   _ -> fail $ "no mail facility (sendmail or mapi) located at configure time (use the sendmail-command option)!"+  where br = packString "\r"+        darcsurl = packString "DarcsURL:"+        content = packString "Content-"+        from_start = packString "From:"+        subject_start = packString "Subject:"+        fixit (l:ls)+         | nullPS l = packedString nilPS $$ vcat (map packedString ls)+         | l == br = packedString nilPS $$ vcat (map packedString ls)+         | takePS 9 l == darcsurl || takePS 8 l == content+            = packedString l $$ fixit ls+         | otherwise = fixit ls+        fixit [] = empty+        find_from (l:ls) | takePS 5 l == from_start = unpackPS l+                         | otherwise = find_from ls+        find_from [] = "From: unknown"+        find_subject (l:ls) | takePS 8 l == subject_start = unpackPS l+                            | otherwise = find_subject ls+        find_subject [] = "Subject: (no subject)"++execSendmail :: [(Char,String)] -> String -> String -> IO ExitCode+execSendmail ftable scmd fn =+  if scmd == "" then+     exec sendmail_path ["-i", "-t"] (File fn, Null, AsIs)+  else case parseCmd (addUrlencoded ftable) scmd of+         Right (arg0:opts, wantstdin) ->+           do let stdin = if wantstdin then File fn else Null+              exec arg0 opts (stdin, Null, AsIs)+         Left e -> fail $ ("failed to send mail, invalid sendmail-command: "++(show e))+         _ -> fail $ ("failed to send mail, invalid sendmail-command")++#ifdef HAVE_MAPI+foreign import ccall "win32/send_email.h send_email" c_send_email+#else+c_send_email+#endif+             :: CString -> {- sender -}+                CString -> {- recipient -}+                CString -> {- cc -}+                CString -> {- subject -}+                CString -> {- body -}+                CString -> {- path -}+                IO Int+#ifndef HAVE_MAPI+c_send_email = impossible+#endif++execPSPipe :: String -> [String] -> PackedString -> IO PackedString+execPSPipe c args ps = liftM renderPS+                     $ execDocPipe c args+                     $ packedString ps++execDocPipe :: String -> [String] -> Doc -> IO Doc+execDocPipe c args instr = withoutProgress $+    do (i,o,e,pid) <- runInteractiveProcess c args Nothing Nothing+       forkIO $ hPutDoc i instr >> hClose i+       mvare <- newEmptyMVar+       forkIO ((hGetContents e >>= -- ratify hGetContents: it's immediately consumed+                hPutStr stderr)+               `finally` putMVar mvare ())+       out <- hGetContentsPS o+       rval <- waitForProcess pid+       takeMVar mvare+       case rval of+         ExitFailure ec ->fail $ "External program '"++c+++                          "' failed with exit code "++ show ec+         ExitSuccess -> return $ packedString out++-- The following is needed for diff, which returns non-zero whenever+-- the files differ.+execPipeIgnoreError :: String -> [String] -> Doc -> IO Doc+execPipeIgnoreError c args instr = withoutProgress $+    do (i,o,e,pid) <- runInteractiveProcess c args Nothing Nothing+       forkIO $ hPutDoc i instr >> hClose i+       mvare <- newEmptyMVar+       forkIO ((hGetContents e >>= -- ratify hGetContents: it's immediately consumed+                hPutStr stderr)+               `finally` putMVar mvare ())+       out <- hGetContentsPS o+       waitForProcess pid+       takeMVar mvare+       return $ packedString out++signString :: [DarcsFlag] -> Doc -> IO Doc+signString [] d = return d+signString (Sign:_) d = signPGP [] d+signString (SignAs keyid:_) d = signPGP ["--local-user", keyid] d+signString (SignSSL idf:_) d = signSSL idf d+signString (_:os) d = signString os d++signPGP :: [String] -> Doc -> IO Doc+signPGP args t = execDocPipe "gpg" ("--clearsign":args) t++signSSL :: String -> Doc -> IO Doc+signSSL idfile t =+    withTemp $ \cert -> do+    opensslPS ["req", "-new", "-key", idfile,+               "-outform", "PEM", "-days", "365"]+                (packString "\n\n\n\n\n\n\n\n\n\n\n")+                >>= opensslPS ["x509", "-req", "-extensions",+                               "v3_ca", "-signkey", idfile,+                               "-outform", "PEM", "-days", "365"]+                >>= opensslPS ["x509", "-outform", "PEM"]+                >>= writeFilePS cert+    opensslDoc ["smime", "-sign", "-signer", cert,+                "-inkey", idfile, "-noattr", "-text"] t+    where opensslDoc = execDocPipe "openssl"+          opensslPS = execPSPipe "openssl"+++verifyPS :: [DarcsFlag] -> PackedString -> IO (Maybe PackedString)+verifyPS [] ps = return $ Just ps+verifyPS (Verify pks:_) ps = verifyGPG pks ps+verifyPS (VerifySSL auks:_) ps = verifySSL auks ps+verifyPS (_:os) ps = verifyPS os ps++verifyGPG :: FilePath -> PackedString -> IO (Maybe PackedString)+verifyGPG goodkeys s =+    withOpenTemp $ \(th,tn) -> do+      hPutPS th s+      hClose th+      rval <- exec "gpg"  ["--batch","--no-default-keyring",+                           "--keyring",fix_path goodkeys, "--verify"]+                           (File tn, Null, Null)+      case rval of+          ExitSuccess -> return $ Just gpg_fixed_s+          _ -> return Nothing+      where gpg_fixed_s = let+                not_begin_signature x =+                    x /= packString "-----BEGIN PGP SIGNED MESSAGE-----"+                    &&+                    x /= packString "-----BEGIN PGP SIGNED MESSAGE-----\r"+                in unlinesPS $ map fix_line $ tail $ dropWhile not_begin_signature $ linesPS s+            fix_line x | lengthPS x < 3 = x+                       | takePS 3 x == packString "- -" = dropPS 2 x+                       | otherwise = x+#if defined(WIN32)+            fix_sep c | c=='/' = '\\'   | otherwise = c+            fix_path p = map fix_sep p+#else+            fix_path p = p+#endif++verifySSL :: FilePath -> PackedString -> IO (Maybe PackedString)+verifySSL goodkeys s = do+    certdata <- opensslPS ["smime", "-pk7out"] s+                >>= opensslPS ["pkcs7", "-print_certs"]+    cruddy_pk <- opensslPS ["x509", "-pubkey"] certdata+    let key_used = concatPS $ tail $+                   takeWhile (/= packString"-----END PUBLIC KEY-----")+                           $ linesPS cruddy_pk+        in do allowed_keys <- linesPS `liftM` readFilePS goodkeys+              if not $ key_used `elem` allowed_keys+                then return Nothing -- Not an allowed key!+                else withTemp $ \cert ->+                     withTemp $ \on ->+                     withOpenTemp $ \(th,tn) -> do+                     hPutPS th s+                     hClose th+                     writeFilePS cert certdata+                     rval <- exec "openssl" ["smime", "-verify", "-CAfile",+                                             cert, "-certfile", cert]+                                             (File tn, File on, Null)+                     case rval of+                       ExitSuccess -> Just `liftM` readFilePS on+                       _ -> return Nothing+    where opensslPS = execPSPipe "openssl"++can_execute :: (String,Int) -> String -> IO Bool+can_execute (arg,expected_return_value) exe = do+ withTemp $ \junk -> do+  ec <- system (unwords [exe,arg,">",junk])+  case ec of+    ExitSuccess | expected_return_value == 0 -> return True+    ExitFailure r | r == expected_return_value -> return True+    _ -> return False+++{-+  - This function returns number of colors supported by current terminal+  - or -1 if color output not supported or error occured.+  - Terminal type determined by TERM env. variable.+  -}+getTermNColors :: IO CInt++#ifdef HAVE_CURSES++foreign import ccall "tgetnum" c_tgetnum :: CString -> IO CInt+foreign import ccall "tgetent" c_tgetent :: Ptr CChar -> CString -> IO CInt++termioBufSize :: Int+termioBufSize = 4096++getTermNColors = if not use_color+                 then return (-1)+                 else do term <- getEnv "TERM"+                         allocaBytes termioBufSize (getTermNColorsImpl term)+                      `catch` \_ -> return (-1)++getTermNColorsImpl :: String -> Ptr CChar -> IO CInt+getTermNColorsImpl term buf = do rc <- withCString term $+                                       \termp -> c_tgetent buf termp+                                 if (rc /= 1) then return (-1)  else withCString "Co" $ \capap -> c_tgetnum capap++#else++getTermNColors = return (-1)++#endif++viewDoc :: Doc -> IO ()+viewDoc = viewDocWith simplePrinters++viewDocWith :: Printers -> Doc -> IO ()+viewDocWith pr msg = do+  isTerminal <- hIsTerminalDevice stdout+  if isTerminal && lengthGreaterThan (20 :: Int) (lines $ renderString msg)+     then do viewer <- get_viewer+             pipeDocToPager viewer [] pr msg+               `ortryrunning` pipeDocToPager  "less" [] pr msg+               `ortryrunning` pipeDocToPager  "more" [] pr msg+               `ortryrunning` pipeDocToPager "" [] pr msg+     else pipeDocToPager "" [] pr msg+  return ()+              where lengthGreaterThan n _ | n <= 0 = True+                    lengthGreaterThan _ [] = False+                    lengthGreaterThan n (_:xs) = lengthGreaterThan (n-1) xs++pipeDocToPager :: String -> [String] -> Printers -> Doc -> IO ExitCode++pipeDocToPager "" _ pr inp = do+  putDocLnWith pr inp+  return ExitSuccess++pipeDocToPager c args pr inp = withoutNonBlock $ withoutProgress $ do+  tmp <- tempdir_loc+  bracket (openBinaryTempFile tmp "darcs-pager") cleanup $ \(fn,fh) ->+    do hPutDocWith pr fh inp+       hClose fh+       h <- openBinaryFile fn ReadMode+       x <- do pid <- runProcess c args Nothing Nothing (Just h) Nothing Nothing+               waitForProcess pid+       when (x == ExitFailure 127) $+            putStrLn $ "Command not found:\n   "++ show (c:args)+       return x+  where+    cleanup (f,h) = do try $ hClose h+                       removeFileMayNotExist f
+ src/Darcs/FilePathMonad.lhs view
@@ -0,0 +1,82 @@+%  Copyright (C) 2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.FilePathMonad ( FilePathMonad, withFilePaths ) where++import Control.Monad ( MonadPlus, mplus, mzero )+import Data.Maybe ( catMaybes )++import Darcs.IO ( ReadableDirectory(..), WriteableDirectory(..) )+import FileName ( FileName, fp2fn, fn2fp, super_name, break_on_dir,+                  norm_path, movedirfilename )+#include "impossible.h"+\end{code}++\begin{code}+data FilePathMonad a = FPM ([FileName] -> ([FileName], a))++withFilePaths :: [FilePath] -> FilePathMonad a -> [FilePath]+withFilePaths fps (FPM x) = map fn2fp $ fst $ x $ map fp2fn fps++instance Monad FilePathMonad where+    (FPM x) >>= y = FPM z where z fs = case x fs of+                                       (fs', a) -> case y a of+                                                   FPM yf -> yf fs'+    return x = FPM $ \fs -> (fs, x)++instance MonadPlus FilePathMonad where+    mzero = fail "mzero FilePathMonad" -- yuck!+    a `mplus` _ = a++instance ReadableDirectory FilePathMonad where+    -- We can't check it actually is a directory here+    mDoesDirectoryExist d =+        FPM $ \fs -> (fs, norm_path d `elem` map norm_path fs)+    -- We can't check it actually is a file here+    mDoesFileExist f =+        FPM $ \fs -> (fs, norm_path f `elem` map norm_path fs)+    mInCurrentDirectory d (FPM j) =+        FPM $ \fs -> (fs, snd $ j $ catMaybes $ map indir fs)+        where indir f = do (d',f') <- break_on_dir f+                           if d == d' then Just f'+                                      else Nothing+    mGetDirectoryContents =+        FPM $ \fs -> (fs, filter (\f -> fp2fn "." == super_name f) fs)+    mReadFilePS = bug "can't mReadFilePS in FilePathMonad!"++instance WriteableDirectory FilePathMonad where+    mWithCurrentDirectory d (FPM j) =+        FPM $ \fs ->+        let splitfs = map splitf fs+            others = catMaybes $ map snd splitfs+            (myfs, a) = j $ catMaybes $ map fst splitfs+            splitf f = case break_on_dir f of+                       Just (d', f') | d' == d -> (Just f', Nothing)+                       _ -> (Nothing, Just f)+        in (others ++ myfs, a)+    mSetFileExecutable _ _ = return ()+    mWriteFilePS _ _ = return ()+    mCreateDirectory _ = return ()+    mRemoveFile f = FPM $ \fs -> (filter (/= f) fs, ())+    mRemoveDirectory f = FPM $ \fs -> (filter (/= f) fs, ())+    mRename a b = FPM $ \fs -> (map (movedirfilename a b) fs, ())+    mModifyFilePS _ _ = return ()+    mModifyFilePSs _ _ = return ()+\end{code}
+ src/Darcs/FilePathUtils.hs view
@@ -0,0 +1,149 @@+{-# OPTIONS_GHC -cpp #-}+-- Copyright (C) 2005 David Roundy+--+-- 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, 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; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++module Darcs.FilePathUtils ( DarcsPath(..), repoPath, unfixedRepoPath,+                             absolute_dir,+                             darcsPath, unfixedDarcsPath, unmake_relative,+                             make_absolute, just_dir, drop_paths, (///) ) where++import Data.Maybe ( catMaybes )++import System.Directory ( doesDirectoryExist )+import Darcs.Utils ( withCurrentDirectory )+import Workaround ( getCurrentDirectory )+import Darcs.URL ( is_ssh_nopath )+import Autoconf ( path_separator )+import FileName ( fn2fp, fp2fn, norm_path )+import Darcs.RepoPath ( AbsolutePath, mkAbsolutePath,+                        RelativePath,+                        SubPath, maybeMkSubPath,+                        toFilePath, FilePathOrURL(..),+                        makeSubPathOf, makeAbsolute, combine,+                      )+import Darcs.URL ( is_absolute, is_relative, is_file )+#include "impossible.h"++data DarcsPath = RepoDP SubPath+               | DotDotDP RelativePath+               | AbsoluteDP AbsolutePath+               | RemoteDP String+     deriving (Ord, Eq)++instance FilePathOrURL DarcsPath where+ toPath (RepoDP x) = toFilePath x+ toPath (DotDotDP x) = toFilePath x+ toPath (AbsoluteDP x) = toFilePath x+ toPath (RemoteDP x) = x++-- | like 'darcsPath', except that it treats remote-looking paths like+--   relative paths+repoPath :: AbsolutePath -> FilePath -> String -> Maybe SubPath+repoPath repo fix pat = fma pat+    where fma p | is_absolute p = makeSubPathOf repo (mkAbsolutePath p)+                | otherwise     = either2maybe $ maybeMkSubPath (fix /// p)++unfixedRepoPath :: FilePath -> Maybe SubPath+unfixedRepoPath p+  | is_absolute p = Nothing+  | otherwise     = either2maybe $ maybeMkSubPath p++darcsPath :: AbsolutePath -> FilePath -> String -> DarcsPath+darcsPath _ _ pat | not $ is_file pat = RemoteDP pat+darcsPath repo fix pat = fma pat+    where fma p | is_relative p = relativeDarcsPath (fix /// p)+                | is_absolute p = case makeSubPathOf repo (mkAbsolutePath p) of+                                  Just sp -> RepoDP sp+                                  Nothing -> AbsoluteDP $ mkAbsolutePath p+                | otherwise = RemoteDP p++relativeDarcsPath :: FilePath -> DarcsPath+relativeDarcsPath p = either DotDotDP RepoDP (maybeMkSubPath p)++unfixedDarcsPath :: FilePath -> DarcsPath+unfixedDarcsPath pat | not $ is_file pat = RemoteDP pat+unfixedDarcsPath pat | is_relative pat = relativeDarcsPath pat+unfixedDarcsPath pat | otherwise = AbsoluteDP $ mkAbsolutePath pat++unmake_relative :: FilePath -> FilePath -> FilePath+unmake_relative _ pat | not $ is_file pat = pat+unmake_relative fix pat = fma $ map cleanup pat+    where fma p | is_absolute p = p+          fma p = make_dotdots fix /// p++make_absolute :: AbsolutePath -> FilePath -> AbsolutePath+make_absolute fix pat+  | is_absolute pat = mkAbsolutePath pat+  | otherwise = case maybeMkSubPath pat of+                Left  rp -> makeAbsolute fix rp+                Right sp -> combine fix sp++-- The following function was moved here as a refactor, just to get it out+-- of DarcsRepo.  It really should be integrated with this new framework,+-- but I'll leave that for later...++absolute_dir :: FilePath -> IO FilePath+absolute_dir dir = do+  isdir <- doesDirectoryExist dir+  if not isdir+     then if is_ssh_nopath dir+            then return $ dir++"."+            else return $ if (take 1 $ reverse dir) == "/"+              then init dir+              else dir+             -- hope it's an URL+     else do+          realdir <- withCurrentDirectory dir getCurrentDirectory+                     -- This one is absolute!+          return realdir++cleanup :: Char -> Char+cleanup '\\' | path_separator == '\\' = '/'+cleanup c = c++make_dotdots :: FilePath -> FilePath+make_dotdots "" = ""+make_dotdots p | is_absolute p = bug $ "Can't make_dotdots on an absolute path:  " ++ p+make_dotdots p = "../" ++ case snd $ break (=='/') p of+                          "" -> ""+                          r -> make_dotdots $ drop 1 r++drop_paths :: String -> [String] -> [String]+drop_paths "" ps = map norm_relative ps+    where norm_relative f | is_relative f = do_norm f+                          | otherwise = f+drop_paths fix ps = catMaybes $ map drop_path ps+  where drop_path p | not $ is_relative p = Just p+        drop_path ('.':'/':p) = drop_path $ dropWhile (=='/') p+        drop_path p = if take (length fix) p == fix+                      then Just $ dropWhile (=='/') $ drop (length fix) p+                      else if is_relative p+                           then Nothing+                           else Just p++just_dir :: FilePath -> FilePath+just_dir d = reverse $ takeWhile (/='/') $ reverse d++(///) :: FilePath -> FilePath -> FilePath+""///a = do_norm a+a///b = do_norm $ a ++ "/" ++ b++do_norm :: FilePath -> FilePath+do_norm f = fn2fp $ norm_path $ fp2fn f++either2maybe :: Either a b -> Maybe b+either2maybe = either (const Nothing) Just
+ src/Darcs/Flags.lhs view
@@ -0,0 +1,90 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.Flags ( DarcsFlag( .. ), want_external_merge ) where+import Darcs.Patch.MatchData ( PatchMatch )+import Darcs.RepoPath ( AbsolutePath )+\end{code}++\begin{code}+data DarcsFlag = Help | ListOptions | NoTest | Test+               | HelpOnMatch | OnlyChangesToFiles+               | LeaveTestDir | NoLeaveTestDir+               | Timings | Debug | DebugVerbose | Verbose | NormalVerbosity | Quiet+               | Target String | Cc String | Output String | OutputAutoName+               | Subject String+               | SendmailCmd String | Author String | PatchName String+               | OnePatch String | SeveralPatch String+               | AfterPatch String | UpToPatch String+               | TagName String | LastN Int+               | OneTag String | AfterTag String | UpToTag String+               | Context String | Count+               | LogFile String | RmLogFile+               | DistName String | All+               | Recursive | NoRecursive | Reorder+               | RestrictPaths | DontRestrictPaths+               | AskDeps | NoAskDeps | IgnoreTimes | LookForAdds | NoLookForAdds+               | AnyOrder | CreatorHash String+               | Intersection | Union | Complement+               | Sign | SignAs String | NoSign | SignSSL String+               | HappyForwarding+               | Verify String | VerifySSL String+               | SSHControlMaster | NoSSHControlMaster+               | EditDescription | NoEditDescription+               | Toks String+               | EditLongComment | NoEditLongComment | PromptLongComment+               | AllowConflicts | MarkConflicts | NoAllowConflicts+               | Boring | AllowCaseOnly+               | DontGrabDeps | Compress | NoCompress | UnCompress+               | WorkDir String | RepoDir String | RemoteRepo String+               | Reply String | ApplyAs String+               | MachineReadable | HumanReadable+               | Pipe | Interactive+               | DiffCmd String+               | ExternalMerge String | Summary | NoSummary+               | Unified | Reverse+               | CheckPoint | Partial | Complete | Lazy | Ephemeral+               | FixFilePath AbsolutePath String | DiffFlags String+               | XMLOutput+               | ForceReplace+               | OnePattern PatchMatch | SeveralPattern PatchMatch+               | AfterPattern PatchMatch | UpToPattern PatchMatch+               | NonApply | NonVerify | NonForce+               | DryRun | SetDefault | NoSetDefault+               | FancyMoveAdd | NoFancyMoveAdd+               | Disable | SetScriptsExecutable | DontSetScriptsExecutable+               | UseHashedInventory | UseOldFashionedInventory+               | UseFormat2+               | PristinePlain | PristineNone | NoUpdateWorking+               | Sibling String | Relink | RelinkPristine | NoLinks+               | Files | NoFiles | Directories | NoDirectories+               | Pending | NoPending+               | PosthookCmd String | NoPosthook | AskPosthook | RunPosthook+               | PrehookCmd String  | NoPrehook  | AskPrehook  | RunPrehook+               | UMask String+               | StoreInMemory+               | NullFlag+                 deriving ( Eq, Show )++want_external_merge :: [DarcsFlag] -> Maybe String+want_external_merge [] = Nothing+want_external_merge (ExternalMerge c:_) = Just c+want_external_merge (_:fs) = want_external_merge fs++\end{code}+
+ src/Darcs/Global.lhs view
@@ -0,0 +1,140 @@+%  Copyright (C) 2005 Tomasz Zielonka+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++This was originally Tomasz Zielonka's AtExit module, slightly generalised+to include global variables.  Here, we attempt to cover broad, global+features, such as exit handlers.  These features slightly break the Haskellian+purity of darcs, in favour of programming convenience.++\begin{code}+module Darcs.Global ( atexit, with_atexit,+                      sshControlMasterDisabled, setSshControlMasterDisabled,+                      verboseMode, setVerboseMode,+                      timingsMode, setTimingsMode,+                      whenDebugMode, withDebugMode, setDebugMode,+                      debugMessage, debugFail, putTiming,+                      darcsdir+    ) where++import Control.Monad ( when )+import Control.Concurrent.MVar+import Control.Exception (bracket_, catch, block, unblock)+import Data.IORef ( IORef, newIORef, readIORef, writeIORef )+import System.IO.Unsafe (unsafePerformIO)+import System.IO (hPutStrLn, hPutStr, stderr)+import System.Time ( calendarTimeToString, toCalendarTime, getClockTime )+import Prelude hiding (catch)++{-# NOINLINE atexit_actions #-}+atexit_actions :: MVar (Maybe [IO ()])+atexit_actions = unsafePerformIO (newMVar (Just []))++atexit :: IO () -> IO ()+atexit action = do+    modifyMVar_ atexit_actions $ \ml -> do+        case ml of+            Just l -> do+                return (Just (action : l))+            Nothing -> do+                hPutStrLn stderr "It's too late to use atexit"+                return Nothing++with_atexit :: IO a -> IO a+with_atexit prog = do+    bracket_+        (return ())+        exit+        prog+  where+    exit = block $ do+        Just actions <- swapMVar atexit_actions Nothing+        -- from now on atexit will not register new actions+        mapM_ runAction actions+    runAction action = do+        catch (unblock action) $ \exn -> do+            hPutStrLn stderr $ "Exception thrown by an atexit registered action:"+            hPutStrLn stderr $ show exn++\end{code}++Write-once-read-many global variables make it easier to implement flags, such+as --no-ssh-cm.  Using global variables reduces the number of parameters+that we have to pass around, but it is rather unsafe and should be used sparingly.++\begin{code}+{-# NOINLINE _debugMode #-}+_debugMode :: IORef Bool+_debugMode = unsafePerformIO $ newIORef False++setDebugMode :: IO ()+setDebugMode = writeIORef _debugMode True++whenDebugMode :: IO () -> IO ()+whenDebugMode j = do b <- readIORef _debugMode+                     when b j++withDebugMode :: (Bool -> IO a) -> IO a+withDebugMode j = readIORef _debugMode >>= j+++debugMessage :: String -> IO ()+debugMessage m = whenDebugMode $ do putTiming; hPutStrLn stderr m++debugFail :: String -> IO a+debugFail m = debugMessage m >> fail m++putTiming :: IO ()+putTiming = when timingsMode $ do t <- getClockTime >>= toCalendarTime+                                  hPutStr stderr (calendarTimeToString t++": ")++{-# NOINLINE _timingsMode #-}+_timingsMode :: IORef Bool+_timingsMode = unsafePerformIO $ newIORef False++setTimingsMode :: IO ()+setTimingsMode = writeIORef _timingsMode True++{-# NOINLINE timingsMode #-}+timingsMode :: Bool+timingsMode = unsafePerformIO $ readIORef _timingsMode++{-# NOINLINE _verboseMode #-}+_verboseMode :: IORef Bool+_verboseMode = unsafePerformIO $ newIORef False++setVerboseMode :: IO ()+setVerboseMode = writeIORef _verboseMode True++{-# NOINLINE verboseMode #-}+verboseMode :: Bool+verboseMode = unsafePerformIO $ readIORef _verboseMode++{-# NOINLINE _sshControlMasterDisabled #-}+_sshControlMasterDisabled :: IORef Bool+_sshControlMasterDisabled = unsafePerformIO $ newIORef False++setSshControlMasterDisabled :: IO ()+setSshControlMasterDisabled = writeIORef _sshControlMasterDisabled True++{-# NOINLINE sshControlMasterDisabled #-}+sshControlMasterDisabled :: Bool+sshControlMasterDisabled = unsafePerformIO $ readIORef _sshControlMasterDisabled++darcsdir :: String+darcsdir = "_darcs"+\end{code}
+ src/Darcs/Hopefully.lhs view
@@ -0,0 +1,29 @@+%  Copyright (C) 2006 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+module Darcs.Hopefully ( Hopefully, PatchInfoAnd, returnH, (>>>=), (>>>), fmapH, failH,+                         piap, n2pia, patchInfoAndPatch,+                         conscientiously, hopefully, info,+                         hopefullyM, extractHash, createHashed,+                         actually, unavailable ) where++import Darcs.HopefullyPrivate -- ratify HopefullyPrivate: this is the one place+                        -- we should import this!+\end{code}+
+ src/Darcs/HopefullyPrivate.lhs view
@@ -0,0 +1,188 @@+%  Copyright (C) 2006 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.HopefullyPrivate ( -- ratify HopefullyPrivate: obvously we need it here...+                                Hopefully(..), returnH, (>>>=), (>>>), fmapH, failH,+                                PatchInfoAnd,+                                piap, n2pia, patchInfoAndPatch,+                                conscientiously, hopefully, info,+                                hopefullyM, createHashed, extractHash,+                                actually, unavailable ) where++import System.IO.Unsafe ( unsafeInterleaveIO )++import Darcs.SignalHandler ( catchNonSignal )+import Printer ( Doc, renderString, errorDoc, text, ($$) )+import Darcs.Patch.Info ( PatchInfo, human_friendly, idpatchinfo )+import Darcs.Patch ( RepoPatch, Named, patch2patchinfo )+import Darcs.Patch.Prim ( Effect(..), Conflict(..) )+import Darcs.Patch.Patchy ( Patchy, ReadPatch(..), Apply(..), Invert(..),+                            ShowPatch(..), Commute(..) )+import Darcs.Patch.Ordered ( MyEq, unsafeCompare, (:>)(..), (:\/:)(..), (:/\:)(..) )+import Darcs.Sealed ( Sealed(Sealed), seal, mapSeal )+import Darcs.Utils ( prettyException )++data Hopefully a C(x y) = Hopefully (SimpleHopefully a C(x y)) | Hashed String (SimpleHopefully a C(x y))++data SimpleHopefully a C(x y) = Actually (a C(x y)) | Unavailable String++data PatchInfoAnd p C(a b) = PIAP !PatchInfo (Hopefully (Named p) C(a b))++{-+instance Monad Hopefully where+    return a = Hopefully (Actually a)+    (Hopefully (Unavailable e)) >>= _ = Hopefully (Unavailable e)+    (Hashed h (Unavailable e)) >>= _ = Hashed h (Unavailable e)+    (Hopefully (Actually a)) >>= f = f a+    (Hashed _ (Actually a)) >>= f = f a+    fail e = Hopefully (Unavailable e)++instance Functor Hopefully where+    fmap = liftM+-}++returnH :: a C(x y) -> Hopefully a C(x y)+returnH = Hopefully . Actually++(>>>=) :: Hopefully a C(x y) -> (a C(x y) -> Hopefully b C(u v)) -> Hopefully b C(u v)+(Hopefully (Unavailable e)) >>>= _ = Hopefully (Unavailable e)+(Hashed h (Unavailable e)) >>>= _ = Hashed h (Unavailable e)+(Hopefully (Actually a)) >>>= f = f a+(Hashed _ (Actually a)) >>>= f = f a++(>>>) :: Hopefully a C(x y) -> Hopefully b C(u v) -> Hopefully b C(u v)+m >>> k = m >>>= \_ -> k++failH :: String -> Hopefully a C(x y)+failH e = Hopefully (Unavailable e)++fmapH :: (a C(x y) -> b C(w z)) -> Hopefully a C(x y) -> Hopefully b C(w z)+fmapH f m1 = m1 >>>= \x1 -> returnH (f x1)++info :: PatchInfoAnd p C(a b) -> PatchInfo+info (PIAP i _) = i++piap :: PatchInfo -> Named p C(a b) -> PatchInfoAnd p C(a b)+piap i p = PIAP i (Hopefully $ Actually p)++n2pia :: Named p C(x y) -> PatchInfoAnd p C(x y)+n2pia x = patch2patchinfo x `piap` x++patchInfoAndPatch :: PatchInfo -> Hopefully (Named p) C(a b) -> PatchInfoAnd p C(a b)+patchInfoAndPatch =  PIAP++hopefully :: PatchInfoAnd p C(a b) -> Named p C(a b)+hopefully = conscientiously $ \e -> text "failed to read patch:" $$ e++conscientiously :: (Doc -> Doc)+                -> PatchInfoAnd p C(a b) -> Named p C(a b)+conscientiously er (PIAP pinf hp) =+    case hopefully2either hp of+      Right p -> p+      Left e -> errorDoc $ er (human_friendly pinf $$ text e)++hopefullyM :: Monad m => PatchInfoAnd p C(a b) -> m (Named p C(a b))+hopefullyM (PIAP pinf hp) = case hopefully2either hp of+                              Right p -> return p+                              Left e -> fail $ renderString (human_friendly pinf $$ text e)++-- Any recommendations for a nice adverb to name the below?+hopefully2either :: Hopefully a C(x y) -> Either String (a C(x y))+hopefully2either (Hopefully (Actually p)) = Right p+hopefully2either (Hashed _ (Actually p)) = Right p+hopefully2either (Hopefully (Unavailable e)) = Left e+hopefully2either (Hashed _ (Unavailable e)) = Left e++actually :: a C(x y) -> Hopefully a C(x y)+actually = Hopefully . Actually++createHashed :: String -> (String -> IO (Sealed (a C(x)))) -> IO (Sealed (Hopefully a C(x)))+createHashed h f = do mapSeal (Hashed h) `fmap` unsafeInterleaveIO (f' `catchNonSignal` handler)+  where+  f' = do Sealed x <- f h+          return (Sealed (Actually x))+  handler e = return $ seal $ Unavailable $ prettyException e++extractHash :: PatchInfoAnd p C(a b) -> Either (Named p C(a b)) String+extractHash (PIAP _ (Hashed s _)) = Right s+extractHash hp = Left $ conscientiously (\e -> text "unable to read patch:" $$ e) hp++unavailable :: String -> Hopefully a C(x y)+unavailable = Hopefully . Unavailable++instance MyEq p => MyEq (PatchInfoAnd p) where+    unsafeCompare (PIAP i _) (PIAP i2 _) = i == i2++--instance Invert (p C(x y)) => Invert (PatchInfoAnd (p C(x y))) where+instance Invert p => Invert (PatchInfoAnd p) where+    identity = PIAP idpatchinfo (actually identity)+    invert (PIAP i p) = PIAP i (invert `fmapH` p)++instance (Conflict p, Effect p, ShowPatch p) => ShowPatch (PatchInfoAnd p) where+    showPatch (PIAP n p) = case hopefully2either p of+                           Right x -> showPatch x+                           Left _ -> human_friendly n+    showContextPatch s (PIAP n p) = case hopefully2either p of+                                    Right x -> showContextPatch s x+                                    Left _ -> human_friendly n+    description (PIAP n _) = human_friendly n+    summary (PIAP n p) = case hopefully2either p of+                         Right x -> summary x+                         Left _ -> human_friendly n+    showNicely (PIAP n p) = case hopefully2either p of+                            Right x -> showNicely x+                            Left _ -> human_friendly n++instance Commute p => Commute (PatchInfoAnd p) where+    commute (x :> y) = do y' :> x' <- commute (hopefully x :> hopefully y)+                          return $ (info y `piap` y') :> (info x `piap` x')+    list_touched_files = list_touched_files . hopefully+    merge (x :\/: y) = case merge (hopefully x :\/: hopefully y) of+                       y' :/\: x' -> (info y `piap` y') :/\: (info x `piap` x')++instance Apply p => Apply (PatchInfoAnd p) where+    apply opts p = apply opts $ hopefully p+    applyAndTryToFix p = do mp' <- applyAndTryToFix $ hopefully p+                            case mp' of+                              Nothing -> return Nothing+                              Just (e,p') -> return $ Just (e, n2pia p')++instance ReadPatch p => ReadPatch (PatchInfoAnd p) where+    readPatch' wanteof = do x <- readPatch' wanteof+                            case x of+                              Just (Sealed p) -> return $ Just $ Sealed $ n2pia p+                              Nothing -> return Nothing++instance Effect p => Effect (PatchInfoAnd p) where+    effect = effect . hopefully+    effectRL = effectRL . hopefully++instance Conflict (p C(x y)) => Conflict (PatchInfoAnd (p C(x y))) where+    list_conflicted_files = list_conflicted_files . hopefully+    resolve_conflicts = resolve_conflicts . hopefully+    commute_no_conflicts (x:>y) = do y':>x' <- commute_no_conflicts (hopefully x :> hopefully y)+                                     return (info y `piap` y' :> info x `piap` x')+    conflictedEffect = conflictedEffect . hopefully++instance RepoPatch (p C(x y)) => Patchy (PatchInfoAnd (p C(x y)))++\end{code}+
+ src/Darcs/IO.lhs view
@@ -0,0 +1,270 @@+%  Copyright (C) 2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\documentclass{article}++\usepackage{verbatim}+\newenvironment{code}{\verbatim}{\endverbatim}++\begin{document}++\title{The DarcsIO library}+\author{David Roundy}++\maketitle++\begin{abstract}+This paper hasn't been written.+\end{abstract}++\begin{comment}+\begin{code}+{-# OPTIONS_GHC -fglasgow-exts #-}+module Darcs.IO ( ReadableDirectory(..), WriteableDirectory(..),+                  TolerantIO, runTolerantly, runSilently,+                ) where++import Prelude hiding ( catch )+import Data.Char ( toLower )+import Data.List ( isSuffixOf )+import System.IO.Error ( isDoesNotExistError, isPermissionError )+import Control.Exception ( catch, catchJust, ioErrors )+import Control.Monad.Error+import System.Directory ( getDirectoryContents, createDirectory,+                          removeDirectory, removeFile,+                          renameFile, renameDirectory,+                          doesDirectoryExist, doesFileExist,+                        )++import FastPackedString ( PackedString, readFilePS, linesPS, nullPS,+                          unlinesPS, nilPS, packString, unpackPS,+                        )+import Darcs.Utils ( withCurrentDirectory, prettyException )+import Darcs.External ( backupByCopying, backupByRenaming )+import Printer ( Doc, renderPS )+import FileName ( FileName, fn2fp, fp2fn )+import Darcs.Lock ( writeBinFile, readBinFile, writeAtomicFilePS )+import Workaround ( setExecutable )+\end{code}+\end{comment}++\begin{comment}+\begin{code}++class MonadPlus m => ReadableDirectory m where+    mDoesDirectoryExist :: FileName -> m Bool+    mDoesFileExist :: FileName -> m Bool+    mInCurrentDirectory :: FileName -> m a -> m a+    mGetDirectoryContents :: m [FileName]+    mReadBinFile :: FileName -> m String+    mReadBinFile f = liftM unpackPS $ mReadFilePS f+    mReadFilePS :: FileName -> m PackedString+    mReadFilePSs :: FileName -> m [PackedString]+    mReadFilePSs f = linesPS `liftM` mReadFilePS f++class ReadableDirectory m => WriteableDirectory m where+    mWithCurrentDirectory :: FileName -> m a -> m a+    mSetFileExecutable :: FileName -> Bool -> m ()+    mWriteBinFile :: FileName -> String -> m ()+    mWriteBinFile fn s = mWriteFilePS fn $ packString s+    mWriteFilePS :: FileName -> PackedString -> m ()+    mWriteFilePSs :: FileName -> [PackedString] -> m ()+    mWriteFilePSs f ss = mWriteFilePS f (unlinesPS ss)+    mCreateDirectory :: FileName -> m ()+    mRemoveDirectory :: FileName -> m ()+    mWriteDoc :: FileName -> Doc -> m ()+    mWriteDoc f d = mWriteFilePS f (renderPS d)+    mCreateFile :: FileName -> m ()+    mCreateFile f = mWriteFilePS f nilPS+    mRemoveFile :: FileName -> m ()+    mRename :: FileName -> FileName -> m ()+    mModifyFilePS :: FileName -> (PackedString -> m PackedString) -> m ()+    mModifyFilePS f j = do ps <- mReadFilePS f+                           ps' <- j ps+                           mWriteFilePS f ps'+    mModifyFilePSs :: FileName -> ([PackedString] -> m [PackedString]) -> m ()+    mModifyFilePSs f j = do ps <- mReadFilePSs f+                            ps' <- j ps+                            mWriteFilePSs f ps'++instance ReadableDirectory IO where+    mDoesDirectoryExist = doesDirectoryExist . fn2fp+    mDoesFileExist = doesFileExist . fn2fp+    mInCurrentDirectory = withCurrentDirectory . fn2fp+    mGetDirectoryContents = map fp2fn `liftM` getDirectoryContents "."+    mReadBinFile = readBinFile . fn2fp+    mReadFilePS = readFilePS . fn2fp++instance WriteableDirectory IO where+    mWithCurrentDirectory = mInCurrentDirectory+    mSetFileExecutable = setExecutable . fn2fp+    mWriteBinFile = writeBinFile . fn2fp+    mWriteFilePS = writeAtomicFilePS . fn2fp+    mCreateDirectory = createDirectory . fn2fp+    mCreateFile f = do exf <- mDoesFileExist f+                       if exf then fail $ "File '"++fn2fp f++"' already exists!"+                              else do exd <- mDoesDirectoryExist f+                                      if exd then fail $ "File '"++fn2fp f++"' already exists!"+                                             else mWriteFilePS f nilPS+    mRemoveFile f = do let fp = fn2fp f+                       x <- readFilePS fp+                       when (not $ nullPS x) $+                            fail $ "Cannot remove non-empty file "++fp+                       removeFile fp+    mRemoveDirectory = removeDirectory . fn2fp+    mRename a b = catchJust ioErrors+                  (renameDirectory x y `mplus` renameFile x y)+                  -- We need to catch does not exist errors, since older+                  -- versions of darcs allowed users to rename nonexistent+                  -- files.  :(+                  (\e -> if isDoesNotExistError e+                                 then return ()+                                 else ioError e)+      where x = fn2fp a+            y = fn2fp b++class Monad m => TolerantMonad m where+    warning :: IO () -> m ()+    runIO :: m a -> IO a+    runTM :: IO a -> m a++newtype TolerantIO a = TIO { runTolerantly :: IO a }+instance TolerantMonad TolerantIO where+    warning io = TIO $ io `catch` \e -> putStrLn $ "Warning: " ++ prettyException e+    runIO (TIO io) = io+    runTM io = TIO io++newtype SilentIO a = SIO { runSilently :: IO a }+instance TolerantMonad SilentIO where+    warning io = SIO $ io `catch` \_ -> return ()+    runIO (SIO io) = io+    runTM io = SIO io++-- NOTE: The following instance declarations are duplicated merely to avoid+-- enabling -fallow-undecidable-instances.  If we used+-- -fallow-undecidable-instances, we would write instead:++-- instance TolerantMonad m => Monad m where+--      ...++-- etc.++instance Monad TolerantIO where+    f >>= g = runTM $ runIO f >>= runIO . g+    f >> g = runTM $ runIO f >> runIO g+    fail s = runTM $ fail s+    return x = runTM $ return x+instance Monad SilentIO where+    f >>= g = runTM $ runIO f >>= runIO . g+    f >> g = runTM $ runIO f >> runIO g+    fail s = runTM $ fail s+    return x = runTM $ return x++instance MonadPlus TolerantIO where+    mzero = runTM mzero+    mplus a b = runTM (mplus (runIO a) (runIO b))+instance MonadPlus SilentIO where+    mzero = runTM mzero+    mplus a b = runTM (mplus (runIO a) (runIO b))++instance ReadableDirectory TolerantIO where+    mDoesDirectoryExist d = runTM $ mDoesDirectoryExist d+    mDoesFileExist f = runTM $ mDoesFileExist f+    mInCurrentDirectory i j = runTM $ mInCurrentDirectory i (runIO j)+    mGetDirectoryContents = runTM mGetDirectoryContents+    mReadBinFile f = runTM $ mReadBinFile f+    mReadFilePS f = runTM $ mReadFilePS f+instance ReadableDirectory SilentIO where+    mDoesDirectoryExist d = runTM $ mDoesDirectoryExist d+    mDoesFileExist f = runTM $ mDoesFileExist f+    mInCurrentDirectory i j = runTM $ mInCurrentDirectory i (runIO j)+    mGetDirectoryContents = runTM mGetDirectoryContents+    mReadBinFile f = runTM $ mReadBinFile f+    mReadFilePS f = runTM $ mReadFilePS f++instance WriteableDirectory TolerantIO where+     mWithCurrentDirectory = mInCurrentDirectory+     mSetFileExecutable f e = warning $ mSetFileExecutable f e+     mWriteBinFile f s = warning $ mWriteBinFile f s+     mWriteFilePS f s = warning $ mWriteFilePS f s+     mCreateFile f = warning $ backup f >> mWriteFilePS f nilPS+     mCreateDirectory d = warning $ backup d >> mCreateDirectory d+     mRemoveFile f = warning $ mRemoveFile f+     mRemoveDirectory d = warning $ catchJust ioErrors+                                 (mRemoveDirectory d)+                                 (\e ->+                                   if "(Directory not empty)" `isSuffixOf` show e+                                   then ioError $ userError $+                                            "Not deleting " ++ fn2fp d ++ " because it is not empty."+                                   else ioError $ userError $+                                            "Not deleting " ++ fn2fp d ++ " because:\n" ++ show e)+     mRename a b = warning $ catchJust ioErrors+                          (let do_backup = if (map toLower x == map toLower y)+                                           then backupByCopying y -- avoid making the original vanish+                                           else backupByRenaming y+                           in do_backup >> mRename a b)+                          (\e -> case () of+                                 _ | isPermissionError e -> ioError $ userError $+                                       couldNotRename ++ "."+                                   | isDoesNotExistError e -> ioError $ userError $+                                       couldNotRename ++ " because " ++ x ++ " does not exist."+                                   | otherwise -> ioError e+                          )+       where+        x = fn2fp a+        y = fn2fp b+        couldNotRename = "Could not rename " ++ x ++ " to " ++ y+instance WriteableDirectory SilentIO where+     mWithCurrentDirectory = mInCurrentDirectory+     mSetFileExecutable f e = warning $ mSetFileExecutable f e+     mWriteBinFile f s = warning $ mWriteBinFile f s+     mWriteFilePS f s = warning $ mWriteFilePS f s+     mCreateFile f = warning $ backup f >> mWriteFilePS f nilPS+     mCreateDirectory d = warning $ backup d >> mCreateDirectory d+     mRemoveFile f = warning $ mRemoveFile f+     mRemoveDirectory d = warning $ catchJust ioErrors+                                 (mRemoveDirectory d)+                                 (\e ->+                                   if "(Directory not empty)" `isSuffixOf` show e+                                   then ioError $ userError $+                                            "Not deleting " ++ fn2fp d ++ " because it is not empty."+                                   else ioError $ userError $+                                            "Not deleting " ++ fn2fp d ++ " because:\n" ++ show e)+     mRename a b = warning $ catchJust ioErrors+                          (let do_backup = if (map toLower x == map toLower y)+                                           then backupByCopying y -- avoid making the original vanish+                                           else backupByRenaming y+                           in do_backup >> mRename a b)+                          (\e -> case () of+                                 _ | isPermissionError e -> ioError $ userError $+                                       couldNotRename ++ "."+                                   | isDoesNotExistError e -> ioError $ userError $+                                       couldNotRename ++ " because " ++ x ++ " does not exist."+                                   | otherwise -> ioError e+                          )+       where+        x = fn2fp a+        y = fn2fp b+        couldNotRename = "Could not rename " ++ x ++ " to " ++ y++backup :: FileName -> IO ()+backup f = backupByRenaming $ fn2fp f+\end{code}+\end{comment}++\end{document}
+ src/Darcs/Lock.lhs view
@@ -0,0 +1,324 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fffi #-}+module Darcs.Lock ( withLock, withLockCanFail,+              withTemp, withOpenTemp, withStdoutTemp,+              withTempDir, withPermDir, withDelayedDir, withNamedTemp,+              writeToFile, appendToFile,+              writeBinFile, writeDocBinFile, appendBinFile, appendDocBinFile,+              readBinFile, readDocBinFile,+              writeAtomicFilePS,+              gzWriteAtomicFilePS, gzWriteAtomicFilePSs, gzWriteDocFile,+              rm_recursive, removeFileMayNotExist,+              canonFilename, maybeRelink,+              world_readable_temp, tempdir_loc,+            ) where++import Prelude hiding ( catch )+import Control.Monad ( liftM )+import Data.List ( inits )+import Data.Maybe ( listToMaybe )+import System.Exit ( exitWith, ExitCode(..) )+import System.IO ( openBinaryFile, openBinaryTempFile,+                   hClose, hPutStr, Handle,+                   IOMode(WriteMode, AppendMode), hFlush, stdout )+import System.IO.Error ( isDoesNotExistError, isAlreadyExistsError )+import Control.Exception ( bracket, catchJust, ioErrors, finally, throwIO,+                           Exception(IOException), catch, try )+import System.Directory ( setCurrentDirectory, removeFile, removeDirectory,+                   doesFileExist, doesDirectoryExist,+                   getDirectoryContents, createDirectory,+                   getTemporaryDirectory,+                 )+import Workaround ( renameFile, getCurrentDirectory )+import Darcs.Utils ( withCurrentDirectory, maybeGetEnv, firstJustIO )+import Control.Monad ( when )+import Workaround ( fileMode, getFileStatus, setFileMode )++import Darcs.URL ( is_relative )+import Darcs.Utils ( catchall, add_to_error_loc )+import FastPackedString ( PackedString, hPutPS, readFilePS, unpackPS,+                          gzWriteFilePSs, nullPS,+                        )+import Darcs.SignalHandler ( withSignalsBlocked )+import Printer ( Doc, hPutDoc, packedString, empty, renderPSs )+import FileName ( breakup )+import Darcs.Global ( atexit, darcsdir )+import Darcs.Compat ( mk_stdout_temp, canonFilename, maybeRelink,+                atomic_create, sloppy_atomic_create )+import System.Posix.Files ( getSymbolicLinkStatus, isDirectory )+import System.Posix ( sleep )+#include "impossible.h"++withLock :: String -> IO a -> IO a+releaseLock :: String -> IO ()++withLock s job = bracket (getlock s 30) releaseLock (\_ -> job)++-- | Tries to perform some task if it can obtain the lock,+-- Otherwise, just gives up without doing the task+withLockCanFail :: String -> IO a -> IO (Either () a)+withLockCanFail s job =+  bracket (takeLock s)+          (\l -> if l then releaseLock s else return ())+          (\l -> if l then job >>= (return.Right)+                      else return $ Left ())++getlock :: String -> Int -> IO String+getlock l 0 = do putStrLn $ "Couldn't get lock "++l+                 exitWith $ ExitFailure 1+getlock lbad tl = do l <- canonFilename lbad+                     gotit <- takeLock l+                     if gotit then return l+                              else do putStrLn $ "Waiting for lock "++l+                                      hFlush stdout -- for Windows+                                      done <- sleep 2+                                      if done == 0+                                         then getlock l (tl - 1)+                                         else getlock l 0++removeFileMayNotExist :: FilePath -> IO ()+removeFileMayNotExist f = catchNonExistence (removeFile f) ()++catchNonExistence :: IO a -> a -> IO a+catchNonExistence job nonexistval =+    catchJust ioErrors job $+    \e -> if isDoesNotExistError e then return nonexistval+                                   else ioError e++releaseLock s = removeFileMayNotExist s++takeLock :: FilePath -> IO Bool+takeLock fp =+    do atomic_create fp+       return True+  `catch` \e -> case e of+                    IOException e'+                     | isAlreadyExistsError e' ->+                        return False+                    _ -> do pwd <- getCurrentDirectory+                            throwIO $ add_to_error_loc e+                                            ("takeLock "++fp++" in "++pwd)++takeFile :: FilePath -> IO Bool+takeFile fp =+    do sloppy_atomic_create fp+       return True+  `catch` \e -> case e of+                    IOException e'+                     | isAlreadyExistsError e' ->+                        return False+                    _ -> do pwd <- getCurrentDirectory+                            throwIO $ add_to_error_loc e+                                            ("takeFile "++fp++" in "++pwd)+\end{code}++\verb!withTemp! safely creates an empty file (not open for writing) and+returns its name.  \verb!withOpenTemp! creates an already open temporary+file.  Both of them run their argument and then delete the file.  Also,+both of them (to my knowledge) are not susceptible to race conditions on+the temporary file (as long as you never delete the temporary file--that+would reintroduce a race condition).++The temp file operations are rather similar to the locking operations, in+that they both should always try to clean up, so exitWith causes trouble.++\begin{code}+withTemp :: (String -> IO a) -> IO a+withTemp = bracket get_empty_file removeFileMayNotExist+    where get_empty_file = do (f,h) <- openBinaryTempFile "." "darcs"+                              hClose h+                              return f++withOpenTemp :: ((Handle, String) -> IO a) -> IO a+withOpenTemp = bracket get_empty_file cleanup+    where cleanup (h,f) = do try $ hClose h+                             removeFileMayNotExist f+          get_empty_file = invert `fmap` openBinaryTempFile "." "darcs"+          invert (a,b) = (b,a)++withStdoutTemp :: (String -> IO a) -> IO a+withStdoutTemp = bracket (mk_stdout_temp "stdout_") removeFileMayNotExist+\end{code}++\verb!withTempDir! creates an empty directory and then removes it when it+is no longer needed.  withTempDir creates a temporary directory.  The+location of that directory is determined by the contents of+_darcs/prefs/tmpdir, if it exists, otherwise by \verb!$DARCS_TMPDIR!, and if+that doesn't exist then whatever your operating system considers to be a+a temporary directory (e.g. \verb!$TMPDIR! under Unix, \verb!$TEMP! under+Windows).+If none of those exist it creates the temporary directory+in the current directory, unless the current directory is under a \verb!_darcs!+directory, in which case the temporary directory in the parent of the highest+\verb!_darcs! directory to avoid accidentally corrupting darcs's internals.+This should not fail, but if it does indeed fail, we go ahead and use the+current directory anyway.++\verb!withPermDir! is like \verb!withTempDir!, except that it doesn't+delete the directory afterwards.++\begin{code}+tempdir_loc :: IO FilePath+tempdir_loc = firstJustIO [ readBinFile (darcsdir++"/prefs/tmpdir") >>= return . Just . head.words >>= chkdir,+                            maybeGetEnv "DARCS_TMPDIR" >>= chkdir,+                            getTemporaryDirectory >>= chkdir . Just,+                            getCurrentDirectorySansDarcs,+                            return $ Just "."  -- always returns a Just+                          ]+              >>= return . fromJust+    where chkdir Nothing = return Nothing+          chkdir (Just d) = doesDirectoryExist d >>= return . \e -> if e then Just (d++"/") else Nothing+                                                         +getCurrentDirectorySansDarcs :: IO (Maybe FilePath)+getCurrentDirectorySansDarcs = do+  c <- getCurrentDirectory+  return $ listToMaybe $ drop 5 $ reverse $ takeWhile no_darcs $ inits c+  where no_darcs x = not $ darcsdir `elem` breakup x++data WithDirKind = Perm | Temp | Delayed++withDir :: WithDirKind -> String -> (String -> IO a) -> IO a+withDir kind abs_or_relative_name job = do+  absolute_name <- if is_relative abs_or_relative_name+                   then liftM (++ abs_or_relative_name) tempdir_loc+                   else return abs_or_relative_name+  formerdir <- getCurrentDirectory+  bracket (create_directory absolute_name 0)+          (case kind of+               Perm -> (\_ -> setCurrentDirectory formerdir)+               Temp -> remove_directory formerdir+               Delayed -> (\dir -> do setCurrentDirectory formerdir+                                      atexit (rm_recursive dir)))+          job+    where newname name 0 = name+          newname name n = name ++ "-" ++ show n+          create_directory :: FilePath -> Int -> IO FilePath+          create_directory name n+              = do createDirectory $ newname name n+                   setCurrentDirectory $ newname name n+                   getCurrentDirectory+                `catch` (\e -> case e of+                              IOException e'+                               | isAlreadyExistsError e' ->+                                  create_directory name (n+1)+                              _ -> throwIO e)+          remove_directory f d = do+              setCurrentDirectory f+              still_here <- doesDirectoryReallyExist d+              when still_here $+                   rm_recursive d `finally` setCurrentDirectory f++withPermDir :: String -> (String -> IO a) -> IO a+withPermDir = withDir Perm++withTempDir :: String -> (String -> IO a) -> IO a+withTempDir = withDir Temp++withDelayedDir :: String -> (String -> IO a) -> IO a+withDelayedDir = withDir Delayed++doesDirectoryReallyExist :: FilePath -> IO Bool+doesDirectoryReallyExist f =+    catchNonExistence (isDirectory `fmap` getSymbolicLinkStatus f) False++rm_recursive :: FilePath -> IO ()+rm_recursive d =+    do isd <- doesDirectoryReallyExist d+       if not isd+          then removeFile d+          else when isd $ do conts <- actual_dir_contents+                             withCurrentDirectory d $+                               (sequence_ $ map rm_recursive conts)+                             removeDirectory d+    where actual_dir_contents = -- doesn't include . or ..+              do c <- getDirectoryContents d+                 return $ filter (/=".") $ filter (/="..") c+\end{code}++\begin{code}+world_readable_temp :: String -> IO String+world_readable_temp f = wrt 0+    where wrt :: Int -> IO String+          wrt 100 = fail $ "Failure creating temp named "++f+          wrt n = do ok <- takeFile $ f++"-"++show n+                     if ok then return $ f++"-"++show n+                           else wrt (n+1)++withNamedTemp :: String -> (String -> IO a) -> IO a+withNamedTemp n = bracket get_empty_file removeFileMayNotExist+    where get_empty_file = world_readable_temp n++readBinFile :: FilePath -> IO String+readBinFile = liftM unpackPS . readFilePS++readDocBinFile :: FilePath -> IO Doc+readDocBinFile fp = do ps <- readFilePS fp+                       return $ if nullPS ps then empty else packedString ps++appendBinFile :: FilePath -> String -> IO ()+appendBinFile f s = appendToFile f $ \h -> hPutStr h s++appendDocBinFile :: FilePath -> Doc -> IO ()+appendDocBinFile f d = appendToFile f $ \h -> hPutDoc h d++writeBinFile :: FilePath -> String -> IO ()+writeBinFile f s = writeToFile f $ \h -> hPutStr h s++writeDocBinFile :: FilePath -> Doc -> IO ()+writeDocBinFile f d = writeToFile f $ \h -> hPutDoc h d++writeAtomicFilePS :: FilePath -> PackedString -> IO ()+writeAtomicFilePS f ps = writeToFile f $ \h -> hPutPS h ps++gzWriteAtomicFilePS :: FilePath -> PackedString -> IO ()+gzWriteAtomicFilePS f ps = gzWriteAtomicFilePSs f [ps]++gzWriteAtomicFilePSs :: FilePath -> [PackedString] -> IO ()+gzWriteAtomicFilePSs f pss =+    withSignalsBlocked $ withNamedTemp f $ \newf -> do+    gzWriteFilePSs newf pss+    already_exists <- doesFileExist f+    when already_exists $ do mode <- fileMode `liftM` getFileStatus f+                             setFileMode newf mode+             `catchall` return ()+    renameFile newf f++gzWriteDocFile :: FilePath -> Doc -> IO ()+gzWriteDocFile f d = gzWriteAtomicFilePSs f $ renderPSs d++writeToFile :: FilePath -> (Handle -> IO ()) -> IO ()+writeToFile f job =+    withSignalsBlocked $ withNamedTemp f $ \newf -> do+    h <- openBinaryFile newf WriteMode+    job h+    hClose h+    already_exists <- doesFileExist f+    when already_exists $ do mode <- fileMode `liftM` getFileStatus f+                             setFileMode newf mode+             `catchall` return ()+    renameFile newf f++appendToFile :: FilePath -> (Handle -> IO ()) -> IO ()+appendToFile f job = withSignalsBlocked $ do+    h <- openBinaryFile f AppendMode+    job h+    hClose h+\end{code}
+ src/Darcs/Match.lhs view
@@ -0,0 +1,453 @@+%  Copyright (C) 2004-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Match ( match_first_patchset, match_second_patchset,+               match_patch,+               match_a_patch, doesnt_not_match, match_a_patchread,+               get_first_match, get_second_match, get_first_match_s, get_second_match_s, +               get_nonrange_match_s,+               first_match, second_match, have_nonrange_match,+               have_patchset_match, get_one_patchset, apply_patches_to_some_files,+               checkMatchSyntax,+             ) where++import Text.Regex ( mkRegex, matchRegex )+import Control.Monad ( liftM )+import Data.Maybe ( isJust )++import Darcs.Hopefully ( PatchInfoAnd, info, piap,+                         conscientiously, hopefully )+import Darcs.Patch.Info ( just_name )+import Darcs.Patch ( RepoPatch, Patchy, Named, invert, invertRL, patch2patchinfo, apply )+import Darcs.Repository ( Repository, PatchSet, read_repo,+                    slurp_recorded, createPristineDirectoryTree )+import Darcs.Repository.ApplyPatches ( apply_patches )+import Darcs.Patch.Depends ( get_patches_in_tag, get_patches_beyond_tag )+import Darcs.Patch.Ordered ( RL(..), concatRL )++import FastPackedString ( mmapFilePS )+import Darcs.Flags ( DarcsFlag( OnePatch, SeveralPatch, Context,+                               AfterPatch, UpToPatch, LastN,+                               OneTag, AfterTag, UpToTag,+                               OnePattern, SeveralPattern,+                               AfterPattern, UpToPattern ) )+import Darcs.Patch.Bundle ( scan_context )+import Darcs.Patch.Match ( Matcher, match_pattern, apply_matcher, make_matcher, parseMatch )+import Darcs.Patch.MatchData ( PatchMatch )+import Printer ( text, ($$) )++import Darcs.IO ( WriteableDirectory(..), ReadableDirectory(..) )+import Darcs.SlurpDirectory ( SlurpMonad(..) )+import FileName (fp2fn, FileName, super_name, norm_path, (///))+import FastPackedString (PackedString)+import Darcs.Sealed ( Sealed(..), FlippedSeal(..), unsafeUnseal, unsealM )+#include "impossible.h"+\end{code}++\paragraph{Selecting patches}\label{selecting}++Many commands operate on a patch or patches that have already been recorded.+There are a number of options that specify which patches are selected for+these operations: \verb!--patch!, \verb!--match!, \verb!--tag!, and variants+on these, which for \verb!--patch! are \verb!--patches!,+\verb!--from-patch!, and \verb!--to-patch!.  The \verb!--patch! and+\verb!--tag! forms simply take (POSIX extended, aka \verb!egrep!) regular+expressions and match them against tag and patch names.  \verb!--match!,+described below, allows more powerful patterns.++The plural forms of these options select all matching patches.  The singular+forms select the last matching patch.  The range (from and to) forms select+patches after or up to (both inclusive) the last matching patch.++These options use the current order of patches in the repository.  darcs may+reorder patches, so this is not necessarily the order of creation or the+order in which patches were applied.  However, as long as you are just+recording patches in your own repository, they will remain in order.++% NOTE --no-deps is implemented in SelectChanges.lhs, but documented here+% for concistency.+When a patch or a group of patches is selected, all patches they depend on+get silently selected too. For example: \verb!darcs pull --patches bugfix!+means ``pull all the patches with `bugfix' in their name, along with any+patches they require.''  If you really only want patches with `bugfix' in+their name, you should use the \verb!--no-deps! option, which makes darcs+exclude any matched patches from the selection which have dependencies that+are themselves not explicitly matched by the selection.++For \verb!unrecord!, \verb!unpull! and \verb!obliterate!, patches that+depend on the selected patches are silently included, or if+\verb!--no-deps! is used selected patches with dependencies on not selected+patches are excluded from the selection.++\begin{code}+have_nonrange_match :: [DarcsFlag] -> Bool+have_nonrange_match fs = isJust (nonrange_matcher fs)++have_patchset_match :: [DarcsFlag] -> Bool+have_patchset_match fs = isJust (nonrange_matcher fs) || hasC fs+    where hasC [] = False+          hasC (Context _:_) = True+          hasC (_:xs) = hasC xs++get_nonrange_match_s :: RepoPatch p => [DarcsFlag] -> PatchSet p -> SlurpMonad ()+get_nonrange_match_s fs repo =+    case nonrange_matcher fs of+        Just m -> if nonrange_matcher_is_tag fs+                        then get_tag_s repo m+                        else get_matcher_s repo m+        Nothing -> fail "Pattern not specified in get_nonrange_match."++first_match :: [DarcsFlag] -> Bool+first_match fs = isJust (has_lastn fs) || isJust (first_matcher fs)++get_first_match :: RepoPatch p => Repository p -> [DarcsFlag] -> IO ()+get_first_match r fs =+    case has_lastn fs of+    Just n -> get_dropn r n+    Nothing -> case first_matcher fs of+               Nothing -> fail "Pattern not specified in get_first_match."+               Just m -> if first_matcher_is_tag fs+                         then get_tag r m+                         else get_before_matcher r m++get_first_match_s :: RepoPatch p => [DarcsFlag] ->PatchSet p -> SlurpMonad ()+get_first_match_s fs repo = +    case has_lastn fs of+    Just n -> get_dropn_s repo n+    Nothing -> case first_matcher fs of+               Nothing -> fail "Pattern not specified in get_first_match."+               Just m -> if first_matcher_is_tag fs+                         then get_tag_s repo m+                         else get_before_matcher_s repo m     +                                      +                                                  +second_match :: [DarcsFlag] -> Bool+second_match fs = isJust $ second_matcher fs++get_second_match :: RepoPatch p => Repository p -> [DarcsFlag] -> IO ()+get_second_match r fs =+    case second_matcher fs of+    Nothing -> fail "Two patterns not specified in get_second_match."+    Just m -> if second_matcher_is_tag fs+              then get_tag r m+              else get_matcher r m+              +              +get_second_match_s :: RepoPatch p => [DarcsFlag] -> PatchSet p -> SlurpMonad ()+get_second_match_s fs repo =+    case second_matcher fs of+    Nothing -> fail "Two patterns not specified in get_second_match."+    Just m -> if second_matcher_is_tag fs+              then get_tag_s repo m+              else get_matcher_s repo m+              +checkMatchSyntax :: [DarcsFlag] -> IO ()+checkMatchSyntax opts = do+ case get_match_pattern opts of+  Nothing -> return ()+  Just p  -> either fail (const $ return ()) $ parseMatch p++get_match_pattern :: [DarcsFlag] -> Maybe PatchMatch+get_match_pattern [] = Nothing+get_match_pattern (OnePattern m:_) = Just m+get_match_pattern (SeveralPattern m:_) = Just m+get_match_pattern (_:fs) = get_match_pattern fs+\end{code}++\begin{code}+tagmatch :: String -> Matcher p+tagmatch r = make_matcher ("tag-name "++r) tm+    where tm p =+              let n = just_name (info p) in+              take 4 n == "TAG " && isJust (matchRegex (mkRegex r) $ drop 4 n)++mymatch :: String -> Matcher p+mymatch r = make_matcher ("patch-name "++r) mm+    where mm = isJust . matchRegex (mkRegex r) . just_name . info++-- | strictJust is a strict version of the Just constructor, used to ensure+-- that if we claim we've got a pattern match, that the pattern will+-- actually match (rathern than fail to compile properly).+strictJust :: a -> Maybe a+strictJust x = Just $! x++nonrange_matcher :: [DarcsFlag] -> Maybe (Matcher p)+nonrange_matcher [] = Nothing+nonrange_matcher (OnePattern m:_) = strictJust $ match_pattern m+nonrange_matcher (OneTag t:_) = strictJust $ tagmatch t+nonrange_matcher (OnePatch p:_) = strictJust $ mymatch p+nonrange_matcher (SeveralPattern m:_) = strictJust $ match_pattern m+nonrange_matcher (SeveralPatch p:_) = strictJust $ mymatch p+nonrange_matcher (_:fs) = nonrange_matcher fs++nonrange_matcher_is_tag :: [DarcsFlag] -> Bool+nonrange_matcher_is_tag [] = False+nonrange_matcher_is_tag (OneTag _:_) = True+nonrange_matcher_is_tag (_:fs) = nonrange_matcher_is_tag fs++first_matcher :: [DarcsFlag] -> Maybe (Matcher p)+first_matcher [] = Nothing+first_matcher (OnePattern m:_) = strictJust $ match_pattern m+first_matcher (AfterPattern m:_) = strictJust $ match_pattern m+first_matcher (AfterTag t:_) = strictJust $ tagmatch t+first_matcher (OnePatch p:_) = strictJust $ mymatch p+first_matcher (AfterPatch p:_) = strictJust $ mymatch p+first_matcher (_:fs) = first_matcher fs++first_matcher_is_tag :: [DarcsFlag] -> Bool+first_matcher_is_tag [] = False+first_matcher_is_tag (AfterTag _:_) = True+first_matcher_is_tag (_:fs) = first_matcher_is_tag fs++second_matcher :: [DarcsFlag] -> Maybe (Matcher p)+second_matcher [] = Nothing+second_matcher (OnePattern m:_) = strictJust $ match_pattern m+second_matcher (UpToPattern m:_) = strictJust $ match_pattern m+second_matcher (OnePatch p:_) = strictJust $ mymatch p+second_matcher (UpToPatch p:_) = strictJust $ mymatch p+second_matcher (UpToTag t:_) = strictJust $ tagmatch t+second_matcher (_:fs) = second_matcher fs++second_matcher_is_tag :: [DarcsFlag] -> Bool+second_matcher_is_tag [] = False+second_matcher_is_tag (UpToTag _:_) = True+second_matcher_is_tag (_:fs) = second_matcher_is_tag fs+\end{code}++\begin{code}+doesnt_not_match :: [DarcsFlag] -> PatchInfoAnd p -> Bool+doesnt_not_match fs =+    case nonrange_matcher fs of+    Nothing -> \_ -> True+    Just m -> apply_matcher m++match_a_patchread :: [DarcsFlag] -> PatchInfoAnd p -> Bool+match_a_patchread fs = case nonrange_matcher fs of+                       Nothing -> const True+                       Just m -> apply_matcher m++match_a_patch :: [DarcsFlag] -> Named p -> Bool+match_a_patch fs p =+    case nonrange_matcher fs of+    Nothing -> True+    Just m -> apply_matcher m (patch2patchinfo p `piap` p)++match_patch :: RepoPatch p => [DarcsFlag] -> PatchSet p -> Named p+match_patch fs ps = case nonrange_matcher fs of+                    Nothing -> bug "Couldn't match_patch"+                    Just m -> find_a_patch m ps++get_one_patchset :: RepoPatch p => Repository p -> [DarcsFlag] -> IO (PatchSet p)+get_one_patchset repository fs =+    case nonrange_matcher fs of+        Just m -> do Sealed ps <- read_repo repository+                     if nonrange_matcher_is_tag fs+                        then return $ get_matching_tag m ps+                        else return $ match_a_patchset m ps+        Nothing -> scan_context `liftM` mmapFilePS (context_f fs)+    where context_f [] = bug "Couldn't match_nonrange_patchset"+          context_f (Context f:_) = f+          context_f (_:xs) = context_f xs++has_lastn :: [DarcsFlag] -> Maybe Int+has_lastn [] = Nothing+has_lastn (LastN (-1):_) = error "--last requires a positive integer argument."+has_lastn (LastN n:_) = Just n+has_lastn (_:fs) = has_lastn fs++match_first_patchset :: RepoPatch p => [DarcsFlag] -> PatchSet p -> PatchSet p+match_first_patchset fs patchset =+    case has_lastn fs of+    Just n -> dropn n patchset+    Nothing -> case first_matcher fs of+               Nothing -> bug "Couldn't match_first_patchset"+               Just m -> dropn 1 $ if first_matcher_is_tag fs+                                   then get_matching_tag m patchset+                                   else match_a_patchset m patchset+    where dropn :: Int -> PatchSet p -> PatchSet p+          dropn n (NilRL:<:ps) = dropn n ps+          dropn 0 ps = ps+          dropn _ NilRL = NilRL:<:NilRL+          dropn n ((_:<:ps):<:xs) = dropn (n-1) $ ps:<:xs++match_second_patchset :: RepoPatch p => [DarcsFlag] -> PatchSet p -> PatchSet p+match_second_patchset fs ps =+    case second_matcher fs of+    Nothing -> bug "Couldn't match_second_patchset"+    Just m -> if second_matcher_is_tag fs+              then get_matching_tag m ps+              else match_a_patchset m ps++find_a_patch :: RepoPatch p => Matcher p -> PatchSet p -> Named p+find_a_patch m NilRL = error $ "Couldn't find patch matching " ++ show m+find_a_patch m (NilRL:<:xs) = find_a_patch m xs+find_a_patch m ((p:<:ps):<:xs) | apply_matcher m $ p = hopefully p+                               | otherwise = find_a_patch m (ps:<:xs)++match_a_patchset :: RepoPatch p => Matcher p -> PatchSet p -> PatchSet p+match_a_patchset m NilRL = error $ "Couldn't find patch matching " ++ show m+match_a_patchset m (NilRL:<:xs) = match_a_patchset m xs+match_a_patchset m ((p:<:ps):<:xs) | apply_matcher m $ p = ((p:<:ps):<:xs)+                                   | otherwise = match_a_patchset m (ps:<:xs)++get_matching_tag :: RepoPatch p => Matcher p -> PatchSet p -> PatchSet p+get_matching_tag m NilRL = error $ "Couldn't find a tag matching " ++ show m+get_matching_tag m (NilRL:<:xs) = get_matching_tag m xs+get_matching_tag m xxx@((p:<:ps):<:xs)+    | apply_matcher m $ p = unsafeUnseal $ get_patches_in_tag (info p) xxx+    | otherwise = get_matching_tag m (ps:<:xs)+\end{code}++\begin{code}+match_exists :: Matcher p -> PatchSet p -> Bool+match_exists _ NilRL = False+match_exists m (NilRL:<:xs) = match_exists m xs+match_exists m ((p:<:ps):<:xs) | apply_matcher m $ p = True+                               | otherwise = match_exists m (ps:<:xs)+\end{code}++\begin{code}+get_matcher :: RepoPatch p => Repository p -> Matcher p -> IO ()+get_matcher r m = do Sealed repo <- read_repo r+                     if match_exists m repo+                        then do createPristineDirectoryTree r "."+                                apply_inv_to_matcher m repo+                        else fail $ "Couldn't match pattern "++ show m++get_before_matcher :: RepoPatch p => Repository p -> Matcher p -> IO ()+get_before_matcher r m =+    do Sealed repo <- read_repo r+       if match_exists m repo+          then do createPristineDirectoryTree r "."+                  apply_inv_to_matcher_inclusive m repo+          else fail $ "Couldn't match pattern "++ show m++apply_inv_to_matcher_inclusive :: (RepoPatch p, WriteableDirectory m) => Matcher p -> PatchSet p -> m ()+apply_inv_to_matcher_inclusive _ NilRL = impossible+apply_inv_to_matcher_inclusive m (NilRL:<:xs) = apply_inv_to_matcher m xs+apply_inv_to_matcher_inclusive m ((p:<:ps):<:xs)+    | apply_matcher m p = apply_invp p+    | otherwise = apply_invp p >> apply_inv_to_matcher_inclusive m (ps:<:xs)++apply_inv_to_matcher :: (RepoPatch p, WriteableDirectory m) => Matcher p -> PatchSet p -> m ()+apply_inv_to_matcher _ NilRL = impossible+apply_inv_to_matcher m (NilRL:<:xs) = apply_inv_to_matcher m xs+apply_inv_to_matcher m ((p:<:ps):<:xs)+    | apply_matcher m p = return ()+    | otherwise = apply_invp p >> apply_inv_to_matcher m (ps:<:xs)+              +maybe_read_file :: FileName -> SlurpMonad ([(FileName, PackedString)])+maybe_read_file file = do+    d <- mDoesDirectoryExist file+    if d+      then do+        children <- mInCurrentDirectory file mGetDirectoryContents+        maybe_read_files [file /// ch | ch <-  children]+      else do+         e <- mDoesFileExist file+         if e+           then do+             contents <- mReadFilePS file+             return  [(norm_path file, contents)]+           else return []+  where maybe_read_files [] =  return []+        maybe_read_files (f:fs) = do+                      x <- maybe_read_file f+                      y <- maybe_read_files fs+                      return $ concat [x,y]++get_file_contents :: RepoPatch p => Repository p -> [FilePath] -> (PatchSet p -> SlurpMonad())+                  -> IO ([(FileName, PackedString)])+get_file_contents r files gf = do+    s <- slurp_recorded r+    Sealed repo <- read_repo r+    let SM slurpFunc = gf repo >>  mapM ( maybe_read_file . fp2fn) files+    case (slurpFunc $ Right s) of+      Left err -> fail err+      Right (_, ret) -> return $ concat ret+      +apply_patches_to_some_files :: RepoPatch p => Repository p -> [FilePath]+                            -> (PatchSet p -> SlurpMonad()) -> IO ()+apply_patches_to_some_files r files gf = do+    fcs <- get_file_contents r files gf+    writeFiles fcs+  where writeFiles [] = return ()+        writeFiles ((p, c):xs) = (ensureDirectories $ super_name p) >> ( mWriteFilePS p c) >> writeFiles xs+        ensureDirectories d = do+          isPar <- mDoesDirectoryExist d+          if isPar +            then return ()+            else ensureDirectories (super_name d) >> (mCreateDirectory d)                 +              +get_matcher_s :: RepoPatch p => PatchSet p -> Matcher p -> SlurpMonad ()+get_matcher_s repo m = +                     if match_exists m repo+                        then apply_inv_to_matcher m repo+                        else fail $ "Couldn't match pattern "++ show m+              +get_before_matcher_s :: RepoPatch p => PatchSet p -> Matcher p -> SlurpMonad ()+get_before_matcher_s repo m = +                     if match_exists m repo+                        then apply_inv_to_matcher_inclusive m repo+                        else fail $ "Couldn't match pattern "++ show m+              +get_dropn_s :: RepoPatch p => PatchSet p -> Int -> SlurpMonad ()+get_dropn_s repo n = applyInvRL $ safetake n $ concatRL repo++get_tag_s :: RepoPatch p => PatchSet p -> Matcher p -> SlurpMonad ()+get_tag_s repo match = do+    let pinfo = patch2patchinfo $ find_a_patch match repo+    case get_patches_beyond_tag pinfo repo of+        FlippedSeal (extras:<:NilRL) -> applyInvRL $ extras+        _ -> impossible++applyInvRL :: (Patchy p, WriteableDirectory m) => RL (PatchInfoAnd p) -> m ()+applyInvRL NilRL = return ()+applyInvRL (p:<:ps) = apply_invp p >> applyInvRL ps++apply_invp :: (Patchy p, WriteableDirectory m) => PatchInfoAnd p -> m ()+apply_invp hp = apply [] (invert $ fromHopefully hp)+    where fromHopefully = conscientiously $ \e ->+                     text "Sorry, partial repository problem.  Patch not available:"+                     $$ e+                     $$ text ""+                     $$ text "If you think what you're trying to do is ok then"+                     $$ text "report this as a bug on the darcs-user list."++get_dropn :: RepoPatch p => Repository p -> Int -> IO ()+get_dropn r n = do createPristineDirectoryTree r "."+                   read_repo r `unsealM` (apply_patches [] . invertRL . safetake n . concatRL)++safetake :: Int -> RL a -> RL a+safetake 0 _ = NilRL+safetake _ NilRL = error "There aren't that many patches..."+safetake i (a:<:as) = a :<: safetake (i-1) as++\end{code}++\begin{code}+get_tag :: RepoPatch p => Repository p -> Matcher p -> IO ()+get_tag r match = do+    Sealed ps <- read_repo r+    let pinfo = patch2patchinfo $ find_a_patch match ps+    case get_patches_beyond_tag pinfo ps of+        FlippedSeal (extras:<:NilRL) -> do createPristineDirectoryTree r "."+                                           apply_patches [] $ invertRL extras+        _ -> impossible+\end{code}
+ src/Darcs/Patch.lhs view
@@ -0,0 +1,151 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\chapter{Theory of patches}+\label{Patch}++\newtheorem{thm}{Theorem}+\newtheorem{dfn}{Definition}++\section{Background}++I think a little background on the author is in order.  I am a physicist,+and think like a physicist.  The proofs and theorems given here are what I+would call ``physicist'' proofs and theorems, which is to say that while+the proofs may not be rigorous, they are practical, and the theorems are+intended to give physical insight.  It would be great to have a+mathematician work on this, but I am not a mathematician, and don't care+for math.++From the beginning of this theory, which originated as the result of a+series of email discussions with Tom Lord, I have looked at patches as+being analogous to the operators of quantum mechanics.  I include in this+appendix footnotes explaining the theory of patches in terms of the theory+of quantum mechanics.  I know that for most people this won't help at all,+but many of my friends (and as I write this all three of darcs' users) are+physicists, and this will be helpful to them.  To non-physicists, perhaps it+will provide some insight into how at least this physicist thinks.++\begin{code}+{-# OPTIONS_GHC -cpp -fno-warn-orphans #-}+#include "gadts.h"+module Darcs.Patch ( RepoPatch, Prim, Patch, RealPatch, Named, Patchy,+                     flattenFL, joinPatches,+                     fromPrim, fromPrims,+               is_null_patch, nullP,+               rmfile, addfile, rmdir, adddir, move,+               hunk, tokreplace, namepatch, anonymous,+               binary,+               description,+               showContextPatch, showPatch, showNicely,+               infopatch, changepref,+               thing, things,+               is_similar, is_addfile, is_addrmfile, is_hunk, is_setpref,+#ifndef GADT_WITNESSES+               merger, is_merger, merge,+               commute, commutex, list_touched_files,+               -- for PatchTest+               unravel, elegant_merge,+#else+               Commute(..),+#endif+               resolve_conflicts,+               Effect, effect,+               is_binary, gzWritePatch, writePatch, is_adddir, is_addrmdir,+               invert, invertFL, invertRL, identity,+               commuteFL, commuteRL,+               readPatch,+               canonize, sort_coalesceFL,+               try_to_shrink,+               apply_to_slurpy, patchname, patchcontents,+               apply_to_filepaths, force_replace_slurpy, apply,+               patch2patchinfo,+               LineMark(AddedLine, RemovedLine, AddedRemovedLine, None),+               MarkedUpFile, markup_file, empty_markedup_file,+               summary, summarize, xml_summary,+               adddeps, getdeps,+               list_conflicted_files,+               modernize_patch,+               -- for Population+               DirMark(..), patchChanges, applyToPop,+             ) where+import Darcs.PopulationData ( DirMark(..) )+import Darcs.Patch.Core ( Patch, Named,+                          flattenFL,+                          adddeps, namepatch,+                          anonymous,+#ifndef GADT_WITNESSES+                          is_merger,+#endif+                          getdeps,+                          is_null_patch, nullP, infopatch,+                          patch2patchinfo, patchname, patchcontents )+import Darcs.Patch.Read ( readPatch )+import Darcs.Patch.Patchy ( Patchy, writePatch, gzWritePatch,+                            showPatch, showNicely, showContextPatch,+                            invert, invertRL, invertFL, identity,+                            thing, things,+                            commuteFL, commuteRL, apply,+                            description, summary,+#ifndef GADT_WITNESSES+                            commute, commutex, list_touched_files,+#else+                            Commute(..)+#endif+                          )+import Darcs.Patch.Viewing ( xml_summary, summarize )+import Darcs.Patch.Apply ( applyToPop, patchChanges, empty_markedup_file,+                           markup_file, force_replace_slurpy,+                           apply_to_filepaths, apply_to_slurpy,+                           LineMark(..), MarkedUpFile )+import Darcs.Patch.Commute ( modernize_patch,+#ifndef GADT_WITNESSES+                             unravel,+                             merger, merge, elegant_merge,+#endif+                            )+import Darcs.Patch.Prim ( FromPrims, fromPrims, joinPatches, FromPrim, fromPrim,+                          Conflict, Effect(effect), list_conflicted_files, resolve_conflicts,+                          Prim, canonize,+                          sort_coalesceFL,+                          rmdir, rmfile, tokreplace, adddir, addfile,+                          binary, changepref, hunk, move, +                          is_adddir, is_addrmdir, is_addfile, is_addrmfile,+                          is_hunk, is_binary, is_setpref,+                          is_similar,+                          try_to_shrink )+import Darcs.Patch.Ordered ( FL )+import Darcs.Patch.Real ( RealPatch )++instance Patchy Patch+instance (Conflict p, Effect p, Patchy p) => Patchy (Named p)++class (Patchy p, Effect p, FromPrim p, Conflict p) => RepoPatchBase p+instance RepoPatchBase Patch+instance RepoPatchBase RealPatch++class (Patchy p, Effect p, FromPrims p, Conflict p) => RepoPatch p+instance RepoPatch Patch+instance RepoPatchBase p => RepoPatch (FL p)++\end{code}++\input{Darcs/Patch/Apply.lhs}+\input{Darcs/Patch/Core.lhs}+\input{Darcs/Patch/Commute.lhs}+\input{Darcs/Patch/Show.lhs}+
+ src/Darcs/Patch/Apply.lhs view
@@ -0,0 +1,526 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans #-}+#include "gadts.h"+module Darcs.Patch.Apply ( apply_to_filepaths, apply_to_slurpy,+                           forceTokReplace,+                           markup_file, empty_markedup_file,+                           patchChanges,+                           applyToPop,+                           LineMark(..), MarkedUpFile,+                           force_replace_slurpy,+                           -- to cut later:+                           applyBinary )+    where++import Prelude hiding ( catch, pi )+import Darcs.Flags ( DarcsFlag( SetScriptsExecutable ) )+import FastPackedString ( PackedString, packString, splitPS, concatPS,+                          breakPS, nullPS, nilPS, linesPS, takePS,+                          unlinesPS,+                          break_after_nth_newline,+                          break_before_nth_newline, )+import FileName ( fn2ps, fn2fp, fp2fn,+                  movedirfilename )+import Darcs.PopulationData ( Population(..), PopTree(..), Info(..), DirMark(..) )+import Data.List ( intersperse )+import Data.Maybe ( catMaybes )+import Darcs.Patch.Patchy ( Apply, apply, applyAndTryToFixFL, applyAndTryToFix,+                            mapMaybeSnd )+import Darcs.Patch.Commute ()+import Darcs.Patch.Core ( Patch(..), Named(..) )+import Darcs.Patch.Prim ( Prim(..), Effect(effect),+                          DirPatchType(..), FilePatchType(..),+                          applyBinary, try_tok_internal )+import Darcs.Patch.Info ( PatchInfo )+import Control.Monad ( when, liftM )+import Darcs.SlurpDirectory ( FileContents, Slurpy, withSlurpy, slurp_modfile )+import RegChars ( regChars )+import Darcs.Repository.Prefs ( change_prefval )+import Darcs.Global ( darcsdir )+import Darcs.IO ( WriteableDirectory(..), ReadableDirectory(..) )+import Darcs.FilePathMonad ( withFilePaths )+#include "impossible.h"+import Darcs.Patch.Ordered ( FL(..), (:>)(..),+                             mapFL, mapFL_FL, spanFL, foldlFL )+\end{code}++++\section{Introduction}++A patch describes a change to the tree.  It could be either a primitive+patch (such as a file add/remove, a directory rename, or a hunk replacement+within a file), or a composite patch describing many such changes.  Every+patch type must satisfy the conditions described in this appendix.  The+theory of patches is independent of the data which the patches manipulate,+which is what makes it both powerful and useful, as it provides a framework+upon which one can build a revision control system in a sane manner.++Although in a sense, the defining property of any patch is that it can be+applied to a certain tree, and thus make a certain change, this change does+not wholly define the patch.  A patch is defined by a+\emph{representation}, together with a set of rules for how it behaves+(which it has in common with its patch type).  The \emph{representation} of+a patch defines what change that particular patch makes, and must be+defined in the context of a specific tree.  The theory of patches is a+theory of the many ways one can change the representation of a patch to+place it in the context of a different tree.  The patch itself is not+changed, since it describes a single change, which must be the same+regardless of its representation\footnote{For those comfortable with+quantum mechanics, think of a patch as a quantum mechanical operator, and+the representation as the basis set.  The analogy breaks down pretty+quickly, however, since an operator could be described in any complete+basis set, while a patch modifying the file {\tt foo} can only be described+in the rather small set of contexts which have a file {\tt foo} to be+modified.}.++So how does one define a tree, or the context of a patch? The simplest way+to define a tree is as the result of a series of patches applied to the+empty tree\footnote{This is very similar to the second-quantized picture,+in which any state is seen as the result of a number of creation operators+acting on the vacuum, and provides a similar set of simplifications---in+particular, the exclusion principle is very elegantly enforced by the+properties of the anti-hermitian fermion creation operators.}.  Thus, the+context of a patch consists of the set of patches that precede it.++\section{Applying patches}+++\begin{code}+apply_to_filepaths :: Apply p => p C(x y) -> [FilePath] -> [FilePath]+apply_to_filepaths pa fs = withFilePaths fs (apply [] pa)++apply_to_slurpy :: (Apply p, Monad m) => p C(x y) -> Slurpy -> m Slurpy+apply_to_slurpy p s = case withSlurpy s (apply [] p) of+                          Left err -> fail err+                          Right (s', ()) -> return s'+\end{code}++\begin{code}+instance Apply p => Apply (Named p) where+    apply opts (NamedP _ _ p) = apply opts p+    applyAndTryToFix (NamedP n d p) = mapMaybeSnd (NamedP n d) `liftM` applyAndTryToFix p++instance Apply Patch where+    apply opts p = applyFL opts $ effect p+    applyAndTryToFixFL (PP x) = mapMaybeSnd (mapFL_FL PP) `liftM` applyAndTryToFixFL x+    applyAndTryToFixFL (ComP xs) = mapMaybeSnd (\xs' -> ComP xs' :>: NilFL) `liftM` applyAndTryToFix xs+    applyAndTryToFixFL x = do apply [] x; return Nothing+    applyAndTryToFix (ComP xs) = mapMaybeSnd ComP `liftM` applyAndTryToFix xs+    applyAndTryToFix x = do mapMaybeSnd ComP `liftM` applyAndTryToFixFL x+\end{code}++\begin{code}+force_replace_slurpy :: Prim C(x y) -> Slurpy -> Maybe Slurpy+force_replace_slurpy (FP f (TokReplace tcs old new)) s =+    slurp_modfile f (forceTokReplace tcs old new) s+force_replace_slurpy _ _ = bug "Can only force_replace_slurpy on a replace."+\end{code}++\begin{code}+instance Apply Prim where+    apply opts (Split ps) = applyFL opts ps+    apply _ Identity = return ()+    apply _ (FP f RmFile) = mRemoveFile f+    apply _ (FP f AddFile) = mCreateFile f+    apply opts p@(FP _ (Hunk _ _ _)) = applyFL opts (p :>: NilFL)+    apply _ (FP f (TokReplace t o n)) = mModifyFilePSs f doreplace+        where doreplace ls =+                  case mapM (try_tok_internal t (packString o) (packString n)) ls of+                  Nothing -> fail $ "replace patch to " ++ fn2fp f+                             ++ " couldn't apply."+                  Just ls' -> return $ map concatPS ls'+    apply _ (FP f (Binary o n)) = mModifyFilePS f doapply+        where doapply oldf = if o == oldf+                             then return n+                             else fail $ "binary patch to " ++ fn2fp f+                                  ++ " couldn't apply."+    apply _ (DP d AddDir) = mCreateDirectory d+    apply _ (DP d RmDir) = mRemoveDirectory d+    apply _ (Move f f') = mRename f f'+    apply _ (ChangePref p f t) =+        do b <- mDoesDirectoryExist (fp2fn $ darcsdir++"/prefs")+           when b $ change_prefval p f t+    applyAndTryToFixFL (FP f RmFile) =+        do x <- mReadFilePS f+           if nullPS x then do mRemoveFile f+                               return Nothing+                       else do mWriteFilePS f nilPS+                               mRemoveFile f+                               return $ Just ("WARNING: Fixing removal of non-empty file "++fn2fp f,+                                              FP f (Binary x nilPS) :>: FP f RmFile :>: NilFL )+    applyAndTryToFixFL p = do apply [] p; return Nothing++applyFL :: WriteableDirectory m => [DarcsFlag] -> FL Prim C(x y) -> m ()+applyFL _ NilFL = return ()+applyFL opts ((FP f h@(Hunk _ _ _)):>:the_ps)+ = case spanFL f_hunk the_ps of+       (xs :> ps') ->+           do let foo = h :>: mapFL_FL (\(FP _ h') -> h') xs+              mModifyFilePS f $ hunkmod foo+              case h of+                (Hunk 1 _ (n:_)) | takePS 2 n == packString "#!" &&+                                   SetScriptsExecutable `elem` opts+                                 -> mSetFileExecutable f True+                _ -> return ()+              applyFL opts ps'+    where f_hunk (FP f' (Hunk _ _ _)) | f == f' = True+          f_hunk _ = False+          hunkmod :: WriteableDirectory m => FL FilePatchType C(x y)+                  -> PackedString -> m PackedString+          hunkmod NilFL ps = return ps+          hunkmod (Hunk line old new:>:hs) ps+           = case applyHunkLines [(line,old,new)] ps of+                 Just ps' -> hunkmod hs ps'+                 Nothing -> fail $ "Error applying hunk to file " ++ fn2fp f+          hunkmod _ _ = impossible+applyFL opts (p:>:ps) = do apply opts p+                           applyFL opts ps+\end{code}++\subsection{Hunk patches}++Hunks are an example of a complex filepatch.  A hunk is a set of lines of a+text file to be replaced by a different set of lines.  Either of these sets+may be empty, which would mean a deletion or insertion of lines.+\begin{code}+applyHunks :: [(Int, [PackedString], [PackedString])]+           -> PackedString -> Maybe [PackedString]+applyHunks [] ps = Just [ps]+applyHunks ((l, [], n):hs) ps+    = case break_before_nth_newline (l - 2) ps of+      (prfix, after_prefix) -> do rest <- applyHunks hs after_prefix+                                  return $ intersperse nl (prfix:n) ++ rest+                                       where nl = packString "\n"+applyHunks ((l, o, n):hs) ps+    = case break_before_nth_newline (l - 2) ps of+      (prfix, after_prefix) ->+          case break_before_nth_newline (length o) after_prefix of+          (oo, _) | oo /= unlinesPS (nilPS:o) -> fail "applyHunks error"+          (_, suffix) ->+              do rest <- applyHunks hs suffix+                 return $ intersperse nl (prfix:n) ++ rest+    where nl = packString "\n"++applyHunkLines :: [(Int, [PackedString], [PackedString])]+               -> FileContents -> Maybe FileContents+applyHunkLines [] c = Just c+applyHunkLines [(1, [], n)] ps | nullPS ps = Just $ unlinesPS (n++[nilPS])+applyHunkLines hs@((l, o, n):hs') ps =+ do pss <- case l of+           1 -> case break_after_nth_newline (length o) ps of+                Nothing -> if ps == unlinesPS o+                           then return $ intersperse nl n+                           else fail "applyHunkLines: Unexpected hunks"+                Just (shouldbeo, suffix)+                    | shouldbeo /= unlinesPS (o++[nilPS]) ->+                        fail $ "applyHunkLines: Bad patch!"+                    | null n ->+                        do x <- applyHunkLines hs' suffix+                           return [x]+                    | otherwise ->+                        do rest <- applyHunks hs' suffix+                           return $ intersperse nl n ++ nl:rest+           _ | l < 0 -> bug "Prim.applyHunkLines: After -ve lines?"+             | otherwise -> applyHunks hs ps+    let result = concatPS pss+    return result+    where nl = packString "\n"+\end{code}++\subsection{Token replace patches}\label{token_replace}++Although most filepatches will be hunks, darcs is clever enough to support+other types of changes as well.  A ``token replace'' patch replaces all+instances of a given token with some other version.  A token, here, is+defined by a regular expression, which must be of the simple [a--z\ldots]\ type,+indicating which characters are allowed in a token, with all other+characters acting as delimiters.  For example, a C identifier would be a+token with the flag \verb![A-Za-z_0-9]!.++\begin{code}+forceTokReplace :: String -> String -> String+                -> FileContents -> Maybe FileContents+forceTokReplace t os ns c = Just $ unlinesPS $ map forceReplace $ linesPS c+    where o = packString os+          n = packString ns+          tokchar = regChars t+          toks_and_intratoks ps | nullPS ps = []+          toks_and_intratoks ps =+              let (before,s') = breakPS tokchar ps+                  (tok, after) = breakPS (not . tokchar) s'+                  in before : tok : toks_and_intratoks after+          forceReplace ps = concatPS $ map o_t_n $ toks_and_intratoks ps+          o_t_n s | s == o = n+                  | otherwise = s+\end{code}++What makes the token replace patch special is the fact that a token replace+can be merged with almost any ordinary hunk, giving exactly what you would+want.  For example, you might want to change the patch type {\tt+TokReplace} to {\tt TokenReplace} (if you decided that saving two+characters of space was stupid).  If you did this using hunks, it would+modify every line where {\tt TokReplace} occurred, and quite likely provoke+a conflict with another patch modifying those lines.  On the other hand, if+you did this using a token replace patch, the only change that it could+conflict with would be if someone else had used the token ``{\tt+TokenReplace}'' in their patch rather than TokReplace---and that actually+would be a real conflict!++%\section{Outputting interesting and useful information}++%Just being able to manipulate patches and trees is not enough.  We also+%want to be able to view the patches and files.  This requires another set+%of functions, closely related to the patch application functions, which+%will give us the necessary information to browse the changes we have made.+%It is \emph{not} the Patch module's responsibility to add any sort of+%markup or formatting, but simply to provide the information necessary for an+%external module to do the formatting.++\begin{code}+data LineMark = AddedLine PatchInfo | RemovedLine PatchInfo+              | AddedRemovedLine PatchInfo PatchInfo | None+                deriving (Show)+type MarkedUpFile = [(PackedString, LineMark)]+empty_markedup_file :: MarkedUpFile+empty_markedup_file = [(nilPS, None)]++markup_file :: Effect p => PatchInfo -> p C(x y)+            -> (FilePath, MarkedUpFile) -> (FilePath, MarkedUpFile)+markup_file x p = mps (effect p)+    where mps :: FL Prim C(a b) -> (FilePath, MarkedUpFile) -> (FilePath, MarkedUpFile)+          mps NilFL = id+          mps (pp:>:pps) = mps pps . markup_prim x pp++markup_prim :: PatchInfo -> Prim C(x y)+            -> (FilePath, MarkedUpFile) -> (FilePath, MarkedUpFile)+markup_prim _ (Split NilFL) (f, mk) = (f, mk)+markup_prim n (Split (p:>:ps)) (f, mk) = markup_prim n (Split ps) $+                                       markup_prim n p (f, mk)+markup_prim _ (FP _ AddFile) (f, mk) = (f, mk)+markup_prim _ (FP _ RmFile) (f, mk) = (f, mk)+markup_prim n (FP f' (Hunk line old new)) (f, mk)+    | fn2fp f' /= f = (f, mk)+    | otherwise = (f, markup_hunk n line old new mk)+markup_prim name (FP f' (TokReplace t o n)) (f, mk)+    | fn2fp f' /= f = (f, mk)+    | otherwise = (f, markup_tok name t o n mk)+markup_prim _ (DP _ _) (f, mk) = (f, mk)+markup_prim _ (Move d d') (f, mk) = (fn2fp $ movedirfilename d d' (fp2fn f), mk)+markup_prim _ (ChangePref _ _ _) (f,mk) = (f,mk)+markup_prim _ Identity (f,mk) = (f,mk)+markup_prim n (FP f' (Binary _ _)) (f,mk)+    | fn2fp f' == f = (f,(packString "Binary file", AddedLine n):mk)+    | otherwise = (f,mk)++markup_hunk :: PatchInfo -> Int -> [PackedString] -> [PackedString]+            -> MarkedUpFile -> MarkedUpFile+markup_hunk n l old new ((sf, RemovedLine pi):mk) =+    (sf, RemovedLine pi) : markup_hunk n l old new mk+markup_hunk n l old new ((sf, AddedRemovedLine po pn):mk) =+    (sf, AddedRemovedLine po pn) : markup_hunk n l old new mk++markup_hunk name 1 old (n:ns) mk =+    (n, AddedLine name) : markup_hunk name 1 old ns mk+markup_hunk n 1 (o:os) [] ((sf, None):mk)+    | o == sf = (sf, RemovedLine n) : markup_hunk n 1 os [] mk+    | otherwise = [(packString "Error in patch application", AddedLine n)]+markup_hunk n 1 (o:os) [] ((sf, AddedLine nold):mk)+    | o == sf = (sf, AddedRemovedLine nold n) : markup_hunk n 1 os [] mk+    | otherwise = [(packString "Error in patch application", AddedLine n)]+markup_hunk _ 1 [] [] mk = mk++markup_hunk n l old new ((sf, AddedLine pi):mk)+    | l > 1 = (sf, AddedLine pi) : markup_hunk n (l-1) old new mk+    | l < 1 = (sf, AddedLine pi) : markup_hunk n (l-1) old new mk+markup_hunk n l old new ((sf, None):mk)+    | l > 1 = (sf, None) : markup_hunk n (l-1) old new mk+    | l < 1 = (sf, None) : markup_hunk n (l-1) old new mk++markup_hunk _ _ _ _ [] = []++markup_hunk _ _ _ _ mk = (packString "Error: ",None) : mk++markup_tok :: PatchInfo -> String -> String -> String+           -> MarkedUpFile -> MarkedUpFile+markup_tok name t ostr nstr mk = concatMap mt mk+    where o = packString ostr+          n = packString nstr+          mt (sf, AddedLine pi) =+              case concatPS `fmap` try_tok_internal t o n sf of+              Just sf' | sf' == sf -> [(sf, AddedLine pi)]+                       | otherwise -> [(sf, AddedRemovedLine pi name),+                                       (sf', AddedLine name)]+              Nothing ->+                  [(sf, AddedLine pi),+                   (packString "There seems to be an inconsistency...", None),+                   (packString "Please run darcs check.", None)]+          mt mark = [mark]+\end{code}++%files or directories, changed by a patch+%we get it solely from the patch here+%instead of performing patch apply on a population+%we !could! achieve the same by applying a patch to a cleaned population+%and getting modified files and dirs+%but this should be significantly slower when the population grows large+%This could be useful for just presenting a summary of what a patch does+%(especially useful for larger repos)++\begin{code}+patchChanges :: Prim C(x y) -> [(String,DirMark)]+patchChanges (Move f1 f2) = [(fn2fp f1,MovedFile $ fn2fp f2),+                             (fn2fp f2,MovedFile $ fn2fp f1)]+patchChanges (DP d AddDir) = [(fn2fp d,AddedDir)]+patchChanges (DP d RmDir) = [(fn2fp d,RemovedDir)]+patchChanges (FP f AddFile) = [(fn2fp f,AddedFile)]+patchChanges (FP f RmFile) = [(fn2fp f,RemovedFile)]+patchChanges (FP f _) = [(fn2fp f,ModifiedFile)]+patchChanges (Split ps) = concat $ mapFL patchChanges ps+patchChanges (ChangePref _ _ _) = []+patchChanges Identity = []+\end{code}++%apply a patch to a population at a given time++\begin{code}+applyToPop :: PatchInfo -> FL Prim C(x y) -> Population -> Population+applyToPop _ NilFL = id+applyToPop pinf (p:>:ps) = applyToPop pinf ps . applyToPop' pinf p ++applyToPop'+    :: PatchInfo -> Prim C(x y) -> Population -> Population+applyToPop' pi patch (Pop _ tree)+ = Pop pi (applyToPopTree patch tree)+   -- ``pi'' is global below!+ where applyToPopTree :: Prim C(x y) -> PopTree -> PopTree+       applyToPopTree (Split ps) tr =+        foldlFL (\t p -> applyToPopTree p t) tr ps+       applyToPopTree p@(FP f AddFile) tr =+           let xxx = splitPS '/' (fn2ps  f) in+               popChange xxx p $ fst $ breakP xxx tr+       applyToPopTree p@(FP f _) tr = popChange (splitPS '/' (fn2ps  f)) p tr+       applyToPopTree p@(DP f AddDir) tr =+           let xxx = splitPS '/' (fn2ps  f) in+               popChange xxx p $ fst $ breakP xxx tr+       applyToPopTree p@(DP d _) tr = popChange (splitPS '/' (fn2ps  d)) p tr+       -- precondition: ``to'' does not exist yet!+       applyToPopTree (Move from to) tr+        = case breakP (splitPS '/' (fn2ps from)) $+               fst $ breakP (splitPS '/' $ fn2ps to) tr of+           (tr',Just ins) ->+               let to' = (splitPS '/' (fn2ps to))+                   ins' = case ins of+                          PopDir i trs -> PopDir (i {nameI = last to',+                                                     modifiedByI = pi,+                                                     modifiedHowI = MovedDir (fn2fp from)})+                                                 trs+                          PopFile i -> PopFile (i {nameI = last to',+                                                   modifiedByI = pi,+                                                   modifiedHowI = MovedFile (fn2fp from)})+                             in insertP to' tr' ins'+           _ -> tr -- ignore the move if ``from'' couldn't be found+       applyToPopTree (ChangePref _ _ _) tr = tr+       applyToPopTree Identity tr = tr++       -- insert snd arg into fst arg+       insertP :: [PackedString] -> PopTree -> PopTree -> PopTree+       insertP [parent,_] org@(PopDir f trs) tr+        | parent == (nameI f) = PopDir f (tr:trs)+        | otherwise = org+       insertP (n:rest) org@(PopDir f trs) tr+        | (nameI f) == n = PopDir f trs'+        | otherwise = org+          where trs' = map (\o -> insertP rest o tr) trs+       insertP _ org _ = org++       -- change a population according to a patch+       popChange :: [PackedString] -> Prim C(x y) -> PopTree -> PopTree+       popChange [parent,path] (DP d AddDir) tr@(PopDir f trs)+        | parent == (nameI f) = PopDir f (new:trs)+        | otherwise = tr+              where new = PopDir (Info {nameI = path,+                                        modifiedByI = pi,+                                        modifiedHowI = AddedDir,+                                        createdByI = Just pi,+                                        creationNameI = Just $ fn2ps d}) []+       -- only mark a directory (and contents) as ``deleted'' do not delete it actually+       popChange [path] (DP _ RmDir) tr@(PopDir f trs)+        | path == (nameI f) = PopDir (f {modifiedByI = pi,+                                         modifiedHowI = RemovedDir}) trs'+        | otherwise = tr+          where trs' = map markDel trs -- recursively ``delete'' the contents++       popChange [parent,path] (FP d AddFile) tr@(PopDir f trs)+        | parent == (nameI f) = PopDir f (new:trs)+        | otherwise = tr+              where new = PopFile (Info {nameI = path,+                                         modifiedByI = pi,+                                         modifiedHowI = AddedFile,+                                         createdByI = Just pi,+                                         creationNameI = Just $ fn2ps d})+       popChange [path] (FP _ RmFile) tr@(PopFile f)+        | path == (nameI f) = PopFile (f {modifiedByI = pi,+                                         modifiedHowI = RemovedFile})+        | otherwise = tr+       popChange [path] (FP _ _) (PopFile f)+        | path == (nameI f)+           = PopFile (f {modifiedByI = pi,+                         modifiedHowI = if modifiedHowI f == AddedFile && modifiedByI f == pi+                                        then AddedFile+                                        else ModifiedFile})+       popChange (n:rest) p tr@(PopDir f trs)+        | (nameI f) == n = PopDir f (map (popChange rest p) trs)+        | otherwise = tr+       popChange _ _ tr = tr+       markDel (PopDir f trs) = PopDir (f {modifiedByI = pi,+                                           modifiedHowI = RemovedDir}) trs'+                where trs' = map markDel trs+       markDel (PopFile f) = PopFile (f {modifiedByI = pi,+                                         modifiedHowI = RemovedFile})++-- break a poptree fst: org tree with subtree removed,+--                 snd: removed subtree+breakP :: [PackedString] -> PopTree -> (PopTree,Maybe PopTree)+breakP [parent,path] tr@(PopDir f trees)+ | parent == (nameI f) = case findRem path trees of+                         Just (trees',tree') -> (PopDir f trees',Just tree')+                         _ -> (tr,Nothing)+ | otherwise = (tr,Nothing)+ where findRem _ [] = Nothing+       findRem the_path (d:trs)+        | the_path == pname d = Just (trs,d)+        | otherwise = do (trs',d') <- findRem the_path trs+                         return (d:trs',d')+breakP (n:rest) tr@(PopDir f trs)+ | (nameI f) == n = case catMaybes inss of+                    [ins] -> (PopDir f trs', Just ins)+                    [] -> (tr,Nothing)+                    _ -> error "breakP: more than one break"+ | otherwise = (tr,Nothing)+   where (trs',inss) = unzip (map (breakP rest) trs)+breakP _ tr = (tr,Nothing)++pname :: PopTree -> PackedString+pname (PopDir i _) = nameI i+pname (PopFile i) = nameI i+\end{code}+
+ src/Darcs/Patch/Bundle.lhs view
@@ -0,0 +1,191 @@+%  Copyright (C) 2002-2004,2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.Patch.Bundle ( hash_bundle, make_bundle, make_bundle2, scan_bundle,+                     make_context, scan_context,+                   ) where++import Darcs.Flags ( DarcsFlag( Unified ) )+import Darcs.Hopefully ( PatchInfoAnd, piap,+                         patchInfoAndPatch,+                         unavailable, hopefully )+import Darcs.Patch ( RepoPatch, Named, showPatch, showContextPatch, readPatch )+import Darcs.Patch.Info ( PatchInfo, readPatchInfo, showPatchInfo, human_friendly )+import Darcs.Patch.Set ( PatchSet, SealedPatchSet )+import Darcs.Patch.Ordered ( RL(..), FL(..), unsafeCoerceP,+                             reverseFL, (+<+), mapFL, mapFL_FL )+import Printer ( Doc, renderPS, newline, text, ($$),+                 (<>), vcat, vsep, renderString )+import Darcs.SlurpDirectory ( Slurpy )+import FastPackedString ( PackedString, unpackPS, packString,+                          lengthPS, takePS, dropPS, linesPS, unlinesPS,+                          dropWhitePS, takeWhilePS, dropWhilePS,+                          nullPS, substrPS,+                        )+import SHA1( sha1PS )+import Darcs.Sealed ( Sealed(Sealed), mapSeal )++hash_bundle :: RepoPatch p => [PatchInfo] -> FL (Named p) C(x y) -> String+hash_bundle _ to_be_sent = sha1PS $ renderPS+                         $ vcat (mapFL showPatch to_be_sent) <> newline++make_bundle :: RepoPatch p => [DarcsFlag] -> Slurpy -> [PatchInfo] -> FL (Named p) C(x y) -> Doc+make_bundle opts the_s common to_be_sent = make_bundle2 opts the_s common to_be_sent to_be_sent++-- | In make_bundle2, it is presumed that the two patch sequences are+-- identical, but that they may be lazily generated.  If two different+-- patch sequences are passed, a bundle with a mismatched hash will be+-- generated, which is not the end of the world, but isn't very useful+-- either.+make_bundle2 :: RepoPatch p => [DarcsFlag] -> Slurpy -> [PatchInfo]+             -> FL (Named p) C(x y) -> FL (Named p) C(x y) -> Doc+make_bundle2 opts the_s common to_be_sent to_be_sent2 =+    text ""+ $$ text "New patches:"+ $$ text ""+ $$ the_new+ $$ text ""+ $$ text "Context:"+ $$ text ""+ $$ (vcat $ map showPatchInfo common)+ $$ text "Patch bundle hash:"+ $$ text (hash_bundle common to_be_sent2)+ $$ text ""+      where the_new = if Unified `elem` opts+                      then showContextPatch the_s to_be_sent+                      else vsep $ mapFL showPatch to_be_sent+\end{code}++\begin{code}+scan_bundle :: RepoPatch p => PackedString -> Either String (SealedPatchSet p)+scan_bundle ps+  | nullPS ps = Left "Bad patch bundle!"+  | otherwise =+    case silly_lex ps of+    ("New patches:",rest) ->+        case get_patches rest of+        (Sealed patches, rest') ->+            case silly_lex rest' of+            ("Context:", rest'') ->+                case get_context rest'' of+                (cont,maybe_hash) ->+                    case substrPS (packString "Patch bundle hash:")+                         maybe_hash of+                    Just n ->+                        if hash_bundle cont (mapFL_FL hopefully patches)+                               == fst (silly_lex $ snd $ silly_lex $+                                       dropPS n maybe_hash)+                        then Right $ Sealed ((reverseFL patches +<+ unavailable_patches cont) :<: NilRL)+                        else Left $+                                 "Patch bundle failed hash!\n" +++                                 "This probably means that the patch has been "+++                                 "corrupted by a mailer.\n"+++                                 "The most likely culprit is CRLF newlines."+                    Nothing -> Right $ Sealed ((reverseFL patches +<+ unavailable_patches cont) :<: NilRL)+            (a,r) -> Left $ "Malformed patch bundle: '"++a++"' is not 'Context:'"+                     ++ "\n" ++ unpackPS r+    ("Context:",rest) ->+        case get_context rest of+        (cont, rest') ->+            case silly_lex rest' of+            ("New patches:", rest'') ->+                case parse_patches rest'' of+                Sealed ps'' -> Right $ Sealed ((reverseFL ps'' +<+ unavailable_patches cont) :<: NilRL)+            (a,_) -> Left $ "Malformed patch bundle: '" ++ a +++                     "' is not 'New patches:'"+    ("-----BEGIN PGP SIGNED MESSAGE-----",rest) ->+            scan_bundle $ filter_gpg_dashes rest+    (_,rest) -> scan_bundle rest++-- filter_gpg_dashes is needed because clearsigned patches escape dashes:+filter_gpg_dashes :: PackedString -> PackedString+filter_gpg_dashes ps =+    unlinesPS $ map drop_dashes $+    takeWhile (/= packString "-----END PGP SIGNED MESSAGE-----") $+    dropWhile not_context_or_newpatches $ linesPS ps+    where drop_dashes x = if lengthPS x < 2 then x+                          else if takePS 2 x == packString "- "+                               then dropPS 2 x+                               else x+          not_context_or_newpatches s = (s /= packString "Context:") &&+                                        (s /= packString "New patches:")++unavailable_patches :: RepoPatch p => [PatchInfo] -> RL (PatchInfoAnd p) C(x y)+unavailable_patches [] = unsafeCoerceP NilRL+unavailable_patches (x:xs) = pi_unavailable x :<: unavailable_patches xs++pi_unavailable :: RepoPatch p => PatchInfo -> PatchInfoAnd p C(x y)+pi_unavailable i = (i `patchInfoAndPatch`+                      unavailable ("Patch not stored in patch bundle:\n" +++                                   renderString (human_friendly i)))+get_context :: PackedString -> ([PatchInfo],PackedString)+get_context ps =+    case readPatchInfo ps of+    Just (pinfo,r') ->+        case get_context r' of+        (pis,r'') -> (pinfo:pis, r'')+    Nothing -> ([],ps)+(-:-) :: a C(x y) -> (Sealed (FL a C(y)),b) -> (Sealed (FL a C(x)),b)+p -:- (Sealed ps, r) = (Sealed (p:>:ps), r)+get_patches :: RepoPatch p => PackedString -> (Sealed (FL (PatchInfoAnd p) C(x)), PackedString)+get_patches ps =+    case readPatchInfo ps of+    Nothing -> (Sealed NilFL, ps)+    Just (pinfo,_) ->+        case readPatch ps of+        Nothing -> (Sealed NilFL, ps)+        Just (Sealed p, r) -> (pinfo `piap` p) -:- get_patches r+parse_patches :: RepoPatch p => PackedString -> Sealed (FL (PatchInfoAnd p) C(x))+parse_patches ps =+  case readPatchInfo ps of+  Nothing -> Sealed NilFL+  Just (pinfo,_) ->+    case readPatch ps of+    Nothing -> Sealed NilFL+    Just (Sealed p, r) -> ((pinfo `piap` p) :>:) `mapSeal` parse_patches r++silly_lex :: PackedString -> (String, PackedString)+silly_lex ps = (unpackPS $ takeWhilePS (/='\n') $ dropWhitePS ps,+                dropWhilePS (/='\n') $ dropWhitePS ps)+\end{code}++\begin{code}+make_context :: [PatchInfo] -> Doc+make_context common =+    text ""+ $$ text "Context:"+ $$ text ""+ $$ (vcat $ map showPatchInfo $ common)+ $$ text ""+\end{code}++\begin{code}+scan_context :: RepoPatch p => PackedString -> PatchSet p C(x)+scan_context ps+  | nullPS ps = error "Bad context!"+  | otherwise =+    case silly_lex ps of+    ("Context:",rest) ->+        case get_context rest of+        (cont, _) -> unavailable_patches cont :<: NilRL+    ("-----BEGIN PGP SIGNED MESSAGE-----",rest) ->+            scan_context $ filter_gpg_dashes rest+    (_,rest) -> scan_context rest+\end{code}
+ src/Darcs/Patch/Check.lhs view
@@ -0,0 +1,296 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+module Darcs.Patch.Check ( PatchCheck(), do_check, file_exists, dir_exists,+                    remove_file, remove_dir, create_file, create_dir,+                    insert_line, delete_line, is_valid, do_verbose_check,+                    file_empty,+                    check_move, modify_file, Possibly(..)+                  ) where++import Text.Regex ( mkRegex, matchRegex )+import System.IO.Unsafe ( unsafePerformIO )+import FastPackedString+import Data.List (isPrefixOf)++newtype PatchCheck a = PC( KnownState -> (KnownState, a) )++data Possibly a = PJust a | PNothing | PSomething+                  deriving (Eq, Show)+data Prop = FileEx String | DirEx String | NotEx String+          | FileLines String [Possibly PackedString]+            deriving (Eq)+data KnownState = P [Prop] [Prop]+                | Inconsistent+                  deriving (Show)+instance  Show Prop  where+    show (FileEx f) = "FileEx "++f+    show (DirEx d)  = "DirEx "++d+    show (NotEx f) = "NotEx"++f+    show (FileLines f l)  = "FileLines "++f++" "++show (take 10 l)+\end{code}++\section{Patch Consistency Checking}++\begin{code}+instance Monad PatchCheck where+    (PC p) >>= k  =  PC( \s0 -> let (s1, a) = p s0+                                    (PC q) = k a+                                in q s1 )+    return a = PC( \s -> (s, a) )+\end{code}++\begin{code}+do_check :: PatchCheck a -> a+do_check (PC p) = snd $ p (P [] [])++do_verbose_check :: PatchCheck a -> a+do_verbose_check (PC p) =+    case p (P [] []) of+    (pc, b) -> unsafePerformIO $ do putStrLn $ show pc+                                    return b++is_valid :: PatchCheck Bool+is_valid = PC iv+    where iv Inconsistent = (Inconsistent, False)+          iv m = (m, True)+\end{code}++\begin{code}+has :: Prop -> [Prop] -> Bool+has _ [] = False+has k (k':ks) = k == k' || has k ks++modify_file :: String+            -> ([Possibly PackedString]-> Maybe [Possibly PackedString])+            -> PatchCheck Bool+modify_file f change = do+    file_exists f+    c <- file_contents f+    case change c of+      Nothing -> assert_not $ FileEx f -- shorthand for "FAIL"+      Just c' -> do set_contents f c'+                    is_valid++insert_line :: String -> Int -> PackedString -> PatchCheck Bool+insert_line f n l = do+    c <- file_contents f+    case il n c of+       [] -> assert_not $ FileEx f+       c' -> do+             set_contents f c'+             return True+  where il 1 mls = (PJust l:mls)+        il i (ml:mls) = ml : il (i-1) mls+        il _ [] = []++delete_line :: String -> Int -> PackedString -> PatchCheck Bool+delete_line f n l = do+    c <- file_contents f+    case dl [] n c of+        Nothing -> assert_not $ FileEx f+        Just c' -> do+            set_contents f c'+            is_valid+  where dl _ _ [] = Nothing+        dl o 1 (ml':ls) =+            case ml' of+            PSomething -> Just $ o++ls+            PNothing -> Just $ o++ls+            PJust l' -> if l' == l then Just $ o++ls+                                   else Nothing+        dl o i (ml:mls) =+            case ml of+            PNothing -> dl (o++[PSomething]) (i-1) mls+            _ -> dl (o++[ml]) (i-1) mls++set_contents :: String -> [Possibly PackedString] -> PatchCheck ()+set_contents f mss = PC (sc f mss)+sc :: String -> [Possibly PackedString] -> KnownState -> (KnownState,())+sc f mss (P ks nots) = (P (scl [] f mss ks) nots, ())+sc _ _ Inconsistent = (Inconsistent, ())+scl :: [Prop] -> String -> [Possibly PackedString] -> [Prop] -> [Prop]+scl olds f mss [] = FileLines f mss : olds+scl olds f mss (FileLines f' mss':ks)+    | f == f' = FileLines f mss : (olds++ks)+    | f /= f' = scl (FileLines f' mss':olds) f mss ks+scl olds f mss (k:ks) = scl (k:olds) f mss ks++file_contents :: String -> PatchCheck [Possibly PackedString]+file_contents f = PC fc+    where fc Inconsistent = (Inconsistent, [])+          fc (P ks nots) = (P ks nots, fic ks)+          fic (FileLines f' mss:_) | f == f' = mss+          fic (_:ks) = fic ks+          fic [] = repeat PNothing++file_empty :: String -> PatchCheck Bool+file_empty f = do+  c <- file_contents f+  let empty = all (PNothing ==) $ take 101 c+  if empty+     then do set_contents f []+             is_valid+     -- Crude way to make it inconsistent and return false:+     else assert_not $ FileEx f+  return empty++movedirfilename :: String -> String -> String -> String+movedirfilename d d' f =+    if (d ++ "/") `isPrefixOf` f+    then d'++drop (length d) f+    else if f == d+         then d'+         else f++do_swap :: String -> String -> PatchCheck Bool+do_swap f f' = PC swfn+  where swfn Inconsistent = (Inconsistent, False)+        swfn (P ks nots) = (P (map sw ks) (map sw nots), True)+        sw (FileEx a) | f  `is_soe` a = FileEx $ movedirfilename f f' a+                      | f' `is_soe` a = FileEx $ movedirfilename f' f a+        sw (DirEx a) | f  `is_soe` a = DirEx $ movedirfilename f f' a+                     | f' `is_soe` a = DirEx $ movedirfilename f' f a+        sw (FileLines a ls) | f  `is_soe` a = FileLines (movedirfilename f f' a) ls+                            | f' `is_soe` a = FileLines (movedirfilename f' f a) ls+        sw (NotEx a) | f `is_soe` a = NotEx $ movedirfilename f f' a+                     | f' `is_soe` a = NotEx $ movedirfilename f' f a+        sw p = p+        is_soe d1 d2 = -- is_superdir_or_equal+            d1 == d2 || (d1 ++ "/") `isPrefixOf` d2++assert :: Prop -> PatchCheck Bool+assert p = PC assertfn+    where assertfn Inconsistent = (Inconsistent, False)+          assertfn (P ks nots) =+              if has p nots then (Inconsistent, False)+              else if has p ks then (P ks nots, True)+              else (P (p:ks) nots, True)++assert_not :: Prop -> PatchCheck Bool+assert_not p = PC assertnfn+    where assertnfn Inconsistent = (Inconsistent, False)+          assertnfn (P ks nots) =+              if has p ks then (Inconsistent, False)+              else if has p nots then (P ks nots, True)+              else (P ks (p:nots), True)++change_to_true :: Prop -> PatchCheck Bool+change_to_true p = PC chtfn+    where chtfn Inconsistent = (Inconsistent, False)+          chtfn (P ks nots) = (P (p:ks) (filter (p /=) nots), True)++change_to_false :: Prop -> PatchCheck Bool+change_to_false p = PC chffn+    where chffn Inconsistent = (Inconsistent, False)+          chffn (P ks nots) = (P (filter (p /=) ks) (p:nots), True)+\end{code}++\begin{code}+assert_file_exists :: String -> PatchCheck Bool+assert_file_exists f = do assert_not $ NotEx f+                          assert_not $ DirEx f+                          assert $ FileEx f+assert_dir_exists :: String -> PatchCheck Bool+assert_dir_exists d = do assert_not $ NotEx d+                         assert_not $ FileEx d+                         assert $ DirEx d+assert_exists :: String -> PatchCheck Bool+assert_exists f = assert_not $ NotEx f++assert_no_such :: String -> PatchCheck Bool+assert_no_such f = do assert_not $ FileEx f+                      assert_not $ DirEx f+                      assert $ NotEx f+\end{code}++\begin{code}+create_file :: String -> PatchCheck Bool+create_file fn = do+  superdirs_exist fn+  assert_no_such fn+  change_to_true (FileEx fn)+  change_to_false (NotEx fn)++create_dir :: String -> PatchCheck Bool+create_dir fn = do+  substuff_dont_exist fn+  superdirs_exist fn+  assert_no_such fn+  change_to_true (DirEx fn)+  change_to_false (NotEx fn)++remove_file :: String -> PatchCheck Bool+remove_file fn = do+  superdirs_exist fn+  assert_file_exists fn+  file_empty fn+  change_to_false (FileEx fn)+  change_to_true (NotEx fn)++remove_dir :: String -> PatchCheck Bool+remove_dir fn = do+  substuff_dont_exist fn+  superdirs_exist fn+  assert_dir_exists fn+  change_to_false (DirEx fn)+  change_to_true (NotEx fn)++check_move :: String -> String -> PatchCheck Bool+check_move f f' = do+  superdirs_exist f+  superdirs_exist f'+  assert_exists f+  assert_no_such f'+  do_swap f f'+\end{code}++\begin{code}+substuff_dont_exist :: String -> PatchCheck Bool+substuff_dont_exist d = PC ssde+    where ssde Inconsistent = (Inconsistent, False)+          ssde (P ks nots) = if all noss ks+                             then (P ks nots, True)+                             else (Inconsistent, False)+              where noss (FileEx f) = not (is_within_dir f)+                    noss (DirEx f) = not (is_within_dir f)+                    noss _ = True+                    is_within_dir f = (d ++ "/") `isPrefixOf` f++superdirs_exist :: String -> PatchCheck Bool+superdirs_exist fn =+  case matchRegex (mkRegex "\\./(.+)/[^/]+") fn of+  Just ["."] -> return True+  Just [d] -> do+                a <- assert_dir_exists ("./"++d)+                b <- superdirs_exist ("./"++d)+                return $! a && b+  _ -> is_valid++file_exists :: String -> PatchCheck Bool+file_exists fn = do+  superdirs_exist fn+  assert_file_exists fn++dir_exists :: String -> PatchCheck Bool+dir_exists fn = do+  superdirs_exist fn+  assert_dir_exists fn+\end{code}+
+ src/Darcs/Patch/Choices.lhs view
@@ -0,0 +1,316 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\section{darcs record}+\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Patch.Choices ( PatchChoices, patch_choices, patch_choices_tps,+                      is_patch_first,+                      get_first_choice, get_middle_choice, get_last_choice,+                      separate_first_middle_from_last,+                      separate_first_from_middle_last,+                      separate_middle_last_from_first,+                      separate_last_from_first_middle,+                      force_first, force_firsts, force_last, force_lasts,+                      force_matching_first, force_matching_last,+                      select_all_middles,+                      make_uncertain, make_everything_later,+                      TaggedPatch, Tag, tag, tp_patch,+                    ) where++import System.IO.Unsafe ( unsafePerformIO )+import Data.IORef ( newIORef, writeIORef, readIORef )+import Darcs.Patch+import Darcs.Patch.Permutations ( commuteWhatWeCanRL )+import Darcs.Patch.Patchy ( Invert, Commute )+import Darcs.Patch.Ordered ( FL(..), RL(..), MyEq, unsafeCompare,+                             (:>)(..), (:\/:)(..), (:/\:)(..),+                             zipWithFL, mapFL_FL, mapFL,+                             (+>+), reverseRL )+\end{code}++PatchChoices divides a sequence of patches into three sets: ``first'',+``middle'' and ``last'', such that all patches can be applied, if you first+apply the first ones then the middle ones and then the last ones.+Obviously if there are dependencies between the patches that will put a+constraint on how you can choose to divide them up.  The PatchChoices data+type and associated functions are here to deal with many of the common+cases that come up when choosing a subset of a group of patches.++\verb!force_last! tells PatchChoices that a particular patch is required to be in+the ``last'' group, which also means that any patches that depend on it+must be in the ``last'' group.++Internally, a PatchChoices doesn't actually reorder the patches until it is+asked for the final output (e.g.\ by \verb!get_first_choice!).  Instead, each+patch is placed in a state of definitely first, definitely last and+undecided---undecided leans towards ``middle''.  In case you're wondering+about the first-middle-last language, it's because in some cases the+``yes'' answers will be last (as is the case for the revert command), and+in others first (as in record, pull and push).++\begin{code}+newtype Tag = TG Integer deriving ( Num, Show, Eq, Ord, Enum )+data TaggedPatch p C(x y) = TP Tag (p C(x y))+data PatchChoice p C(x y) = PC (TaggedPatch p C(x y)) (Maybe Bool)+newtype PatchChoices p = PCs (EasyPC p)+type EasyPC p = FL (PatchChoice p)++instance Eq (TaggedPatch p) where+    TP t1 _ == TP t2 _ = t1 == t2++tag :: TaggedPatch p -> Tag+tag (TP (TG t) _) = TG t++tp_patch :: TaggedPatch p -> p+tp_patch (TP _ p) = p++liftTP :: (p -> p) -> (TaggedPatch p -> TaggedPatch p)+liftTP f (TP t p) = TP t (f p)++instance MyEq p => MyEq (TaggedPatch p) where+    unsafeCompare (TP t1 p1) (TP t2 p2) = t1 == t2 && unsafeCompare p1 p2++instance Invert p => Invert (TaggedPatch p) where+    invert = liftTP invert+    identity = TP (-1) identity++instance Commute p => Commute (TaggedPatch p) where+    commute (TP t1 p1 :> TP t2 p2) = do p2' :> p1' <- commute (p1 :> p2)+                                        return (TP t2 p2' :> TP t1 p1')+    list_touched_files (TP _ p) = list_touched_files p+    merge (TP t1 p1 :\/: TP t2 p2) = case merge (p1 :\/: p2) of+                                     p2' :/\: p1' -> TP t2 p2' :/\: TP t1 p1'++patch_choices :: Patchy p => FL p C(x y) -> PatchChoices p C(x y)+patch_choices = fst . patch_choices_tps++patch_choices_tps :: Patchy p => FL p C(x y) -> (PatchChoices p C(x y), FL (TaggedPatch p) C(x y))+patch_choices_tps ps = let tps = zipWithFL TP [1..] ps+                       in (PCs $ zipWithFL (flip PC) (repeat Nothing) tps, tps)++force_matching_first :: Patchy p => (TaggedPatch p -> Bool) -> PatchChoices p -> PatchChoices p+make_everything_later :: Patchy p => PatchChoices p -> PatchChoices p++is_patch_first :: TaggedPatch p -> PatchChoices p -> Maybe Bool+\end{code}++\begin{code}+instance MyEq p => MyEq (PatchChoice p) where+    unsafeCompare (PC tp1 _) (PC tp2 _) = unsafeCompare tp1 tp2++instance Invert p => Invert (PatchChoice p) where+    invert (PC tp mf) = PC (invert tp) (fmap not mf)+    identity = PC identity Nothing++instance Commute p => Commute (PatchChoice p) where+    commute (PC t1 x1 :> PC t2 x2)+        = do t2' :> t1' <- commute (t1 :> t2)+             return (PC t2' x2 :> PC t1' x1)+    merge (PC t1 x1 :\/: PC t2 x2)+        = case merge (t1 :\/: t2) of+          t2' :/\: t1' -> PC t2' x2 :/\: PC t1' x1+    list_touched_files (PC t _) = list_touched_files t++invertSeq :: (Invert p, Invert q) => (p :> q) C(x y) -> (q :> p) C(y x)+invertSeq (x :> y) = (invert y :> invert x)++separate_first_from_middle_last :: Patchy p => PatchChoices p+                                -> (FL (TaggedPatch p) :> FL (TaggedPatch p))+separate_first_from_middle_last (PCs e) = pull_only_firsts e++separate_first_middle_from_last :: Patchy p => PatchChoices p+                                -> (FL (TaggedPatch p) :> FL (TaggedPatch p))+separate_first_middle_from_last (PCs e) = pull_firsts_middles e++separate_last_from_first_middle :: Patchy p => PatchChoices p+                                -> (FL (TaggedPatch p) :> FL (TaggedPatch p))+separate_last_from_first_middle pc =+    (get_first_choice pc +>+ get_middle_choice pc :> get_last_choice pc)++separate_middle_last_from_first :: Patchy p => PatchChoices p+                                -> (FL (TaggedPatch p) :> FL (TaggedPatch p))+separate_middle_last_from_first pc =+    (get_first_choice pc :> get_middle_choice pc +>+ get_last_choice pc)++get_first_choice :: Patchy p => PatchChoices p -> FL (TaggedPatch p)+get_first_choice (PCs e) = fst' $ pull_firsts e++get_last_choice :: Patchy p => PatchChoices p -> FL (TaggedPatch p)+get_last_choice (PCs e)+ = invert $ fst' $ pull_firsts $ invert e++get_middle_choice :: Patchy p => PatchChoices p -> FL (TaggedPatch p)+get_middle_choice (PCs e) = mapFL_FL pc2tp $+                            invert $ snd' $ pull_firsts $ invert+                                   $ snd' $ pull_firsts e+    where pc2tp (PC tp _) = tp++fst' :: (a :> b) -> a+fst' (x:>_) = x++snd' :: (a :> b) -> b+snd' (_:>x) = x++pull_firsts_middles :: Patchy p => EasyPC p -> (FL (TaggedPatch p) :> FL (TaggedPatch p))+pull_firsts_middles easyPC =+    let r = unsafePerformIO+          $ newIORef (error "pull_firsts_middles called badly")+        f :: Patchy p => RL (TaggedPatch p) C(x y) -> EasyPC p C(y z) -> FL (TaggedPatch p)+        f acc NilFL = unsafePerformIO (writeIORef r (reverseRL acc)) `seq` NilFL+        f acc (PC tp (Just False):>:e) = f (tp:<:acc) e+        f acc (PC tp _:>:e) = case commuteWhatWeCanRL (acc :> tp) of+                              more :> tp' :> acc' -> reverseRL more+>+tp':>:f acc' e+        xs = f NilRL easyPC+    in (xs :> unsafePerformIO (readIORef r))++pull_only_firsts :: Patchy p => EasyPC p -> (FL (TaggedPatch p) :> FL (TaggedPatch p))+pull_only_firsts easyPC =+    let r = unsafePerformIO+          $ newIORef (error "pull_only_firsts called badly")+        f :: Patchy p => RL (TaggedPatch p) C(x y) -> EasyPC p C(y z) -> FL (TaggedPatch p)+        f acc NilFL = unsafePerformIO (writeIORef r (reverseRL acc)) `seq` NilFL+        f acc (PC tp (Just True):>:e) = case commuteWhatWeCanRL (acc :> tp) of+                                        more :> tp' :> acc' -> reverseRL more+>+tp':>:f acc' e+        f acc (PC tp _:>:e) = f (tp:<:acc) e+        xs = f NilRL easyPC+    in (xs :> unsafePerformIO (readIORef r))++{-+pull_middles_lasts :: EasyPC p -> ([TaggedPatch p], [TaggedPatch p])+pull_middles_lasts easyPC =+    let r = unsafePerformIO+          $ newIORef (error "pull_middles_lasts called badly")+        f acc [] = unsafePerformIO (writeIORef r (reverse acc)) `seq` []+        f acc (PC tp (Just True):e) = f (tp:acc) e+        f acc (PC (TP t p) _:e) = case commute_up_list p acc of+                                  (acc', p') -> TP t p':f acc' e+        xs = f [] easyPC+    in (xs, unsafePerformIO (readIORef r))+-}++--pull_only_lasts :: EasyPC p -> ([TaggedPatch p], [TaggedPatch p])+--pull_only_lasts easyPC =+--    let r = unsafePerformIO+--          $ newIORef (error "pull_only_lasts called badly")+--        f acc [] = unsafePerformIO (writeIORef r (reverse acc)) `seq` []+--        f acc (PC (TP t p) (Just False):e) = case commute_up_list p acc of+--                                             (acc', p') -> TP t p':f acc' e+--        f acc (PC tp _:e) = f (tp:acc) e+--        xs = f [] easyPC+--    in (xs, unsafePerformIO (readIORef r))++pull_firsts :: Patchy p => EasyPC p -> (FL (TaggedPatch p) :> EasyPC p)+pull_firsts e = case pull_first e of+                Nothing -> (NilFL :> e)+                Just (p:>e') -> case pull_firsts e' of+                                (ps:>e'') -> (p:>:ps :> e'')++pull_lasts :: Patchy p => EasyPC p -> (EasyPC p :> FL (TaggedPatch p))+pull_lasts e = invertSeq $ pull_firsts $ invert e++pull_first :: Patchy p => EasyPC p -> Maybe (TaggedPatch p :> EasyPC p)+pull_first NilFL = Nothing+pull_first (PC tp (Just True):>:e) = Just (tp :> e)+pull_first (PC (TP t p) (Just False):>:e) =+    case pull_first e of+    Just (TP t2 p2 :> e') ->+        case commute (p:>p2) of+        Just (p2':>p') -> Just (TP t2 p2' :> PC (TP t p') (Just False):>:e')+        Nothing -> error "Aaack fixme!"+    Nothing -> Nothing+pull_first (PC tp@(TP t p) Nothing:>:e) =+    case pull_first e of+    Just (TP t2 p2 :> e') ->+        case commute (p:>p2) of+        Just (p2':>p') -> Just (TP t2 p2' :> (PC (TP t p') Nothing:>:e'))+        Nothing -> Just (tp :> PC (TP (-t2) p2) (Just True):>:e')+    Nothing -> Nothing+\end{code}++\begin{code}+is_patch_first tp (PCs e) = ipf e+  where ipf (PC a mb:>:e') | a == tp   = mb+                           | otherwise = ipf e'+        -- actually, the following should be impossible, but this is a reasonable answer+        ipf NilFL = Just False++set_simplys :: [Tag] -> Bool -> EasyPC p -> EasyPC p+set_simplys ts b e = mapFL_FL ch e+    where ch (PC tp@(TP t _) _)+           | t `elem` ts = PC tp (Just b)+           | otherwise   = PC tp Nothing++m2ids :: (TaggedPatch p -> Bool) -> EasyPC p -> [Tag]+m2ids m (PC tp@(TP t _) _:>:e)+ | m tp = t:m2ids m e+ | otherwise = m2ids m e+m2ids _ NilFL = []++force_matching_first m (PCs e) =+    let thd (PC (TP t _) _) = t+        xs = m2ids m e+        not_needed = case pull_firsts $ set_simplys xs True e of+                     _ :> rest -> mapFL thd rest+        ch pc@(PC tp@(TP t _) _)+         | t `elem` not_needed = pc+         | otherwise = PC tp (Just True)+    in PCs $ mapFL_FL ch e++force_firsts :: Patchy p => [Tag] -> PatchChoices p -> PatchChoices p+force_firsts ps pc = force_matching_first ((`elem` ps) . tag) pc++force_first :: Patchy p => Tag -> PatchChoices p -> PatchChoices p+force_first p pc = force_matching_first ((== p) . tag) pc++select_all_middles :: Patchy p => Bool -> PatchChoices p -> PatchChoices p+select_all_middles b (PCs e) = PCs (mapFL_FL f e)+    where f (PC tp Nothing) = PC tp (Just b')+          f pc = pc+          b' = not b++reverse_pc :: Patchy p => PatchChoices p -> PatchChoices p+reverse_pc (PCs e) = PCs $ invert e++force_matching_last :: Patchy p => (TaggedPatch p -> Bool) -> PatchChoices p -> PatchChoices p+force_matching_last m (PCs e) =+    let thd (PC (TP t _) _) = t+        xs = m2ids m e+        not_needed = case pull_lasts $ set_simplys xs False e of+                     rest :> _ -> mapFL thd rest+        ch pc@(PC tp@(TP t _) _)+         | t `elem` not_needed = pc+         | otherwise = PC tp (Just False)+    in PCs $ mapFL_FL ch e++force_last :: Patchy p => Tag -> PatchChoices p -> PatchChoices p+force_last p pc = reverse_pc $ force_first p $ reverse_pc pc++force_lasts :: Patchy p => [Tag] -> PatchChoices p -> PatchChoices p+force_lasts ps pc = reverse_pc $ force_firsts ps $ reverse_pc pc++make_uncertain :: Patchy p => Tag -> PatchChoices p -> PatchChoices p+make_uncertain t (PCs e) = PCs $ mapFL_FL ch e+    where ch pc@(PC x _) = if t == tag x then PC x Nothing else pc++make_everything_later (PCs e) = PCs $ mapFL_FL ch e+                               where ch (PC tp Nothing) = PC tp (Just False)+                                     ch (PC tp (Just True)) = PC tp Nothing+                                     ch x = x+\end{code}+
+ src/Darcs/Patch/Commute.lhs view
@@ -0,0 +1,886 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans #-}+#include "gadts.h"+module Darcs.Patch.Commute ( fromPrims,+                             modernize_patch,+#ifndef GADT_WITNESSES+                             merge, elegant_merge,+                             merger, unravel,+#endif+                             public_unravel, mangle_unravelled,+                             CommuteFunction, Perhaps(..),+                             -- for other commutes:+                             toMaybe,+                           )+       where++import Control.Monad ( MonadPlus, mplus, msum, mzero )++import FileName ( FileName, fn2fp, fp2fn )+import Darcs.Patch.Info ( invert_name, idpatchinfo )+import Darcs.Patch.Patchy ( Commute(..), Invert(..) )+import Darcs.Patch.Core ( Patch(..), Named(..),+#ifndef GADT_WITNESSES+                          flattenFL,+                          is_merger,+#endif+                          merger_undo,+                          join_patchesFL )+import Darcs.Patch.Prim ( Prim(..), FromPrims(..),+                          Conflict(..), Effect(..),+                          is_filepatch, sort_coalesceFL,+#ifndef GADT_WITNESSES+                          FilePatchType(..), DirPatchType(..),+#else+                          FilePatchType(Hunk),+#endif+                          is_hunk, modernizePrim )+import FastPackedString ( PackedString, packString,+                          lastPS, nullPS )+import Data.Maybe ( isJust )+import Data.List ( intersperse, sort )+#ifndef GADT_WITNESSES+import Darcs.Patch.Permutations ( head_permutationsRL, head_permutationsFL )+import Printer ( text, vcat, ($$) )+import Darcs.Patch.Patchy ( invertRL )+import Darcs.Patch.Show ( showPatch_ )+import Data.List ( nubBy )+import Darcs.Sealed ( unsafeUnseal )+#endif+import Darcs.Utils ( nubsort )+#include "impossible.h"+import Darcs.Sealed ( Sealed(..), mapSeal )+import Darcs.Patch.Ordered ( mapFL, mapFL_FL, unsafeCoerceP,+                             FL(..), RL(..),+                             (:/\:)(..), (:<)(..), (:\/:)(..), (:>)(..),+#ifndef GADT_WITNESSES+                             lengthFL, mapRL,+#endif+                             reverseFL, reverseRL, concatFL,+                             MyEq, unsafeCompare+                           )++--import Darcs.ColorPrinter ( traceDoc )+--import Printer ( greenText )+\end{code}+ +\section{Commuting patches}++\subsection{Composite patches}++Composite patches are made up of a series of patches intended to be applied+sequentially.  They are represented by a list of patches, with the first+patch in the list being applied first.++\newcommand{\commutex}{\longleftrightarrow}+\newcommand{\commutes}{\longleftrightarrow}++The first way (of only two) to change the context of a patch is by+commutation, which is the process of changing the order of two sequential+patches.+\begin{dfn}+The commutation of patches $P_1$ and $P_2$ is represented by+\[ P_2 P_1 \commutes {P_1}' {P_2}'. \]+Here $P_1'$ is intended to describe the same change as $P_1$, with the+only difference being that $P_1'$ is applied after $P_2'$ rather than+before $P_2$.+\end{dfn}+The above definition is obviously rather vague, the reason being that what+is the ``same change'' has not been defined, and we simply assume (and+hope) that the code's view of what is the ``same change'' will match those+of its human users.  The `$\commutes$' operator should be read as something+like the $==$ operator in C, indicating that the right hand side performs+identical changes to the left hand side, but the two patches are in+reversed order.  When read in this manner, it is clear that commutation+must be a reversible process, and indeed this means that commutation+\emph{can} fail, and must fail in certain cases.  For example, the creation+and deletion of the same file cannot be commuted.  When two patches fail to+commutex, it is said that the second patch depends on the first, meaning+that it must have the first patch in its context (remembering that the+context of a patch is a set of patches, which is how we represent a tree).+\footnote{The fact that commutation can fail makes a huge difference in the+whole patch formalism.  It may be possible to create a formalism in which+commutation always succeeds, with the result of what would otherwise be a+commutation that fails being something like a virtual particle (which can+violate conservation of energy), and it may be that such a formalism would+allow strict mathematical proofs (whereas those used in the current+formalism are mostly only hand waving ``physicist'' proofs).  However, I'm+not sure how you'd deal with a request to delete a file that has not yet+been created, for example.  Obviously you'd need to create some kind of+antifile, which would annihilate with the file when that file finally got+created, but I'm not entirely sure how I'd go about doing this.+$\ddot\frown$ So I'm sticking with my hand waving formalism.}++%I should add that one using the inversion relationship of sequential+%patches, one can avoid having to provide redundant definitions of+%commutation.++% There is another interesting property which is that a commutex's results+% can't be affected by commuting another thingamabopper.++\begin{code}+data Perhaps a = Unknown | Failed | Succeeded a++instance  Monad Perhaps where+    (Succeeded x) >>= k =  k x+    Failed   >>= _      =  Failed+    Unknown  >>= _      =  Unknown+    Failed   >> _       =  Failed+    (Succeeded _) >> k  =  k+    Unknown  >> k       =  k+    return              =  Succeeded+    fail _              =  Unknown++instance  MonadPlus Perhaps where+    mzero                 = Unknown+    Unknown `mplus` ys    = ys+    Failed  `mplus` _     = Failed+    (Succeeded x) `mplus` _ = Succeeded x++toMaybe :: Perhaps a -> Maybe a+toMaybe (Succeeded x) = Just x+toMaybe _ = Nothing++toPerhaps :: Maybe a -> Perhaps a+toPerhaps (Just x) = Succeeded x+toPerhaps Nothing = Failed++#ifndef GADT_WITNESSES+clever_commute :: CommuteFunction -> CommuteFunction+clever_commute c (p1:<p2) =+    case c (p1 :< p2) of+    Succeeded x -> Succeeded x+    Failed -> Failed+    Unknown -> case c (invert p2 :< invert p1) of+               Succeeded (p1' :< p2') -> Succeeded (invert p2' :< invert p1')+               Failed -> Failed+               Unknown -> Unknown+#endif++speedy_commute :: CommuteFunction+speedy_commute (p1 :< p2) -- Deal with common case quickly!+    | p1_modifies /= Nothing && p2_modifies /= Nothing &&+      p1_modifies /= p2_modifies = Succeeded (unsafeCoerceP p2 :< unsafeCoerceP p1)+    | otherwise = Unknown+    where p1_modifies = is_filepatch_merger p1+          p2_modifies = is_filepatch_merger p2++instance Commute p => Commute (Named p) where+    commute (NamedP n1 d1 p1 :> NamedP n2 d2 p2) =+        if n2 `elem` d1 || n1 `elem` d2+        then Nothing+        else do (p2' :> p1') <- commute (p1 :> p2)+                return (NamedP n2 d2 p2' :> NamedP n1 d1 p1')+    merge (NamedP n1 d1 p1 :\/: NamedP n2 d2 p2)+        = case merge (p1 :\/: p2) of+          (p2' :/\: p1') -> NamedP n2 d2 p2' :/\: NamedP n1 d1 p1'+    list_touched_files (NamedP _ _ p) = list_touched_files p++instance Conflict p => Conflict (Named p) where+    list_conflicted_files (NamedP _ _ p) = list_conflicted_files p+    resolve_conflicts (NamedP _ _ p) = resolve_conflicts p++everything_else_commute :: MaybeCommute -> CommuteFunction+everything_else_commute c x = eec x+    where+    eec :: CommuteFunction+    eec (PP px :< PP py) = toPerhaps $ do y' :< x' <- commutex (px :< py)+                                          return (PP y' :< PP x')+    eec (ComP NilFL :< p1) = Succeeded (unsafeCoerceP p1 :< (ComP NilFL))+    eec (p2 :< ComP NilFL) = Succeeded (ComP NilFL :< unsafeCoerceP p2)+    eec (ComP (p:>:ps) :< p1) = toPerhaps $ do+                              (p1' :< p') <- c (p :< p1)+                              (p1'' :< ComP ps') <- c (ComP ps :< p1')+                              return (p1'' :< ComP (p':>:ps'))+    eec (patch2 :< ComP patches) =+        toPerhaps $ do (patches' :< patch2') <- ccr (patch2 :< reverseFL patches)+                       return (ComP (reverseRL patches') :< patch2')+        where ccr :: FORALL(x y) (Patch :< RL Patch) C(x y) -> Maybe ((RL Patch :< Patch) C(x y))+              ccr (p2 :< NilRL) = seq p2 $ return (NilRL :< p2)+              ccr (p2 :< p:<:ps) = do (p' :< p2') <- c (p2 :< p)+                                      (ps' :< p2'') <- ccr (p2' :< ps)+                                      return (p':<:ps' :< p2'')+    eec _xx =+        msum [+#ifndef GADT_WITNESSES+              clever_commute commute_recursive_merger       _xx+             ,clever_commute other_commute_recursive_merger _xx+#endif+             ]++{-+Note that it must be true that++commutex (A^-1 A, P) = Just (P, A'^-1 A')++and++if commutex (A, B) == Just (B', A')+then commutex (B^-1, A^-1) == Just (A'^-1, B'^-1)+-}++#ifndef GADT_WITNESSES+merger_commute :: (Patch :< Patch) -> Perhaps (Patch :< Patch)+merger_commute (Merger _ _ p1 p2 :< pA)+    | unsafeCompare pA p1 = Succeeded (merger "0.0" p2 p1 :< p2)+    | unsafeCompare pA (invert (merger "0.0" p2 p1)) = Failed+merger_commute (Merger _ _+                (Merger _ _ c b)+                (Merger _ _ c' a) :<+                Merger _ _ b' c'')+    | unsafeCompare b' b && unsafeCompare c c' && unsafeCompare c c'' =+        Succeeded (merger "0.0" (merger "0.0" b a) (merger "0.0" b c) :<+                   merger "0.0" b a)+merger_commute _ = Unknown+#endif++instance Commute Patch where+    merge (y :\/: z) =+#ifndef GADT_WITNESSES+        case actual_merge (y:\/:z) of+        y' -> case commutex (y' :< z) of+                         Nothing -> bugDoc $ text "merge_patches bug"+                                    $$ showPatch_ y+                                   $$ showPatch_ z+                                   $$ showPatch_ y'+                         Just (z' :< _) -> z' :/\: y'+#else+        case elegant_merge (y:\/:z) of+        Just (z' :/\: y') -> z' :/\: y'+        Nothing -> undefined+#endif+    commutex x = toMaybe $ msum [speedy_commute x,+#ifndef GADT_WITNESSES+                                 clever_commute merger_commute x,+#endif+                                 everything_else_commute commutex x+                        ]+    -- Recurse on everything, these are potentially spoofed patches+    list_touched_files (ComP ps) = nubsort $ concat $ mapFL list_touched_files ps+    list_touched_files (Merger _ _ p1 p2) = nubsort $ list_touched_files p1+                                            ++ list_touched_files p2+    list_touched_files c@(Regrem _ _ _ _) = list_touched_files $ invert c+    list_touched_files (PP p) = list_touched_files p++commute_no_merger :: MaybeCommute+commute_no_merger x =+#ifndef GADT_WITNESSES+    toMaybe $ msum [speedy_commute x,+                    everything_else_commute commute_no_merger x]+#else+    bug "commute_no_merger undefined when compiled with GADTs" x+#endif++is_filepatch_merger :: Patch C(x y) -> Maybe FileName+is_filepatch_merger (PP p) = is_filepatch p+is_filepatch_merger (Merger _ _ p1 p2) = do+     f1 <- is_filepatch_merger p1+     f2 <- is_filepatch_merger p2+     if f1 == f2 then return f1 else Nothing+is_filepatch_merger (Regrem und unw p1 p2)+    = is_filepatch_merger (Merger und unw p1 p2)+is_filepatch_merger (ComP _) = Nothing+\end{code}++\begin{code}+#ifndef GADT_WITNESSES+commute_recursive_merger :: (Patch :< Patch) -> Perhaps (Patch :< Patch)+commute_recursive_merger (p@(Merger _ _ p1 p2) :< pA) = toPerhaps $+  do (pA' :< _) <- commutex (undo :< pA)+     commutex (invert undo :< pA')+     (pAmid :< _) <- commutex (invert p1 :< pA)+     (pAx :< p1') <- commutex (p1 :< pAmid)+     assert (pAx `unsafeCompare` pA)+     (_ :<p2') <- commutex (p2 :< pAmid)+     (_ :< p2o) <- commutex (p2' :< invert pAmid)+     assert (p2o `unsafeCompare` p2)+     let p' = if unsafeCompare p1' p1 && unsafeCompare p2' p2+              then p+              else merger "0.0" p1' p2'+         undo' = merger_undo p'+     (_ :< pAo) <- commutex (pA' :< undo')+     assert (pAo `unsafeCompare` pA)+     return (pA' :< p')+    where undo = merger_undo p+commute_recursive_merger _ = Unknown++other_commute_recursive_merger :: (Patch :< Patch) -> Perhaps (Patch :< Patch)+other_commute_recursive_merger (pA':< p_old@(Merger _ _ p1' p2')) =+  toPerhaps $+  do (_ :< pA) <- commutex (pA' :< merger_undo p_old)+     (p1 :< pAmid) <- commutex (pA :< p1')+     (pAmido :< _) <- commutex (invert p1 :< pA)+     assert (pAmido `unsafeCompare` pAmid)+     (_ :< p2) <- commutex (p2' :< invert pAmid)+     (_ :< p2o') <- commutex (p2 :< pAmid)+     assert (p2o' `unsafeCompare` p2')+     let p = if p1 `unsafeCompare` p1' && p2 `unsafeCompare` p2'+             then p_old+             else merger "0.0" p1 p2+         undo = merger_undo p+     assert (not $ pA `unsafeCompare` p1) -- special case here...+     (pAo' :< _) <- commutex (undo :<pA)+     assert (pAo' `unsafeCompare` pA')+     return (p :< pA)+other_commute_recursive_merger _ = Unknown++assert :: Bool -> Maybe ()+assert False = Nothing+assert True = Just ()+#endif+\end{code}++\begin{code}+type CommuteFunction = FORALL(x y) (Patch :< Patch) C(x y) -> Perhaps ((Patch :< Patch) C(x y))+type MaybeCommute = FORALL(x y) (Patch :< Patch) C(x y) -> Maybe ((Patch :< Patch) C(x y))+\end{code}++\paragraph{Merge}+\newcommand{\merge}{\Longrightarrow}+The second way one can change the context of a patch is by a {\bf merge}+operation.  A merge is an operation that takes two parallel patches and+gives a pair of sequential patches.  The merge operation is represented by+the arrow ``\( \merge \)''.+\begin{dfn}\label{merge_dfn}+The result of a merge of two patches, $P_1$ and $P_2$ is one of two patches,+$P_1'$ and $P_2'$, which satisfy the relationship:+\[  P_2 \parallel P_1 \merge {P_2}' P_1 \commutex {P_1}' P_2. \]+\end{dfn}+Note that the sequential patches resulting from a merge are \emph{required}+to commutex.  This is an important consideration, as without it most of the+manipulations we would like to perform would not be possible.  The other+important fact is that a merge \emph{cannot fail}.  Naively, those two+requirements seem contradictory.  In reality, what it means is that the+result of a merge may be a patch which is much more complex than any we+have yet considered\footnote{Alas, I don't know how to prove that the two+constraints even \emph{can} be satisfied.  The best I have been able to do+is to believe that they can be satisfied, and to be unable to find an case+in which my implementation fails to satisfy them.  These two requirements+are the foundation of the entire theory of patches (have you been counting+how many foundations it has?).}.++\subsection{How merges are actually performed}++The constraint that any two compatible patches (patches which can+successfully be applied to the same tree) can be merged is actually quite+difficult to apply.  The above merge constraints also imply that the result+of a series of merges must be independent of the order of the merges.  So+I'm putting a whole section here for the interested to see what algorithms+I use to actually perform the merges (as this is pretty close to being the+most difficult part of the code).++The first case is that in which the two merges don't actually conflict, but+don't trivially merge either (e.g.\ hunk patches on the same file, where the+line number has to be shifted as they are merged).  This kind of merge can+actually be very elegantly dealt with using only commutation and inversion.++There is a handy little theorem which is immensely useful when trying to+merge two patches.+\begin{thm}\label{merge_thm}+$ P_2' P_1 \commutex P_1' P_2 $ if and only if $ P_1'^{ -1}+P_2' \commutex P_2 P_1^{ -1} $, provided both commutations succeed.  If+either commutex fails, this theorem does not apply.+\end{thm}+This can easily be proven by multiplying both sides of the first+commutation by $P_1'^{ -1}$ on the left, and by $P_1^{ -1}$ on the right.+Besides being used in merging, this theorem is also useful in the recursive+commutations of mergers.  From Theorem~\ref{merge_thm}, we see that the+merge of $P_1$ and $P_2'$ is simply the commutation of $P_2$ with $P_1^{+-1}$ (making sure to do the commutation the right way).  Of course, if this+commutation fails, the patches conflict.  Moreover, one must check that the+merged result actually commutes with $P_1$, as the theorem applies only+when \emph{both} commutations are successful.++\begin{code}++elegant_merge :: (Patch :\/: Patch) C(x y)+              -> Maybe ((Patch :/\: Patch) C(x y))+elegant_merge (p1 :\/: p2) =+  case commutex (p1 :< invert p2) of+  Just (ip2':<p1') -> case commutex (p1' :< p2) of+                      Nothing -> Nothing -- should be a redundant check+                      Just (_:<p1o) -> if unsafeCompare p1o p1+                                       then Just (invert ip2' :/\: p1')+                                       else Nothing+  Nothing -> Nothing++\end{code}++Of course, there are patches that actually conflict, meaning a merge where+the two patches truly cannot both be applied (e.g.\ trying to create a file+and a directory with the same name).  We deal with this case by creating a+special kind of patch to support the merge, which we will call a+``merger''.  Basically, a merger is a patch that contains the two patches+that conflicted, and instructs darcs basically to resolve the conflict.  By+construction a merger will satisfy the commutation property (see+Definition~\ref{merge_dfn}) that characterizes all merges.  Moreover the+merger's properties are what makes the order of merges unimportant (which+is a rather critical property for darcs as a whole).++The job of a merger is basically to undo the two conflicting patches, and+then apply some sort of a ``resolution'' of the two instead.  In the case+of two conflicting hunks, this will look much like what CVS does, where it+inserts both versions into the file.  In general, of course, the two+conflicting patches may both be mergers themselves, in which case the+situation is considerably more complicated.++\begin{code}+#ifndef GADT_WITNESSES+actual_merge :: (Patch :\/: Patch) -> Patch+actual_merge (ComP the_p1s :\/: ComP the_p2s) =+    join_patchesFL $ mc the_p1s the_p2s+    where mc :: FL Patch -> FL Patch -> FL Patch+          mc NilFL (_:>:_) = NilFL+          mc p1s NilFL = p1s+          mc p1s (p2:>:p2s) = mc (merge_patches_after_patch p1s p2) p2s+actual_merge (ComP p1s :\/: p2) = seq p2 $+                              join_patchesFL $ merge_patches_after_patch p1s p2+actual_merge (p1 :\/: ComP p2s) = seq p1 $ merge_patch_after_patches p1 p2s++actual_merge (p1 :\/: p2) = case elegant_merge (p1:\/:p2) of+                            Just (_ :/\: p1') -> p1'+                            Nothing -> merger "0.0" p2 p1++merge_patch_after_patches :: Patch -> FL Patch -> Patch+merge_patch_after_patches p (p1:>:p1s) =+    merge_patch_after_patches (actual_merge (p:\/:p1)) p1s+merge_patch_after_patches p NilFL = p++merge_patches_after_patch :: FL Patch -> Patch -> FL Patch+merge_patches_after_patch p2s p =+    case commutex (merge_patch_after_patches p p2s :< join_patchesFL p2s) of+    Just (ComP p2s':< _) -> p2s'+    _ -> impossible+#endif+\end{code}++Much of the merger code depends on a routine which recreates from a single+merger the entire sequence of patches which led up to that merger (this is,+of course, assuming that this is the complicated general case of a merger+of mergers of mergers).  This ``unwind'' procedure is rather complicated,+but absolutely critical to the merger code, as without it we wouldn't even+be able to undo the effects of the patches involved in the merger, since we+wouldn't know what patches were all involved in it.++Basically, unwind takes a merger such as+\begin{verbatim}+M( M(A,B), M(A,M(C,D)))+\end{verbatim}+From which it recreates a merge history:+\begin{verbatim}+C+A+M(A,B)+M( M(A,B), M(A,M(C,D)))+\end{verbatim}+(For the curious, yes I can easily unwind this merger in my head [and on+paper can unwind insanely more complex mergers]---that's what comes of+working for a few months on an algorithm.)  Let's start with a simple+unwinding.  The merger \verb!M(A,B)! simply means that two patches+(\verb!A! and \verb!B!) conflicted, and of the two of them \verb!A! is+first in the history.  The last two patches in the unwinding of any merger+are always just this easy.  So this unwinds to:+\begin{verbatim}+A+M(A,B)+\end{verbatim}+What about a merger of mergers? How about \verb!M(A,M(C,D))!.  In this case+we know the two most recent patches are:+\begin{verbatim}+A+M(A,M(C,D))+\end{verbatim}+But obviously the unwinding isn't complete, since we don't yet see where+\verb!C! and \verb!D! came from.  In this case we take the unwinding of+\verb!M(C,D)! and drop its latest patch (which is \verb!M(C,D)! itself) and+place that at the beginning of our patch train:+\begin{verbatim}+C+A+M(A,M(C,D))+\end{verbatim}+As we look at \verb!M( M(A,B), M(A,M(C,D)))!, we consider the unwindings of+each of its subpatches:+\begin{verbatim}+          C+A         A+M(A,B)    M(A,M(C,D))+\end{verbatim}+As we did with \verb!M(A,M(C,D))!, we'll drop the first patch on the+right and insert the first patch on the left.  That moves us up to the two+\verb!A!'s.  Since these agree, we can use just one of them (they+``should'' agree).  That leaves us with the \verb!C! which goes first.++The catch is that things don't always turn out this easily.  There is no+guarantee that the two \verb!A!'s would come out at the same time, and if+they didn't, we'd have to rearrange things until they did.  Or if there was+no way to rearrange things so that they would agree, we have to go on to+plan B, which I will explain now.++Consider the case of \verb!M( M(A,B), M(C,D))!.  We can easily unwind the+two subpatches+\begin{verbatim}+A         C+M(A,B)    M(C,D)+\end{verbatim}+Now we need to reconcile the \verb!A! and \verb!C!.  How do we do this?+Well, as usual, the solution is to use the most wonderful+Theorem~\ref{merge_thm}.  In this case we have to use it in the reverse of+how we used it when merging, since we know that \verb!A! and \verb!C! could+either one be the \emph{last} patch applied before \verb!M(A,B)! or+\verb!M(C,D)!.  So we can find \verb!C'! using+\[+A^{ -1} C \commutex C' A'^{ -1}+\]+Giving an unwinding of+\begin{verbatim}+C'+A+M(A,B)+M( M(A,B), M(C,D) )+\end{verbatim}+There is a bit more complexity to the unwinding process (mostly having to+do with cases where you have deeper nesting), but I think the general+principles that are followed are pretty much included in the above+discussion.++\begin{code}+#ifndef GADT_WITNESSES+unwind :: Patch -> RL Patch -- Recreates a patch history in reverse.+unwind (Merger _ unwindings _ _) = unwindings+unwind p = p :<: NilRL;++true_unwind :: Patch -> RL Patch -- Recreates a patch history in reverse.+true_unwind p@(Merger _ _ p1 p2) =+    case (unwind p1, unwind p2) of+    (_:<:p1s,_:<:p2s) -> p :<: p1 :<: reconcile_unwindings p p1s p2s+    _ -> impossible+true_unwind _ = impossible++reconcile_unwindings :: Patch -> RL Patch -> RL Patch -> RL Patch+reconcile_unwindings _ NilRL p2s = p2s+reconcile_unwindings _ p1s NilRL = p1s+reconcile_unwindings p (p1:<:p1s) p2s =+    case [(p1s', p2s')|+          p1s'@(hp1s':<:_) <- head_permutationsRL (p1:<:p1s),+          p2s'@(hp2s':<:_) <- head_permutationsRL p2s,+          hp1s' `unsafeCompare` hp2s'] of+    ((p1':<:p1s', _:<:p2s'):_) ->+        p1' :<: reconcile_unwindings p p1s' p2s'+    [] -> case reverseFL `fmap` put_before p1 (reverseRL p2s) of+          Just p2s' -> p1 :<: reconcile_unwindings p p1s p2s'+          Nothing ->+              case fmap reverseFL $ put_before (headRL p2s) $+                   reverseRL (p1:<:p1s) of+              Just p1s' -> case p2s of+                           hp2s:<:tp2s -> hp2s :<:+                                          reconcile_unwindings p p1s' tp2s+                           NilRL -> impossible+              Nothing ->+                  bugDoc $ text "in function reconcile_unwindings"+                        $$ text "Original patch:"+                        $$ showPatch_ p+    _ -> bug "in reconcile_unwindings"++put_before :: Patch -> FL Patch -> Maybe (FL Patch)+put_before p1 (p2:>:p2s) =+    do p2':<p1' <- commutex (invert p1:<p2)+       commutex (p1:<p2')+       (p2' :>:) `fmap` put_before p1' p2s+put_before _ NilFL = Just NilFL+#endif+\end{code}+ +\section{Conflicts}++There are a couple of simple constraints on the routine which determines+how to resolve two conflicting patches (which is called `glump').  These+must be satisfied in order that the result of a series of merges is always+independent of their order.  Firstly, the output of glump cannot change+when the order of the two conflicting patches is switched.  If it did, then+commuting the merger could change the resulting patch, which would be bad.+Secondly, the result of the merge of three (or more) conflicting patches+cannot depend on the order in which the merges are performed.++The conflict resolution code (glump) begins by ``unravelling'' the merger+into a set of sequences of patches.  Each sequence of patches corresponds+to one non-conflicted patch that got merged together with the others.  The+result of the unravelling of a series of merges must obviously be+independent of the order in which those merges are performed.  This+unravelling code (which uses the unwind code mentioned above) uses probably+the second most complicated algorithm.  Fortunately, if we can successfully+unravel the merger, almost any function of the unravelled merger satisfies+the two constraints mentioned above that the conflict resolution code must+satisfy.++\begin{code}+instance Conflict Patch where+  commute_no_conflicts (x:>y) = do x' :< y' <- commute_no_merger (y :< x)+                                   return (y':>x')+#ifndef GADT_WITNESSES+  resolve_conflicts patch = rcs NilFL $ reverseFL $ flattenFL patch+    where rcs :: FL Patch C(w y) -> RL Patch C(x y) -> [[Sealed (FL Prim C(w))]]+          rcs _ NilRL = []+          rcs passedby (p@(Merger _ _ _ _):<:ps) =+              case commute_no_merger (join_patchesFL passedby:<p) of+              Just (p'@(Merger _ _ p1 p2):<_) ->+                  (map Sealed $ nubBy unsafeCompare $ effect (glump09 p1 p2) : unravel p')+                  : rcs (p :>: passedby) ps+              Nothing -> rcs (p :>: passedby) ps+              _ -> impossible+          rcs passedby (p:<:ps) = seq passedby $+                                  rcs (p :>: passedby) ps+#else+  resolve_conflicts = bug "haven't defined resolve_conflicts with type witnesses."+#endif++public_unravel :: Patch C(x y) -> [Sealed (FL Prim C(y))]+#ifdef GADT_WITNESSES+public_unravel = bug "Haven't implemented public_unravel with type witnesses."+#else+public_unravel p = map Sealed $ unravel p+#endif++#ifndef GADT_WITNESSES+unravel :: Patch -> [FL Prim]+unravel p = nubBy unsafeCompare $+            map (sort_coalesceFL . concatFL . mapFL_FL effect) $+            get_supers $ map reverseRL $ new_ur p $ unwind p++get_supers :: [FL Patch] -> [FL Patch]+get_supers (x:xs) =+    case filter (not.(x `is_superpatch_of`)) xs of+    xs' -> if or $ map (`is_superpatch_of` x) xs'+           then get_supers xs'+           else x : get_supers xs'+get_supers [] = []+is_superpatch_of :: FL Patch -> FL Patch -> Bool+x `is_superpatch_of` y | lengthFL y > lengthFL x = False+x `is_superpatch_of` y = x `iso` y+    where iso :: FL Patch -> FL Patch -> Bool+          _ `iso` NilFL = True+          NilFL `iso` _ = False+          a `iso` (b:>:bs) =+              case filter ((`unsafeCompare` b) . headFL) $+                   head_permutationsFL a of+              ((_:>:as):_) -> as `iso` bs+              [] -> False+              _ -> bug "bug in is_superpatch_of"++headFL :: FL a -> a+headFL (x:>:_) = x+headFL NilFL = bug "bad headFL"++merger :: String -> Patch -> Patch -> Patch+merger "0.0" p1 p2 = Merger undoit unwindings p1 p2+    where fake_p = Merger identity NilRL p1 p2+          unwindings = true_unwind fake_p+          p = Merger identity unwindings p1 p2+          undoit =+              case (is_merger p1, is_merger p2) of+              (True ,True ) -> join_patchesFL $ invertRL $ tailRL $ unwind p+                               where tailRL (_:<:t) = t+                                     tailRL _ = impossible+              (False,False) -> invert p1+              (True ,False) -> join_patchesFL NilFL+              (False,True ) -> join_patchesFL (invert p1 :>: merger_undo p2 :>: NilFL)+merger g _ _ =+    error $ "Cannot handle mergers other than version 0.0\n"++g+    ++ "\nPlease use darcs optimize --modernize with an older darcs."++glump09 :: Patch -> Patch -> Patch+glump09 p1 p2 = fromPrims $ unsafeUnseal $ mangle_unravelled $ map Sealed $ unravel $ merger "0.0" p1 p2++#endif++mangle_unravelled :: [Sealed (FL Prim C(x))] -> Sealed (FL Prim C(x))+mangle_unravelled pss = if only_hunks pss+                        then (:>: NilFL) `mapSeal` mangle_unravelled_hunks pss+                        else head pss++only_hunks :: [Sealed (FL Prim C(x))] -> Bool+only_hunks [] = False+only_hunks pss = fn2fp f /= "" && all oh pss+    where f = get_a_filename pss+          oh :: Sealed (FL Prim C(x)) -> Bool+          oh (Sealed (p:>:ps)) = is_hunk p &&+                                 [fn2fp f] == list_touched_files p &&+                                 oh (Sealed ps)+          oh (Sealed NilFL) = True++apply_hunks :: [Maybe PackedString] -> FL Prim C(x y) -> [Maybe PackedString]+apply_hunks ms (FP _ (Hunk l o n):>:ps) = apply_hunks (rls l ms) ps+    where rls 1 mls = map Just n ++ drop (length o) mls+          rls i (ml:mls) = ml : rls (i-1) mls+          rls _ [] = bug "rls in apply_hunks"+apply_hunks ms NilFL = ms+apply_hunks _ (_:>:_) = impossible++get_old :: [Maybe PackedString] -> [Sealed (FL Prim C(x))] -> [Maybe PackedString]+get_old mls (ps:pss) = get_old (get_hunks_old mls ps) pss+get_old mls [] = mls++get_a_filename :: [Sealed (FL Prim C(x))] -> FileName+get_a_filename ((Sealed (FP f _:>:_)):_) = f+get_a_filename _ = fp2fn ""++get_hunks_old :: [Maybe PackedString] -> Sealed (FL Prim C(x))+              -> [Maybe PackedString]+get_hunks_old mls (Sealed ps) =+    apply_hunks (apply_hunks mls ps) (invert ps)++get_hunks_new :: [Maybe PackedString] -> Sealed (FL Prim C(x))+              -> [Maybe PackedString]+get_hunks_new mls (Sealed ps) = apply_hunks mls ps++get_hunkline :: [[Maybe PackedString]] -> Int+get_hunkline = ghl 1+    where ghl :: Int -> [[Maybe PackedString]] -> Int+          ghl n pps =+            if any (isJust . head) pps+            then n+            else ghl (n+1) $ map tail pps++make_chunk :: Int -> [Maybe PackedString] -> [PackedString]+make_chunk n mls = pull_chunk $ drop (n-1) mls+    where pull_chunk (Just l:mls') = l : pull_chunk mls'+          pull_chunk (Nothing:_) = []+          pull_chunk [] = bug "should this be [] in pull_chunk?"++mangle_unravelled_hunks :: [Sealed (FL Prim C(x))] -> Sealed (Prim C(x))+--mangle_unravelled_hunks [[h1],[h2]] = Deal with simple cases handily?+mangle_unravelled_hunks pss =+        if null nchs then bug "mangle_unravelled_hunks"+                     else Sealed (FP filename (Hunk l old new))+    where oldf = get_old (repeat Nothing) pss+          newfs = map (get_hunks_new oldf) pss+          l = get_hunkline $ oldf : newfs+          nchs = sort $ map (make_chunk l) newfs+          filename = get_a_filename pss+          old = make_chunk l oldf+          new = [top] ++ concat (intersperse [middle] nchs) ++ [bottom]+          top    = packString $ "v v v v v v v" ++ eol_c+          middle = packString $ "*************" ++ eol_c+          bottom = packString $ "^ ^ ^ ^ ^ ^ ^" ++ eol_c+          eol_c  = if any (\ps -> not (nullPS ps) && lastPS ps == '\r') old+                   then "\r"+                   else ""+\end{code}++\begin{code}+instance Effect Patch where+    effect p@(Merger _ _ _ _) = sort_coalesceFL $ effect $ merger_undo p+    effect p@(Regrem _ _ _ _) = invert $ effect $ invert p+    effect (ComP ps) = concatFL $ mapFL_FL effect ps+    effect (PP p) = effect p+    isHunk p = do PP p' <- return p+                  isHunk p'++modernize_patch :: Patch C(x y) -> Patch C(x y)+modernize_patch p@(Merger _ _ _ _) = fromPrims $ effect p+modernize_patch p@(Regrem _ _ _ _) = fromPrims $ effect p+modernize_patch (ComP ps) = ComP $ filtermv $ mapFL_FL modernize_patch ps+    where filtermv :: FL Patch C(x y) -> FL Patch C(x y)+#ifndef GADT_WITNESSES+          filtermv (PP (Move _ b):>:xs) | hasadd xs = filtermv xs+              where hasadd (PP (FP b' AddFile):>:_) | b' == b = True+                    hasadd (PP (DP b' AddDir):>:_) | b' == b = True+                    hasadd (PP (FP b' RmFile):>:_) | b' == b = False+                    hasadd (PP (DP b' RmDir):>:_) | b' == b = False+                    hasadd (_:>:z) = hasadd z+                    hasadd NilFL = False+#endif+          filtermv (x:>:xs) = x :>: filtermv xs+          filtermv NilFL = NilFL++modernize_patch (PP p) = fromPrims $ modernizePrim p++instance FromPrims Patch where+    fromPrims (p :>: NilFL) = PP p+    fromPrims ps = join_patchesFL $ mapFL_FL PP ps+    joinPatches = join_patchesFL+\end{code}++\begin{code}+#ifndef GADT_WITNESSES+new_ur :: Patch -> RL Patch -> [RL Patch]+new_ur p (Merger _ _ p1 p2 :<: ps) =+   case filter ((`unsafeCompare` p1) . headRL) $ head_permutationsRL ps of+   ((_:<:ps'):_) -> new_ur p (p1:<:ps') ++ new_ur p (p2:<:ps')+   _ -> bugDoc $ text "in function new_ur"+              $$ text "Original patch:"+              $$ showPatch_ p+              $$ text "Unwound:"+              $$ vcat (mapRL showPatch_ $ unwind p)++new_ur op ps =+    case filter (is_merger.headRL) $ head_permutationsRL ps of+    [] -> [ps]+    (ps':_) -> new_ur op ps'++headRL :: RL a -> a+headRL (x:<:_) = x+headRL _ = bug "bad headRL"+#endif+\end{code}++\begin{code}++instance Invert p => Invert (Named p) where+    invert (NamedP n d p)  = NamedP (invert_name n) (map invert_name d) (invert p)+    identity = NamedP idpatchinfo [] identity++instance Invert Patch where+    invert (Merger undo unwindings p1 p2)+        = Regrem undo unwindings p1 p2+    invert (Regrem undo unwindings p1 p2)+        = Merger undo unwindings p1 p2+    invert (PP p) = PP (invert p)+    invert (ComP ps)  = ComP $ invert ps+    identity = ComP NilFL++instance MyEq Patch where+    unsafeCompare = eq_patches+instance MyEq p => MyEq (Named p) where+    unsafeCompare (NamedP n1 d1 p1) (NamedP n2 d2 p2) =+        n1 == n2 && d1 == d2 && unsafeCompare p1 p2++eq_patches :: Patch C(x y) -> Patch C(w z) -> Bool+eq_patches (PP p1) (PP p2) = unsafeCompare p1 p2+eq_patches (ComP ps1) (ComP ps2)+ = eq_FL eq_patches ps1 ps2+eq_patches (ComP NilFL) (PP Identity) = True+eq_patches (PP Identity) (ComP NilFL) = True+eq_patches (Merger _ _ p1a p1b) (Merger _ _ p2a p2b)+ = eq_patches p1a p2a &&+   eq_patches p1b p2b+eq_patches (Regrem _ _ p1a p1b) (Regrem _ _ p2a p2b)+ = eq_patches p1a p2a &&+   eq_patches p1b p2b+eq_patches _ _ = False++eq_FL :: (FORALL(b c d e) a C(b c) -> a C(d e) -> Bool)+      -> FL a C(x y) -> FL a C(w z) -> Bool+eq_FL _ NilFL NilFL = True+eq_FL f (x:>:xs) (y:>:ys) = f x y && eq_FL f xs ys+eq_FL _ _ _ = False++\end{code}
+ src/Darcs/Patch/Core.lhs view
@@ -0,0 +1,174 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\section{Patch relationships}++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Patch.Core+       ( Patch(..), Named(..),+         join_patchesFL, concatFL, flattenFL,+         nullP, is_null_patch, infopatch,+         n_fn,+         adddeps, namepatch, anonymous,+         merger_undo, is_merger,+         getdeps,+         patch2patchinfo, patchname, patchcontents,+       )+       where++import Prelude hiding ( pi )+import FileName ( fn2fp, fp2fn, norm_path )+import Darcs.Patch.Info ( PatchInfo, patchinfo, make_filename )+import Darcs.Patch.Patchy ( Patchy )+import Darcs.Patch.Ordered+import Darcs.Patch.Prim ( Prim(..), FromPrim(..), Effect(effect, effectRL) )+#include "impossible.h"++data Patch C(x y) where+    PP :: Prim C(x y) -> Patch C(x y)+    ComP :: FL Patch C(x y) -> Patch C(x y)+    Merger :: Patch C(x y)+           -> RL Patch C(x b)+           -> Patch C(c b)+           -> Patch C(c d)+           -> Patch C(x y)+    Regrem :: Patch C(x y)+           -> RL Patch C(x b)+           -> Patch C(c b)+           -> Patch C(c a)+           -> Patch C(y x)++instance FromPrim Patch where+    fromPrim = PP++data Named p C(x y) where+    NamedP :: !PatchInfo -> ![PatchInfo] -> !(p C(x y)) -> Named p C(x y)++instance Effect p => Effect (Named p) where+    effect (NamedP _ _ p) = effect p+    effectRL (NamedP _ _ p) = effectRL p++is_null_patch :: Patch C(x y) -> Bool+is_null_patch (ComP ps) = and $ mapFL is_null_patch ps+is_null_patch _ = False++nullP :: Patch C(x y) -> EqCheck C(x y)+nullP (ComP NilFL) = IsEq+nullP (ComP (x:>:xs)) | IsEq <- nullP x = nullP (ComP xs)+nullP _ = NotEq++is_merger :: Patch C(a b) -> Bool+is_merger (Merger _ _ _ _) = True+is_merger (Regrem _ _ _ _) = True+is_merger _ = False++merger_undo :: Patch C(x y) -> Patch C(x y)+merger_undo (Merger undo _ _ _) = undo+merger_undo _ = impossible+\end{code}++%Another nice thing to be able to do with composite patches is to `flatten'+%them, that is, turn them into a simple list of patches (appropriately+%ordered, of course), with all nested compositeness unnested.++\begin{code}+{- INLINE flattenFL -}+flattenFL :: Patch C(x y) -> FL Patch C(x y)+flattenFL (ComP ps) = concatFL (mapFL_FL flattenFL ps)+flattenFL (PP Identity) = NilFL+flattenFL p = p :>: NilFL++\end{code}++\begin{code}+join_patchesFL :: FL Patch C(x y) -> Patch C(x y)+join_patchesFL ps = ComP $! ps++namepatch :: Patchy p => String -> String -> String -> [String] -> p C(x y) -> Named p C(x y)+infopatch :: Patchy p => PatchInfo -> p C(x y) -> Named p C(x y)+adddeps :: Named p C(x y) -> [PatchInfo] -> Named p C(x y)+getdeps :: Named p C(x y) -> [PatchInfo]+namepatch date name author desc p+    | '\n' `elem` name = error "Patch names cannot contain newlines."+    | otherwise = NamedP (patchinfo date name author desc) [] p+anonymous :: Patchy p => p C(x y) -> Named p C(x y)+anonymous p = namepatch "today" "anonymous" "unknown" ["anonymous"] p+infopatch pi p = NamedP pi [] p+adddeps (NamedP pi _ p) ds = NamedP pi ds p+getdeps (NamedP _ ds _) = ds++patch2patchinfo :: Named p C(x y) -> PatchInfo+patch2patchinfo (NamedP i _ _) = i++patchname :: Named p C(x y) -> String+patchname (NamedP i _ _) = make_filename i++patchcontents :: Named p C(x y) -> p C(x y)+patchcontents (NamedP _ _ p) = p+\end{code}++\begin{code}+n_fn :: FilePath -> FilePath+n_fn f = "./"++(fn2fp $ norm_path $ fp2fn f)+\end{code}++The simplest relationship between two patches is that of ``sequential''+patches, which means that the context of the second patch (the one on the+left) consists of the first patch (on the right) plus the context of the+first patch.  The composition of two patches (which is also a patch) refers+to the patch which is formed by first applying one and then the other.  The+composition of two patches, $P_1$ and $P_2$ is represented as $P_2P_1$,+where $P_1$ is to be applied first, then $P_2$\footnote{This notation is+inspired by the notation of matrix multiplication or the application of+operators upon a Hilbert space.  In the algebra of patches, there is+multiplication (i.e.\ composition), which is associative but not+commutative, but no addition or subtraction.}++There is one other very useful relationship that two patches can have,+which is to be parallel patches, which means that the two patches have an+identical context (i.e.\ their representation applies to identical trees).+This is represented by $P_1\parallel P_2$.  Of course, two patches may also+have no simple relationship to one another.  In that case, if you want to+do something with them, you'll have to manipulate them with respect to+other patches until they are either in sequence or in parallel.++The most fundamental and simple property of patches is that they must be+invertible.  The inverse of a patch is described by: $P^{ -1}$.  In the+darcs implementation, the inverse is required to be computable from+knowledge of the patch only, without knowledge of its context, but that+(although convenient) is not required by the theory of patches.+\begin{dfn}+The inverse of patch $P$ is $P^{ -1}$, which is the ``simplest'' patch for+which the composition \( P^{ -1} P \) makes no changes to the tree.+\end{dfn}+Using this definition, it is trivial to prove the following theorem+relating to the inverse of a composition of two patches.+\begin{thm} The inverse of the composition of two patches is+\[ (P_2 P_1)^{ -1} = P_1^{ -1} P_2^{ -1}. \]+\end{thm}+Moreover, it is possible to show that the right inverse of a patch is equal+to its left inverse.  In this respect, patches continue to be analogous to+square matrices, and indeed the proofs relating to these properties of the+inverse are entirely analogous to the proofs in the case of matrix+multiplication.  The compositions proofs can also readily be extended to+the composition of more than two patches.+\begin{code}++\end{code}
+ src/Darcs/Patch/Depends.lhs view
@@ -0,0 +1,481 @@+%  Copyright (C) 2003-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\section{Dependencies}+\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Patch.Depends ( get_common_and_uncommon, get_tags_right,+                 get_common_and_uncommon_or_missing,+                 optimize_patchset, deep_optimize_patchset,+                 slightly_optimize_patchset,+                 get_patches_beyond_tag, get_patches_in_tag,+                 is_tag,+                 patchset_union, patchset_intersection,+                 commute_to_end,+               ) where+import Data.List ( delete, intersect )+import Control.Monad ( liftM2 )+import Control.Monad.Error (Error(..), MonadError(..))++import Darcs.Patch ( RepoPatch, Named, getdeps, commutex,+                     commuteFL,+                     patch2patchinfo, merge )+import Darcs.Patch.Ordered ( (:\/:)(..), (:<)(..), (:/\:)(..), (:>)(..),+                             RL(..), FL(..),+                             (+<+),+                             reverseFL, mapFL_FL, mapFL, concatReverseFL,+                             lengthRL, concatRL, reverseRL, mapRL,+                             unsafeCoerceP, EqCheck(..) )+import Darcs.Patch.Permutations ( partitionRL )+import Darcs.Patch.Info ( PatchInfo, just_name, human_friendly )+import Darcs.Patch.Set ( PatchSet, SealedPatchSet )+import Darcs.Patch.Patchy ( sloppyIdentity )+import Darcs.Hopefully ( PatchInfoAnd, piap, info,+                         hopefully, conscientiously, hopefullyM )+import Darcs.Progress ( progressRL )+import Darcs.Sealed (Sealed(..), FlippedSeal(..)+                    , flipSeal, seal )+import Printer ( errorDoc, renderString, ($$), text )+#include "impossible.h"+\end{code}++\begin{code}+get_common_and_uncommon :: RepoPatch p => (PatchSet p C(x),PatchSet p C(y)) ->+                           ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+get_common_and_uncommon_or_missing :: RepoPatch p => (PatchSet p C(x),PatchSet p C(y)) ->+                                      Either PatchInfo ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+\end{code}++\begin{code}+get_common_and_uncommon = +    either missingPatchError id . get_common_and_uncommon_err++get_common_and_uncommon_or_missing = +    either (\(MissingPatch x _) -> Left x) Right . get_common_and_uncommon_err++get_common_and_uncommon_err :: RepoPatch p => (PatchSet p C(x),PatchSet p C(y)) ->+                               Either MissingPatch ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+get_common_and_uncommon_err (ps1,ps2) = gcau (optimize_patchset ps1) ps2++{-+with_partial_intersection takes two PatchSets and splits them into a common+intersection portion and two sets of patches.  The intersection, however,+is only lazily determined, so there is no guarantee that all intersecting+patches will be included in the intersection PatchSet.  This is a pretty+efficient function, because it makes use of the already-broken-up nature of+PatchSets.++PatchSets have the property that if++(info $ last $ head a) == (info $ last $ head b)++then (tail a) and (tail b) are identical repositories, and we want to take+advantage of this if possible, to avoid reading too many inventories.  In+the case of --partial repositories or patch bundles, it is crucial that we+don't need to read the whole history, since it isn't available.++TODO:++The length equalising isn't necessarily right. We probably also be+thinking about not going past the end of a partial repository, or favour+local repository stuff over remote repository stuff.++Also, when comparing l1 to l2, we should really be comparing the+newly discovered one to /all/ the lasts in the other patch set+that we've got so far.+-}+with_partial_intersection :: forall a p C(x y). RepoPatch p => PatchSet p C(x) -> PatchSet p C(y)+                          -> (FORALL(z) PatchSet p C(z) -> RL (PatchInfoAnd p) C(z x)+                                                        -> RL (PatchInfoAnd p) C(z y) -> a)+                          -> a+with_partial_intersection NilRL ps2 j = j (NilRL:<:NilRL) NilRL (concatRL ps2)+with_partial_intersection ps1 NilRL j = j (NilRL:<:NilRL) (concatRL ps1) NilRL+with_partial_intersection (NilRL:<:ps1) ps2 j =+    with_partial_intersection ps1 ps2 j+with_partial_intersection ps1 (NilRL:<:ps2) j =+    with_partial_intersection ps1 ps2 j+-- NOTE: symmetry is broken here, so we want the PatchSet with more history+-- first!+with_partial_intersection ((pi1:<:NilRL):<:common) ((pi2:<:NilRL):<:_) j+-- NOTE: Since the patchsets have the same starting but different ending+-- we can coerce them.  The type system is not aware of our invariant on tags,+-- but both pi1 and pi2 should be tags, thus we check they are both identity+-- patches.+    | info pi1 == info pi2+    , IsEq <- sloppyIdentity pi1+    , IsEq <- sloppyIdentity pi2 = j common NilRL (unsafeCoerceP NilRL)+with_partial_intersection (orig_ps1:<:orig_ps1s) (orig_ps2:<:orig_ps2s) j+ = f (lengthRL orig_ps1) (last $ mapRL info orig_ps1) (orig_ps1:>:NilFL) orig_ps1s+     (lengthRL orig_ps2) (last $ mapRL info orig_ps2) (orig_ps2:>:NilFL) orig_ps2s+    where {- Invariants: nx = length $ concatReverseFL psx+                         lx = last $ concatReverseFL psx   -}+          f :: Int -> PatchInfo -> FL (RL (PatchInfoAnd p)) C(r x) -> PatchSet p C(r)+            -> Int -> PatchInfo -> FL (RL (PatchInfoAnd p)) C(u y) -> PatchSet p C(u)+            -> a+          f _n1 l1 ps1 ps1s _n2 l2 ps2 _ps2s+           | l1 == l2 = j ps1s (unsafeCoerceP (concatReverseFL ps1)) (unsafeCoerceP (concatReverseFL ps2))+          f n1 l1 ps1 ps1s n2 l2 ps2 ps2s+           = case compare n1 n2 of+             GT -> case dropWhileNilRL ps2s of+                   ps2':<:ps2s' ->+                       f n1 l1 ps1 ps1s+                         (n2 + lengthRL ps2') (last $ mapRL info ps2') (ps2':>:ps2) ps2s'+                   NilRL -> -- We keep going round f so the l1 == l2 case+                            -- has a chance to kick in+                         case dropWhileNilRL ps1s of+                         ps1':<:ps1s' ->+                             f (n1 + lengthRL ps1') (last $ mapRL info ps1')+                               (ps1':>:ps1) ps1s'+                               n2 l2 ps2 ps2s+                         NilRL -> j (NilRL:<:NilRL) (concatReverseFL ps1) (concatReverseFL ps2)+             _  -> case dropWhileNilRL ps1s of+                   ps1':<:ps1s' ->+                       f (n1 + lengthRL ps1') (last $ mapRL info ps1') (ps1':>:ps1) ps1s'+                         n2 l2 ps2 ps2s+                   NilRL -> -- We keep going round f so the l1 == l2 case+                            -- has a chance to kick in+                         case dropWhileNilRL ps2s of+                         ps2':<:ps2s' ->+                             f n1 l1 ps1 NilRL+                               (n2 + lengthRL ps2') (last $ mapRL info ps2')+                               (ps2':>:ps2) ps2s'+                         NilRL -> j (NilRL:<:NilRL) (concatReverseFL ps1) (concatReverseFL ps2)++{-+gcau determines a list of "common" patches and patches unique to each of+the two PatchSets.  The list of "common" patches only needs to include all+patches that are not interspersed with the "unique" patches, but including+more patches in the list of "common" patches doesn't really hurt, except+for efficiency considerations.  Mostly, we want to access as few elements+as possible of the PatchSet list, since those can be expensive (or+unavailable).++PatchSets have the property that if++(info $ last $ head a) == (info $ last $ head b)++then (tail a) and (tail b) are identical repositories, and we want to take+advantage of this if possible, to avoid reading too many inventories.  In+the case of --partial repositories or patch bundles, it is crucial that we+don't need to read the whole history, since it isn't available.++TODO:++The length equalising isn't necessarily right. We probably also be+thinking about not going past the end of a partial repository, or favour+local repository stuff over remote repo stuff.++Also, when comparing l1 to l2, we should really be comparing the+newly discovered one to /all/ the lasts in the other patch set+that we've got so far.+-}++gcau :: forall p C(x y). RepoPatch p => PatchSet p C(x) -> PatchSet p C(y)+     -> Either MissingPatch ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+gcau NilRL ps2 = return ([], NilRL:<:NilRL :\/: concatRL ps2 :<: NilRL)+gcau ps1 NilRL = return ([], concatRL ps1 :<: NilRL :\/: NilRL:<:NilRL)+gcau (NilRL:<:ps1) ps2 = gcau ps1 ps2+gcau ps1 (NilRL:<:ps2) = gcau ps1 ps2+gcau ((pi1:<:NilRL):<:_) ((pi2:<:NilRL):<:_)+ | info pi1 == info pi2+ , IsEq <- sloppyIdentity pi1+ , IsEq <- sloppyIdentity pi2 = return ([info pi1], NilRL:<:NilRL :\/: unsafeCoerceP (NilRL:<:NilRL))+gcau (orig_ps1:<:orig_ps1s) (orig_ps2:<:orig_ps2s)+ = f (lengthRL orig_ps1) (last $ mapRL info orig_ps1) (orig_ps1:>:NilFL) orig_ps1s+     (lengthRL orig_ps2) (last $ mapRL info orig_ps2) (orig_ps2:>:NilFL) orig_ps2s+    where {- Invariants: nx = lengthRL $ concatReverseFL psx+                         lx = last $ concatReverseFL psx   -}+          f :: Int -> PatchInfo -> FL (RL (PatchInfoAnd p)) C(r x) -> PatchSet p C(r)+            -> Int -> PatchInfo -> FL (RL (PatchInfoAnd p)) C(u y) -> PatchSet p C(u)+            -> Either MissingPatch ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+          f _n1 l1 ps1 _ps1s _n2 l2 ps2 _ps2s+           | l1 == l2 = gcau_simple (unsafeCoerceP (concatReverseFL ps1)) (unsafeCoerceP (concatReverseFL ps2))+          f n1 l1 ps1 ps1s n2 l2 ps2 ps2s+           = case compare n1 n2 of+             GT -> case dropWhileNilRL ps2s of+                   ps2':<:ps2s' ->+                       f n1 l1 ps1 ps1s+                         (n2 + lengthRL ps2') (last $ mapRL info ps2') (ps2':>:ps2) ps2s'+                   NilRL -> -- We keep going round f so the l1 == l2 case+                            -- has a chance to kick in+                         case dropWhileNilRL ps1s of+                         ps1':<:ps1s' ->+                             f (n1 + lengthRL ps1') (last $ mapRL info ps1')+                               (ps1':>:ps1) ps1s'+                               n2 l2 ps2 ps2s+                         NilRL -> gcau_simple (concatReverseFL ps1) (concatReverseFL ps2)+             _  -> case dropWhileNilRL ps1s of+                   ps1':<:ps1s' ->+                       f (n1 + lengthRL ps1') (last $ mapRL info ps1') (ps1':>:ps1) ps1s'+                         n2 l2 ps2 ps2s+                   NilRL -> -- We keep going round f so the l1 == l2 case+                            -- has a chance to kick in+                         case dropWhileNilRL ps2s of+                         ps2':<:ps2s' ->+                             f n1 l1 ps1 NilRL+                               (n2 + lengthRL ps2') (last $ mapRL info ps2')+                               (ps2':>:ps2) ps2s'+                         NilRL -> gcau_simple (concatReverseFL ps1) (concatReverseFL ps2)++dropWhileNilRL :: PatchSet p C(x) -> PatchSet p C(x)+dropWhileNilRL (NilRL:<:xs) = dropWhileNilRL xs+dropWhileNilRL xs = xs++gcau_simple :: RepoPatch p => RL (PatchInfoAnd p) C(x y) -> RL (PatchInfoAnd p) C(u v)+            -> Either MissingPatch ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(y v))+gcau_simple ps1 ps2 = do+ FlippedSeal ex1 <- get_extra (return NilFL) common ps1+ FlippedSeal ex2 <- get_extra (return NilFL) common ps2+ let ps1' = filter (`elem` common) $ ps1_info+ return (ps1', (unsafeCoerceP ex1 :<: NilRL) :\/: ex2 :<: NilRL)+  where common   = ps1_info `intersect` mapRL info ps2+        ps1_info = mapRL info ps1++data MissingPatch = MissingPatch !PatchInfo !String++instance Error MissingPatch where+    -- we don't really need those methods+    noMsg = bug "MissingPatch doesn't define noMsg."++get_extra :: RepoPatch p => Either MissingPatch (FL (Named p) C(x y))+          -> [PatchInfo]+          -> RL (PatchInfoAnd p) C(u x)+          -> Either MissingPatch (FlippedSeal (RL (PatchInfoAnd p)) C(y))+get_extra _ _ NilRL = return (flipSeal NilRL)+get_extra skipped common (hp:<:pps) =+    if info hp `elem` common && is_tag (info hp)+    then case getdeps `fmap` hopefullyM hp of+         Just ds -> get_extra (liftM2 (:>:) ep skipped) (ds++delete (info hp) common) pps+         Nothing -> get_extra (liftM2 (:>:) ep skipped) (delete (info hp) common) pps+    else if info hp `elem` common+         then get_extra (liftM2 (:>:) ep skipped) (delete (info hp) common) pps+         else do+            p <- ep+            skpd <- skipped+            case commuteFL (p :> skpd) of+              Just (skipped_patch' :> p') -> do+                  FlippedSeal x <- get_extra (return skipped_patch') common pps+                  return $ flipSeal (info hp `piap` p' :<: x)+              Nothing -> errorDoc $ text "bug in get_extra commuting patch:"+                         $$ human_friendly (info hp)+    where ep = case hopefullyM hp of+               Right p' -> return p'+               Left e -> throwError (MissingPatch (info hp) e)++missingPatchError :: MissingPatch -> a+missingPatchError (MissingPatch pinfo e) =+    errorDoc+        ( text "failed to read patch in get_extra:"+          $$ human_friendly pinfo $$ text e+          $$ text "Perhaps this is a 'partial' repository?" )++get_extra_old :: RepoPatch p => FL (Named p) C(x y)+              -> [PatchInfo]+              -> RL (PatchInfoAnd p) C(u x)+              -> FlippedSeal (RL (PatchInfoAnd p)) C(y)+get_extra_old skipped common pps =+    either missingPatchError id (get_extra (return skipped) common pps)+              +\end{code}++\begin{code}+get_patches_beyond_tag :: RepoPatch p => PatchInfo -> PatchSet p C(x) -> FlippedSeal (RL (RL (PatchInfoAnd p))) C(x)+get_patches_beyond_tag t ((hp:<:NilRL):<:_) | info hp == t = flipSeal $ NilRL :<: NilRL+get_patches_beyond_tag t patchset@((hp:<:ps):<:pps) =+    if info hp == t+    then if get_tags_right patchset == [info hp]+         then flipSeal $ NilRL :<: NilRL -- special case to avoid looking at redundant patches+         else case get_extra_old NilFL [t] (concatRL patchset) of+              FlippedSeal x -> flipSeal $ x :<: NilRL+    else hp `prepend` get_patches_beyond_tag t (ps:<:pps)+ where+ prepend :: (PatchInfoAnd p) C(x y) -> FlippedSeal (RL (RL (PatchInfoAnd p))) C(x) -> FlippedSeal (RL (RL (PatchInfoAnd p))) C(y)+ prepend pp (FlippedSeal NilRL)     = flipSeal $ (pp:<:NilRL) :<: NilRL+ prepend pp (FlippedSeal (p:<:ps')) = flipSeal $ (pp:<:p)     :<: ps'+get_patches_beyond_tag t (NilRL:<:pps) = get_patches_beyond_tag t pps+get_patches_beyond_tag t NilRL = bug $ "tag\n" +++                                 renderString (human_friendly t) +++                                 "\nis not in the patchset in get_patches_beyond_tag."++get_patches_in_tag :: RepoPatch p => PatchInfo -> PatchSet p C(x) -> SealedPatchSet p+get_patches_in_tag t pps@((hp:<:NilRL):<:xs)+    | info hp == t = seal pps+    | otherwise = get_patches_in_tag t xs++get_patches_in_tag t ((hp:<:ps):<:xs)+    | info hp /= t = get_patches_in_tag t (ps:<:xs)++get_patches_in_tag t ((pa:<:ps):<:xs) = gpit thepis (pa:>:NilFL) (ps:<:xs)+    where thepis = getdeps $ conscientiously+                   (\e -> text "Couldn't read tag"+                          $$ human_friendly t+                          $$ text ""+                          $$ e) pa+          gpit :: RepoPatch p => [PatchInfo] -> (FL (PatchInfoAnd p)) C(x y) -> PatchSet p C(x) -> SealedPatchSet p+          gpit _ sofar NilRL = seal $ reverseFL sofar :<: NilRL+          gpit deps sofar ((hp:<:NilRL):<:xs')+              | info hp `elem` deps+              , IsEq <- sloppyIdentity hp = seal $ (reverseFL $ hp :>: sofar) :<: xs'+              | IsEq <- sloppyIdentity hp = gpit deps sofar xs'+          gpit deps sofar (NilRL:<:xs') = gpit deps sofar xs'+          gpit deps sofar ((hp:<:ps'):<:xs')+              | info hp `elem` deps+                  = let odeps = filter (/=info hp) deps+                        alldeps = if is_tag $ info hp+                                  then odeps ++ getdeps (hopefully hp)+                                  else odeps+                    in gpit alldeps (hp:>:sofar) (ps':<:xs')+              | otherwise+                  = gpit deps (commute_by sofar $ hopefully hp) (ps':<:xs')+          commute_by :: RepoPatch p => FL (PatchInfoAnd p) C(x y) -> (Named p) C(w x)+                     -> FL (PatchInfoAnd p) C(w z)+          commute_by NilFL _ = unsafeCoerceP NilFL+          commute_by (hpa:>:xs') p =+              case commutex (hopefully hpa :< p) of+                Nothing -> bug "Failure commuting patches in commute_by called by gpit!"+                Just (p':<a') -> (info hpa `piap` a') :>: commute_by xs' p'++get_patches_in_tag t _ = errorDoc $ text "Couldn't read tag"+                                 $$ human_friendly t+\end{code}++\begin{code}+is_tag :: PatchInfo -> Bool+is_tag pinfo = take 4 (just_name pinfo) == "TAG "++get_tags_right :: RL (RL (PatchInfoAnd p)) C(x y) -> [PatchInfo]+get_tags_right NilRL = []+get_tags_right (ps:<:_) = get_tags_r (mapRL info_and_deps ps)+    where+    get_tags_r :: [(PatchInfo, Maybe [PatchInfo])] -> [PatchInfo]+    get_tags_r [] = []+    get_tags_r (hp:pps) = case snd hp of+                          Just ds -> fst hp : get_tags_r (drop_tags_r ds pps)+                          Nothing -> fst hp : get_tags_r pps++    drop_tags_r :: [PatchInfo]+                -> [(PatchInfo, Maybe [PatchInfo])] -> [(PatchInfo, Maybe [PatchInfo])]+    drop_tags_r [] pps = pps+    drop_tags_r _  []  = []+    drop_tags_r ds (hp:pps)+        | fst hp `elem` ds = case snd hp of+                             Just ds' -> drop_tags_r (ds'++delete (fst hp) ds) pps+                             Nothing -> drop_tags_r (delete (fst hp) ds) pps+        | otherwise = hp : drop_tags_r ds pps+                      +    info_and_deps :: PatchInfoAnd p C(x y) -> (PatchInfo, Maybe [PatchInfo])+    info_and_deps p +        | is_tag (info p) = (info p, getdeps `fmap` hopefullyM p)+        | otherwise = (info p, Nothing)+\end{code}++\begin{code}+deep_optimize_patchset :: PatchSet p C(x) -> PatchSet p C(x)+deep_optimize_patchset pss = optimize_patchset (concatRL pss :<: NilRL)++optimize_patchset :: PatchSet p C(x) -> PatchSet p C(x)+optimize_patchset NilRL = NilRL+optimize_patchset (ps:<:pss) = opsp ps +<+ pss+  where +        opsp :: RL (PatchInfoAnd p) C(x y) -> RL (RL (PatchInfoAnd p)) C(x y)+        opsp NilRL = NilRL+        opsp (hp:<:pps)+             | is_tag (info hp) && get_tags_right ((hp:<:pps):<:NilRL) == [info hp]+                 = (hp:<:NilRL) :<: opsp pps+             | otherwise = hp -:- opsp pps++(-:-) :: (PatchInfoAnd p) C(x y) -> RL (RL (PatchInfoAnd p)) C(a x) -> RL (RL (PatchInfoAnd p)) C(a y)+pp -:- NilRL = (pp:<:NilRL) :<: NilRL+pp -:- (p:<:ps) = ((pp:<:p) :<: ps)++slightly_optimize_patchset :: PatchSet p C(x) -> PatchSet p C(x)+slightly_optimize_patchset NilRL = NilRL+slightly_optimize_patchset (ps:<:pss) = sops (progressRL "Optimizing inventory" ps) +<+ pss+    where sops :: RL (PatchInfoAnd p) C(x y) -> RL (RL (PatchInfoAnd p)) C(x y)+          sops NilRL = NilRL+          sops (pinfomp :<: NilRL) = (pinfomp :<: NilRL) :<: NilRL+          sops (hp:<:pps) | is_tag (info hp) = if get_tags_right ((hp:<:pps):<:NilRL) == [info hp]+                                               then (hp:<:NilRL) :<: (pps:<: NilRL)+                                               else hp -:- sops (progressRL "Optimizing inventory" pps)+                          | otherwise = hp -:- sops pps+\end{code}++\begin{code}+commute_to_end :: forall p C(x y). RepoPatch p => FL (Named p) C(x y) -> PatchSet p C(y)+               -> (FL (Named p) :< RL (RL (PatchInfoAnd p))) C(() x)+commute_to_end select from = ctt (mapFL patch2patchinfo select) from NilFL+   where+-- In order to preserve the structure of the original PatchSet, we commute+-- the patches we are going to throw away past the patches we plan to keep.+-- This puts them at the end of the PatchSet where it is safe to discard them.+-- We return all the patches in the PatchSet which have been commuted.+      ctt :: [PatchInfo] -> PatchSet p C(v) -> FL (Named p) C(v u)+          -> (FL (Named p) :< RL (RL (PatchInfoAnd p))) C(() x)+      -- This unsafeCoerceP should be fine, because if we run out of+      -- patches in the selection the ending context of the second param+      -- should be x (because we have commute all of the selected sequence,+      -- with context C(x y), past the elements of the second parameter.+      -- Unfortunately this is hard to express in the type system while+      -- using an accumulator to build up the return value.+      ctt [] ps acc = (unsafeCoerceP acc) :< ps+      ctt sel (NilRL:<:ps) acc = ctt sel ps acc+      ctt sel ((hp:<:hps):<:ps) acc+         | info hp `elem` sel+            = case commuteFL (hopefully hp :> acc) of+              Nothing -> bug "patches to commute_to_end does not commutex (1)"+              Just (acc' :> _) -> ctt (delete (info hp) sel) (hps:<:ps) acc'+         | otherwise+            = ctt sel (hps:<:ps) (hopefully hp:>:acc)+      ctt _ _ _ = bug "patches to commute_to_end does not commutex (2)"+\end{code}++\begin{code}+patchset_intersection :: RepoPatch p => [SealedPatchSet p] -> SealedPatchSet p+patchset_intersection [] = seal (NilRL :<: NilRL)+patchset_intersection [x] = x+patchset_intersection (Sealed y:ys) = +    case patchset_intersection ys of+    Sealed ys' -> with_partial_intersection y ys' $+      \common a b -> +          case mapRL info a `intersect` mapRL info b of+          morecommon -> +              case partitionRL (\e -> info e `elem` morecommon) a of+                commonps :> _ -> seal $ commonps :<: common++patchset_union :: RepoPatch p => [SealedPatchSet p] -> SealedPatchSet p+patchset_union [] = seal (NilRL :<: NilRL)+patchset_union [x] = x+patchset_union (Sealed y:ys) = +    case patchset_union ys of+    Sealed ys' -> with_partial_intersection y ys' $+      \common a b ->+        case gcau_simple a b of+        Left e -> missingPatchError e+        Right (_, (a' :<: NilRL) :\/: (b' :<: NilRL)) -> +          case (merge_sets (a' :\/: b')) of+          Sealed a'b' -> seal $ (a'b' +<+ b) :<: common+        _ -> impossible++merge_sets :: RepoPatch p => (RL (PatchInfoAnd p) :\/: RL (PatchInfoAnd p)) C(x y) -> Sealed (RL (PatchInfoAnd p) C(y))+merge_sets (l :\/: r) =+    let pl = mapFL_FL hopefully $ reverseRL l+        pr = mapFL_FL hopefully $ reverseRL r+        p2pimp p = patch2patchinfo p `piap` p+    in case merge (pl:\/: pr) of+       (_:/\:pl') -> seal $ reverseFL $ mapFL_FL p2pimp pl'+\end{code}
+ src/Darcs/Patch/Info.lhs view
@@ -0,0 +1,315 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.Patch.Info ( PatchInfo, patchinfo, invert_name, is_inverted,+                          idpatchinfo,+                          make_filename, make_alt_filename, readPatchInfo,+                          just_name, just_author, repopatchinfo, RepoPatchInfo,+                          human_friendly, to_xml, pi_date, set_pi_date,+                          pi_name, pi_rename, pi_author, pi_tag, pi_log,+                          showPatchInfo,+                        ) where+import Text.Html hiding (name, text)+import FastPackedString+import Printer ( renderString, Doc, packedString,+                 empty, ($$), (<>), (<+>), vcat, text, blueText, prefix )+import OldDate ( readUTCDate, showIsoDateTime )+import System.Time ( CalendarTime(ctTZ), calendarTimeToString, toClockTime,+                     toCalendarTime )+import System.IO.Unsafe ( unsafePerformIO )+import SHA1 ( sha1PS )+import Prelude hiding (pi, log)++data RepoPatchInfo = RPI String PatchInfo++repopatchinfo :: String -> PatchInfo -> RepoPatchInfo+repopatchinfo r pi = RPI r pi++data PatchInfo = PatchInfo { _pi_date    :: !PackedString+                           , _pi_name    :: !PackedString+                           , _pi_author  :: !PackedString+                           , _pi_log     :: ![PackedString]+                           , is_inverted :: !Bool+                           }+                 deriving (Eq,Ord)++idpatchinfo :: PatchInfo+idpatchinfo = patchinfo "identity" "identity" "identity" []++patchinfo :: String -> String -> String -> [String] -> PatchInfo+patchinfo date name author log =+    PatchInfo { _pi_date = packString date+              , _pi_name = packString name+              , _pi_author = packString author+              , _pi_log = map packString log+              , is_inverted = False }+\end{code}++\section{Patch info formatting}+++\begin{code}+invert_name :: PatchInfo -> PatchInfo+invert_name pi = pi { is_inverted = not (is_inverted pi) }+\end{code}++\begin{code}+just_name :: PatchInfo -> String+just_name pinf = if is_inverted pinf then "UNDO: " ++ unpackPS (_pi_name pinf)+                                     else unpackPS (_pi_name pinf)++just_author :: PatchInfo -> String+just_author = unpackPS . _pi_author++human_friendly :: PatchInfo -> Doc+human_friendly pi =+    text (friendly_d $ _pi_date pi) <> text "  " <> packedString (_pi_author pi)+ $$ hfn (_pi_name pi)+ $$ vcat (map ((text "  " <>) . packedString) (_pi_log pi))+  where hfn x = case pi_tag pi of+                Nothing -> inverted <+> packedString x+                Just t -> text "  tagged" <+> text t+        inverted = if is_inverted pi then text "  UNDO:" else text "  *"++-- note the difference with just_name+pi_name :: PatchInfo -> String+pi_name = unpackPS . _pi_name++pi_rename :: PatchInfo -> String -> PatchInfo+pi_rename x n = x { _pi_name = packString n }++pi_author :: PatchInfo -> String+pi_author = unpackPS . _pi_author++-- | Note: we ignore timezone information in the date string,+--   systematically treating a time as UTC.  So if the patch+--   tells me it's 17:00 EST, we're actually treating it as+--   17:00 UTC, in other words 11:00 EST.  This is for+--   backwards compatibility to darcs prior to 2003-11, sometime+--   before 1.0.  Fortunately, newer patch dates are written in+--   UTC, so this timezone truncation is harmless for them.+readPatchDate :: PackedString -> CalendarTime+readPatchDate = ignoreTz . readUTCDate . unpackPS+  where ignoreTz ct = ct { ctTZ = 0 }++pi_date :: PatchInfo -> CalendarTime+pi_date = readPatchDate . _pi_date++set_pi_date :: String -> PatchInfo -> PatchInfo+set_pi_date date pi = pi { _pi_date = packString date }++pi_log :: PatchInfo -> [String]+pi_log = map unpackPS . _pi_log++pi_tag :: PatchInfo -> Maybe String+pi_tag pinf =+    if l == t+      then Just $ unpackPS r+      else Nothing+    where (l, r) = splitAtPS (lengthPS t) (_pi_name pinf)+          t = packString "TAG "++friendly_d :: PackedString -> String+--friendly_d d = calendarTimeToString . readPatchDate . d+friendly_d d = unsafePerformIO $ do+    ct <- toCalendarTime $ toClockTime $ readPatchDate d+    return $ calendarTimeToString ct+\end{code}++\begin{code}+to_xml :: PatchInfo -> Doc+to_xml pi =+        text "<patch"+    <+> text "author='" <> escapeXML (just_author pi) <> text "'"+    <+> text "date='" <> escapeXML (unpackPS $ _pi_date pi) <> text "'"+    <+> text "local_date='" <> escapeXML (friendly_d $ _pi_date pi) <> text "'"+    <+> text "inverted='" <> text (show $ is_inverted pi) <> text "'"+    <+> text "hash='" <> text (make_filename pi) <> text "'>"+ $$     prefix "\t" (+            text "<name>" <> escapeXML (pi_name pi) <> text "</name>"+         $$ comments_as_xml (_pi_log pi))+ $$     text "</patch>"++comments_as_xml :: [PackedString] -> Doc+comments_as_xml comments+  | lengthPS comments' > 0 = text "<comment>"+                          <> escapeXML (unpackPS comments')+                          <> text "</comment>"+  | otherwise = empty+    where comments' = unlinesPS comments++-- escapeXML is duplicated in Patch.lhs and Annotate.lhs+-- It should probably be refactored to exist in one place.+escapeXML :: String -> Doc+escapeXML = text . strReplace '\'' "&apos;" . strReplace '"' "&quot;" .+  strReplace '>' "&gt;" . strReplace '<' "&lt;" . strReplace '&' "&amp;"+++strReplace :: Char -> String -> String -> String+strReplace _ _ [] = []+strReplace x y (z:zs)+  | x == z    = y ++ (strReplace x y zs)+  | otherwise = z : (strReplace x y zs)+\end{code}++\begin{code}+make_alt_filename :: PatchInfo -> String+make_alt_filename pi@(PatchInfo { is_inverted = False }) =+    fix_up_fname (midtrunc (pi_name pi)++"-"++just_author pi++"-"++unpackPS (_pi_date pi))+make_alt_filename pi@(PatchInfo { is_inverted = True}) =+    make_alt_filename (pi { is_inverted = False }) ++ "-inverted"++make_filename :: PatchInfo -> String+make_filename pi =+    showIsoDateTime d++"-"++sha1_a++"-"++sha1PS sha1_me++".gz"+        where b2ps True = packString "t"+              b2ps False = packString "f"+              sha1_me = concatPS [_pi_name pi,+                                  _pi_author pi,+                                  _pi_date pi,+                                  concatPS $ _pi_log pi,+                                  b2ps $ is_inverted pi]+              d = readPatchDate $ _pi_date pi+              sha1_a = take 5 $ sha1PS $ _pi_author pi++midtrunc :: String -> String+midtrunc s+    | length s < 73 = s+    | otherwise = (take 40 s)++"..."++(reverse $ take 30 $ reverse s)+fix_up_fname :: String -> String+fix_up_fname = map munge_char++munge_char :: Char -> Char+munge_char '*' = '+'+munge_char '?' = '2'+munge_char '>' = '7'+munge_char '<' = '2'+munge_char ' ' = '_'+munge_char '"' = '~'+munge_char '`' = '.'+munge_char '\'' = '.'+munge_char '/' = '1'+munge_char '\\' = '1'+munge_char '!' = '1'+munge_char ':' = '.'+munge_char ';' = ','+munge_char '{' = '~'+munge_char '}' = '~'+munge_char '(' = '~'+munge_char ')' = '~'+munge_char '[' = '~'+munge_char ']' = '~'+munge_char '=' = '+'+munge_char '#' = '+'+munge_char '%' = '8'+munge_char '&' = '6'+munge_char '@' = '9'+munge_char '|' = '1'+munge_char  c  =  c+\end{code}+++\begin{code}+instance  HTML RepoPatchInfo  where+    toHtml = htmlPatchInfo+instance  Show PatchInfo  where+    show pi = renderString (showPatchInfo pi)+\end{code}++\paragraph{Patch info}+Patch is stored between square brackets.+\begin{verbatim}+[ <patch name>+<patch author>*<patch date>+ <patch log (may be empty)> (indented one)+ <can have multiple lines in patch log,>+ <as long as they're preceded by a space>+ <and don't end with a square bracket.>+]+\end{verbatim}+\begin{code}+-- note that below I assume the name has no newline in it.+showPatchInfo :: PatchInfo -> Doc+showPatchInfo pi =+    blueText "[" <> packedString (_pi_name pi)+ $$ packedString (_pi_author pi) <> text inverted <> packedString (_pi_date pi)+                                 <> myunlines (_pi_log pi) <> blueText "] "+    where inverted = if is_inverted pi then "*-" else "**"+          myunlines [] = empty+          myunlines xs = mul xs+              where mul [] = text "\n"+                    mul (s:ss) = text "\n " <> packedString s <> mul ss++readPatchInfo :: PackedString -> Maybe (PatchInfo, PackedString)+readPatchInfo s | nullPS (dropWhitePS s) = Nothing+readPatchInfo s =+    if headPS (dropWhitePS s) /= '[' -- ]+    then Nothing+    else case breakOnPS '\n' $ tailPS $ dropWhitePS s of+         (name,s') ->+             case breakOnPS '*' $ tailPS s' of+             (author,s2) ->+                 case breakPS (\c->c==']'||c=='\n') $ dropPS 2 s2 of+                 (ct,s''') ->+                     do (log, s4) <- lines_starting_with_ending_with ' ' ']' $ dn s'''+                        return $ (PatchInfo { _pi_date = ct+                                            , _pi_name = name+                                            , _pi_author = author+                                            , _pi_log = log+                                            , is_inverted = indexPS s2 1 /= '*'+                                            }, s4)+    where dn x = if nullPS x || headPS x /= '\n' then x else tailPS x+\end{code}++\begin{code}+lines_starting_with_ending_with :: Char -> Char -> PackedString+                                -> Maybe ([PackedString],PackedString)+lines_starting_with_ending_with st en s = lswew s+    where+  lswew x | nullPS x = Nothing+  lswew x =+    if headPS x == en+    then Just ([], tailPS x)+    else if headPS x /= st+         then Nothing+         else case breakOnPS '\n' $ tailPS x of+              (l,r) -> case lswew $ tailPS r of+                       Just (ls,r') -> Just (l:ls,r')+                       Nothing ->+                           case breakLastPS en l of+                           Just (l2,_) ->+                               Just ([l2], dropPS (lengthPS l2+2) x)+                           Nothing -> Nothing+\end{code}++\begin{code}+htmlPatchInfo :: RepoPatchInfo -> Html+htmlPatchInfo (RPI r pi) =+    toHtml $ (td << patch_link r pi) `above`+               ((td ! [align "right"] << mail_link (just_author pi)) `beside`+                (td << (friendly_d $ _pi_date pi)))++patch_link :: String -> PatchInfo -> Html+patch_link r pi =+    toHtml $ hotlink+               ("darcs?"++r++"**"++make_filename pi)+               [toHtml $ pi_name pi]+mail_link :: String -> Html+mail_link email = toHtml $ hotlink ("mailto:"++email) [toHtml email]+\end{code}+
+ src/Darcs/Patch/Match.lhs view
@@ -0,0 +1,284 @@+%  Copyright (C) 2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.Patch.Match ( PatchMatch, Matcher,+                    patch_match, match_pattern,+                    apply_matcher, make_matcher,+                    parseMatch,+                    match_parser, helpOnMatchers,+                  ) where++import Text.ParserCombinators.Parsec+import Text.ParserCombinators.Parsec.Expr+import Text.Regex ( mkRegex, matchRegex )+import Data.Maybe ( isJust )+import System.IO.Unsafe ( unsafePerformIO )++import Darcs.Hopefully ( PatchInfoAnd, info )+import Darcs.Patch.Info ( just_name, just_author, make_filename,+                          pi_date )+import DateMatcher ( parseDateMatcher )++import Darcs.Patch.MatchData ( PatchMatch(..), patch_match )++data Matcher p C(x y) = MATCH String (PatchInfoAnd p C(x y) -> Bool)++instance Show (Matcher p C(x y)) where+    show (MATCH s _) = '"':s ++ "\""++make_matcher :: String -> (PatchInfoAnd p C(x y) -> Bool) -> Matcher p C(x y)+make_matcher s m = MATCH s m++apply_matcher :: Matcher p C(x y) -> PatchInfoAnd p C(x y) -> Bool+apply_matcher (MATCH _ m) = m++parseMatch :: PatchMatch -> Either String (PatchInfoAnd p C(x y) -> Bool)+parseMatch (PatternMatch s) =+    case parse match_parser "match" s of+    Left err -> Left $ "Invalid -"++"-match pattern '"++s+++                "'.\n"++ unlines (map ("    "++) $ lines $ show err) -- indent+    Right m -> Right m++match_pattern :: PatchMatch -> Matcher p C(x y)+match_pattern p@(PatternMatch s) =+    case parseMatch p of+    Left err -> error err+    Right m -> MATCH s m+\end{code}++\paragraph{Match}++Currently \verb!--match! accepts five primitive match types, although+there are plans to expand it to match more patterns.  Also, note that the+syntax is still preliminary and subject to change.++The first match type accepts a literal string which is checked against+the patch name.  The syntax is+\begin{verbatim}+darcs annotate --summary --match 'exact foo+bar'+\end{verbatim}+This is useful for situations where a patch name contains characters that+could be considered special for regular expressions.++In this and the other match types, the argument must be enclosed in double+quotes if it contains spaces.  You can escape a quote in the argument with a+backslash; backslash escapes itself, but it is treated literally if followed+by a character other than a double quote or backslash, so it is typically not+necessary to escape a backslash.  No such escaping is necessary unless the+argument is enclosed in double quotes.++The second match type accepts a regular expression which is checked against+the patch name.  The syntax is+\begin{verbatim}+darcs annotate --summary --match 'name foo'+\end{verbatim}+Note that to match regexp metacharacters, such as \verb|(|, literally, they+must be escaped with backslash along with any embedded double quotes.  To+match a literal backslash it must be written quadrupled in general, but often+it need not be escaped, since backslash is only special in regexps when+followed by a metacharacter.  In the following example pairs, the first+literal is matched by the second sequence in the match name:+``\verb|"|'':``\verb|\"|'', ``\verb|\|'':``\verb|\\\\|'',+``\verb|\x|'':``\verb|\x|'', ``\verb|(|'':``\verb|\(|''.++The third match type matches the darcs hash for each patch:+\begin{verbatim}+darcs annotate --summary --match \+  'hash 20040403105958-53a90-c719567e92c3b0ab9eddd5290b705712b8b918ef'+\end{verbatim}+Note you need to provide the full hash string as above. +This is intended to be used, for example, by programs allowing you to view+darcs repositories (e.g.\ CGI scripts like viewCVS).++The fourth match type accepts a regular expression which is checked against+the patch author.  The syntax is+\begin{verbatim}+darcs annotate --summary --match 'author foo'+\end{verbatim}++There is also support for matching by date.  This is done using commands such as+\begin{verbatim}+darcs annotate --summary --match 'date "last week"'+darcs annotate --summary --match 'date yesterday'+darcs annotate --summary --match 'date "today 14:00"'+darcs annotate --summary --match 'date "tea time yesterday"'+darcs annotate --summary --match 'date "3 days before last year at 17:00"'+darcs changes --from-match 'date "Sat Jun  30 11:31:30 EDT 2004"'+\end{verbatim}++Notes: when matching on the ISO format, a partial date is treated as a range.+English dates can either refer to a specific day (``6 months ago',``day before+yesterday''), or to an interval+from some past date (``last month'') to the present.  Putting this all+together, if today is ``2004-07-24'' then the following matches should work:++\begin{tabular}{|ll|}+\hline+\textbf{date} & \textbf{patches selected} \\+\hline+2004          & from 2004-01-01 up to and including 2004-12-31 \\+2004-01       & from 2004-01-01 up to and including 2004-01-31 \\+2004-01-01    & during 2004-01-01 \\+\hline+today         & during 2004-07-24 (starting midnight in your timezone) \\+yesterday     & during 2004-07-23 \\+6 months ago  & during 2004-01-23 \\+\hline+last 6 months & since  2004-01-23 \\+last month    & since  2004-06-23 (not 2004-06-01!) \\+last week     & since  2004-07-16 \\+\hline+\end{tabular}++For more precise control, you may specify an interval, either+in a small subset of English or+of \htmladdnormallinkfoot{the ISO 8601 format}{http://www.w3.org/TR/NOTE-datetime}.+If you use the ISO format, note that durations, when+specified alone, are interpreted as being relative to the current date and time.+\begin{verbatim}+darcs annotate --summary --match 'date "between 2004-03-12 and last week"'+darcs annotate --summary --match 'date "after 2005"'+darcs annotate --summary --match 'date "in the last 3 weeks"'+darcs annotate --summary --match 'date "P3M/2006-03-17"'+darcs annotate --summary --match 'date "2004-01-02/2006-03-17"'+darcs annotate --summary --match 'date "P2M6D"'+\end{verbatim}++You may also prefer to combine date matching with a more specific pattern.+\begin{verbatim}+darcs annotate --summary --match 'date "last week" && name foo'+\end{verbatim}++The \verb!--match! pattern can include the logical operators \verb!&&!,+\verb!||! and \verb!not!, as well as grouping of patterns with parentheses.+For example+\begin{verbatim}+darcs annotate --summary --match 'name record && not name overrode'+\end{verbatim}++\begin{code}+match_parser :: CharParser st (PatchInfoAnd p C(x y) -> Bool)+match_parser = do m <- submatch+                  eof+                  return m++submatch :: CharParser st (PatchInfoAnd p C(x y) -> Bool)+submatch = buildExpressionParser table match <?> "match rule"++table :: OperatorTable Char st (PatchInfoAnd p C(x y) -> Bool)+table   = [ [prefix "not" negate_match,+             prefix "!" negate_match ]+          , [binary "||" or_match,+             binary "or" or_match,+             binary "&&" and_match,+            binary "and" and_match ]+          ]+    where binary name fun =+              Infix (do trystring name+                        spaces+                        return fun) AssocLeft+          prefix  name fun = Prefix $ do trystring name+                                         spaces+                                         return fun+          negate_match a p = not (a p)+          or_match m1 m2 p = (m1 p) || (m2 p)+          and_match m1 m2 p = (m1 p) && (m2 p)++trystring :: String -> CharParser st String+trystring s = try $ string s++match :: CharParser st (PatchInfoAnd p C(x y) -> Bool)+match = between spaces spaces+        (parens submatch+         <|> choice matchers_+         <?> "simple match")+        where matchers_ = map createMatchHelper primitiveMatchers++type MatchHelper p C(x y) = PatchInfoAnd p C(x y) -> Bool++createMatchHelper :: (String, String, [String], String -> MatchHelper p C(x y))+                  -> CharParser st (MatchHelper p C(x y))+createMatchHelper (key,_,_,matcher) =+  do trystring key+     spaces+     q <- quoted+     return $ matcher q++helpOnMatchers :: String+helpOnMatchers =+  let blurb :: (String, String, [String], String -> MatchHelper p C(x y)) -> String+      blurb (key, help, examples, _) =+        "'" ++ key ++ "' " ++ help +++        ", e.g.:\n" ++ (unlines $ map (mkExample key) examples)+      mkExample key x =+        "  darcs annotate --summary --match '" ++ key ++ " " ++ x ++ "'"+  in "Matching patches:\n"+     ++ (unlines $ map blurb primitiveMatchers) ++ "\n"+     ++ "You can also use logical operators 'and', '&&', 'or', '||', 'not', '!'"+     ++ " to combine match expressions, as well as parentheses for grouping. "+     ++ " For more details on matching, see the manual."++primitiveMatchers :: [(String, String, [String], String -> MatchHelper p C(x y))]+primitiveMatchers =+ [ ("exact", "checks a literal string against the patch name"+           , ["\"my most excellent patch\""]+           , exactmatch )+ , ("name", "checks a regular expression against the patch name"+          , ["[eE]xcellent"]+          , mymatch )+ , ("author", "checks a regular expression against the author name"+            , ["foo@bar"]+            , authormatch )+ , ("hash",  "matches the darcs hash for a patch"+          ,  ["20040403105958-53a90-c719567e92c3b0ab9eddd5290b705712b8b918ef"]+          ,  hashmatch )+ , ("date", "matches the patch date"+          , ["\"tea time yesterday\"", "\"2006-04-02 22:41\""]+          , datematch ) ]++parens :: CharParser st (PatchInfoAnd p C(x y) -> Bool)+       -> CharParser st (PatchInfoAnd p C(x y) -> Bool)+parens p  = between (string "(") (string ")") p++quoted :: CharParser st String+quoted = between (char '"') (char '"')+                 (many $ do { char '\\' -- allow escapes+                            ; try (oneOf ['\\', '"']) <|> return '\\'+                            }+                         <|>  noneOf ['"'])+         <|> between spaces spaces (many $ noneOf " ()")+         <?> "string"+\end{code}++\begin{code}+mymatch, exactmatch, authormatch, hashmatch, datematch :: String -> MatchHelper p C(x y)++mymatch r hp = isJust $ matchRegex (mkRegex r) $ just_name (info hp)++exactmatch r hp = r == (just_name (info hp))++authormatch a hp = isJust $ matchRegex (mkRegex a) $ just_author (info hp)++hashmatch h hp = let rh = make_filename (info hp) in+                        (rh == h) || (rh == h++".gz")++datematch d hp = let dm = unsafePerformIO $ parseDateMatcher d+                        in dm $ pi_date (info hp)+\end{code}
+ src/Darcs/Patch/MatchData.lhs view
@@ -0,0 +1,30 @@+%  Copyright (C) 2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.Patch.MatchData ( PatchMatch(..), patch_match,+                      ) where++data PatchMatch = PatternMatch String+                  deriving ( Eq )++instance Show PatchMatch where+    show (PatternMatch m) = "pattern " ++ show m++patch_match :: String -> PatchMatch+patch_match s = PatternMatch s+\end{code}
+ src/Darcs/Patch/Non.lhs view
@@ -0,0 +1,182 @@+%  Copyright (C) 2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\section{``NonPatch'' patches}++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans #-}+#include "gadts.h"+module Darcs.Patch.Non+       ( NonPatch, Non(..), Nonable(..), unNon,+         showNon, readNon, showNons, readNons,+         add, rem, addP, remP, addPs, remPs, remAddP, remAddPs, remNons,+         (*>), (>*), (*>>), (>>*),+         prop_adjust_twice ) where++import Prelude hiding ( rem )+import Data.List ( delete )+import Control.Monad ( liftM )+import Darcs.Patch.Prim ( Prim, FromPrim(..), ToFromPrim(..), Effect(..),+                          showPrim, FileNameFormat(..), sort_coalesceFL )+import Darcs.Patch.Patchy+import Darcs.Patch.ReadMonads ( ParserM, lex_char )+import Darcs.Patch.Ordered+import Darcs.Patch.Read ( readPrim )+import Darcs.Patch.Viewing ()+import Darcs.Patch.Permutations ( removeFL, commuteWhatWeCanFL )+import Darcs.Show+import Darcs.Sealed ( Sealed(Sealed) )+import Printer ( Doc, empty, vcat, hiddenPrefix, blueText, redText, ($$) )++--import Darcs.ColorPrinter ( traceDoc )+--import Printer ( greenText )++showNons :: ShowPatch (FL p) => [Non p C(x)] -> Doc+showNons [] = empty+showNons xs = blueText "{{" $$ vcat (map showNon xs) $$ blueText "}}"++showNon :: ShowPatch (FL p) => Non p C(x) -> Doc+showNon (Non c p) = hiddenPrefix "|" (showPatch c)+                    $$ hiddenPrefix "|" (blueText ":")+                    $$ showPrim NewFormat p++readNons :: (ReadPatch p, ParserM m) => m [Non p C(x)]+readNons = peekfor "{{" rns (return [])+    where rns = peekfor "}}" (return []) $+                do Just (Sealed ps) <- readPatch' False+                   lex_char ':'+                   Just (Sealed p) <- readPrim NewFormat False+                   (Non ps p :) `liftM` rns++readNon :: (ReadPatch p, ParserM m) => m (Maybe (Non p C(x)))+readNon = do Just (Sealed ps) <- readPatch' False+             peekfor ":" (do Just (Sealed p) <- readPatch' False+                             return $ Just $ Non ps p)+                         (return Nothing)++instance (Commute p, MyEq p) => Eq (Non p C(x)) where+    (Non cx x) == (Non cy y) | IsEq <- cx =\/= cy,+                               IsEq <- x =\/= y = True+                             | otherwise = False++data Non p C(x) where+    Non :: FL p C(a x) -> Prim C(x y) -> Non p C(a)++type NonPatch C(x) = Non Prim C(x)++unNon :: FromPrim p => Non p C(x) -> Sealed (FL p C(x))+unNon (Non c x) = Sealed (c +>+ fromPrim x :>: NilFL)++class Nonable p where+    non :: p C(x y) -> Non p C(x)++addP :: (Patchy p, ToFromPrim p) => p C(x y) -> Non p C(y) -> Non p C(x)+addP p n | Just n' <- p >* n = n'+addP p (Non c x) = Non (p:>:c) x++addPs :: (Patchy p, ToFromPrim p) => RL p C(x y) -> Non p C(y) -> Non p C(x)+addPs NilRL n = n+addPs (p:<:ps) n = addPs ps $ addP p n++add :: (Effect q, Patchy p, ToFromPrim p) => q C(x y) -> Non p C(y) -> Non p C(x)+add q = addPs (mapRL_RL fromPrim $ effectRL q)++-- remNons really only works right if the relevant nons are conflicting...+remNons :: (Nonable p, Effect p, Patchy p, ToFromPrim p, ShowPatch p) => [Non p C(x)] -> Non p C(x) -> Non p C(x)+remNons ns (Non c x) = case remNonHelper ns c of+                       NilFL :> c' -> Non c' x+                       _ -> Non c x++remNonHelper :: (Nonable p, Effect p, Patchy p, ToFromPrim p) => [Non p C(x)] -> FL p C(x y)+             -> (FL Prim :> FL p) C(x y)+remNonHelper [] x = NilFL :> x+remNonHelper ns (c:>:cs)+    | non c `elem` ns = case remNonHelper (map (addP $ invert c) $ delete (non c) ns) cs of+                        a :> z -> sort_coalesceFL (effect c+>+a) :> z+    | otherwise = case commuteWhatWeCanFL (c :> cs) of+                  b :> c' :> d ->+                      case remNonHelper ns b of+                      a :> b' -> a :> (b'+>+c':>:d)+remNonHelper _ NilFL = NilFL :> NilFL++remP :: (Patchy p, ToFromPrim p) => p C(x y) -> Non p C(x) -> Maybe (Non p C(y))+remP p n | Just n' <- n *> p = Just n'+remP p (Non pc x) = do c <- removeFL p pc+                       return (Non c x)++remPs :: (Patchy p, ToFromPrim p) => FL p C(x y) -> Non p C(x) -> Maybe (Non p C(y))+remPs NilFL n = Just n+remPs (p:>:ps) n = remP p n >>= remPs ps++rem :: (Effect q, Patchy p, ToFromPrim p) => q C(x y) -> Non p C(x) -> Maybe (Non p C(y))+rem q = remPs (mapFL_FL fromPrim $ effect q)++remAddP :: (Patchy p, ToFromPrim p) => p C(x y) -> Non p C(y) -> Non p C(x)+remAddP p n = maybe (addP p n) id $ remP (invert p) n++remAddPs :: (Patchy p, ToFromPrim p) => RL p C(x y) -> Non p C(y) -> Non p C(x)+remAddPs NilRL n = n+remAddPs (x:<:xs) n = remAddPs xs $ remAddP x n++(*>) :: (Patchy p, ToFromPrim p) => Non p C(x) -> p C(x y) -> Maybe (Non p C(y))+n *> p = invert p >* n++(>*) :: (Patchy p, ToFromPrim p) => p C(x y) -> Non p C(y) -> Maybe (Non p C(x))+y >* (Non c x) = do c' :> y' <- commuteFL (y :> c)+                    px' :> _ <- commute (y' :> fromPrim x)+                    x' <- toPrim px'+                    return (Non c' x')++(*>>) :: (Effect q, Patchy q, Patchy p, ToFromPrim p) => Non p C(x) -> q C(x y) -> Maybe (Non p C(y))+n *>> p = invert p >>* n++(>>*) :: (Effect q, Patchy p, ToFromPrim p) => q C(x y) -> Non p C(y) -> Maybe (Non p C(x))+q >>* nn = adj (effectRL q) nn+    where adj :: (Patchy p, ToFromPrim p) => RL Prim C(x y) -> Non p C(y) -> Maybe (Non p C(x))+          adj NilRL n = Just n+          adj (x:<:xs) n = fromPrim x >* n >>= adj xs++prop_adjust_twice :: (Patchy p, ToFromPrim p) => p C(x y) -> Non p C(y) -> Maybe Doc+prop_adjust_twice p n =+    do n' <- p >* n+       case n' *> p of+         Nothing -> Just (redText "prop_adjust_inverse 1")+         Just n'' | n'' /= n -> Just (redText "prop_adjust_inverse 2")+         _ -> case n *> invert p of+              Nothing -> Just (redText "prop_adjust_inverse 3")+              Just n'' | n'' /= n' -> Just (redText "prop_adjust_inverse 4")+              _ -> case invert p >* n' of+                   Nothing -> Just (redText "prop_adjust_inverse 5")+                   Just n'' | n'' /= n -> Just (redText "prop_adjust_inverse 6")+                   _ -> Nothing+                                   ++instance Nonable Prim where+    non = Non NilFL++instance Show2 p => Show (Non p C(x)) where+    showsPrec = showsPrec1++instance Show2 p => Show1 (Non p) where+    showsPrec1 d (Non cs p) = showParen (d > app_prec) $ showString "Non " .+                              showsPrec2 (app_prec + 1) cs . showString " " .+                              showsPrec (app_prec + 1) p++instance Patchy Prim++\end{code}
+ src/Darcs/Patch/Ordered.lhs view
@@ -0,0 +1,260 @@+%  Copyright (C) 2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Patch.Ordered ( EqCheck(..), isEq, (:>)(..), (:<)(..), (:\/:)(..), (:/\:)(..),+                             FL(..), RL(..),Proof(..),+#ifndef GADT_WITNESSES+                             unsafeUnFL, unsafeFL, unsafeRL, unsafeUnRL,+#endif+                             lengthFL, mapFL, mapFL_FL, spanFL, foldlFL, allFL,+                             splitAtFL, bunchFL, foldlRL,+                             lengthRL, mapRL, mapRL_RL, zipWithFL,+                             unsafeMap_l2f, filterE, filterFL,+                             reverseFL, reverseRL, (+>+), (+<+),+                             nullFL, concatFL, concatRL, concatReverseFL, headRL,+                             MyEq, unsafeCompare, (=\/=), (=/\=),+                             unsafeCoerceP+                           ) where++#include "impossible.h"+import GHC.Base (unsafeCoerce#)+import Darcs.Show+import Darcs.Sealed ( FlippedSeal(..), flipSeal )++data EqCheck C(a b) where+    IsEq :: EqCheck C(a a)+    NotEq :: EqCheck C(a b)++instance Eq (EqCheck C(a b)) where+    IsEq == IsEq = True+    NotEq == NotEq = True+    _ == _ = False++isEq :: EqCheck C(a b) -> Bool+isEq IsEq = True+isEq NotEq = False++instance Show (EqCheck C(a b)) where+    show IsEq = "IsEq"+    show NotEq = "NotEq"++data Proof a C(x y) where+    Proof :: a -> Proof a C(x x)++data (a1 :> a2) C(x y) = FORALL(z) (a1 C(x z)) :> (a2 C(z y))+infixr 1 :>+data (a1 :< a2) C(x y) = FORALL(z) (a1 C(z y)) :< (a2 C(x z))+infix 1 :<+infix 1 :/\:, :\/:+data (a1 :\/: a2) C(x y) = FORALL(z) (a1 C(z x)) :\/: (a2 C(z y))+data (a1 :/\: a2) C(x y) = FORALL(z) (a1 C(x z)) :/\: (a2 C(y z))+class MyEq p where+    -- Minimal definition defines any one of unsafeCompare, =\/= and =/\=.+    unsafeCompare :: p C(a b) -> p C(c d) -> Bool+    unsafeCompare a b = IsEq == (a =/\= unsafeCoerceP b)+    (=\/=) :: p C(a b) -> p C(a c) -> EqCheck C(b c)+    a =\/= b | unsafeCompare a b = unsafeCoerceP IsEq+             | otherwise = NotEq+    (=/\=) :: p C(a c) -> p C(b c) -> EqCheck C(a b)+    a =/\= b | IsEq == (a =\/= unsafeCoerceP b) = unsafeCoerceP IsEq+             | otherwise = NotEq++infix 4 =\/=, =/\=++unsafeCoerceP :: a C(x y) -> a C(b c)+unsafeCoerceP = unsafeCoerce#++instance (Show2 a, Show2 b) => Show ( (a :> b) C(x y) ) where+    showsPrec d (x :> y) = showOp2 1 ":>" d x y++instance (Show2 a, Show2 b) => Show2 (a :> b) where+    showsPrec2 = showsPrec++instance (Show2 a, Show2 b) => Show ( (a :\/: b) C(x y) ) where+    showsPrec d (x :\/: y) = showOp2 9 ":\\/:" d x y++instance (Show2 a, Show2 b) => Show2 (a :\/: b) where+    showsPrec2 = showsPrec++infixr 5 :>:, :<:, +>+, +<+++-- forward list+data FL a C(x z) where+    (:>:) :: a C(x y) -> FL a C(y z) -> FL a C(x z)+    NilFL :: FL a C(x x)++instance Show2 a => Show (FL a C(x z)) where+   showsPrec _ NilFL = showString "NilFL"+   showsPrec d (x :>: xs) = showParen (d > prec) $ showsPrec2 (prec + 1) x .+                            showString " :>: " . showsPrec (prec + 1) xs+       where prec = 5++instance Show2 a => Show2 (FL a) where+   showsPrec2 = showsPrec++-- reverse list+data RL a C(x z) where+    (:<:) :: a C(y z) -> RL a C(x y) -> RL a C(x z)+    NilRL :: RL a C(x x)++nullFL :: FL a C(x z) -> Bool+nullFL NilFL = True+nullFL _ = False++filterFL :: (FORALL(x y) p C(x y) -> EqCheck C(x y)) -> FL p C(w z) -> FL p C(w z)+filterFL _ NilFL = NilFL+filterFL f (x:>:xs) | IsEq <- f x = filterFL f xs+                    | otherwise = x :>: filterFL f xs++filterE :: (a -> EqCheck C(x y)) -> [a] -> [Proof a C(x y)]+filterE _ [] = []+filterE p (x:xs)+    | IsEq <- p x = Proof x : filterE p xs+    | otherwise   = filterE p xs++(+>+) :: FL a C(x y) -> FL a C(y z) -> FL a C(x z)+NilFL +>+ ys = ys+(x:>:xs) +>+ ys = x :>: xs +>+ ys++(+<+) :: RL a C(y z) -> RL a C(x y) -> RL a C(x z)+NilRL +<+ ys = ys+(x:<:xs) +<+ ys = x :<: xs +<+ ys++reverseFL :: FL a C(x z) -> RL a C(x z)+reverseFL xs = r NilRL xs+  where r :: RL a C(l m) -> FL a C(m o) -> RL a C(l o)+        r ls NilFL = ls+        r ls (a:>:as) = r (a:<:ls) as++reverseRL :: RL a C(x z) -> FL a C(x z)+reverseRL xs = r NilFL xs -- r (xs :> NilFL)+  where r :: FL a C(m o) -> RL a C(l m) -> FL a C(l o)+        r ls NilRL = ls+        r ls (a:<:as) = r (a:>:ls) as++concatFL :: FL (FL a) C(x z) -> FL a C(x z)+concatFL NilFL = NilFL+concatFL (a:>:as) = a +>+ concatFL as++concatRL :: RL (RL a) C(x z) -> RL a C(x z)+concatRL NilRL = NilRL+concatRL (a:<:as) = a +<+ concatRL as++spanFL :: (FORALL(w y) a C(w y) -> Bool) -> FL a C(x z) -> (FL a :> FL a) C(x z)+spanFL f (x:>:xs) | f x = case spanFL f xs of+                            ys :> zs -> (x:>:ys) :> zs+spanFL _ xs = NilFL :> xs++splitAtFL :: Int -> FL a C(x z) -> (FL a :> FL a) C(x z)+splitAtFL 0 xs = NilFL :> xs+splitAtFL _ NilFL = NilFL :> NilFL+splitAtFL n (x:>:xs) = case splitAtFL (n-1) xs of+                       (xs':>xs'') -> (x:>:xs' :> xs'')++-- 'bunchFL n' groups patches into batches of n, except that it always puts+-- the first patch in its own group, this being a recognition that the+-- first patch is often *very* large.++bunchFL :: Int -> FL a C(x y) -> FL (FL a) C(x y)+bunchFL _ NilFL = NilFL+bunchFL n (x:>:xs) = (x :>: NilFL) :>: bFL xs+    where bFL :: FL a C(x y) -> FL (FL a) C(x y)+          bFL NilFL = NilFL+          bFL bs = case splitAtFL n bs of+                   a :> b -> a :>: bFL b+++allFL :: (FORALL(x y) a C(x y) -> Bool) -> FL a C(w z) -> Bool+allFL f xs = and $ mapFL f xs++foldlFL :: (FORALL(w y) a -> b C(w y) -> a) -> a -> FL b C(x z) -> a+foldlFL _ x NilFL = x+foldlFL f x (y:>:ys) = foldlFL f (f x y) ys++foldlRL :: (FORALL(w y) a -> b C(w y) -> a) -> a -> RL b C(x z) -> a+foldlRL _ x NilRL = x+foldlRL f x (y:<:ys) = foldlRL f (f x y) ys++mapFL_FL :: (FORALL(w y) a C(w y) -> b C(w y)) -> FL a C(x z) -> FL b C(x z)+mapFL_FL _ NilFL = NilFL+mapFL_FL f (a:>:as) = f a :>: mapFL_FL f as++zipWithFL :: (FORALL(x y) a -> p C(x y) -> q C(x y))+          -> [a] -> FL p C(w z) -> FL q C(w z)+zipWithFL f (x:xs) (y :>: ys) = f x y :>: zipWithFL f xs ys+zipWithFL _ _ NilFL = NilFL+zipWithFL _ [] (_:>:_) = bug "zipWithFL called with too short a list"++mapRL_RL :: (FORALL(w y) a C(w y) -> b C(w y)) -> RL a C(x z) -> RL b C(x z)+mapRL_RL _ NilRL = NilRL+mapRL_RL f (a:<:as) = f a :<: mapRL_RL f as++mapFL :: (FORALL(w z) a C(w z) -> b) -> FL a C(x y) -> [b]+mapFL _ NilFL = []+mapFL f (a :>: b) = f a : mapFL f b++mapRL :: (FORALL(w z) a C(w z) -> b) -> RL a C(x y) -> [b]+mapRL _ NilRL = []+mapRL f (a :<: b) = f a : mapRL f b++unsafeMap_l2f :: (FORALL(w z) a -> b C(w z)) -> [a] -> FL b C(x y)+unsafeMap_l2f _ [] = unsafeCoerceP NilFL+unsafeMap_l2f f (x:xs) = f x :>: unsafeMap_l2f f xs++lengthFL :: FL a C(x z) -> Int+lengthFL xs = l xs 0+  where l :: FL a C(x z) -> Int -> Int+        l NilFL n = n+        l (_:>:as) n = l as $! n+1++lengthRL :: RL a C(x z) -> Int+lengthRL xs = l xs 0+  where l :: RL a C(x z) -> Int -> Int+        l NilRL n = n+        l (_:<:as) n = l as $! n+1++concatReverseFL :: FL (RL a) C(x y) -> RL a C(x y)+concatReverseFL = concatRL . reverseFL++headRL :: RL a C(x y) -> FlippedSeal a C(y)+headRL (x:<:_) = flipSeal x+headRL _ = impossible++#ifndef GADT_WITNESSES+-- These are useful for interfacing with modules outside of+-- patch theory, such as Show.lhs+unsafeUnFL :: FL a -> [a]+unsafeUnFL NilFL = []+unsafeUnFL (a:>:as) = a : unsafeUnFL as++unsafeUnRL :: RL a -> [a]+unsafeUnRL NilRL = []+unsafeUnRL (a:<:as) = a : unsafeUnRL as++unsafeFL :: [a] -> FL a+unsafeFL [] = NilFL+unsafeFL (a:as) = a :>: unsafeFL as++unsafeRL :: [a] -> RL a+unsafeRL [] = NilRL+unsafeRL (a:as) = a :<: unsafeRL as+#endif++\end{code}
+ src/Darcs/Patch/Patchy.lhs view
@@ -0,0 +1,225 @@+%  Copyright (C) 2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Patch.Patchy ( Patchy,+                            Apply, apply, applyAndTryToFix, applyAndTryToFixFL,+                            mapMaybeSnd,+                            Commute(..), commuteFL, commuteRL, commuteRLFL,+                            mergeFL,+                            ShowPatch(..),+                            ReadPatch, readPatch', bracketedFL, peekfor,+                            Invert(..), invertFL, invertRL ) where++import Control.Monad ( liftM )+import Data.Maybe ( fromJust )+import Data.Word ( Word8 )+import Data.List ( nub )++import Darcs.SlurpDirectory ( Slurpy )+import Darcs.Sealed ( Sealed(..) )+import Darcs.Patch.ReadMonads ( ParserM, lex_eof, peek_input, my_lex, work, alter_input )+import Darcs.Patch.Ordered+import Printer ( Doc, (<>), text )+import Darcs.Lock ( writeDocBinFile, gzWriteDocFile )+import Darcs.IO ( WriteableDirectory )+import Darcs.Flags ( DarcsFlag )+import English ( plural, Noun(Noun) )+import FastPackedString ( PackedString, ifHeadThenTail, packString, dropWhitePS )+--import Darcs.ColorPrinter ( traceDoc )+--import Printer ( greenText, ($$) )++class (Apply p, Commute p, ShowPatch p, ReadPatch p, Invert p) => Patchy p where+-- instance (ShowPatch p, Invert p) => Patchy p where++class Apply p where+    apply :: WriteableDirectory m => [DarcsFlag] -> p C(x y) -> m ()+    apply _ p = do mp' <- applyAndTryToFix p+                   case mp' of+                     Nothing -> return ()+                     Just (e, _) -> fail $ "Unable to apply a patch: " ++ e+    applyAndTryToFix :: WriteableDirectory m => p C(x y) -> m (Maybe (String, p C(x y)))+    applyAndTryToFix p = do apply [] p; return Nothing+    applyAndTryToFixFL :: WriteableDirectory m => p C(x y) -> m (Maybe (String, FL p C(x y)))+    applyAndTryToFixFL p = mapMaybeSnd (:>:NilFL) `liftM` applyAndTryToFix p++mapMaybeSnd :: (a -> b) -> Maybe (c, a) -> Maybe (c, b)+mapMaybeSnd f (Just (a,b)) = Just (a,f b)+mapMaybeSnd _ Nothing = Nothing++class Commute p where+    commute :: (p :> p) C(x y) -> Maybe ((p :> p) C(x y))+    commutex :: (p :< p) C(x y) -> Maybe ((p :< p) C(x y))+    commute (x :> y) = do x' :< y' <- commutex (y :< x)+                          return (y' :> x')+    commutex (x :< y) = do x' :> y' <- commute (y :> x)+                           return (y' :< x')+    merge :: (p :\/: p) C(x y) -> (p :/\: p) C(x y)+    list_touched_files :: p C(x y) -> [FilePath]++class Commute p => ShowPatch p where+    showPatch :: p C(x y) -> Doc+    showNicely :: p C(x y) -> Doc+    showNicely = showPatch+    showContextPatch :: Slurpy -> p C(x y) -> Doc+    showContextPatch _ p = showPatch p+    description :: p C(x y) -> Doc+    description = showPatch+    summary :: p C(x y) -> Doc+    summary = showPatch+    writePatch :: FilePath -> p C(x y) -> IO ()+    writePatch f p = writeDocBinFile f $ showPatch p <> text "\n"+    gzWritePatch :: FilePath -> p C(x y) -> IO ()+    gzWritePatch f p = gzWriteDocFile f $ showPatch p <> text "\n"+    thing :: p C(x y) -> String+    thing _ = "patch"+    things :: p C(x y) -> String+    things x = plural (Noun $ thing x) ""++class ReadPatch p where+    readPatch'+        :: ParserM m => Bool -> m (Maybe (Sealed (p C(x ))))++class MyEq p => Invert p where+    invert :: p C(x y) -> p C(y x)+    identity :: p C(x x)+    sloppyIdentity :: p C(x y) -> EqCheck C(x y)+    sloppyIdentity p = identity =\/= p++instance Apply p => Apply (FL p) where+    apply _ NilFL = return ()+    apply opts (p:>:ps) = apply opts p >> apply opts ps+    applyAndTryToFix NilFL = return Nothing+    applyAndTryToFix (p:>:ps) = do mp <- applyAndTryToFixFL p+                                   mps <- applyAndTryToFix ps+                                   return $ case (mp,mps) of+                                            (Nothing, Nothing) -> Nothing+                                            (Just (e,p'),Nothing) -> Just (e,p'+>+ps)+                                            (Nothing, Just (e,ps')) -> Just (e,p:>:ps')+                                            (Just (e,p'), Just (es,ps')) ->+                                                Just (unlines [e,es], p'+>+ps')++instance Commute p => Commute (FL p) where+    commute (NilFL :> x) = Just (x :> NilFL)+    commute (x :> NilFL) = Just (NilFL :> x)+    commute (xs :> ys) = do ys' :> rxs' <- commuteRLFL (reverseFL xs :> ys)+                            return $ ys' :> reverseRL rxs'+    merge (NilFL :\/: x) = x :/\: NilFL+    merge (x :\/: NilFL) = NilFL :/\: x+    merge ((x:>:xs) :\/: ys) = fromJust $ do ys' :/\: x' <- return $ mergeFL (x :\/: ys)+                                             xs' :/\: ys'' <- return $ merge (ys' :\/: xs)+                                             return (ys'' :/\: (x' :>: xs'))+    list_touched_files xs = nub $ concat $ mapFL list_touched_files xs++mergeFL :: Commute p => (p :\/: FL p) C(x y) -> (FL p :/\: p) C(x y)+mergeFL (p :\/: NilFL) = NilFL :/\: p+mergeFL (p :\/: (x :>: xs)) = fromJust $ do x' :/\: p' <- return $ merge (p :\/: x)+                                            xs' :/\: p'' <- return $ mergeFL (p' :\/: xs)+                                            return ((x' :>: xs') :/\: p'')++commuteRLFL :: Commute p => (RL p :> FL p) C(x y) -> Maybe ((FL p :> RL p) C(x y))+commuteRLFL (NilRL :> ys) = Just (ys :> NilRL)+commuteRLFL (xs :> NilFL) = Just (NilFL :> xs)+commuteRLFL (xs :> y :>: ys) = do y' :> xs' <- commuteRL (xs :> y)+                                  ys' :> xs'' <- commuteRLFL (xs' :> ys)+                                  return (y' :>: ys' :> xs'')++commuteRL :: Commute p => (RL p :> p) C(x y) -> Maybe ((p :> RL p) C(x y))+commuteRL (z :<: zs :> w) = do w' :> z' <- commute (z :> w)+                               w'' :> zs' <- commuteRL (zs :> w')+                               return (w'' :> z' :<: zs')+commuteRL (NilRL :> w) = Just (w :> NilRL)++commuteFL :: Commute p => (p :> FL p) C(x y) -> Maybe ((FL p :> p) C(x y))+commuteFL (p :> NilFL) = Just (NilFL :> p)+commuteFL (q :> p :>: ps) = do p' :> q' <- commute (q :> p)+                               ps' :> q'' <- commuteFL (q' :> ps)+                               return (p' :>: ps' :> q'')++instance ReadPatch p => ReadPatch (FL p) where+    readPatch' want_eof = Just `liftM` read_patches+     where read_patches :: ParserM m => m (Sealed (FL p C(x )))+           read_patches = do --tracePeek "starting FL read"+                             mp <- readPatch' False+                             case mp of+                               Just (Sealed p) -> do --tracePeek "found one patch"+                                                     Sealed ps <- read_patches+                                                     return $ Sealed (p:>:ps)+                               Nothing -> if want_eof+                                          then do --tracePeek "no more patches"+                                                  unit' <- lex_eof+                                                  case unit' of+                                                    () -> return $ Sealed NilFL+                                          else do --tracePeek "no more patches"+                                                  return $ Sealed NilFL+--           tracePeek x = do y <- peek_input+--                            traceDoc (greenText x $$ greenText (show $ sal_to_string y)) return ()++{-# INLINE bracketedFL #-}+bracketedFL :: (ReadPatch p, ParserM m) =>+               Word8 -> Word8 -> m (Maybe (Sealed (FL p C(x))))+bracketedFL pre post =+    peekforw pre bfl (return Nothing)+        where bfl :: (ReadPatch p, ParserM m) => m (Maybe (Sealed (FL p C(x))))+              bfl = peekforw post (return $ Just $ Sealed NilFL)+                                  (do Just (Sealed p) <- readPatch' False+                                      Just (Sealed ps) <- bfl+                                      return $ Just $ Sealed (p:>:ps))++{-# INLINE peekforw #-}+peekforw :: ParserM m => Word8 -> m a -> m a -> m a+peekforw w ifstr ifnot = do s <- peek_input+                            case ifHeadThenTail w $ dropWhitePS s of+                              Just s' -> alter_input (const s') >> ifstr+                              Nothing -> ifnot++peekforPS :: ParserM m => PackedString -> m a -> m a -> m a+peekforPS ps ifstr ifnot = do s <- peek_input+                              case ((ps ==) . fst) `fmap` my_lex s of+                                Just True -> work my_lex >> ifstr+                                _ -> ifnot++{-# INLINE peekfor #-}+peekfor :: ParserM m => String -> m a -> m a -> m a+peekfor str = peekforPS (packString str)++instance Apply p => Apply (RL p) where+    apply _ NilRL = return ()+    apply opts (p:<:ps) = apply opts ps >> apply opts p+instance Commute p => Commute (RL p) where+    commute (xs :> ys) = do fys' :> xs' <- commuteRLFL (xs :> reverseRL ys)+                            return (reverseFL fys' :> xs')+    merge (x :\/: y) = case merge (reverseRL x :\/: reverseRL y) of+                       (ry' :/\: rx') -> reverseFL ry' :/\: reverseFL rx'+    list_touched_files = list_touched_files . reverseRL+instance ReadPatch p => ReadPatch (RL p) where+    readPatch' want_eof = do Just (Sealed fl) <- readPatch' want_eof+                             return $ Just $ Sealed $ reverseFL fl++invertFL :: Invert p => FL p C(x y) -> RL p C(y x)+invertFL NilFL = NilRL+invertFL (x:>:xs) = invert x :<: invertFL xs++invertRL :: Invert p => RL p C(x y) -> FL p C(y x)+invertRL NilRL = NilFL+invertRL (x:<:xs) = invert x :>: invertRL xs++\end{code}+
+ src/Darcs/Patch/Permutations.lhs view
@@ -0,0 +1,164 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans #-}+#include "gadts.h"+module Darcs.Patch.Permutations ( removeFL, removeRL, removeCommon,+                                  commuteWhatWeCanFL, commuteWhatWeCanRL,+                                  partitionFL, partitionRL,+                                  head_permutationsFL, head_permutationsRL,+                                  headPermutationsFL,+                                  remove_subsequenceFL, remove_subsequenceRL ) where++import Data.Maybe ( catMaybes )+import Darcs.Patch.Patchy ( Commute, commute, Invert(..), invertFL, invertRL )+import Darcs.Patch.Ordered+#include "impossible.h"+\end{code}++\begin{code}++partitionFL :: Commute p => (FORALL(u v) p C(u v) -> Bool) -> FL p C(x y) -> (FL p :> FL p) C(x y)+partitionFL _ NilFL = NilFL :> NilFL+partitionFL keepleft (p :>: ps) | keepleft p = case partitionFL keepleft ps of+                                               a :> b -> p :>: a :> b+                                | otherwise = case commuteWhatWeCanFL (p :> ps) of+                                              a :> p' :> b -> case partitionFL keepleft a of+                                                              a' :> b' -> a' :> b' +>+ p' :>: b++partitionRL :: Commute p => (FORALL(u v) p C(u v) -> Bool) -> RL p C(x y) -> (RL p :> RL p) C(x y)+partitionRL _ NilRL = NilRL :> NilRL+partitionRL keepright (p :<: ps) | keepright p = case partitionRL keepright ps of+                                                 a :> b -> a :> (p :<: b)+                                 | otherwise = case commuteWhatWeCanRL (ps :> p) of+                                               a :> p' :> b -> case partitionRL keepright b of+                                                               a' :> b' -> (a'+<+p':<:a) :> b'++commuteWhatWeCanFL :: Commute p => (p :> FL p) C(x y) -> (FL p :> p :> FL p) C(x y)+commuteWhatWeCanFL (p :> x :>: xs) =+    case commute (p :> x) of+    Nothing -> case commuteWhatWeCanFL (x :> xs) of+               xs1 :> x' :> xs2 -> case commuteWhatWeCanFL (p :> xs1) of+                              xs1' :> p' :> xs2' -> xs1' :> p' :> xs2' +>+ x' :>: xs2+    Just (x' :> p') -> case commuteWhatWeCanFL (p' :> xs) of+                       a :> p'' :> c -> x' :>: a :> p'' :> c+commuteWhatWeCanFL (y :> NilFL) = NilFL :> y :> NilFL++commuteWhatWeCanRL :: Commute p => (RL p :> p) C(x y) -> (RL p :> p :> RL p) C(x y)+commuteWhatWeCanRL (x :<: xs :> p) =+    case commute (x :> p) of+    Nothing -> case commuteWhatWeCanRL (xs :> x) of+               xs1 :> x' :> xs2 -> case commuteWhatWeCanRL (xs2 :> p) of+                              xs1' :> p' :> xs2' -> xs1' +<+ x' :<: xs1 :> p' :> xs2'+    Just (p' :> x') -> case commuteWhatWeCanRL (xs :> p') of+                       a :> p'' :> c -> a :> p'' :> x' :<: c+commuteWhatWeCanRL (NilRL :> y) = NilRL :> y :> NilRL++removeCommon :: (MyEq p, Commute p) => (FL p :\/: FL p) C(x y) -> (FL p :\/: FL p) C(x y)+removeCommon (xs :\/: NilFL) = xs :\/: NilFL+removeCommon (NilFL :\/: xs) = NilFL :\/: xs+removeCommon (xs :\/: ys) = rc xs (headPermutationsFL ys)+    where rc :: (MyEq p, Commute p) => FL p C(x y) -> [(p:>FL p) C(x z)] -> (FL p :\/: FL p) C(y z)+          rc nms ((n:>ns):_) | Just ms <- removeFL n nms = removeCommon (ms :\/: ns)+          rc ms [n:>ns] = ms :\/: n:>:ns+          rc ms (_:nss) = rc ms nss+          rc _ [] = impossible -- because we already checked for NilFL case++removeFL :: (MyEq p, Commute p) => p C(x y) -> FL p C(x z) -> Maybe (FL p C(y z))+removeFL x xs = r x $ headPermutationsFL xs+    where r :: (MyEq p, Commute p) => p C(x y) -> [(p:>FL p) C(x z)] -> Maybe (FL p C(y z))+          r _ [] = Nothing+          r z ((z':>zs):zss) | IsEq <- z =\/= z' = Just zs+                             | otherwise = r z zss++removeRL :: (MyEq p, Commute p) => p C(y z) -> RL p C(x z) -> Maybe (RL p C(x y))+removeRL x xs = r x $ head_permutationsRL xs+    where r :: (MyEq p, Commute p) => p C(y z) -> [RL p C(x z)] -> Maybe (RL p C(x y))+          r z ((z':<:zs):zss) | IsEq <- z =/\= z' = Just zs+                              | otherwise = r z zss+          r _ _ = Nothing++remove_subsequenceFL :: (MyEq p, Commute p) => FL p C(a b)+                     -> FL p C(a c) -> Maybe (FL p C(b c))+remove_subsequenceFL a b | lengthFL a > lengthFL b = Nothing+                         | otherwise = rsFL a b+    where rsFL :: (MyEq p, Commute p) => FL p C(a b) -> FL p C(a c) -> Maybe (FL p C(b c))+          rsFL NilFL ys = Just ys+          rsFL (x:>:xs) yys = removeFL x yys >>= remove_subsequenceFL xs++remove_subsequenceRL :: (MyEq p, Commute p) => RL p C(ab abc)+                     -> RL p C(a abc) -> Maybe (RL p C(a ab))+remove_subsequenceRL a b | lengthRL a > lengthRL b = Nothing+                         | otherwise = rsRL a b+    where rsRL :: (MyEq p, Commute p) => RL p C(ab abc) -> RL p C(a abc) -> Maybe (RL p C(a ab))+          rsRL NilRL ys = Just ys+          rsRL (x:<:xs) yys = removeRL x yys >>= remove_subsequenceRL xs++head_permutationsFL :: Commute p => FL p C(x y) -> [FL p C(x y)]+head_permutationsFL ps = map (\ (x:>xs) -> x:>:xs) $ headPermutationsFL ps++headPermutationsFL :: Commute p => FL p C(x y) -> [(p :> FL p) C(x y)]+headPermutationsFL NilFL = []+headPermutationsFL (p:>:ps) =+    (p:>ps) : catMaybes (map (swapfirstFL.(p:>)) $ headPermutationsFL ps)+        where swapfirstFL (p1:>p2:>xs) = do p2':>p1' <- commute (p1:>p2)+                                            Just $ p2':>p1':>:xs++head_permutationsRL :: Commute p => RL p C(x y) -> [RL p C(x y)]+head_permutationsRL NilRL = []+head_permutationsRL (p:<:ps) =+    (p:<:ps) : catMaybes (map (swapfirstRL.(p:<:)) $ head_permutationsRL ps)+        where swapfirstRL (p1:<:p2:<:xs) = do p1':>p2' <- commute (p2:>p1)+                                              Just $ p2':<:p1':<:xs+              swapfirstRL _ = Nothing++instance (MyEq p, Commute p) => MyEq (FL p) where+    a =\/= b | lengthFL a /= lengthFL b = NotEq+             | otherwise = cmpSameLength a b+             where cmpSameLength :: FL p C(x y) -> FL p C(x z) -> EqCheck C(y z)+                   cmpSameLength (x:>:xs) xys | Just ys <- removeFL x xys = cmpSameLength xs ys+                   cmpSameLength NilFL NilFL = IsEq+                   cmpSameLength _ _ = NotEq+    xs =/\= ys = reverseFL xs =/\= reverseFL ys++instance (Invert p, Commute p) => Invert (FL p) where+    invert = reverseRL . invertFL+    identity = NilFL+    sloppyIdentity NilFL = IsEq+    sloppyIdentity (x:>:xs) | IsEq <- sloppyIdentity x = sloppyIdentity xs+    sloppyIdentity _ = NotEq++instance (MyEq p, Commute p) => MyEq (RL p) where+    unsafeCompare = bug "Buggy use of unsafeCompare on RL"+    a =/\= b | lengthRL a /= lengthRL b = NotEq+             | otherwise = cmpSameLength a b+             where cmpSameLength :: RL p C(x y) -> RL p C(w y) -> EqCheck C(x w)+                   cmpSameLength (x:<:xs) xys | Just ys <- removeRL x xys = cmpSameLength xs ys+                   cmpSameLength NilRL NilRL = IsEq+                   cmpSameLength _ _ = NotEq+    xs =\/= ys = reverseRL xs =\/= reverseRL ys++instance (Commute p, Invert p) => Invert (RL p) where+    invert = reverseFL . invertRL+    identity = NilRL+    sloppyIdentity NilRL = IsEq+    sloppyIdentity (x:<:xs) | IsEq <- sloppyIdentity x = sloppyIdentity xs+    sloppyIdentity _ = NotEq++\end{code}
+ src/Darcs/Patch/Prim.lhs view
@@ -0,0 +1,1242 @@+%  Copyright (C) 2002-2003,2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\section{Patch relationships}++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Patch.Prim+       ( Prim(..), IsConflictedPrim(IsC), ConflictState(..), showPrim,+         DirPatchType(..), FilePatchType(..),+         CommuteFunction, Perhaps(..),+         null_patch, nullP, is_null_patch,+         is_identity,+         formatFileName, FileNameFormat(..),+         adddir, addfile, binary, changepref,+         hunk, move, rmdir, rmfile, tokreplace,+         is_addrmfile, is_addfile, is_hunk, is_binary, is_setpref,+         is_similar, is_adddir, is_addrmdir, is_filepatch,+         canonize, try_to_shrink, modernizePrim,+         subcommutes, sort_coalesceFL, join,+         applyBinary, try_tok_internal,+         try_shrinking_inverse,+         FromPrim(..), FromPrims(..), ToFromPrim(..),+         Conflict(..), Effect(..), commute_no_conflictsFL, commute_no_conflictsRL+       )+       where++import Prelude hiding ( pi )+import Control.Monad ( MonadPlus, msum, mzero, mplus )+import Data.Maybe ( isNothing )+#ifndef GADT_WITNESSES+import Data.Map ( toList, fromListWith, mapWithKey )+import Data.List ( foldl' )+#endif+import FastPackedString ( PackedString, lengthPS, dropPS,+                          packString, unpackPS, substrPS,+                          breakPS, concatPS,+                          takePS, fromPS2Hex, nullPS )+import FileName ( FileName, fn2ps, fn2fp, fp2fn, norm_path,+                  movedirfilename, encode_white )+import Darcs.Patch.Ordered+import Darcs.Sealed ( Sealed, unseal )+import Darcs.Patch.Patchy ( Invert(..), Commute(..) )+import Darcs.Patch.Permutations () -- for Invert instance of FL+import Darcs.SlurpDirectory ( FileContents )+import Darcs.Show+import Darcs.Utils ( nubsort )+import Lcs ( getChanges )+import RegChars ( regChars )+import Printer ( Doc, vcat, packedString, Color(Cyan,Magenta), lineColor,+                 text, userchunk, invisibleText, invisiblePS, blueText,+                 ($$), (<+>), (<>), prefix, userchunkPS,+               )+import GHC.Base (unsafeCoerce#)+#include "impossible.h"++data Prim C(x y) where+    Move :: !FileName -> !FileName -> Prim C(x y)+    DP :: !FileName -> !(DirPatchType C(x y)) -> Prim C(x y)+    FP :: !FileName -> !(FilePatchType C(x y)) -> Prim C(x y)+    Split :: FL Prim C(x y) -> Prim C(x y)+    Identity :: Prim C(x x)+    ChangePref :: !String -> !String -> !String -> Prim C(x y)++data FilePatchType C(x y) = RmFile | AddFile+                          | Hunk !Int [PackedString] [PackedString]+                          | TokReplace !String !String !String+                          | Binary PackedString PackedString+                            deriving (Eq,Ord)++data DirPatchType C(x y) = RmDir | AddDir+                           deriving (Eq,Ord)++instance MyEq FilePatchType where+    unsafeCompare a b = a == unsafeCoerce# b++instance MyEq DirPatchType where+    unsafeCompare a b = a == unsafeCoerce# b++null_patch :: Prim C(x x)+null_patch = Identity++is_null_patch :: Prim C(x y) -> Bool+is_null_patch (FP _ (Binary x y)) = nullPS x && nullPS y+is_null_patch (FP _ (Hunk _ [] [])) = True+is_null_patch Identity = True+is_null_patch _ = False++nullP :: Prim C(x y) -> EqCheck C(x y)+nullP = sloppyIdentity++is_identity :: Prim C(x y) -> EqCheck C(x y)+is_identity (FP _ (Binary old new)) | old == new = unsafeCoerce# IsEq+is_identity (FP _ (Hunk _ old new)) | old == new = unsafeCoerce# IsEq+is_identity (FP _ (TokReplace _ old new)) | old == new = unsafeCoerce# IsEq+is_identity (Move old new) | old == new = unsafeCoerce# IsEq+is_identity Identity = IsEq+is_identity _ = NotEq+\end{code}++%FIXME: The following code needs to be moved.  It is a function+%``is\_similar'' which tells you if two patches are in the same category+%human-wise.  Currently it just returns true if they are filepatches on the+%same file.++\begin{code}+is_similar :: Prim C(x y) -> Prim C(a b) -> Bool+is_similar (FP f _) (FP f' _) = f == f'+is_similar (DP f _) (DP f' _) = f == f'+is_similar _ _ = False++is_addfile :: Prim C(x y) -> Bool+is_addfile (FP _ AddFile) = True+is_addfile _ = False++is_adddir :: Prim C(x y) -> Bool+is_adddir (DP _ AddDir) = True+is_adddir _ = False++is_addrmfile :: Prim C(x y) -> Bool+is_addrmfile (FP _ AddFile) = True+is_addrmfile (FP _ RmFile) = True+is_addrmfile _ = False++is_addrmdir :: Prim C(x y) -> Bool+is_addrmdir (DP _ AddDir) = True+is_addrmdir (DP _ RmDir) = True+is_addrmdir _ = False++is_hunk :: Prim C(x y) -> Bool+is_hunk (FP _ (Hunk _ _ _)) = True+is_hunk _ = False++is_binary :: Prim C(x y) -> Bool+is_binary (FP _ (Binary _ _)) = True+is_binary _ = False++is_setpref :: Prim C(x y) -> Bool+is_setpref (ChangePref _ _ _) = True+is_setpref _ = False+\end{code}++\begin{code}+addfile :: FilePath -> Prim C(x y)+rmfile :: FilePath -> Prim C(x y)+adddir :: FilePath -> Prim C(x y)+rmdir :: FilePath -> Prim C(x y)+move :: FilePath -> FilePath -> Prim C(x y)+changepref :: String -> String -> String -> Prim C(x y)+hunk :: FilePath -> Int -> [PackedString] -> [PackedString] -> Prim C(x y)+tokreplace :: FilePath -> String -> String -> String -> Prim C(x y)+binary :: FilePath -> PackedString -> PackedString -> Prim C(x y)++evalargs :: (a -> b -> c) -> a -> b -> c+evalargs f x y = (f $! x) $! y++addfile f = FP (fp2fn $ n_fn f) AddFile+rmfile f = FP (fp2fn $ n_fn f) RmFile+adddir d = DP (fp2fn $ n_fn d) AddDir+rmdir d = DP (fp2fn $ n_fn d) RmDir+move f f' = Move (fp2fn $ n_fn f) (fp2fn $ n_fn f')+changepref p f t = ChangePref p f t+hunk f line old new = evalargs FP (fp2fn $ n_fn f) (Hunk line old new)+tokreplace f tokchars old new =+    evalargs FP (fp2fn $ n_fn f) (TokReplace tokchars old new)+binary f old new = FP (fp2fn $! n_fn f) $ Binary old new+\end{code}++\begin{code}+n_fn :: FilePath -> FilePath+n_fn f = "./"++(fn2fp $ norm_path $ fp2fn f)+\end{code}++The simplest relationship between two patches is that of ``sequential''+patches, which means that the context of the second patch (the one on the+left) consists of the first patch (on the right) plus the context of the+first patch.  The composition of two patches (which is also a patch) refers+to the patch which is formed by first applying one and then the other.  The+composition of two patches, $P_1$ and $P_2$ is represented as $P_2P_1$,+where $P_1$ is to be applied first, then $P_2$\footnote{This notation is+inspired by the notation of matrix multiplication or the application of+operators upon a Hilbert space.  In the algebra of patches, there is+multiplication (i.e.\ composition), which is associative but not+commutative, but no addition or subtraction.}++There is one other very useful relationship that two patches can have,+which is to be parallel patches, which means that the two patches have an+identical context (i.e.\ their representation applies to identical trees).+This is represented by $P_1\parallel P_2$.  Of course, two patches may also+have no simple relationship to one another.  In that case, if you want to+do something with them, you'll have to manipulate them with respect to+other patches until they are either in sequence or in parallel.++The most fundamental and simple property of patches is that they must be+invertible.  The inverse of a patch is described by: $P^{ -1}$.  In the+darcs implementation, the inverse is required to be computable from+knowledge of the patch only, without knowledge of its context, but that+(although convenient) is not required by the theory of patches.+\begin{dfn}+The inverse of patch $P$ is $P^{ -1}$, which is the ``simplest'' patch for+which the composition \( P^{ -1} P \) makes no changes to the tree.+\end{dfn}+Using this definition, it is trivial to prove the following theorem+relating to the inverse of a composition of two patches.+\begin{thm} The inverse of the composition of two patches is+\[ (P_2 P_1)^{ -1} = P_1^{ -1} P_2^{ -1}. \]+\end{thm}+Moreover, it is possible to show that the right inverse of a patch is equal+to its left inverse.  In this respect, patches continue to be analogous to+square matrices, and indeed the proofs relating to these properties of the+inverse are entirely analogous to the proofs in the case of matrix+multiplication.  The compositions proofs can also readily be extended to+the composition of more than two patches.+\begin{code}+instance Invert Prim where+    invert Identity = Identity+    invert (FP f RmFile)  = FP f AddFile+    invert (FP f AddFile)  = FP f RmFile+    invert (FP f (Hunk line old new))  = FP f $ Hunk line new old+    invert (FP f (TokReplace t o n)) = FP f $ TokReplace t n o+    invert (FP f (Binary o n)) = FP f $ Binary n o+    invert (DP d RmDir) = DP d AddDir+    invert (DP d AddDir) = DP d RmDir+    invert (Move f f') = Move f' f+    invert (ChangePref p f t) = ChangePref p t f+    invert (Split ps) = Split $ invert ps+    identity = Identity+    sloppyIdentity Identity = IsEq+    sloppyIdentity _ = NotEq++\end{code}++\begin{code}+instance Show (Prim C(x y)) where+    showsPrec d (Move fn1 fn2) = showParen (d > app_prec) $ showString "Move " .+                                 showsPrec (app_prec + 1) fn1 . showString " " .+                                 showsPrec (app_prec + 1) fn2+    showsPrec d (DP fn dp) = showParen (d > app_prec) $ showString "DP " .+                             showsPrec (app_prec + 1) fn . showString " " .+                             showsPrec (app_prec + 1) dp+    showsPrec d (FP fn fp) = showParen (d > app_prec) $ showString "FP " .+                             showsPrec (app_prec + 1) fn . showString " " .+                             showsPrec (app_prec + 1) fp+    showsPrec d (Split l) = showParen (d > app_prec) $ showString "Split " .+                            showsPrec (app_prec + 1) l+    showsPrec _ Identity = showString "Identity"+    showsPrec d (ChangePref p f t) = showParen (d > app_prec) $ showString "ChangePref " .+                                     showsPrec (app_prec + 1) p . showString " " .+                                     showsPrec (app_prec + 1) f . showString " " .+                                     showsPrec (app_prec + 1) t++instance Show2 Prim where+   showsPrec2 = showsPrec++instance Show (FilePatchType C(x y)) where+    showsPrec _ RmFile = showString "RmFile"+    showsPrec _ AddFile = showString "AddFile"+    showsPrec d (Hunk line old new) | all ((==1) . length . unpackPS) old && all ((==1) . length . unpackPS) new+        = showParen (d > app_prec) $ showString "Hunk " .+                                      showsPrec (app_prec + 1) line . showString " " .+                                      showsPrecC old . showString " " .+                                      showsPrecC new+       where showsPrecC [] = showString "[]"+             showsPrecC ss = showParen True $ showString "packStringLetters " . showsPrec (app_prec + 1) (map (head . unpackPS) ss)+    showsPrec d (Hunk line old new) = showParen (d > app_prec) $ showString "Hunk " .+                                      showsPrec (app_prec + 1) line . showString " " .+                                      showsPrec (app_prec + 1) old . showString " " .+                                      showsPrec (app_prec + 1) new+    showsPrec d (TokReplace t old new) = showParen (d > app_prec) $ showString "TokReplace " .+                                         showsPrec (app_prec + 1) t . showString " " .+                                         showsPrec (app_prec + 1) old . showString " " .+                                         showsPrec (app_prec + 1) new+    -- this case may not work usefully+    showsPrec d (Binary old new) = showParen (d > app_prec) $ showString "Binary " .+                                   showsPrec (app_prec + 1) old . showString " " .+                                   showsPrec (app_prec + 1) new++instance Show (DirPatchType C(x y)) where+    showsPrec _ RmDir = showString "RmDir"+    showsPrec _ AddDir = showString "AddDir"++{-+instance Show (Prim C(x y))  where+    show p = renderString (showPrim p) ++ "\n"+-}++data FileNameFormat = OldFormat | NewFormat+formatFileName :: FileNameFormat -> FileName -> Doc+formatFileName OldFormat = packedString . fn2ps+formatFileName NewFormat = text . encode_white . fn2fp++showPrim :: FileNameFormat -> Prim C(a b) -> Doc+showPrim x (FP f AddFile) = showAddFile x f+showPrim x (FP f RmFile)  = showRmFile x f+showPrim x (FP f (Hunk line old new))  = showHunk x f line old new+showPrim x (FP f (TokReplace t old new))  = showTok x f t old new+showPrim x (FP f (Binary old new))  = showBinary x f old new+showPrim x (DP d AddDir) = showAddDir x d+showPrim x (DP d RmDir)  = showRmDir x d+showPrim x (Move f f') = showMove x f f'+showPrim _ (ChangePref p f t) = showChangePref p f t+showPrim x (Split ps)  = showSplit x ps+showPrim _ Identity = blueText "{}"++\end{code}+++\paragraph{Add file}+Add an empty file to the tree.++\verb!addfile filename!+\begin{code}+showAddFile :: FileNameFormat -> FileName -> Doc+showAddFile x f = blueText "addfile" <+> formatFileName x f+\end{code}++\paragraph{Remove file}+Delete a file from the tree.++\verb!rmfile filename!+\begin{code}+showRmFile :: FileNameFormat -> FileName -> Doc+showRmFile x f = blueText "rmfile" <+> formatFileName x f+\end{code}++\paragraph{Move}+Rename a file or directory.++\verb!move oldname newname!+\begin{code}+showMove :: FileNameFormat -> FileName -> FileName -> Doc+showMove x d d' = blueText "move" <+> formatFileName x d <+> formatFileName x d'+\end{code}++\paragraph{Change Pref}+Change one of the preference settings.  Darcs stores a number of simple+string settings.  Among these are the name of the test script and the name+of the script that must be called prior to packing in a make dist.+\begin{verbatim}+changepref prefname+oldval+newval+\end{verbatim}+\begin{code}+showChangePref :: String -> String -> String -> Doc+showChangePref p f t = blueText "changepref" <+> text p+                    $$ userchunk f+                    $$ userchunk t+\end{code}++\paragraph{Add dir}+Add an empty directory to the tree.++\verb!adddir filename!+\begin{code}+showAddDir :: FileNameFormat -> FileName -> Doc+showAddDir x d = blueText "adddir" <+> formatFileName x d+\end{code}++\paragraph{Remove dir}+Delete a directory from the tree.++\verb!rmdir filename!+\begin{code}+showRmDir :: FileNameFormat -> FileName -> Doc+showRmDir x d = blueText "rmdir" <+> formatFileName x d+\end{code}+++\paragraph{Hunk}+Replace a hunk (set of contiguous lines) of text with a new+hunk.+\begin{verbatim}+hunk FILE LINE#+-LINE+...++LINE+...+\end{verbatim}+\begin{code}+showHunk :: FileNameFormat -> FileName -> Int -> [PackedString] -> [PackedString] -> Doc+showHunk x f line old new =+           blueText "hunk" <+> formatFileName x f <+> text (show line)+        $$ lineColor Magenta (prefix "-" (vcat $ map userchunkPS old))+        $$ lineColor Cyan    (prefix "+" (vcat $ map userchunkPS new))+\end{code}++\paragraph{Token replace}++Replace a token with a new token.  Note that this format means that+whitespace must not be allowed within a token.  If you know of a practical+application of whitespace within a token, let me know and I may change+this.+\begin{verbatim}+replace FILENAME [REGEX] OLD NEW+\end{verbatim}+\begin{code}+showTok :: FileNameFormat -> FileName -> String -> String -> String -> Doc+showTok x f t o n = blueText "replace" <+> formatFileName x f+                                     <+> text "[" <> userchunk t <> text "]"+                                     <+> userchunk o+                                     <+> userchunk n+\end{code}++\paragraph{Binary file modification}++Modify a binary file+\begin{verbatim}+binary FILENAME+oldhex+*HEXHEXHEX+...+newhex+*HEXHEXHEX+...+\end{verbatim}+\begin{code}+showBinary :: FileNameFormat -> FileName -> PackedString -> PackedString -> Doc+showBinary x f o n =+    blueText "binary" <+> formatFileName x f+ $$ invisibleText "oldhex"+ $$ (vcat $ map makeprintable $ break_every 78 $ fromPS2Hex o)+ $$ invisibleText "newhex"+ $$ (vcat $ map makeprintable $ break_every 78 $ fromPS2Hex n)+     where makeprintable ps = invisibleText "*" <> invisiblePS ps++break_every :: Int -> PackedString -> [PackedString]+break_every n ps | lengthPS ps < n = [ps]+                 | otherwise = takePS n ps : break_every n (dropPS n ps)+\end{code}++\paragraph{Split patch [OBSOLETE!]}+A split patch is similar to a composite patch but rather than being+composed of several patches grouped together, it is created from one+patch that has been split apart, typically through a merge or+commutation.+\begin{verbatim}+(+  <put patches here> (indented two)+)+\end{verbatim}+\begin{code}+showSplit :: FileNameFormat -> FL Prim C(x y) -> Doc+showSplit x ps = blueText "("+            $$ vcat (mapFL (showPrim x) ps)+            $$ blueText ")"+\end{code}+++\section{Commuting patches}++\subsection{Composite patches}++Composite patches are made up of a series of patches intended to be applied+sequentially.  They are represented by a list of patches, with the first+patch in the list being applied first.+\begin{code}+commute_split :: CommuteFunction+commute_split (Split patches :< patch) =+    toPerhaps $ do (p1 :< ps) <- cs (patches :< patch)+                   case sort_coalesceFL ps of+                            p :>: NilFL -> return (p1 :< p)+                            ps' -> return (p1 :< Split ps')+    where cs :: ((FL Prim) :< Prim) C(x y) -> Maybe ((Prim :< (FL Prim)) C(x y))+          cs (NilFL :< p1) = return (p1 :< NilFL)+          cs (p:>:ps :< p1) = do p1' :< p' <- commutex (p :< p1)+                                 p1'' :< ps' <- cs (ps :< p1')+                                 return (p1'' :< p':>:ps')+commute_split _ = Unknown+\end{code}++\begin{code}+try_to_shrink :: FL Prim C(x y) -> FL Prim C(x y)+try_to_shrink = mapPrimFL try_harder_to_shrink++mapPrimFL :: (FORALL(x y) FL Prim C(x y) -> FL Prim C(x y))+             -> FL Prim C(w z) -> FL Prim C(w z)+mapPrimFL f x =+#ifdef GADT_WITNESSES+                f x+#else +     case mapM toSimple $ mapFL id x of+     Just sx -> foldl' (+>+) NilFL $ map snd $ toList $+                fmap f $ mapWithKey fromSimples $+                fromListWith (flip (+>+)) $+                map (\ (a,b) -> (a,b:>:NilFL)) sx+     Nothing -> f x++data Simple C(x y) = SFP !(FilePatchType C(x y)) | SDP !(DirPatchType C(x y))+                   deriving ( Show )++toSimple :: Prim C(x y) -> Maybe (FileName, Simple C(x y))+toSimple (FP a b) = Just (a, SFP b)+toSimple (DP a AddDir) = Just (a, SDP AddDir)+toSimple (DP _ RmDir) = Nothing -- ordering is trickier with rmdir present+toSimple (Move _ _) = Nothing+toSimple (Split _) = Nothing+toSimple Identity = Nothing+toSimple (ChangePref _ _ _) = Nothing++fromSimple :: FileName -> Simple C(x y) -> Prim C(x y)+fromSimple a (SFP b) = FP a b+fromSimple a (SDP b) = DP a b++fromSimples :: FileName -> FL Simple C(x y) -> FL Prim C(x y)+fromSimples a bs = mapFL_FL (fromSimple a) bs+#endif++try_harder_to_shrink :: FL Prim C(x y) -> FL Prim C(x y)+try_harder_to_shrink x = try_to_shrink2 $ maybe x id (try_shrinking_inverse x)++try_to_shrink2 :: FL Prim C(x y) -> FL Prim C(x y)+try_to_shrink2 psold =+    let ps = sort_coalesceFL psold+        ps_shrunk = shrink_a_bit ps+                    in+    if lengthFL ps_shrunk < lengthFL ps+    then try_to_shrink2 ps_shrunk+    else ps_shrunk++try_shrinking_inverse :: FL Prim C(x y) -> Maybe (FL Prim C(x y))+try_shrinking_inverse (x:>:y:>:z)+    | IsEq <- invert x =\/= y = Just z+    | otherwise = case try_shrinking_inverse (y:>:z) of+                  Nothing -> Nothing+                  Just yz' -> Just $ case try_shrinking_inverse (x:>:yz') of+                                     Nothing -> x:>:yz'+                                     Just xyz' -> xyz'+try_shrinking_inverse _ = Nothing++shrink_a_bit :: FL Prim C(x y) -> FL Prim C(x y)+shrink_a_bit NilFL = NilFL+shrink_a_bit (p:>:ps) =+    case try_one NilRL p ps of+    Nothing -> p :>: shrink_a_bit ps+    Just ps' -> ps'++try_one :: RL Prim C(w x) -> Prim C(x y) -> FL Prim C(y z)+        -> Maybe (FL Prim C(w z))+try_one _ _ NilFL = Nothing+try_one sofar p (p1:>:ps) =+    case coalesce (p1 :< p) of+    Just p' -> Just (reverseRL sofar +>+ p':>:NilFL +>+ ps)+    Nothing -> case commutex (p1 :< p) of+               Nothing -> Nothing+               Just (p' :< p1') -> try_one (p1':<:sofar) p' ps++sort_coalesceFL :: FL Prim C(x y) -> FL Prim C(x y)+sort_coalesceFL = mapPrimFL sort_coalesceFL2++sort_coalesceFL2 :: FL Prim C(x y) -> FL Prim C(x y)+sort_coalesceFL2 NilFL = NilFL+sort_coalesceFL2 (x:>:xs) | IsEq <- nullP x = sort_coalesceFL2 xs+sort_coalesceFL2 (x:>:xs) | IsEq <- is_identity x = sort_coalesceFL2 xs+sort_coalesceFL2 (x:>:xs) = push_coalesce_patch x $ sort_coalesceFL2 xs++push_coalesce_patch :: Prim C(x y) -> FL Prim C(y z) -> FL Prim C(x z)+push_coalesce_patch new NilFL = new :>: NilFL+push_coalesce_patch new ps@(p:>:ps')+    = case coalesce (p :< new) of+      Just new' | IsEq <- nullP new' -> ps'+                | otherwise -> push_coalesce_patch new' ps'+      Nothing -> if comparePrim new p == LT then new:>:ps+                            else case commutex (p :< new) of+                                 Just (new' :< p') ->+                                     case push_coalesce_patch new' ps' of+                                     r | lengthFL r < 1 + lengthFL ps'+                                           -> push_coalesce_patch p' r+                                     r -> p' :>: r+                                 Nothing -> new:>:ps+\end{code}++\newcommand{\commutex}{\longleftrightarrow}+\newcommand{\commutes}{\longleftrightarrow}++The first way (of only two) to change the context of a patch is by+commutation, which is the process of changing the order of two sequential+patches.+\begin{dfn}+The commutation of patches $P_1$ and $P_2$ is represented by+\[ P_2 P_1 \commutes {P_1}' {P_2}'. \]+Here $P_1'$ is intended to describe the same change as $P_1$, with the+only difference being that $P_1'$ is applied after $P_2'$ rather than+before $P_2$.+\end{dfn}+The above definition is obviously rather vague, the reason being that what+is the ``same change'' has not been defined, and we simply assume (and+hope) that the code's view of what is the ``same change'' will match those+of its human users.  The `$\commutes$' operator should be read as something+like the $==$ operator in C, indicating that the right hand side performs+identical changes to the left hand side, but the two patches are in+reversed order.  When read in this manner, it is clear that commutation+must be a reversible process, and indeed this means that commutation+\emph{can} fail, and must fail in certain cases.  For example, the creation+and deletion of the same file cannot be commuted.  When two patches fail to+commutex, it is said that the second patch depends on the first, meaning+that it must have the first patch in its context (remembering that the+context of a patch is a set of patches, which is how we represent a tree).+\footnote{The fact that commutation can fail makes a huge difference in the+whole patch formalism.  It may be possible to create a formalism in which+commutation always succeeds, with the result of what would otherwise be a+commutation that fails being something like a virtual particle (which can+violate conservation of energy), and it may be that such a formalism would+allow strict mathematical proofs (whereas those used in the current+formalism are mostly only hand waving ``physicist'' proofs).  However, I'm+not sure how you'd deal with a request to delete a file that has not yet+been created, for example.  Obviously you'd need to create some kind of+antifile, which would annihilate with the file when that file finally got+created, but I'm not entirely sure how I'd go about doing this.+$\ddot\frown$ So I'm sticking with my hand waving formalism.}++%I should add that one using the inversion relationship of sequential+%patches, one can avoid having to provide redundant definitions of+%commutation.++% There is another interesting property which is that a commutex's results+% can't be affected by commuting another thingamabopper.++\begin{code}+is_in_directory :: FileName -> FileName -> Bool+is_in_directory d f = iid (fn2fp d) (fn2fp f)+    where iid (cd:cds) (cf:cfs)+              | cd /= cf = False+              | otherwise = iid cds cfs+          iid [] ('/':_) = True+          iid [] [] = True -- Count directory itself as being in directory...+          iid _ _ = False++data Perhaps a = Unknown | Failed | Succeeded a++instance  Monad Perhaps where+    (Succeeded x) >>= k =  k x+    Failed   >>= _      =  Failed+    Unknown  >>= _      =  Unknown+    Failed   >> _       =  Failed+    (Succeeded _) >> k  =  k+    Unknown  >> k       =  k+    return              =  Succeeded+    fail _              =  Unknown++instance  MonadPlus Perhaps where+    mzero                 = Unknown+    Unknown `mplus` ys    = ys+    Failed  `mplus` _     = Failed+    (Succeeded x) `mplus` _ = Succeeded x++toMaybe :: Perhaps a -> Maybe a+toMaybe (Succeeded x) = Just x+toMaybe _ = Nothing++toPerhaps :: Maybe a -> Perhaps a+toPerhaps (Just x) = Succeeded x+toPerhaps Nothing = Failed++clever_commute :: CommuteFunction -> CommuteFunction+clever_commute c (p1:<p2) =+    case c (p1 :< p2) of+    Succeeded x -> Succeeded x+    Failed -> Failed+    Unknown -> case c (invert p2 :< invert p1) of+               Succeeded (p1' :< p2') -> Succeeded (invert p2' :< invert p1')+               Failed -> Failed+               Unknown -> Unknown+--clever_commute c (p1,p2) = c (p1,p2) `mplus`+--    (case c (invert p2,invert p1) of+--     Succeeded (p1', p2') -> Succeeded (invert p2', invert p1')+--     Failed -> Failed+--     Unknown -> Unknown)++speedy_commute :: CommuteFunction+speedy_commute (p1 :< p2) -- Deal with common case quickly!+    | p1_modifies /= Nothing && p2_modifies /= Nothing &&+      p1_modifies /= p2_modifies = Succeeded (unsafeCoerce# p2 :< unsafeCoerce# p1)+    | otherwise = Unknown+    where p1_modifies = is_filepatch p1+          p2_modifies = is_filepatch p2++everything_else_commute :: CommuteFunction+everything_else_commute x = eec x+    where+    eec :: CommuteFunction+    eec (ChangePref p f t :<p1) = Succeeded (unsafeCoerce# p1 :< ChangePref p f t)+    eec (p2 :<ChangePref p f t) = Succeeded (ChangePref p f t :< unsafeCoerce# p2)+    eec (Identity :< p1) = Succeeded (p1 :< Identity)+    eec (p2 :< Identity) = Succeeded (Identity :< p2)+    eec xx =+        msum [+              clever_commute commute_filedir                xx+             ,clever_commute commute_split                  xx+             ]++{-+Note that it must be true that++commutex (A^-1 A, P) = Just (P, A'^-1 A')++and++if commutex (A, B) == Just (B', A')+then commutex (B^-1, A^-1) == Just (A'^-1, B'^-1)+-}++instance Commute Prim where+    merge (y :\/: z) =+        case elegant_merge (y:\/:z) of+        Just (z' :/\: y') -> z' :/\: y'+        Nothing -> error "Commute Prim merge"+    commutex x = toMaybe $ msum [speedy_commute x,+                                 everything_else_commute x+                                ]+    -- Recurse on everything, these are potentially spoofed patches+    list_touched_files (Move f1 f2) = map fn2fp [f1, f2]+    list_touched_files (Split ps) = nubsort $ concat $ mapFL list_touched_files ps+    list_touched_files (FP f _) = [fn2fp f]+    list_touched_files (DP d _) = [fn2fp d]+    list_touched_files (ChangePref _ _ _) = []+    list_touched_files Identity = []++is_filepatch :: Prim C(x y) -> Maybe FileName+is_filepatch (FP f _) = Just f+is_filepatch _ = Nothing+\end{code}++\begin{code}+is_superdir :: FileName -> FileName -> Bool+is_superdir d1 d2 = isd (fn2fp d1) (fn2fp d2)+    where isd s1 s2 =+              length s2 >= length s1 + 1 && take (length s1 + 1) s2 == s1 ++ "/"++commute_filedir :: CommuteFunction+commute_filedir (FP f1 p1 :< FP f2 p2) =+  if f1 /= f2 then Succeeded ( FP f2 (unsafeCoerce# p2) :< FP f1 (unsafeCoerce# p1) )+  else commuteFP f1 (p1 :< p2)+commute_filedir (DP d1 p1 :< DP d2 p2) =+  if (not $ is_in_directory d1 d2) && (not $ is_in_directory d2 d1) &&+     d1 /= d2+  then Succeeded ( DP d2 (unsafeCoerce# p2) :< DP d1 (unsafeCoerce# p1) )+  else Failed+commute_filedir (DP d dp :< FP f fp) =+    if not $ is_in_directory d f+    then Succeeded (FP f (unsafeCoerce# fp) :< DP d (unsafeCoerce# dp))+    else Failed++commute_filedir (Move d d' :< FP f2 p2)+    | f2 == d' = Failed+    | (p2 == AddFile || p2 == RmFile) && d == f2 = Failed+    | otherwise = Succeeded (FP (movedirfilename d d' f2) (unsafeCoerce# p2) :< Move d d')+commute_filedir (Move d d' :< DP d2 p2)+    | is_superdir d2 d' || is_superdir d2 d = Failed+    | (p2 == AddDir || p2 == RmDir) && d == d2 = Failed+    | d2 == d' = Failed+    | otherwise = Succeeded (DP (movedirfilename d d' d2) (unsafeCoerce# p2) :< Move d d')+commute_filedir (Move d d' :< Move f f')+    | f == d' || f' == d = Failed+    | f == d || f' == d' = Failed+    | d `is_superdir` f && f' `is_superdir` d' = Failed+    | otherwise =+        Succeeded (Move (movedirfilename d d' f) (movedirfilename d d' f') :<+                   Move (movedirfilename f' f d) (movedirfilename f' f d'))++commute_filedir _ = Unknown+\end{code}++\begin{code}+type CommuteFunction = FORALL(x y) (Prim :< Prim) C(x y) -> Perhaps ((Prim :< Prim) C(x y))+subcommutes :: [(String, CommuteFunction)]+subcommutes =+    [("speedy_commute", speedy_commute),+     ("commute_filedir", clever_commute commute_filedir),+     ("commute_filepatches", clever_commute commute_filepatches),+     ("commutex", toPerhaps . commutex)+    ]+\end{code}++\paragraph{Merge}+\newcommand{\merge}{\Longrightarrow}+The second way one can change the context of a patch is by a {\bf merge}+operation.  A merge is an operation that takes two parallel patches and+gives a pair of sequential patches.  The merge operation is represented by+the arrow ``\( \merge \)''.+\begin{dfn}\label{merge_dfn}+The result of a merge of two patches, $P_1$ and $P_2$ is one of two patches,+$P_1'$ and $P_2'$, which satisfy the relationship:+\[  P_2 \parallel P_1 \merge {P_2}' P_1 \commutex {P_1}' P_2. \]+\end{dfn}+Note that the sequential patches resulting from a merge are \emph{required}+to commutex.  This is an important consideration, as without it most of the+manipulations we would like to perform would not be possible.  The other+important fact is that a merge \emph{cannot fail}.  Naively, those two+requirements seem contradictory.  In reality, what it means is that the+result of a merge may be a patch which is much more complex than any we+have yet considered\footnote{Alas, I don't know how to prove that the two+constraints even \emph{can} be satisfied.  The best I have been able to do+is to believe that they can be satisfied, and to be unable to find an case+in which my implementation fails to satisfy them.  These two requirements+are the foundation of the entire theory of patches (have you been counting+how many foundations it has?).}.++\subsection{How merges are actually performed}++The constraint that any two compatible patches (patches which can+successfully be applied to the same tree) can be merged is actually quite+difficult to apply.  The above merge constraints also imply that the result+of a series of merges must be independent of the order of the merges.  So+I'm putting a whole section here for the interested to see what algorithms+I use to actually perform the merges (as this is pretty close to being the+most difficult part of the code).++The first case is that in which the two merges don't actually conflict, but+don't trivially merge either (e.g.\ hunk patches on the same file, where the+line number has to be shifted as they are merged).  This kind of merge can+actually be very elegantly dealt with using only commutation and inversion.++There is a handy little theorem which is immensely useful when trying to+merge two patches.+\begin{thm}\label{merge_thm}+$ P_2' P_1 \commutex P_1' P_2 $ if and only if $ P_1'^{ -1}+P_2' \commutex P_2 P_1^{ -1} $, provided both commutations succeed.  If+either commutex fails, this theorem does not apply.+\end{thm}+This can easily be proven by multiplying both sides of the first+commutation by $P_1'^{ -1}$ on the left, and by $P_1^{ -1}$ on the right.++\begin{code}++elegant_merge :: (Prim :\/: Prim) C(x y)+              -> Maybe ((Prim :/\: Prim) C(x y))+elegant_merge (p1 :\/: p2) =+    do p1':>ip2' <- commute (invert p2 :> p1)+       -- The following should be a redundant check+       p1o:>_ <- commute (p2 :> p1')+       IsEq <- return $ p1o =\/= p1+       return (invert ip2' :/\: p1')+\end{code}++It can sometimes be handy to have a canonical representation of a given+patch.  We achieve this by defining a canonical form for each patch type,+and a function ``{\tt canonize}'' which takes a patch and puts it into+canonical form.  This routine is used by the diff function to create an+optimal patch (based on an LCS algorithm) from a simple hunk describing the+old and new version of a file.+\begin{code}+canonize :: Prim C(x y) -> FL Prim C(x y)+canonize (Split ps) = sort_coalesceFL ps+canonize p | IsEq <- is_identity p = NilFL+canonize (FP f (Hunk line old new)) = canonizeHunk f line old new+canonize p = p :>: NilFL+\end{code}++A simpler, faster (and more generally useful) cousin of canonize is the+coalescing function.  This takes two sequential patches, and tries to turn+them into one patch.  This function is used to deal with ``split'' patches,+which are created when the commutation of a primitive patch can only be+represented by a composite patch.  In this case the resulting composite+patch must return to the original primitive patch when the commutation is+reversed, which a split patch accomplishes by trying to coalesce its+contents each time it is commuted.++\begin{code}+coalesce :: (Prim :< Prim) C(x y) -> Maybe (Prim C(x y))+coalesce (FP f1 _ :< FP f2 _) | f1 /= f2 = Nothing+coalesce (p2 :< p1) | IsEq <- p2 =\/= invert p1 = Just null_patch+coalesce (FP f1 p1 :< FP _ p2) = coalesceFilePrim f1 (p1 :< p2) -- f1 = f2+coalesce (Identity :< p) = Just p+coalesce (p :< Identity) = Just p+coalesce (Split NilFL :< p) = Just p+coalesce (p :< Split NilFL) = Just p+coalesce (Move a b :< Move b' a') | a == a' = Just $ Move b' b+coalesce (Move a b :< FP f AddFile) | f == a = Just $ FP b AddFile+coalesce (FP f RmFile :< Move a b) | b == f = Just $ FP a RmFile+coalesce (ChangePref p f1 t1 :< ChangePref p2 f2 t2) | p == p2 && t2 == f1 = Just $ ChangePref p f2 t1+coalesce _ = Nothing++join :: (Prim :> Prim) C(x y) -> Maybe (Prim C(x y))+join (x :> y) = coalesce (y :< x)+\end{code}++\subsection{File patches}++A file patch is a patch which only modifies a single+file.  There are some rules which can be made about file patches in+general, which makes them a handy class.+For example, commutation of two filepatches is trivial if they modify+different files.  If they happen to+modify the same file, we'll have to check whether or not they commutex.+\begin{code}+commute_filepatches :: CommuteFunction+commute_filepatches (FP f1 p1 :< FP f2 p2) | f1 == f2 = commuteFP f1 (p1 :< p2)+commute_filepatches _ = Unknown++commuteFP :: FileName -> (FilePatchType :< FilePatchType) C(x y)+          -> Perhaps ((Prim :< Prim) C(x y))+commuteFP f (Hunk line1 [] [] :< p2) =+    seq f $ Succeeded (FP f (unsafeCoerceP p2) :< FP f (Hunk line1 [] []))+commuteFP f (p2 :< Hunk line1 [] []) =+    seq f $ Succeeded (FP f (Hunk line1 [] []) :< FP f (unsafeCoerceP p2))+commuteFP f (Hunk line1 old1 new1 :< Hunk line2 old2 new2) = seq f $+  toPerhaps $ commuteHunk f (Hunk line1 old1 new1 :< Hunk line2 old2 new2)+commuteFP f (TokReplace t o n :< Hunk line2 old2 new2) = seq f $+    case try_tok_replace t o n old2 of+    Nothing -> Failed+    Just old2' ->+      case try_tok_replace t o n new2 of+      Nothing -> Failed+      Just new2' -> Succeeded (FP f (Hunk line2 old2' new2') :<+                               FP f (TokReplace t o n))+commuteFP f (TokReplace t o n :< TokReplace t2 o2 n2)+    | seq f $ t /= t2 = Failed+    | o == o2 = Failed+    | n == o2 = Failed+    | o == n2 = Failed+    | n == n2 = Failed+    | otherwise = Succeeded (FP f (TokReplace t2 o2 n2) :<+                             FP f (TokReplace t o n))+commuteFP _ _ = Unknown+\end{code}++\begin{code}+coalesceFilePrim :: FileName -> (FilePatchType :< FilePatchType) C(x y)+                  -> Maybe (Prim C(x y))+coalesceFilePrim f (Hunk line1 old1 new1 :< Hunk line2 old2 new2)+    = coalesceHunk f line1 old1 new1 line2 old2 new2+-- Token replace patches operating right after (or before) AddFile (RmFile)+-- is an identity patch, as far as coalescing is concerned.+coalesceFilePrim f (TokReplace _ _ _ :< AddFile) = Just $ FP f AddFile+coalesceFilePrim f (RmFile :< TokReplace _ _ _) = Just $ FP f RmFile+coalesceFilePrim f (TokReplace t1 o1 n1 :< TokReplace t2 o2 n2)+    | t1 == t2 && n2 == o1 = Just $ FP f $ TokReplace t1 o2 n1+coalesceFilePrim f (Binary m n :< Binary o m')+    | m == m' = Just $ FP f $ Binary o n+coalesceFilePrim _ _ = Nothing+\end{code}++\subsection{Hunks}++The hunk is the simplest patch that has a commuting pattern in which the+commuted patches differ from the originals (rather than simple success or+failure).  This makes commuting or merging two hunks a tad tedious.+\begin{code}+commuteHunk :: FileName -> (FilePatchType :< FilePatchType) C(x y)+            -> Maybe ((Prim :< Prim) C(x y))+commuteHunk f (Hunk line2 old2 new2 :< Hunk line1 old1 new1)+  | seq f $ line1 + lengthnew1 < line2 =+      Just (FP f (Hunk line1 old1 new1) :<+            FP f (Hunk (line2 - lengthnew1 + lengthold1) old2 new2))+  | line2 + lengthold2 < line1 =+      Just (FP f (Hunk (line1+ lengthnew2 - lengthold2) old1 new1) :<+            FP f (Hunk line2 old2 new2))+  | line1 + lengthnew1 == line2 &&+    lengthold2 /= 0 && lengthold1 /= 0 && lengthnew2 /= 0 && lengthnew1 /= 0 =+      Just (FP f (Hunk line1 old1 new1) :<+            FP f (Hunk (line2 - lengthnew1 + lengthold1) old2 new2))+  | line2 + lengthold2 == line1 &&+    lengthold2 /= 0 && lengthold1 /= 0 && lengthnew2 /= 0 && lengthnew1 /= 0 =+      Just (FP f (Hunk (line1 + lengthnew2 - lengthold2) old1 new1) :<+            FP f (Hunk line2 old2 new2))+  | otherwise = seq f Nothing+  where lengthnew1 = length new1+        lengthnew2 = length new2+        lengthold1 = length old1+        lengthold2 = length old2+commuteHunk _ _ = impossible+\end{code}+Hunks, of course, can be coalesced if they have any overlap.  Note that+coalesce code doesn't check if the two patches are conflicting.  If you are+coalescing two conflicting hunks, you've already got a bug somewhere.++\begin{code}+coalesceHunk :: FileName+             -> Int -> [PackedString] -> [PackedString]+             -> Int -> [PackedString] -> [PackedString]+             -> Maybe (Prim C(x y))+coalesceHunk f line1 old1 new1 line2 old2 new2+    | line1 == line2 && lengthold1 < lengthnew2 =+        if take lengthold1 new2 /= old1+        then Nothing+        else case drop lengthold1 new2 of+        extranew -> Just (FP f (Hunk line1 old2 (new1 ++ extranew)))+    | line1 == line2 && lengthold1 > lengthnew2 =+        if take lengthnew2 old1 /= new2+        then Nothing+        else case drop lengthnew2 old1 of+        extraold -> Just (FP f (Hunk line1 (old2 ++ extraold) new1))+    | line1 == line2 = if new2 == old1 then Just (FP f (Hunk line1 old2 new1))+                       else Nothing+    | line1 < line2 && lengthold1 >= line2 - line1 =+        case take (line2 - line1) old1 of+        extra-> coalesceHunk f line1 old1 new1 line1 (extra ++ old2) (extra ++ new2)+    | line1 > line2 && lengthnew2 >= line1 - line2 =+        case take (line1 - line2) new2 of+        extra-> coalesceHunk f line2 (extra ++ old1) (extra ++ new1) line2 old2 new2+    | otherwise = Nothing+    where lengthold1 = length old1+          lengthnew2 = length new2+\end{code}++One of the most important pieces of code is the canonization of a hunk,+which is where the ``diff'' algorithm is performed.  This algorithm begins+with chopping off the identical beginnings and endings of the old and new+hunks.  This isn't strictly necessary, but is a good idea, since this+process is $O(n)$, while the primary diff algorithm is something+considerably more painful than that\ldots\ actually the head would be dealt+with all right, but with more space complexity.  I think it's more+efficient to just chop the head and tail off first.++\begin{code}+canonizeHunk :: FileName -> Int+             -> [PackedString] -> [PackedString] -> FL Prim C(x y)+canonizeHunk f line old new+    | null old || null new+        = FP f (Hunk line old new) :>: NilFL+canonizeHunk f line old new = make_holey f line $ getChanges old new++make_holey :: FileName -> Int -> [(Int,[PackedString], [PackedString])]+           -> FL Prim C(x y)+make_holey f line changes =+    unsafeMap_l2f (\ (l,o,n) -> FP f (Hunk (l+line) o n)) changes+        +applyBinary :: PackedString -> PackedString+            -> FileContents -> Maybe FileContents+applyBinary o n c | c == o = Just n+applyBinary _ _ _ = Nothing+\end{code}++\begin{code}+try_tok_replace :: String -> String -> String+                -> [PackedString] -> Maybe [PackedString]+try_tok_replace t o n mss =+  mapM (fmap concatPS . try_tok_internal t (packString o) (packString n)) mss+++try_tok_internal :: String -> PackedString -> PackedString+                 -> PackedString -> Maybe [PackedString]+try_tok_internal _ o n s | isNothing (substrPS o s) &&+                           isNothing (substrPS n s) = Just [s]+try_tok_internal t o n s =+    case breakPS (regChars t) s of+    (before,s') ->+        case breakPS (not . regChars t) s' of+        (tok,after) ->+            case try_tok_internal t o n after of+            Nothing -> Nothing+            Just rest ->+                if tok == o+                then Just $ before : n : rest+                else if tok == n+                     then Nothing+                     else Just $ before : tok : rest+\end{code}++\begin{code}+modernizePrim :: Prim C(x y) -> FL Prim C(x y)+modernizePrim (Split ps) = concatFL $ mapFL_FL modernizePrim ps+modernizePrim p = p :>: NilFL+\end{code}++\begin{code}+instance MyEq Prim where+    unsafeCompare (Move a b) (Move c d) = a == c && b == d+    unsafeCompare (DP d1 p1) (DP d2 p2)+        = d1 == d2 && p1 `unsafeCompare` p2 +    unsafeCompare (FP f1 fp1) (FP f2 fp2)+        = f1 == f2 && fp1 `unsafeCompare` fp2+    unsafeCompare (Split ps1) (Split ps2)+        = eq_FL unsafeCompare ps1 ps2+    unsafeCompare (ChangePref a1 b1 c1) (ChangePref a2 b2 c2)+        = c1 == c2 && b1 == b2 && a1 == a2+    unsafeCompare Identity Identity = True+    unsafeCompare _ _ = False++merge_orders :: Ordering -> Ordering -> Ordering+merge_orders EQ x = x+merge_orders LT _ = LT+merge_orders GT _ = GT++comparePrim :: Prim C(x y) -> Prim C(w z) -> Ordering+comparePrim (Move a b) (Move c d) = compare (a, b) (c, d)+comparePrim (Move _ _) _ = LT+comparePrim _ (Move _ _) = GT+comparePrim (DP d1 p1) (DP d2 p2) = compare (d1, p1) $ unsafeCoerceP (d2, p2)+comparePrim (DP _ _) _ = LT+comparePrim _ (DP _ _) = GT+comparePrim (FP f1 fp1) (FP f2 fp2) = compare (f1, fp1) $ unsafeCoerceP (f2, fp2)+comparePrim (FP _ _) _ = LT+comparePrim _ (FP _ _) = GT+comparePrim (Split ps1) (Split ps2) = compare_FL comparePrim ps1 $ unsafeCoerceP ps2+comparePrim (Split _) _ = LT+comparePrim _ (Split _) = GT+comparePrim Identity Identity = EQ+comparePrim Identity _ = LT+comparePrim _ Identity = GT+comparePrim (ChangePref a1 b1 c1) (ChangePref a2 b2 c2)+ = compare (c1, b1, a1) (c2, b2, a2)++eq_FL :: (FORALL(b c d e) a C(b c) -> a C(d e) -> Bool)+      -> FL a C(x y) -> FL a C(w z) -> Bool+eq_FL _ NilFL NilFL = True+eq_FL f (x:>:xs) (y:>:ys) = f x y && eq_FL f xs ys+eq_FL _ _ _ = False++compare_FL :: (FORALL(b c d e) a C(b c) -> a C(d e) -> Ordering)+           -> FL a C(x y) -> FL a C(w z) -> Ordering+compare_FL _ NilFL NilFL = EQ+compare_FL _ NilFL _     = LT+compare_FL _ _     NilFL = GT+compare_FL f (x:>:xs) (y:>:ys) = f x y `merge_orders` compare_FL f xs ys+                                   +\end{code}++\begin{code}++class FromPrim p where+   fromPrim :: Prim C(x y) -> p C(x y)++class FromPrim p => ToFromPrim p where+    toPrim :: p C(x y) -> Maybe (Prim C(x y))++class FromPrims p where+    fromPrims :: FL Prim C(x y) -> p C(x y)+    joinPatches :: FL p C(x y) -> p C(x y)++instance FromPrim Prim where+    fromPrim = id+instance ToFromPrim Prim where+    toPrim = Just . id++instance FromPrim p => FromPrims (FL p) where+    fromPrims = mapFL_FL fromPrim+    joinPatches = concatFL+instance FromPrim p => FromPrims (RL p) where+    fromPrims = reverseFL . mapFL_FL fromPrim+    joinPatches = concatRL . reverseFL++class (Invert p, Commute p, Effect p) => Conflict p where+    list_conflicted_files :: p C(x y) -> [FilePath]+    list_conflicted_files p =+        nubsort $ concatMap (unseal list_touched_files) $ concat $ resolve_conflicts p+    resolve_conflicts :: p C(x y) -> [[Sealed (FL Prim C(y))]]+    resolve_conflicts _ = []+    commute_no_conflicts :: (p :> p) C(x y) -> Maybe ((p :> p) C(x y))+    commute_no_conflicts (x:>y) =+        do y':>x' <- commute (x:>y)+           y'':>ix'' <- commute (invert x :> y')+           IsEq <- return $ y'' =\/= y+           IsEq <- return $ ix'' =\/= invert x'+           return (y':>x')+    conflictedEffect :: p C(x y) -> [IsConflictedPrim]+    conflictedEffect x = case list_conflicted_files x of+                         [] -> mapFL (IsC Okay) $ effect x+                         _ -> mapFL (IsC Conflicted) $ effect x++instance Conflict p => Conflict (FL p) where+    list_conflicted_files = nubsort . concat . mapFL list_conflicted_files+    resolve_conflicts NilFL = []+    resolve_conflicts x = resolve_conflicts $ reverseFL x+    commute_no_conflicts (NilFL :> x) = Just (x :> NilFL)+    commute_no_conflicts (x :> NilFL) = Just (NilFL :> x)+    commute_no_conflicts (xs :> ys) = do ys' :> rxs' <- commute_no_conflictsRLFL (reverseFL xs :> ys)+                                         return $ ys' :> reverseRL rxs'+    conflictedEffect = concat . mapFL conflictedEffect++instance Conflict p => Conflict (RL p) where+    list_conflicted_files = nubsort . concat . mapRL list_conflicted_files+    resolve_conflicts x = rcs x NilFL+        where rcs :: RL p C(x y) -> FL p C(y w) -> [[Sealed (FL Prim C(w))]]+              rcs NilRL _ = []+              rcs (p:<:ps) passedby | (_:_) <- resolve_conflicts p =+                  case commute_no_conflictsFL (p:>passedby) of+                    Just (_:> p') -> resolve_conflicts p' ++ rcs ps (p:>:passedby)+                    Nothing -> rcs ps (p:>:passedby)+              rcs (p:<:ps) passedby = seq passedby $ rcs ps (p:>:passedby)+    commute_no_conflicts (NilRL :> x) = Just (x :> NilRL)+    commute_no_conflicts (x :> NilRL) = Just (NilRL :> x)+    commute_no_conflicts (xs :> ys) = do ys' :> rxs' <- commute_no_conflictsRLFL (xs :> reverseRL ys)+                                         return $ reverseFL ys' :> rxs'+    conflictedEffect = concat . reverse . mapRL conflictedEffect++data IsConflictedPrim where+    IsC :: !ConflictState -> !(Prim C(x y)) -> IsConflictedPrim+data ConflictState = Okay | Conflicted | Duplicated deriving ( Eq, Ord, Show, Read)++class Effect p where+    effect :: p C(x y) -> FL Prim C(x y)+    effect = reverseRL . effectRL+    effectRL :: p C(x y) -> RL Prim C(x y)+    effectRL = reverseFL . effect+    isHunk :: p C(x y) -> Maybe (Prim C(x y))+    isHunk _ = Nothing++instance Effect Prim where+    effect p | IsEq <- sloppyIdentity p = NilFL+             | otherwise = p :>: NilFL+    effectRL p | IsEq <- sloppyIdentity p = NilRL+               | otherwise = p :<: NilRL+    isHunk p = if is_hunk p then Just p else Nothing++instance Conflict Prim++instance Effect p => Effect (FL p) where+    effect p = concatFL $ mapFL_FL effect p+    effectRL p = concatRL $ mapRL_RL effectRL $ reverseFL p++instance Effect p => Effect (RL p) where+    effect p = concatFL $ mapFL_FL effect $ reverseRL p+    effectRL p = concatRL $ mapRL_RL effectRL p++commute_no_conflictsFL :: Conflict p => (p :> FL p) C(x y) -> Maybe ((FL p :> p) C(x y))+commute_no_conflictsFL (p :> NilFL) = Just (NilFL :> p)+commute_no_conflictsFL (q :> p :>: ps) = do p' :> q' <- commute_no_conflicts (q :> p)+                                            ps' :> q'' <- commute_no_conflictsFL (q' :> ps)+                                            return (p' :>: ps' :> q'')++commute_no_conflictsRL :: Conflict p => (RL p :> p) C(x y) -> Maybe ((p :> RL p) C(x y))+commute_no_conflictsRL (NilRL :> p) = Just (p :> NilRL)+commute_no_conflictsRL (p :<: ps :> q) = do q' :> p' <- commute_no_conflicts (p :> q)+                                            q'' :> ps' <- commute_no_conflictsRL (ps :> q')+                                            return (q'' :> p' :<: ps')++commute_no_conflictsRLFL :: Conflict p => (RL p :> FL p) C(x y) -> Maybe ((FL p :> RL p) C(x y))+commute_no_conflictsRLFL (NilRL :> ys) = Just (ys :> NilRL)+commute_no_conflictsRLFL (xs :> NilFL) = Just (NilFL :> xs)+commute_no_conflictsRLFL (xs :> y :>: ys) = do y' :> xs' <- commute_no_conflictsRL (xs :> y)+                                               ys' :> xs'' <- commute_no_conflictsRLFL (xs' :> ys)+                                               return (y' :>: ys' :> xs'')++\end{code}
+ src/Darcs/Patch/Properties.lhs view
@@ -0,0 +1,360 @@+%  Copyright (C) 2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\documentclass{article}+%\usepackage{color}++\usepackage{verbatim}+\usepackage{html}+\usepackage{fancyvrb}+\newenvironment{code}{\comment}{\endcomment}+% \newenvironment{code}{\color{blue}\verbatim}{\endverbatim}++\newcommand{\commutes}{\longleftrightarrow}++\begin{document}++\begin{code}+{-# OPTIONS_GHC -cpp -fno-warn-deprecations -fno-warn-orphans -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Patch.Properties ( recommute, commute_inverses, permutivity, partial_permutivity,+                                identity_commutes, inverse_doesnt_commute,+                                patch_and_inverse_commute, merge_either_way,+                                show_read,+                                merge_commute, merge_consistent, merge_arguments_consistent,+                                join_inverses, join_commute ) where++import Control.Monad ( msum, mplus )+import Darcs.Show ( Show2(..) )+import Darcs.Patch.Patchy+import Darcs.Patch.Prim+import Darcs.Patch ()+import Darcs.Patch.Read ( readPatch )+import Darcs.Patch.Ordered+import Darcs.Sealed ( Sealed(Sealed) )+import Printer ( Doc, renderPS, redText, greenText, ($$) )+--import Darcs.ColorPrinter ( traceDoc )+\end{code}++\section{Patch properties}++Darcs is built on a hierarchy of patch types.  At the lowest level are+``primitive'' patches, and from these building blocks, a whole hierarchy of+patch types are built.  Each of these patch types must support a number of+functions, which must obey a number of laws.++\subsection{Properties of identity}++\newtheorem{prp}{Property}++\begin{prp}[Identity commutes trivially]+  The identity patch must commute with any patch without modifying said patch.+\end{prp}++\begin{code}+identity_commutes :: Patchy p => p C(x y) -> Maybe Doc+identity_commutes p = case commute (p :> identity) of+                      Nothing -> Just $ redText "identity_commutes failed:" $$ showPatch p+                      Just (i :> p') | IsEq <- i =\/= identity,+                                       IsEq <- p' =\/= p ->+                          case commute (identity :> p) of+                          Nothing -> Just $ redText "identity_commutes failed 2:" $$ showPatch p+                          Just (i2 :> p2) | IsEq <- i2 =\/= identity,+                                            IsEq <- p2 =\/= p -> Nothing+                          Just _ -> Just $ greenText "identity_commutes 2"+                      Just _ -> Just $ greenText "identity_commutes"+\end{code}++\begin{prp}[Inverse doesn't commute]+  A patch and its inverse will always commute, unless that patch is an+  identity patch (or an identity-like patch that has no effect).+\end{prp}++\begin{code}+inverse_doesnt_commute :: Patchy p => p C(a b) -> Maybe Doc+inverse_doesnt_commute p | IsEq <- sloppyIdentity p = Nothing+                         | otherwise = do p' :> _ <- commute (invert p :> p)+                                          Just $ redText "inverse_doesnt_commute" $$ showPatch p'+\end{code}++\subsection{Commute properties}++\begin{prp}[Recommute]+  $AB \commutes B'A'$ if and only if $B'A' \commutes AB$+\end{prp}++\begin{code}+recommute :: Patchy p => (FORALL(x y) ((p :> p) C(x y) -> Maybe ((p :> p) C(x y))))+          -> (p :> p) C(a b) -> Maybe Doc+recommute c (x :> y) =+    case c (x :> y) of+    Nothing -> Nothing+    Just (y' :> x') ->+       case c (y' :> x') of+         Nothing -> Just (redText "failed" $$ showPatch y' $$ redText ":>" $$ showPatch x')+         Just (x'' :> y'') ->+             case y'' =/\= y of+             NotEq -> Just (redText "y'' =/\\= y failed, where x" $$ showPatch x $$+                            redText ":> y" $$ showPatch y $$+                            redText "y'" $$ showPatch y' $$+                            redText ":> x'" $$ showPatch x' $$+                            redText "x''" $$ showPatch x'' $$+                            redText ":> y''" $$ showPatch y'')+             IsEq -> case x'' =/\= x of+                     NotEq -> Just (redText "x'' /= x" $$ showPatch x'' $$ redText ":>" $$ showPatch y'')+                     IsEq -> Nothing+\end{code}++\begin{prp}[Commute inverses]+  $AB \commutes B'A'$ if and only if $B^{-1}A^{-1} \commutes A'^{-1}B'^{-1}$+\end{prp}++\begin{code}+commute_inverses :: Patchy p => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y)))+                 -> (p :> p) C(a b) -> Maybe Doc+commute_inverses c (x :> y) =+    case c (x :> y) of+    Nothing -> Nothing+    Just (y' :> x') ->+        case c (invert y :> invert x) of+        Nothing -> Just $ redText "second commute failed" $$+                   redText "x" $$ showPatch x $$ redText "y" $$ showPatch y $$+                   redText "y'" $$ showPatch y' $$ redText "x'" $$ showPatch x'+        Just (ix' :> iy') ->+            case invert ix' =/\= x' of+            NotEq -> Just $ redText "invert ix' /= x'" $$+                     redText "x" $$ showPatch x $$+                     redText "y" $$ showPatch y $$+                     redText "y'" $$ showPatch y' $$+                     redText "x'" $$ showPatch x' $$+                     redText "ix'" $$ showPatch ix' $$+                     redText "iy'" $$ showPatch iy' $$+                     redText "invert ix'" $$ showPatch (invert ix') $$+                     redText "invert iy'" $$ showPatch (invert iy')+            IsEq -> case y' =\/= invert iy' of+                    NotEq -> Just $ redText "y' /= invert iy'" $$ showPatch iy' $$ showPatch y'+                    IsEq -> Nothing+\end{code}++\begin{prp}[Patch and inverse]+  If $AB \commutes B'A'$ then $A^{-1}B' \commutes BA'^{-1}$+\end{prp}++This property is only true of primitive patches.++\begin{code}+patch_and_inverse_commute :: Patchy p =>+                             (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y)))+                          -> (p :> p) C(a b) -> Maybe Doc+patch_and_inverse_commute c (x :> y) =+  do y' :> x' <- c (x :> y)+     case c (invert x :> y') of+       Nothing -> Just (redText "failure in patch_and_inverse_commute")+       Just (y'' :> ix') ->+           case y'' =\/= y of+           NotEq -> Just (redText "y'' /= y" $$+                          redText "x" $$ showPatch x $$+                          redText "y" $$ showPatch y $$+                          redText "x'" $$ showPatch x' $$+                          redText "y'" $$ showPatch y' $$+                          redText "y''" $$ showPatch y'' $$+                          redText ":> x'" $$ showPatch x')+           IsEq -> case x' =\/= invert ix' of+                   NotEq -> Just (redText "x' /= invert ix'" $$+                                  redText "y''" $$ showPatch y'' $$+                                  redText ":> x'" $$ showPatch x' $$+                                  redText "invert x" $$ showPatch (invert x) $$+                                  redText ":> y" $$ showPatch y $$+                                  redText "y'" $$ showPatch y' $$+                                  redText "ix'" $$ showPatch ix')+                   IsEq -> Nothing+\end{code}++\begin{prp}[Permutivity]+  (to be added...)+\end{prp}++\begin{code}+permutivity :: Patchy p => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y)))+            -> (p :> p :> p) C(a b) -> Maybe Doc+permutivity c (x:>y:>z) =+  do y1 :> x1 <- c (x :> y)+     z2 :> y2 <- --traceDoc (greenText "first commuted") $+                 c (y :> z)+     z3 :> x3 <- --traceDoc (greenText "second commuted") $+                 c (x :> z2)+     case c (x1 :> z) of+       Nothing -> Just $ redText "permutivity1"+       Just (z4 :> x4) ->+         --traceDoc (greenText "third commuted" $$+         --          greenText "about to commute" $$+         --          greenText "y1" $$ showPatch y1 $$+         --          greenText "z4" $$ showPatch z4) $+         case c (y1 :> z4) of+         Nothing -> Just $ redText "permutivity2"+         Just (z3_ :> y4)+             | IsEq <- z3_ =\/= z3 ->+                  --traceDoc (greenText "passed z3") $ error "foobar test" $+                  case c (y4 :> x4) of+                  Nothing -> Just $ redText "permutivity5: input was" $$+                             redText "x" $$ showPatch x $$+                             redText "y" $$ showPatch y $$+                             redText "z" $$ showPatch z $$+                             redText "z3" $$ showPatch z3 $$+                             redText "failed commute of" $$+                             redText "y4" $$ showPatch y4 $$+                             redText "x4" $$ showPatch x4 $$+                             redText "whereas commute of x and y give" $$+                             redText "y1" $$ showPatch y1 $$+                             redText "x1" $$ showPatch x1+                  Just (x3_ :> y2_)+                       | NotEq <- x3_ =\/= x3 -> Just $ redText "permutivity6"+                       | NotEq <- y2_ =/\= y2 -> Just $ redText "permutivity7"+                       | otherwise -> Nothing+             | otherwise ->+                 Just $ redText "permutivity failed" $$+                        redText "z3" $$ showPatch z3 $$+                        redText "z3_" $$ showPatch z3_++partial_permutivity :: Patchy p => (FORALL(x y) (p :> p) C(x y) -> Maybe ((p :> p) C(x y)))+                    -> (p :> p :> p) C(a b) -> Maybe Doc+partial_permutivity c (xx:>yy:>zz) = pp (xx:>yy:>zz) `mplus` pp (invert zz:>invert yy:>invert xx)+    where pp (x:>y:>z) = do z1 :> y1 <- c (y :> z)+                            _ :> x1 <- c (x :> z1)+                            case c (x :> y) of+                              Just _ -> Nothing -- this is covered by full permutivity test above+                              Nothing ->+                                  case c (x1 :> y1) of+                                  Nothing -> Nothing+                                  Just _ -> Just $ greenText "partial_permutivity error" $$+                                            greenText "x" $$ showPatch x $$+                                            greenText "y" $$ showPatch y $$+                                            greenText "z" $$ showPatch z++\end{code}++\begin{code}+merge_arguments_consistent :: Patchy p =>+                              (FORALL(x y) p C(x y) -> Maybe Doc)+                           -> (p :\/: p) C(a b) -> Maybe Doc+merge_arguments_consistent is_consistent (x :\/: y) =+    msum [(\z -> redText "merge_arguments_consistent x" $$ showPatch x $$ z) `fmap` is_consistent x,+          (\z -> redText "merge_arguments_consistent y" $$ showPatch y $$ z) `fmap` is_consistent y]++merge_consistent :: Patchy p =>+                           (FORALL(x y) p C(x y) -> Maybe Doc)+                        -> (p :\/: p) C(a b) -> Maybe Doc+merge_consistent is_consistent (x :\/: y) =+    case merge (x :\/: y) of+    y' :/\: x' ->+        msum [(\z -> redText "merge_consistent x" $$ showPatch x $$ z) `fmap` is_consistent x,+              (\z -> redText "merge_consistent y" $$ showPatch y $$ z) `fmap` is_consistent y,+              (\z -> redText "merge_consistent x'" $$ showPatch x' $$ z $$+                     redText "where x' comes from x" $$ showPatch x $$+                     redText "and y" $$ showPatch y) `fmap` is_consistent x',+              (\z -> redText "merge_consistent y'" $$ showPatch y' $$ z) `fmap` is_consistent y']++merge_either_way :: Patchy p => (p :\/: p) C(x y) -> Maybe Doc+merge_either_way (x :\/: y) =+    case merge (x :\/: y) of+    y' :/\: x' -> case merge (y :\/: x) of+                  x'' :/\: y'' | IsEq <- x'' =\/= x',+                                 IsEq <- y'' =\/= y' -> Nothing+                               | otherwise -> Just $ redText "merge_either_way bug"++merge_commute :: Patchy p => (p :\/: p) C(x y) -> Maybe Doc+merge_commute (x :\/: y) =+    case merge (x :\/: y) of+    y' :/\: x' ->+        case commute (x :> y') of+        Nothing -> Just $ redText "merge_commute 1" $$+                   redText "x" $$ showPatch x $$+                   redText "y" $$ showPatch y $$+                   redText "x'" $$ showPatch x' $$+                   redText "y'" $$ showPatch y'+        Just (y_ :> x'_)+            | IsEq <- y_ =\/= y,+              IsEq <- x'_ =\/= x' ->+                      case commute (y :> x') of+                      Nothing -> Just $ redText "merge_commute 2 failed" $$+                                 redText "x" $$ showPatch x $$+                                 redText "y" $$ showPatch y $$+                                 redText "x'" $$ showPatch x' $$+                                 redText "y'" $$ showPatch y'+                      Just (x_ :> y'_)+                           | IsEq <- x_ =\/= x,+                             IsEq <- y'_ =\/= y' -> Nothing+                           | otherwise -> Just $ redText "merge_commute 3" $$+                                          redText "x" $$ showPatch x $$+                                          redText "y" $$ showPatch y $$+                                          redText "x'" $$ showPatch x' $$+                                          redText "y'" $$ showPatch y' $$+                                          redText "x_" $$ showPatch x_ $$+                                          redText "y'_" $$ showPatch y'_+            | otherwise -> Just $ redText "merge_commute 4" $$+                           redText "x" $$ showPatch x $$+                           redText "y" $$ showPatch y $$+                           redText "x'" $$ showPatch x' $$+                           redText "y'" $$ showPatch y' $$+                           redText "x'_" $$ showPatch x'_ $$+                           redText "y_" $$ showPatch y_++\end{code}++\begin{code}+join_inverses :: (FORALL(x y) (Prim :> Prim) C(x y) -> Maybe (Prim C(x y)))+              -> Prim C(a b) -> Maybe Doc+join_inverses j p = case j (invert p :> p) of+                    Just Identity -> Nothing+                    Just p' -> Just $ redText "join_inverses gave just" $$ showPatch p'+                    Nothing -> Just $ redText "join_inverses failed"++join_commute :: (FORALL(x y) (Prim :> Prim) C(x y) -> Maybe (Prim C(x y)))+             -> (Prim :> Prim :> Prim) C(a b) -> Maybe Doc+join_commute j (a :> b :> c) =+    do x <- j (b :> c)+       b' :>: c' :>: NilFL :> a' <- commuteFL (a :> b :>: c :>: NilFL)+       case commute (a :> x) of+         Nothing -> Just $ greenText "join_commute 1"+         Just (x' :> a'') ->+             case a'' =/\= a' of+             NotEq -> Just $ greenText "join_commute 3"+             IsEq -> case j (b' :> c') of+                     Nothing -> Just $ greenText "join_commute 4"+                     Just x'' -> case x' =\/= x'' of+                                 NotEq -> Just $ greenText "join_commute 5"+                                 IsEq -> Nothing+\end{code}+++\begin{code}+show_read :: (Show2 p, Patchy p) => p C(a b) -> Maybe Doc+show_read p = let ps = renderPS (showPatch p)+              in case readPatch ps of+                 Nothing -> Just (redText "unable to read " $$ showPatch p)+                 Just (Sealed p',_) | IsEq <- p' =\/= p -> Nothing+                                    | otherwise -> Just $ redText "trouble reading patch p" $$+                                                          showPatch p $$+                                                          redText "reads as p'" $$+                                                          showPatch p' $$+                                                          redText "aka" $$+                                                          greenText (show2 p) $$+                                                          redText "and" $$+                                                          greenText (show2 p')+\end{code}++\end{document}
+ src/Darcs/Patch/QuickCheck.lhs view
@@ -0,0 +1,774 @@+\begin{code}+{-# OPTIONS_GHC -cpp -fno-warn-deprecations -fno-warn-orphans -fglasgow-exts -fallow-undecidable-instances #-}+#include "gadts.h"+module Darcs.Patch.QuickCheck ( WithStartState, RepoModel, Tree,+#ifndef GADT_WITNESSES+                                merge_examples, commute_examples, triple_examples,+#endif+                                prop_consistent_tree_flattenings, prop_fail,+                                prop_is_mergeable,+                                flattenOne, simpleCheck, simpleConditionalCheck, thoroughCheck,+                                commutePairFromTree, mergePairFromTree,+                                commuteTripleFromTree,+                                commutePairFromTWFP, mergePairFromTWFP, getPairs, getTriples,+                                patchFromTree,+                                quickCheck, real_patch_loop_examples, shrink+                              ) where++import Control.Arrow ( (***) )+import Control.Monad ( liftM, replicateM, mplus, mzero )+import FastPackedString+import Test.QuickCheck+import Darcs.Sealed+import Darcs.Patch ( Patch )+import Darcs.Patch.Ordered+import Darcs.Patch.Patchy (--showPatch,+                           Invert(..), Commute(..))+import Darcs.Patch.Prim (Prim(..), Effect(..), FilePatchType(..), FromPrim(..), is_identity )+import Darcs.Patch.Real ( RealPatch, prim2real )+--import Darcs.ColorPrinter ( errorDoc )+--import Darcs.ColorPrinter ( traceDoc )+import Darcs.Show+--import Printer ( greenText, ($$) )+import FileName++#include "impossible.h"+++#ifndef GADT_WITNESSES+instance Eq (a C(x y)) => Eq (Sealed2 a) where+    (Sealed2 x) == (Sealed2 y) = x == y+#endif++instance Show2 Patch where+    show2 = show++#ifndef GADT_WITNESSES+triple_examples :: (FromPrim p, Commute p, Invert p) => [p :> p :> p]+triple_examples = [commuteTripleFromTree id $+                   WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+                   (ParTree+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "g"]))+                     (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [packString "j"]))+                      (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "s"])) NilTree)))+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "e"])) NilTree))+                  ,commuteTripleFromTree id $+                   WithStartState (RepoModel { rmFileName = fp2fn "./file",+                                               rmFileContents = [packString "j"] })+                   (ParTree+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "s"]))+                     (ParTree+                      (SeqTree (FP (fp2fn "./file") (Hunk 1 [packString "j"] [])) NilTree)+                      (SeqTree (FP (fp2fn "./file") (Hunk 1 [packString "j"] [])) NilTree)))+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "j"] [])) NilTree))+                  ]+++merge_examples :: (FromPrim p, Commute p, Invert p) => [p :\/: p]+merge_examples = map (mergePairFromCommutePair id) commute_examples++commute_examples :: (FromPrim p, Commute p) => [p :> p]+commute_examples = [+                   commutePairFromTWFP id $+                   WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+                   (TWFP 3+                    (ParTree+                     (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "h"])) NilTree)+                     (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "b"]))+                       (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "f"]))+                         (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "v"]))+                           (SeqTree (FP (fp2fn "./file") (Hunk 1 [packString "f"] [])) NilTree)))))),+                   commutePairFromTWFP id $+                   WithStartState+                   (RepoModel { rmFileName = fp2fn "./file",+                                rmFileContents = [packString "f",packString "s",packString "d"] })+                   (TWFP 3+                    (ParTree+                     (SeqTree (FP (fp2fn "./file") (Hunk 2 [packString "d"] [])) NilTree)+                     (ParTree+                      (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "f"] [])) NilTree)+                      (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "f"] []))+                        (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "s",packString "d"] []))+                          (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "v"])) NilTree)))))),+{-                   commutePairFromTWFP id $+                   WithStartState+                   (RepoModel { rmFileName = fp2fn "./file",+                                rmFileContents = [packString "f",packString "u",+                                                  packString "s",packString "d"] })+                   (TWFP 5+                    (ParTree+                     (SeqTree (FP (fp2fn "./file") (Hunk 4 [] [packString "x"]))+                      (SeqTree (FP (fp2fn "./file") (Hunk 3 [packString "d"] [])) NilTree))+                     (ParTree+                      (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "f",packString "u"] [])) NilTree)+                      (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "f"] []))+                       (SeqTree (FP(fp2fn "./file") (Hunk 0 [packString "u",packString "s",packString "d"] []))+                        (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "a"]))+                         (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "a"] [])) NilTree))))))),-}+                   commutePairFromTree id $+                   WithStartState (RepoModel { rmFileName = fp2fn "./file",+                                          rmFileContents = [packString "n",packString "t",packString "h"] })+                   (ParTree+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "n",packString "t",packString "h"] []))+                     NilTree)+                    (SeqTree (FP (fp2fn "./file") (Hunk 2 [packString "h"] []))+                     (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "n"] []))+                      (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "t"] [])) NilTree)))),+                  commutePairFromTree id $+                  WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+                  (ParTree+                   (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "n"])) NilTree)+                   (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "i"]))+                                (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "i"])) NilTree))),+                  commutePairFromTree id $+                  WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+                  (ParTree+                   (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "c"]))+                     (ParTree+                       (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "c"] [packString "r"])) NilTree)+                       (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "h"]))+                        (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "d"])) NilTree))))+                   (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "f"])) NilTree)),+                  commutePairFromTWFP id $+                  WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+                  (TWFP 1+                  (ParTree+                   (ParTree+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "t"])) NilTree)+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "t"])) NilTree))+                   (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "f"])) NilTree))),+                   commutePairFromTWFP id $+                   WithStartState (RepoModel { rmFileName = fp2fn "./file",+                                               rmFileContents = [packString "f",packString " r",+                                                                 packString "c",packString "v"] })+                   (TWFP 4+                    (ParTree+                     (SeqTree (FP (fp2fn "./file") (Hunk 2 [packString "c",packString "v"] []))+                        (ParTree+                         (SeqTree (FP (fp2fn "./file") (Hunk 1 [packString "r"] []))+                          (SeqTree (FP (fp2fn "fi le") (Hunk 0 [packString "f"] [])) NilTree))+                         (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "f",packString "r"] []))+                          (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "y"])) NilTree))))+                     (SeqTree (FP (fp2fn "./file") (Hunk 3 [packString "v"] [])) NilTree))),+                   commutePairFromTree id $+                   WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+                   (ParTree+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "z"])) NilTree)+                    (ParTree+                     (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "f"])) NilTree)+                     (ParTree+                      (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "r"])) NilTree)+                      (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "d"])) NilTree))))+                 , commutePairFromTree id $+                   WithStartState (RepoModel { rmFileName = fp2fn "./file",+                                               rmFileContents = [packString "t",packString "r",+                                                                 packString "h"] })+                   (ParTree+                    (ParTree+                     (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "t",packString "r",packString "h"] []))+                              NilTree)+                     (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "o"])) NilTree))+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "t"] []))+                     (SeqTree (FP (fp2fn "./file") (Hunk 1 [packString "h"] [])) NilTree)))+                 , commutePairFromTWFP id $+                   WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] }) $+                   TWFP 2+                   (ParTree+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "h"])) NilTree)+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "y"]))+                     (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [packString "m"]))+                      (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "v"])) NilTree))))+                 , commutePairFromTree id $+                 WithStartState (RepoModel {rmFileName = fp2fn "./file",rmFileContents = [] })+                 (ParTree+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "p"]))+                   (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "p"] []))+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "c"])) NilTree)))+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "z"])) NilTree))+                 , commutePairFromTree id $+                 WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+                 (ParTree+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "j" ]))+                   (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "j"] [])) NilTree))+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "v"])) NilTree))+                 , commutePairFromTree id $+                 WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+                 (ParTree+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "v"])) NilTree)+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "j" ]))+                   (SeqTree (FP (fp2fn "./file") (Hunk 0 [packString "j"] [])) NilTree)))+                 , commutePairFromTree id $+                 WithStartState (RepoModel { rmFileName = fp2fn "./file",+                                             rmFileContents = [packString "x",packString "c"] })+                 (ParTree+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "h"]))+                   (ParTree+                    (SeqTree (FP (fp2fn "./file") (Hunk 2 [packString "c"] [])) NilTree)+                    (SeqTree (FP (fp2fn "./file") (Hunk 1 [packString "x"] []))+                     (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "j"])) NilTree))))+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [packString "l"])) NilTree))+                 , commutePairFromTree id $+                 WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+                 (ParTree+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] (packStringLetters "s"))) NilTree)+                  (SeqTree (FP (fp2fn "./file") (Hunk 0 [] (packStringLetters "k")))+                   (SeqTree (FP (fp2fn "./file") (Hunk 0 (packStringLetters "k") []))+                    (SeqTree (FP (fp2fn "./file") (Hunk 0 [] (packStringLetters "m")))+                     (SeqTree (FP (fp2fn "./file") (Hunk 0 (packStringLetters "m") [])) NilTree)))))+                 ]+#endif++simpleConditionalCheck :: (Arbitrary p, Show p, Show q) => (p -> Bool) -> (p -> Maybe q) -> IO Int+simpleConditionalCheck nottrivial t = do okay <- quickCheckWith maxSuccessTests maxTryTests maxSize t'+                                         return $ if okay then 0 else 1+    where t' p = nottrivial p ==> case t p of+                                  Nothing -> True+                                  Just q -> error $ show q+          maxSuccessTests = 100+          maxTryTests     = 50 * maxSuccessTests+          maxSize         = 100++simpleCheck :: (Arbitrary p, Show p, Show q) => (p -> Maybe q) -> IO Int+simpleCheck t = do okay <- quickCheck' t'+                   return $ if okay then 0 else 1+    where t' p = case t p of+                 Nothing -> True+                 Just q -> error $ show q++thoroughCheck :: (Arbitrary p, Show p, Show q) => Int -> (p -> Maybe q) -> IO Int+thoroughCheck num t = do let ntries = 20*num+                             maxsize = max 100 (num `div` 10)+                         okay <- quickCheckWith num ntries maxsize t'+                         return $ if okay then 0 else 1+    where t' p = case t p of+                 Nothing -> True+                 Just q -> error $ show q++data RepoModel C(x)+ = RepoModel {+     rmFileName :: !FileName,+     rmFileContents :: [PackedString]+   } deriving (Eq)++instance Show (RepoModel C(x)) where+  showsPrec d rm = showParen (d > app_prec) $+                   showString "RepoModel { rmFileName = " . showsPrec 0 (rmFileName rm) .+                   showString ", rmFileContents = " . showsPrec 0 (rmFileContents rm) .+                   showString " }"++instance Show1 RepoModel where+    showsPrec1 = showsPrec++#ifdef GADT_WITNESSES+data InitRepoModel -- this ought to be defined somewhere central as the unique starting state+#endif++initRepoModel :: RepoModel C(InitRepoModel)+initRepoModel = RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] }+rebuildRepoModel :: RepoModel C(x) -> RepoModel C(y)+rebuildRepoModel rm = RepoModel { rmFileName = rmFileName rm, rmFileContents = rmFileContents rm }++data WithEndState px s C(y) = WithEndState { wesPatch :: px C(y), _wesState :: s C(y) }++class ArbitraryState s p where+  arbitraryState :: s C(x) -> Gen (Sealed (WithEndState (p C(x)) s))+  -- does a coarbitrary make sense?++class ArbitraryStateIn s p where+  arbitraryStateIn :: s C(x) -> Gen (p C(x))++instance ArbitraryState RepoModel Prim where+  arbitraryState rm = oneof [arbitraryFP rm]++instance Arbitrary (Sealed2 (FL Prim)) where+  arbitrary = do Sealed2 ps1 <- liftM (unseal (seal2 . wesPatch)) $ arbitraryState initRepoModel+                 return $ Sealed2 $ mapFL_FL make_identity_identity ps1+                     where make_identity_identity :: Prim C(x y) -> Prim C(x y)+                           make_identity_identity p | IsEq <- is_identity p = identity+                                                    | otherwise = p++instance Arbitrary (Sealed2 (FL (WithState RepoModel Prim))) where+  arbitrary = liftM (unseal (seal2 . wesPatch)) $ arbitraryState initRepoModel++prop_consistent_tree_flattenings :: Sealed (WithStartState RepoModel (Tree Prim)) -> Bool+prop_consistent_tree_flattenings (Sealed (WithStartState start t))+  = fromJust $+    do Sealed (G2 flat) <- return $ flattenTree $ mapTree prim2real t+       rms <- return $ map (applyPatch start) flat+       return $ and $ zipWith assert_equal_fst (zip rms flat) (tail $ zip rms flat)++assert_equal_fst :: (Eq a, Show a, Show b, Show c) => (a, b) -> (a, c) -> Bool+assert_equal_fst (x,bx) (y,by)+    | x == y = True+    | otherwise = error ("Not really equal:\n" ++ show x ++ "\nand\n" ++ show y+                         ++ "\ncoming from\n" ++ show bx ++ "\nand\n" ++ show by)++-- WithState and prop_fail are handy for debugging arbitrary code+data WithState s p C(x y) = WithState (s C(x)) (p C(x y)) (s C(y))+  deriving Show++data WithStartState s p C(x) = WithStartState (s C(x)) (p C(x))++instance (Show1 s, Show1 p) => Show (WithStartState s p C(x)) where+   showsPrec d (WithStartState s p) = showParen (d > app_prec) $ showString "WithStartState " .+                                      showsPrec1 (app_prec + 1) s . showString " " .+                                      showsPrec1 (app_prec + 1) p++instance (Show1 s, Show1 p) => Show1 (WithStartState s p) where+   showsPrec1 = showsPrec++prop_fail :: Int -> Tree Prim C(x) -> Bool+prop_fail n xs = sizeTree xs < n++instance ArbitraryState s p => ArbitraryState s (WithState s p) where+  arbitraryState rm = do xandrm' <- arbitraryState rm+                         flip unseal xandrm' $ \(WithEndState x rm') ->+                           return $ seal $ WithEndState (WithState rm x rm') rm'++instance ArbitraryState s p => ArbitraryState s (FL p) where+  arbitraryState rm1 = sized $ \n -> do k <- choose (0, n)+                                        arbitraryList k rm1+      where arbitraryList :: FORALL(x) Int -> s C(x) -> Gen (Sealed (WithEndState (FL p C(x)) s))+            arbitraryList 0 rm = return $ seal $ WithEndState NilFL rm+            arbitraryList (n+1) rm = do Sealed (WithEndState x rm') <- arbitraryState rm+                                        Sealed (WithEndState xs rm'') <- arbitraryList n rm'+                                        return $ seal $ WithEndState (x :>: xs) rm''+            arbitraryList _ _ = impossible++data Tree p C(x) where+   NilTree :: Tree p C(x)+   SeqTree :: p C(x y) -> Tree p C(y) -> Tree p C(x)+   ParTree :: Tree p C(x) -> Tree p C(x) -> Tree p C(x)++mapTree :: (FORALL(y z) p C(y z) -> q C(y z)) -> Tree p C(x) -> Tree q C(x)+mapTree _ NilTree = NilTree+mapTree f (SeqTree p t) = SeqTree (f p) (mapTree f t)+mapTree f (ParTree t1 t2) = ParTree (mapTree f t1) (mapTree f t2)++instance Show2 p => Show (Tree p C(x)) where+   showsPrec _ NilTree = showString "NilTree"+   showsPrec d (SeqTree a t) = showParen (d > app_prec) $ showString "SeqTree " .+                               showsPrec2 (app_prec + 1) a . showString " " .+                               showsPrec (app_prec + 1) t+   showsPrec d (ParTree t1 t2) = showParen (d > app_prec) $ showString "ParTree " .+                                 showsPrec (app_prec + 1) t1 . showString " " .+                                 showsPrec (app_prec + 1) t2++instance Show2 p => Show1 (Tree p) where+    showsPrec1 = showsPrec++sizeTree :: Tree p C(x) -> Int+sizeTree NilTree = 0+sizeTree (SeqTree _ t) = 1 + sizeTree t+sizeTree (ParTree t1 t2) = 1 + sizeTree t1 + sizeTree t2++-- newtype G1 l p C(x) = G1 { _unG1 :: l (p C(x)) }+newtype G2 l p C(x y) = G2 { unG2 :: l (p C(x y)) }++flattenTree :: (Commute p) => Tree p C(z) -> Sealed (G2 [] (FL p) C(z))+flattenTree NilTree = seal $ G2 $ return NilFL+flattenTree (SeqTree p t) = mapSeal (G2 . map (p :>:) . unG2) $ flattenTree t+flattenTree (ParTree t1 t2) = flip unseal (flattenTree t1) $ \gpss1 ->+                              flip unseal (flattenTree t2) $ \gpss2 ->+                              seal $ G2 $+                              do ps1 <- unG2 gpss1+                                 ps2 <- unG2 gpss2+                                 ps2' :/\: ps1' <- return $ merge (ps1 :\/: ps2)+                                 -- We can't prove that the existential type in the result+                                 -- of merge will be the same for each pair of+                                 -- ps1 and ps2.+                                 map unsafeCoerceP [ps1 +>+ ps2', ps2 +>+ ps1']++instance ArbitraryState s p => ArbitraryStateIn s (Tree p) where+  arbitraryStateIn rm = frequency [(2, return NilTree)+                                  ,(2, do Sealed (WithEndState p rm') <- arbitraryState rm+                                          t <- arbitraryStateIn rm'+                                          return (SeqTree p t))+                                  ,(1, do t1 <- arbitraryStateIn rm+                                          t2 <- arbitraryStateIn rm+                                          return (ParTree t1 t2))]+++shrinkWSSTree :: Sealed (WithStartState RepoModel (Tree Prim))+              -> [Sealed (WithStartState RepoModel (Tree Prim))]+shrinkWSSTree = unseal doShrinkWSSTree+ where+ doShrinkWSSTree wss@(WithStartState rm t)+  = shrinkWSSTree' wss -- shrink the tree+     `mplus`+    do -- shrink the starting context+      pos <- [0 .. length (rmFileContents rm) - 1]+      let rmFileContents' = take pos (rmFileContents rm) ++ drop (pos+1) (rmFileContents rm)+          t' = shrinkPosStart pos (canonizeTree t)+      return $ seal $ WithStartState (rm { rmFileContents = rmFileContents' }) (canonizeTree t')+++-- If we had a more general repo model, then Int would need to be more general too++class ShrinkablePos p where+  shrinkPos :: Int -> p C(x y) -> (p C(x y), Maybe Int)+  shrinkPatch :: p C(x y) -> [(p C(x y), Maybe Int)]+  nullPatch :: p C(x y) -> EqCheck C(x y)++class ShrinkablePosStart p where+  shrinkPosStart :: Int -> p C(x) -> p C(x)++instance ShrinkablePos p => ShrinkablePosStart (Tree p) where+  shrinkPosStart _ NilTree = NilTree+  shrinkPosStart pos (SeqTree p t)+    = let (p', mpos') = shrinkPos pos p+      in case mpos' of+           Nothing -> SeqTree p' t+           Just pos' -> SeqTree p' (shrinkPosStart pos' t)+  shrinkPosStart pos (ParTree t1 t2) = ParTree (shrinkPosStart pos t1) (shrinkPosStart pos t2)++smartFP :: FileName -> FilePatchType C(x y) -> Prim C(x y)+smartFP _ (Hunk _ [] []) | avoidEmptyHunks = unsafeCoerceP Identity+smartFP fn filepatch = FP fn filepatch++instance ShrinkablePos Prim where+  shrinkPos pos (FP fn fp) = (smartFP fn *** id) (shrinkPos pos fp)+  shrinkPos pos Identity = (Identity, Just pos)+  shrinkPos _ _ = impossible+  shrinkPatch (FP fn fp) = map (smartFP fn *** id) (shrinkPatch fp)+  shrinkPatch Identity = []+  shrinkPatch _ = impossible+  nullPatch (FP _ fp) = nullPatch fp+  nullPatch Identity = IsEq+  nullPatch _ = impossible++avoidEmptyHunks :: Bool+avoidEmptyHunks = True++instance ShrinkablePos FilePatchType where+  shrinkPos pos (Hunk n old new)+    | pos < n = (Hunk (n-1) old new, Just pos)+    | pos >= n + length old = (Hunk n old new, Just (pos + length new - length old))+    | otherwise = (Hunk n (take pos' old ++ drop (pos'+1) old) new, Nothing)+        where pos' = pos - n+  shrinkPos _ _ = bug "foo1 in ShrinkablePos"+  shrinkPatch (Hunk (n+1) [] []) = [(Hunk n [] [], Nothing)]+  shrinkPatch (Hunk n old new)+   = do i <- [0 .. length new - 1]+        return (Hunk n old (take i new ++ drop (i+1) new), Just (n + i))+  shrinkPatch _ = bug "foo in ShrinkablePos"+  nullPatch (Hunk _ [] []) = unsafeCoerceP IsEq -- is this safe?+  nullPatch _ = NotEq++shrinkWSSTree'+ -- start a new line here because apparently ' confuses CPP..+   :: WithStartState RepoModel (Tree Prim) C(x)+   -> [Sealed (WithStartState RepoModel (Tree Prim))]+shrinkWSSTree' (WithStartState _ NilTree) = []+shrinkWSSTree' (WithStartState rm t@(SeqTree p t'))+  = return (seal (WithStartState (applyPatch rm p) (canonizeTree t')))+     `mplus`+    liftM (seal . WithStartState rm) (map canonizeTree $ shrinkTree t)+shrinkWSSTree' (WithStartState rm t@(ParTree _ _))+  = liftM (seal . WithStartState rm) (map canonizeTree $ shrinkTree t)++-- canonize a tree, removing any dead branches+canonizeTree :: ShrinkablePos p => Tree p C(x) -> Tree p C(x)+canonizeTree NilTree = NilTree+canonizeTree (ParTree t1 t2)+    | NilTree <- canonizeTree t1 = canonizeTree t2+    | NilTree <- canonizeTree t2 = canonizeTree t1+    | otherwise = ParTree (canonizeTree t1) (canonizeTree t2)+canonizeTree (SeqTree p t) | IsEq <- nullPatch p = canonizeTree t+                           | otherwise = SeqTree p (canonizeTree t)++-- shrink the tree without changing the starting context+shrinkTree :: ShrinkablePos p => Tree p C(x) -> [Tree p C(x)]+shrinkTree NilTree = []+shrinkTree (SeqTree p t) = do case nullPatch p of+                                 IsEq -> return t+                                 NotEq -> mzero+                             `mplus`+                           do (p', pos) <- shrinkPatch p+                              return (SeqTree p' (maybe id shrinkPosStart pos t))+                             `mplus`+                           do t' <- shrinkTree t+                              return (SeqTree p t')+shrinkTree (ParTree t1 t2) = [t1, t2]+                              `mplus`+                             do t1' <- shrinkTree t1+                                return (ParTree t1' t2)+                              `mplus`+                             do t2' <- shrinkTree t2+                                return (ParTree t1 t2')++instance Arbitrary (Sealed (WithStartState RepoModel (Tree Prim))) where+  arbitrary = do Sealed (WithStartState rm tree) <-+                     liftM (seal . WithStartState initRepoModel) (arbitraryStateIn initRepoModel)+                 return $ Sealed $ WithStartState rm (canonizeTree tree)+  shrink = shrinkWSSTree++prop_is_mergeable :: forall p C(x) . (FromPrim p, Commute p)+                  => Sealed (WithStartState RepoModel (Tree Prim))+                  -> Maybe (Tree p C(x))+prop_is_mergeable (Sealed (WithStartState _ t))+   = case flattenOne t of+        Sealed ps -> let _ = seal2 ps :: Sealed2 (FL p)+                     in case lengthFL ps of+                       _ -> Nothing++flattenOne :: (FromPrim p, Commute p) => Tree Prim C(x) -> Sealed (FL p C(x))+flattenOne NilTree = seal NilFL+flattenOne (SeqTree p t) = flip unseal (flattenOne t) $ \ps -> seal (fromPrim p :>: ps)+flattenOne (ParTree t1 t2) =+    flip unseal (flattenOne t1) $ \ps1 ->+    flip unseal (flattenOne t2) $ \ps2 ->+    --traceDoc (greenText "flattening two parallel series: ps1" $$ showPatch ps1 $$+    --          greenText "ps2" $$ showPatch ps2) $+    case merge (ps1 :\/: ps2) of+      ps2' :/\: _ -> seal (ps1 +>+ ps2')++instance Arbitrary (Sealed2 (FL RealPatch)) where+    arbitrary = do Sealed (WithStartState _ tree) <- arbitrary :: Gen (Sealed (WithStartState RepoModel (Tree Prim)))+                   return $ unseal seal2 (flattenOne tree)++instance Arbitrary (Sealed2 RealPatch) where+    arbitrary = do Sealed (WithStartState _ tree) <- arbitrary :: Gen (Sealed (WithStartState RepoModel (Tree Prim)))+                   case mapFL seal2 `unseal` flattenOne tree of+                     [] -> return $ seal2 $ fromPrim Identity+                     ps -> elements ps++instance (Arbitrary (Sealed2 (FL p)), Commute p) => Arbitrary (Sealed2 (p :\/: p)) where+    arbitrary = do Sealed2 (a :> b) <- arbitrary+                   case commute (a :> b) of+                     Just (b' :> _) -> return (seal2 (a :\/: b'))+                     Nothing -> arbitrary++instance Arbitrary (Sealed2 (FL p)) => Arbitrary (Sealed2 (p :> p)) where+    arbitrary = do Sealed2 ps <- arbitrary+                   let pairs = getPairs ps+                   case pairs of+                      [] -> arbitrary+                      _ -> elements pairs++instance (Invert p, Arbitrary (Sealed2 (FL p))) => Arbitrary (Sealed2 (p :> p :> p)) where+    arbitrary = do Sealed2 ps <- arbitrary+                   return $ last_triple ps+        where last_triple :: FL p C(x y) -> Sealed2 (p :> p :> p)+              last_triple NilFL = seal2 $ identity :> identity :> identity+              last_triple (a :>: NilFL) = seal2 $ a :> invert a :> identity+              last_triple (a :>: b :>: NilFL) = seal2 $ invert a :> a :> b+              last_triple (a :>: b :>: c :>: NilFL) = seal2 $ a :> b :> c+              last_triple (_ :>: xs) = last_triple xs++data TreeWithFlattenPos p C(x) = TWFP Int (Tree p C(x))++commutePairFromTWFP :: (FromPrim p, Commute p)+                    => (FORALL (y z) (p :> p) C(y z) -> t)+                    -> (WithStartState RepoModel (TreeWithFlattenPos Prim) C(x) -> t)+commutePairFromTWFP handlePair (WithStartState _ (TWFP n t))+    = unseal2 handlePair $+      let xs = unseal getPairs (flattenOne t)+      in if length xs > n && n >= 0 then xs!!n else seal2 (fromPrim Identity :> fromPrim Identity)++commutePairFromTree :: (FromPrim p, Commute p)+                    => (FORALL (y z) (p :> p) C(y z) -> t)+                    -> (WithStartState RepoModel (Tree Prim) C(x) -> t)+commutePairFromTree handlePair (WithStartState _ t)+   = unseal2 handlePair $+     let Sealed ps = flattenOne t+         xs = --traceDoc (greenText "I'm flattening one to get:" $$ showPatch ps) $+              getPairs ps+     in if null xs then seal2 (fromPrim Identity :> fromPrim Identity) else last xs++commuteTripleFromTree :: (FromPrim p, Commute p)+                      => (FORALL (y z) (p :> p :> p) C(y z) -> t)+                      -> (WithStartState RepoModel (Tree Prim) C(x) -> t)+commuteTripleFromTree handle (WithStartState _ t)+   = unseal2 handle $+     let Sealed ps = flattenOne t+         xs = --traceDoc (greenText "I'm flattening one to get:" $$ showPatch ps) $+              getTriples ps+     in if null xs+        then seal2 (fromPrim Identity :> fromPrim Identity :> fromPrim Identity)+        else last xs++mergePairFromCommutePair :: (Commute p, Invert p)+                         => (FORALL (y z) (p :\/: p) C(y z) -> t)+                         -> (FORALL (y z) (p :>   p) C(y z) -> t)+mergePairFromCommutePair handlePair (a :> b)+ = case commute (a :> b) of+     Just (b' :> _) -> handlePair (a :\/: b')+     Nothing -> handlePair (b :\/: b)++-- impredicativity problems mean we can't use (.) in the definitions below++mergePairFromTWFP :: (FromPrim p, Commute p, Invert p)+                  => (FORALL (y z) (p :\/: p) C(y z) -> t)+                  -> (WithStartState RepoModel (TreeWithFlattenPos Prim) C(x) -> t)+mergePairFromTWFP x = commutePairFromTWFP (mergePairFromCommutePair x)++mergePairFromTree :: (FromPrim p, Commute p, Invert p)+                  => (FORALL (y z) (p :\/: p) C(y z) -> t)+                  -> (WithStartState RepoModel (Tree Prim) C(x) -> t)+mergePairFromTree x = commutePairFromTree (mergePairFromCommutePair x)++patchFromCommutePair :: (Commute p, Invert p)+                     => (FORALL (y z) p C(y z) -> t)+                     -> (FORALL (y z) (p :> p) C(y z) -> t)+patchFromCommutePair handle (_ :> b) = handle b++patchFromTree :: (FromPrim p, Commute p, Invert p)+              => (FORALL (y z) p C(y z) -> t)+              -> (WithStartState RepoModel (Tree Prim) C(x) -> t)+patchFromTree x = commutePairFromTree (patchFromCommutePair x)+++instance Show2 p => Show (TreeWithFlattenPos p C(x)) where+   showsPrec d (TWFP n t) = showParen (d > app_prec) $ showString "TWFP " .+                            showsPrec (app_prec + 1) n . showString " " .+                            showsPrec1 (app_prec + 1) t++instance Show1 (TreeWithFlattenPos Prim) where+   show1 = show++instance Arbitrary (Sealed (WithStartState RepoModel (TreeWithFlattenPos Prim))) where+   arbitrary = do Sealed (WithStartState rm t) <- arbitrary+                  let num = unseal (length . getPairs) (flattenOneRP t)+                  if num == 0 then return $ Sealed $ WithStartState rm $ TWFP 0 NilTree+                    else do n <- choose (0, num - 1)+                            return $ Sealed $ WithStartState rm $ TWFP n t+                    where -- just used to get the length. In principle this should be independent of the patch type.+                          flattenOneRP :: Tree Prim C(x) -> Sealed (FL RealPatch C(x))+                          flattenOneRP = flattenOne+   shrink (Sealed (WithStartState rm (TWFP n t))) =+      [Sealed (WithStartState rm' (TWFP n' t')) | Sealed (WithStartState rm' t') <- shrink (Sealed (WithStartState rm t)),+                                                  n' <- [0..n]]+++getPairs :: FL p C(x y) -> [Sealed2 (p :> p)]+getPairs NilFL = []+getPairs (_:>:NilFL) = []+getPairs (a:>:b:>:c) = seal2 (a:>b) : getPairs (b:>:c)++getTriples :: FL p C(x y) -> [Sealed2 (p :> p :> p)]+getTriples NilFL = []+getTriples (_:>:NilFL) = []+getTriples (_:>:_:>:NilFL) = []+getTriples (a:>:b:>:c:>:d) = seal2 (a:>b:>c) : getTriples (b:>:c:>:d)++arbitraryFP :: RepoModel C(x) -> Gen (Sealed (WithEndState (Prim C(x)) RepoModel))+arbitraryFP rm+ = do (fp, newcontents) <- arbitraryFilePatchType (rmFileContents rm)+      return $ seal $ WithEndState (FP (rmFileName rm) fp) (rebuildRepoModel (rm { rmFileContents = newcontents }))++-- Really [PackedString] should be parametrised by x y, and the result tuple sealed on y+arbitraryFilePatchType :: [PackedString] -> Gen (FilePatchType C(x y), [PackedString])+arbitraryFilePatchType contents = oneof [arbitraryHunk contents]++arbitraryHunk :: [PackedString] -> Gen (FilePatchType C(x y), [PackedString])+arbitraryHunk contents+ = sized $ \n ->+   do start <- choose (0, min n (length contents))+      (removelen, _)+        <- frequency $ zip (if start == length contents then [1, 13, 0, 0] else [1, 3, 5, 3])+                [return (0, 0)+                ,do xa <- choose (0, n)+                    return (0, xa)+                ,do xr <- choose (1, min n (length contents - start))+                    return (xr, 0)+                ,do xr <- choose (1, min n (length contents - start))+                    xa <- choose (0, n)+                    return (xr, xa)+                ]+      addlen <- choose (0, n)+      additems <- replicateM addlen (do c <- choose ('a', 'z')+                                        return $ packString [c])+      let newcontents = take start contents ++ additems ++ drop (start + removelen) contents+      return (Hunk start (take removelen $ drop start $ contents) additems, newcontents)++class Applyable p where+  applyPatch :: RepoModel C(x) -> p C(x y) -> RepoModel C(y)++instance Applyable p => Applyable (FL p) where+  applyPatch rm NilFL = rm+  applyPatch rm (p :>: ps) = applyPatch (applyPatch rm p) ps++instance Applyable RealPatch where+  applyPatch rm p = applyPatch rm (effect p)++instance Applyable Prim where+  applyPatch (rm@RepoModel { rmFileName = filename, rmFileContents = oldcontents }) (FP filename' fp)+     | filename == filename' = rebuildRepoModel (rm { rmFileContents = applyFilePatchType oldcontents fp })+  applyPatch rm Identity = rm+  applyPatch _ _ = bug "We haven't defined applyPatch on Prim for all patch types."++applyFilePatchType :: [PackedString] -> FilePatchType C(x y) -> [PackedString]+applyFilePatchType oldcontents (Hunk n old new)+ = if take (length old) (drop n oldcontents) == old+   then take n oldcontents ++ new ++ drop (n + length old) oldcontents+   else error "Bad patch context"+applyFilePatchType _ _ = bug "We haven't defined applyFilePatchType for all patch types."++packStringLetters :: String -> [PackedString]+packStringLetters = map (packString . (:[]))++real_patch_loop_examples :: [Sealed (WithStartState RepoModel (Tree Prim))]+real_patch_loop_examples =+    [Sealed (WithStartState (RepoModel { rmFileName = fx, rmFileContents = [] })+     $ canonizeTree+     (ParTree+      (SeqTree (FP fx (Hunk 0 [] (packStringLetters "pkotufogbvdabnmbzajvolwviqebieonxvcvuvigkfgybmqhzuaaurjspd")))+       (ParTree+        (SeqTree (FP fx (Hunk 46 (packStringLetters "qhzu") (packStringLetters "zafybdcokyjskcgnvhkbzpysaafnjjhcstgrczplxsfwagmh")))+         (ParTree+          (ParTree+           NilTree+           (ParTree+            (ParTree+             (ParTree+              (SeqTree (FP fx (Hunk 14 (packStringLetters "mbzajvolwviqebieonxvcvuvigkfgyb") (packStringLetters "vujnxnhvybvpouyciaabszfmgssezlwwjgnethvrpnfrkubphzvdgymjjoacppqps")))+               (ParTree+                NilTree+                (ParTree+                 (SeqTree (FP fx (Hunk 39 (packStringLetters "ssezlwwjgnethvrpnfrkubphzvdgymjjoacppqpsmzafybdcokyjskcgnvhkbz") (packStringLetters "wnesidpccwoiqiichxaaejdsyrhrusqljlcoro")))+                  (ParTree+                   (ParTree+                    (SeqTree (FP fx (Hunk 11 (packStringLetters "abnvujnxnhvybvpouyciaabszfmgwnesidpccwoiqii") (packStringLetters "czfdhqkipdstfjycqaxwnbxrihrufdeyneqiiiafwzlmg"))) NilTree)+                    NilTree)+                   NilTree))+                 (SeqTree (FP fx (Hunk 24 [] (packStringLetters "dihgmsotezucqdgxczvcivijootyvhlwymbiueufnvpwpeukmskqllalfe"))) NilTree))))+              (SeqTree (FP fx (Hunk 55 (packStringLetters "yjskcgnvhkbzpysaafnjjhcstgrczplxsfwagmhaaurjsp") (packStringLetters "xldhrutyhcyaqeezwujiguawfyawjjqlirxshjddvq"))) NilTree))+             (SeqTree (FP fx (Hunk 19 [] (packStringLetters "ooygwiyogqrqnytixqtmvdxx")))+              (SeqTree (FP fx (Hunk 25 (packStringLetters "yogqrqnytixqtmvdxxvolwviqebieonxvcvuvigkfgybmzafybdcokyjskcgnvhkbz") (packStringLetters "akhsmlbkdxnvfoikmiatfbpzdrsyykkpoxvvddeaspzxe")))+               (SeqTree (FP fx (Hunk 38 [] (packStringLetters "ji")))+                (ParTree+                 NilTree+                 (ParTree+                  NilTree+                  (ParTree+                   (ParTree+                    NilTree+                    (SeqTree (FP fx (Hunk 25 (packStringLetters "akhsmlbkdxnvfjioikmiatfbpzdrsyykkpoxvvddeaspzxepysaafnjjhcstgrczplxs") (packStringLetters "onjbhddskcj")))+                     (SeqTree (FP fx (Hunk 38 [] (packStringLetters "fyscunxxxjjtyqpfxeznhtwvlphmp"))) NilTree)))+                   (ParTree+                    NilTree+                    (SeqTree (FP fx (Hunk 43 [] (packStringLetters "xcchzwmzoezxkmkhcmesplnjpqriypshgiqklgdnbmmkldnydiy")))+                     (ParTree+                      NilTree+                      (SeqTree (FP fx (Hunk 63 (packStringLetters "plnjpqriypshgiqklgdnbmmkldnydiymiatfbpzdrsyykkpoxvvddeaspzxepysaafn") (packStringLetters "anjlzfdqbjqbcplvqvkhwjtkigp"))) NilTree)))))))))))+            (ParTree+             NilTree+             NilTree)))+          NilTree))+        NilTree))+      (ParTree+       NilTree+       (SeqTree (FP fx (Hunk 0 [] (packStringLetters "ti")))+        (SeqTree (FP fx (Hunk 0 (packStringLetters "t") (packStringLetters "ybcop")))+         (SeqTree (FP fx (Hunk 1 [] (packStringLetters "dvlhgwqlpaeweerqrhnjtfolczbqbzoccnvdsyqiefqitrqneralf")))+          (SeqTree (FP fx (Hunk 14 [] (packStringLetters "yairbjphwtnaerccdlfewujvjvmjakbc")))+           (SeqTree (FP fx (Hunk 50 [] (packStringLetters "xayvfuwaiiogginufnhsrmktpmlbvxiakjwllddkiyofyfw")))+            (ParTree+             NilTree+             NilTree)))))))))]++fx :: FileName+fx = fp2fn "./F"++\end{code}
+ src/Darcs/Patch/Read.lhs view
@@ -0,0 +1,284 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fno-warn-orphans #-}+module Darcs.Patch.Read ( readPrim, readPatch )+             where++import Prelude hiding ( pi )+import Control.Monad ( liftM )++#include "gadts.h"+import FastPackedString ( PackedString, nilPS, headPS, tailPS, breakFirstPS,+                          nullPS, unpackPS, breakOnPS, dropWhilePS, concatPS,+                          fromHex2PS, readIntPS, dropWhitePS )+import FileName ( FileName, fn2fp, fp2fn, ps2fn, decode_white )+import Darcs.Patch.Core ( Patch(..), Named(..) )+import Darcs.Patch.Prim ( Prim(..), FileNameFormat(..),+                          DirPatchType(..), FilePatchType(..),+                          hunk, binary )+#ifndef GADT_WITNESSES+import Darcs.Patch.Commute ( merger )+import Darcs.Patch.Patchy ( invert )+#endif+import Darcs.Patch.Info ( PatchInfo, readPatchInfo )+import Darcs.Patch.ReadMonads (ParserM, work, maybe_work, alter_input,+                               parse_strictly, peek_input, lex_string, lex_eof, my_lex)+#include "impossible.h"+import Darcs.Patch.Patchy ( ReadPatch, readPatch', bracketedFL )+import Darcs.Patch.Ordered ( FL(..) )+import Darcs.Sealed ( Sealed(..), seal, mapSeal )+\end{code}++\begin{code}+readPatch :: ReadPatch p => PackedString -> Maybe (Sealed (p C(x )), PackedString)+readPatch ps = case parse_strictly (readPatch' False) ps of+                   Just (Just p, ps') -> Just (p, ps')+                   _ -> Nothing++instance ReadPatch p => ReadPatch (Named p) where+ readPatch' want_eof+   = do s <- peek_input+        case liftM (unpackPS . fst) $ my_lex s of+          Just ('[':_) ->      liftM Just $ readNamed want_eof -- ]+          _ -> return Nothing++instance ReadPatch Prim where+ readPatch' w = readPrim OldFormat w++readPrim :: ParserM m => FileNameFormat -> Bool -> m (Maybe (Sealed (Prim C(x ))))+readPrim x _+   = do s <- peek_input+        case liftM (unpackPS . fst) $ my_lex s of+          Just "{}" ->         do work my_lex+                                  return $ Just $ seal Identity+          Just "(" ->          liftM Just $ readSplit x -- )+          Just "hunk" ->       liftM (Just . seal) $ readHunk x+          Just "replace" ->    liftM (Just . seal) $ readTok x+          Just "binary" ->     liftM (Just . seal) $ readBinary x+          Just "addfile" ->    liftM (Just . seal) $ readAddFile x+          Just "adddir" ->     liftM (Just . seal) $ readAddDir x+          Just "rmfile" ->     liftM (Just . seal) $ readRmFile x+          Just "rmdir" ->      liftM (Just . seal) $ readRmDir x+          Just "move" ->       liftM (Just . seal) $ readMove x+          Just "changepref" -> liftM (Just . seal) $ readChangePref+          _ -> return Nothing++instance ReadPatch Patch where+ readPatch' want_eof+   = do mps <- bracketedFL (fromIntegral $ fromEnum '{') (fromIntegral $ fromEnum '}')+        case mps of+          Just (Sealed ps) -> return $ Just $ Sealed $ ComP ps+          Nothing -> do s <- peek_input+                        case liftM (unpackPS . fst) $ my_lex s of+#ifndef GADT_WITNESSES+                          Just "merger" ->     liftM (Just . seal) $ readMerger True+                          Just "regrem" ->     liftM (Just . seal) $ readMerger False+#endif+                          _ -> liftM (fmap (mapSeal PP)) $ readPatch' want_eof+\end{code}++\begin{code}+read_patches :: ParserM m => FileNameFormat -> String -> Bool -> m (Sealed (FL Prim C(x )))+read_patches x str want_eof+ = do mp <- readPrim x False+      case mp of+          Nothing -> do unit <- lex_string str+                        case unit of+                            () -> if want_eof then do unit' <- lex_eof+                                                      case unit' of+                                                          () -> return $ seal NilFL+                                              else return $ seal NilFL+          Just (Sealed p) -> do Sealed ps <- read_patches x str want_eof+                                return $ seal (p:>:ps)+\end{code}++\begin{code}+readSplit :: ParserM m => FileNameFormat -> m (Sealed (Prim C(x )))+readSplit x = do+  work my_lex+  ps <- read_patches x ")" False+  return $ Split `mapSeal` ps+\end{code}++\begin{code}+readFileName :: FileNameFormat -> PackedString -> FileName+readFileName OldFormat = ps2fn+readFileName NewFormat = fp2fn . decode_white . unpackPS++readHunk :: ParserM m => FileNameFormat -> m (Prim C(x y))+readHunk x = do+  work my_lex+  fi <- work my_lex+  l <- work readIntPS+  have_nl <- skip_newline+  if have_nl+     then do work $ lines_starting_with ' ' -- skipping context+             old <- work $ lines_starting_with '-'+             new <- work $ lines_starting_with '+'+             work $ lines_starting_with ' ' -- skipping context+             return $ hunk (fn2fp $ readFileName x fi) l old new+     else return $ hunk (fn2fp $ readFileName x fi) l [] []++skip_newline :: ParserM m => m Bool+skip_newline = do s <- peek_input+                  if nullPS s+                    then return False+                    else if headPS s /= '\n'+                         then return False+                         else alter_input tailPS >> return True+\end{code}++\begin{code}+readTok :: ParserM m => FileNameFormat -> m (Prim C(x y))+readTok x = do+  work my_lex+  f <- work my_lex+  regstr <- work my_lex+  o <- work my_lex+  n <- work my_lex+  return $ FP (readFileName x f) $ TokReplace (drop_brackets $ unpackPS regstr)+                          (unpackPS o) (unpackPS n)+    where drop_brackets = init . tail+\end{code}++\paragraph{Binary file modification}++Modify a binary file+\begin{verbatim}+binary FILENAME+oldhex+*HEXHEXHEX+...+newhex+*HEXHEXHEX+...+\end{verbatim}+\begin{code}+readBinary :: ParserM m => FileNameFormat -> m (Prim C(x y))+readBinary x = do+  work my_lex+  fi <- work my_lex+  work my_lex+  alter_input dropWhitePS+  old <- work $ lines_starting_with '*'+  work my_lex+  alter_input dropWhitePS+  new <- work $ lines_starting_with '*'+  return $ binary (fn2fp $ readFileName x fi)+                  (fromHex2PS $ concatPS old)+                  (fromHex2PS $ concatPS new)+\end{code}++\begin{code}+readAddFile :: ParserM m => FileNameFormat -> m (Prim C(x y))+readAddFile x = do work my_lex+                   f <- work my_lex+                   return $ FP (readFileName x f) AddFile+\end{code}++\begin{code}+readRmFile :: ParserM m => FileNameFormat -> m (Prim C(x y))+readRmFile x = do work my_lex+                  f <- work my_lex+                  return $ FP (readFileName x f) RmFile+\end{code}++\begin{code}+readMove :: ParserM m => FileNameFormat -> m (Prim C(x y))+readMove x = do work my_lex+                d <- work my_lex+                d' <- work my_lex+                return $ Move (readFileName x d) (readFileName x d')+\end{code}++\begin{code}+readChangePref :: ParserM m => m (Prim C(x y))+readChangePref+ = do work my_lex+      p <- work my_lex+      f <- work (Just . breakOnPS '\n' . tailPS . dropWhilePS (== ' '))+      t <- work (Just . breakOnPS '\n' . tailPS)+      return $ ChangePref (unpackPS p) (unpackPS f) (unpackPS t)+\end{code}++\begin{code}+readAddDir :: ParserM m => FileNameFormat -> m (Prim C(x y))+readAddDir x = do work my_lex+                  f <- work my_lex+                  return $ DP (readFileName x f) AddDir+\end{code}++\begin{code}+readRmDir :: ParserM m => FileNameFormat -> m (Prim C(x y))+readRmDir x = do work my_lex+                 f <- work my_lex+                 return $ DP (readFileName x f) RmDir+\end{code}++\begin{code}+#ifndef GADT_WITNESSES+readMerger :: ParserM m => Bool -> m (Patch C(x y))+readMerger b = do work my_lex+                  g <- work my_lex+                  lex_string "("+                  Just (Sealed p1) <- readPatch' False+                  Just (Sealed p2) <- readPatch' False+                  lex_string ")"+                  let m = merger (unpackPS g) p1 p2+                  return $ if b then m else invert m+#endif+\end{code}++\begin{code}+readNamed :: (ReadPatch p, ParserM m) => Bool -> m (Sealed (Named p C(x )))+readNamed want_eof+          = do mn <- maybe_work readPatchInfo+               case mn of+                   Nothing -> bug "readNamed 1"+                   Just n ->+                       do d <- read_depends+                          Just p <- readPatch' want_eof+                          return $ (NamedP n d) `mapSeal` p+read_depends :: ParserM m => m [PatchInfo]+read_depends = do s <- peek_input+                  case my_lex s of+                      Just (xs, _) | unpackPS xs == "<" ->+                          do work my_lex+                             read_pis+                      _ -> return []+read_pis :: ParserM m => m [PatchInfo]+read_pis = do mpi <- maybe_work readPatchInfo+              case mpi of+                  Just pi -> do pis <- read_pis+                                return (pi:pis)+                  Nothing -> do alter_input (tailPS . dropWhilePS (/= '>'))+                                return []+\end{code}++\begin{code}+lines_starting_with :: Char -> PackedString -> Maybe ([PackedString], PackedString)+lines_starting_with c thes =+    Just (lsw [] thes)+    where lsw acc s | nullPS s || headPS s /= c = (reverse acc, s)+          lsw acc s = let s' = tailPS s+                  in case breakFirstPS '\n' s' of+                     Just (l, r) -> lsw (l:acc) r+                     Nothing -> (reverse (s':acc), nilPS)+\end{code}
+ src/Darcs/Patch/ReadMonads.hs view
@@ -0,0 +1,90 @@++module Darcs.Patch.ReadMonads (ParserM, work, maybe_work, alter_input,+                        parse_strictly, parse_lazily,+                        peek_input,+                        lex_char, lex_string, lex_strings, lex_eof,+                        my_lex) where++import FastPackedString ( PackedString, dropWhitePS, breakWhitePS, nullPS,+                          unpackPS, nilPS )++lex_char :: ParserM m => Char -> m ()+lex_char c = lex_string [c]++lex_string :: ParserM m => String -> m ()+lex_string str = work+           $ \s -> case my_lex s of+                       Just (xs, ys) | unpackPS xs == str -> Just ((), ys)+                       _ -> Nothing++lex_eof :: ParserM m => m ()+lex_eof = work+        $ \s -> if nullPS (dropWhitePS s)+                then (Just ((), nilPS))+                else Nothing++lex_strings :: ParserM m => [String] -> m String+lex_strings str =+    work $ \s ->+    case my_lex s of+    Just (xs, ys) | xs' `elem` str -> Just (xs', ys)+        where xs' = unpackPS xs+    _ -> Nothing++my_lex :: PackedString -> Maybe (PackedString, PackedString)+my_lex s = let s' = dropWhitePS s+           in if nullPS s'+              then Nothing+              else Just $ breakWhitePS s'++alter_input :: ParserM m+            => (PackedString -> PackedString) -> m ()+alter_input f = work (\s -> Just ((), f s))++class Monad m => ParserM m where+    work :: (PackedString -> Maybe (a, PackedString)) -> m a+    maybe_work :: (PackedString -> Maybe (a, PackedString)) -> m (Maybe a)+    peek_input :: m PackedString++----- Strict Monad -----+parse_strictly :: SM a -> PackedString -> Maybe (a, PackedString)+parse_strictly (SM f) s = f s++newtype SM a = SM (PackedString -> Maybe (a, PackedString))+instance Monad SM where+    SM m >>= k = SM $ \s -> case m s of+                                Nothing -> Nothing+                                Just (x, s') ->+                                    case k x of+                                        SM y -> y s'+    return x         = SM (\s -> Just (x,s))+    fail _           = SM (\_ -> Nothing)++instance ParserM SM where+    work f = SM f+    maybe_work f = SM $ \s -> case f s of+                                  Just (x, s') -> Just (Just x, s')+                                  Nothing -> Just (Nothing, s)+    peek_input = SM $ \s -> Just (s, s)++----- Lazy Monad -----+parse_lazily :: LM a -> PackedString -> (a, PackedString)+parse_lazily (LM f) s = f s++newtype LM a = LM (PackedString -> (a, PackedString))+instance Monad LM where+    LM m >>= k = LM $ \s -> let (x, s') = m s+                                LM y = k x+                            in y s'+    return x = LM (\s -> (x,s))+    fail s = error s++instance ParserM LM where+    work f = LM $ \s -> case f s of+                            Nothing -> error "parser error"+                            Just x -> x+    maybe_work f = LM $ \s -> case f s of+                                  Nothing -> (Nothing, s)+                                  Just (x, s') -> (Just x, s')+    peek_input = LM $ \s -> (s, s)+
+ src/Darcs/Patch/Real.lhs view
@@ -0,0 +1,722 @@+%  Copyright (C) 2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\section{Conflictor patches}++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans #-}+#include "gadts.h"+module Darcs.Patch.Real+       ( RealPatch(..), prim2real, is_consistent, is_forward, is_duplicate,+         pullCommon, mergeUnravelled ) where++import Control.Monad ( mplus, liftM )+import Data.List ( partition, nub )+import Darcs.Patch.Prim ( Prim, FromPrim(..), ToFromPrim(..), Conflict(..), Effect(..),+                          showPrim, FileNameFormat(NewFormat),+                          sort_coalesceFL, IsConflictedPrim(..), ConflictState(..) )+import Darcs.Patch.Read ( readPrim )+import Darcs.Patch.Patchy+import Darcs.Patch.Ordered+--import Darcs.Patch.Read ()+--import Darcs.Patch.Viewing ()+--import Darcs.Patch.Apply ()+import Darcs.Patch.Commute ( mangle_unravelled )+import Darcs.Patch.Non ( Non(..), Nonable(..), unNon,+                         showNons, showNon, readNons, readNon,+                         add, addP, addPs, remP, remPs, remNons,+                         (*>), (>*), (*>>), (>>*) )+import Darcs.Patch.Permutations ( commuteWhatWeCanFL, commuteWhatWeCanRL,+                                  removeRL, removeFL, remove_subsequenceFL )+import FastPackedString ( unpackPS )+import Darcs.Patch.ReadMonads (work, peek_input, my_lex )+import Darcs.Utils ( nubsort )+import Darcs.Sealed ( FlippedSeal(..), Sealed(Sealed), mapSeal )+import Darcs.Show+import Printer ( Doc, renderString, blueText, redText, (<+>), ($$) )+import Darcs.ColorPrinter ( errorDoc, assertDoc )+--import Printer ( greenText )+--import Darcs.ColorPrinter ( traceDoc )+#include "impossible.h"++-- Duplicate x: This patch has no effect since 'x' is already present in the repository+--+-- Etacilpud x: invert (Duplicate x)+--+-- Normal prim: A primitive patch+--+-- Conflictor ix xx x:+-- 'ix' is the set of patches:+--   * that conflict with 'x' and also conflict with another patch in the repository+--   * that conflict with a patch that conflict with 'x'+-- 'xx' is the sequence of patches that conflict *only* with 'x'+-- 'x' is the current patch+--+-- 'ix' and 'x' are stored as "Non" objects, which include any necessary+--  context to uniquely define the patch that is referred to.+--+-- InvConflictor ix xx x: like invert (Conflictor ix xx x)+data RealPatch C(x y) where+    Duplicate :: Non RealPatch C(x) -> RealPatch C(x x)+    Etacilpud :: Non RealPatch C(x) -> RealPatch C(x x)+    Normal :: Prim C(x y) -> RealPatch C(x y)+    Conflictor :: [Non RealPatch C(x)] -> FL Prim C(x y) -> Non RealPatch C(x) -> RealPatch C(y x)+    InvConflictor :: [Non RealPatch C(x)] -> FL Prim C(x y) -> Non RealPatch C(x) -> RealPatch C(x y)++is_duplicate :: RealPatch C(s y) -> Bool+is_duplicate (Duplicate _) = True+is_duplicate (Etacilpud _) = True+is_duplicate _ = False++is_forward :: RealPatch C(s y) -> Maybe Doc+is_forward p@(InvConflictor _ _ _) =+    Just $ redText "An inverse conflictor" $$ showPatch p+is_forward p@(Etacilpud _) =+    Just $ redText "An inverse duplicate" $$ showPatch p+is_forward _ = Nothing++mergeUnravelled :: [Sealed ((FL Prim) C(x))] -> Maybe (FlippedSeal RealPatch C(x))+mergeUnravelled [] = Nothing+mergeUnravelled [_] = Nothing+mergeUnravelled ws = case reverseFL `fmap` mergeConflictingNons+                                           (map sealed2non $ filter notNullS ws) of+                     Nothing -> Nothing+                     Just NilRL -> bug "found no patches in mergeUnravelled"+                     Just (z:<:_) -> Just $ FlippedSeal z+    where notNullS :: Sealed ((FL Prim) C(x)) -> Bool+          notNullS (Sealed NilFL) = False+          notNullS _ = True++sealed2non :: Sealed ((FL Prim) C(x)) -> Non RealPatch C(x)+sealed2non (Sealed xs) = case reverseFL xs of+                         y:<:ys -> Non (mapFL_FL fromPrim $ reverseRL ys) y+                         NilRL -> bug "NilFL encountered in sealed2non"++mergeConflictingNons :: [Non RealPatch C(x)] -> Maybe (FL RealPatch C(x x))+mergeConflictingNons ns = mcn $ map unNon ns+    where mcn :: [Sealed (FL RealPatch C(x))] -> Maybe (FL RealPatch C(x x))+          mcn [] = Just NilFL+          mcn [Sealed p] = case sort_coalesceFL $ effect p of -- this is just a safety check, and could+                           NilFL -> Just p                    -- be removed when we're sure of the code.+                           _ -> Nothing+          mcn (Sealed p1:Sealed p2:zs) = case pullCommon p1 p2 of+                                         Common c ps qs ->+                                             case merge (ps :\/: qs) of+                                             qs' :/\: _ -> mcn (Sealed (c +>+ ps +>+ qs'):zs)++assertConsistent :: RealPatch C(x y) -> RealPatch C(x y)+assertConsistent x = assertDoc (do e <- is_consistent x+                                   Just (redText "Inconsistent patch:" $$ showPatch x $$ e)) x++mergeAfterConflicting :: FL RealPatch C(x x) -> FL Prim C(x y)+                      -> Maybe (FL RealPatch C(x x), FL RealPatch C(x y))+mergeAfterConflicting xxx yyy = --traceDoc (greenText "mergeAfterConflicting xxx" $$ showPatch xxx $$+                                --          greenText "and yyy" $$ showPatch yyy) $+                                mac (reverseFL xxx) yyy NilFL+    where mac :: RL RealPatch C(x y) -> FL Prim C(y z) -> FL RealPatch C(z a)+              -> Maybe (FL RealPatch C(x x), FL RealPatch C(x a))+          mac NilRL xs goneby = case sort_coalesceFL $ effect goneby of+                                NilFL -> Just (NilFL, mapFL_FL Normal xs)+                                _z -> --traceDoc (greenText "mac1 z" $$ showPatch _z) $+                                      Nothing+          mac (p:<:ps) xs goneby = --traceDoc (greenText "mac ps" $$ showPatch ps $$+                                   --          greenText "p" $$ showPatch p $$+                                   --          greenText "xs" $$ showPatch xs $$+                                   --          greenText "goneby" $$ showPatch goneby) $+                                   case commuteFL (p :> mapFL_FL Normal xs) of+                                   Nothing -> case commuteWhatWeCanRL (ps :> p) of+                                              a:>p':>b ->+                                                  do (b',xs') <- mac b xs goneby+                                                     --traceDoc (greenText "foo1" $$+                                                     --          showPatch (sort_coalesceFL $+                                                     --                     effect $ p':<:a)) $ Just ()+                                                     NilFL <- return $ sort_coalesceFL $ effect $ p':<:a+                                                     return (reverseRL (p':<:a)+>+b', xs')+                                                   `mplus` do NilFL <- return goneby+                                                              NilFL <- return $ sort_coalesceFL $+                                                                       effect (p:<:ps)+                                                              return (reverseRL (p:<:ps),+                                                                      mapFL_FL Normal xs)+                                   Just (l:>p'') ->+                                       case allNormal l of+                                       Just xs'' -> mac ps xs'' (p'':>:goneby)+                                       Nothing ->+                                              case commuteWhatWeCanRL (ps :> p) of+                                              a:>p':>b ->+                                                  do (b',xs') <- mac b xs goneby+                                                     --traceDoc (greenText "foo2" $$+                                                     --          showPatch (sort_coalesceFL $+                                                     --                     effect $ p':<:a)) $ Just ()+                                                     NilFL <- return $ sort_coalesceFL $ effect $ p':<:a+                                                     return $ (reverseRL (p':<:a)+>+b', xs')++geteff :: [Non RealPatch C(x)] -> FL Prim C(x y) -> ([Non RealPatch C(x)], FL RealPatch C(x y))+geteff _ NilFL = ([],NilFL)+geteff ix (x:>:xs) | Just ix' <- mapM (remP (Normal x)) ix+                               = --traceDoc (greenText "I got rid of x" $$ showPatch x) $+                                 case geteff ix' xs of+                                 (ns,xs') -> (non (Normal x) : map (addP (Normal x)) ns,+                                              Normal x :>: xs')+geteff ix xx = case mergeConflictingNons ix of+               Nothing -> errorDoc $ redText "mergeConflictingNons failed in geteff with ix" $$+                          showNons ix $$ redText "xx" $$ showPatch xx+               Just rix -> case mergeAfterConflicting rix xx of+                           Just (a,x) -> (map (addPs (reverseFL a)) $ toNons x,+                                          a +>+ x)+                           Nothing -> errorDoc $ redText "mergeAfterConflicting failed in geteff"$$+                                      redText "where ix" $$ showNons ix $$+                                      redText "and xx" $$ showPatch xx $$+                                      redText "and rix" $$ showPatch rix++xx2nons :: [Non RealPatch C(x)] -> FL Prim C(x y) -> [Non RealPatch C(x)]+xx2nons ix xx = fst $ geteff ix xx++xx2patches :: [Non RealPatch C(x)] -> FL Prim C(x y) -> FL RealPatch C(x y)+xx2patches ix xx = snd $ geteff ix xx++allNormal :: FL RealPatch C(x y) -> Maybe (FL Prim C(x y))+allNormal (Normal x:>:xs) = (x :>:) `fmap` allNormal xs+allNormal NilFL = Just NilFL+allNormal _ = Nothing++is_consistent :: RealPatch C(x y) -> Maybe Doc+is_consistent (Normal _) = Nothing+is_consistent (Duplicate _) = Nothing+is_consistent (Etacilpud _) = Nothing+is_consistent (Conflictor im mm m@(Non deps _))+    | not $ everyone_conflicts im = Just $ redText "Someone doesn't conflict in im in is_consistent"+    | Just _ <- remPs rmm m, _:>:_ <- mm = Just $ redText "m doesn't conflict with mm in is_consistent"+    | any (\x -> any (x `conflicts_with`) nmm) im+        = Just $ redText "mm conflicts with im in is_consistent where nmm is" $$+                 showNons nmm+    | Nothing <- (nmm ++ im) `minus` toNons deps = Just $ redText "dependencies not in conflict:" $$+                                                   showNons (toNons deps) $$+                                                   redText "compared with deps itself:" $$+                                                   showPatch deps+    | otherwise = case all_conflicts_with m im of+                  (im1,[]) | im1 `eqSet` im -> Nothing+                  (_,imnc) -> Just $ redText "m doesn't conflict with im in is_consistent.  unconflicting:"+                              $$ showNons imnc+    where (nmm, rmm) = geteff im mm+is_consistent c@(InvConflictor _ _ _) = is_consistent (invert c)++everyone_conflicts :: [Non RealPatch C(x)] -> Bool+everyone_conflicts [] = True+everyone_conflicts (x:xs) = case all_conflicts_with x xs of+                            ([],_) -> False+                            (_,xs') -> everyone_conflicts xs'++prim2real :: Prim C(x y) -> RealPatch C(x y)+prim2real = Normal++instance Patchy RealPatch++instance MyEq p => Eq (Sealed (p C(x))) where+    (Sealed x) == (Sealed y) | IsEq <- x =\/= y = True+                             | otherwise = False++merge_with :: Non RealPatch C(x) -> [Non RealPatch C(x)] -> Sealed (FL Prim C(x))+merge_with p [] = effect `mapSeal` unNon p+merge_with p xs = mergeall $ map unNon $ (p:) $ unconflicting_of $+                  filter (\x -> not (p `depends_upon` x) && not (p `conflicts_with` x)) xs+    where mergeall :: [Sealed (FL RealPatch C(x))] -> Sealed (FL Prim C(x))+          mergeall [Sealed x] = Sealed $ effect x+          mergeall [] = Sealed NilFL+          mergeall (Sealed x:Sealed y:rest) = case merge (x :\/: y) of+                                              y' :/\: _ -> mergeall (Sealed (x+>+y'):rest)+          unconflicting_of [] = []+          unconflicting_of (q:qs) = case all_conflicts_with q qs of+                                    ([],_) -> q:qs+                                    (_,nc) -> unconflicting_of nc++instance Conflict RealPatch where+    conflictedEffect (Duplicate (Non _ x)) = [IsC Duplicated x]+    conflictedEffect (Etacilpud _) = impossible+    conflictedEffect (Conflictor _ _ (Non _ x)) = [IsC Conflicted x]+    conflictedEffect (InvConflictor _ _ _) = impossible+    conflictedEffect (Normal x) = [IsC Okay x]+    resolve_conflicts (Conflictor ix xx x) = [mangle_unravelled unravelled : unravelled]+            where unravelled = nub $ filter isn $ map (`merge_with` (x:ix++nonxx)) (x:ix++nonxx)+                  nonxx = case reverseFL $ xx2patches ix xx of+                          NilRL -> []+                          Normal q:<:qs -> [Non (reverseRL qs) q]+                          _ -> []+                  isn :: Sealed (FL p C(x)) -> Bool+                  isn (Sealed NilFL) = False+                  isn _ = True+    resolve_conflicts _ = []++    -- cA+    commute_no_conflicts (Duplicate x :> Duplicate y) = Just (Duplicate y :> Duplicate x)+    commute_no_conflicts (Etacilpud x :> Duplicate y) = Just (Duplicate y :> Etacilpud x)+    commute_no_conflicts (Duplicate x :> Etacilpud y) = Just (Etacilpud y :> Duplicate x)+    commute_no_conflicts (Etacilpud x :> Etacilpud y) = Just (Etacilpud y :> Etacilpud x)+    -- cB+    commute_no_conflicts (x :> Duplicate d) = if d == addP (invert x) (non x)+                                              then Just (x :> Duplicate d)+                                              else do d' <- remP (invert x) d+                                                      return (Duplicate d' :> x)+    commute_no_conflicts (Duplicate d' :> x) = Just (x :> Duplicate (addP (invert x) d'))+    commute_no_conflicts c@(Etacilpud _ :> _) = invertCommuteNC c+    commute_no_conflicts c@(_ :> Etacilpud _) = invertCommuteNC c+    -- cE+    commute_no_conflicts (Normal x :> Normal y) = do y' :> x' <- commute (x :> y)+                                                     return (Normal y' :> Normal x')+    -- cF -- involves a conflict+    -- cG+    commute_no_conflicts (Normal x :> Conflictor iy yy y) =+        do iyy' :> x' <- commuteFL (x :> invert yy)+           y':iy' <- mapM (Normal x' >*) (y:iy)+           return (Conflictor iy' (invert iyy') y' :> Normal x')+    -- cFi+cGi  -- handle with previous two pattern matches+    commute_no_conflicts c@(InvConflictor _ _ _ :> Normal _) = invertCommuteNC c+    -- icG FIXME: where is icF?+    commute_no_conflicts (Conflictor iy' yy' y' :> Normal x') =+        do x :> iyy <- commuteRL (invertFL yy' :> x')+           y:iy <- mapM (*> Normal x') (y':iy')+           return (Normal x :> Conflictor iy (invertRL iyy) y)+    -- icGi      -- handle with previous pattern match+    commute_no_conflicts c@(Normal _ :> InvConflictor _ _ _) = invertCommuteNC c+    -- cH -- this involves a conflict commute+    -- cI+    commute_no_conflicts (Conflictor ix xx x :> Conflictor iy yy y) =+        do xx' :> yy' <- commute (yy :> xx)+           x':ix' <- mapM (yy >>*) (x:ix)+           y':iy' <- mapM (*>> xx') (y:iy)+           False <- return $ any (conflicts_with y) (x':ix')+           False <- return $ any (conflicts_with x') iy+           return (Conflictor iy' yy' y' :> Conflictor ix' xx' x')+    -- cHi+cIi            uses previous two matches+    commute_no_conflicts c@(InvConflictor _ _ _ :> InvConflictor _ _ _) = invertCommuteNC c+    -- cJ+    commute_no_conflicts (InvConflictor ix xx x :> Conflictor iy yy y) =+        do iyy' :> xx' <- commute (xx :> invert yy)+           y':iy' <- mapM (xx' >>*) (y:iy)+           x':ix' <- mapM (invertFL iyy' >>*) (x:ix)+           False <- return $ any (conflicts_with y') (x':ix')+           False <- return $ any (conflicts_with x') iy'+           return (Conflictor iy' (invert iyy') y' :> InvConflictor ix' xx' x')+    -- icJ+    commute_no_conflicts (Conflictor iy' yy' y' :> InvConflictor ix' xx' x') =+        do xx :> iyy <- commute (invert yy' :> xx')+           y:iy <- mapM (*>> xx') (y':iy')+           x:ix <- mapM (*>> yy') (x':ix')+           False <- return $ any (conflicts_with y') (x':ix')+           False <- return $ any (conflicts_with x') iy'+           return (InvConflictor ix xx x :> Conflictor iy (invert iyy) y)++instance FromPrim RealPatch where+    fromPrim = prim2real+instance ToFromPrim RealPatch where+    toPrim (Normal p) = Just p+    toPrim _ = Nothing++instance MyEq RealPatch where+    (Duplicate x) =\/= (Duplicate y) | x == y = IsEq+    (Etacilpud x) =\/= (Etacilpud y) | x == y = IsEq+    (Normal x) =\/= (Normal y) = x =\/= y+    (Conflictor cx xx x) =\/= (Conflictor cy yy y)+        | map (add $ invertFL xx) cx `eqSet`+          map (add $ invertFL yy) cy &&+          add (invert xx) x == add (invert yy) y = xx =/\= yy+    (InvConflictor cx xx x) =\/= (InvConflictor cy yy y)+        | cx `eqSet` cy && x == y = xx =\/= yy+    _ =\/= _ = NotEq++eqSet :: Eq a => [a] -> [a] -> Bool+eqSet [] [] = True+eqSet (x:xs) xys | Just ys <- remove1 x xys = eqSet xs ys+eqSet _ _ = False++remove1 :: Eq a => a -> [a] -> Maybe [a]+remove1 x (y:ys) | x == y = Just ys+                 | otherwise = (y :) `fmap` remove1 x ys+remove1 _ [] = Nothing++minus :: Eq a => [a] -> [a] -> Maybe [a]+minus xs [] = Just xs+minus xs (y:ys) = do xs' <- remove1 y xs+                     xs' `minus` ys++invertNon :: Non RealPatch C(x) -> Non RealPatch C(x)+invertNon (Non c x)+    | Just rc' <- removeRL nix (reverseFL c) = Non (reverseRL rc') (invert x)+    | otherwise = addPs (Normal x :<: reverseFL c) $ non nix+    where nix = Normal $ invert x++nonTouches :: Non RealPatch C(x) -> [FilePath]+nonTouches (Non c x) = list_touched_files (c +>+ fromPrim x :>: NilFL)++toNons :: (Conflict p, Patchy p, ToFromPrim p, Nonable p) => FL p C(x y) -> [Non p C(x)]+toNons xs = map lastNon $ initsFL xs+    where lastNon :: (Conflict p, Patchy p, Nonable p) => Sealed ((p :> FL p) C(x)) -> Non p C(x)+          lastNon (Sealed xxx) = case commuteWhatWeCanRL $ reverseFoo xxx of+                                 deps :> p :> _ -> case non p of+                                                   Non NilFL pp -> Non (reverseRL deps) pp+                                                   Non ds pp -> errorDoc $ redText "Weird case in toNons" $$+                                                                redText "please report this bug!" $$+                                                                (case xxx of+                                                                 z:>zs -> showPatch (z:>:zs)) $$+                                                                redText "ds are" $$ showPatch ds $$+                                                                redText "pp is" $$ showPatch pp+          reverseFoo :: (p :> FL p) C(x y) -> (RL p :> p) C(x y)+          reverseFoo (p :> ps) = rf NilRL p ps+              where rf :: RL p C(a b) -> p C(b c) -> FL p C(c d) -> (RL p :> p) C(a d)+                    rf rs l NilFL = rs :> l+                    rf rs x (y:>:ys) = rf (x:<:rs) y ys++initsFL :: Patchy p => FL p C(x y) -> [Sealed ((p :> FL p) C(x))]+initsFL NilFL = []+initsFL (x:>:xs) = Sealed (x:>NilFL) : map (\ (Sealed (y:>xs')) -> Sealed (x:>y:>:xs')) (initsFL xs)++fromNons :: [Non RealPatch C(x)] -> Maybe (Sealed (FL Prim C(x)))+fromNons [] = Just $ Sealed $ NilFL+fromNons ns = do (Sealed p, ns') <- pullInContext ns+                 ns'' <- mapM (remP $ fromPrim p) ns'+                 Sealed ps <- fromNons ns''+                 return $ Sealed $ p :>: ps++pullInContext :: [Non RealPatch C(x)] -> Maybe (Sealed (Prim C(x)), [Non RealPatch C(x)])+pullInContext (Non NilFL p:ns) = Just (Sealed p, ns)+pullInContext (n:ns) = do (sp,ns') <- pullInContext ns+                          return (sp, n:ns')+pullInContext [] = Nothing++filterConflictsFL :: Non RealPatch C(x) -> FL Prim C(x y) -> (FL Prim :> FL Prim) C(x y)+filterConflictsFL _ NilFL = NilFL :> NilFL+filterConflictsFL n (p:>:ps)+    | Just n' <- remP (fromPrim p) n = case filterConflictsFL n' ps of+                                       p1 :> p2 -> p:>:p1 :> p2+    | otherwise = case commuteWhatWeCanFL (p :> ps) of+                  p1 :> p' :> p2 -> case filterConflictsFL n p1 of+                                    p1a :> p1b -> p1a :> p1b +>+ p' :>: p2++instance Invert RealPatch where+    invert (Duplicate d) = Etacilpud d+    invert (Etacilpud d) = Duplicate d+    invert (Normal p) = Normal (invert p)+    invert (Conflictor x c p) = InvConflictor x c p+    invert (InvConflictor x c p) = Conflictor x c p+    identity = Normal identity++instance Commute RealPatch where+--    commute (x :> y) | traceDoc (greenText "commuting x" $$ showPatch x $$+--                                 greenText "with y" $$ showPatch y) False = undefined+    commute (x :> y) | Just (y' :> x') <- commute_no_conflicts (assertConsistent x :> assertConsistent y) = Just (y' :> x')+    -- cF+    commute (Normal x :> Conflictor a1'nop2 n1'x p1') -- these patches conflicted+        | Just rn1' <- removeRL x (reverseFL n1'x) =+                      do let p2:n1nons = reverse $ xx2nons a1'nop2 $ reverseRL (x:<:rn1')+                             a2 = p1':a1'nop2++n1nons+                         case (a1'nop2, reverseRL rn1', p1') of+                           ([], NilFL, Non c y) | NilFL <- sort_coalesceFL $ effect c ->+                                    Just (Normal y :> Conflictor a1'nop2 (y:>:NilFL) p2)+                           (a1,n1,_) -> Just (Conflictor a1 n1 p1' :> Conflictor a2 NilFL p2)+    -- cFi  -- handle with previous pattern match+    commute c@(InvConflictor _ _ _ :> Normal _) = invertCommute c+    -- cH+    commute (Conflictor a1 n1 p1 :> Conflictor a2 n2 p2)+        | Just a2_minus_p1 <- remove1 p1' a2,+          not (p2 `depends_upon` p1') =+              do let n1nons = map (add n2) $ xx2nons a1 n1+                     n2nons = xx2nons a2 n2+                     Just a2_minus_p1n1 = a2_minus_p1 `minus` n1nons+                     n2n1 = n2 +>+ n1+                     a1' = map (add n2) a1+                     p2ooo = remNons a1' p2+                 n1' :> n2' <- return $ filterConflictsFL p2ooo n2n1+                 let n1'n2'nons = xx2nons a2_minus_p1n1 (n1'+>+n2')+                     n1'nons = take (lengthFL n1') n1'n2'nons+                     n2'nons = drop (lengthFL n1') n1'n2'nons+                     Just a1'nop2 = (a2++n2nons) `minus` (p1':n1'nons)+                     Just a2'o = --traceDoc (greenText "\n\nConflictor a1 n1 p1 is" $$+                                 --          showPatch (assertConsistent $ Conflictor a1 n1 p1) $$+                                 --          greenText "and Conflictor a2 n2 p2 is" $$+                                 --          showPatch (assertConsistent $ Conflictor a2 n2 p2) $$+                                 --          greenText "where n2'nons is" $$ showNons n2'nons $$+                                 --          greenText "and others are" $$+                                 --          showNons (fst $ all_conflicts_with p2 $ a2_minus_p1++n2nons) $$+                                 --          greenText "These came from" $$+                                 --          showNons (a2_minus_p1++n2nons) $$+                                 --          greenText "n1'n2'nons" $$ showNons n1'n2'nons $$+                                 --          greenText "from n1' :> n2'" $$+                                 --          showPatch n1' $$ greenText ":>" $$ showPatch n2' $$+                                 --          greenText "p2" $$ showNon p2 $$+                                 --          greenText "p2 fixed" $$ showNon p2ooo $$+                                 --          -- greenText "pren1" $$ showPatch pren1 $$+                                 --          greenText "n1'" $$ showPatch n1' $$+                                 --          greenText "p2" $$ showNon p2 +                                 --         ) +                                 (fst $ all_conflicts_with p2 $ a2_minus_p1++n2nons) `minus` n2'nons+                     Just a2' = mapM (remPs (xx2patches a1'nop2 n1')) $+                                a2'o+                     Just p2' = remPs (xx2patches a1'nop2 n1') p2+                 case (a2', n2', p2') of+                   ([], NilFL, Non c x) | NilFL <- sort_coalesceFL $ effect c ->+                                          Just (Normal x :> Conflictor a1'nop2 (n1'+>+x:>:NilFL) p1')+                                        | otherwise -> impossible+                   _ -> Just (Conflictor a2' n2' p2' :> Conflictor (p2:a1'nop2) n1' p1')+        where (_,rpn2) = geteff a2 n2+              p1' = addPs (reverseFL rpn2) p1+    -- cHi         -- uses previous match+    commute c@(InvConflictor _ _ _ :> InvConflictor _ _ _) = invertCommute c+    commute _ = Nothing++    merge (InvConflictor _ _ _ :\/: _) = impossible+    merge (_ :\/: InvConflictor _ _ _) = impossible+    merge (Etacilpud _ :\/: _) = impossible+    merge (_ :\/: Etacilpud _) = impossible+--    merge (x :\/: y) | traceDoc (greenText "merging x" $$ showPatch x $$+--                                 greenText "with y" $$ showPatch y) False = impossible+    -- mA+    merge (Duplicate a :\/: Duplicate b) = Duplicate b :/\: Duplicate a+    -- mB+    merge (Duplicate a :\/: b) = b :/\: Duplicate (addP (invert b) a) -- FIXME ???+    -- smB+    merge m@(_ :\/: Duplicate _) = swapMerge m+    -- mC+--    merge _ | traceDoc (greenText "about to look for conflictingness") False = impossible+    merge (x :\/: y) | Just (y' :> ix') <- commute (invert (assertConsistent x) :> assertConsistent y),+                       Just (y'' :> _) <- commute (x :> y'),+                       IsEq <- y'' =\/= y = --traceDoc (greenText "These didn't conflict") $+                                            assertConsistent y' :/\: invert (assertConsistent ix')+                     | IsEq <- x =\/= y,+                       n <- addP (invert x) $ non x =+                                 --traceDoc (greenText "Found duplicate") $+                                 Duplicate n :/\: Duplicate n+--    merge (x :\/: y) | traceDoc (greenText "trying to merging x" $$ showPatch x $$+--                                 greenText "which conflicts with y" $$ showPatch y) False = impossible+    -- mD+    merge (Normal x :\/: Normal y) =+        Conflictor [] (x:>:NilFL) (non $ Normal y) :/\: Conflictor [] (y:>:NilFL) (non $ Normal x)+    -- mG+    merge (Normal x :\/: Conflictor iy yy y) =+          --traceDoc (greenText "merging Normal x" $$ showPatch x $$+          --          greenText "and Conflictor iy yy y" $$ showPatch (Conflictor iy yy y)) $+          Conflictor iy yyx y :/\: Conflictor (y:iy++nyy) NilFL x'+              where yyx = yy +>+ x:>:NilFL+                    (x':nyy) = reverse $ xx2nons iy yyx+    -- smE+smG+    merge m@(Conflictor _ _ _ :\/: Normal _) = swapMerge m+--    merge (x :\/: y) | traceDoc (greenText "still trying to merge x" $$ showPatch x $$+--                                 greenText "with y" $$ showPatch y) False = impossible+    -- mH see also cH+    merge (Conflictor ix xx x :\/: Conflictor iy yy y) =+        case pullCommonRL (reverseFL xx) (reverseFL yy) of+        CommonRL rxx1 ryy1 c ->+            case commuteRLFL (ryy1 :> invertRL rxx1) of+            Just (ixx' :> ryy') ->+                let xx' = invert ixx'+                    yy' = reverseRL ryy'+                    y':iy' = map (add $ invertFL ixx') (y:iy)+                    x':ix' = map (add ryy') (x:ix)+                    nyy' = xx2nons iy' yy'+                    nxx' = xx2nons ix' xx'+                    icx = drop (lengthRL rxx1) $ xx2nons ix (reverseRL $ c+<+rxx1)+                    ic' = map (add ryy') icx+                    ixy' = ic' ++ (iy'+++ix')+                    -- +++ above is a more efficient version of nub+                    -- (iy'++ix') given that we know each element shows up+                    -- only once in either list.+                in --traceDoc (greenText "here I am! and so is ixy'" $$ showNons ixy' $$+                   --          greenText "and iy" $$ showNons iy $$ greenText (show $ length iy) $$+                   --          greenText "and ix" $$ showNons ix $$+                   --          greenText "and iy'" $$ showNons iy' $$+                   --          greenText "and ix'" $$ showNons ix' $$+                   --          greenText "and ic'" $$ showNons ic'+                   --         ) $+                Conflictor (x':ixy'++nxx') yy' y' :/\: Conflictor (y':ixy'++nyy') xx' x'+            Nothing -> impossible pullInContext fromNons+--    merge _ = error "haven't finished fixing merge"++    list_touched_files (Duplicate p) = nonTouches p+    list_touched_files (Etacilpud p) = nonTouches p+    list_touched_files (Normal p) = list_touched_files p+    list_touched_files (Conflictor x c p) =+        nubsort $ concatMap nonTouches x ++ list_touched_files c ++ nonTouches p+    list_touched_files (InvConflictor x c p) =+        nubsort $ concatMap nonTouches x ++ list_touched_files c ++ nonTouches p++{-+all_conflicts_withFL :: FL Prim C(x y) -> [Non RealPatch C(x)]+                     -> ([Non RealPatch C(x)], [Non RealPatch C(x)])+all_conflicts_withFL xx ns = case partition f ns of+                             ([],nc) -> ([],nc)+                             (c,nc) -> case acw c nc of+                                       (c',nc') -> (c++c',nc')+    where acw (y:ys) zs = case all_conflicts_with y zs of+                          (c,nc) -> case acw ys nc of+                                    (c',nc') -> (c++c',nc')+          acw [] zs = ([],zs)+          f (Non c p) = case commuteRLFL (invertFL c :> mapFL_FL Normal xx) of+                        Nothing -> True+                        Just (xx' :> _) -> case commuteFL (Normal (invert p) :> xx') of+                                           Nothing -> True+                                           Just _ -> False+-}+all_conflicts_with :: Non RealPatch C(x) -> [Non RealPatch C(x)]+                   -> ([Non RealPatch C(x)], [Non RealPatch C(x)])+all_conflicts_with x ys = acw $ partition (conflicts_with x) ys+    where acw ([],nc) = ([],nc)+          acw (c:cs, nc) = case all_conflicts_with c nc of+                           (c1,nc1) -> case acw (cs, nc1) of+                                       (xs',nc') -> (c:c1++xs',nc')++conflicts_with :: Non RealPatch C(x) -> Non RealPatch C(x) -> Bool+conflicts_with x y | x `depends_upon` y || y `depends_upon` x = False+conflicts_with x (Non cy y) =+    case remPs cy x of+    Just (Non cx' x') -> case commuteFL (fromPrim (invert y) :> cx' +>+ fromPrim x' :>: NilFL) of+                         Just _ -> False+                         Nothing -> True+    Nothing -> True++depends_upon :: Non RealPatch C(x) -> Non RealPatch C(x) -> Bool+depends_upon (Non xs _) (Non ys y) =+    case remove_subsequenceFL (ys +>+ fromPrim y :>: NilFL) xs of+    Just _ -> True+    Nothing -> False++(+++) :: Eq a => [a] -> [a] -> [a]+[] +++ x = x+x +++ [] = x+(x:xs) +++ xys | Just ys <- remove1 x xys = x : (xs +++ ys)+               | otherwise = x : (xs +++ xys)++swapMerge :: (RealPatch :\/: RealPatch) C(x y) -> (RealPatch :/\: RealPatch) C(x y)+swapMerge (x :\/: y) = case merge (y :\/: x) of x' :/\: y' -> y' :/\: x'++invertCommute :: (RealPatch :> RealPatch) C(x y) -> Maybe ((RealPatch :> RealPatch) C(x y))+invertCommute (x :> y) = do ix' :> iy' <- commute (invert y :> invert x)+                            return (invert iy' :> invert ix')++invertCommuteNC :: (RealPatch :> RealPatch) C(x y) -> Maybe ((RealPatch :> RealPatch) C(x y))+invertCommuteNC (x :> y) = do ix' :> iy' <- commute_no_conflicts (invert y :> invert x)+                              return (invert iy' :> invert ix')+pullCommon :: Patchy p => FL p C(o x) -> FL p C(o y) -> Common p C(o x y)+pullCommon NilFL ys = Common NilFL NilFL ys+pullCommon xs NilFL = Common NilFL xs NilFL+pullCommon (x:>:xs) xys | Just ys <- removeFL x xys = case pullCommon xs ys of+                                                      Common c xs' ys' -> Common (x:>:c) xs' ys'+pullCommon (x:>:xs) ys = case commuteWhatWeCanFL (x :> xs) of+                         xs1:>x':>xs2 -> case pullCommon xs1 ys of+                                         Common c xs1' ys' -> Common c (xs1'+>+x':>:xs2) ys'++data Common p C(o x y) where+    Common :: FL p C(o i) -> FL p C(i x) -> FL p C(i y) -> Common p C(o x y)++pullCommonRL :: Patchy p => RL p C(x o) -> RL p C(y o) -> CommonRL p C(x y o)+pullCommonRL NilRL ys = CommonRL NilRL ys NilRL+pullCommonRL xs NilRL = CommonRL xs NilRL NilRL+pullCommonRL (x:<:xs) xys+    | Just ys <- removeRL x xys = case pullCommonRL xs ys of+                                  CommonRL xs' ys' c -> CommonRL xs' ys' (x:<:c)+pullCommonRL (x:<:xs) ys =+    case commuteWhatWeCanRL (xs :> x) of+    xs1:>x':>xs2 -> case pullCommonRL xs2 ys of+                    CommonRL xs2' ys' c -> CommonRL (xs2'+<+x':<:xs1) ys' c++data CommonRL p C(x y f) where+    CommonRL :: RL p C(x i) -> RL p C(y i) -> RL p C(i f) -> CommonRL p C(x y f)++instance Apply RealPatch where+    apply opts p = apply opts (effect p)+    applyAndTryToFixFL (Normal p) = mapMaybeSnd (mapFL_FL Normal) `liftM` applyAndTryToFixFL p+    applyAndTryToFixFL x = do apply [] x; return Nothing++instance ShowPatch RealPatch where+    showPatch (Duplicate d) = blueText "duplicate" $$ showNon d+    showPatch (Etacilpud d) = blueText "etacilpud" $$ showNon d+    showPatch (Normal p) = showPrim NewFormat p+    showPatch (Conflictor i NilFL p) =+        blueText "conflictor" <+> showNons i <+> blueText "[]" $$ showNon p+    showPatch (Conflictor i cs p) =+        blueText "conflictor" <+> showNons i <+> blueText "[" $$+        showPatch cs $$+        blueText "]" $$+        showNon p+    showPatch (InvConflictor i NilFL p) =+        blueText "rotcilfnoc" <+> showNons i <+> blueText "[]" $$ showNon p+    showPatch (InvConflictor i cs p) =+        blueText "rotcilfnoc" <+> showNons i <+> blueText "[" $$+        showPatch cs $$+        blueText "]" $$+        showNon p+    showContextPatch s (Normal p) = showContextPatch s p+    showContextPatch _ c = showPatch c++instance ReadPatch RealPatch where+ readPatch' want_eof =+     do s <- peek_input+        case fmap (unpackPS . fst) $ my_lex s of+          Just "duplicate" ->+              do work my_lex+                 p <- readNon+                 return $ (Sealed . Duplicate) `fmap` p+          Just "etacilpud" ->+              do work my_lex+                 p <- readNon+                 return $ (Sealed . Etacilpud) `fmap` p+          Just "conflictor" ->+              do work my_lex+                 --let tracePeek x = do y <- peek_input+                 --                     traceDoc (greenText x $$ greenText (show $ unpackPS y)) return ()+                 i <- readNons+                 Just (Sealed ps) <- bracketedFL (fromIntegral $ fromEnum '[') (fromIntegral $ fromEnum ']')++                 Just p <- readNon+                 return $ Just $ Sealed $ Conflictor i (unsafeCoerceP ps) p+          Just "rotcilfnoc" ->+              do work my_lex+                 i <- readNons+                 Just (Sealed ps) <- bracketedFL (fromIntegral $ fromEnum '[') (fromIntegral $ fromEnum ']')+                 Just p <- readNon+                 return $ Just $ Sealed $ InvConflictor i ps p+          _ -> do mp <- readPrim NewFormat want_eof+                  case mp of+                    Just p -> return $ Just $ Normal `mapSeal` p+                    Nothing -> return Nothing++instance Show (RealPatch C(x y)) where+    show p = renderString $ showPatch p++instance Show2 RealPatch where+    show2 = show++instance Nonable RealPatch where+    non (Duplicate d) = d+    non (Etacilpud d) = invertNon d -- FIXME !!! ???+    non (Normal p) = Non NilFL p+    non (Conflictor _ xx x) = add (invertFL xx) x+    non (InvConflictor _ _ n) = invertNon n++instance Effect RealPatch where+    effect (Duplicate _) = NilFL+    effect (Etacilpud _) = NilFL+    effect (Normal p) = effect p+    effect (Conflictor _ e _) = invert e+    effect (InvConflictor _ e _) = e+    effectRL (Duplicate _) = NilRL+    effectRL (Etacilpud _) = NilRL+    effectRL (Normal p) = effectRL p+    effectRL (Conflictor _ e _) = invertFL e+    effectRL (InvConflictor _ e _) = reverseFL e+    isHunk rp = do Normal p <- return rp+                   isHunk p++\end{code}
+ src/Darcs/Patch/Set.lhs view
@@ -0,0 +1,36 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.Patch.Set ( PatchSet, SealedPatchSet ) where++import Darcs.Hopefully ( PatchInfoAnd )+import Darcs.Patch.Ordered ( RL )+import Darcs.Sealed ( Sealed )++-- A PatchSet is in reverse order, plus has information about which tags+-- are clean, meaning all patches applied prior to them are in the tag+-- itself, so we can stop reading at that point.  Just to clarify, the+-- first patch in a PatchSet is the one most recently applied to the repo.+type PatchSet p C(x) = RL (RL (PatchInfoAnd p)) C(() x)++type SealedPatchSet p = Sealed (RL (RL (PatchInfoAnd p)) C(()))+\end{code}+
+ src/Darcs/Patch/Show.lhs view
@@ -0,0 +1,87 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fno-warn-orphans #-}+module Darcs.Patch.Show ( showPatch_, showNamedPrefix )+             where++import Prelude hiding ( pi )++import Printer ( Doc, renderString, vcat,+                 text, blueText,+                 ($$), (<+>) )+import Darcs.Patch.Core ( Patch(..) )+import Darcs.Patch.Prim ( showPrim, FileNameFormat(..) )+import Darcs.Patch.Info ( PatchInfo, showPatchInfo )+import Darcs.Patch.Ordered ( FL(NilFL), mapFL )+#include "gadts.h"+\end{code}++\section{Patch string formatting}++Of course, in order to store our patches in a file, we'll have to save them+as some sort of strings.  The convention is that each patch string will end+with a newline, but on parsing we skip any amount of whitespace between+patches.+\begin{code}+instance Show (Patch C(x y))  where+    show p = renderString (showPatch_ p) ++ "\n"++showPatch_ :: Patch C(a b) -> Doc+showPatch_ (PP p) = showPrim OldFormat p+showPatch_ (ComP NilFL) = blueText "{" $$ blueText "}"+showPatch_ (ComP ps)  = blueText "{"+                        $$ vcat (mapFL showPatch_ ps)+                        $$ blueText "}"+showPatch_ (Merger _ _ p1 p2) = showMerger "merger" p1 p2+showPatch_ (Regrem _ _ p1 p2) = showMerger "regrem" p1 p2+\end{code}++\paragraph{Merger patches}+Merge two patches.  The MERGERVERSION is included to allow some degree of+backwards compatibility if the merger algorithm needs to be changed.+\begin{verbatim}+merger MERGERVERSION+<first patch>+<second patch>+\end{verbatim}+\begin{code}+showMerger :: String -> Patch C(a b) -> Patch C(d e) -> Doc+showMerger merger_name p1 p2 =+    blueText merger_name <+> text "0.0" <+> blueText "("+                           $$ showPatch_ p1+                           $$ showPatch_ p2+                           $$ blueText ")"+\end{code}++\paragraph{Named patches}++Named patches are displayed as a ``patch id'' which is in square brackets,+followed by a patch.  Optionally, after the patch id (but before the patch+itself) can come a list of dependencies surrounded by angle brackets.  Each+dependency consists of a patch id.++\begin{code}+showNamedPrefix :: PatchInfo -> [PatchInfo] -> Doc+showNamedPrefix n d = showPatchInfo n+                   $$ blueText "<"+                   $$ vcat (map showPatchInfo d)+                   $$ blueText ">"++\end{code}
+ src/Darcs/Patch/Test.lhs view
@@ -0,0 +1,712 @@+%  Copyright (C) 2002-2003,2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fno-warn-deprecations -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Patch.Test+             ( prop_read_show,+               prop_inverse_composition, prop_commute_twice,+               prop_inverse_valid, prop_other_inverse_valid,+               prop_commute_equivalency, prop_commute_either_order,+               prop_commute_either_way, prop_merge_is_commutable_and_correct,+               prop_merge_is_swapable, prop_merge_valid,+               prop_unravel_three_merge, prop_unravel_seq_merge,+               prop_unravel_order_independent,+               prop_simple_smart_merge_good_enough,+               prop_elegant_merge_good_enough,+               prop_patch_and_inverse_is_identity,+               quickmerge, check_patch, check_a_patch, verbose_check_a_patch,+               prop_resolve_conflicts_valid,+               test_patch, prop_commute_inverse,+               subcommutes_inverse, subcommutes_nontrivial_inverse,+               subcommutes_failure,+               join_patches+             ) where++import Prelude hiding ( pi )+import Test.QuickCheck+import Control.Monad ( liftM, liftM2, liftM3, liftM4, replicateM )++import Darcs.Patch.Info ( PatchInfo, patchinfo )+import Darcs.Patch.Check ( PatchCheck, Possibly(..),+                    check_move, remove_dir, create_dir,+                    is_valid, insert_line, file_empty, file_exists,+                    delete_line, modify_file, create_file, remove_file,+                    do_check, do_verbose_check,+                  )+import RegChars ( regChars )+import FastPackedString ( PackedString, packString,+                          linesPS, nullPS, concatPS, breakPS,+                        )+import FileName ( fn2fp )++import Darcs.Patch.Patchy ( Commute )+import Darcs.Patch ( addfile, adddir, move, showPatch,+                     hunk, tokreplace, joinPatches, binary,+                     changepref, is_merger, invert, commute, commutex, merge,+                     readPatch, resolve_conflicts,+                     effect, fromPrims,+                     unravel, merger, elegant_merge )+import Darcs.Patch.Core ( Patch(..) )+import Darcs.Patch.Prim ( Prim(..), DirPatchType(..), FilePatchType(..),+                          CommuteFunction, Perhaps(..),+                          subcommutes )+import Printer ( renderPS )+import Darcs.Patch.Ordered+import Darcs.Sealed ( Sealed(Sealed), unsafeUnseal, unseal )++#include "impossible.h"++instance Eq Patch where+   x == y = IsEq == (x =\/= y)++instance Eq Prim where+   x == y = IsEq == (x =\/= y)++instance (Commute a, MyEq a) => Eq (FL a) where+   x == y = IsEq == (x =\/= y)++instance Arbitrary Patch where+    arbitrary = sized arbpatch+--    coarbitrary p = coarbitrary (show p)++instance Arbitrary Prim where+    arbitrary = onepatchgen+--    coarbitrary = impossible+\end{code}++\begin{code}+hunkgen :: Gen Prim+hunkgen = do+  i <- frequency [(1,choose (0,5)),(1,choose (0,35)),+                  (2,return 0),(3,return 1),(2,return 2),(1,return 3)]+  j <- frequency [(1,choose (0,5)),(1,choose (0,35)),+                  (2,return 0),(3,return 1),(2,return 2),(1,return 3)]+  if i == 0 && j == 0 then hunkgen+    else liftM4 hunk filepathgen linenumgen+                (replicateM i filelinegen)+                (replicateM j filelinegen)++tokreplacegen :: Gen Prim+tokreplacegen = do+  f <- filepathgen+  o <- tokengen+  n <- tokengen+  if o == n+     then return $ tokreplace f "A-Za-z" "old" "new"+     else return $ tokreplace f "A-Za-z_" o n++twofilegen :: (FilePath -> FilePath -> Prim) -> Gen Prim+twofilegen p = do+  n1 <- filepathgen+  n2 <- filepathgen+  if n1 /= n2 && (check_a_patch $ fromPrims $ (p n1 n2 :>: NilFL))+     then return $ p n1 n2+     else twofilegen p++chprefgen :: Gen Prim+chprefgen = do+  f <- oneof [return "color", return "movie"]+  o <- tokengen+  n <- tokengen+  if o == n then return $ changepref f "old" "new"+            else return $ changepref f o n++simplepatchgen :: Gen Prim+simplepatchgen = frequency [(1,liftM addfile filepathgen),+                            (1,liftM adddir filepathgen),+                            (1,liftM3 binary filepathgen arbitrary arbitrary),+                            (1,twofilegen move),+                            (1,tokreplacegen),+                            (1,chprefgen),+                            (7,hunkgen)+                           ]++onepatchgen :: Gen Prim+onepatchgen = oneof [simplepatchgen, (invert) `fmap` simplepatchgen]++norecursgen :: Int -> Gen Patch+norecursgen 0 = PP `fmap` onepatchgen+norecursgen n = oneof [PP `fmap` onepatchgen,flatcompgen n]++arbpatch :: Int -> Gen Patch+arbpatch 0 = PP `fmap` onepatchgen+arbpatch n = frequency [(3,PP `fmap` onepatchgen),+                       -- (1,compgen n),+                        (2,flatcompgen n),+                        (0,raw_merge_gen n),+                        (0,mergegen n),+                        (1,PP `fmap` onepatchgen)+                       ]++unempty :: Arbitrary a => Gen [a]+unempty = do+  as <- arbitrary+  case as of+    [] -> unempty+    _ -> return as++join_patches :: [Patch] -> Patch+join_patches = joinPatches . unsafeFL++raw_merge_gen :: Int -> Gen Patch+raw_merge_gen n = do p1 <- arbpatch len+                     p2 <- arbpatch len+                     if (check_a_patch $ join_patches [invert p1,p2]) &&+                        (check_a_patch $ join_patches [invert p2,p1])+                        then case merge (p2 :\/: p1) of+                             _ :/\: p2' -> return p2'+                        else raw_merge_gen n+    where len = if n < 15 then n`div`3 else 3++mergegen :: Int -> Gen Patch+mergegen n = do+  p1 <- norecursgen len+  p2 <- norecursgen len+  if (check_a_patch $ join_patches [invert p1,p2]) &&+         (check_a_patch $ join_patches [invert p2,p1])+     then case merge (p2:\/:p1) of+          p1' :/\: p2' ->+              if check_a_patch $ join_patches [p1,p2']+              then return $ join_patches [p1,p2']+              else return $ join_patches [PP $ addfile "Error_in_mergegen",+                                          PP $ addfile "Error_in_mergegen",+                                          p1,p2,p1',p2']+     else mergegen n+  where len = if n < 15 then n`div`3 else 3++arbpi :: Gen PatchInfo+arbpi = liftM4 patchinfo unempty unempty unempty unempty++instance Arbitrary PatchInfo where+    arbitrary = arbpi+--    coarbitrary pi = coarbitrary (show pi)++instance Arbitrary PackedString where+    arbitrary = liftM packString arbitrary+--    coarbitrary ps = coarbitrary (unpackPS ps)++{-+plistgen :: Int -> Int -> Gen [Patch]+plistgen s n+    | n <= 0 = return []+    | otherwise = do+                  next <- arbpatch s+                  rest <- plistgen s (n-1)+                  return $ next : rest++compgen :: Int -> Gen Patch+compgen n = do+    size <- choose (0,n)+    myp <- liftM join_patches $ plistgen size ((n+1) `div` (size+1))+-- here I assume we only want to consider valid patches...+    if check_a_patch myp+       then return myp+       else compgen n+-}++flatlistgen :: Int -> Gen [Patch]+flatlistgen n = replicateM n (PP `fmap` onepatchgen)++flatcompgen :: Int -> Gen Patch+flatcompgen n = do+  myp <- liftM (join_patches . regularize_patches) $ flatlistgen n+  if check_a_patch myp+     then return myp+     else flatcompgen n++linenumgen :: Gen Int+linenumgen = frequency [(1,return 1), (1,return 2), (1,return 3),+                    (3,liftM (\n->1+abs n) arbitrary) ]++tokengen :: Gen String+tokengen = oneof [return "hello", return "world", return "this",+                  return "is", return "a", return "silly",+                  return "token", return "test"]++toklinegen :: Gen String+toklinegen = liftM unwords $ replicateM 3 tokengen++filelinegen :: Gen PackedString+filelinegen = liftM packString $+              frequency [(1,map fromSafeChar `fmap` arbitrary),(5,toklinegen),+                         (1,return ""), (1,return "{"), (1,return "}") ]++filepathgen :: Gen String+filepathgen = liftM fixpath badfpgen++fixpath :: String -> String+fixpath "" = "test"+fixpath p = fpth p++fpth :: String -> String+fpth ('/':'/':cs) = fpth ('/':cs)+fpth (c:cs) = c : fpth cs+fpth [] = []++newtype SafeChar = SS Char+instance Arbitrary SafeChar where+    arbitrary = oneof $ map (return . SS) (['a'..'z']++['A'..'Z']++['1'..'9']++"0")++fromSafeChar :: SafeChar -> Char+fromSafeChar (SS s) = s++badfpgen :: Gen String+badfpgen =  frequency [(1,return "test"), (1,return "hello"), (1,return "world"),+                       (1,map fromSafeChar `fmap` arbitrary),+                       (1,liftM2 (\a b-> a++"/"++b) filepathgen filepathgen) ]++{-+instance Arbitrary Char where+    arbitrary = oneof $ map return+                (['a'..'z']++['A'..'Z']++['1'..'9']++['0','~','.',',','-','/'])+-}+--    coarbitrary c = coarbitrary (ord c)+\end{code}++\begin{code}+check_patch :: Patch -> PatchCheck Bool+check_a_patch :: Patch -> Bool+check_a_patch p = do_check $ do check_patch p+                                check_patch $ invert p+verbose_check_a_patch :: Patch -> Bool+verbose_check_a_patch p = do_verbose_check $ do check_patch p+                                                check_patch $ invert p++check_patch p | is_merger p = do+  check_patch $ fromPrims $ effect p+check_patch (Merger _ _ _ _) = impossible+check_patch (Regrem _ _ _ _) = impossible+check_patch (ComP NilFL) = is_valid+check_patch (ComP (p:>:ps)) =+  check_patch p >> check_patch (ComP ps)+check_patch (PP Identity) = is_valid+check_patch (PP (Split NilFL)) = is_valid+check_patch (PP (Split (p:>:ps))) =+  check_patch (PP p) >> check_patch (PP (Split ps))++check_patch (PP (FP f RmFile)) = remove_file $ fn2fp f+check_patch (PP (FP f AddFile)) =  create_file $ fn2fp f+check_patch (PP (FP f (Hunk line old new))) = do+    file_exists $ fn2fp f+    mapM (delete_line (fn2fp f) line) old+    mapM (insert_line (fn2fp f) line) (reverse new)+    is_valid+check_patch (PP (FP f (TokReplace t old new))) =+    modify_file (fn2fp f) (try_tok_possibly t old new)+-- note that the above isn't really a sure check, as it leaves PSomethings+-- and PNothings which may have contained new...+check_patch (PP (FP f (Binary o n))) = do+    file_exists $ fn2fp f+    mapM (delete_line (fn2fp f) 1) (linesPS o)+    file_empty $ fn2fp f+    mapM (insert_line (fn2fp f) 1) (reverse $ linesPS n)+    is_valid++check_patch (PP (DP d AddDir)) = create_dir $ fn2fp d+check_patch (PP (DP d RmDir)) = remove_dir $ fn2fp d++check_patch (PP (Move f f')) = check_move (fn2fp f) (fn2fp f')+check_patch (PP (ChangePref _ _ _)) = return True++regularize_patches :: [Patch] -> [Patch]+regularize_patches patches = rpint [] patches+    where rpint ok_ps [] = ok_ps+          rpint ok_ps (p:ps) =+            if check_a_patch (join_patches $ p:ok_ps)+            then rpint (p:ok_ps) ps+            else rpint ok_ps ps+\end{code}++\begin{code}+prop_inverse_composition :: Patch -> Patch -> Bool+prop_inverse_composition p1 p2 =+    invert (join_patches [p1,p2]) == join_patches [invert p2, invert p1]+prop_inverse_valid :: Patch -> Bool+prop_inverse_valid p1 = check_a_patch $ join_patches [invert p1,p1]+prop_other_inverse_valid :: Patch -> Bool+prop_other_inverse_valid p1 = check_a_patch $ join_patches [p1,invert p1]+\end{code}++\begin{code}+prop_commute_twice :: Patch -> Patch -> Property+prop_commute_twice p1 p2 =+    (does_commute p1 p2) ==> (Just (p2:<p1) == (commutex (p2:<p1) >>= commutex))+does_commute :: Patch -> Patch -> Bool+does_commute p1 p2 =+    commutex (p2:<p1) /= Nothing && (check_a_patch $ join_patches [p1,p2])+prop_commute_equivalency :: Patch -> Patch -> Property+prop_commute_equivalency p1 p2 =+    (does_commute p1 p2) ==>+    case commutex (p2:<p1) of+    Just (p1':<p2') -> check_a_patch $ join_patches [p1,p2,invert p1',invert p2']+    _ -> impossible+\end{code}++\begin{code}+prop_commute_either_way :: Patch -> Patch -> Property+prop_commute_either_way p1 p2 =+    does_commute p1 p2 ==> does_commute (invert p2) (invert p1)+\end{code}++\begin{code}+prop_commute_either_order :: Patch -> Patch -> Patch -> Property+prop_commute_either_order p1 p2 p3 =+    check_a_patch (join_patches [p1,p2,p3]) &&+    does_commute p1 (join_patches [p2,p3]) &&+    does_commute p2 p3 ==>+    case commutex (p2:<p1) of+    Nothing -> False+    Just (p1':<p2') ->+        case commutex (p3:<p1') of+        Nothing -> False+        Just (_:<p3') ->+            case commutex (p3':<p2') of+            Nothing -> False+            Just (_:< p3'') ->+                case commutex (p3:<p2) of+                Nothing -> False+                Just (_:<p3'a) ->+                    case commutex (p3'a:<p1) of+                    Just (_:<p3''a) -> p3''a == p3''+                    Nothing -> False+\end{code}++\begin{code}+prop_patch_and_inverse_is_identity :: Patch -> Patch -> Property+prop_patch_and_inverse_is_identity p1 p2 =+    (check_a_patch $ join_patches [p1,p2]) && (commutex (p2:<p1) /= Nothing) ==>+    case commutex (p2:<p1) of+    Just (_:<p2') -> case commutex (p2':<invert p1) of+                    Nothing -> True -- This is a subtle distinction.+                    Just (_:<p2'') -> p2'' == p2+    Nothing -> impossible+\end{code}++\begin{code}+quickmerge :: (Patch :\/: Patch) -> Patch+quickmerge (p1:\/:p2) = case merge (p1:\/:p2) of+                        _ :/\: p1' -> p1'+\end{code}++\begin{code}+prop_merge_is_commutable_and_correct :: Patch -> Patch -> Property+prop_merge_is_commutable_and_correct p1 p2 =+    (check_a_patch $ join_patches [invert p1,p2]) ==>+    case merge (p2:\/:p1) of+    p1' :/\: p2' ->+        case commutex (p2':<p1) of+        Nothing -> False+        Just (p1'':<p2'') -> p2'' == p2 && p1' == p1''+prop_merge_is_swapable :: Patch -> Patch -> Property+prop_merge_is_swapable p1 p2 =+    (check_a_patch $ join_patches [invert p1,p2]) ==>+    case merge (p2:\/:p1) of+    p1' :/\: p2' ->+           case merge (p1:\/:p2) of+           p2''' :/\: p1''' -> p1' == p1''' && p2' == p2'''++prop_merge_valid :: Patch -> Patch -> Property+prop_merge_valid p1 p2 =+    (check_a_patch $ join_patches [invert p1,p2]) ==>+    case merge (p2:\/:p1) of+    _ :/\: p2' ->+        check_a_patch $ join_patches [invert p1,p2,invert p2,p1,p2']+\end{code}++\begin{code}+prop_simple_smart_merge_good_enough :: Patch -> Patch -> Property+prop_simple_smart_merge_good_enough p1 p2 =+    (check_a_patch $ join_patches [invert p1,p2]) ==>+    smart_merge (p2:\/:p1) == simple_smart_merge (p2:\/:p1)++smart_merge :: (Patch :\/: Patch) -> Maybe (Patch :< Patch)+smart_merge (p1 :\/: p2) =+  case simple_smart_merge (p1:\/:p2) of+  Nothing -> Nothing+  Just (p1'a:<p2a) ->+      case simple_smart_merge (p2 :\/: p1) >>= commutex of+      Nothing -> Nothing+      Just (p1'b :< p2b) ->+          if p1'a == p1'b && p2a == p2b && p2a == p2+          then Just (p1'a :< p2)+          else Nothing+simple_smart_merge :: (Patch :\/:  Patch) -> Maybe (Patch :< Patch)+simple_smart_merge (p1 :\/: p2) =+  case commutex (p1 :< invert p2) of+  Just (_:<p1') ->+      case commutex (p1':< p2) of+      Just (_:< p1o) ->+          if p1o == p1 then Just (p1' :< p2)+          else Nothing+      Nothing -> Nothing+  Nothing -> Nothing++prop_elegant_merge_good_enough :: Patch -> Patch -> Property+prop_elegant_merge_good_enough p1 p2 =+    (check_a_patch $ join_patches [invert p1,p2]) ==>+    (fst' `fmap` smart_merge (p2:\/:p1)) ==+       (snd'' `fmap` elegant_merge (p2:\/:p1))++fst' :: p :< p -> p+fst' (x:<_) = x++snd'' :: q :/\: p -> p+snd'' (_:/\:x) = x++instance Eq p => Eq (p :< p) where+   (x:<y) == (x':<y') = x == x' && y == y'++instance Show p => Show (p :< p) where+  show (x :< y) = show x ++ " :< " ++ show y+\end{code}++\begin{code}+test_patch :: String+test_patch = test_str ++ test_note+tp1, tp2 :: Patch+tp1 = unsafeUnseal . fst . fromJust . readPatch $ packString "\nmove ./test/test ./hello\n"+tp2 = unsafeUnseal . fst . fromJust . readPatch $ packString "\nmove ./test ./hello\n"+tp1', tp2' :: Patch+tp2' = quickmerge (tp2:\/:tp1)+tp1' = quickmerge (tp1:\/:tp2)+test_note :: String+test_note = (if commutex (tp2':<tp1) == Just (tp1':<tp2)+              then "At least they commutex right.\n"+              else "Argh! they don't even commutex right.\n")+         ++(if check_a_patch $ tp2+              then "tp2 itself is valid!\n"+              else "Oh my! tp2 isn't even valid!\n")+         ++(if check_a_patch $ tp2'+              then "tp2' itself is valid!\n"+              else "Aaack! tp2' itself is invalid!\n")+         ++(if check_a_patch $ join_patches [tp1, tp2']+              then "Valid merge tp2'!\n"+              else "Bad merge tp2'!\n")+         ++ (if check_a_patch $ join_patches [tp2, tp1']+              then "Valid merge tp1'!\n"+              else "Bad merge tp1'!\n")+         ++ (if check_a_patch $ join_patches [tp2,tp1',invert tp2',invert tp1]+              then "Both agree!\n"+              else "The two merges don't agree!\n")+         ++ (if check_a_patch $ join_patches [invert tp2, tp1]+              then "They should be mergable!\n"+              else "Wait a minute, these guys can't be merged!\n")+tp :: Patch+tp = tp1'++test_str :: String+test_str = "Patches are:\n"++(show tp)+           ++(if check_a_patch tp+              then "At least the patch itself is valid.\n"+              else "The patch itself is bad!\n")+           ++"commutex of tp1' and tp2 is "++show (commutex (tp1':<tp2))++"\n"+           ++"commutex of tp2' and tp1 is "++show (commutex (tp2':<tp1))++"\n"+           {-++ "\nSimply flattened, it is:\n"+                  ++ (show $ mapFL (joinPatches.flattenFL.merger_equivalent) $ flattenFL tp)+           ++ "\n\nUnravelled, it gives:\n" ++ (show $ map unravel $ flatten tp)+           ++ "\n\nUnwound, it gives:\n" ++ (show $ mapFL unwind $ flattenFL tp)+           ++(if check_a_patch (join_patches$ reverse $ unwind tp)+              then "Unwinding is valid.\n"+              else "Bad unwinding!\n")+           ++(if check_a_patch $ join_patches [tp,invert tp]+              then "Inverse is valid.\n"+              else "Bad inverse!\n")+           ++(if check_a_patch $ join_patches [invert tp, tp]+              then "Other inverse is valid.\n"+              else "Bad other inverse!\n")-}+\end{code}++The conflict resolution code (glump) begins by ``unravelling'' the merger+into a set of sequences of patches.  Each sequence of patches corresponds+to one non-conflicted patch that got merged together with the others.  The+result of the unravelling of a series of merges must obviously be+independent of the order in which those merges are performed.  This+unravelling code (which uses the unwind code mentioned above) uses probably+the second most complicated algorithm.  Fortunately, if we can successfully+unravel the merger, almost any function of the unravelled merger satisfies+the two constraints mentioned above that the conflict resolution code must+satisfy.++\begin{code}+prop_unravel_three_merge :: Patch -> Patch -> Patch -> Property+prop_unravel_three_merge p1 p2 p3 =+    (check_a_patch $ join_patches [invert p1,p2,invert p2,p3]) ==>+    (unravel $ merger "0.0" (merger "0.0" p2 p3) (merger "0.0" p2 p1)) ==+    (unravel $ merger "0.0" (merger "0.0" p1 p3) (merger "0.0" p1 p2))+\end{code}+\begin{code}+prop_unravel_seq_merge :: Patch -> Patch -> Patch -> Property+prop_unravel_seq_merge p1 p2 p3 =+    (check_a_patch $ join_patches [invert p1,p2,p3]) ==>+    (unravel $ merger "0.0" p3 $ merger "0.0" p2 p1) ==+    (unravel $ merger "0.0" (merger "0.0" p2 p1) p3)+\end{code}+\begin{code}+prop_unravel_order_independent :: Patch -> Patch -> Property+prop_unravel_order_independent p1 p2 =+    (check_a_patch $ join_patches [invert p1,p2]) ==>+    (unravel $ merger "0.0" p2 p1) == (unravel $ merger "0.0" p1 p2)+\end{code}++\begin{code}+prop_resolve_conflicts_valid :: Patch -> Patch -> Property+prop_resolve_conflicts_valid p1 p2 =+    (check_a_patch $ join_patches [invert p1,p2]) ==>+    and $ map (check_a_patch.(\l-> join_patches [p,merge_list l]))+            $ resolve_conflicts p+        where p = case merge (p1:\/:p2) of+                  _ :/\: p1' -> join_patches [p2,p1']++merge_list :: [Sealed (FL Prim C(x))] -> Patch+merge_list patches = fromPrims `unseal` doml NilFL patches+    where doml mp (Sealed p:ps) =+              case commute (invert p :> mp) of+              Just (mp' :> _) -> doml (effect p +>+ effect mp') ps+              Nothing -> doml mp ps -- This shouldn't happen for "good" resolutions.+          doml mp [] = Sealed mp+\end{code}++\begin{code}+try_tok_possibly :: String -> String -> String+                -> [Possibly PackedString] -> Maybe [Possibly PackedString]+try_tok_possibly t o n mss =+    mapM (silly_maybe_possibly $ liftM concatPS .+                    try_tok_internal t (packString o) (packString n))+                 $ take 1000 mss++silly_maybe_possibly :: (PackedString -> Maybe PackedString) ->+                        (Possibly PackedString -> Maybe (Possibly PackedString))+silly_maybe_possibly f =+    \px -> case px of+           PNothing -> Just PNothing+           PSomething -> Just PSomething+           PJust x -> case f x of+                      Nothing -> Nothing+                      Just x' -> Just $ PJust x'++try_tok_internal :: String -> PackedString -> PackedString+                 -> PackedString -> Maybe [PackedString]+try_tok_internal _ _ _ s | nullPS s = Just []+try_tok_internal t o n s =+    case breakPS (regChars t) s of+    (before,s') ->+        case breakPS (not . regChars t) s' of+        (tok,after) ->+            case try_tok_internal t o n after of+            Nothing -> Nothing+            Just rest ->+                if tok == o+                then Just $ before : n : rest+                else if tok == n+                     then Nothing+                     else Just $ before : tok : rest+\end{code}++\begin{code}+prop_read_show :: Patch -> Bool+prop_read_show p = case readPatch $ renderPS $ showPatch p of+                   Just (Sealed p',_) -> p' == p+                   Nothing -> False+\end{code}++%In order for merges to work right with commuted patches, inverting a patch+%past a patch and its inverse had golly well better give you the same patch+%back again.+\begin{code}+prop_commute_inverse :: Patch -> Patch -> Property+prop_commute_inverse p1 p2 =+    does_commute p1 p2 ==> case commutex (p2:< p1) of+                           Nothing -> impossible+                           Just (p1':<_) ->+                               case commutex (invert p2:< p1') of+                               Nothing -> False+                               Just (p1'':<_) -> p1'' == p1+\end{code}++\begin{code}+subcommutes_inverse :: [(String, Prim -> Prim -> Property)]+subcommutes_inverse = zip names (map prop_subcommute cs)+    where (names, cs) = unzip subcommutes+          prop_subcommute c p1 p2 =+              does c p1 p2 ==>+              case c (p2:< p1) of+              Succeeded (p1':<p2') ->+                  case c (invert p2:< p1') of+                  Succeeded (p1'':<ip2x') -> p1'' == p1 &&+                      case c (invert p1:< invert p2) of+                      Succeeded (ip2':< ip1') ->+                          case c (p2':< invert p1) of+                          Succeeded (ip1o':< p2o) ->+                              invert ip1' == p1' && invert ip2' == p2' &&+                              ip1o' == ip1' && p2o == p2 &&+                              p1'' == p1 && ip2x' == ip2'+                          _ -> False+                      _ -> False+                  _ -> False+              _ -> False++subcommutes_nontrivial_inverse :: [(String, Prim -> Prim -> Property)]+subcommutes_nontrivial_inverse = zip names (map prop_subcommute cs)+    where (names, cs) = unzip subcommutes+          prop_subcommute c p1 p2 =+              nontrivial c p1 p2 ==>+              case c (p2:< p1) of+              Succeeded (p1':<p2') ->+                  case c (invert p2:< p1') of+                  Succeeded (p1'':<ip2x') -> p1'' == p1 &&+                      case c (invert p1:< invert p2) of+                      Succeeded (ip2':< ip1') ->+                          case c (p2':< invert p1) of+                          Succeeded (ip1o':< p2o) ->+                              invert ip1' == p1' && invert ip2' == p2' &&+                              ip1o' == ip1' && p2o == p2 &&+                              p1'' == p1 && ip2x' == ip2'+                          _ -> False+                      _ -> False+                  _ -> False+              _ -> False++subcommutes_failure :: [(String, Prim -> Prim -> Property)]+subcommutes_failure = zip names (map prop cs)+    where (names, cs) = unzip subcommutes+          prop c p1 p2 =+              does_fail c p1 p2 ==> case c (invert p1 :< invert p2) of+                                    Failed -> True+                                    _ -> False++does_fail :: CommuteFunction -> Prim -> Prim -> Bool+does_fail c p1 p2 =+    fails (c (p2:<p1)) && (check_a_patch $ fromPrims $ unsafeFL [p1,p2])+        where fails Failed = True+              fails _ = False++does :: CommuteFunction -> Prim -> Prim -> Bool+does c p1 p2 =+    succeeds (c (p2:<p1)) && (check_a_patch $ fromPrims $ unsafeFL [p1,p2])+        where succeeds (Succeeded _) = True+              succeeds _ = False++nontrivial :: CommuteFunction -> Prim -> Prim -> Bool+nontrivial c p1 p2 =+    succeeds (c (p2:<p1)) && (check_a_patch $ fromPrims $ unsafeFL [p1,p2])+        where succeeds (Succeeded (p1' :< p2')) = p1' /= p1 || p2' /= p2+              succeeds _ = False+\end{code}+
+ src/Darcs/Patch/TouchesFiles.lhs view
@@ -0,0 +1,85 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.Patch.TouchesFiles ( look_touch, choose_touching,+                      select_touching,+                      deselect_not_touching, select_not_touching,+                    ) where+import Data.List ( sort )++import Darcs.Patch.Choices ( PatchChoices, patch_choices, tag,+                             get_first_choice, get_middle_choice, get_last_choice,+                      force_firsts, force_lasts, tp_patch,+                    )+import Darcs.Patch ( Patchy, apply_to_filepaths, list_touched_files )+import Darcs.Patch.Ordered ( FL(..), mapFL_FL, (+>+) )+\end{code}++\begin{code}+select_touching :: Patchy p => [FilePath] -> PatchChoices p -> PatchChoices p+select_touching [] pc = pc+select_touching files pc = force_firsts xs pc+    where ct _ NilFL = []+          ct fs (tp:>:tps) = case look_touch fs (tp_patch tp) of+                             (True, fs') -> tag tp:ct fs' tps+                             (False, fs') -> ct fs' tps+          xs = ct (map fix files) (get_middle_choice pc +>+ get_last_choice pc)++deselect_not_touching :: Patchy p => [FilePath] -> PatchChoices p -> PatchChoices p+deselect_not_touching [] pc = pc+deselect_not_touching files pc = force_lasts xs pc+    where ct _ NilFL = []+          ct fs (tp:>:tps) = case look_touch fs (tp_patch tp) of+                             (True, fs') -> ct fs' tps+                             (False, fs') -> tag tp:ct fs' tps+          xs = ct (map fix files) (get_first_choice pc +>+ get_middle_choice pc)++select_not_touching :: Patchy p => [FilePath] -> PatchChoices p -> PatchChoices p+select_not_touching [] pc = pc+select_not_touching files pc = force_firsts xs pc+    where ct _ NilFL = []+          ct fs (tp:>:tps) = case look_touch fs (tp_patch tp) of+                             (True, fs') -> ct fs' tps+                             (False, fs') -> tag tp:ct fs' tps+          xs = ct (map fix files) (get_first_choice pc +>+ get_middle_choice pc)++fix :: FilePath -> FilePath+fix f | take 1 (reverse f) == "/" = fix $ reverse $ drop 1 $ reverse f+fix "" = "."+fix "." = "."+fix f = "./" ++ f++choose_touching :: Patchy p => [FilePath] -> FL p -> FL p+choose_touching [] p = p+choose_touching files p =+    mapFL_FL tp_patch $ get_first_choice $ select_touching files $ patch_choices p++look_touch :: Patchy p => [FilePath] -> p -> (Bool, [FilePath])+look_touch fs p = (orr affects (list_touched_files p) fs+                   || fs' /= fs, fs')+    where orr :: (a -> b -> Bool) -> [a] -> [b] -> Bool+          orr fun (a:as) bs = any (fun a) bs || orr fun as bs+          orr _ [] _ = False+          affects touched f | touched == f = True+          affects t f = case splitAt (length f) t of+                        (t', '/':_) -> t' == f+                        _ -> case splitAt (length t) f of+                             (f', '/':_) -> f' == t+                             _ -> False+          fs' = sort $ apply_to_filepaths p fs+\end{code}
+ src/Darcs/Patch/Unit.lhs view
@@ -0,0 +1,446 @@+%  Copyright (C) 2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp -fno-warn-deprecations -fno-warn-orphans -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Patch.Unit ( run_patch_unit_tests ) where++import Control.Monad ( unless )+import Data.Maybe ( catMaybes )+import FastPackedString+import Darcs.Sealed+import Darcs.Patch+import Darcs.Patch.Patchy ( mergeFL, Invert )+import Darcs.Patch.Real ( RealPatch, prim2real, is_consistent, is_forward, is_duplicate )+import Darcs.Patch.Test () -- for instance Eq Patch+import Darcs.Patch.Ordered+import Darcs.Patch.Properties ( recommute, commute_inverses, permutivity, partial_permutivity,+                                inverse_doesnt_commute, patch_and_inverse_commute,+                                merge_commute, merge_consistent, merge_arguments_consistent,+                                merge_either_way, show_read,+                                join_inverses, join_commute )+import Darcs.Patch.Prim ( join )+import Darcs.Patch.QuickCheck+import Printer ( Doc, redText, ($$) )+--import Printer ( greenText )+--import Darcs.ColorPrinter ( traceDoc )+--import Darcs.ColorPrinter ( errorDoc )+import Darcs.ColorPrinter () -- for instance Show Doc++-- import Debug.Trace+-- #include "impossible.h"+\end{code}++\begin{code}+run_patch_unit_tests :: IO Int+run_patch_unit_tests =+    run_some_tests ""+    [--do putStr "Checking with quickcheck that real patches have consistent flattenings... "+     --   quickCheck (not . isBottomTimeOut (Just 10) . prop_consistent_tree_flattenings) >> return 0+     run_primitive_tests "prim join inverses"+                         (\(a:\/:_) -> join_inverses join a) mergeables+    ,do putStr "Checking prim join inverses using QuickCheck... "+        simpleCheck (join_inverses join)+    ,run_primitive_tests "prim inverse doesn't commute"+                         (\(a:\/:_) -> inverse_doesnt_commute a) mergeables+    -- The following fails because of setpref patches...+    --,do putStr "Checking prim inverse doesn't commute using QuickCheck... "+    --    simpleCheck (inverse_doesnt_commute :: Prim -> Maybe Doc)+    ,run_primitive_tests "join commute" (join_commute join) prim_permutables+    ,do putStr "Checking prim join commute using QuickCheck... "+        simpleCheck (unseal2 (join_commute join))++    ,run_primitive_tests "prim recommute"+                         (recommute commute) $ map mergeable2commutable mergeables+    ,run_primitive_tests "prim patch and inverse commute"+                         (patch_and_inverse_commute commute) $ map mergeable2commutable mergeables+    ,run_primitive_tests "prim inverses commute"+                         (commute_inverses commute) $ map mergeable2commutable mergeables++--    ,do putStr "Checking prim recommute using QuickCheck... "+--        simpleCheck (recommute+--                     (commute :: Prim :> Prim+--                              -> Maybe (Prim :> Prim)))++    ,run_primitive_tests "FL prim recommute"+                         (recommute commute) $ map mergeable2commutable mergeablesFL+    ,run_primitive_tests "FL prim patch and inverse commute"+                         (patch_and_inverse_commute commute) $ map mergeable2commutable mergeablesFL+    ,run_primitive_tests "FL prim inverses commute"+                         (commute_inverses commute) $ map mergeable2commutable mergeablesFL++    ,run_primitive_tests "fails" (commute_fails commute) ([] :: [Prim :> Prim])++    ,run_primitive_tests "read and show work on Prim" show_read prim_patches+    ,run_primitive_tests "read and show work on RealPatch" show_read real_patches+    ,do putStr "Checking that readPatch and showPatch work on RealPatch... "+        simpleCheck (unseal $ patchFromTree $ (show_read :: RealPatch -> Maybe Doc))+    ,do putStr "Checking that readPatch and showPatch work on FL RealPatch... "+        simpleCheck (unseal2 $ (show_read :: FL RealPatch -> Maybe Doc))++    ,run_primitive_tests "example flattenings work"+                             (\x -> if prop_consistent_tree_flattenings x+                                    then Nothing+                                    else Just $ redText "oops")+                             real_patch_loop_examples+    ,do putStr "Checking that tree flattenings are consistent... "+        simpleCheck ((\b -> if b then Nothing else Just False) . prop_consistent_tree_flattenings)++    ,do putStr "Checking with quickcheck that real patches are consistent... "+        simpleCheck (unseal $ patchFromTree $ is_consistent)+    ,run_primitive_tests "real merge input consistent"+                             (merge_arguments_consistent is_consistent) real_mergeables+    ,run_primitive_tests "real merge input is forward"+                             (merge_arguments_consistent is_forward) real_mergeables+    ,run_primitive_tests "real merge output is forward"+                             (merge_consistent is_forward) real_mergeables+    ,run_primitive_tests "real merge output consistent"+                             (merge_consistent is_consistent) real_mergeables+    ,run_primitive_tests "real merge either way" merge_either_way real_mergeables+    ,run_primitive_tests "real merge and commute" merge_commute real_mergeables++    ,run_primitive_tests "real recommute" (recommute commute) real_commutables+    ,run_primitive_tests "real inverses commute" (commute_inverses commute) real_commutables++    ,run_primitive_tests "real permutivity" (permutivity commute) $+                         filter (not_duplicatestriple) real_triples+    ,run_primitive_tests "real partial permutivity" (partial_permutivity commute) $+                         filter (not_duplicatestriple) real_triples++    ,do putStr "Checking we can do merges using QuickCheck... "+        simpleCheck (prop_is_mergeable ::+                         Sealed (WithStartState RepoModel (Tree Prim))+                             -> Maybe (Tree RealPatch C(x)))+    ,do putStr "Checking again we can do merges using QuickCheck... "+        thoroughCheck 1000 (prop_is_mergeable ::+                                Sealed (WithStartState RepoModel (Tree Prim))+                                    -> Maybe (Tree RealPatch C(x)))++    ,do putStr "Checking recommute using QuickCheck Tree generator... "+        simpleCheck (unseal $ commutePairFromTree $+                    (recommute+                     (commute :: RealPatch :> RealPatch+                              -> Maybe (RealPatch :> RealPatch))))+    ,do putStr "Checking recommute using QuickCheck TWFP generator... "+        simpleCheck (unseal $ commutePairFromTWFP $+                    (recommute+                     (commute :: RealPatch :> RealPatch+                              -> Maybe (RealPatch :> RealPatch))))+    ,do putStr "Checking nontrivial recommute... "+        simpleConditionalCheck (unseal $ commutePairFromTree $ nontrivial_reals)+                                   (unseal $ commutePairFromTree $+                                    (recommute+                                     (commute :: RealPatch :> RealPatch+                                              -> Maybe (RealPatch :> RealPatch))))+    ,do putStr "Checking nontrivial recommute using TWFP... "+        simpleConditionalCheck (unseal $ commutePairFromTWFP $ nontrivial_reals)+                                   (unseal $ commutePairFromTWFP $+                                    (recommute+                                     (commute :: RealPatch :> RealPatch+                                              -> Maybe (RealPatch :> RealPatch))))++    ,do putStr "Checking inverses commute using QuickCheck Tree generator... "+        simpleCheck (unseal $ commutePairFromTree $+                    (commute_inverses+                     (commute :: RealPatch :> RealPatch+                              -> Maybe (RealPatch :> RealPatch))))+    ,do putStr "Checking inverses commute using QuickCheck TWFP generator... "+        simpleCheck (unseal $ commutePairFromTWFP $+                    (commute_inverses+                     (commute :: RealPatch :> RealPatch+                              -> Maybe (RealPatch :> RealPatch))))+    ,do putStr "Checking nontrivial inverses commute... "+        simpleConditionalCheck (unseal $ commutePairFromTree $ nontrivial_reals)+                                   (unseal $ commutePairFromTree $+                                    (commute_inverses+                                     (commute :: RealPatch :> RealPatch+                                              -> Maybe (RealPatch :> RealPatch))))+    ,do putStr "Checking nontrivial inverses commute using TWFP... "+        simpleConditionalCheck (unseal $ commutePairFromTWFP $ nontrivial_reals)+                                   (unseal $ commutePairFromTWFP $+                                    (commute_inverses+                                     (commute :: RealPatch :> RealPatch+                                              -> Maybe (RealPatch :> RealPatch))))++    ,do putStr "Checking merge either way using QuickCheck TWFP generator... "+        simpleCheck (unseal $ mergePairFromTWFP $+                     (merge_either_way :: RealPatch :\/: RealPatch -> Maybe Doc))+    ,do putStr "Checking merge either way using QuickCheck Tree generator... "+        simpleCheck (unseal $ mergePairFromTree $+                     (merge_either_way :: RealPatch :\/: RealPatch -> Maybe Doc))+    ,do putStr "Checking nontrivial merge either way... "+        simpleConditionalCheck (unseal $ mergePairFromTree $ nontrivial_merge_reals)+                                   (unseal $ mergePairFromTree $+                                    (merge_either_way :: RealPatch :\/: RealPatch -> Maybe Doc))+    ,do putStr "Checking nontrivial merge either way using TWFP... "+        simpleConditionalCheck (unseal $ mergePairFromTWFP $ nontrivial_merge_reals)+                                   (unseal $ mergePairFromTWFP $+                                    (merge_either_way :: RealPatch :\/: RealPatch -> Maybe Doc))++    ,do putStr "Checking permutivity... "+        simpleConditionalCheck (unseal $ commuteTripleFromTree not_duplicatestriple)+            (unseal $ commuteTripleFromTree $ permutivity+                    (commute :: RealPatch :> RealPatch -> Maybe (RealPatch :> RealPatch)))+    ,do putStr "Checking partial permutivity... "+        simpleConditionalCheck (unseal $ commuteTripleFromTree not_duplicatestriple)+            (unseal $ commuteTripleFromTree $ partial_permutivity+                    (commute :: RealPatch :> RealPatch -> Maybe (RealPatch :> RealPatch)))+    ,do putStr "Checking nontrivial permutivity... "+        simpleConditionalCheck (unseal $ commuteTripleFromTree+                                           (\t -> nontrivial_triple t && not_duplicatestriple t))+                  (unseal $ commuteTripleFromTree $+                    (permutivity+                     (commute :: RealPatch :> RealPatch+                              -> Maybe (RealPatch :> RealPatch))))+    ]++not_duplicatestriple :: RealPatch :> RealPatch :> RealPatch -> Bool+not_duplicatestriple (a :> b :> c) = not $ any is_duplicate [a,b,c]++--not_duplicates_pair :: RealPatch :> RealPatch -> Bool+--not_duplicates_pair (a :> b) = not $ any is_duplicate [a,b]++nontrivial_triple :: RealPatch :> RealPatch :> RealPatch -> Bool+nontrivial_triple (a :> b :> c) =+    case commute (a :> b) of+    Nothing -> False+    Just (b' :> a') ->+      case commute (a' :> c) of+      Nothing -> False+      Just (c'' :> a'') ->+        case commute (b :> c) of+        Nothing -> False+        Just (c' :> b'') -> (not (a `unsafeCompare` a') || not (b `unsafeCompare` b')) &&+                            (not (c' `unsafeCompare` c) || not (b'' `unsafeCompare` b)) &&+                            (not (c'' `unsafeCompare` c) || not (a'' `unsafeCompare` a'))++nontrivial_reals :: RealPatch :> RealPatch -> Bool+nontrivial_reals = nontrivial_commute++nontrivial_commute :: Patchy p => p :> p -> Bool+nontrivial_commute (x :> y) = case commute (x :> y) of+                              Just (y' :> x') -> not (y' `unsafeCompare` y) ||+                                                 not (x' `unsafeCompare` x)+                              Nothing -> False++nontrivial_merge_reals :: RealPatch :\/: RealPatch -> Bool+nontrivial_merge_reals = nontrivial_merge++nontrivial_merge :: Patchy p => p :\/: p -> Bool+nontrivial_merge (x :\/: y) = case merge (x :\/: y) of+                              y' :/\: x' -> not (y' `unsafeCompare` y) ||+                                            not (x' `unsafeCompare` x)++run_some_tests :: String -> [IO Int] -> IO Int+run_some_tests name ts = do unless (null name) $ putStr $ "Testing " ++ name ++ "... "+                            errs <- sum `fmap` sequence ts+                            unless (null name) $+                                   if errs < 1+                                   then putStrLn "passed."+                                   else putStrLn $ "failed " ++ name ++" in "++ show errs ++ " tests."+                            return errs++run_primitive_tests :: (Show a, Show b) => String -> (a -> Maybe b) -> [a] -> IO Int+run_primitive_tests name test datas = run_some_tests name $ map test' datas+    where test' d = case test d of+                    Just e -> do putStrLn $ name ++ " failed!"+                                 putStrLn $ "Input: " ++ show d+                                 putStrLn $ "Output: " ++ show e+                                 return 1+                    Nothing -> return 0++\end{code}++\begin{code}+quickhunk :: Int -> String -> String -> Prim+quickhunk l o n = hunk "test" l (map (\c -> packString [c]) o)+                                (map (\c -> packString [c]) n)+\end{code}++\begin{code}+prim_permutables :: [Prim :> Prim :> Prim]+prim_permutables =+    [quickhunk 0 "e" "bo" :> quickhunk 3 "" "x" :> quickhunk 2 "f" "qljo"]++mergeables :: [Prim :\/: Prim]+mergeables = [quickhunk 1 "a" "b" :\/: quickhunk 1 "a" "c",+              quickhunk 1 "a" "b" :\/: quickhunk 3 "z" "c",+              quickhunk 0 "" "a" :\/: quickhunk 1 "" "b",+              quickhunk 0 "a" "" :\/: quickhunk 1 "" "b",+              quickhunk 0 "a" "" :\/: quickhunk 1 "b" "",+              quickhunk 0 "" "a" :\/: quickhunk 1 "b" ""+             ]++mergeablesFL :: [FL Prim :\/: FL Prim]+mergeablesFL = map (\ (x:\/:y) -> (x :>: NilFL) :\/: (y :>: NilFL)) mergeables +++           [] --    [(quickhunk 1 "a" "b" :>: quickhunk 3 "z" "c" :>: NilFL)+              --  :\/: (quickhunk 1 "a" "z" :>: NilFL),+              --  (quickhunk 1 "a" "b" :>: quickhunk 1 "b" "c" :>: NilFL)+              --  :\/: (quickhunk 1 "a" "z" :>: NilFL)]++mergeable2commutable :: Invert p => p :\/: p -> p :> p+mergeable2commutable (x :\/: y) = invert x :> y++prim_patches :: [Prim]+prim_patches = concatMap mergeable2patches mergeables+    where mergeable2patches (x:\/:y) = [x,y]++real_patches :: [RealPatch]+real_patches = concatMap commutable2patches real_commutables+    where commutable2patches (x:>y) = [x,y]++unsafeUnseal2 :: Sealed2 p -> p+unsafeUnseal2 (Sealed2 p) = p++real_triples :: [RealPatch :> RealPatch :> RealPatch]+real_triples = [ob' :> oa2 :> a2'',+                oa' :> oa2 :> a2''] ++ triple_examples+               ++ map unsafeUnseal2 (concatMap getTriples realFLs)+    where oa = prim2real $ quickhunk 1 "o" "aa"+          oa2 = oa+          a2 = prim2real $ quickhunk 2 "a34" "2xx"+          ob = prim2real $ quickhunk 1 "o" "bb"+          ob' :/\: oa' = merge (oa :\/: ob)+          a2' :/\: _ = merge (ob' :\/: a2)+          a2'' :/\: _ = merge (oa2 :\/: a2')++realFLs :: [FL RealPatch]+realFLs = [oa :>: invert oa :>: oa :>: invert oa :>: ps +>+ oa :>: invert oa :>: NilFL]+    where oa = prim2real $ quickhunk 1 "o" "a"+          ps :/\: _ = merge (oa :>: invert oa :>: NilFL :\/: oa :>: invert oa :>: NilFL)++real_commutables :: [RealPatch :> RealPatch]+real_commutables = commute_examples ++ map mergeable2commutable real_mergeables+++                   [invert oa :> ob'] ++ map unsafeUnseal2 (concatMap getPairs realFLs)+    where oa = prim2real $ quickhunk 1 "o" "a"+          ob = prim2real $ quickhunk 1 "o" "b"+          _ :/\: ob' = mergeFL (ob :\/: oa :>: invert oa :>: NilFL)++real_mergeables :: [RealPatch :\/: RealPatch]+real_mergeables = map (\ (x :\/: y) -> prim2real x :\/: prim2real y) mergeables+                        ++ real_igloo_mergeables+                        ++ real_quickcheck_mergeables+                        ++ merge_examples+                        ++ catMaybes (map pair2m (concatMap getPairs realFLs))+                        ++ [(oa :\/: od),+                            (oa :\/: a2'),+                            (ob' :\/: od''),+                            (oe :\/: od),+                            (of' :\/: oe'),+                            (ob' :\/: oe'),+                            (oa :\/: oe'),+                            (ob' :\/: oc'),+                            (b2' :\/: oc'''),+                            (ob' :\/: a2),+                            (b2' :\/: og'''),+                            (oc''' :\/: og'''),+                            (oc'' :\/: og''),+                            (ob'' :\/: og''),+                            (ob'' :\/: oc''),+                            (oc' :\/: od'')]+    where oa = prim2real $ quickhunk 1 "o" "aa"+          a2 = prim2real $ quickhunk 2 "a34" "2xx"+          og = prim2real $ quickhunk 3 "4" "g"+          ob = prim2real $ quickhunk 1 "o" "bb"+          b2 = prim2real $ quickhunk 2 "b" "2"+          oc = prim2real $ quickhunk 1 "o" "cc"+          od = prim2real $ quickhunk 7 "x" "d"+          oe = prim2real $ quickhunk 7 "x" "e"+          pf = prim2real $ quickhunk 7 "x" "f"+          od'' = prim2real $ quickhunk 8 "x" "d"+          ob' :>: b2' :>: NilFL :/\: _ = mergeFL (oa :\/: ob :>: b2 :>: NilFL)+          a2' :/\: _ = merge (ob' :\/: a2)+          ob'' :/\: _ = merge (a2 :\/: ob')+          og' :/\: _ = merge (oa :\/: og)+          og'' :/\: _ = merge (a2 :\/: og')+          og''' :/\: _ = merge (ob' :\/: og')+          oc' :/\: _ = merge (oa :\/: oc)+          oc'' :/\: _ = merge (a2 :\/: oc)+          oc''' :/\: _ = merge (ob' :\/: oc')+          oe' :/\: _ = merge (od :\/: oe)+          of' :/\: _ = merge (od :\/: pf)+          pair2m :: Sealed2 (RealPatch :> RealPatch)+                 -> Maybe (RealPatch :\/: RealPatch)+          pair2m (Sealed2 (xx :> y)) = do y' :> _ <- commute (xx :> y)+                                          return (xx :\/: y')++real_igloo_mergeables :: [RealPatch :\/: RealPatch]+real_igloo_mergeables = [(a :\/: b),+                    (b :\/: c),+                    (a :\/: c),+                    (x :\/: a),+                    (y :\/: b),+                    (z :\/: c),+                    (x' :\/: y'),+                    (z' :\/: y'),+                    (x' :\/: z'),+                    (a :\/: a)]+    where a = prim2real $ quickhunk 1 "1" "A"+          b = prim2real $ quickhunk 2 "2" "B"+          c = prim2real $ quickhunk 3 "3" "C"+          x = prim2real $ quickhunk 1 "1BC" "xbc"+          y = prim2real $ quickhunk 1 "A2C" "ayc"+          z = prim2real $ quickhunk 1 "AB3" "abz"+          x' :/\: _ = merge (a :\/: x)+          y' :/\: _ = merge (b :\/: y)+          z' :/\: _ = merge (c :\/: z)++real_quickcheck_mergeables :: [RealPatch :\/: RealPatch]+real_quickcheck_mergeables = [-- invert k1 :\/: n1+                             --, invert k2 :\/: n2+                               hb :\/: k+                             , b' :\/: b'+                             , n' :\/: n'+                             , b :\/: d+                             , k' :\/: k'+                             , k3 :\/: k3+                             ] ++ catMaybes (map pair2m pairs)+    where hb = prim2real $ quickhunk 0 "" "hb"+          k = prim2real $ quickhunk 0 "" "k"+          n = prim2real $ quickhunk 0 "" "n"+          b = prim2real $ quickhunk 1 "b" ""+          d = prim2real $ quickhunk 2 "" "d"+          d':/\:_ = merge (b :\/: d)+          --k1 :>: n1 :>: NilFL :/\: _ = mergeFL (hb :\/: k :>: n :>: NilFL)+          --k2 :>: n2 :>: NilFL :/\: _ =+          --    merge (hb :>: b :>: NilFL :\/: k :>: n :>: NilFL)+          k' :>: n' :>: NilFL :/\: _ :>: b' :>: _ = merge (hb :>: b :>: d' :>: NilFL :\/: k :>: n :>: NilFL)+          pairs = getPairs (hb :>: b :>: d' :>: k' :>: n' :>: NilFL)+          pair2m :: Sealed2 (RealPatch :> RealPatch)+                 -> Maybe (RealPatch :\/: RealPatch)+          pair2m (Sealed2 (xx :> y)) = do y' :> _ <- commute (xx :> y)+                                          return (xx :\/: y')++          i = prim2real $ quickhunk 0 "" "i"+          x = prim2real $ quickhunk 0 "" "x"+          xi = prim2real $ quickhunk 0 "xi" ""+          d3 :/\: _ = merge (xi :\/: d)+          _ :/\: k3 = mergeFL (k :\/: i :>: x :>: xi :>: d3 :>: NilFL)++\end{code}++\begin{code}+commute_fails :: (MyEq p, Patchy p) => (p :> p -> Maybe (p :> p)) -> p :> p+              -> Maybe Doc+commute_fails c (x :> y) = do y' :> x' <- c (x :> y)+                              return $ redText "x" $$ showPatch x $$+                                       redText ":> y" $$ showPatch y $$+                                       redText "y'" $$ showPatch y' $$+                                       redText ":> x'" $$ showPatch x'++\end{code}
+ src/Darcs/Patch/Viewing.lhs view
@@ -0,0 +1,345 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fno-warn-orphans #-}+module Darcs.Patch.Viewing ( xml_summary, summarize )+             where++import Prelude hiding ( pi )+import Control.Monad ( liftM )+import Data.List ( sort )++import Darcs.SlurpDirectory ( Slurpy, get_slurp, get_filecontents )+import FastPackedString ( nullPS, linesPS )+import FileName ( FileName, fp2fn, fn2fp )+import Printer ( Doc, empty, vcat,+                 text, blueText, Color(Cyan,Magenta), lineColor,+                 minus, plus, ($$), (<+>), (<>),+                 prefix, renderString,+                 userchunkPS,+               )+import Darcs.Patch.Core ( Patch(..), Named(..),+                          patchcontents )+import Darcs.Patch.Prim ( Prim(..), is_hunk, isHunk, formatFileName, showPrim, FileNameFormat(..), Conflict(..),+                          Effect, IsConflictedPrim(IsC), ConflictState(..),+                          DirPatchType(..), FilePatchType(..) )+import Darcs.Patch.Patchy ( Patchy, Apply, ShowPatch(..), identity )+import Darcs.Patch.Show ( showPatch_, showNamedPrefix )+import Darcs.Patch.Info ( showPatchInfo, human_friendly )+import Darcs.Patch.Apply ( apply_to_slurpy )+#include "impossible.h"+#include "gadts.h"+import Darcs.Patch.Ordered ( RL(..), FL(..),+                             mapFL, mapFL_FL, reverseRL )+\end{code}+++\begin{code}+instance ShowPatch Prim where+    showPatch = showPrim OldFormat+    showContextPatch s p@(FP _ (Hunk _ _ _)) = showContextHunk s (PP p)+    showContextPatch s (Split ps) =+        blueText "(" $$ showContextSeries s (mapFL_FL PP ps)+                     <> blueText ")"+    showContextPatch _ p = showPatch p+    summary = gen_summary False . (:[]) . IsC Okay+    thing _ = "change"++summarize :: (Conflict e, Effect e) => e C(x y) -> Doc+summarize = gen_summary False . conflictedEffect++instance ShowPatch Patch where+    showPatch = showPatch_+    showContextPatch s (PP x) | is_hunk x = showContextHunk s (PP x)+    showContextPatch _ (ComP NilFL) = blueText "{" $$ blueText "}"+    showContextPatch s (ComP ps) = blueText "{" $$ showContextSeries s ps+                                   $$ blueText "}"+    showContextPatch _ p = showPatch p+    summary = summarize+    thing _ = "change"+\end{code}++\begin{code}+showContextSeries :: (Apply p, ShowPatch p, Effect p) => Slurpy -> FL p C(x y) -> Doc+showContextSeries slur patches = scs slur identity patches+    where scs :: (Apply p, ShowPatch p, Effect p) => Slurpy -> Prim C(w x) -> FL p C(x y) -> Doc+          scs s pold (p:>:ps) =+              case isHunk p of+              Nothing -> showContextPatch s p $$ scs s' identity ps+              Just hp ->+                  case ps of+                  NilFL -> coolContextHunk s pold hp identity+                  (p2:>:_) ->+                      case isHunk p2 of+                      Nothing -> coolContextHunk s pold hp identity $$ scs s' hp ps+                      Just hp2 -> coolContextHunk s pold hp hp2 $$+                                  scs s' hp ps+              where s' =+                        fromJust $ apply_to_slurpy p s+          scs _ _ NilFL = empty+\end{code}++\begin{code}+showContextHunk :: (Apply p, ShowPatch p, Effect p) => Slurpy -> p C(x y) -> Doc+showContextHunk s p = case isHunk p of+                        Just h -> coolContextHunk s identity h identity+                        Nothing -> showPatch p++coolContextHunk :: Slurpy -> Prim C(a b) -> Prim C(b c)+                -> Prim C(c d) -> Doc+coolContextHunk s prev p@(FP f (Hunk l o n)) next =+    case (linesPS . get_filecontents) `liftM` get_slurp f s of+    Nothing -> showPatch p -- This is a weird error...+    Just ls ->+        let numpre = case prev of+                     (FP f' (Hunk lprev _ nprev))+                         | f' == f &&+                           l - (lprev + length nprev + 3) < 3 &&+                           lprev < l ->+                             max 0 $ l - (lprev + length nprev + 3)+                     _ -> if l >= 4 then 3 else l - 1+            pre = take numpre $ drop (l - numpre - 1) ls+            numpost = case next of+                      (FP f' (Hunk lnext _ _))+                          | f' == f && lnext < l+length n+4 &&+                            lnext > l ->+                              lnext - (l+length n)+                      _ -> 3+            cleanedls = case reverse ls of+                        (x:xs) | nullPS x -> reverse xs+                        _ -> ls+            post = take numpost $ drop (max 0 $ l+length o-1) cleanedls+            in blueText "hunk" <+> formatFileName OldFormat f <+> text (show l)+            $$ prefix " " (vcat $ map userchunkPS pre)+            $$ lineColor Magenta (prefix "-" (vcat $ map userchunkPS o))+            $$ lineColor Cyan    (prefix "+" (vcat $ map userchunkPS n))+            $$ prefix " " (vcat $ map userchunkPS post)+coolContextHunk _ _ _ _ = impossible+\end{code}++\begin{code}+xml_summary :: (Effect p, Patchy p, Conflict p) => Named p C(x y) -> Doc+xml_summary p = text "<summary>"+             $$ gen_summary True (conflictedEffect $ patchcontents p)+             $$ text "</summary>"++-- Yuck duplicated code below...+escapeXML :: String -> Doc+escapeXML = text . strReplace '\'' "&apos;" . strReplace '"' "&quot;" .+  strReplace '>' "&gt;" . strReplace '<' "&lt;" . strReplace '&' "&amp;"++strReplace :: Char -> String -> String -> String+strReplace _ _ [] = []+strReplace x y (z:zs)+  | x == z    = y ++ (strReplace x y zs)+  | otherwise = z : (strReplace x y zs)+-- end yuck duplicated code.++gen_summary :: Bool -> [IsConflictedPrim] -> Doc+gen_summary use_xml p+    = vcat themoves+   $$ vcat themods+    where themods = map summ $ combine $ sort $ concatMap s2 p+          s2 :: IsConflictedPrim -> [(FileName, Int, Int, Int, Bool, ConflictState)]+          s2 (IsC c x) = map (append56 c) $ s x+          s :: Prim C(x y) -> [(FileName, Int, Int, Int, Bool)]+          s (FP f (Hunk _ o n)) = [(f, length o, length n, 0, False)]+          s (FP f (Binary _ _)) = [(f, 0, 0, 0, False)]+          s (FP f AddFile) = [(f, -1, 0, 0, False)]+          s (FP f RmFile) = [(f, 0, -1, 0, False)]+          s (FP f (TokReplace _ _ _)) = [(f, 0, 0, 1, False)]+          s (DP d AddDir) = [(d, -1, 0, 0, True)]+          s (DP d RmDir) = [(d, 0, -1, 0, True)]+          s (Split xs) = concat $ mapFL s xs+          s (Move _ _) = [(fp2fn "", 0, 0, 0, False)]+          s (ChangePref _ _ _) = [(fp2fn "", 0, 0, 0, False)]+          s Identity = [(fp2fn "", 0, 0, 0, False)]+          append56 f (a,b,c,d,e) = (a,b,c,d,e,f)+          (-1) .+ _ = -1+          _ .+ (-1) = -1+          a .+ b = a + b+          combine ((f,a,b,r,isd,c):(f',a',b',r',_,c'):ss)+              -- Don't combine AddFile and RmFile: (maybe an old revision of) darcs+              -- allows a single patch to add and remove the same file, see issue 185+              | f == f' && (a /= -1 || b' /= -1) && (a' /= -1 || b /= -1) =+                  combine ((f,a.+a',b.+b',r+r',isd,combineConflitStates c c'):ss)+          combine ((f,a,b,r,isd,c):ss) = (f,a,b,r,isd,c) : combine ss+          combine [] = []+          combineConflitStates Conflicted _ = Conflicted+          combineConflitStates _ Conflicted = Conflicted+          combineConflitStates Duplicated _ = Duplicated+          combineConflitStates _ Duplicated = Duplicated+          combineConflitStates Okay Okay = Okay++          summ (f,_,-1,_,False,Okay)+              = if use_xml then text "<remove_file>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</remove_file>"+                           else text "R" <+> text (fn2fp f)+          summ (f,_,-1,_,False,Conflicted)+              = if use_xml then text "<remove_file conflict='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</remove_file>"+                           else text "R!" <+> text (fn2fp f)+          summ (f,_,-1,_,False,Duplicated)+              = if use_xml then text "<remove_file duplicate='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</remove_file>"+                           else text "R" <+> text (fn2fp f) <+> text "(duplicate)"+          summ (f,-1,_,_,False,Okay)+              = if use_xml then text "<add_file>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</add_file>"+                           else text "A" <+> text (fn2fp f)+          summ (f,-1,_,_,False,Conflicted)+              = if use_xml then text "<add_file conflict='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</add_file>"+                           else text "A!" <+> text (fn2fp f)+          summ (f,-1,_,_,False,Duplicated)+              = if use_xml then text "<add_file duplicate='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</add_file>"+                           else text "A" <+> text (fn2fp f) <+> text "(duplicate)"+          summ (f,0,0,0,False,Okay) | f == fp2fn "" = empty+          summ (f,0,0,0,False,Conflicted) | f == fp2fn ""+              = if use_xml then empty -- don't know what to do here...+                           else text "!" <+> text (fn2fp f)+          summ (f,0,0,0,False,Duplicated) | f == fp2fn ""+              = if use_xml then empty -- don't know what to do here...+                           else text (fn2fp f) <+> text "(duplicate)"+          summ (f,a,b,r,False,Okay)+              = if use_xml then text "<modify_file>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                                    <> xrm a <> xad b <> xrp r+                             $$ text "</modify_file>"+                           else text "M" <+> text (fn2fp f)+                                         <+> rm a <+> ad b <+> rp r+          summ (f,a,b,r,False,Conflicted)+              = if use_xml then text "<modify_file conflict='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                                    <> xrm a <> xad b <> xrp r+                             $$ text "</modify_file>"+                           else text "M!" <+> text (fn2fp f)+                                    <+> rm a <+> ad b <+> rp r+          summ (f,a,b,r,False,Duplicated)+              = if use_xml then text "<modify_file duplicate='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                                    <> xrm a <> xad b <> xrp r+                             $$ text "</modify_file>"+                           else text "M" <+> text (fn2fp f)+                                    <+> rm a <+> ad b <+> rp r <+> text "(duplicate)"+          summ (f,_,-1,_,True,Okay)+              = if use_xml then text "<remove_directory>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</remove_directory>"+                           else text "R" <+> text (fn2fp f) <> text "/"+          summ (f,_,-1,_,True,Conflicted)+              = if use_xml then text "<remove_directory conflict='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</remove_directory>"+                           else text "R!" <+> text (fn2fp f) <> text "/"+          summ (f,_,-1,_,True,Duplicated)+              = if use_xml then text "<remove_directory duplicate='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</remove_directory>"+                           else text "R" <+> text (fn2fp f) <> text "/ (duplicate)"+          summ (f,-1,_,_,True,Okay)+              = if use_xml then text "<add_directory>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</add_directory>"+                           else text "A" <+> text (fn2fp f) <> text "/"+          summ (f,-1,_,_,True,Conflicted)+              = if use_xml then text "<add_directory conflict='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</add_directory>"+                           else text "A!" <+> text (fn2fp f) <> text "/"+          summ (f,-1,_,_,True,Duplicated)+              = if use_xml then text "<add_directory duplicate='true'>"+                             $$ escapeXML (drop_dotslash $ fn2fp f)+                             $$ text "</add_directory>"+                           else text "A!" <+> text (fn2fp f) <> text "/ (duplicate)"+          summ _ = empty+          ad 0 = empty+          ad a = plus <> text (show a)+          xad 0 = empty+          xad a = text "<added_lines num='" <> text (show a) <> text "'/>"+          rm 0 = empty+          rm a = minus <> text (show a)+          xrm 0 = empty+          xrm a = text "<removed_lines num='" <> text (show a) <> text "'/>"+          rp 0 = empty+          rp a = text "r" <> text (show a)+          xrp 0 = empty+          xrp a = text "<replaced_tokens num='" <> text (show a) <> text "'/>"+          drop_dotslash ('.':'/':str) = drop_dotslash str+          drop_dotslash str = str+          themoves :: [Doc]+          themoves = map showmoves p+          showmoves :: IsConflictedPrim -> Doc+          showmoves (IsC _ (Move a b))+              = if use_xml+                then text "<move from=\""+                  <> escapeXML (drop_dotslash $ fn2fp a) <> text "\" to=\""+                  <> escapeXML (drop_dotslash $ fn2fp b) <> text"\"/>"+                else text " "    <> text (fn2fp a)+                  <> text " -> " <> text (fn2fp b)+          showmoves _ = empty+\end{code}++\begin{code}+instance (Conflict p, ShowPatch p) => ShowPatch (Named p) where+    showPatch (NamedP n [] p) = showPatchInfo n <> showPatch p+    showPatch (NamedP n d p) = showNamedPrefix n d <+> showPatch p+    showContextPatch s (NamedP n [] p) = showPatchInfo n <> showContextPatch s p+    showContextPatch s (NamedP n d p) = showNamedPrefix n d <+> showContextPatch s p+    description (NamedP n _ _) = human_friendly n+    summary p = description p $$ text "" $$+                prefix "    " (summarize p) -- this isn't summary because summary does the+                                            -- wrong thing with (Named (FL p)) so that it can+                                            -- get the summary of a sequence of named patches+                                            -- right.+    showNicely p@(NamedP _ _ pt) = description p $$+                                   prefix "    " (showNicely pt)++instance (Conflict p, ShowPatch p) => Show (Named p C(x y)) where+    show = renderString . showPatch++instance (Conflict p, Apply p, Effect p, ShowPatch p) => ShowPatch (FL p) where+    showPatch xs = vcat (mapFL showPatch xs)+    showContextPatch = showContextSeries+    description = vcat . mapFL description+    summary = vcat . mapFL summary+    thing x = thing (helperx x) ++ "s"+        where helperx :: FL a C(x y) -> a C(x y)+              helperx _ = undefined+    things = thing++instance (Conflict p, Apply p, ShowPatch p) => ShowPatch (RL p) where+    showPatch = showPatch . reverseRL+    showContextPatch s = showContextPatch s . reverseRL+    description = description . reverseRL+    summary = summary . reverseRL+    thing = thing . reverseRL+    things = things . reverseRL++instance (Conflict p, Patchy p) => Patchy (FL p)+instance (Conflict p, Patchy p) => Patchy (RL p)++\end{code}
+ src/Darcs/Population.lhs view
@@ -0,0 +1,167 @@+%  Copyright (C) 2003-2004 Jan Scheffczyk and David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\section{Population}+NOTE: this documentation belongs in a ``libdarcs API'' chapter, which+currently doesn't exist.+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Population ( Population, patchChanges, applyToPop,+                    getPopFrom,+                    setPopState,+                    DirMark(..),+                    getRepoPop, getRepoPopVersion,+                    lookup_pop, lookup_creation_pop,+                    modified_to_xml,+                  ) where+import FastPackedString ( unpackPS, packString,+                        )+import Data.Maybe ( catMaybes )+import Darcs.Utils ( withCurrentDirectory )++import Darcs.Hopefully ( PatchInfoAnd, hopefully, info )+import FileName ( fn2fp, fp2fn, fn2ps, norm_path )+import Darcs.Patch ( RepoPatch, applyToPop, patchcontents, patchChanges,+                     Effect, effect )+import Darcs.Patch.Ordered ( FL(..), RL(..), reverseRL, concatRL, mapRL )+import Darcs.Patch.Info ( PatchInfo, patchinfo, to_xml )+import Darcs.Patch.Set ( PatchSet )+import Darcs.Sealed ( liftSM )+import Darcs.Repository ( withRepositoryDirectory, ($-), read_repo )+import Darcs.Repository.Pristine ( identifyPristine, getPristinePop )+import Darcs.PopulationData ( Population(..), PopTree(..), Info(..), DirMark(..),+                        setPopState, getPopFrom )+import Printer ( empty, text, ($$), (<>), Doc )+#include "impossible.h"+\end{code}++a dummy PatchInfo++\begin{code}+nullPI :: PatchInfo+nullPI = patchinfo [] [] [] []+\end{code}++population of an empty repository++\begin{code}+initPop :: Population+initPop = Pop nullPI (PopDir i [])+ where i = Info {nameI = packString ".",+                 modifiedByI = nullPI,+                 modifiedHowI = DullDir,+                 createdByI = Nothing,+                 creationNameI = Just (packString ".")}+\end{code}++apply a patchset to a population++\begin{code}+applyPatchSetPop :: RepoPatch p => PatchSet p -> Population -> Population+applyPatchSetPop ps pop = applyPatchesPop (reverseRL $ concatRL ps) pop+\end{code}++apply Patches to a population++\begin{code}+applyPatchesPop :: Effect p => FL (PatchInfoAnd p) -> Population -> Population+applyPatchesPop NilFL = id+applyPatchesPop (hp:>:hps) = applyPatchesPop hps .+                             applyToPop (info hp) (effect $ patchcontents $ hopefully hp)+\end{code}++get the pristine population from a repo++\begin{code}++getRepoPop :: FilePath -> IO Population+getRepoPop repobasedir+ = withRepositoryDirectory [] repobasedir $- \repository -> do+      pinfo <- (head . mapRL info . concatRL) `liftSM` read_repo repository+      -- pinfo is the latest patchinfo+      mp <- withCurrentDirectory repobasedir $+                identifyPristine >>= getPristinePop pinfo+      case mp of+          (Just pop) -> return pop+          (Nothing) -> getRepoPopVersion repobasedir pinfo++getRepoPopVersion :: FilePath -> PatchInfo -> IO Population+getRepoPopVersion repobasedir pinfo = withRepositoryDirectory [] repobasedir $- \repository ->+   do pips <- concatRL `liftSM` read_repo repository+      return $ applyPatchSetPop (dropWhileRL ((/=pinfo).info) pips:<:NilRL) initPop+          where dropWhileRL f (x:<:xs) | f x = dropWhileRL f xs+                                       | otherwise = x :<: xs+                dropWhileRL _ NilRL = NilRL+\end{code}+++Routines for pulling data conveniently out of a Population++\begin{code}+lookup_pop :: FilePath -> Population -> Maybe Population+lookup_pop f p = lookup_pop' (unpackPS $ fn2ps $ fp2fn f) p++lookup_pop' :: String -> Population -> Maybe Population+lookup_pop' f p@(Pop _ (PopFile i))+    | unpackPS (nameI i) == f = Just p+    | otherwise = Nothing+lookup_pop' d p@(Pop pinfo (PopDir i c))+    | unpackPS (nameI i) == "." =+        case catMaybes $ map (lookup_pop' (dropDS d).(Pop pinfo)) c of+        [apop] -> Just apop+        [] -> Nothing+        _ -> impossible+    | unpackPS (nameI i) == takeWhile (/='/') d =+        case dropWhile (=='/') $ dropWhile (/='/') d of+        "" -> Just p+        d' -> case catMaybes $ map (lookup_pop' d'.(Pop pinfo)) c of+              [apop] -> Just apop+              [] -> Nothing+              _ -> impossible+    | otherwise = Nothing+    where dropDS ('.':'/':f) = dropDS f+          dropDS f = f++lookup_creation_pop :: PatchInfo -> FilePath -> Population -> Maybe Population+lookup_creation_pop pinfo f p = lookup_creation_pop' pinfo (unpackPS $ fn2ps $ fp2fn f) p++lookup_creation_pop' :: PatchInfo -> String -> Population -> Maybe Population+lookup_creation_pop' b a (Pop pinfo pp) = (Pop pinfo) `fmap` lcp pp+    where lcp p@(PopFile i)+              | fixname `fmap` creationNameI i == f && createdByI i == who = Just p+              | otherwise = Nothing+          lcp p@(PopDir i c)+              | fixname `fmap` creationNameI i == f && createdByI i == who = Just p+              | otherwise = case catMaybes $ map lcp c of+                            [apop] -> Just apop+                            _ -> Nothing+          fixname = packString . fn2fp . norm_path . fp2fn . unpackPS+          f = Just $ packString $ fn2fp $ norm_path $ fp2fn a+          who = Just b+\end{code}++\begin{code}+modified_to_xml :: Info -> Doc+modified_to_xml i | modifiedHowI i == DullDir = empty+                  | modifiedHowI i == DullFile = empty+modified_to_xml i = text "<modified>"+                 $$ text "<modified_how>" <> text (show (modifiedHowI i)) <>+                    text "</modified_how>"+                 $$ to_xml (modifiedByI i)+                 $$ text "</modified>"+\end{code}
+ src/Darcs/PopulationData.lhs view
@@ -0,0 +1,147 @@+%  Copyright (C) 2003-2004 Jan Scheffczyk and David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++NOTE: this documentation belongs in a ``libdarcs API'' chapter, which+currently doesn't exist.+\begin{code}+module Darcs.PopulationData ( Population(..), PopTree(..), Info(..),+                        setPopState, notModified, setState,+                        DirMark(..), getPopFrom+                      ) where+import Darcs.Patch.Info+import FastPackedString+import Darcs.Utils ( withCurrentDirectory )+import System.Directory ( doesDirectoryExist, getDirectoryContents )+\end{code}++the population of a darcs repository+(simpler Slurpy)+PatchInfo: state when last modified+PopTree: the directory listing++\begin{code}+data Population = Pop PatchInfo PopTree+ deriving (Show, Eq)++setPopState :: PatchInfo -> Population -> Population+setPopState i (Pop _ tr) = Pop i tr+\end{code}++directory listing++\begin{code}+data PopTree = PopDir !Info ![PopTree]+             | PopFile !Info+ deriving ( Ord, Eq )+\end{code}++info of a directory member++\begin{code}+data DirMark = AddedFile | RemovedFile | MovedFile String+             | ModifiedFile | DullFile+             | AddedDir | RemovedDir | MovedDir !String | DullDir+               deriving ( Ord, Eq )+data Info = Info {nameI :: !PackedString, -- name of the element+                  modifiedByI :: !PatchInfo, -- last patch modifying this element+                  modifiedHowI :: !DirMark, -- how was it modified+                  createdByI :: !(Maybe PatchInfo), -- this can be unknown when restored backwards!+                  creationNameI :: !(Maybe PackedString)} -- the original name of the element+ deriving ( Ord, Eq )+\end{code}++was an Info record not modified?++\begin{code}+notModified :: Info -> Bool+notModified i = (modifiedHowI i == DullFile) || (modifiedHowI i == DullDir)+\end{code}++set the modifier for an Info record++\begin{code}+setState :: Info -> PatchInfo -> Info+setState i pinfo = i { modifiedByI = pinfo }++instance Show PopTree where+ show s = showPop "" s++showPop :: String -> PopTree -> String+showPop indent (PopDir i fs)+ = indent ++ show i ++ "\n" +++   unlines (map (showPop (' ':indent)) fs)+showPop indent (PopFile i)+ = indent ++ show i++instance Show Info where+ show i = show (nameI i) ++ " " ++ show (modifiedHowI i) +++          " at state " ++ show (modifiedByI i)++instance Show DirMark where+ show AddedFile = "File added"+ show RemovedFile = "File removed"+ show (MovedFile s) = "File moved to " ++ s+ show ModifiedFile = "File modified"+ show DullFile = "File old"+ show AddedDir = "Dir added"+ show RemovedDir = "Dir removed"+ show (MovedDir s) = "Dir moved from " ++ s+ show DullDir = "Dir old"++\end{code}++read the population from a given directory ``dirname''+all folders and documents get the given time ``t''++This needs to be here in order to avoid a circular dependency between+Population and Pristine.++\begin{code}+getPopFrom :: FilePath -> PatchInfo -> IO Population+getPopFrom the_directory pinfo =+    withCurrentDirectory the_directory $+       do popT <- getPopFrom_helper "."+          return (Pop pinfo popT)+ where getPopFrom_helper :: FilePath -> IO PopTree+       getPopFrom_helper dirname = do+        isdir <- doesDirectoryExist dirname+        let n = packString dirname+        if isdir+          then do+           fnames <- getDirectoryContents dirname+           sl <- withCurrentDirectory dirname+                 (sequence $ map getPopFrom_helper $ filter not_hidden fnames)+           let i = Info {nameI = n,+                         modifiedByI = pinfo,+                         modifiedHowI = DullDir,+                         createdByI = Just pinfo,+                         creationNameI = Just n}+           return $ PopDir i sl+          else do let i = Info {nameI = n,+                                modifiedByI = pinfo,+                                modifiedHowI = DullFile,+                                createdByI = Just pinfo,+                                creationNameI = Just n}+                  return $ PopFile i++not_hidden :: FilePath -> Bool+not_hidden ('.':_) = False+not_hidden ('_':_) = False+not_hidden _ = True+\end{code}+
+ src/Darcs/PrintPatch.lhs view
@@ -0,0 +1,48 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.PrintPatch ( printPatch, contextualPrintPatch,+                          printPatchPager, printFriendly ) where++import Darcs.Patch ( Patchy, showContextPatch, showPatch )+import Darcs.SlurpDirectory ( Slurpy )+import Darcs.Arguments ( DarcsFlag, showFriendly )+import Printer ( putDocLnWith )+import Darcs.ColorPrinter ( fancyPrinters )+import Darcs.External ( viewDocWith )+\end{code}+++\begin{code}++printFriendly :: Patchy p => [DarcsFlag] -> p C(x y) -> IO ()+printFriendly opts p = putDocLnWith fancyPrinters $ showFriendly opts p++printPatch :: Patchy p => p C(x y) -> IO ()+printPatch p = putDocLnWith fancyPrinters $ showPatch p++printPatchPager :: Patchy p => p C(x y) -> IO ()+printPatchPager p = viewDocWith fancyPrinters $ showPatch p++contextualPrintPatch :: Patchy p => Slurpy -> p C(x y) -> IO ()+contextualPrintPatch s p = putDocLnWith fancyPrinters $ showContextPatch s p++\end{code}
+ src/Darcs/Progress.lhs view
@@ -0,0 +1,218 @@+% Various utility functions that do not belong anywhere else.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.Progress ( beginTedious, endTedious, tediousSize,+                        debugMessage, debugFail, withoutProgress,+                        progress, finishedOne, finishedOneIO,+                        progressList, progressFL, progressRL,+                        setProgressMode ) where++import Prelude hiding (lookup, catch)++import Control.Exception ( catch, throw )+import Control.Monad ( when )+import System.IO ( stdout, stderr, hFlush, hPutStr, hPutStrLn,+                   hSetBuffering, hIsTerminalDevice,+                   Handle, BufferMode(LineBuffering) )+import System.IO.Unsafe ( unsafePerformIO )+import Data.Char ( toLower )+import Data.Map ( Map, empty, adjust, insert, delete, lookup )+import Data.Maybe ( isJust )+import Control.Concurrent ( forkIO, threadDelay )+import Data.IORef ( IORef, newIORef, readIORef, writeIORef, modifyIORef )++import Darcs.Patch.Ordered ( FL(..), RL(..), lengthRL, lengthFL )+import Darcs.Global ( withDebugMode, debugMessage, putTiming, debugFail )++handleProgress :: IO ()+handleProgress = do threadDelay 1000000+                    handleMoreProgress "" 0++handleMoreProgress :: String -> Int -> IO ()+handleMoreProgress k n = withProgressMode $ \m ->+    if m then do s <- getProgressLast+                 mp <- getProgressData s+                 case mp of+                   Nothing -> do threadDelay 1000000+                                 handleMoreProgress k n+                   Just p -> do when (k /= s || n < sofar p) $ whenProgressMode $ printProgress s p+                                threadDelay 1000000+                                handleMoreProgress s (sofar p)+         else do threadDelay 1000000+                 handleMoreProgress k n++printProgress :: String -> ProgressData -> IO ()+printProgress k (ProgressData {sofar=s, total=Just t, latest=Just l}) =+    myput (k++" "++show s++"/"++show t++" : "++l) (k++" "++show s++"/"++show t)+printProgress k (ProgressData {latest=Just l}) =+    myput (k++" "++l) k+printProgress k (ProgressData {sofar=s, total=Just t}) | t >= s =+    myput (k++" "++show s++"/"++show t) (k++" "++show s)+printProgress k (ProgressData {sofar=s}) =+    myput (k++" "++show s) k++myput :: String -> String -> IO ()+myput l s = withDebugMode $ \debugMode ->+            if debugMode+            then putTiming >> hPutStrLn stderr l+            else if '\n' `elem` l+                 then myput (takeWhile (/= '\n') l) s+                 else if length l < 80 then putTiming >> simpleput l+                                       else putTiming >> simpleput (take 80 s)++{-# NOINLINE simpleput #-}+simpleput :: String -> IO ()+simpleput = unsafePerformIO $ mkhPutCr stderr++beginTedious :: String -> IO ()+beginTedious k = do debugMessage $ "Beginning " ++ lower k+                    setProgressData k $ ProgressData { sofar = 0,+                                                       latest = Nothing,+                                                       total = Nothing }++endTedious :: String -> IO ()+endTedious k = whenProgressMode $ do p <- getProgressData k+                                     modifyIORef _progressData (\(a,m) -> (a,delete k m))+                                     when (isJust p) $ debugMessage $ "Done "++lower k++lower :: String -> String+lower (x:xs) = toLower x:xs+lower "" = ""++beginOrEndTedious :: String -> Int -> IO ()+beginOrEndTedious k l = do mp <- getProgressData k+                           case mp of+                             Nothing -> do beginTedious k+                                           tediousSize k l+                             Just p -> if total p == Just l+                                       then endTedious k+                                       else return ()++tediousSize :: String -> Int -> IO ()+tediousSize k s = updateProgressData k uptot+    where uptot p = case total p of Just t -> seq ts $ p { total = Just ts }+                                        where ts = t + s+                                    Nothing -> p { total = Just s }++minlist :: Int+minlist = 4++progressList :: String -> [a] -> [a]+progressList _ [] = []+progressList k (x:xs) = if l < minlist then x:xs+                                       else startit x : pl xs+    where l = length (x:xs)+          startit y = unsafePerformIO $ do beginOrEndTedious k l+                                           return y+          pl [y] = [startit y]+          pl [] = []+          pl (y:ys) = progress k y : pl ys++progressFL :: String -> FL a C(x y) -> FL a C(x y)+progressFL _ NilFL = NilFL+progressFL k (x:>:xs) = if l < minlist then x:>:xs+                                       else startit x :>: pl xs+    where l = lengthFL (x:>:xs)+          startit y = unsafePerformIO $ do beginOrEndTedious k l+                                           return y+          pl :: FL a C(x y) -> FL a C(x y)+          pl (y:>:NilFL) = (startit y) :>: NilFL+          pl NilFL = NilFL+          pl (y:>:ys) = progress k y :>: pl ys++progressRL :: String -> RL a C(x y) -> RL a C(x y)+progressRL _ NilRL = NilRL+progressRL k (x:<:xs) = if l < minlist then x:<:xs+                                       else startit x :<: pl xs+    where l = lengthRL (x:<:xs)+          startit y = unsafePerformIO $ do beginOrEndTedious k l+                                           return y+          pl :: RL a C(x y) -> RL a C(x y)+          pl (y:<:NilRL) = (startit y) :<: NilRL+          pl NilRL = NilRL+          pl (y:<:ys) = progress k y :<: pl ys++progress :: String -> a -> a+progress k a = unsafePerformIO $ progressIO k >> return a++progressIO :: String -> IO ()+progressIO "" = return ()+progressIO k = do updateProgressData k (\p -> p { sofar = sofar p + 1,+                                                  latest = Nothing })+                  putDebug k ""++finishedOne :: String -> String -> a -> a+finishedOne k l a = unsafePerformIO $ finishedOneIO k l >> return a++finishedOneIO :: String -> String -> IO ()+finishedOneIO "" _ = return ()+finishedOneIO k l = do updateProgressData k (\p -> p { sofar = sofar p + 1,+                                                       latest = Just l })+                       putDebug k l++putDebug :: String -> String -> IO ()+putDebug _ _ = return ()+--putDebug k "" = when (False && debugMode) $ hPutStrLn stderr $ "P: "++k+--putDebug k l = when (False && debugMode) $ hPutStrLn stderr $ "P: "++k++" : "++l++{-# NOINLINE _progressMode #-}+_progressMode :: IORef Bool+_progressMode = unsafePerformIO $ do hSetBuffering stderr LineBuffering+                                     newIORef True++{-# NOINLINE _progressData #-}+_progressData :: IORef (String, Map String ProgressData)+_progressData = unsafePerformIO $ do forkIO handleProgress+                                     newIORef ("", empty)++mkhPutCr :: Handle -> IO (String -> IO ())+mkhPutCr fe = do+  isTerm <- hIsTerminalDevice fe+  stdoutIsTerm <- hIsTerminalDevice stdout+  return $ if isTerm then \s -> do hPutStr fe $ '\r':s++"\r"+                                   hFlush fe+                                   let spaces = '\r':take (length s) (repeat ' ')++"\r"+                                   hPutStr fe spaces+                                   when stdoutIsTerm $ hPutStr stdout spaces+                     else \s -> when (not $ null s) $ do hPutStrLn fe s+                                                         hFlush fe++setProgressMode :: Bool -> IO ()+setProgressMode m = writeIORef _progressMode m++withoutProgress :: IO a -> IO a+withoutProgress j = withProgressMode $ \m -> do debugMessage "Disabling progress reports..."+                                                setProgressMode False+                                                a <- j `catch` \e -> setProgressMode m >> throw e+                                                if m then debugMessage "Reenabling progress reports."+                                                     else debugMessage "Leaving progress reports off."+                                                setProgressMode m+                                                return a++updateProgressData :: String -> (ProgressData -> ProgressData) -> IO ()+updateProgressData k f = whenProgressMode $ modifyIORef _progressData (\(_,m) -> (k,adjust f k m))++setProgressData :: String -> ProgressData -> IO ()+setProgressData k p = whenProgressMode $ modifyIORef _progressData (\(a,m) -> (a,insert k p m))++getProgressData :: String -> IO (Maybe ProgressData)+getProgressData k = withProgressMode $ \p -> if p then (lookup k . snd) `fmap` readIORef _progressData+                                                  else return Nothing++getProgressLast :: IO String+getProgressLast = withProgressMode $ \p -> if p then fst `fmap` readIORef _progressData+                                                else return ""++whenProgressMode :: IO a -> IO ()+whenProgressMode j = withProgressMode $ const $ j >> return ()++withProgressMode :: (Bool -> IO a) -> IO a+withProgressMode j = readIORef _progressMode >>= j++data ProgressData = ProgressData { sofar :: !Int,+                                   latest :: !(Maybe String),+                                   total :: !(Maybe Int)}++\end{code}
+ src/Darcs/RemoteApply.lhs view
@@ -0,0 +1,64 @@+\begin{code}+module Darcs.RemoteApply ( remote_apply, apply_as ) where++import System.Exit ( ExitCode )++import Darcs.Flags ( DarcsFlag( ApplyAs, Debug ) )+import Darcs.Utils ( breakCommand )+import Darcs.URL ( is_url, is_ssh )+import Darcs.External+import Printer+\end{code}++This module is used by the push and put commands to apply the a bundle to a+remote repository. By remote I do not necessarily mean a repository on another+machine, it is just not the repository we're located in.++\begin{code}+remote_apply :: [DarcsFlag] -> String -> Doc -> IO ExitCode+remote_apply opts repodir bundle +    = case apply_as opts of+        Nothing -> if is_ssh repodir+                   then apply_via_ssh opts repodir bundle+                   else if is_url repodir+                        then apply_via_url opts repodir bundle+                        else apply_via_local opts repodir bundle+        Just un -> if is_ssh repodir+                   then apply_via_ssh_and_sudo repodir un bundle+                   else apply_via_sudo un repodir bundle++apply_as :: [DarcsFlag] -> Maybe String+apply_as (ApplyAs user:_) = Just user+apply_as (_:fs) = apply_as fs+apply_as [] = Nothing+apply_via_sudo :: String -> String -> Doc -> IO ExitCode+apply_via_sudo user repo bundle =+    pipeDoc "sudo" ["-u",user,"darcs","apply","--all","--repodir",repo] bundle+apply_via_local :: [DarcsFlag] -> String -> Doc -> IO ExitCode+apply_via_local opts repo bundle =+    pipeDoc "darcs" ("apply":"--all":"--repodir":repo:applyopts opts) bundle++apply_via_url :: [DarcsFlag] -> String -> Doc -> IO ExitCode+apply_via_url opts repo bundle =+    do maybeapply <- maybeURLCmd "APPLY" repo+       case maybeapply of+         Nothing -> apply_via_local opts repo bundle+         Just apply ->+           do let (cmd, args) = breakCommand apply+              pipeDoc cmd (args ++ [repo]) bundle++apply_via_ssh :: [DarcsFlag] -> String -> Doc -> IO ExitCode+apply_via_ssh opts repo bundle =+    pipeDocSSH addr ["darcs apply --all "++unwords (applyopts opts)++" --repodir '"++path++"'"] bundle+        where (addr,':':path) = break (==':') repo++apply_via_ssh_and_sudo :: String -> String -> Doc -> IO ExitCode+apply_via_ssh_and_sudo repo username bundle =+    pipeDocSSH addr ["sudo -u "++username+++                         " darcs apply --all --repodir '"++path++"'"] bundle+        where (addr,':':path) = break (==':') repo++applyopts :: [DarcsFlag] -> [String]+applyopts opts = if Debug `elem` opts then ["--debug"] else []++\end{code}
+ src/Darcs/RepoPath.hs view
@@ -0,0 +1,163 @@+{-# OPTIONS_GHC -cpp #-}+-- Copyright (C) 2007 Eric Kow+--+-- 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, 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; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++module Darcs.RepoPath ( AbsolutePath, mkAbsolutePath,+                        RelativePath, mkRelativePath,+                        SubPath, maybeMkSubPath,+                        rp2fn, unsafeFn2rp,+                        ap2fn, unsafeFn2ap,+                        sp2fn,+                        FilePathOrURL(..), FilePathLike(toFilePath),+                        appendToPath, combine, takeDirectory,+                        makeSubPathOf, makeAbsolute,+                      ) where++import Data.List ( isPrefixOf )++import Autoconf ( path_separator )+import FileName++class FilePathOrURL a where+ {-# INLINE toPath #-}+ toPath :: a -> String++class FilePathOrURL a => FilePathLike a where+ {-# INLINE toFilePath #-}+ toFilePath :: a -> FilePath+ {-# INLINE toInternal #-}+ toInternal :: a -> FilePath+ {-# INLINE fromInternal #-}+ fromInternal :: FilePath -> a++-- | Relative to the local darcs repository and normalized+--   Note: these are understood not to have the dot in front+newtype SubPath      = SubPath FilePath deriving (Eq, Ord)+newtype RelativePath = RelativePath FilePath deriving (Eq, Ord)+newtype AbsolutePath = AbsolutePath FilePath deriving (Eq, Ord)++instance FilePathOrURL AbsolutePath where+ toPath (AbsolutePath x) = x+instance FilePathOrURL RelativePath where+ toPath (RelativePath x) = x+instance FilePathOrURL SubPath where+ toPath (SubPath x) = x++instance FilePathLike AbsolutePath where+ toFilePath (AbsolutePath x) = x+ toInternal (AbsolutePath x) = x+ fromInternal xs       = AbsolutePath xs+instance FilePathLike RelativePath where+ toFilePath (RelativePath x) = x+ toInternal (RelativePath x) = x+ fromInternal = RelativePath+instance FilePathLike SubPath where+ toFilePath (SubPath x) = x+ toInternal (SubPath x) = x+ fromInternal = SubPath++-- | Make the second path relative to the first, if possible+makeSubPathOf :: AbsolutePath -> AbsolutePath -> Maybe SubPath+makeSubPathOf (AbsolutePath p1) (AbsolutePath p2) =+ -- The slash prevents "foobar" from being treated as relative to "foo"+ if p1 == p2 || (p1 ++ "/") `isPrefixOf` p2+    then Just $ SubPath $ drop (length p1 + 1) p2+    else Nothing++-- | Interpret the second (relative) path wrt the first (absolute) one+--   N.B. makeAbsolute "\/foo" "..\/..\/..\/bar" == "\/bar"+makeAbsolute :: AbsolutePath -> RelativePath -> AbsolutePath+makeAbsolute p1 (RelativePath p2) = ma p2+ where ma ('.':'.':'/':r) = if pp1 == p1 then AbsolutePath r else ma r+       ma r = combine p1 (SubPath r)+       pp1 = takeDirectory p1++combine :: FilePathLike a => a -> SubPath -> a+combine p1 (SubPath "") = p1+combine p1 (SubPath p2) | null (toInternal p1) = fromInternal p2+combine p1 (SubPath p2) = withInternal (++ '/':p2) p1++appendToPath :: FilePathLike a => String -> a -> a+appendToPath suf = withInternal (++ suf)++takeDirectory :: FilePathLike a => a -> a+takeDirectory = withInternal (reverse .  drop 1 . dropWhile (/='/') . reverse)++withInternal :: FilePathLike a => (FilePath -> FilePath) -> a -> a+withInternal f = fromInternal . f . toInternal++-- TODO: quickcheck that withInternal id x == id x++instance Show AbsolutePath where+ show = show . toFilePath+instance Show RelativePath where+ show = show . toFilePath+instance Show SubPath where+ show = show . toFilePath++cleanup :: Char -> Char+cleanup '\\' | path_separator == '\\' = '/'+cleanup c = c++norm_slashes :: String -> String+#ifndef WIN32+-- multiple slashes in front are ignored under Unix+norm_slashes ('/':p) = '/' : dropWhile (== '/') p+#endif+norm_slashes p = p++{-# INLINE mkAbsolutePath #-}+mkAbsolutePath :: FilePath -> AbsolutePath+mkAbsolutePath p = AbsolutePath $ slashes ++ (fn2fp $ norm_path $ fp2fn cleanp)+  where+    cleanp  = map cleanup p+    slashes = norm_slashes $ takeWhile (== '/') cleanp++{-# INLINE mkRelativePath #-}+mkRelativePath :: FilePath -> RelativePath+mkRelativePath p = unsafeFn2rp $ norm_path $ fp2fn $ map cleanup p++maybeMkSubPath :: FilePath -> Either RelativePath SubPath+maybeMkSubPath rawp =+ case p of+   ('.':'.':'/':_) -> Left $ RelativePath p+   _ -> Right $ SubPath p+ where p = fn2fp $ norm_path $ fp2fn $ map cleanup rawp++{-# INLINE ap2fn #-}+ap2fn :: AbsolutePath -> FileName+ap2fn = fp2fn . toFilePath++{-# INLINE rp2fn #-}+rp2fn :: RelativePath -> FileName+rp2fn = fp2fn . toFilePath++{-# INLINE sp2fn #-}+sp2fn :: SubPath -> FileName+sp2fn = fp2fn . toFilePath++{-# INLINE unsafeFn2ap #-}+-- | unsafe because we don't actually know if the FileName+--   encodes a relative path+unsafeFn2ap :: FileName -> AbsolutePath+unsafeFn2ap = AbsolutePath . fn2fp++{-# INLINE unsafeFn2rp #-}+-- | unsafe because we don't actually know if the FileName+--   encodes a relative path+unsafeFn2rp :: FileName -> RelativePath+unsafeFn2rp = RelativePath . fn2fp
+ src/Darcs/Repository.lhs view
@@ -0,0 +1,256 @@+%  Copyright (C) 2002-2004 David Roundy+%  Copyright (C) 2005 Juliusz Chroboczek+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Repository ( Repository, ($-), maybeIdentifyRepository,+                          identifyRepositoryFor,+                          withRepoLock, withRepoReadLock,+                          withRepository, withRepositoryDirectory, withGutsOf,+                          makePatchLazy, writePatchSet,+                    findRepository, amInRepository, amNotInRepository,+                    slurp_pending, replacePristine,+                    slurp_recorded, slurp_recorded_and_unrecorded,+                    withRecorded,+                    get_unrecorded, get_unrecorded_unsorted, get_unrecorded_no_look_for_adds,+                    read_repo, sync_repo,+                    prefsUrl,+                    read_pending, add_to_pending,+                    tentativelyAddPatch, tentativelyRemovePatches, tentativelyAddToPending,+                    tentativelyReplacePatches,+                    tentativelyMergePatches, considerMergeToWorking,+                    revertRepositoryChanges, finalizeRepositoryChanges,+                    copyRepository, copy_oldrepo_patches,+                    patchSetToRepository,+                    unrevertUrl,+                    applyToWorking, patchSetToPatches,+                    createPristineDirectoryTree, createPartialsPristineDirectoryTree,+                    optimizeInventory, cleanRepository, checkPristineAgainstCwd,+                    getMarkedupFile,+                    PatchSet, SealedPatchSet, PatchInfoAnd,+                    setScriptsExecutable+                  ) where++import Darcs.Repository.Internal+    (Repository(..), RepoType(..), ($-), pristineFromWorking,+     maybeIdentifyRepository, identifyRepositoryFor,+     findRepository, amInRepository, amNotInRepository,+     makePatchLazy,+     slurp_pending, replacePristine,+     slurp_recorded, slurp_recorded_and_unrecorded,+     withRecorded,+     get_unrecorded, get_unrecorded_unsorted, get_unrecorded_no_look_for_adds,+     read_repo, sync_repo,+     prefsUrl, checkPristineAgainstCwd,+     read_pending, add_to_pending,+     withRepoLock, withRepoReadLock, withRepository, withRepositoryDirectory, withGutsOf,+     tentativelyAddPatch, tentativelyRemovePatches, tentativelyAddToPending,+     tentativelyReplacePatches,+     tentativelyMergePatches, considerMergeToWorking,+     revertRepositoryChanges, finalizeRepositoryChanges,+     unrevertUrl,+     applyToWorking, patchSetToPatches,+     createPristineDirectoryTree, createPartialsPristineDirectoryTree,+     optimizeInventory, cleanRepository,+     getMarkedupFile,+     setScriptsExecutable+    )+import Darcs.Repository.Prefs ( unionCaches, fetchFileUsingCache )+import Darcs.Patch.Set ( PatchSet, SealedPatchSet )++import Control.Monad ( unless, when )+import Data.Either(Either(..))++import qualified Darcs.Repository.DarcsRepo as DarcsRepo+import qualified Darcs.Repository.HashedRepo as HashedRepo++import Darcs.Hopefully ( PatchInfoAnd, info, extractHash )+import Darcs.Repository.Checkpoint ( identify_checkpoint, write_checkpoint_patch, get_checkpoint )+import Darcs.Repository.ApplyPatches ( apply_patches )+import Darcs.Repository.HashedRepo ( apply_to_tentative_pristine )+import Darcs.Patch ( RepoPatch, Named, Patch, patch2patchinfo, apply )+import Darcs.Patch.Ordered ( RL(..), bunchFL, mapFL, mapRL, mapRL_RL, concatFL, reverseRL,+                             concatRL, lengthRL )+import Darcs.Repository.Format ( RepoProperty ( HashedInventory ),+                                 format_has )+import Darcs.Patch.Depends ( get_patches_beyond_tag )+import Darcs.Utils ( withCurrentDirectory, catchall )+import Darcs.External ( copyFileOrUrl, Cachable(..) )+import Darcs.Progress ( debugMessage, progressFL, progressRL, tediousSize,+                        beginTedious, endTedious, progress )+import Darcs.Lock ( withTempDir )+import Darcs.Sealed ( Sealed(..), unsafeUnflippedseal, unsealM )++import Darcs.Flags ( DarcsFlag( Quiet, Partial, Lazy, Ephemeral ) )+import Darcs.Global ( darcsdir )+#include "impossible.h"++\end{code}++\begin{code}+copyRepository :: RepoPatch p => Repository p -> IO ()+copyRepository fromrepository@(Repo _ opts rf _)+    | Partial `elem` opts && not (format_has HashedInventory rf) =+        do isPartial <- copyPartialRepository fromrepository+           unless (isPartial == IsPartial) $ copyFullRepository fromrepository+    | otherwise = copyFullRepository fromrepository++data PorNP = NotPartial | IsPartial+             deriving ( Eq )++data RepoSort = Hashed | Old++copyInventory :: forall p . RepoPatch p => Repository p -> IO ()+copyInventory fromrepo@(Repo fromdir opts rf (DarcsRepository _ cremote)) = do+  repo@(Repo todir xx rf2 (DarcsRepository yy c)) <- identifyRepositoryFor fromrepo "."+  let newrepo :: Repository p+      newrepo = Repo todir xx rf2 (DarcsRepository yy (c `unionCaches` cremote))+      copyHashedHashed = HashedRepo.copy_repo newrepo opts fromdir+      copyAnythingToOld r = withCurrentDirectory todir $ read_repo r `unsealM` +                            DarcsRepo.write_inventory_and_patches opts+      repoSort rfx | format_has HashedInventory rfx = Hashed+                   | otherwise = Old+  case repoSort rf2 of+    Hashed ->+        if format_has HashedInventory rf+        then copyHashedHashed+        else withCurrentDirectory todir $+             do HashedRepo.revert_tentative_changes+                Sealed patches <- read_repo fromrepo+                let k = "Copying patch"+                beginTedious k+                tediousSize k (lengthRL $ concatRL patches)+                let patches' = mapRL_RL (mapRL_RL (progress k)) patches+                HashedRepo.write_tentative_inventory c opts patches'+                endTedious k+                HashedRepo.finalize_tentative_changes repo opts+    Old -> case repoSort rf of+           Hashed -> copyAnythingToOld fromrepo+           _ -> copy_oldrepo_patches opts fromrepo todir++copy_oldrepo_patches :: RepoPatch p => [DarcsFlag] -> Repository p -> FilePath -> IO ()+copy_oldrepo_patches opts repository@(Repo dir _ _ _) out = do+  Sealed patches <- DarcsRepo.read_repo opts "."+  mpi <- if Partial `elem` opts+         -- FIXME this should get last pinfo *before*+         -- desired tag...+         then identify_checkpoint repository+         else return Nothing+  DarcsRepo.copy_patches opts dir out $ mapRL info $ since_checkpoint mpi $ concatRL (patches :: PatchSet Patch)+      where --since_checkpoint :: Maybe PatchInfo+            --     -> [PatchInfoAnd] -> [PatchInfoAnd]+            since_checkpoint Nothing ps = ps+            since_checkpoint (Just ch) (hp:<:ps)+                | ch == info hp = hp :<: NilRL+                | otherwise = hp :<: since_checkpoint (Just ch) ps+            since_checkpoint _ NilRL = NilRL++copyPartialRepository :: forall p. RepoPatch p => Repository p -> IO PorNP+copyPartialRepository fromrepository@(Repo _ opts _ _) = do+  mch <- get_checkpoint fromrepository+  case mch :: Maybe (Named p) of+    Nothing -> do putStrLn "No checkpoint."+                  return NotPartial+    Just ch ->+      do copyInventory fromrepository+         withRepoLock opts $- \torepository -> do+           write_checkpoint_patch ch+           Sealed local_patches <- read_repo torepository+           let pi_ch = patch2patchinfo ch+               needed_patches = reverseRL $ concatRL $ unsafeUnflippedseal $+                                get_patches_beyond_tag pi_ch local_patches+           apply opts ch `catch`+                             \e -> fail ("Bad checkpoint!\n" ++ show e)+           apply_patches opts needed_patches+           debugMessage "Writing the pristine"+           pristineFromWorking torepository+           return IsPartial++copyFullRepository :: RepoPatch p => Repository p -> IO ()+copyFullRepository fromrepository@(Repo fromdir opts rffrom _) = do+  copyInventory fromrepository+  debugMessage "Copying prefs"+  copyFileOrUrl opts (fromdir++"/"++darcsdir++"/prefs/prefs") (darcsdir++"/prefs/prefs") (MaxAge 600)+                     `catchall` return ()+  debugMessage "Grabbing lock in new repository..."+  withRepoLock opts $- \torepository@(Repo _ _ rfto (DarcsRepository _ c)) ->+      if format_has HashedInventory rffrom && format_has HashedInventory rfto+      then do debugMessage "Writing working directory contents..."+              createPristineDirectoryTree torepository "."+              fetch_patches_if_necessary opts torepository+              when (Partial `elem` opts) $ putStrLn $+                       "--partial: hashed or darcs-2 repository detected, using --lazy instead"+      else if format_has HashedInventory rfto+           then do Sealed local_patches <- read_repo torepository+                   withTempDir "newpristine" $ \newpris -> replacePristine torepository newpris+                   let patchesToApply = progressFL "Applying patch" $ concatFL $ reverseRL $+                                        mapRL_RL reverseRL local_patches+                   sequence_ $ mapFL (apply_to_tentative_pristine c opts) $ bunchFL 100 patchesToApply+                   finalizeRepositoryChanges torepository+                   debugMessage "Writing working directory contents..."+                   createPristineDirectoryTree torepository "."+           else do read_repo torepository `unsealM` (apply_patches opts . reverseRL . concatRL)+                   debugMessage "Writing the pristine"+                   pristineFromWorking torepository++-- | writePatchSet is like patchSetToRepository, except that it doesn't+-- touch the working directory or pristine cache.+writePatchSet :: RepoPatch p => PatchSet p -> [DarcsFlag] -> IO (Repository p)+writePatchSet patchset opts = do+    maybeRepo <- maybeIdentifyRepository opts "."+    let repo@(Repo _ _ rf2 (DarcsRepository _ c)) = +          case maybeRepo of+            Right r -> r+            Left e  -> bug ("Current directory not repository in writePatchSet: " ++ e)+    debugMessage "Writing inventory"+    if format_has HashedInventory rf2+       then do HashedRepo.write_tentative_inventory c opts patchset+               HashedRepo.finalize_tentative_changes repo opts+       else DarcsRepo.write_inventory_and_patches opts patchset+    return repo++-- | patchSetToRepository takes a patch set, and writes a new repository in the current directory+--   that contains all the patches in the patch set. This function is used when 'darcs get'ing a+--   repository with the --to-match flag and the new repository is not in hashed format.+--   This function does not (yet) work for hashed repositories. If the passed @DarcsFlag@s tell +--   darcs to create a hashed repository, this function will call @error@.+patchSetToRepository :: RepoPatch p => PatchSet p -> [DarcsFlag] -> IO (Repository p)+patchSetToRepository patchset opts = do+    repo <- writePatchSet patchset opts+    read_repo repo `unsealM` (apply_patches opts . reverseRL . concatRL)+    debugMessage "Writing the pristine"+    pristineFromWorking repo+    return repo++-- | Unless a flag has been given in the first argument that tells darcs not to do so (--lazy,+--   --partial or --ephemeral), this function fetches all patches that the given repository has +--   with fetchFileUsingCache. This is used as a helper in copyFullRepository.+fetch_patches_if_necessary :: RepoPatch p => [DarcsFlag] -> Repository p -> IO ()+fetch_patches_if_necessary opts torepository@(Repo _ _ _ (DarcsRepository _ c)) = +    unless (Partial `elem` opts || Lazy `elem` opts || Ephemeral `elem` opts) $+             do putInfo "Copying patches, to get lazy repository hit ctrl-C..."+                Sealed r <- read_repo torepository+                let peekaboo :: PatchInfoAnd p C(x y) -> IO ()+                    peekaboo x = case extractHash x of+                                 Left _ -> return ()+                                 Right h -> fetchFileUsingCache c "patches" h >> return ()+                sequence_ $ mapRL peekaboo $ progressRL "Copying patches" $ concatRL r+  where putInfo = when (not $ Quiet `elem` opts) . putStrLn++\end{code}
+ src/Darcs/Repository/ApplyPatches.lhs view
@@ -0,0 +1,50 @@+%  Copyright (C) 2002-2005,2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.Repository.ApplyPatches ( apply_patches, apply_patches_with_feedback ) where++import Darcs.Patch ( Patchy, apply )+import Darcs.Hopefully ( PatchInfoAnd, hopefully, info )+import Darcs.Patch.Info ( human_friendly )+import Darcs.Patch.Ordered ( FL(..), lengthFL, mapFL )+import Darcs.Flags ( DarcsFlag )+import Darcs.Utils ( putDocLnError )+import Darcs.Progress ( beginTedious, endTedious, tediousSize, finishedOneIO )+import Printer ( text )++apply_patches_with_feedback :: Patchy p => [DarcsFlag] -> String -> FL (PatchInfoAnd p) C(x y) -> IO ()+apply_patches_with_feedback _ _ NilFL = return ()+apply_patches_with_feedback opts k patches =+    do beginTedious k+       tediousSize k (lengthFL patches)+       sequence_ $ mapFL apply_cautiously patches+       endTedious k+    where apply_cautiously :: Patchy p => PatchInfoAnd p C(a b) -> IO ()+          apply_cautiously hp =+             do finishedOneIO k (show $ human_friendly $ info hp)+                apply opts (hopefully hp) `catch` \e ->+                  do putDocLnError $ text "Unapplicable patch:"+                     putDocLnError $ human_friendly (info hp)+                     ioError e++apply_patches :: Patchy p => [DarcsFlag] -> FL (PatchInfoAnd p) C(x y) -> IO ()+apply_patches opts ps = apply_patches_with_feedback opts "Applying patch" ps++\end{code}
+ src/Darcs/Repository/Checkpoint.lhs view
@@ -0,0 +1,181 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\chapter{Checkpoints}+\label{checkpoints}++There should be a discussion of checkpoints here.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Repository.Checkpoint ( get_checkpoint, get_checkpoint_by_default,+                                     identify_checkpoint,+                                     write_checkpoint, write_recorded_checkpoint,+                                     write_checkpoint_patch,+                                   ) where++import System.Directory ( setCurrentDirectory )+import Workaround ( getCurrentDirectory, createDirectoryIfMissing )+import System.IO.Unsafe ( unsafeInterleaveIO )+import Data.Maybe ( listToMaybe, catMaybes )+import Darcs.Hopefully ( hopefully, info )+import FastPackedString ( PackedString, nilPS, nullPS )++import Darcs.Lock ( withTempDir, writeDocBinFile )+import Darcs.SlurpDirectory ( Slurpy, empty_slurpy, mmap_slurp, )+import Darcs.Patch ( RepoPatch, Patch, Named, invertRL, patch2patchinfo,+                     apply_to_slurpy, patchcontents,+                     effect, fromPrims,+                     is_setpref, infopatch,+                     readPatch,+                     gzWritePatch+                   )+import Darcs.Patch.Ordered ( RL(..), FL(..),+                             unsafeFL, unsafeUnFL, (+>+),+                             mapRL, mapFL_FL, mapRL_RL, reverseRL, concatRL, concatFL )+import Darcs.Repository.Internal ( Repository(..), read_repo, slurp_recorded, withRecorded )+import Darcs.Repository.ApplyPatches ( apply_patches )+import Darcs.Patch.Info ( PatchInfo, make_filename, readPatchInfo,+                          showPatchInfo+                        )+import Darcs.Diff ( smart_diff )+import Darcs.External ( gzFetchFilePS, fetchFilePS, Cachable(..) )+import Darcs.Flags ( DarcsFlag(LookForAdds, Partial, Complete ) )+import Darcs.Patch.Depends ( get_patches_beyond_tag, get_patches_in_tag )+import Darcs.Repository.Prefs ( filetype_function )+import Darcs.Utils ( catchall )+import Darcs.FilePathUtils ( absolute_dir )+import Darcs.Global ( darcsdir )+import Printer ( Doc, ($$), empty )+#include "impossible.h"+import Darcs.Sealed ( Sealed(Sealed), FlippedSeal(..), unsafeUnseal, liftSM )+\end{code}++\begin{code}+read_patch_ids :: PackedString -> [PatchInfo]+read_patch_ids inv | nullPS inv = []+read_patch_ids inv = case readPatchInfo inv of+                     Just (pinfo,r) -> pinfo : read_patch_ids r+                     Nothing -> []+\end{code}++\begin{code}+read_checkpoints :: String -> IO [(PatchInfo, Maybe Slurpy)]+read_checkpoints d = do+  realdir <- absolute_dir d+  pistr <- fetchFilePS (realdir++"/"++darcsdir++"/checkpoints/inventory") Uncachable+           `catchall` return nilPS+  pis <- return $ reverse $ read_patch_ids pistr+  slurpies <- sequence $ map (fetch_checkpoint realdir) pis+  return $ zip pis slurpies+      where fetch_checkpoint r pinfo =+                unsafeInterleaveIO $ do+                pstr <- gzFetchFilePS+                    (r++"/"++darcsdir++"/checkpoints/"++make_filename pinfo) Cachable+                case fst `fmap` readPatch pstr of+                  Nothing -> return Nothing+                  Just (Sealed p) -> return $ apply_to_slurpy (p :: (Named Patch)) empty_slurpy++get_checkpoint :: RepoPatch p => Repository p -> IO (Maybe (Named p))+get_checkpoint repository@(Repo _ opts _ _) = if Partial `elem` opts+                                              then get_check_internal repository+                                              else return Nothing++get_checkpoint_by_default :: RepoPatch p => Repository p -> IO (Maybe (Named p))+get_checkpoint_by_default repository@(Repo _ opts _ _) = if Complete `elem` opts+                                                         then return Nothing+                                                         else get_check_internal repository++identify_checkpoint :: RepoPatch p => Repository p -> IO (Maybe PatchInfo)+identify_checkpoint repository@(Repo r _ _ _) = do+  pis <- (map info . catMaybes . mapRL lastRL) `liftSM` read_repo repository+  pistr <- fetchFilePS (r++"/"++darcsdir++"/checkpoints/inventory") Uncachable+           `catchall` return nilPS+  return $ listToMaybe $ filter (`elem` pis) $ reverse $ read_patch_ids pistr+    where lastRL = headFL . reverseRL+          headFL (x:>:_) = Just x+          headFL NilFL = Nothing++get_check_internal :: RepoPatch p => Repository p -> IO (Maybe (Named p))+get_check_internal repository@(Repo r _ _ _) = do+  mc <- identify_checkpoint repository+  case mc of+    Nothing -> return Nothing+    Just pinfo ->  (fmap unsafeUnseal . fmap fst . readPatch) `fmap`+                        gzFetchFilePS+                            (r++"/"++darcsdir++"/checkpoints/"++make_filename pinfo) Cachable++format_inv :: [PatchInfo] -> Doc+format_inv [] = empty+format_inv (pinfo:ps) = showPatchInfo pinfo+                     $$ format_inv ps++write_recorded_checkpoint :: RepoPatch p => Repository p -> PatchInfo -> IO ()+write_recorded_checkpoint r@(Repo _ _ _ _) pinfo = do+    ps <- (mapFL_FL hopefully.reverseRL.concatRL) `liftSM` read_repo r+    ftf <- filetype_function+    s <- slurp_recorded r+    write_checkpoint_patch $ infopatch pinfo+        (fromPrims $ changepps ps +>+ smart_diff [LookForAdds] ftf empty_slurpy s :: Patch)+    where changeps = unsafeFL . filter is_setpref .+                     unsafeUnFL . effect . patchcontents+          changepps = concatFL . mapFL_FL changeps++write_checkpoint :: RepoPatch p => Repository p -> PatchInfo -> IO ()+write_checkpoint repo@(Repo _ _ _ _) pinfo = do+    repodir <- getCurrentDirectory+    ps <- (reverseRL.mapRL_RL hopefully.concatRL.unsafeUnseal.get_patches_in_tag pinfo)+          `liftSM` read_repo repo+    ftf <- filetype_function+    with_tag repo pinfo $ do+      s <- mmap_slurp "."+      setCurrentDirectory repodir+      write_checkpoint_patch $ infopatch pinfo $+          (fromPrims $ changepps ps +>+ smart_diff [LookForAdds] ftf empty_slurpy s :: Patch)+    where changeps = unsafeFL . filter is_setpref .+                     unsafeUnFL . effect . patchcontents+          changepps = concatFL . mapFL_FL changeps++write_checkpoint_patch :: RepoPatch p => Named p -> IO ()+write_checkpoint_patch p =+ do createDirectoryIfMissing False (darcsdir++"/checkpoints")+    gzWritePatch (darcsdir++"/checkpoints/"++make_filename (patch2patchinfo p)) p+    cpi <- (map fst) `fmap` read_checkpoints "."+    writeDocBinFile (darcsdir++"/checkpoints/inventory")+        $ format_inv $ reverse $ patch2patchinfo p:cpi++with_tag :: RepoPatch p  => Repository p -> PatchInfo -> (IO ()) -> IO ()+with_tag r pinfo job = do+    Sealed ps <- read_repo r+    case get_patches_beyond_tag pinfo ps of+        FlippedSeal (extras :<: NilRL) -> withRecorded r (withTempDir "checkpoint") $ \_ -> do+                                            apply_patches [] $ invertRL extras+                                            job+        _ -> bug "with_tag"+\end{code}++The \verb!_darcs! directory also contains a directory called+``\verb!prefs!'', which is described in Chapter~\ref{configuring}.++\begin{comment}+\section{Getting interesting info on change history}++One can query the repository for the entire markup history of a file.  This+provides a data structure which contains a history of \emph{all} the+revisions ever made on a given file.++\end{comment}
+ src/Darcs/Repository/DarcsRepo.lhs view
@@ -0,0 +1,339 @@+%  Copyright (C) 2002-2005,2007-2008 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\chapter{DarcsRepo format}+\label{repository_format}++A repository consists of a working directory, which has within it a+directory called \verb!_darcs!. There must also be a subdirectory within+\verb!_darcs! named \verb!patches!.  The \verb!patches! directory contains+the actual patches which are in the repository.  There must also be a+\emph{pristine tree}, which may either be a directory containing a cache of+the version of the tree which has been recorded, or a stub, and may be+named either ``current'' or ``pristine''.++\emph{WARNING!} Viewing files in the pristine cache is perfectly+acceptable, but if you view them with an editor (e.g.\ vi or Emacs), that+editor may create temporary files in the pristine tree+(\verb|_darcs/pristine/| or \verb|_darcs/current/|), which will temporarily+cause your repository to be inconsistent.  So \emph{don't record any+patches while viewing files in \_darcs/current with an editor!}  A better+plan would be to restrict yourself to viewing these files with a pager such+as more or less.++Also within \verb!_darcs! is the \verb!inventory! file, which lists all the+patches that are in the repository. Moreover, it also gives the order of the+representation of the patches as they are stored. Given a source of patches,+i.e.\ any other set of repositories which have between them all the patches+contained in a given repository, that repository can be reproduced based on only the+information in the \verb!inventory! file. Under those circumstances, the+order of the patches specified in the \verb!inventory! file would be+unimportant, as this order is only needed to provide context for the+interpretation of the stored patches in this repository.++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Repository.DarcsRepo ( write_inventory, write_inventory_and_patches,+                                    add_to_inventory, add_to_tentative_pristine,+                                    add_to_tentative_inventory, remove_from_tentative_inventory,+                                    finalize_tentative_changes, finalize_pristine_changes,+                                    revert_tentative_changes,+                                    read_repo, write_and_read_patch,+                                    copy_patches+                                  ) where++import System.Directory ( doesDirectoryExist )+import Workaround ( renameFile, createDirectoryIfMissing )+import Darcs.Utils ( clarify_errors )+import Darcs.Progress ( debugMessage, beginTedious, endTedious, finishedOneIO )+import Darcs.FilePathUtils ( absolute_dir )+import System.IO ( hPutStrLn, stderr )+import System.IO.Unsafe ( unsafeInterleaveIO )+import Control.Monad ( liftM, when, unless )+import Darcs.Hopefully ( Hopefully, PatchInfoAnd,+                         patchInfoAndPatch, info,+                         actually, hopefully, unavailable, n2pia )+import Darcs.SignalHandler ( withSignalsBlocked )+import FastPackedString ( PackedString, packString, nilPS, gzReadFilePS,+                          readFilePS,+                          breakOnPS, nullPS )+import Darcs.SlurpDirectory ( Slurpy, empty_slurpy )+import Darcs.Patch ( RepoPatch, Effect, Prim, Named, Patch, invert,+                     effect,+                     patch2patchinfo,+                     apply_to_slurpy,+                     readPatch,+                     writePatch, gzWritePatch, showPatch )+import Darcs.Patch.Ordered ( FL(..), RL(..), (:<)(..),+                             reverseFL, mapFL, unsafeCoerceP,+                             reverseRL, concatRL, mapRL, mapRL_RL )+import Darcs.Patch.Info ( PatchInfo, make_filename, readPatchInfo,+                          showPatchInfo,+                 )+import Darcs.Patch.Set ( PatchSet, SealedPatchSet )+import Darcs.Patch.Depends ( is_tag )+import Darcs.External ( gzFetchFilePS, fetchFilePS, copyFilesOrUrls, Cachable(..),+                        cloneFile )+import Darcs.Lock ( writeBinFile, writeDocBinFile, appendDocBinFile, appendBinFile )+import Darcs.Flags ( DarcsFlag( NoCompress ) )+import Darcs.Patch.Depends ( slightly_optimize_patchset, commute_to_end, deep_optimize_patchset )+import Darcs.Repository.Pristine ( identifyPristine, applyPristine )+import Darcs.Global ( darcsdir )+import Darcs.Utils ( catchall )+import Darcs.Progress ( progressFL )+import Printer ( text, (<>), Doc, ($$), empty )+import Darcs.Sealed ( Sealed(Sealed), seal, unseal )+\end{code}++There is a very special patch which may be stored in \verb!patches! which+is called `pending'.  This patch describes any changes which have not yet+been recorded, and cannot be determined by a simple diff.  For example, file+additions or renames are placed in pending until they are recorded.+Similarly, token replaces are stored in pending until they are recorded.++\begin{code}+write_patch :: RepoPatch p => [DarcsFlag] -> Named p C(x y) -> IO FilePath+write_patch opts p =+       do let writeFun = if NoCompress `elem` opts+                         then writePatch+                         else gzWritePatch+              pname = darcsdir++"/patches/"++make_filename (patch2patchinfo p)+          writeFun pname p+          return pname++write_and_read_patch :: RepoPatch p => [DarcsFlag] -> PatchInfoAnd p C(x y)+                     -> IO (PatchInfoAnd p C(x y))+write_and_read_patch opts p = do fn <- write_patch opts $ hopefully p+                                 unsafeInterleaveIO $ parse fn+    where parse fn = do debugMessage ("Reading patch file: "++ fn)+                        ps <- gzReadFilePS fn+                        Sealed pp <- case readPatch ps of+                                    Just (x,_) -> return x+                                    Nothing -> fail ("Couldn't parse patch file "++fn)+                        return $ n2pia $ unsafeCoerceP pp++\end{code}++\begin{code}+--format_inventory is not exported for use outside of the DarcsRepo module+--itself.+format_inventory :: [PatchInfo] -> Doc+format_inventory [] = empty+format_inventory (pinfo:ps) = showPatchInfo pinfo $$ format_inventory ps++write_inventory :: RepoPatch p => FilePath -> PatchSet p C(x) -> IO ()+-- Note that write_inventory optimizes the inventory it writes out by+-- checking on tag dependencies.+-- FIXME: There is also a problem that write_inventory always writes+-- out the entire inventory, including the parts that you haven't+-- changed...+write_inventory dir ps = withSignalsBlocked $ do+    createDirectoryIfMissing False (dir++"/"++darcsdir++"/inventories")+    simply_write_inventory "inventory" dir $ slightly_optimize_patchset ps++simply_write_inventory :: RepoPatch p => String -> FilePath -> PatchSet p C(x) -> IO ()+simply_write_inventory name dir NilRL =+    writeBinFile (dir++"/"++darcsdir++"/"++name) ""+simply_write_inventory name dir (ps:<:NilRL) = do+    writeDocBinFile (dir++"/"++darcsdir++"/"++name) $ format_inventory $ mapFL info $ reverseRL ps+simply_write_inventory _ _ (NilRL:<:_) =+    fail $ "Bug in simply_write_inventory, please report!"+simply_write_inventory name dir (ps:<:pss) = do+    tagname <- return $ make_filename $ last $ mapRL info ps+    simply_write_inventory ("inventories/"++tagname) dir pss+    writeDocBinFile (dir++"/"++darcsdir++"/"++name) $ text "Starting with tag:"+                                           $$ format_inventory (mapFL info $ reverseRL ps)++write_inventory_and_patches :: RepoPatch p => [DarcsFlag] -> PatchSet p C(x) -> IO ()+write_inventory_and_patches opts ps = do write_inventory "." ps+                                         sequence_ $ mapRL (write_patch opts . hopefully) $ concatRL ps++add_to_inventory :: FilePath -> [PatchInfo] -> IO ()+add_to_inventory dir pinfos =+    appendDocBinFile (dir++"/"++darcsdir++"/inventory") $ text "\n" <> pidocs pinfos+    where+        pidocs [] = text ""+        pidocs (p:ps) = showPatchInfo p $$ pidocs ps++add_to_tentative_inventory :: forall p C(x y). RepoPatch p => [DarcsFlag] -> Named p C(x y) -> IO FilePath+add_to_tentative_inventory opts p =+    do appendDocBinFile (darcsdir++"/tentative_inventory") $ text "\n"+                            <> showPatchInfo (patch2patchinfo p)+       when (is_tag $ patch2patchinfo p) $+            do debugMessage "Optimizing the tentative inventory, since we're adding a tag."+               realdir <- absolute_dir "."+               let k = "Reading tentative inventory"+               beginTedious k+               Sealed ps <- read_repo_private k opts realdir "tentative_inventory"+                            :: IO  (SealedPatchSet p)+               simply_write_inventory "tentative_inventory" "." $ slightly_optimize_patchset ps+       write_patch opts p++add_to_tentative_pristine :: Effect p => p C(x y) -> IO ()+add_to_tentative_pristine p =+    do -- Sealed p <- (fst . fromJust . readPatchCarefully) `fmap` gzReadFilePS fp+       appendDocBinFile (darcsdir++"/tentative_pristine") $ showPatch (effect p) -- FIXME: this is inefficient!+       appendBinFile (darcsdir++"/tentative_pristine") "\n"++remove_from_tentative_inventory :: RepoPatch p => Bool -> [DarcsFlag] -> FL (Named p) C(x y) -> IO ()+remove_from_tentative_inventory update_pristine opts to_remove =+    do finalize_tentative_changes+       Sealed allpatches <- read_repo opts "."+       skipped :< unmodified <- return $ commute_to_end (unsafeCoerceP to_remove) allpatches+       sequence_ $ mapFL (write_patch opts) skipped+       write_inventory "." $ deep_optimize_patchset+                           $ mapRL_RL n2pia (reverseFL skipped) :<: unmodified+       remove_from_checkpoint_inventory to_remove+       when update_pristine $+            do pris <- identifyPristine+               repairable $ applyPristine pris+                              $ progressFL "Applying inverse to pristine" $ invert to_remove+       revert_tentative_changes++finalize_tentative_changes :: IO ()+finalize_tentative_changes = renameFile (darcsdir++"/tentative_inventory") (darcsdir++"/inventory")++finalize_pristine_changes :: IO ()+finalize_pristine_changes =+    do Sealed ps <- read_patches $ darcsdir++"/tentative_pristine"+       pris <- identifyPristine+       repairable $ applyPristine pris ps+    where +      read_patches :: String -> IO (Sealed (FL Prim C(x)))+      read_patches f = do ps <- readFilePS f+                          return $ case readPatch ps of+                                   Just (x, _) -> x+                                   Nothing -> seal $ NilFL++repairable :: IO a -> IO a+repairable x = x `clarify_errors` unlines+               ["Your repository is now in an inconsistent state.",+                "This must be fixed by running darcs repair."]++revert_tentative_changes :: IO ()+revert_tentative_changes =+    do cloneFile (darcsdir++"/inventory") (darcsdir++"/tentative_inventory")+       writeBinFile (darcsdir++"/tentative_pristine") ""+\end{code}++\begin{code}+copy_patches :: [DarcsFlag] -> FilePath -> FilePath -> [PatchInfo] -> IO ()+copy_patches opts dir out patches = do+  realdir <- absolute_dir dir+  copyFilesOrUrls opts (realdir++"/"++darcsdir++"/patches") (map make_filename patches)+                       (out++"/"++darcsdir++"/patches") Cachable++read_repo :: RepoPatch p => [DarcsFlag] -> String -> IO (SealedPatchSet p)+read_repo opts d = do+  realdir <- absolute_dir d+  let k = "Reading inventory of repository "++d+  beginTedious k+  read_repo_private k opts realdir "inventory" `catch`+                        (\e -> do hPutStrLn stderr ("Invalid repository:  " ++ realdir)+                                  ioError e)++read_repo_private :: RepoPatch p => String -> [DarcsFlag] -> FilePath -> FilePath -> IO (SealedPatchSet p)+read_repo_private k opts d iname = do+    i <- fetchFilePS (d++"/"++darcsdir++"/"++iname) Uncachable+    finishedOneIO k iname+    (rest,str) <- case breakOnPS '\n' i of+                  (swt,pistr) | swt == packString "Starting with tag:" ->+                    do r <- rr $ head $ read_patch_ids pistr+                       return (r,pistr)+                  _ -> do endTedious k+                          return (seal NilRL,i)+    pis <- return $ reverse $ read_patch_ids str+    isdir <- doesDirectoryExist d+    let parse f = let fn = d ++ "/"++darcsdir++"/patches/" ++ make_filename f+                  in if isdir then parse_local fn+                              else parse_remote fn+    lift2Sealed (:<:) (return rest) (read_patches parse pis)+    where rr pinfo = unsafeInterleaveIO $ read_repo_private k opts d $+                     "inventories/"++make_filename pinfo+          -- parse_remote should really download to a temporary file removed+          -- at exit+          parse_remote, parse_local :: RepoPatch p => String -> IO (Sealed (Hopefully (Named p) C(x)))+          parse_remote fn = do ps <- gzFetchFilePS fn Cachable+                               return $ hopefullyNoParseError fn (readPatch ps)+          parse_local fn = do ps <- gzReadFilePS fn+                              return $ hopefullyNoParseError fn (readPatch ps)+          hopefullyNoParseError :: String -> Maybe (Sealed (a C(x)), b) -> Sealed (Hopefully a C(x))+          hopefullyNoParseError _ (Just (Sealed x, _)) = seal $ actually x+          hopefullyNoParseError s Nothing = seal $ unavailable $ "Couldn't parse file "++s+          read_patches :: RepoPatch p => (FORALL(b) PatchInfo -> IO (Sealed (Hopefully (Named p) C(b))))+                       -> [PatchInfo] -> IO (Sealed (RL (PatchInfoAnd p) C(x)))+          read_patches _ [] = return $ seal NilRL+          read_patches parse (i:is) =+              lift2Sealed (\p rest -> i `patchInfoAndPatch` p :<: rest)+                          (read_patches parse is)+                          (parse i `catch` \e -> return $ seal $ unavailable $ show e)+          lift2Sealed :: (FORALL(y z) q C(y z) -> p C(x y) -> r C(x z))+                      -> IO (Sealed (p C(x))) -> (FORALL(b) IO (Sealed (q C(b)))) -> IO (Sealed (r C(x)))+          lift2Sealed f iox ioy = do Sealed x <- unseal seal `fmap` unsafeInterleaveIO iox+                                     Sealed y <- unseal seal `fmap` unsafeInterleaveIO ioy+                                     return $ seal $ f y x++read_patch_ids :: PackedString -> [PatchInfo]+read_patch_ids inv | nullPS inv = []+read_patch_ids inv = case readPatchInfo inv of+                     Just (pinfo,r) -> pinfo : read_patch_ids r+                     Nothing -> []+\end{code}++\begin{code}+read_checkpoints :: String -> IO [(PatchInfo, Maybe Slurpy)]+read_checkpoints d = do+  realdir <- absolute_dir d+  pistr <- fetchFilePS (realdir++"/"++darcsdir++"/checkpoints/inventory") Uncachable+           `catchall` return nilPS+  pis <- return $ reverse $ read_patch_ids pistr+  slurpies <- sequence $ map (fetch_checkpoint realdir) pis+  return $ zip pis slurpies+      where fetch_checkpoint r pinfo =+                unsafeInterleaveIO $ do+                pstr <- gzFetchFilePS+                    (r++"/"++darcsdir++"/checkpoints/"++make_filename pinfo) Cachable+                case fst `liftM` readPatch_ pstr of+                  Nothing -> return Nothing+                  Just (Sealed p) -> return $ apply_to_slurpy p empty_slurpy+            readPatch_ :: PackedString -> Maybe (Sealed (Named Patch C(x)), PackedString)+            readPatch_ = readPatch++remove_from_checkpoint_inventory :: RepoPatch p => FL (Named p) C(x y) -> IO ()+remove_from_checkpoint_inventory ps = do+    -- only tags can be checkpoints+    let pinfos = filter is_tag $ mapFL patch2patchinfo ps+    unless (null pinfos) $ do+        createDirectoryIfMissing False (darcsdir++"/checkpoints")+        cpi <- (map fst) `liftM` read_checkpoints "."+        writeDocBinFile (darcsdir++"/checkpoints/inventory") $+            format_inventory $ reverse $ filter (`notElem` pinfos) cpi+\end{code}++The \verb!_darcs! directory also contains a directory called+``\verb!prefs!'', which is described in Chapter~\ref{configuring}.++\begin{comment}+\section{Getting interesting info on change history}++One can query the repository for the entire markup history of a file.  This+provides a data structure which contains a history of \emph{all} the+revisions ever made on a given file.++\end{comment}+
+ src/Darcs/Repository/Format.lhs view
@@ -0,0 +1,132 @@+%  Copyright (C) 2005 David Roundy+%+%  This file is licensed under the GPL, version two or later.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Repository.Format ( RepoFormat(..), RepoProperty(..), identifyRepoFormat,+                    create_repo_format, writeRepoFormat,+                    write_problem, read_problem, readfrom_and_writeto_problem,+                    format_has, format_has_together,+                  ) where++import Data.List ( sort, intersperse )+import Data.Maybe ( isJust, catMaybes )+import Control.Monad ( msum )++import Darcs.SignalHandler ( catchNonSignal )+import Darcs.External ( fetchFilePS, Cachable( Cachable ) )+import FastPackedString ( PackedString, packString, nilPS, unpackPS,+                          nullPS, linesPS, splitPS, findPS )+import Darcs.Flags ( DarcsFlag ( UseFormat2, UseHashedInventory ) )+import Darcs.Lock ( writeBinFile )+import Darcs.Utils ( catchall, prettyException )+import Darcs.Progress ( beginTedious, endTedious, finishedOneIO )+import Darcs.Global ( darcsdir )+#include "impossible.h"++data RepoProperty = Darcs1_0 | Darcs2 | HashedInventory+newtype RepoFormat = RF [[PackedString]] deriving ( Show )+\end{code}++\begin{code}+df :: FilePath+df = darcsdir++"/format"++identifyRepoFormat :: String -> IO (Either String RepoFormat)+identifyRepoFormat repo =+ do let k = "Identifying repository "++repo+    beginTedious k+    finishedOneIO k "format"+    dff <- fetchFilePS (repo ++ "/" ++ df) Cachable `catchall` return nilPS+    -- below is a workaround for servers that don't return a 404 on nonexistent files+    rf <- if nullPS dff || isJust (findPS '<' dff)+          then do finishedOneIO k "inventory"+                  have_inventory <- doesRemoteFileExist (repo++"/"++darcsdir++"/inventory")+                  case have_inventory of+                    Right _ -> return $ Right default_repo_format+                    Left e -> return $ Left $ "Not a repository: "++repo++" ("++e++")"+          else return $ Right $ parse_repo_format dff+    endTedious k+    return rf+    where drfe x = fetchFilePS x Cachable >> return True+          doesRemoteFileExist x = (fmap Right) (drfe x) `catchNonSignal`+                                  (\e -> return (Left (prettyException e)))+++writeRepoFormat :: RepoFormat -> FilePath -> IO ()+writeRepoFormat (RF rf) loc = writeBinFile loc $ unlines $+                              map (concat . intersperse "|" . map unpackPS) rf++parse_repo_format :: PackedString -> RepoFormat+parse_repo_format ps =+    RF $ map (splitPS '|') $ filter (not.nullPS) $ linesPS ps++default_repo_format :: RepoFormat+default_repo_format = RF [[rp2ps Darcs1_0]]++create_repo_format :: [DarcsFlag] -> RepoFormat+create_repo_format fs = RF ([map rp2ps flags2inv] ++ maybe2)+    where flags2inv | UseFormat2 `elem` fs || UseHashedInventory `elem` fs = [HashedInventory]+                    | otherwise = [Darcs1_0]+          maybe2 = if UseFormat2 `elem` fs then [[rp2ps Darcs2]] else []++\end{code}++\begin{code}+-- Nothing means we can write+write_problem :: RepoFormat -> Maybe String+write_problem rf | isJust $ read_problem rf = read_problem rf+write_problem (RF ks) = unlines `fmap` justsOrNothing (map wp ks)+    where wp x | all is_known x = Nothing+          wp [] = impossible+          wp x = Just $ unwords $ "Can't write repository format: " :+                 map unpackPS (filter (not . is_known) x)++readfrom_and_writeto_problem :: RepoFormat -> RepoFormat -> Maybe String+readfrom_and_writeto_problem inrf outrf+    | format_has Darcs2 inrf /= format_has Darcs2 outrf+        = Just "Cannot mix darcs-2 repositories with older formats" +    | otherwise = msum [read_problem inrf, write_problem outrf]+\end{code}++\begin{code}+read_problem :: RepoFormat -> Maybe String+read_problem rf | format_has Darcs1_0 rf && format_has Darcs2 rf+                    = Just "Invalid repositoryformat:  format 2 is incompatible with format 1"+read_problem (RF ks) = unlines `fmap` justsOrNothing (map rp ks)+    where rp x | any is_known x = Nothing+          rp [] = impossible+          rp x = Just $ unwords $+                 "Can't understand repository format:" : map unpackPS x++is_known :: PackedString -> Bool+is_known p = p `elem` map rp2ps known_properties++known_properties :: [RepoProperty]+known_properties = [Darcs1_0, Darcs2, HashedInventory]++justsOrNothing :: [Maybe x] -> Maybe [x]+justsOrNothing mxs =+ case catMaybes mxs of+   [] -> Nothing+   xs -> Just xs+\end{code}++\begin{code}+format_has :: RepoProperty -> RepoFormat -> Bool+format_has f (RF ks) = rp2ps f `elem` concat ks++format_has_together :: [RepoProperty] -> RepoFormat -> Bool+format_has_together fs (RF ks) = fht (sort $ map rp2ps fs) ks+    where fht _ [] = False+          fht x (y:ys) | x == sort y = True+                       | otherwise = fht x ys+\end{code}++\begin{code}+rp2ps :: RepoProperty -> PackedString+rp2ps Darcs1_0 = packString "darcs-1.0"+rp2ps Darcs2 = packString "darcs-2"+rp2ps HashedInventory = packString "hashed"+\end{code}
+ src/Darcs/Repository/HashedIO.lhs view
@@ -0,0 +1,378 @@+%  Copyright (C) 2007 David Roundy+%+%  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, 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.++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Repository.HashedIO ( HashedIO, applyHashed,+                                   copyHashed, syncHashed, copyPartialsHashed, listHashedContents,+                                   slurpHashed, hashSlurped ) where++import System.Posix.Types ( EpochTime )+import Control.Monad.State ( StateT, runStateT, modify, get, put, gets, lift )+import Control.Monad ( when )+import Data.Maybe ( isJust )+import System.IO.Unsafe ( unsafeInterleaveIO )++import Workaround ( createDirectoryIfMissing )+import Darcs.SlurpDirectory ( Slurpy(..), withSlurpy, undefined_time, undefined_size )+import Darcs.Repository.Prefs ( Cache, fetchFileUsingCache, writeFileUsingCache,+                                peekInCache, speculateFileUsingCache,+                                findFileMtimeUsingCache, setFileMtimeUsingCache )+import Darcs.Patch ( Patchy, apply )+import Darcs.IO ( ReadableDirectory(..), WriteableDirectory(..) )+import Darcs.Flags ( DarcsFlag )+import Darcs.Lock ( writeAtomicFilePS )+import Darcs.Utils ( withCurrentDirectory )+import Darcs.Progress ( debugMessage, beginTedious, endTedious, tediousSize, finishedOneIO, progress )+import FileName ( FileName, norm_path, fp2fn, fn2fp, fn2niceps, niceps2fn,+                  break_on_dir, own_name, super_name )+import FastPackedString ( PackedString, packString, unpackPS, linesPS, unlinesPS, nilPS, lengthPS )+import SHA1 ( sha1PS )++readHashFile :: Cache -> String -> String -> IO (String,PackedString)+readHashFile c subdir hash =+    do debugMessage $ "Reading hash file "++hash++" from "++subdir++"/"+       fetchFileUsingCache c subdir hash++applyHashed :: Patchy q => Cache -> [DarcsFlag] -> String -> q C(x y) -> IO String+applyHashed c fs h p = do s <- slurpHashed c fs h+                          let ms = withSlurpy s $ apply fs p+                          case ms of+                            Left e -> fail e+                            Right (s', ()) -> hashSlurped c fs s'+{-+applyHashed c fs h p = do (_,hd) <- runStateT (apply fs p) $+                                    HashDir { permissions = RW, cache = c,+                                              options = fs, rootHash = h }+                          return $ rootHash hd+-}++data HashDir r p = HashDir { permissions :: !r, cache :: !Cache,+                             options :: ![DarcsFlag], rootHash :: !String }+type HashedIO r p = StateT (HashDir r p) IO++data RO = RO+data RW = RW+{-+class Readable r where+    isRO :: r -> Bool+    isRO = const False+instance Readable RW+instance Readable RO where+    isRO RO = True+-}++instance ReadableDirectory (HashedIO r p) where+    mDoesDirectoryExist fn = do thing <- identifyThing fn+                                case thing of Just (D,_) -> return True+                                              _ -> return False+    mDoesFileExist fn = do thing <- identifyThing fn+                           case thing of Just (F,_) -> return True+                                         _ -> return False+    mInCurrentDirectory fn j | fn' == fp2fn "" = j+                             | otherwise =+                                 case break_on_dir fn' of+                                 Nothing -> do c <- readroot+                                               case geta D fn' c of+                                                 Nothing -> fail "dir doesn't exist mInCurrentDirectory..."+                                                 Just h -> inh h j+                                 Just (d,fn'') -> do c <- readroot+                                                     case geta D d c of+                                                       Nothing -> fail "dir doesn't exist..."+                                                       Just h -> inh h $ mInCurrentDirectory fn'' j+        where fn' = norm_path fn+    mGetDirectoryContents = map (\ (_,f,_) -> f) `fmap` readroot+    mReadFilePS fn = mInCurrentDirectory (super_name fn) $ do+                                          c <- readroot+                                          case geta F (own_name fn) c of+                                            Nothing -> fail $ " file don't exist... "++ fn2fp fn+                                            Just h -> readhash h++instance WriteableDirectory (HashedIO RW p) where+    mWithCurrentDirectory fn j+        | fn' == fp2fn "" = j+        | otherwise =+            case break_on_dir fn' of+            Nothing -> do c <- readroot+                          case geta D fn' c of+                            Nothing -> fail "dir doesn't exist in mWithCurrentDirectory..."+                            Just h -> do (h',x) <- withh h j+                                         writeroot $ seta D fn' h' c+                                         return x+            Just (d,fn'') -> do c <- readroot+                                case geta D d c of+                                  Nothing -> fail "dir doesn't exist..."+                                  Just h -> do (h',x) <- withh h $ mWithCurrentDirectory fn'' j+                                               writeroot $ seta D d h' c+                                               return x+        where fn' = norm_path fn+    mSetFileExecutable _ _ = return ()+    mWriteFilePS fn ps = do mexists <- identifyThing fn+                            case mexists of+                              Just (D,_) -> fail "can't write file over directory"+                              _ -> do h <- writeHashFile ps+                                      makeThing fn (F,h)+    mCreateDirectory fn = do h <- writeHashFile nilPS+                             exists <- isJust `fmap` identifyThing fn+                             when exists $ fail "can't mCreateDirectory over an existing object."+                             makeThing fn (D,h)+    mRename o n = do nexists <- isJust `fmap` identifyThing n+                     when nexists $ fail "mRename failed..."+                     mx <- identifyThing o+                     -- for backwards compatibility accept rename of nonexistent files.+                     case mx of Nothing -> return ()+                                Just x -> do rmThing o+                                             makeThing n x+    mRemoveDirectory = rmThing+    mRemoveFile f = do x <- mReadFilePS f+                       when (lengthPS x /= 0) $+                            fail $ "Cannot remove non-empty file "++fn2fp f+                       rmThing f++identifyThing :: FileName -> HashedIO r p (Maybe (ObjType,String))+identifyThing fn | fn' == fp2fn "" = do h <- gets rootHash+                                        return $ Just (D, h)+                 | otherwise = case break_on_dir fn' of+                               Nothing -> getany fn' `fmap` readroot+                               Just (d,fn'') -> do c <- readroot+                                                   case geta D d c of+                                                     Nothing -> return Nothing+                                                     Just h -> inh h $ identifyThing fn''+        where fn' = norm_path fn++makeThing :: FileName -> (ObjType,String) -> HashedIO RW p ()+makeThing fn (o,h) = mWithCurrentDirectory (super_name $ norm_path fn) $+                     seta o (own_name $ norm_path fn) h `fmap` readroot >>= writeroot++rmThing :: FileName -> HashedIO RW p ()+rmThing fn = mWithCurrentDirectory (super_name $ norm_path fn) $+             do c <- readroot+                let c' = filter (\(_,x,_)->x/= own_name (norm_path fn)) c+                if length c' == length c - 1+                  then writeroot c'+                  else fail "obj doesn't exist in rmThing"++readhash :: String -> HashedIO r p PackedString+readhash h = do c <- gets cache+                z <- lift $ unsafeInterleaveIO $ readHashFile c "pristine.hashed" h+                let (_,out) = z+                return out++readTediousHash :: String -> String -> HashedIO r p PackedString+readTediousHash k h = do lift $ finishedOneIO k h+                         readhash h++gethashmtime :: String -> HashedIO r p EpochTime+gethashmtime h = do HashDir _ c _ _ <- get+                    lift $ unsafeInterleaveIO $ findFileMtimeUsingCache c "pristine.hashed" h++withh :: String -> HashedIO RW p a -> HashedIO RW p (String,a)+withh h j = do hd <- get+               put $ hd { rootHash = h }+               x <- j+               h' <- gets rootHash+               put hd+               return (h',x)++inh :: String -> HashedIO r p a -> HashedIO r p a+inh h j = do hd <- get+             put $ hd { rootHash = h }+             x <- j+             put hd+             return x++safeInterleave :: HashedIO RO p a -> HashedIO r p a+safeInterleave job = do HashDir _ c opts h <- get+                        z <- lift $ unsafeInterleaveIO $ runStateT job+                             (HashDir { permissions = RO, cache = c, options = opts, rootHash = h })+                        let (x,_) = z+                        return x++readroot :: HashedIO r p [(ObjType, FileName, String)]+readroot = do haveitalready <- peekroot+              cc <- gets rootHash >>= readdir+              when (not haveitalready) $ speculate cc+              return cc+    where speculate :: [(a,b,String)] -> HashedIO r q ()+          speculate c = do cac <- gets cache+                           mapM_ (\(_,_,z) -> lift $ speculateFileUsingCache cac "pristine.hashed" z) c+          peekroot :: HashedIO r p Bool+          peekroot = do HashDir _ c _ h <- get+                        lift $ peekInCache c "pristine.hashed" h++writeroot :: [(ObjType, FileName, String)] -> HashedIO r p ()+writeroot c = do h <- writedir c+                 modify $ \hd -> hd { rootHash = h }++data ObjType = F | D deriving Eq++geta :: ObjType -> FileName -> [(ObjType, FileName, String)] -> Maybe String+geta o f c = do (o',h) <- getany f c+                if o == o' then Just h else Nothing++getany :: FileName -> [(ObjType, FileName, String)] -> Maybe (ObjType,String)+getany _ [] = Nothing+getany f ((o,f',h):_) | f == f' = Just (o,h)+getany f (_:r) = getany f r++seta :: ObjType -> FileName -> String -> [(ObjType, FileName, String)] -> [(ObjType, FileName, String)]+seta o f h [] = [(o,f,h)]+seta o f h ((_,f',_):r) | f == f' = (o,f,h):r+seta o f h (x:xs) = x : seta o f h xs++readdir :: String -> HashedIO r p [(ObjType, FileName, String)]+readdir hash = (parsed . linesPS) `fmap` readhash hash+    where parsed (t:n:h:rest) | t == dir = (D, niceps2fn n, unpackPS h) : parsed rest+                              | t == file = (F, niceps2fn n, unpackPS h) : parsed rest+          parsed _ = []+dir :: PackedString+dir = packString "directory:"+file :: PackedString+file = packString "file:"+++writedir :: [(ObjType, FileName, String)] -> HashedIO r p String+writedir c = writeHashFile cps+    where cps = unlinesPS $ concatMap (\ (o,d,h) -> [showO o,fn2niceps d,packString h]) c++[nilPS]+          showO D = dir+          showO F = file++writeHashFile :: PackedString -> HashedIO r p String+writeHashFile ps = do c <- gets cache+                      opts <- gets options+                      lift $ writeFileUsingCache c opts "pristine.hashed" ps++slurpHashed :: Cache -> [DarcsFlag] -> String -> IO Slurpy+slurpHashed c opts h = fst `fmap` runStateT slh+                                  (HashDir { permissions = RO, cache = c,+                                             options = opts, rootHash = h })++slh :: HashedIO r p Slurpy+slh = do c <- readroot+         hroot <- gets rootHash+         lift $ beginTedious k+         safeInterleave $ SlurpDir rootdir (Just hroot) `fmap` mapM sl c+    where sl (F,n,h) = do ps <- safeInterleave $ readTediousHash k h+                          t <- gethashmtime h+                          let len = if length h == 75 then read (take 10 h)+                                                      else undefined_size+                          return $ SlurpFile n (Just h, t, len) ps+          sl (D,n,h) = inh h $ do c <- readroot+                                  lift $ tediousSize k (length c)+                                  lift $ finishedOneIO k h+                                  SlurpDir n (Just h) `fmap` mapM sl c+          k = "Reading pristine"++rootdir :: FileName+rootdir = fp2fn "."++hashSlurped :: Cache -> [DarcsFlag] -> Slurpy -> IO String+hashSlurped c opts sl = do beginTedious k+                           h <- fst `fmap` runStateT (hsl sl)+                                        (HashDir { permissions = RW, cache = c,+                                                   options = opts, rootHash = sha1PS nilPS })+                           endTedious k+                           return h+    where hsl (SlurpDir _ (Just h) _) = return h+          hsl (SlurpDir _ Nothing ss) = do lift $ tediousSize k (length ss)+                                           mapM hs ss >>= writedir+          hsl (SlurpFile _ (Just h,_,_) _) = return h+          hsl (SlurpFile _ _ x) = writeHashFile x+          hs (SlurpDir d (Just h) _) = progress k $ return (D, d, h)+          hs s@(SlurpDir d Nothing _) = do h <- hsl s+                                           lift $ finishedOneIO k h+                                           return (D, d, h)+          hs (SlurpFile f (Just h,_,_) _) = progress k $ return (F, f, h)+          hs s@(SlurpFile f _ _) = do h <- hsl s+                                      lift $ finishedOneIO k h+                                      return (F, f, h)+          k = "Writing pristine"++grab :: FileName -> Slurpy -> Maybe Slurpy+grab _ (SlurpFile _ _ _) = Nothing+grab fn (SlurpDir _ _ ss) = g ss where g [] = Nothing+                                       g (s@(SlurpDir fn' _ _):_) | fn' == fn = Just s+                                       g (s@(SlurpFile fn' _ _):_) | fn' == fn = Just s+                                       g (_:x) = g x++syncHashed :: Cache -> Slurpy -> String -> IO ()+syncHashed c s r = do runStateT sh $ HashDir {permissions=RW, cache=c, options=[], rootHash=r}+                      return ()+    where sh = do cc <- readroot+                  lift $ tediousSize k (length cc)+                  mapM_ sh' cc+          sh' (D,n,h) = case progress k $ grab n s of+                        Just s' -> lift $ syncHashed c s' h+                        Nothing -> return ()+          sh' (F,n,h) = case progress k $ grab n s of+                        Just (SlurpFile _ (_,t',l) x) ->+                            do t <- lift $ findFileMtimeUsingCache c "pristine.hashed" h+                               when (t' /= undefined_time && t' /= t) $+                                    do ps <- readhash h+                                       when (lengthPS ps == fromIntegral l && ps == x) $+                                            lift $ setFileMtimeUsingCache c "pristine.hashed" h t'+                        _ -> return ()+          k = "Synchronizing pristine"++copyHashed :: String -> Cache -> [DarcsFlag] -> String -> IO ()+copyHashed k c opts z = do runStateT cph $ HashDir { permissions = RO, cache = c,+                                                     options = opts, rootHash = z }+                           return ()+    where cph = do cc <- readroot+                   lift $ tediousSize k (length cc)+                   mapM_ cp cc+          cp (F,n,h) = do ps <- readhash h+                          lift $ finishedOneIO k (fn2fp n)+                          lift $ writeAtomicFilePS (fn2fp n) ps+          cp (D,n,h) = do lift $ createDirectoryIfMissing False (fn2fp n)+                          lift $ finishedOneIO k (fn2fp n)+                          lift $ withCurrentDirectory (fn2fp n) $ copyHashed k c opts h++copyPartialsHashed :: Cache -> [DarcsFlag] -> String -> [FilePath] -> IO ()+copyPartialsHashed c opts root = mapM_ (copyPartialHashed c opts root)++copyPartialHashed :: Cache -> [DarcsFlag] -> String -> FilePath -> IO ()+copyPartialHashed c opts root ff =+    do createDirectoryIfMissing True (basename ff)+       runStateT (cp $ fp2fn ff) $ HashDir { permissions = RO, cache = c,+                                             options=opts, rootHash = root }+       return ()+ where basename = reverse . dropWhile ('/' /=) . dropWhile ('/' ==) . reverse+       cp f = do mt <- identifyThing f+                 case mt of+                   Just (D,h) -> do lift $ createDirectoryIfMissing True (fn2fp f)+                                    lift $ withCurrentDirectory (fn2fp f) $ copyHashed "" c opts h+                   Just (F,h) -> do ps <- readhash h+                                    lift $ writeAtomicFilePS (fn2fp f) ps+                   Nothing -> return ()++listHashedContents :: String -> Cache -> [DarcsFlag] -> String -> IO [String]+listHashedContents k c opts root =+    do beginTedious k+       tediousSize k 1+       x <- fst `fmap` runStateT (lhc (D,fp2fn ".",root)) (HashDir RO c opts root)+       endTedious k+       return x+    where lhc :: (ObjType, FileName, String) -> HashedIO r a [String]+          lhc (D,dname,d) = do xs <- inh d $ readroot+                               lift $ finishedOneIO k (fn2fp dname)+                               lift $ tediousSize k (length $ filter (\(x,_,_) -> x == D) xs)+                               hcxs <- mapM lhc xs+                               return (d:concat hcxs)+          lhc (F,_,h) = return [h]++\end{code}
+ src/Darcs/Repository/HashedRepo.lhs view
@@ -0,0 +1,395 @@+%  Copyright (C) 2006-2007 David Roundy+%+%  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, 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.+\chapter{Hashed inventory format}+\label{hashed_format}++The hashed inventory format is similar to the ``DarcsRepo'' format (see+Chapter~\ref{repository_format}), but I haven't gotten around to+documenting it.++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Repository.HashedRepo ( revert_tentative_changes, finalize_tentative_changes,+                                     slurp_pristine, sync_repo, clean_pristine,+                                     copy_pristine, copy_partials_pristine, pristine_from_working,+                                     apply_to_tentative_pristine, replacePristine,+                                     add_to_tentative_inventory, remove_from_tentative_inventory,+                                     read_repo, write_and_read_patch,+                                     write_tentative_inventory, copy_repo, slurp_all_but_darcs+                                   ) where++import System.Directory ( getDirectoryContents, doesFileExist )+import System.IO.Unsafe ( unsafeInterleaveIO )+import System.IO ( stderr, hPutStrLn )+import Data.List ( delete, (\\) )+import Control.Monad ( unless )++import Workaround ( renameFile, createDirectoryIfMissing )+import Darcs.Flags ( DarcsFlag )+import Darcs.Patch.Set ( PatchSet, SealedPatchSet )+import Darcs.FilePathUtils ( absolute_dir )+import Darcs.Repository.Prefs ( Cache, fetchFileUsingCache, speculateFileUsingCache, writeFileUsingCache,+                                unionCaches, cleanCaches, repo2cache, okayHash, takeHash )+import Darcs.Repository.HashedIO ( applyHashed, slurpHashed, hashSlurped, listHashedContents,+                                   copyHashed, syncHashed, copyPartialsHashed )+import Darcs.Repository.InternalTypes ( Repository(..), extractCache )+import Darcs.Hopefully ( PatchInfoAnd, patchInfoAndPatch, n2pia, info,+                         extractHash, createHashed )+import Darcs.SlurpDirectory ( Slurpy, empty_slurpy, slurp_remove, slurp )+import Darcs.Patch ( RepoPatch, Patchy, Named, showPatch, patch2patchinfo, readPatch )+import Darcs.Patch.Depends ( commute_to_end, slightly_optimize_patchset )+import Darcs.Patch.Info ( PatchInfo, showPatchInfo, human_friendly, readPatchInfo )+import Darcs.Patch.Ordered ( unsafeCoerceP, (:<)(..) )+import FileName ( fp2fn )+import FastPackedString ( PackedString, nilPS, nullPS, readFilePS,+                          gzReadFilePS, takePS, dropPS, dropWhilePS,+                          tailPS, lengthPS,+                          packString, breakOnPS, unpackPS, dropWhitePS )+import Printer ( Doc, hcat, (<>), ($$), renderString, renderPS, text, invisiblePS )+import SHA1 ( sha1PS )+import Darcs.External ( copyFileOrUrl, cloneFile, fetchFilePS, Cachable( Uncachable ) )+import Darcs.Lock ( writeBinFile, writeDocBinFile, writeAtomicFilePS, appendBinFile, appendDocBinFile,+                    removeFileMayNotExist )+import Darcs.Utils ( withCurrentDirectory )+import Darcs.Progress ( beginTedious, tediousSize, endTedious, debugMessage, finishedOneIO )+#include "impossible.h"+import Darcs.Patch.Ordered ( FL(..), RL(..),+                             mapRL, mapFL, lengthRL )+import Darcs.Sealed ( Sealed(..), seal, unseal )+import Darcs.Global ( darcsdir )++revert_tentative_changes :: IO ()+revert_tentative_changes =+    do cloneFile (darcsdir++"/hashed_inventory") (darcsdir++"/tentative_hashed_inventory")+       i <- gzReadFilePS (darcsdir++"/hashed_inventory")+       writeBinFile (darcsdir++"/tentative_pristine") $ "pristine:" ++ inv2pris i++finalize_tentative_changes :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> IO ()+finalize_tentative_changes r opts =+    do let t = darcsdir++"/tentative_hashed_inventory"+       -- first let's optimize it...+       debugMessage "Optimizing the inventory..."+       ps <- read_tentative_repo r opts "."+       write_tentative_inventory (extractCache r) opts ps+       -- then we'll add in the pristine cache,+       i <- gzReadFilePS t+       p <- gzReadFilePS $ darcsdir++"/tentative_pristine"+       writeDocBinFile t $ pris2inv (inv2pris p) i+       -- and rename it to its final value+       renameFile t $ darcsdir++"/hashed_inventory"+       -- note: in general we can't clean the pristine cache, because a+       -- simultaneous get might be in progress++clean_pristine :: Repository p C(r u t) -> IO ()+clean_pristine r@(Repo d opts _ _) = withCurrentDirectory d $+   do -- we'll remove obsolete bits of our pristine cache+      debugMessage "Cleaning out the pristine cache..."+      i <- gzReadFilePS (darcsdir++"/hashed_inventory")+      hs <- listHashedContents "Cleaning pristine cache" (extractCache r) opts $ inv2pris i+      let hashdir = darcsdir++"/pristine.hashed/"+      fs <- filter okayHash `fmap` getDirectoryContents hashdir+      mapM_ (removeFileMayNotExist . (hashdir++)) (fs \\ hs)+      -- and also clean out any global caches.+      debugMessage "Cleaning out any global caches..."+      cleanCaches (extractCache r) "pristine.hashed"++add_to_tentative_inventory :: RepoPatch p => Cache -> [DarcsFlag] -> PatchInfoAnd p C(x y) -> IO FilePath+add_to_tentative_inventory c opts p =+    do hash <- snd `fmap` write_patch_if_necesary c opts p+       appendDocBinFile (darcsdir++"/tentative_hashed_inventory") $ showPatchInfo $ info p+       appendBinFile (darcsdir++"/tentative_hashed_inventory") $ "\nhash: " ++ hash ++ "\n"+       return $ darcsdir++"/patches/" ++ hash++remove_from_tentative_inventory :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag]+                                -> FL (Named p) C(x t) -> IO ()+remove_from_tentative_inventory repo opts to_remove =+       -- FIXME: This algorithm should be *far* simpler.  All we need do is+       -- to to remove the patches from a patchset and then write that+       -- patchset.  The commutation behavior of PatchInfoAnd should track+       -- which patches need to be rewritten for us.+    do allpatches <- read_tentative_repo repo opts "."+       skipped :< _ <- return $ commute_to_end to_remove allpatches+       okay <- simple_remove_from_tentative_inventory repo opts+               (mapFL patch2patchinfo to_remove ++ mapFL patch2patchinfo skipped)+       unless okay $ bug "bug in HashedRepo.remove_from_tentative_inventory"+       sequence_ $ mapFL (add_to_tentative_inventory (extractCache repo) opts . n2pia) skipped++simple_remove_from_tentative_inventory :: forall p C(r u t). RepoPatch p =>+                                          Repository p C(r u t) -> [DarcsFlag] -> [PatchInfo] -> IO Bool+simple_remove_from_tentative_inventory repo opts pis = do+    inv <- read_tentative_repo repo opts "."+    case cut_inv pis inv of+      Nothing -> return False+      Just (Sealed inv') -> do write_tentative_inventory (extractCache repo) opts inv'+                               return True+    where cut_inv :: [PatchInfo] -> PatchSet p C(x) -> Maybe (SealedPatchSet p)+          cut_inv [] x = Just $ seal x+          cut_inv x (NilRL:<:rs) = cut_inv x rs+          cut_inv xs ((hp:<:r):<:rs) | info hp `elem` xs = cut_inv (info hp `delete` xs) (r:<:rs)+          cut_inv _ _ = Nothing++writeHashFile :: Cache -> [DarcsFlag] -> String -> Doc -> IO String+writeHashFile c opts subdir d = do debugMessage $ "Writing hash file to "++subdir+                                   writeFileUsingCache c opts subdir $ renderPS d++read_repo :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> String -> IO (PatchSet p C(r))+read_repo repo opts d = do+  realdir <- absolute_dir d+  Sealed ps <- read_repo_private repo opts realdir "hashed_inventory" `catch`+                 (\e -> do hPutStrLn stderr ("Invalid repository:  " ++ realdir)+                           ioError e)+  return $ unsafeCoerceP ps++read_tentative_repo :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> String -> IO (PatchSet p C(t))+read_tentative_repo repo opts d = do+  realdir <- absolute_dir d+  Sealed ps <- read_repo_private repo opts realdir "tentative_hashed_inventory" `catch`+                 (\e -> do hPutStrLn stderr ("Invalid repository:  " ++ realdir)+                           ioError e)+  return $ unsafeCoerceP ps++read_repo_private :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag]+                  -> FilePath -> FilePath -> IO (SealedPatchSet p)+read_repo_private repo opts d iname =+ do inventories <- read_inventory_private repo opts (d++"/"++darcsdir) iname+    parseinvs inventories+    where read_patches :: RepoPatch p => [(PatchInfo, String)] -> IO (Sealed (RL (PatchInfoAnd p) C(x)))+          read_patches [] = return $ seal NilRL+          read_patches allis@((i1,h1):is1) =+              lift2Sealed (\p rest -> i1 `patchInfoAndPatch` p :<: rest)+                          (rp is1)+                          (createHashed h1 (const $ speculate h1 allis >> parse i1 h1))+              where rp :: RepoPatch p => [(PatchInfo, String)] -> IO (Sealed (RL (PatchInfoAnd p) C(x)))+                    rp [] = return $ seal NilRL+                    rp [(i,h),(il,hl)] =+                        lift2Sealed (\p rest -> i `patchInfoAndPatch` p :<: rest)+                                    (rp [(il,hl)])+                                    (createHashed h (const $ speculate h (reverse allis) >> parse i h))+                    rp ((i,h):is) = lift2Sealed (\p rest -> i `patchInfoAndPatch` p :<: rest)+                                                (rp is)+                                                (createHashed h (parse i))+          speculate :: String -> [(PatchInfo, String)] -> IO ()+          speculate h is = do already_got_one <- doesFileExist (d++"/"++darcsdir++"/patches/"++h)+                              unless already_got_one $+                                     mapM_ (speculateFileUsingCache (extractCache repo) "patches" . snd) is+          parse :: Patchy p => PatchInfo -> String -> IO (Sealed (p C(x)))+          parse i h = do debugMessage ("Reading patch file: "++ show (human_friendly i))+                         (fn,ps) <- fetchFileUsingCache (extractCache repo) "patches" h+                         case readPatch ps of+                           Just (p,_) -> return p+                           Nothing -> fail $ unlines ["Couldn't parse file "++fn,+                                                      "which is patch",+                                                      renderString $ human_friendly i]+          parseinvs :: RepoPatch p => [[(PatchInfo, String)]] -> IO (SealedPatchSet p)+          parseinvs [] = return $ seal NilRL+          parseinvs (i:is) = lift2Sealed (:<:) (parseinvs is) (read_patches i)+          lift2Sealed :: (FORALL(y z) q C(y z) -> p C(x y) -> r C(x z))+                      -> IO (Sealed (p C(x))) -> (FORALL(b) IO (Sealed (q C(b)))) -> IO (Sealed (r C(x)))+          lift2Sealed f iox ioy = do Sealed x <- unseal seal `fmap` unsafeInterleaveIO iox+                                     Sealed y <- unseal seal `fmap` unsafeInterleaveIO ioy+                                     return $ seal $ f y x++write_and_read_patch :: RepoPatch p => Cache -> [DarcsFlag] -> PatchInfoAnd p C(x y)+                     -> IO (PatchInfoAnd p C(x y))+write_and_read_patch c opts p = do (i,h) <- write_patch_if_necesary c opts p+                                   Sealed x <- createHashed h (parse i)+                                   return $ patchInfoAndPatch i $ unsafeCoerceP x+    where parse i h = do debugMessage ("Reading patch file: "++ show (human_friendly i))+                         (fn,ps) <- fetchFileUsingCache c "patches" h+                         case readPatch ps of+                           Just (x,_) -> return x+                           Nothing -> fail $ unlines ["Couldn't parse patch file "++fn,+                                                      "which is",+                                                      renderString $ human_friendly i]++write_tentative_inventory :: RepoPatch p => Cache -> [DarcsFlag] -> PatchSet p C(x) -> IO ()+write_tentative_inventory c opts = write_either_inventory c opts "tentative_hashed_inventory"++copy_repo :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> String -> IO ()+copy_repo repo@(Repo outr _ _ _) opts inr = do+    createDirectoryIfMissing False (outr++"/"++darcsdir++"/inventories")+    copyFileOrUrl opts (inr++"/"++darcsdir++"/hashed_inventory") (outr++"/"++darcsdir++"/hashed_inventory")+                  Uncachable -- no need to copy anything but hashed_inventory!+    appendBinFile (outr++"/"++darcsdir++"/prefs/sources") (show $ repo2cache inr `unionCaches` extractCache repo)+    debugMessage "Done copying hashed inventory."++write_either_inventory :: RepoPatch p => Cache -> [DarcsFlag] -> String -> PatchSet p C(x) -> IO ()+write_either_inventory c opts iname x =+    do createDirectoryIfMissing False $ darcsdir++"/inventories"+       let k = "Writing inventory"+       beginTedious k+       tediousSize k (lengthRL x)+       hsh <- write_inventory_private k c opts $ slightly_optimize_patchset x+       endTedious k+       case hsh of+         Nothing -> writeBinFile (darcsdir++"/"++iname) ""+         Just h -> gzReadFilePS (darcsdir++"/inventories/"++h) >>= writeAtomicFilePS (darcsdir++"/"++iname)++write_inventory_private :: RepoPatch p => String -> Cache -> [DarcsFlag]+                        -> PatchSet p C(x) -> IO (Maybe String)+write_inventory_private _ _ _ NilRL = return Nothing+write_inventory_private _ _ _ (NilRL:<:NilRL) = return Nothing+write_inventory_private _ _ _ (NilRL:<:_) = -- This shouldn't be possible, so best to check...+    bug "malformed PatchSet in HashedRepo.write_inventory_private"+write_inventory_private k c opts (x:<:xs) =+  do resthash <- write_inventory_private k c opts xs+     finishedOneIO k (case resthash of Nothing -> ""; Just h -> h)+     inventory <- sequence $ mapRL (write_patch_if_necesary c opts) x+     let inventorylist = hcat (map pihash $ reverse inventory)+         inventorycontents = case resthash of+                             Just lasthash -> text ("Starting with inventory:\n"++lasthash) $$+                                              inventorylist+                             _ -> inventorylist+     hash <- writeHashFile c opts "inventories" inventorycontents+     return $ Just hash++write_patch_if_necesary :: RepoPatch p => Cache -> [DarcsFlag]+                        -> PatchInfoAnd p C(x y) -> IO (PatchInfo, String)+write_patch_if_necesary c opts hp =+    case extractHash hp of+    Right h -> return (info hp, h)+    Left p -> fmap (\h -> (info hp, h)) $ writeHashFile c opts "patches" $ showPatch p++pihash :: (PatchInfo,String) -> Doc+pihash (pinf,hash) = showPatchInfo pinf $$ text ("hash: " ++ hash ++ "\n")++read_inventory_private :: Repository p C(r u t) -> [DarcsFlag] -> String -> String+                       -> IO [[(PatchInfo, String)]]+read_inventory_private repo opts d iname = do+    i <- skip_pristine `fmap` fetchFilePS (d++"/"++iname) Uncachable+    (rest,str) <- case breakOnPS '\n' i of+                  (swt,pistr) | swt == packString "Starting with inventory:" ->+                    case breakOnPS '\n' $ tailPS pistr of+                    (h,thisinv) | okayHash $ unpackPS h ->+                      do r <- unsafeInterleaveIO $ read_inventories+                              (extractCache repo) opts (unpackPS h)+                         return (r,thisinv)+                    _ -> fail $ "Bad hash in " ++ d ++ "/"++darcsdir++"/" ++ iname+                  _ -> return ([],i)+    return $ reverse (read_patch_ids str) : rest++read_inventories :: Cache -> [DarcsFlag] -> String -> IO [[(PatchInfo, String)]]+read_inventories cache opts ihash = do+    (fn,i_and_p) <- fetchFileUsingCache cache "inventories" ihash+    let i = skip_pristine i_and_p+    (rest,str) <- case breakOnPS '\n' i of+                  (swt,pistr) | swt == packString "Starting with inventory:" ->+                    case breakOnPS '\n' $ tailPS pistr of+                    (h,thisinv) | okayHash $ unpackPS h ->+                      do r <- unsafeInterleaveIO $+                              read_inventories cache opts (unpackPS h)+                         return (r,thisinv)+                    _ -> fail $ "Bad hash in file " ++ fn+                  _ -> return ([],i)+    return $ reverse (read_patch_ids str) : rest++read_patch_ids :: PackedString -> [(PatchInfo, String)]+read_patch_ids inv | nullPS inv = []+read_patch_ids inv = case readPatchInfo inv of+                     Nothing -> []+                     Just (pinfo,r) ->+                         case readHash r of+                         Nothing -> []+                         Just (h,r') -> (pinfo,h) : read_patch_ids r'++readHash :: PackedString -> Maybe (String, PackedString)+readHash s = let s' = dropWhitePS s+                 (l,r) = breakOnPS '\n' s'+                 (kw,h) = breakOnPS ' ' l+             in if kw /= packString "hash:" || lengthPS h <= 1+                then Nothing+                else Just (unpackPS $ tailPS h,r)++apply_pristine :: Patchy q => Cache -> [DarcsFlag] -> String -> String -> q C(() ()) -> IO ()+apply_pristine c opts d iname p =+    do i <- gzReadFilePS (d++"/"++iname)+       h <- applyHashed c opts (inv2pris i) p+       writeDocBinFile (d++"/"++iname) $ pris2inv h i++apply_to_tentative_pristine :: Patchy q => Cache -> [DarcsFlag] -> q C(() ()) -> IO ()+apply_to_tentative_pristine c opts p = apply_pristine c opts "." (darcsdir++"/tentative_pristine") p++slurp_pristine :: Cache -> [DarcsFlag] -> String -> String -> IO Slurpy+slurp_pristine c opts d iname = do+    i <- fetchFilePS (d++"/"++iname) Uncachable+    slurp_pristine_private c opts i++slurp_pristine_private :: Cache -> [DarcsFlag] -> PackedString -> IO Slurpy+slurp_pristine_private c opts inv = case inv2pris inv of+                                    h | h == sha1PS nilPS -> return empty_slurpy+                                      | otherwise -> slurpHashed c opts h++pristine_from_working :: Cache -> [DarcsFlag] -> IO ()+pristine_from_working c opts = replacePristine c opts "."++replacePristine :: Cache -> [DarcsFlag] -> FilePath -> IO ()+replacePristine c opts d = do s <- slurp_all_but_darcs d+                              h <- hashSlurped c opts s+                              let t = darcsdir++"/hashed_inventory"+                              i <- gzReadFilePS t+                              writeDocBinFile t $ pris2inv h i++copy_pristine :: Cache -> [DarcsFlag] -> String -> String -> IO ()+copy_pristine c opts d iname = do+    i <- fetchFilePS (d++"/"++iname) Uncachable+    debugMessage $ "Copying hashed pristine tree: "++inv2pris i+    let k = "Copying pristine"+    beginTedious k+    copyHashed k c opts $ inv2pris i+    endTedious k++sync_repo :: Cache -> IO ()+sync_repo c = do i <- readFilePS $ darcsdir++"/hashed_inventory"+                 s <- slurp_all_but_darcs "."+                 beginTedious "Synchronizing pristine"+                 syncHashed c s $ inv2pris i+                 ++copy_partials_pristine :: Cache -> [DarcsFlag] -> String -> String -> [FilePath] -> IO ()+copy_partials_pristine c opts d iname fps =+  do i <- fetchFilePS (d++"/"++iname) Uncachable+     copyPartialsHashed c opts (inv2pris i) fps++inv2pris :: PackedString -> String+inv2pris inv | takePS pristine_name_length inv == pristine_name =+                 case takeHash $ dropPS pristine_name_length inv of+                 Just (h,_) -> h+                 Nothing -> error "Bad hash in inventory!"+             | otherwise = sha1PS nilPS++pris2inv :: String -> PackedString -> Doc+pris2inv h inv = invisiblePS pristine_name <> text h $$ invisiblePS (skip_pristine inv)++pristine_name :: PackedString+pristine_name = packString "pristine:"++skip_pristine :: PackedString -> PackedString+skip_pristine ps+    | takePS pristine_name_length ps == pristine_name = dropPS 1 $ dropWhilePS (/= '\n') $+                                                        dropPS pristine_name_length ps+    | otherwise = ps++pristine_name_length :: Int+pristine_name_length = lengthPS pristine_name++slurp_all_but_darcs :: FilePath -> IO Slurpy+slurp_all_but_darcs d = do s <- slurp d+                           case slurp_remove (fp2fn $ "./"++darcsdir) s of+                             Nothing -> return s+                             Just s' -> return s'++\end{code}
+ src/Darcs/Repository/Internal.lhs view
@@ -0,0 +1,874 @@+%  Copyright (C) 2002-2004,2007-2008 David Roundy+%  Copyright (C) 2005 Juliusz Chroboczek+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Repository.Internal ( Repository(..), RepoType(..), ($-),+                    maybeIdentifyRepository, identifyDarcs1Repository, identifyRepositoryFor,+                    findRepository, amInRepository, amNotInRepository,+                    slurp_pending, pristineFromWorking, revertRepositoryChanges,+                    slurp_recorded, slurp_recorded_and_unrecorded,+                    withRecorded, checkPristineAgainstCwd,+                    get_unrecorded, get_unrecorded_unsorted, get_unrecorded_no_look_for_adds,+                    read_repo, sync_repo,+                    prefsUrl, makePatchLazy,+                    read_pending, add_to_pending,+                    withRepoLock, withRepoReadLock,+                    withRepository, withRepositoryDirectory, withGutsOf,+                    tentativelyAddPatch, tentativelyRemovePatches, tentativelyAddToPending,+                    tentativelyReplacePatches,+                    tentativelyMergePatches, considerMergeToWorking,+                    finalizeRepositoryChanges,+                    unrevertUrl,+                    applyToWorking, patchSetToPatches,+                    createPristineDirectoryTree, createPartialsPristineDirectoryTree,+                    replacePristine,+                    optimizeInventory, cleanRepository,+                    getMarkedupFile,+                    PatchSet, SealedPatchSet,+                    setScriptsExecutable+                  ) where++import Printer ( putDocLn, (<+>), text, ($$) )++import Data.Maybe ( isJust, isNothing )+import Darcs.Repository.Prefs ( get_prefval )+import Darcs.Resolution ( standard_resolution, external_resolution )+import System.Exit ( ExitCode(..), exitWith )+import System.Cmd ( system )+import Darcs.External ( backupByCopying, clonePartialsTree )+import Darcs.IO ( runTolerantly, runSilently )+import Darcs.Repository.Pristine ( identifyPristine, nopristine, checkPristine,+                                   easyCreatePristineDirectoryTree, slurpPristine, syncPristine,+                                   easyCreatePartialsPristineDirectoryTree,+                                   createPristineFromWorking )+import qualified Darcs.Repository.Pristine as Pristine ( replacePristine )+import Data.List ( (\\) )+import Darcs.SignalHandler ( withSignalsBlocked )+import Darcs.Repository.Format ( RepoFormat, RepoProperty( Darcs2, HashedInventory ),+                                 identifyRepoFormat, format_has,+                                 write_problem, read_problem, readfrom_and_writeto_problem )+import System.Directory ( doesDirectoryExist, setCurrentDirectory, removeFile )+import Control.Monad ( liftM, when, unless )+import Workaround ( createDirectoryIfMissing, getCurrentDirectory, renameFile, setExecutable )+import FastPackedString ( PackedString, readFilePS, gzReadFilePS, nilPS, packString, takePS )+import Darcs.Patch ( Effect, is_hunk, is_binary, description,+                     try_to_shrink, commuteFL )+import Darcs.Patch.Prim ( try_shrinking_inverse )+import Darcs.Patch.Bundle ( scan_bundle, make_bundle )+import Darcs.SlurpDirectory ( Slurpy, slurp_unboring, mmap_slurp, co_slurp,+                              slurp_has, list_slurpy_files )+import Darcs.Hopefully ( PatchInfoAnd, info, n2pia,+                         hopefully, hopefullyM )+import Darcs.Repository.ApplyPatches ( apply_patches )+import qualified Darcs.Repository.HashedRepo as HashedRepo+                            ( revert_tentative_changes, finalize_tentative_changes,+                              remove_from_tentative_inventory, sync_repo,+                              copy_pristine, copy_partials_pristine, slurp_pristine,+                              apply_to_tentative_pristine, pristine_from_working,+                              write_tentative_inventory, write_and_read_patch,+                              add_to_tentative_inventory, read_repo, clean_pristine,+                              replacePristine, slurp_all_but_darcs )+import qualified Darcs.Repository.DarcsRepo as DarcsRepo+import Darcs.Flags ( DarcsFlag(AnyOrder, Boring, LookForAdds, Verbose, Quiet,+                               MarkConflicts, AllowConflicts, NoUpdateWorking,+                               RepoDir, WorkDir, UMask, Test, LeaveTestDir,+                               SetScriptsExecutable, DryRun),+                     want_external_merge )+import Darcs.Patch.Ordered ( FL(..), RL(..), EqCheck(..), unsafeCoerceP,+                             (:\/:)(..), (:/\:)(..), (:>)(..),+                             (+>+), lengthFL,+                             unsafeUnFL, allFL, filterFL,+                             reverseRL, reverseFL, concatRL, mapFL,+                             mapFL_FL, concatFL )+import Darcs.Patch ( RepoPatch, Patchy, Prim, RealPatch, Patch, merge,+                     joinPatches, sort_coalesceFL,+                     list_conflicted_files, list_touched_files,+                     Named, patchcontents, anonymous,+                     commuteRL, fromPrims,+                     patch2patchinfo, readPatch,+                     writePatch, effect, invert,+                     is_addfile, is_adddir,+                     is_addrmfile, is_addrmdir, is_setpref,+                     apply, apply_to_slurpy,+                     empty_markedup_file, MarkedUpFile+                   )+import Darcs.Patch.Permutations ( commuteWhatWeCanFL, removeFL )+import Darcs.Patch.Info ( PatchInfo )+import Darcs.Patch.Set ( PatchSet, SealedPatchSet )+import Darcs.Patch.Apply ( markup_file, LineMark(None) )+import Darcs.Patch.Depends ( get_common_and_uncommon, deep_optimize_patchset )+import Darcs.Diff ( smart_diff )+import Darcs.Utils ( promptYorn, catchall, withCurrentDirectory, withUMask, nubsort )+import Darcs.Progress ( progressFL, debugMessage )+import Darcs.FilePathUtils ( absolute_dir )+import Darcs.URL ( is_file )+import Darcs.Repository.Prefs ( darcsdir_filter, boring_file_filter, filetype_function,+                                getCaches )+import Darcs.Lock ( withLock, writeDocBinFile, withDelayedDir, removeFileMayNotExist,+                    withTempDir, withPermDir )+import Darcs.Sealed ( Sealed(Sealed), mapSeal, unsafeUnseal, liftSM, seal )+import Darcs.Repository.InternalTypes( Repository(..), RepoType(..) )+import Darcs.Global ( darcsdir )+#include "impossible.h"++maybeIdentifyRepository :: [DarcsFlag] -> String -> IO (Either String (Repository p))+maybeIdentifyRepository opts "." =+    do darcs <- doesDirectoryExist darcsdir+       rf_or_e <- identifyRepoFormat "."+       here <- absolute_dir "."+       case rf_or_e of+         Left err -> return $ Left err+         Right rf ->+             case read_problem rf of+             Just err -> return $ Left err+             Nothing -> if darcs then do pris <- identifyPristine+                                         cs <- getCaches opts here+                                         return $ Right $ Repo here opts rf (DarcsRepository pris cs)+                                 else return (Left "Not a repository")+maybeIdentifyRepository opts url' =+ do url <- absolute_dir url'+    rf_or_e <- identifyRepoFormat url+    case rf_or_e of+      Left e -> return $ Left e+      Right rf -> case read_problem rf of+                  Just err -> return $ Left err+                  Nothing ->  do cs <- getCaches opts url+                                 return $ Right $ Repo url opts rf (DarcsRepository nopristine cs)++identifyDarcs1Repository :: [DarcsFlag] -> String -> IO (Repository Patch)+identifyDarcs1Repository opts url =+    do er <- maybeIdentifyRepository opts url+       case er of+           Left s -> fail s+           Right r -> return r++identifyRepositoryFor :: RepoPatch p => Repository p -> String -> IO (Repository p)+identifyRepositoryFor (Repo _ opts rf _) url =+    do Repo absurl _ rf' t <- identifyDarcs1Repository opts url+       let t' = case t of DarcsRepository x c -> DarcsRepository x c+       case readfrom_and_writeto_problem rf' rf of+         Just e -> fail $ "Incompatibility with repository " ++ url ++ ":\n" ++ e+         Nothing -> return $ Repo absurl opts rf' t'++isRight :: Either a b -> Bool+isRight (Right _) = True+isRight _         = False++currentDirIsRepository :: IO Bool+currentDirIsRepository = isRight `liftM` maybeIdentifyRepository [] "."++amInRepository :: [DarcsFlag] -> IO (Either String FilePath)+amInRepository (WorkDir d:_) =+    do setCurrentDirectory d `catchall` (fail $ "can't set directory to "++d)+       air <- currentDirIsRepository+       if air+          then return (Right "")+          else return (Left "You need to be in a repository directory to run this command.")+amInRepository (_:fs) = amInRepository fs+amInRepository [] = +    seekRepo (Left "You need to be in a repository directory to run this command.")++-- | hunt upwards for the darcs repository+-- This keeps changing up one parent directory, testing at each+-- step if the current directory is a repository or not.  $+-- WARNING this changes the current directory for good if matchFn succeeds+seekRepo :: Either String FilePath+            -- ^ what to return if we don't find a repository+         -> IO (Either String FilePath)+seekRepo onFail = getCurrentDirectory >>= helper "" where+   helper dir startpwd = do+    air <- currentDirIsRepository+    if air+       then return (Right dir)+       else do cd <- getCurrentDirectory+               setCurrentDirectory ".."+               cd' <- getCurrentDirectory+               if cd' /= cd+                  then helper (reverse (takeWhile (/='/') $ reverse cd)///dir) startpwd+                  else do setCurrentDirectory startpwd+                          return onFail+    where ""///b = b+          a///"" = a+          a///b = a ++ "/" ++ b+++amNotInRepository :: [DarcsFlag] -> IO (Either String FilePath)+amNotInRepository (WorkDir d:_) = do createDirectoryIfMissing False d+                                     -- note that the above could always fail+                                     setCurrentDirectory d+                                     amNotInRepository []+amNotInRepository (_:f) = amNotInRepository f+amNotInRepository [] =+    do air <- currentDirIsRepository+       if air then return (Left $ "You may not run this command in a repository.")+              else return $ Right ""++findRepository :: [DarcsFlag] -> IO (Either String FilePath)+findRepository (RepoDir d:_) | is_file d =+    do setCurrentDirectory d `catchall` (fail $ "can't set directory to "++d)+       findRepository []+findRepository (WorkDir d:_) =+    do setCurrentDirectory d `catchall` (fail $ "can't set directory to "++d)+       findRepository []+findRepository (_:fs) = findRepository fs+findRepository [] = seekRepo (Right "")++slurp_pending :: RepoPatch p => Repository p -> IO Slurpy+slurp_pending repo = do+  cur <- slurp_recorded repo+  pend <- read_pending repo+  case apply_to_slurpy pend cur of+    Just pendcur -> return pendcur+    Nothing -> do putStrLn "Yikes, pending has conflicts!"+                  return cur++slurp_recorded :: RepoPatch p => Repository p -> IO Slurpy+slurp_recorded (Repo dir opts rf (DarcsRepository _ c))+    | format_has HashedInventory rf =+        HashedRepo.slurp_pristine c opts dir $ darcsdir++"/hashed_inventory"+slurp_recorded repository@(Repo dir _ _ (DarcsRepository p _)) = do+    mc <- withCurrentDirectory dir $ slurpPristine p+    case mc of (Just slurpy) -> return slurpy+               Nothing -> withDelayedDir "pristine.temp" $ \cd ->+                          do createPristineDirectoryTree repository cd+                             mmap_slurp cd++slurp_recorded_and_unrecorded :: RepoPatch p => Repository p -> IO (Slurpy, Slurpy)+slurp_recorded_and_unrecorded repo@(Repo r _ _ _) = do+  cur <- slurp_recorded repo+  pend <- read_pending repo+  withCurrentDirectory r $+      case apply_to_slurpy pend cur of+      Nothing -> fail "Yikes, pending has conflicts!"+      Just pendslurp -> do unrec <- co_slurp pendslurp "."+                           return (cur, unrec)++pendingName :: RepoType p -> String+pendingName (DarcsRepository _ _) = darcsdir++"/patches/pending"++read_pending :: RepoPatch p => Repository p -> IO (FL Prim)+read_pending (Repo r _ _ tp) =+    withCurrentDirectory r (read_pendingfile (pendingName tp))++add_to_pending :: RepoPatch p => Repository p -> FL Prim -> IO ()+add_to_pending (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return ()+add_to_pending repo p =+    do pend <- get_unrecorded repo+       make_new_pending repo (pend +>+ p)++readPrims :: PackedString -> Sealed (FL Prim C(x))+readPrims s = case readPatch s of+              Nothing -> Sealed NilFL+              Just (Sealed p,_) -> Sealed (effect (p :: Patch C(x y)))++read_pendingfile :: String -> IO (FL Prim)+read_pendingfile name = do+  pend <- gzReadFilePS name `catchall` return nilPS+  case readPrims pend of+    Sealed p -> return p++make_new_pending :: RepoPatch p => Repository p -> FL Prim -> IO ()+make_new_pending (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return ()+make_new_pending repo@(Repo r _ _ tp) origp =+    withCurrentDirectory r $+    do let newname = pendingName tp ++ ".new"+       debugMessage $ "Writing new pending:  " ++ newname+       writePatch newname (fromPrims $ sift_for_pending origp :: Patch)+       cur <- slurp_recorded repo+       p <- read_pendingfile newname+       when (isNothing $ apply_to_slurpy p cur) $ do+         let buggyname = pendingName tp ++ "_buggy"+         renameFile newname buggyname+         bugDoc $ text "There was an attempt to write an invalid pending!"+                    $$ text "If possible, please send the contents of"+                    <+> text buggyname+                    $$ text "along with a bug report."+       renameFile newname (pendingName tp)+       debugMessage $ "Finished writing new pending:  " ++ newname++sift_for_pending :: FL Prim -> FL Prim+sift_for_pending simple_ps =+ let oldps = maybe simple_ps id $ try_shrinking_inverse $ crude_sift simple_ps+ in if allFL (\p -> is_addfile p || is_adddir p) $ oldps+    then oldps+    else +      case try_to_shrink $ sfp NilFL $ reverseFL oldps of+      ps | lengthFL ps < lengthFL oldps -> sift_for_pending ps+         | otherwise -> ps+      where sfp :: FL Prim C(x y) -> RL Prim C(y z) -> FL Prim C(x z)+            sfp sofar NilRL = sofar+            sfp sofar (p:<:ps)+                | is_hunk p || is_binary p+                    = case commuteFL (p :> sofar) of+                      Just (sofar' :> _) -> sfp sofar' ps+                      Nothing -> sfp (p:>:sofar) ps+            sfp sofar (p:<:ps) = sfp (p:>:sofar) ps++get_unrecorded_no_look_for_adds :: RepoPatch p => Repository p -> IO (FL Prim)+get_unrecorded_no_look_for_adds = get_unrecorded_private (filter (/= LookForAdds))++get_unrecorded_unsorted :: RepoPatch p => Repository p -> IO (FL Prim)+get_unrecorded_unsorted = get_unrecorded_private (AnyOrder:)++get_unrecorded :: RepoPatch p => Repository p -> IO (FL Prim)+get_unrecorded = get_unrecorded_private id++get_unrecorded_private :: RepoPatch p => ([DarcsFlag]->[DarcsFlag]) -> Repository p -> IO (FL Prim)+get_unrecorded_private _ (Repo _ opts _ _)+    | NoUpdateWorking `elem` opts = return NilFL+get_unrecorded_private modopts repository@(Repo r oldopts _ _) =+  withCurrentDirectory r $ do+    debugMessage "Looking for unrecorded changes..."+    cur <- slurp_pending repository+    work <- if LookForAdds `elem` opts+            then do nboring <- if Boring `elem` opts+                               then return $ darcsdir_filter+                               else boring_file_filter+                    slurp_unboring (myfilt cur nboring) "."+            else co_slurp cur "."+    pend <- read_pending repository+    when (Verbose `elem` opts) $ putStrLn "diffing dir..."+    ftf <- filetype_function+    let dif = case smart_diff opts ftf cur work of+              di -> if AnyOrder `elem` opts+                    then pend +>+ di+                    else sort_coalesceFL $ pend +>+ di+    seq dif $ debugMessage "Found unrecorded changes."+    return dif+    where myfilt s nboring f = slurp_has f s || nboring [f] /= []+          opts = modopts oldopts++-- @todo: we should not have to open the result of HashedRepo and+-- seal it.  Instead, update this function to work with type witnesses+-- by fixing DarcsRepo to match HashedRepo in the handling of +-- Repository state.+read_repo :: RepoPatch p => Repository p -> IO (SealedPatchSet p)+read_repo repo@(Repo r opts rf _)+    | format_has HashedInventory rf = do ps <- HashedRepo.read_repo repo opts r+                                         return $ seal ps+    | otherwise = DarcsRepo.read_repo opts r++makePatchLazy :: RepoPatch p => Repository p -> PatchInfoAnd p -> IO (PatchInfoAnd p)+makePatchLazy (Repo r opts rf (DarcsRepository _ c)) p+    | format_has HashedInventory rf = withCurrentDirectory r $ HashedRepo.write_and_read_patch c opts p+    | otherwise = withCurrentDirectory r $ DarcsRepo.write_and_read_patch opts p++sync_repo :: Repository p -> IO ()+sync_repo (Repo r _ rf (DarcsRepository _ c))+    | format_has HashedInventory rf = withCurrentDirectory r $ HashedRepo.sync_repo c+sync_repo (Repo r _ _ (DarcsRepository p _)) = withCurrentDirectory r $ syncPristine p++prefsUrl :: Repository p -> String+prefsUrl (Repo r _ _ (DarcsRepository _ _)) = r ++ "/"++darcsdir++"/prefs"++unrevertUrl :: Repository p -> String+unrevertUrl (Repo r _ _ (DarcsRepository _ _)) = r ++ "/"++darcsdir++"/patches/unrevert"++applyToWorking :: Patchy p => Repository p1 -> [DarcsFlag] -> p -> IO ()+applyToWorking (Repo r _ _ (DarcsRepository _ _)) opts patch =+    withCurrentDirectory r $ if Quiet `elem` opts+                             then runSilently $ apply opts patch+                             else runTolerantly $ apply opts patch++handle_pend_for_add :: (RepoPatch p, Effect q) => Repository p -> q -> IO ()+handle_pend_for_add (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return ()+handle_pend_for_add (Repo _ _ _ rt) p =+    do let pn = pendingName rt ++ ".tentative"+       Sealed pend <- (readPrims `fmap` gzReadFilePS pn) `catchall` (return $ Sealed NilFL)+       let effectp = if allFL is_simple pend then crude_sift $ effect p+                                             else effect p+       Sealed newpend <- return $ rmpend (progressFL "Removing from pending:" effectp) pend+       writePatch pn $ (fromPrims newpend :: Patch)+    where rmpend :: FL Prim C(x y) -> FL Prim C(x z) -> Sealed (FL Prim) C(y)+          rmpend NilFL x = Sealed x+          rmpend _ NilFL = Sealed NilFL+          rmpend (x:>:xs) xys | Just ys <- removeFL x xys = rmpend xs ys+          rmpend (x:>:xs) ys = case commuteWhatWeCanFL (x:>xs) of+                               a:>x':>b -> (invert (x':>:b) +>+) `mapSeal` rmpend a ys++is_simple :: Prim C(x y) -> Bool+is_simple x = is_hunk x || is_binary x || is_setpref x ||+              is_addrmfile x || is_addrmdir x++crude_sift :: FL Prim C(x y) -> FL Prim C(x y)+crude_sift xs = if allFL is_simple xs then filterFL ishunkbinary xs else xs+    where ishunkbinary :: Prim C(x y) -> EqCheck C(x y)+          ishunkbinary x | is_hunk x || is_binary x = unsafeCoerceP IsEq+                         | otherwise = NotEq++data HashedVsOld a = HvsO { old, hashed :: a }++decideHashedOrNormal :: Monad m => RepoFormat -> HashedVsOld (m a) -> m a+decideHashedOrNormal rf (HvsO { hashed = h, old = o })+    | format_has HashedInventory rf = h+    | otherwise = o++tentativelyMergePatches :: RepoPatch p => Repository p -> String -> [DarcsFlag]+                        -> FL (PatchInfoAnd p) -> FL (PatchInfoAnd p) -> IO (FL Prim)+tentativelyMergePatches = tentativelyMergePatches_ MakeChanges++considerMergeToWorking :: RepoPatch p => Repository p -> String -> [DarcsFlag]+                       -> FL (PatchInfoAnd p) -> FL (PatchInfoAnd p) -> IO (FL Prim)+considerMergeToWorking = tentativelyMergePatches_ DontMakeChanges++data MakeChanges = MakeChanges | DontMakeChanges deriving ( Eq )++tentativelyMergePatches_ :: RepoPatch p => MakeChanges+                         -> Repository p -> String -> [DarcsFlag]+                         -> FL (PatchInfoAnd p) -> FL (PatchInfoAnd p) -> IO (FL Prim)+tentativelyMergePatches_ mc r cmd opts usi themi =+  do let us = mapFL_FL hopefully usi+         them = mapFL_FL hopefully themi+         pc = case merge (progressFL "Merging them" them :\/: progressFL "Merging us" us) of+              _ :/\: x -> x+     pend <- get_unrecorded_unsorted r -- we don't care if it looks pretty...+     pend' :/\: pw <- return $ merge (pc :\/: anonymous (fromPrims pend) :>: NilFL)+     let pwprim = joinPatches $ progressFL "Examining patches for conflicts" $ mapFL_FL patchcontents pw+         Sealed standard_resolved_pw = standard_resolution pwprim+     debugMessage "Checking for conflicts..."+     mapM_ backupByCopying $ list_touched_files standard_resolved_pw+     debugMessage "Announcing conflicts..."+     have_conflicts <- announce_merge_conflicts cmd opts standard_resolved_pw+     debugMessage "Checking for unrecorded conflicts..."+     have_unrecorded_conflicts <- check_unrecorded_conflicts opts pc+     debugMessage "Reading working directory..."+     (_, working) <- slurp_recorded_and_unrecorded r+     debugMessage "Working out conflicts in actual working directory..."+     pw_resolution <-+          case (want_external_merge opts, have_conflicts || have_unrecorded_conflicts) of+          (Nothing,_) -> return $ if AllowConflicts `elem` opts+                                  then NilFL+                                  else standard_resolved_pw+          (_,False) -> return standard_resolved_pw+          (Just c, True) -> unsafeUnseal `fmap`+                            external_resolution working c+                                                    (effect us +>+ pend)+                                                    (effect them) pwprim+     debugMessage "Applying patches to the local directories..."+     when (mc == MakeChanges) $+          do let themi' = case usi of NilFL -> themi+                                      _ -> mapFL_FL n2pia pc+             debugMessage "Adding patches to inventory..."+             sequence_ $ mapFL (tentativelyAddPatch_ DontUpdatePristine r opts) themi'+             debugMessage "Applying patches to pristine..."+             applyToTentativePristine r themi'+             debugMessage "Updating pending..."+             setTentativePending r (effect pend' +>+ pw_resolution)+     return (effect pwprim +>+ pw_resolution)++announce_merge_conflicts :: String -> [DarcsFlag] -> FL Prim -> IO Bool+announce_merge_conflicts cmd opts resolved_pw =+    case nubsort $ list_touched_files $ resolved_pw of+    [] -> return False+    cfs -> if MarkConflicts `elem` opts || AllowConflicts `elem` opts+              || want_external_merge opts /= Nothing+           then do putStrLn "We have conflicts in the following files:"+                   putStrLn $ unwords cfs+                   return True+           else do putStrLn "There are conflicts in the following files:"+                   putStrLn $ unwords cfs+                   fail $ "Refusing to "++cmd++" patches leading to conflicts.\n"+++                          "If you would rather apply the patch and mark the conflicts,\n"+++                          "use the --mark-conflicts or --allow-conflicts options to "++cmd++"\n"+++                          "These can set as defaults by adding\n"+++                          " "++cmd++" mark-conflicts\n"++ +                          "to "++darcsdir++"/prefs/defaults in the target repo. "++check_unrecorded_conflicts :: forall p. RepoPatch p => [DarcsFlag] -> FL (Named p) -> IO Bool+check_unrecorded_conflicts opts _ | NoUpdateWorking `elem` opts = return False+check_unrecorded_conflicts opts pc =+    do repository <- identifyDarcs1Repository opts "."+       mpend <- read_pending repository+       case mpend of+         NilFL -> return False+         pend ->+             case merge (fromPrims pend :\/: fromPrims (concatFL $ mapFL_FL effect pc)) of+             _ :/\: (pend' :: p) ->+                 case list_conflicted_files pend' of+                 [] -> return False+                 fs -> do yorn <- promptYorn+                                  ("You have conflicting local changes to:\n"+                                   ++ unwords fs++"\nProceed?")+                          when (yorn /= 'y') $+                               do putStr "Cancelled."+                                  exitWith ExitSuccess+                          return True++tentativelyAddPatch :: RepoPatch p => Repository p -> [DarcsFlag] -> PatchInfoAnd p -> IO ()+tentativelyAddPatch = tentativelyAddPatch_ UpdatePristine++data UpdatePristine = UpdatePristine | DontUpdatePristine deriving Eq++tentativelyAddPatch_ :: RepoPatch p => UpdatePristine -> Repository p -> [DarcsFlag]+                     -> PatchInfoAnd p -> IO ()+tentativelyAddPatch_ _ _ opts _+    | DryRun `elem` opts = bug "tentativelyAddPatch_ called when --dry-run is specified"+tentativelyAddPatch_ up r@(Repo dir _ rf (DarcsRepository _ c)) opts p =+    withCurrentDirectory dir $+    do decideHashedOrNormal rf $ HvsO {+          hashed = HashedRepo.add_to_tentative_inventory c opts p,+          old = DarcsRepo.add_to_tentative_inventory opts (hopefully p) }+       when (up == UpdatePristine) $ do debugMessage "Applying to pristine cache..."+                                        applyToTentativePristine r p+                                        debugMessage "Updating pending..."+                                        handle_pend_for_add r p++applyToTentativePristine :: (Effect q, Patchy q) => Repository p -> q -> IO ()+applyToTentativePristine (Repo dir opts rf (DarcsRepository _ c)) p =+    withCurrentDirectory dir $+    do when (Verbose `elem` opts) $ putDocLn $ text "Applying to pristine..." <+> description p+       decideHashedOrNormal rf $ HvsO {hashed = HashedRepo.apply_to_tentative_pristine c opts p,+                                       old = DarcsRepo.add_to_tentative_pristine p}++tentativelyAddToPending :: forall p. RepoPatch p => Repository p -> [DarcsFlag] -> FL Prim -> IO ()+tentativelyAddToPending (Repo _ opts _ _) _ _+    | NoUpdateWorking `elem` opts = return ()+    | DryRun `elem` opts = bug "tentativelyAddToPending called when --dry-run is specified"+tentativelyAddToPending (Repo dir _ _ rt) _ patch =+    withCurrentDirectory dir $ do+      let pn = pendingName rt+          tpn = pn ++ ".tentative"+      pend <- gzReadFilePS tpn `catchall` (return nilPS)+      let newpend = case readPrims pend of+                    Sealed NilFL -> patch+                    Sealed p -> p +>+ patch+      writePatch tpn $ (fromPrims newpend :: Patch)++setTentativePending :: forall p. RepoPatch p => Repository p -> FL Prim -> IO ()+setTentativePending (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return ()+setTentativePending (Repo dir _ _ rt) patch =+    withCurrentDirectory dir $+    writePatch (pendingName rt ++ ".tentative") $ (fromPrims (sift_for_pending patch) :: Patch)++prepend :: forall p. RepoPatch p => Repository p -> FL Prim -> IO ()+prepend (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return ()+prepend (Repo _ _ _ rt) patch = do let pn = pendingName rt ++ ".tentative"+                                   pend <- gzReadFilePS pn `catchall` (return nilPS)+                                   let newpend = case readPrims pend of+                                                 Sealed NilFL -> patch+                                                 Sealed p -> patch +>+ p+                                   writePatch pn $ (fromPrims (crude_sift newpend) :: Patch)++tentativelyRemovePatches :: RepoPatch p => Repository p -> [DarcsFlag]+                         -> FL (Named p) -> IO ()+tentativelyRemovePatches = tentativelyRemovePatches_ UpdatePristine++tentativelyRemovePatches_ :: RepoPatch p => UpdatePristine+                          -> Repository p -> [DarcsFlag]+                          -> FL (Named p) -> IO ()+tentativelyRemovePatches_ up repository@(Repo dir _ rf (DarcsRepository _ c)) opts ps =+    withCurrentDirectory dir $ do+      when (up == UpdatePristine) $ do debugMessage "Adding changes to pending..."+                                       prepend repository $ effect ps+      remove_from_unrevert_context repository ps+      debugMessage "Removing changes from tentative inventory..."+      if format_has HashedInventory rf+        then do HashedRepo.remove_from_tentative_inventory repository opts ps+                when (up == UpdatePristine) $+                     HashedRepo.apply_to_tentative_pristine c opts $+                     progressFL "Applying inverse to pristine" $ invert ps+        else DarcsRepo.remove_from_tentative_inventory updarcspris opts ps+               where updarcspris = up==UpdatePristine && not (format_has HashedInventory rf)++tentativelyReplacePatches :: RepoPatch p => Repository p -> [DarcsFlag]+                          -> FL (Named p) -> IO ()+tentativelyReplacePatches repository opts ps =+    do tentativelyRemovePatches_ DontUpdatePristine repository opts ps+       sequence_ $ mapFL+           (tentativelyAddPatch_ DontUpdatePristine repository opts . n2pia) ps++finalize_pending :: RepoPatch p => Repository p -> IO ()+finalize_pending (Repo dir opts _ rt)+    | NoUpdateWorking `elem` opts =+        withCurrentDirectory dir $ removeFileMayNotExist $ (pendingName rt)+finalize_pending repository@(Repo dir _ _ rt) = do+  withCurrentDirectory dir $ do let pn = pendingName rt+                                    tpn = pn ++ ".tentative"+                                tpfile <- gzReadFilePS tpn `catchall` (return nilPS)+                                let tpend = unsafeUnseal $ readPrims tpfile+                                    new_pending = sift_for_pending tpend+                                make_new_pending repository new_pending++finalizeRepositoryChanges :: RepoPatch p => Repository p -> IO ()+finalizeRepositoryChanges (Repo _ opts _ _)+    | DryRun `elem` opts = bug "finalizeRepositoryChanges called when --dry-run specified"+finalizeRepositoryChanges repository@(Repo dir opts rf _)+    | format_has HashedInventory rf =+        withCurrentDirectory dir $ do debugMessage "Considering whether to test..."+                                      testTentative repository+                                      debugMessage "Finalizing changes..."+                                      withSignalsBlocked $ do HashedRepo.finalize_tentative_changes repository opts+                                                              finalize_pending repository+                                      debugMessage "Done finalizing changes..."+finalizeRepositoryChanges repository@(Repo dir _ _ (DarcsRepository _ _)) =+  withCurrentDirectory dir $ do debugMessage "Considering whether to test..."+                                testTentative repository+                                debugMessage "Finalizing changes..."+                                withSignalsBlocked $ do DarcsRepo.finalize_pristine_changes+                                                        DarcsRepo.finalize_tentative_changes+                                                        finalize_pending repository++testTentative :: RepoPatch p => Repository p -> IO ()+testTentative repository@(Repo dir opts _ _) =+    when (Test `elem` opts) $ withCurrentDirectory dir $+    do let putInfo = if not $ Quiet `elem` opts then putStrLn else const (return ())+       debugMessage "About to run test if it exists."+       testline <- get_prefval "test"+       case testline of+         Nothing -> return ()+         Just testcode ->+             withTentative repository (wd "testing") $ \_ ->+             do putInfo "Running test...\n"+                when (SetScriptsExecutable `elem` opts) setScriptsExecutable+                ec <- system testcode+                if ec == ExitSuccess+                  then putInfo "Test ran successfully.\n"+                  else do putInfo "Test failed!\n"+                          exitWith ec+    where wd = if LeaveTestDir `elem` opts then withPermDir else withTempDir++revertRepositoryChanges :: RepoPatch p => Repository p -> IO ()+revertRepositoryChanges (Repo _ opts _ _)+    | DryRun `elem` opts = bug "revertRepositoryChanges called when --dry-run is specified"+revertRepositoryChanges r@(Repo dir opts rf dr@(DarcsRepository _ _)) =+    withCurrentDirectory dir $+    do removeFileMayNotExist (pendingName dr ++ ".tentative")+       x <- read_pending r+       setTentativePending r $ effect x+       when (NoUpdateWorking `elem` opts) $ removeFileMayNotExist $ pendingName dr+       decideHashedOrNormal rf $ HvsO { hashed = HashedRepo.revert_tentative_changes,+                                        old = DarcsRepo.revert_tentative_changes }++patchSetToPatches :: RepoPatch p => PatchSet p -> FL (Named p)+patchSetToPatches patchSet = mapFL_FL hopefully $ reverseRL $ concatRL patchSet++getUMask :: [DarcsFlag] -> Maybe String+getUMask [] = Nothing+getUMask ((UMask u):_) = Just u+getUMask (_:l) = getUMask l++withGutsOf :: Repository p -> IO () -> IO ()+withGutsOf (Repo _ _ rf _) | format_has HashedInventory rf = id+                           | otherwise = withSignalsBlocked++withRepository :: [DarcsFlag] -> (forall p. RepoPatch p => Repository p -> IO a) -> IO a+withRepository opts1 = withRepositoryDirectory opts1 "."++withRepositoryDirectory :: [DarcsFlag] -> String+                        -> (forall p. RepoPatch p => Repository p -> IO a) -> IO a+withRepositoryDirectory opts1 url job =+    do Repo dir opts rf rt <- identifyDarcs1Repository opts1 url+       let rt' = case rt of DarcsRepository t c -> DarcsRepository t c+       if format_has Darcs2 rf+         then do debugMessage $ "Identified darcs-2 repo: " ++ dir+                 job (Repo dir opts rf rt' :: Repository (FL RealPatch))+         else do debugMessage $ "Identified darcs-1 repo: " ++ dir+                 job (Repo dir opts rf rt :: Repository Patch)++($-) :: ((forall p. RepoPatch p => Repository p -> IO a) -> IO a)+     -> (forall p. RepoPatch p => Repository p -> IO a) -> IO a+x $- y = x y++withRepoLock :: [DarcsFlag] -> (forall p. RepoPatch p => Repository p -> IO a) -> IO a+withRepoLock opts job =+    withRepository opts $- \repository@(Repo _ _ rf _) ->+    do case write_problem rf of+         Nothing -> return ()+         Just err -> fail err+       let name = "./"++darcsdir++"/lock"+           wu = case (getUMask opts) of+                  Nothing -> id+                  Just u -> withUMask u+       wu $ if DryRun `elem` opts+            then job repository+            else withLock name (revertRepositoryChanges repository >> job repository)++withRepoReadLock :: [DarcsFlag] -> (forall p. RepoPatch p => Repository p -> IO a) -> IO a+withRepoReadLock opts job =+    withRepository opts $- \repository@(Repo _ _ rf _) ->+    do case write_problem rf of+         Nothing -> return ()+         Just err -> fail err+       let name = "./"++darcsdir++"/lock"+           wu = case (getUMask opts) of Nothing -> id+                                        Just u -> withUMask u+       wu $ if format_has HashedInventory rf || DryRun `elem` opts+            then job repository+            else withLock name (revertRepositoryChanges repository >> job repository)+\end{code}++\begin{code}+remove_from_unrevert_context :: RepoPatch p => Repository p -> FL (Named p) -> IO ()+remove_from_unrevert_context repository ps = do+  bundle <- unrevert_patch_bundle `catchall` return (NilRL:<:NilRL)+  case bundle of+    NilRL:<:NilRL -> return ()+    _ -> do+    let unrevert_loc = unrevertUrl repository+    debugMessage "Adjusting the context of the unrevert changes..."+    Sealed ref <- read_repo repository+    case get_common_and_uncommon (bundle, ref) of+        (common,(h_us:<:NilRL):<:NilRL :\/: NilRL:<:NilRL) ->+            case commuteRL (reverseFL ps :> hopefully h_us) of+            Nothing -> unrevert_impossible unrevert_loc+            Just (us' :> _) -> do+                s <- slurp_recorded repository+                writeDocBinFile unrevert_loc $+                             make_bundle [] s+                             (common \\ pis) (us':>:NilFL)+        (common,(x:<:NilRL):<:NilRL:\/:_)+            | isr && any (`elem` common) pis -> unrevert_impossible unrevert_loc+            | isr -> return ()+            where isr = isJust $ hopefullyM x+        _ -> unrevert_impossible unrevert_loc+  where unrevert_impossible unrevert_loc =+            do yorn <- promptYorn "This operation will make unrevert impossible!\nProceed?"+               case yorn of+                 'n' -> fail "Cancelled to avoid unrevert catastrophe!"+                 'y' -> removeFile unrevert_loc `catchall` return ()+                 _ -> impossible+        pis = mapFL patch2patchinfo ps+        unrevert_patch_bundle :: RepoPatch p => IO (PatchSet p)+        unrevert_patch_bundle = do pf <- readFilePS (unrevertUrl repository)+                                   case scan_bundle pf of+                                     Right (Sealed foo) -> return foo+                                     Left err -> fail $ "Couldn't parse unrevert patch:\n" ++ err+\end{code}++\begin{code}+optimizeInventory :: RepoPatch p => Repository p -> IO ()+optimizeInventory repository@(Repo r opts rf (DarcsRepository _ c)) =+    do Sealed ps <- read_repo repository+       decideHashedOrNormal rf $+           HvsO { hashed = do revertRepositoryChanges repository+                              HashedRepo.write_tentative_inventory c opts $ deep_optimize_patchset ps+                              finalizeRepositoryChanges repository,+                  old = DarcsRepo.write_inventory r $ deep_optimize_patchset ps+                }++cleanRepository :: RepoPatch p => Repository p -> IO ()+cleanRepository repository@(Repo _ _ rf _) =+    decideHashedOrNormal rf $+    HvsO { hashed = HashedRepo.clean_pristine repository,+           old = return () }++replacePristine :: Repository p -> FilePath -> IO ()+replacePristine (Repo r opts rf (DarcsRepository pris c)) d+    | format_has HashedInventory rf = withCurrentDirectory r $ HashedRepo.replacePristine c opts d+    | otherwise = withCurrentDirectory r $ Pristine.replacePristine d pris++createPristineDirectoryTree :: RepoPatch p => Repository p -> FilePath -> IO ()+createPristineDirectoryTree repo@(Repo r opts rf (DarcsRepository pris c)) reldir+    | format_has HashedInventory rf =+        do createDirectoryIfMissing True reldir+           withCurrentDirectory reldir $ HashedRepo.copy_pristine c opts r (darcsdir++"/hashed_inventory")+    | otherwise =+        do dir <- absolute_dir reldir+           done <- withCurrentDirectory r $ easyCreatePristineDirectoryTree pris dir+           unless done $ do patches <- (reverseRL . concatRL) `liftSM` read_repo repo+                            createDirectoryIfMissing True dir+                            withCurrentDirectory dir $ apply_patches [] patches++createPartialsPristineDirectoryTree :: RepoPatch p => Repository p -> [FilePath] -> FilePath -> IO ()+createPartialsPristineDirectoryTree (Repo r opts rf (DarcsRepository _ c)) prefs dir+    | format_has HashedInventory rf =+        do createDirectoryIfMissing True dir+           withCurrentDirectory dir $+               HashedRepo.copy_partials_pristine c opts r (darcsdir++"/hashed_inventory") prefs+createPartialsPristineDirectoryTree r@(Repo rdir _ _ (DarcsRepository pris _)) prefs dir+ = withCurrentDirectory rdir $+   do done <- easyCreatePartialsPristineDirectoryTree prefs pris dir+      unless done $ withRecorded r (withTempDir "recorded") $ \_ -> do+          clonePartialsTree "." dir prefs++pristineFromWorking :: RepoPatch p => Repository p -> IO ()+pristineFromWorking (Repo dir opts rf (DarcsRepository _ c))+    | format_has HashedInventory rf =+        withCurrentDirectory dir $ HashedRepo.pristine_from_working c opts+pristineFromWorking (Repo dir _ _ (DarcsRepository p _)) =+  withCurrentDirectory dir $ createPristineFromWorking p++withRecorded :: RepoPatch p => Repository p -> ((FilePath -> IO a) -> IO a) -> (FilePath -> IO a) -> IO a+withRecorded repository mk_dir f+    = mk_dir $ \d -> do createPristineDirectoryTree repository d+                        f d++checkPristineAgainstCwd :: RepoPatch p => Repository p -> IO Bool+checkPristineAgainstCwd (Repo dir _ rf (DarcsRepository p _))+    | not $ format_has HashedInventory rf = do here <- absolute_dir "."+                                               withCurrentDirectory dir $ checkPristine here p+checkPristineAgainstCwd repository@(Repo _ opts _ _) =+    do s2 <- mmap_slurp "."+       s1 <- slurp_recorded repository+       ftf <- filetype_function+       case smart_diff opts ftf s1 s2 of+         NilFL -> return True+         _ -> return False++withTentative :: forall p a. RepoPatch p =>+                 Repository p -> ((FilePath -> IO a) -> IO a) -> (FilePath -> IO a) -> IO a+withTentative (Repo dir opts rf (DarcsRepository _ c)) mk_dir f+    | format_has HashedInventory rf =+        mk_dir $ \d -> do HashedRepo.copy_pristine c opts dir (darcsdir++"/tentative_pristine")+                          f d+withTentative repository@(Repo dir opts _ _) mk_dir f =+    withRecorded repository mk_dir $ \d ->+    do ps <- read_patches (dir ++ "/"++darcsdir++"/tentative_pristine")+       apply opts $ joinPatches ps+       f d+    where read_patches :: FilePath -> IO (FL p)+          read_patches fil = do ps <- readFilePS fil+                                return $ case readPatch ps of+                                           Just (Sealed x, _) -> x+                                           Nothing -> NilFL+\end{code}++\begin{code}+getMarkedupFile :: RepoPatch p => Repository p -> PatchInfo -> FilePath -> IO MarkedUpFile+getMarkedupFile repository pinfo f = do+  patches <- (dropWhile ((/= pinfo) . info) . unsafeUnFL+              . reverseRL . concatRL) `liftSM` read_repo repository+  return $ snd $ do_mark_all patches (f, empty_markedup_file)+do_mark_all :: RepoPatch p => [PatchInfoAnd p]+            -> (FilePath, MarkedUpFile) -> (FilePath, MarkedUpFile)+do_mark_all (hp:pps) (f, mk) =+    case hopefullyM hp of+    Just p -> do_mark_all pps $ markup_file (info hp) (patchcontents p) (f, mk)+    Nothing -> (f, [(packString "Error reading a patch!",None)])+do_mark_all [] (f, mk) = (f, mk)+\end{code}++\begin{code}+-- | Sets scripts in or below the current directory executable. A script is any file that starts+--   with the bytes '#!'. This is used sometimes for --set-scripts-executable, but at other times+--   --set-scripts-executable is handled by the hunk patch case of applyFL.+setScriptsExecutable :: IO ()+setScriptsExecutable = do+    debugMessage "Making scripts executable"+    myname <- getCurrentDirectory+    c <- list_slurpy_files `fmap` (HashedRepo.slurp_all_but_darcs myname)+    let setExecutableIfScript f =+              do contents <- readFilePS f+                 when (takePS 2 contents == packString "#!") $ do+                   debugMessage ("Making executable: " ++ f)+                   setExecutable f True+    mapM_ setExecutableIfScript c+\end{code}+
+ src/Darcs/Repository/InternalTypes.lhs view
@@ -0,0 +1,40 @@+%  Copyright (C) 2006-2007 David Roundy+%+%  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, 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.++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Repository.InternalTypes ( Repository(..), RepoType(..), Pristine(..)+                                      , extractCache+                                      ) where++import Darcs.Repository.Prefs ( Cache )+import Darcs.Flags ( DarcsFlag )+import Darcs.Repository.Format ( RepoFormat )++data Pristine+  = NoPristine !String+  | PlainPristine !String+  | HashedPristine+    deriving ( Show )++data Repository (p :: * C(-> * -> *)) C(recordedstate unrecordedstate tentativestate) = Repo !String ![DarcsFlag] !RepoFormat !(RepoType p) deriving ( Show )++data RepoType (p :: * C(-> * -> *)) = DarcsRepository !Pristine Cache deriving ( Show )++extractCache :: Repository p C(r u t) -> Cache+extractCache (Repo _ _ _ (DarcsRepository _ c)) = c+\end{code}
+ src/Darcs/Repository/Motd.lhs view
@@ -0,0 +1,46 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+module Darcs.Repository.Motd (get_motd, show_motd) where+import Control.Monad ( unless )+import Darcs.Flags ( DarcsFlag( Quiet ) )+import Darcs.External ( fetchFilePS, Cachable(..) )+import Darcs.Global ( darcsdir )+import FastPackedString ( nullPS, nilPS, hPutPS, PackedString )+import Darcs.Utils ( catchall )+import System.IO ( stdout )+\end{code}++\paragraph{motd}\label{motd}+The \verb!_darcs/prefs/motd! file may contain a ``message of the day''+which will be displayed to users who get or pull from the repository without the+\verb!--quiet! option.++\begin{code}+get_motd :: String -> IO PackedString+get_motd repo = fetchFilePS (repo++"/"++darcsdir++"/prefs/motd") (MaxAge 600)+                     `catchall` return nilPS++show_motd :: [DarcsFlag] -> String -> IO ()+show_motd opts repo = unless (Quiet `elem` opts) $ do+  motd <- get_motd repo+  unless (nullPS motd)+      $ do hPutPS stdout motd+           putStrLn "**********************"+\end{code}
+ src/Darcs/Repository/Prefs.lhs view
@@ -0,0 +1,638 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Repository.Prefs ( add_to_preflist, get_preflist, set_preflist,+                   get_global,+                   defaultrepo, set_defaultrepo,+                   get_prefval, set_prefval, change_prefval,+                   def_prefval,+                   write_default_prefs,+                   boring_file_filter, darcsdir_filter,+                   FileType(..), filetype_function,+                   okayHash, takeHash,+                   Cache, getCaches, unionCaches, cleanCaches,+                   fetchFileUsingCache, speculateFileUsingCache, writeFileUsingCache,+                   findFileMtimeUsingCache, setFileMtimeUsingCache, peekInCache,+                   repo2cache+                 ) where++import System.Posix ( setFileTimes )+import System.IO ( hPutStrLn, stderr )+import System.IO.Error ( isDoesNotExistError )+import System.Posix.Files ( linkCount, modificationTime, getSymbolicLinkStatus )+import System.Posix.Types ( EpochTime )+import Workaround ( getCurrentDirectory, createLink, createDirectoryIfMissing )+import System.Directory ( removeFile, doesFileExist, getDirectoryContents )+import Control.Monad ( liftM, unless, when, mplus, guard )+import Text.Regex ( Regex, mkRegex, matchRegex, )+import Data.Char ( toUpper )+import Data.Maybe ( isNothing, isJust, catMaybes, listToMaybe )+import Data.List ( nub, isPrefixOf )+import System.Environment ( getEnv )++import Darcs.SlurpDirectory ( undefined_time )+import Darcs.Flags ( DarcsFlag( NoSetDefault, DryRun, Ephemeral, NoCompress, RemoteRepo ) )+import Darcs.Utils ( withCurrentDirectory, catchall, stripCr )+import Darcs.IO ( ReadableDirectory(..), WriteableDirectory(..) )+import FileName ( fp2fn )+import Darcs.Lock ( writeAtomicFilePS, gzWriteAtomicFilePS )+import Darcs.FilePathUtils ( unmake_relative )+import Darcs.URL ( is_file )+import Darcs.External ( gzFetchFilePS, fetchFilePS, speculateFileOrUrl, copyFileOrUrl,+                        Cachable( Cachable ) )+import Darcs.Progress ( progressList, debugMessage, debugFail )+import SHA1 ( sha1PS )+import Crypt.SHA256 ( sha256sum )+import FastPackedString ( PackedString, nilPS, unpackPS, gzWriteFilePS, lengthPS,+                          linesPS, dropPS )+import Darcs.Global ( darcsdir )+\end{code}++\section{prefs}++The \verb!_darcs! directory contains a \verb!prefs!  directory.  This+directory exists simply to hold user configuration settings specific to+this repository.  The contents of this directory are intended to be+modifiable by the user, although in some cases a mistake in such a+modification may cause darcs to behave strangely.++++\input{Darcs/ArgumentDefaults.lhs}++\begin{code}+write_default_prefs :: IO ()+write_default_prefs = do sequence_ [default_boring, default_binaries]+                         set_preflist "motd" []+\end{code}++\paragraph{repos}+The \verb!_darcs/prefs/repos! file contains a list of repositories you have+pulled from or pushed to, and is used for autocompletion of pull and push+commands in bash.  Feel free to delete any lines from this list that might+get in there, or to delete the file as a whole.++\paragraph{author}\label{author_prefs}+The \verb!_darcs/prefs/author! file contains the email address (or name) to+be used as the author when patches are recorded in this repository,+e.g.\ \verb!David Roundy <droundy@abridgegame.org>!.  This+file overrides the contents of the environment variables+\verb!$DARCS_EMAIL! and \verb!$EMAIL!.++\paragraph{boring}\label{boring}+The \verb!_darcs/prefs/boring! file may contain a list of regular+expressions describing files, such as object files, that you do not expect+to add to your project.  As an example, the boring file that I use with+my darcs repository is:+\begin{verbatim}+\.hi$+\.o$+^\.[^/]+^_+~$+(^|/)CVS($|/)+\end{verbatim}+A newly created repository has a longer boring file that+includes many common source control, backup, temporary, and compiled files.++You may want to have the boring file under version+control.  To do this you can use darcs setpref to set the value+``boringfile'' to the name of your desired boring file+(e.g.\ \verb-darcs setpref boringfile .boring-, where \verb-.boring-+is the repository path of a file+that has been+darcs added to your repository).  The boringfile preference overrides+\verb!_darcs/prefs/boring!, so be sure to copy that file to the boringfile.++You can also set up a ``boring'' regexps+file in your home directory, named \verb!~/.darcs/boring!, which will be+used with all of your darcs repositories.++Any file not already managed by darcs and whose repository path (such+as \verb!manual/index.html!) matches any of+the boring regular expressions is considered boring.  The boring file is+used to filter the files provided to darcs add, to allow you to use a+simple \verb-darcs add newdir newdir\/\*\-+without accidentally adding a bunch of+object files.  It is also used when the \verb!--look-for-adds! flag is+given to whatsnew or record.+Note that once a file has been added to darcs, it is not considered+boring, even if it matches the boring file filter.++\begin{code}+default_boring :: IO ()+default_boring = set_preflist "boring" $ "# Boring file regexps:" :+                 ["\\.hi$", "\\.hi-boot$", "\\.o-boot$", -- Haskell interfaces+                  "\\.o$","\\.o\\.cmd$", -- object files+                  "\\.p_hi$", "\\.p_o$", -- profiling Haskell+                  "\\.installed-pkg-config", "\\.setup-config",+                  "\\.setup-config^dist(/|$)", -- Cabal intermediates+                  "# *.ko files aren't boring by default because they might",+                  "# be Korean translations rather than kernel modules.",+                  "# \\.ko$",+                  "\\.ko\\.cmd$","\\.mod\\.c$",+                  "(^|/)\\.tmp_versions($|/)",+                  "(^|/)CVS($|/)","\\.cvsignore$", -- CVS+                  "^\\.#",              -- CVS, Emacs locks+                  "(^|/)RCS($|/)", ",v$", -- RCS+                  "(^|/)\\.svn($|/)",   -- Subversion admin directory+                  "(^|/)\\.hg($|/)", -- Mercurial+                  "(^|/)\\.git($|/)", -- Git+                  "\\.bzr$", "(^|/)SCCS($|/)", -- bzr, SCCS+                  "~$",                 -- Emacs (and other) backups+                  "(^|/)"++darcsdir++"($|/)", "(^|/)\\.darcsrepo($|/)", -- darcs admin directory+                  "\\.bak$","\\.BAK$",  -- editor backups(?)+                  "\\.orig$", "\\.rej$", -- patch originals and rejects+                  "(^|/)vssver\\.scc$",+                  "\\.swp$","(^|/)MT($|/)",+                  "(^|/)\\{arch\\}($|/)","(^|/).arch-ids($|/)", -- GNU Arch+                  "(^|/),","\\.prof$","(^|/)\\.DS_Store$",+                  "(^|/)BitKeeper($|/)","(^|/)ChangeSet($|/)",+                  -- Python, Emacs, Java byte code:+                  "\\.py[co]$", "\\.elc$","\\.class$",+                  -- Compiled ZSH configuration files+                  "\\.zwc$",+                  -- Gentoo tools can leave revdep files behind+                  "\\.revdep-rebuild.*",+                  -- X server spam+                  "\\..serverauth.*",+                  -- Image spam+                  "\\#", "(^|/)Thumbs\\.db$",+                  -- autotools stuff:+                  "(^|/)autom4te\\.cache($|/)", "(^|/)config\\.(log|status)$",+                  "^\\.depend$",        -- generated dependencies+                  "(^|/)(tags|TAGS)$",  -- vi, Emacs tags+                  "#(^|/)\\.[^/]",+                  "(^|/|\\.)core$",     -- core dumps+                  -- objects and libraries; lo and la are libtool things+                  "\\.(obj|a|exe|so|lo|la)$",+                  "^\\.darcs-temp-mail$", -- darcs editor file+                  "-darcs-backup[[:digit:]]+$", -- merge conflict backups+                  -- Common LISP output files for CLISP and CMUCL+                  "\\.(fas|fasl|sparcf|x86f)$",+                  "\\.part$", -- partial broken files (KIO copy operations)+                  -- WAF files. ( http://code.google.com/p/waf/ )+                  "(^|/)\\.waf-[[:digit:].]+-[[:digit:]]+($|/)",+                  "(^|/)\\.lock-wscript$",+                  "^\\.darcs-temp-mail$", -- darcs editor file+                  -- Microsoft Web Expression, Visual Studio metadata directories+                  "\\_vti_cnf$",+                  "\\_vti_pvt$"+                  ]++darcsdir_filter :: [FilePath] -> [FilePath]+darcsdir_filter = filter (not.is_darcsdir)+is_darcsdir :: FilePath -> Bool+is_darcsdir ('.':'/':f) = is_darcsdir f+is_darcsdir "." = True+is_darcsdir "" = True+is_darcsdir ".." = True+is_darcsdir "../" = True+is_darcsdir fp = darcsdir `isPrefixOf` fp+boring_file_filter :: IO ([FilePath] -> [FilePath])++get_global f = (getEnv "HOME" >>= get_preffile.(++("/.darcs/"++f)))+               `catchall` return []++boring_file_filter = do+    borefile <- def_prefval "boringfile" (darcsdir ++ "/prefs/boring")+    bores <- get_lines borefile `catchall` return []+    gbs <- get_global "boring"+    return $ actual_boring_file_filter $ map mkRegex (bores++gbs)++noncomments :: [String] -> [String]+noncomments ss = filter is_ok ss+                 where is_ok "" = False+                       is_ok ('#':_) = False+                       is_ok _ = True++get_lines :: ReadableDirectory m => FilePath -> m [String]+get_lines f = (notconflicts . noncomments . map stripCr . lines)+              `liftM` mReadBinFile (fp2fn f)+    where notconflicts = filter nc+          startswith [] _ = True+          startswith (x:xs) (y:ys) | x == y = startswith xs ys+          startswith _ _ = False+          nc l | startswith "v v v v v v v" l = False+          nc l | startswith "*************" l = False+          nc l | startswith "^ ^ ^ ^ ^ ^ ^" l = False+          nc _ = True++actual_boring_file_filter :: [Regex] -> [FilePath] -> [FilePath]+actual_boring_file_filter regexps fs =+    filter (abf (not.is_darcsdir) regexps . normalize) fs+    where+    abf fi (r:rs) = abf (\f -> fi f && isNothing (matchRegex r f)) rs+    abf fi [] = fi+\end{code}++\begin{code}+normalize :: FilePath -> FilePath+normalize ('.':'/':f) = normalize f+normalize f = normalize_helper $ reverse f+              where+              normalize_helper ('/':rf) = normalize_helper rf+              normalize_helper rf = reverse rf+\end{code}++\paragraph{binaries}+The \verb!_darcs/prefs/binaries! file may contain a list of regular+expressions describing files that should be treated as binary files rather+than text files. Darcs automatically treats files containing+\verb!^Z\! or \verb!'\0'! within the first 4096 bytes as being binary files.+You probably will want to have the binaries file under+version control.  To do this you can use darcs setpref to set the value+``binariesfile'' to the name of your desired binaries file+(e.g.\ \verb'darcs setpref binariesfile ./.binaries', where+\verb'.binaries' is a file that has been+darcs added to your repository).  As with the boring file, you can also set+up a \verb!~/.darcs/binaries! file if you like.++\begin{code}+data FileType = BinaryFile | TextFile+                deriving (Eq)+default_binaries :: IO ()+default_binaries =+    set_preflist "binaries" $ "# Binary file regexps:" :+                 ext_regexes ["png","gz","pdf","jpg","jpeg","gif","tif",+                              "tiff","pnm","pbm","pgm","ppm","bmp","mng",+                              "tar","bz2","z","zip","jar","so","a",+                              "tgz","mpg","mpeg","iso","exe","doc",+                              "elc", "pyc"]+    where ext_regexes exts = concat $ map ext_regex exts+          ext_regex e = ["\\."++e++"$", "\\."++map toUpper e++"$"]++filetype_function :: IO (FilePath -> FileType)+filetype_function = do+    binsfile <- def_prefval "binariesfile" (darcsdir ++ "/prefs/binaries")+    bins <- get_lines binsfile `catch`+             (\e-> if isDoesNotExistError e then return [] else ioError e)+    gbs <- get_global "binaries"+    regexes <- return (map (\r -> mkRegex r) (bins ++ gbs))+    let isbin f = or $ map (\r -> isJust $ matchRegex r f) regexes+        ftf f = if isbin $ normalize f then BinaryFile else TextFile+        in+        return ftf+\end{code}++\begin{code}+add_to_preflist :: WriteableDirectory m => String -> String -> m ()+get_preflist :: ReadableDirectory m => String -> m [String]+set_preflist :: WriteableDirectory m => String -> [String] -> m ()+get_global :: String -> IO [String]++set_defaultrepo :: String -> [DarcsFlag] -> IO ()+\end{code}++\begin{code}+-- this avoids a circular dependency with Repository+prefsDirectory :: ReadableDirectory m => m String+prefsDirectory =+    do darcs <- mDoesDirectoryExist $ fp2fn darcsdir+       if darcs+          then return $ darcsdir ++ "/prefs/"+          else fail $ "Directory " ++ darcsdir ++ "/ does not exist!"++withPrefsDirectory :: ReadableDirectory m => (String -> m ()) -> m ()+withPrefsDirectory j = do prefs <- prefsDirectory `mplus` return "x"+                          when (prefs /= "x") $ j prefs++add_to_preflist p s = withPrefsDirectory $ \prefs -> do+  hasprefs <- mDoesDirectoryExist $ fp2fn prefs+  unless hasprefs $ mCreateDirectory $ fp2fn prefs+  pl <- get_preflist p+  mWriteBinFile (fp2fn $ prefs ++ p) $ unlines $ add_to_list s pl+get_preflist p = do prefs <- prefsDirectory `mplus` return "x"+                    if (prefs /= "x") then get_preffile $ prefs ++ p+                                      else return []+get_preffile :: ReadableDirectory m => FilePath -> m [String]+get_preffile f = do+  hasprefs <- mDoesFileExist (fp2fn f)+  if hasprefs+    then get_lines f+    else return []+set_preflist p ls = withPrefsDirectory $ \prefs -> do+  haspref <- mDoesDirectoryExist $ fp2fn prefs+  if haspref+     then mWriteBinFile (fp2fn $ prefs ++ p) (unlines ls)+     else return ()++add_to_list :: Eq a => a -> [a] -> [a]+add_to_list s [] = [s]+add_to_list s (s':ss) = if s == s' then (s:ss) else s': add_to_list s ss+\end{code}++\begin{code}+set_prefval :: WriteableDirectory m => String -> String -> m ()+get_prefval :: ReadableDirectory m => String -> m (Maybe String)+def_prefval :: String -> String -> IO String+def_prefval p d = do+  pv <- get_prefval p+  case pv of Nothing -> return d+             Just v -> return v+get_prefval p =+    do pl <- get_preflist "prefs"+       case map snd $ filter ((==p).fst) $ map (break (==' ')) pl of+           [val] -> case words val of+               [] -> return Nothing+               _ -> return $ Just $ tail val+           _ -> return Nothing+set_prefval p v = do pl <- get_preflist "prefs"+                     set_preflist "prefs" $+                       filter ((/=p).fst.(break (==' '))) pl ++ [p++" "++v]+change_prefval :: WriteableDirectory m => String -> String -> String -> m ()+change_prefval p f t =+    do pl <- get_preflist "prefs"+       ov <- get_prefval p+       newval <- case ov of+                 Nothing -> return t+                 Just old -> if old == f then return t else return old+       set_preflist "prefs" $+                    filter ((/=p).fst.(break(==' '))) pl ++ [p++" "++newval]+\end{code}++\begin{code}+defaultrepo :: [DarcsFlag] -> FilePath -> [String] -> IO [String]+defaultrepo opts fix [] =+ case [r | RemoteRepo r <- opts] of+   [] -> do defrepo <- get_preflist "defaultrepo"+            case defrepo of+              [r] -> return [unmake_relative fix r]+              _ -> return []+   (r:_) -> return [unmake_relative fix r]+defaultrepo _ _ r = return r+set_defaultrepo r opts = do doit <- if (NoSetDefault `notElem` opts && DryRun `notElem` opts && r_is_not_tmp)+                                    then return True+                                    else do olddef <-+                                                get_preflist "defaultrepo"+                                            return (olddef == [])+                            when doit+                                (set_preflist "defaultrepo" [r])+                            add_to_preflist "repos" r+                         `catchall` return () -- we don't care if this fails!+ where+  r_is_not_tmp = not $ r `elem` [x | RemoteRepo x <- opts]+\end{code}++\paragraph{email}+The \verb!_darcs/prefs/email! file is used to provide the e-mail address for your+repository that others will use when they \verb!darcs send! a patch back to you.+The contents of the file should simply be an e-mail address.++\begin{code}+data WritableOrNot = Writable | NotWritable deriving ( Show )+data CacheType = Repo | Directory deriving ( Eq, Show )+data CacheLoc = Cache !CacheType !WritableOrNot !String+newtype Cache = Ca [CacheLoc] -- abstract type for hiding cache++instance Eq CacheLoc where+    (Cache Repo _ a) == (Cache Repo _ b) = a == b+    (Cache Directory _ a) == (Cache Directory _ b) = a == b+    _ == _ = False+instance Show CacheLoc where+    show (Cache Repo Writable a) = "thisrepo:" ++ a+    show (Cache Repo NotWritable a) = "repo:" ++ a+    show (Cache Directory Writable a) = "cache:" ++ a+    show (Cache Directory NotWritable a) = "readonly:" ++ a+instance Show Cache where+    show (Ca cs) = unlines $ map show cs++unionCaches :: Cache -> Cache -> Cache+unionCaches (Ca a) (Ca b) = Ca (nub (a++b))++repo2cache :: String -> Cache+repo2cache r = Ca [Cache Repo NotWritable r]++okayHash :: String -> Bool+okayHash s = length s == 40 || length s == 64 || length s == 75++takeHash :: PackedString -> Maybe (String, PackedString)+takeHash ps = do h <- listToMaybe $ linesPS ps+                 guard $ okayHash $ unpackPS h+                 Just (unpackPS h, dropPS (lengthPS h) ps)++checkHash :: String -> PackedString -> Bool+checkHash h s | length h == 40 = sha1PS s == h+              | length h == 64 = sha256sum s == h+              | length h == 75 = lengthPS s == read (take 10 h) && sha256sum s == drop 11 h+              | otherwise = False++getCaches :: [DarcsFlag] -> String -> IO Cache+getCaches opts repodir =+    do here <- parsehs `fmap` get_preffile (darcsdir ++ "/prefs/sources")+       there <- (parsehs . lines . unpackPS) `fmap`+                (gzFetchFilePS (repodir ++ "/" ++ darcsdir ++ "/prefs/sources") Cachable+                 `catchall` return nilPS)+       maincache <- parsehs `fmap` get_global "sources"+       thisdir <- getCurrentDirectory+       let thisrepo = if Ephemeral `elem` opts+                      then [Cache Repo NotWritable thisdir]+                      else [Cache Repo Writable thisdir]+       return $ Ca $ nub $ thisrepo ++ maincache ++ here +++                  [Cache Repo NotWritable repodir] ++ there+      where parsehs = catMaybes . map readln . noncomments+            readln l | take 5 l == "repo:" = Just (Cache Repo NotWritable (drop 5 l))+                     | take 9 l == "thisrepo:" = Just (Cache Repo Writable (drop 9 l))+                     | take 6 l == "cache:" = Just (Cache Directory Writable (drop 6 l))+                     | take 9 l == "readonly:" = Just (Cache Directory NotWritable (drop 9 l))+                     | otherwise = Nothing++findFileMtimeUsingCache :: Cache -> String -> String -> IO EpochTime+findFileMtimeUsingCache (Ca cache) subdir f = mt cache+    where mt [] = return undefined_time+          mt (Cache Repo Writable r:_) = (modificationTime `fmap`+                                          getSymbolicLinkStatus (r++"/"++darcsdir++"/"++subdir++"/"++f))+                                         `catchall` return undefined_time+          mt (_:cs) = mt cs++setFileMtimeUsingCache :: Cache -> String -> String -> EpochTime -> IO ()+setFileMtimeUsingCache (Ca cache) subdir f t = st cache+    where st [] = return ()+          st (Cache Repo Writable r:_) = setFileTimes (r++"/"++darcsdir++"/"++subdir++"/"++f) t t+                                         `catchall` return ()+          st (_:cs) = st cs++fetchFileUsingCache :: Cache -> String -> String -> IO (String, PackedString)+fetchFileUsingCache = fetchFileUsingCachePrivate Anywhere++peekInCache :: Cache -> String -> String -> IO Bool+peekInCache (Ca cache) subdir f = cacheHasIt cache `catchall` return False+    where cacheHasIt [] = return False+          cacheHasIt (Cache _ NotWritable _:cs) = cacheHasIt cs+          cacheHasIt (Cache t Writable d:cs) = do ex <- doesFileExist (fn t d)+                                                  if ex then return True+                                                        else cacheHasIt cs+          fn Directory d = d ++ "/" ++ subdir ++ "/" ++ f+          fn Repo r = r ++ "/"++darcsdir++"/" ++ subdir ++ "/" ++ f++speculateFileUsingCache :: Cache -> String -> String -> IO ()+speculateFileUsingCache c sd h = do debugMessage $ "Speculating on "++h+                                    copyFileUsingCache OnlySpeculate c sd h++data OrOnlySpeculate = ActuallyCopy | OnlySpeculate deriving ( Eq )++copyFileUsingCache :: OrOnlySpeculate -> Cache -> String -> String -> IO ()+copyFileUsingCache oos (Ca cache) subdir f =+    do debugMessage $ "I'm doing copyFileUsingCache on "++subdir++"/"++f+       Just stickItHere <- cacheLoc cache+       createDirectoryIfMissing False (reverse $ dropWhile (/='/') $ reverse stickItHere)+       sfuc cache stickItHere+    `catchall` return ()+    where cacheLoc [] = return Nothing+          cacheLoc (Cache _ NotWritable _:cs) = cacheLoc cs+          cacheLoc (Cache t Writable d:cs) =+              do ex <- doesFileExist (fn t d)+                 if ex then fail "Bug in darcs: This exception should be caught in speculateFileUsingCache"+                       else do othercache <- cacheLoc cs+                               case othercache of Just x -> return $ Just x+                                                  Nothing -> return $ Just (fn t d)+          sfuc [] _ = return ()+          sfuc (Cache t NotWritable d:_) out = if oos == OnlySpeculate+                                               then speculateFileOrUrl (fn t d) out+                                               else copyFileOrUrl [] (fn t d) out Cachable+          sfuc (_:cs) out = sfuc cs out+          fn Directory d = d ++ "/" ++ subdir ++ "/" ++ f+          fn Repo r = r ++ "/"++darcsdir++"/" ++ subdir ++ "/" ++ f+++data FromWhere = LocalOnly | Anywhere deriving ( Eq )++fetchFileUsingCachePrivate :: FromWhere -> Cache -> String -> String -> IO (String, PackedString)+fetchFileUsingCachePrivate fromWhere (Ca cache) subdir f =+    do when (fromWhere == Anywhere) $ copyFileUsingCache ActuallyCopy (Ca cache) subdir f+       ffuc cache+    `catchall` debugFail ("Couldn't fetch `"++f++"'\nin subdir "++subdir+++                          " from sources:\n\n"++show (Ca cache))+    where ffuc (Cache t NotWritable d:cs)+              | Anywhere == fromWhere || is_file (fn t d) =+              do debugMessage $ "In fetchFileUsingCachePrivate I'm going manually"+                 debugMessage $ "    getting "++f+                 debugMessage $ "    from "++fn t d+                 x <- gzFetchFilePS (fn t d) Cachable+                 if not $ checkHash f x+                    then do x' <- fetchFilePS (fn t d) Cachable+                            when (not $ checkHash f x') $+                                 do hPutStrLn stderr $ "Hash failure in "++d++" of hash "++f+                                    fail $ "Hash failure in "++d++" of hash "++f+                            return (fn t d, x')+                    else return (fn t d, x) -- FIXME: create links in caches+              `catchall` ffuc cs+          ffuc (Cache t Writable d:cs) =+              do x1 <- gzFetchFilePS (fn t d) Cachable+                 x <- if not $ checkHash f x1+                      then do x2 <- fetchFilePS (fn t d) Cachable+                              when (not $ checkHash f x2) $+                                 do hPutStrLn stderr $ "Hash failure in "++d++" of hash "++f+                                    removeFile (fn t d)+                                    fail $ "Hash failure in "++d++" of hash "++f+                              return x2+                      else return x1+                 mapM_ (tryLinking (fn t d)) cs+                 return (fn t d, x)+              `catchall` do (fname,x) <- ffuc cs+                            do createCache t d subdir+                               createLink fname (fn t d)+                               return (fn t d, x)+                             `catchall`+                             do gzWriteFilePS (fn t d) x `catchall` return ()+                                return (fname,x)+          ffuc (_:cs) = ffuc cs+          ffuc [] = debugFail $ "No sources from which to fetch file `"++f++"'\n"++ show (Ca cache)+          tryLinking ff (Cache Directory Writable d) =+              do createDirectoryIfMissing False (d++"/"++subdir)+                 createLink ff (fn Directory d)+              `catchall` return ()+          tryLinking _ _ = return ()+          fn Directory d = d ++ "/" ++ subdir ++ "/" ++ f+          fn Repo r = r ++ "/"++darcsdir++"/" ++ subdir ++ "/" ++ f++createCache :: CacheType -> String -> String -> IO ()+createCache Directory d subdir = createDirectoryIfMissing True (d ++ "/" ++ subdir)+createCache _ _ _ = return ()++writeFileUsingCache :: Cache -> [DarcsFlag] -> String -> PackedString -> IO String+writeFileUsingCache (Ca cache) opts subdir ps =+    (fetchFileUsingCachePrivate LocalOnly (Ca cache) subdir hash >> return hash) `catchall`+    wfuc cache `catchall`+         debugFail ("Couldn't write `"++hash++"'\nin subdir "++subdir++" to sources:\n\n"+++                    show (Ca cache))+    where hash = case show (lengthPS ps) of+                 x | l > 10 -> sha256sum ps+                   | otherwise -> take (10-l) (repeat '0') ++ x ++'-':sha256sum ps+                                        where l = length x+          wfuc (Cache _ NotWritable _:cs) = wfuc cs+          wfuc (Cache t Writable d:_) =+              do createCache t d subdir+                 if NoCompress `elem` opts+                    then writeAtomicFilePS (fn t d) ps -- FIXME: create links in caches+                    else gzWriteAtomicFilePS (fn t d) ps -- FIXME: create links in caches+                 return hash+          wfuc [] = debugFail $ "No location to write file `" ++ subdir ++"/"++hash ++ "'"+          fn Directory d = d ++ "/" ++ subdir ++ "/" ++ hash+          fn Repo r = r ++ "/"++darcsdir++"/" ++ subdir ++ "/" ++ hash++cleanCaches :: Cache -> String -> IO ()+cleanCaches (Ca cs) subdir = mapM_ cleanCache cs+    where cleanCache (Cache Directory Writable d) =+             (withCurrentDirectory (d++"/"++subdir) $+              do fs <- getDirectoryContents "."+                 mapM_ clean $ progressList ("Cleaning cache "++d++"/"++subdir) $+                       filter okayHash fs) `catchall` return ()+          cleanCache _ = return ()+          clean f = do lc <- linkCount `liftM` getSymbolicLinkStatus f+                       when (lc < 2) $ removeFile f+                    `catchall` return ()++\end{code}++\paragraph{sources}+The \verb!_darcs/prefs/sources! file is used to indicate alternative+locations from which to download patches when using a ``hashed''+repository.  This file contains lines such as:+\begin{verbatim}+cache:/home/droundy/.darcs/cache+readonly:/home/otheruser/.darcs/cache+repo:http://darcs.net+\end{verbatim}+This would indicate that darcs should first look in+\verb!/home/droundy/.darcs/cache! for patches that might be missing, and if+the patch isn't there, it should save a copy there for future use.  In that+case, darcs will look in \verb!/home/otheruser/.darcs/cache! to see if that+user might have downloaded a copy, but won't try to save a copy there, of+course.  Finally, it will look in \verb!http://darcs.net!.  Note that the+\verb!sources! file can also exist in \verb!~/.darcs/!.  Also note that the+sources mentioned in your \verb!sources! file will be tried \emph{before}+the repository you are pulling from.  This can be useful in avoiding+downloading patches multiple times when you pull from a remote repository+to more than one local repository.++We strongly advise that you enable a global cache directory, which will+allow darcs to avoid re-downloading patches (for example, when doing a+second darcs get of the same repository), and also allows darcs to use hard+links to reduce disk usage.  To do this, simply+\begin{verbatim}+mkdir -p $HOME/.darcs/cache+echo cache:$HOME/.darcs/cache > $HOME/.darcs/sources+\end{verbatim}+Note that the cache directory should reside on the same filesystem as your+repositories, so you may need to vary this.  You can also use multiple+cache directories on different filesystems, if you have several filesystems+on which you use darcs.
+ src/Darcs/Repository/Pristine.lhs view
@@ -0,0 +1,200 @@+%  Copyright (C) 2002-2005 David Roundy+%  Copyright (C) 2004 Juliusz Chroboczek+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.Repository.Pristine ( Pristine, flagsToPristine, nopristine,+                 createPristine, removePristine, identifyPristine,+                 checkPristine, slurpPristine,+                 applyPristine, createPristineFromWorking,+                 syncPristine, replacePristine, getPristinePop,+                 pristineDirectory, pristineToFlagString,+                 easyCreatePristineDirectoryTree,+                 easyCreatePartialsPristineDirectoryTree+               ) where++import Data.Maybe ( isJust )+import Control.Monad ( when, liftM )+import System.Directory ( createDirectory, doesDirectoryExist, doesFileExist,+                   renameDirectory, removeFile )+import Darcs.Lock ( rm_recursive, writeBinFile )+import Darcs.Diff ( cmp, sync )+import Workaround ( getCurrentDirectory )+import Darcs.SlurpDirectory ( Slurpy,  mmap_slurp, co_slurp )+import Darcs.Utils ( catchall )++import Darcs.PopulationData ( Population, getPopFrom )+import Darcs.Flags ( DarcsFlag( PristinePlain, PristineNone, UseHashedInventory, UseFormat2 ) )+import Darcs.IO ( WriteableDirectory(mWithCurrentDirectory) )+import Darcs.Patch ( Patchy, apply )+import Darcs.Patch.Info ( PatchInfo )+import FileName ( fp2fn )+import FastPackedString ( nilPS )+import SHA1 ( sha1PS )+import Darcs.External ( cloneTree, cloneTreeExcept, clonePartialsTree )+import Darcs.Repository.InternalTypes ( Pristine(..) )+import Darcs.Global ( darcsdir )+#include "impossible.h"++nopristine :: Pristine+nopristine = NoPristine "aack?"++pristineName :: String+pristineName = "pristine"++identifyPristine :: IO (Pristine)+identifyPristine = do mp <- reallyIdentifyPristine+                      case mp of+                          Nothing -> fail "Pristine tree doesn't exist."+                          Just pristine -> return pristine++reallyIdentifyPristine :: IO (Maybe Pristine)+reallyIdentifyPristine = +    do dir <- findpristine doesDirectoryExist ""+       none <- findpristine doesFileExist ".none"+       hashinv <- doesFileExist $ darcsdir++"/hashed_inventory"+       hashpris <- doesDirectoryExist hashedPristineDirectory+       case (dir, none, hashinv && hashpris) of+           (Nothing, Nothing, False) -> return Nothing+           (Just n, Nothing, False) ->+               return (Just (PlainPristine n))+           (Nothing, Just n, False) ->+               return (Just (NoPristine n))+           (Nothing, Nothing, True) ->+               return (Just HashedPristine)+           _ -> fail "Multiple pristine trees."+    where findpristine fn ext =+              do e1 <- fn n1+                 e2 <- fn n2+                 case (e1, e2) of+                     (False, False) -> return Nothing+                     (True, False) -> return (Just n1)+                     (False, True) -> return (Just n2)+                     (True, True) -> fail "Multiple pristine trees."+              where  n1 = darcsdir++"/pristine" ++ ext+                     n2 = darcsdir++"/current" ++ ext++flagsToPristine :: [DarcsFlag] -> Pristine+flagsToPristine fs | UseFormat2 `elem` fs || UseHashedInventory `elem` fs = HashedPristine+flagsToPristine (PristineNone : _) = NoPristine (darcsdir++"/" ++ pristineName ++ ".none")+flagsToPristine (PristinePlain : _) = PlainPristine (darcsdir++"/" ++ pristineName)+flagsToPristine (_ : t) = flagsToPristine t+flagsToPristine [] = flagsToPristine [PristinePlain]++createPristine :: Pristine -> IO Pristine+createPristine p = +    do oldpristine <- reallyIdentifyPristine+       when (isJust oldpristine) $ fail "Pristine tree already exists."+       case p of+           NoPristine n -> writeBinFile n "Do not delete this file.\n"+           PlainPristine n -> createDirectory n+           HashedPristine -> do createDirectory hashedPristineDirectory+                                writeFile (hashedPristineDirectory++"/"++sha1PS nilPS) ""+       return p++hashedPristineDirectory :: String+hashedPristineDirectory = darcsdir++"/pristine.hashed"++removePristine :: Pristine -> IO ()+removePristine (NoPristine n) = removeFile n+removePristine (PlainPristine n) = rm_recursive n+removePristine HashedPristine = rm_recursive hashedPristineDirectory++checkPristine :: FilePath -> Pristine -> IO Bool+checkPristine _ (NoPristine _) = return True+checkPristine path (PlainPristine n) = do cwd <- getCurrentDirectory+                                          cmp (cwd ++ "/" ++ n) path+checkPristine _ HashedPristine = +    bug "HashedPristine is not implemented yet."++slurpPristine :: Pristine -> IO (Maybe Slurpy)+slurpPristine (PlainPristine n) = do cwd <- getCurrentDirectory+                                     slurpy <- mmap_slurp (cwd ++ "/" ++ n)+                                     return (Just slurpy)+slurpPristine (NoPristine _) = return Nothing+slurpPristine HashedPristine =+    bug "HashedPristine is not implemented yet."++applyPristine :: Patchy p => Pristine -> p C(x y) -> IO ()+applyPristine (NoPristine _) _ = return ()+-- We don't need flags for now, since we don't care about+-- SetScriptsExecutable for the pristine cache.+applyPristine (PlainPristine n) p =+    mWithCurrentDirectory (fp2fn n) $ apply [] p+applyPristine HashedPristine _ =+    bug "3 HashedPristine is not implemented yet."++createPristineFromWorking :: Pristine -> IO ()+createPristineFromWorking (NoPristine _) = return ()+createPristineFromWorking (PlainPristine n) = cloneTreeExcept [darcsdir] "." n+createPristineFromWorking HashedPristine =+    bug "HashedPristine is not implemented yet."++syncPristine :: Pristine -> IO ()+syncPristine (NoPristine _) = return ()+syncPristine (PlainPristine n) =+    do ocur <- mmap_slurp n+       owork <- co_slurp ocur "."+       sync n ocur owork+syncPristine HashedPristine = return () -- FIXME this should be implemented!++replacePristine :: FilePath -> Pristine -> IO ()+replacePristine _ (NoPristine _) = return ()+replacePristine newcur (PlainPristine n) =+    do rm_recursive nold+           `catchall` return ()+       renameDirectory n nold+       renameDirectory newcur n+       return ()+           where nold = darcsdir ++ "/" ++ pristineName ++ "-old"+replacePristine _ HashedPristine =+    bug "HashedPristine is not implemented yet."++getPristinePop :: PatchInfo -> Pristine -> IO (Maybe Population)+getPristinePop pinfo (PlainPristine n) =+    Just `liftM` getPopFrom n pinfo+getPristinePop _ _ = return Nothing++pristineDirectory :: Pristine -> Maybe String+pristineDirectory (PlainPristine n) = Just n+pristineDirectory _ = Nothing++pristineToFlagString :: Pristine -> String+pristineToFlagString (NoPristine _) = "--no-pristine-tree"+pristineToFlagString (PlainPristine _) = "--plain-pristine-tree"+pristineToFlagString HashedPristine =+    bug "HashedPristine is not implemented yet."++easyCreatePristineDirectoryTree :: Pristine -> FilePath -> IO Bool+easyCreatePristineDirectoryTree (NoPristine _) _ = return False+easyCreatePristineDirectoryTree (PlainPristine n) p+ = cloneTree n p >> return True+easyCreatePristineDirectoryTree HashedPristine _ =+    bug "HashedPristine is not implemented yet."++easyCreatePartialsPristineDirectoryTree :: [FilePath] -> Pristine -> FilePath+                                        -> IO Bool+easyCreatePartialsPristineDirectoryTree _ (NoPristine _) _ = return False+easyCreatePartialsPristineDirectoryTree prefs (PlainPristine n) p+ = clonePartialsTree n p prefs >> return True+easyCreatePartialsPristineDirectoryTree _ HashedPristine _ =+    bug "HashedPristine is not implemented yet."+\end{code}+
+ src/Darcs/Resolution.lhs view
@@ -0,0 +1,237 @@+%  Copyright (C) 2003,2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+#include "gadts.h"+module Darcs.Resolution ( standard_resolution,+                          external_resolution,+                          patchset_conflict_resolutions,+                        ) where++import System.Exit ( ExitCode( ExitSuccess ) )+import System.Directory ( setCurrentDirectory, getCurrentDirectory )+import Data.List ( zip4 )+import Control.Monad ( when )++import Darcs.Patch ( RepoPatch, Prim, joinPatches, resolve_conflicts,+                     effect,+                     apply_to_filepaths, patchcontents,+                     invert, list_conflicted_files, commute )+import Darcs.Patch.Ordered ( FL(..), RL(..), (:>)(..), (+>+),+                             mapFL_FL, reverseRL, lengthFL )++import CommandLine ( parseCmd )+import Darcs.Hopefully ( hopefully )+import Darcs.Utils ( askUser )+import Darcs.SlurpDirectory ( Slurpy, slurp, write_files )+import Darcs.Patch.Set ( PatchSet )+import Darcs.Diff ( smart_diff )+import Darcs.Sealed ( Sealed(..) )+import Darcs.Repository.Prefs ( filetype_function )+import Darcs.Flags ( DarcsFlag(LookForAdds) )+import Exec ( exec, Redirect(..) )+import Darcs.Lock ( withTempDir )+import Darcs.External ( cloneTree )+import Darcs.Patch.Apply ( apply_to_slurpy )++--import Darcs.ColorPrinter ( traceDoc )+--import Printer ( greenText, ($$), Doc )+--import Darcs.Patch ( showPatch )+\end{code}++\begin{code}+standard_resolution :: RepoPatch p => p C(x y) -> Sealed (FL Prim C(y))+standard_resolution p = merge_list $ map head $ resolve_conflicts p++merge_list :: [Sealed (FL Prim C(x))] -> Sealed (FL Prim C(x))+merge_list patches = doml NilFL patches+    where doml :: FL Prim C(x y) -> [Sealed (FL Prim C(x))] -> Sealed (FL Prim C(x))+          doml mp (Sealed p:ps) =+              case commute (invert p :> mp) of+              Just (mp' :> _) -> doml (effect p +>+ effect mp') ps+              Nothing -> doml mp ps -- This shouldn't happen for "good" resolutions.+          doml mp [] = Sealed mp+\end{code}++\paragraph{Resolution of conflicts}\label{resolution}++To resolve conflicts using an external tool, you need to specify a command+to use, e.g.+\begin{verbatim}+--external-merge 'opendiff %1 %2 -ancestor %a -merge %o'+\end{verbatim}+The \verb!%1! and \verb!%2!  are replaced with the two versions to be+merged, \verb!%a! is replaced with the common ancestor of the two versions.+Most importantly, \verb!%o! is replaced with the name of the output file+that darcs will require to be created holding the merged version.  The+above example works with the FileMerge.app tool that comes with Apple's+developer tools.  To use xxdiff, you would use+\begin{verbatim}+--external-merge 'xxdiff -m -O -M %o %1 %a %2'+\end{verbatim}+To use \verb!kdiff3!, you can use+\begin{verbatim}+--external-merge 'kdiff3 --output %o %a %1 %2'+\end{verbatim}+To use \verb!tortoiseMerge!, you can use+\begin{verbatim}+--external-merge 'tortoiseMerge /base:"%a" /mine:"%1" /theirs:"%2" /merged:"%o"'+\end{verbatim}+(\verb!tortoiseMerge! is a nice merge tool that comes with TortoiseSVN and works well+on Windows.)++% Fixme: Is it actually a shell command on MS Windows?+Note that the command is split into space-separated words and the first one is+\verb!exec!ed with the rest as arguments---it is not a shell command. In particular,+on Windows this means that the first command path should not contain spaces and+you should make sure the command is in your \verb!PATH!. ++The substitution of the \verb!%! escapes is done everywhere. If you need to prevent+substitution you can use a double percentage sign, i.e. \verb!%%a! is substituted with+\verb!%a!. Here is an example script to use the Emacs' Ediff package for merging.+% This is indented so that the leading #s don't confuse the preprocessor.+\begin{verbatim}+ #! /bin/sh+ # External merge command for darcs, using Emacs Ediff, via server if possible.+ # It needs args %1 %2 %a %o, i.e. the external merge command is, say,+ # `emerge3 %1 %2 %a %o'.+ test $# -eq 4 || exit 1+ form="(ediff-merge-files-with-ancestor"+ while test $# -gt 0; do+     count=$count.+     if [ $count = .... ]; then+         form=$form\ nil         # Lisp STARTUP-HOOKS arg+     fi+     case $1 in                  # Worry about quoting -- escape " and \+         *[\"\\]* ) form=$form\ \"$(echo $1 | sed -e's/["\\]/\\\0/g')\" ;;+         *) form=$form\ \"$1\" ;;+     esac+     shift+ done+ form=$form')'+ ( emacsclient --eval "$form" || # Emacs 22 server+   gnudoit "$form" ||            # XEmacs/Emacs 21 server+   emacs --eval "$form" ||       # Relatively slow to start up+   xemacs -eval "$form"          # Horribly slow to start up+ ) 2>/dev/null+\end{verbatim}+It would be invoked like:+\begin{verbatim}+--external-merge 'emerge3 %1 %2 %a %o'+\end{verbatim}++If you figure out how to use darcs with another merge tool, please let me+know what flags you used so I can mention it here.++Note that if you do use an external merge tool, most likely you will want+to add to your defaults file+(\verb!_darcs/prefs/defaults! or \verb!~/.darcs/prefs!, see \ref{defaults})+a line such as+\begin{verbatim}+ALL external-merge kdiff3 --output %o %a %1 %2+\end{verbatim}+or+\begin{verbatim}+ALL external-merge tortoiseMerge /base:"%a" /mine:"%1" /theirs:"%2" /merged:"%o"+\end{verbatim}++Note that the defaults file does not want quotes around the command.++\begin{code}+external_resolution :: RepoPatch p => Slurpy -> String -> FL Prim C(x y) -> FL Prim C(x z)+                    -> p C(x a)+                    -> IO (Sealed (FL Prim C(x)))+external_resolution s1 c p1 p2 pmerged = do+ sa <- apply_to_slurpy (invert p1) s1+ sm <- apply_to_slurpy pmerged s1+ s2 <- apply_to_slurpy p2 sa+ let nms = list_conflicted_files pmerged+     nas = apply_to_filepaths (invert pmerged) nms+     n1s = apply_to_filepaths p1 nas+     n2s = apply_to_filepaths p2 nas+     ns = zip4 nas n1s n2s nms+  in do+   former_dir <- getCurrentDirectory+   withTempDir "version1" $ \d1 -> do+     write_files s1 n1s+     setCurrentDirectory former_dir+     withTempDir "ancestor" $ \da -> do+       write_files sa nas+       setCurrentDirectory former_dir+       withTempDir "merged" $ \dm -> do+         write_files sm nms+         setCurrentDirectory former_dir+         withTempDir "cleanmerged" $ \dc -> do+           cloneTree dm "."+           setCurrentDirectory former_dir+           withTempDir "version2" $ \d2 -> do+             write_files s2 n2s+             mapM_ (externally_resolve_file c da d1 d2 dm) ns+             sc <- slurp dc+             sfixed <- slurp dm+             ftf <- filetype_function+             case smart_diff [LookForAdds] ftf sc sfixed of+               di -> lengthFL di `seq` return (Sealed di)+               -- The `seq` above forces the two slurpies to be read before+               -- we delete their directories.++externally_resolve_file :: String -> String -> String -> String -> String+                        -> (FilePath, FilePath, FilePath, FilePath)+                        -> IO ()+externally_resolve_file c da d1 d2 dm (fa, f1, f2, fm) = do+    putStrLn $ "Merging file "++fm++" by hand."+    ec <- run c [('1', d1///f1), ('2', d2///f2), ('a', da///fa), ('o', dm///fm), ('%', "%")]+    when (ec /= ExitSuccess) $+         putStrLn $ "External merge command exited with " ++ show ec+    askUser "Hit return to move on..."+    return ()++run :: String -> [(Char,String)] -> IO ExitCode+run c replacements =+    case parseCmd replacements c of+    Left err     -> fail $ show err+    Right (c2,_) -> rr c2+    where rr (command:args) = do putStrLn $ "Running command '" +++                                            unwords (command:args) ++ "'"+                                 exec command args (Null,Null,Null)+          rr [] = return ExitSuccess++(///) :: FilePath -> FilePath -> FilePath+d /// f = d ++ "/" ++ f+\end{code}++\begin{code}+patchset_conflict_resolutions :: RepoPatch p => PatchSet p C(x) -> Sealed (FL Prim C(x))+patchset_conflict_resolutions (NilRL:<:_) = --traceDoc (greenText "no conflicts A") $+                                            Sealed NilFL+patchset_conflict_resolutions NilRL = --traceDoc (greenText "no conflicts B") $+                                      Sealed NilFL+patchset_conflict_resolutions (xs:<:_)+    = --traceDoc (greenText "looking at resolutions" $$+      --         (sh $ resolve_conflicts $ joinPatches $+      --              mapFL_FL (patchcontents . hopefully) $ reverseRL xs )) $+      merge_list $ map head $ resolve_conflicts $ joinPatches $+      mapFL_FL (patchcontents . hopefully) $ reverseRL xs+    --where sh :: [[Sealed (FL Prim)]] -> Doc+    --      sh [] = greenText "no more conflicts"+    --      sh (x:ps) = greenText "one conflict" $$ sh1 x $$ sh ps+    --      sh1 :: [Sealed (FL Prim)] -> Doc+    --      sh1 [] = greenText "end of unravellings"+    --      sh1 (Sealed x:ps) = greenText "one unravelling:" $$ showPatch x $$+    --                          sh1 ps+\end{code}
+ src/Darcs/Sealed.lhs view
@@ -0,0 +1,96 @@+%  Copyright (C) 2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+#include "gadts.h"+module Darcs.Sealed ( Sealed(..), seal, unseal, mapSeal,+#ifndef GADT_WITNESSES+                      unsafeUnseal, unsafeUnflippedseal,+#endif+                      Sealed2(..), seal2, unseal2, mapSeal2,+                      FlippedSeal(..), flipSeal, unsealFlipped,+                      unsealM, liftSM+                    ) where++import GHC.Base ( unsafeCoerce# )+import Darcs.Show++data Sealed a where+    Sealed :: a C(x ) -> Sealed a++seal :: a C(x ) -> Sealed a+seal = Sealed++data Sealed2 a where+    Sealed2 :: !(a C(x y )) -> Sealed2 a++seal2 :: a C(x y ) -> Sealed2 a+seal2 = Sealed2++data FlippedSeal a C(y) where+    FlippedSeal :: !(a C(x y)) -> FlippedSeal a C(y)++flipSeal :: a C(x y) -> FlippedSeal a C(y)+flipSeal = FlippedSeal++#ifndef GADT_WITNESSES+unsafeUnseal :: Sealed a -> a+unsafeUnseal (Sealed a) = a++unsafeUnflippedseal :: FlippedSeal a -> a+unsafeUnflippedseal (FlippedSeal a) = a+#endif++seriouslyUnsafeUnseal :: Sealed a -> a C(())+seriouslyUnsafeUnseal (Sealed a) = unsafeCoerce# a++unseal :: (FORALL(x) a C(x ) -> b) -> Sealed a -> b+unseal f x = f (seriouslyUnsafeUnseal x)++-- laziness property:+-- unseal (const True) undefined == True++unsealM :: Monad m => m (Sealed a) -> (FORALL(x) a C(x) -> m b) -> m b+unsealM m1 m2 = do sx <- m1+                   unseal m2 sx++liftSM :: Monad m => (FORALL(x) a C(x) -> b) -> m (Sealed a) -> m b+liftSM f m = do sx <- m+                return (unseal f sx)++mapSeal :: (FORALL(x) a C(x ) -> b C(x )) -> Sealed a -> Sealed b+mapSeal f = unseal (seal . f)++seriouslyUnsafeUnseal2 :: Sealed2 a -> a C(() ())+seriouslyUnsafeUnseal2 (Sealed2 a) = unsafeCoerce# a++unseal2 :: (FORALL(x y) a C(x y ) -> b) -> Sealed2 a -> b+unseal2 f a = f (seriouslyUnsafeUnseal2 a)++mapSeal2 :: (FORALL(x y) a C(x y ) -> b C(x y )) -> Sealed2 a -> Sealed2 b+mapSeal2 f = unseal2 (seal2 . f)++unsealFlipped :: (FORALL(x y) a C(x y) -> b) -> FlippedSeal a C(z) -> b+unsealFlipped f (FlippedSeal a) = f a++instance Show1 a => Show (Sealed a) where+    showsPrec d (Sealed x) = showParen (d > app_prec) $ showString "Sealed " . showsPrec1 (app_prec + 1) x+instance Show2 a => Show (Sealed2 a) where+    showsPrec d (Sealed2 x) = showParen (d > app_prec) $ showString "Sealed2 " . showsPrec2 (app_prec + 1) x++\end{code}
+ src/Darcs/SelectChanges.lhs view
@@ -0,0 +1,504 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -cpp -fffi -fglasgow-exts #-}+#include "gadts.h"+module Darcs.SelectChanges ( with_selected_changes',+                             with_selected_changes_to_files',+                             with_selected_last_changes_to_files',+                             with_selected_last_changes_reversed',+                       with_selected_changes,+                       with_selected_changes_to_files,+                       with_selected_changes_reversed,+                       with_selected_last_changes_to_files,+                       with_selected_last_changes_to_files_reversed,+                       with_selected_last_changes_reversed,+                       view_changes,+                       with_selected_patch_from_repo,+                     ) where+import System.IO+import Data.List ( intersperse )+import Data.Maybe ( isJust, catMaybes )+import Data.Char ( toUpper )+import Control.Monad ( when )+import System.Exit ( exitWith, ExitCode(ExitSuccess) )++import English ( Noun(..), englishNum  )+import Darcs.Hopefully ( PatchInfoAnd, hopefully, n2pia )+import Darcs.Repository ( Repository, read_repo, read_pending )+import Darcs.Patch ( RepoPatch, Patchy, Prim, summary, commute,+                     fromPrims, invert, list_touched_files, anonymous )+import qualified Darcs.Patch ( thing, things )+import Darcs.Patch.Ordered ( FL(..), RL(..), (:<)(..), (:>)(..),+                             (+>+), lengthFL, concatRL, mapFL_FL,+                             spanFL, reverseFL, (+<+), mapFL )+import Darcs.Patch.Choices ( PatchChoices, patch_choices, patch_choices_tps,+                             force_first, force_last, make_uncertain, tag,+                      is_patch_first,+                      separate_first_middle_from_last,+                      separate_first_from_middle_last,+                      separate_middle_last_from_first,+                      select_all_middles,+                      separate_last_from_first_middle,+                      force_matching_last,+                      force_matching_first, make_everything_later,+                      TaggedPatch, tp_patch,+                    )+import Darcs.Patch.TouchesFiles ( deselect_not_touching, select_not_touching )+import Darcs.PrintPatch ( printFriendly, printPatch, printPatchPager )+import Darcs.SlurpDirectory ( Slurpy )+import Darcs.Match ( have_nonrange_match, match_a_patch, doesnt_not_match )+import Darcs.Flags ( DarcsFlag( DryRun, All, Summary, DontGrabDeps, Verbose+                             ) )+import Darcs.Sealed ( Sealed(..) )+import Darcs.Utils ( askUser, promptCharFancy, without_buffering )+import Printer ( prefix, putDocLn )+#include "impossible.h"+\end{code}++\begin{code}+type WithPatches p a =+        String              -- jobname+     -> [DarcsFlag]         -- opts+     -> Slurpy              -- directory+     -> FL p                -- patches to select among+     -> (FL p :> FL p -> IO a) -- job+     -> IO a                -- result of running job++-- | The only difference with 'WithPatches' is the [FilePath] argument+type WithPatchesToFiles p a =+        String              -- jobname+     -> [DarcsFlag]         -- opts+     -> Slurpy              -- directory+     -> [FilePath]          -- files+     -> FL p                -- patches to select among+     -> (FL p :> FL p -> IO a) -- job+     -> IO a                -- result of running job++with_selected_changes'               :: WithPatches Prim a+with_selected_changes_to_files'      :: WithPatchesToFiles Prim a+with_selected_last_changes_to_files' :: WithPatchesToFiles Prim a+with_selected_last_changes_reversed' :: WithPatches Prim a+                                     +with_selected_changes'               = wasc  First+with_selected_changes_to_files'      = wasc_ First+with_selected_last_changes_to_files' = wasc_ Last+with_selected_last_changes_reversed' = wasc  LastReversed++with_selected_changes               :: RepoPatch p => WithPatches (PatchInfoAnd p) a+with_selected_changes_to_files      :: RepoPatch p => WithPatchesToFiles (PatchInfoAnd p) a+with_selected_changes_reversed      :: RepoPatch p => WithPatches (PatchInfoAnd p) a+with_selected_last_changes_to_files :: RepoPatch p => WithPatchesToFiles (PatchInfoAnd p) a+with_selected_last_changes_to_files_reversed :: RepoPatch p => WithPatchesToFiles (PatchInfoAnd p) a+with_selected_last_changes_reversed :: RepoPatch p => WithPatches (PatchInfoAnd p) a+                                    +with_selected_changes               = wasc'  First+with_selected_changes_to_files      = wasc_' First+with_selected_changes_reversed      = wasc'  FirstReversed+with_selected_last_changes_to_files = wasc_' Last+with_selected_last_changes_to_files_reversed = wasc_' LastReversed+with_selected_last_changes_reversed = wasc'  LastReversed++data WhichChanges = Last | LastReversed | First | FirstReversed deriving (Eq, Show)++-- | wasc and wasc_ are just shorthand for with_any_selected_changes+wasc  :: Patchy p => WhichChanges -> WithPatches p a+wasc mwch j o s = wasc_ mwch j o s []+wasc_ :: Patchy p => WhichChanges -> WithPatchesToFiles p a+wasc_ = with_any_selected_changes++wasc'  :: RepoPatch p => WhichChanges -> WithPatches (PatchInfoAnd p) a+wasc' mwch j o s = wasc_' mwch j o s []+wasc_' :: RepoPatch p => WhichChanges -> WithPatchesToFiles (PatchInfoAnd p) a+wasc_' = with_any_selected_changes'++with_any_selected_changes :: Patchy p => WhichChanges -> WithPatchesToFiles p a+with_any_selected_changes wch jn opts s fs =+    with_any_selected_changes_ wch (patches_to_consider (Just wch) fs) jn opts s fs++with_any_selected_changes' :: RepoPatch p => WhichChanges -> WithPatchesToFiles (PatchInfoAnd p) a+with_any_selected_changes' wch jn opts s fs =+    with_any_selected_changes_ wch (patches_to_consider' (Just wch) fs opts) jn opts s fs++view_changes :: RepoPatch p => [DarcsFlag] -> Slurpy -> [FilePath] -> FL (PatchInfoAnd p) -> IO ()+view_changes opts _ fp ps =+ without_buffering $ do text_view opts ps_len 0 NilRL init_tps init_pc+                        return ()+ where ps_to_consider :> _ = patches_to_consider' Nothing fp opts ps+       (init_pc, init_tps) = patch_choices_tps ps_to_consider+       ps_len = lengthFL init_tps+\end{code}++\begin{code}+data KeyPress a = KeyPress { kp     :: Char+                           , kpHelp :: String }++helpFor :: String -> [[KeyPress a]] -> String+helpFor jobname options =+  unlines $ [ "How to use "++jobname++":" ]+            ++ (concat $ intersperse [""] $ map (map help) options)+            ++ [ ""+               , "?: show this help"+               , ""+               , "<Space>: accept the current default (which is capitalized)"+               ]+  where help i = kp i:(": "++kpHelp i)++keysFor :: [[KeyPress a]] -> [Char]+keysFor = concatMap (map kp)+\end{code}++\begin{code}+with_selected_patch_from_repo :: RepoPatch p => String -> Repository p -> [DarcsFlag] -> Bool+                              -> ((PatchInfoAnd p,[PatchInfoAnd p]) -> IO ()) -> IO ()+with_selected_patch_from_repo jn repository opts ignore_pending job = do+    Sealed p_s <- read_repo repository+    pend <- if ignore_pending+            then return NilFL+            else read_pending repository+    sp <- without_buffering $ wspfr jn (doesnt_not_match opts)+                              (concatRL p_s) [n2pia $ anonymous $ fromPrims pend]+    case sp of+        Just (selected, s_and_pend) ->+          case (last s_and_pend, init s_and_pend) of+          (pend',skipped) ->+            case commute (pend' :> selected) of+            Just (selected' :> _) -> job (selected', skipped)+            Nothing -> impossible+        Nothing -> do putStrLn $ "Cancelling "++jn++" since no patch was selected."+                      exitWith $ ExitSuccess++wspfr :: RepoPatch p => String -> (PatchInfoAnd p -> Bool)+      -> RL (PatchInfoAnd p) -> [PatchInfoAnd p]+      -> IO (Maybe (PatchInfoAnd p, [PatchInfoAnd p]))+wspfr _ _ NilRL _ = return Nothing+wspfr jn matches (p:<:pps) skipped+    | not $ matches p = wspfr jn matches pps (p:skipped)+    | otherwise =+    case commute_by (skipped :< p) of+    Nothing -> do putStr "\nSkipping depended-upon patch:"+                  printFriendly [] p+                  wspfr jn matches pps (p:skipped)+    Just (p' :< skipped') -> do+      printFriendly [] p+      let repeat_this  = wspfr jn matches (p:<:pps) skipped+          options = [[ KeyPress 'y' (jn++" this patch")+                     , KeyPress 'n' ("don't "++jn++" it")+                     , KeyPress 'v' "view this patch in full"+                     , KeyPress 'p' "view this patch in full with pager"+                     , KeyPress 'x' "view a summary of this patch"+                     , KeyPress 'q' ("cancel "++jn)+                    ]]+      let prompt  = "Shall I "++jn++" this patch?"+      yorn <- promptCharFancy prompt (keysFor options) (Just 'n') "?h"+      case yorn of+        'y' -> return $ Just (p', skipped')+        'n' -> wspfr jn matches pps (p:skipped)+        'v' -> printPatch p >> repeat_this+        'p' -> printPatchPager p >> repeat_this+        'x' -> do putDocLn $ prefix "    " $ summary p+                  repeat_this+        'q' -> do putStrLn $ jn_cap++" cancelled."+                  exitWith $ ExitSuccess+        _   -> do putStrLn $ helpFor jn options+                  repeat_this+  where jn_cap = (toUpper $ head jn) : tail jn++commute_by :: Patchy p => [p] :< p -> Maybe (p :< [p])+commute_by ([] :< a) = Just (a :< [])+commute_by (p:ps :< a) =+    case commute (a :> p) of+    Nothing -> Nothing+    Just (p':>a') -> case commute_by (ps :< a') of+                     Nothing -> Nothing+                     Just (a'' :< ps') -> Just (a'' :< p':ps')+\end{code}++\begin{code}+with_any_selected_changes_ :: Patchy p => WhichChanges+                           -> (FL p -> FL p :> FL p)+                           -> WithPatchesToFiles p a+with_any_selected_changes_ whichch p2c+                          jobname opts _ _ ps job =+   if All `elem` opts || DryRun `elem` opts+   then job $ case whichch of LastReversed -> invert other_ps :> invert ps_to_consider+                              FirstReversed -> invert other_ps :> invert ps_to_consider+                              _ -> ps_to_consider :> other_ps+   else do pc <- without_buffering $+                 tentatively_text_select "" jobname (Noun "patch") whichch+                                        opts ps_len 0 NilRL init_tps init_pc+           job $ selected_patches whichch rejected_ps pc+ where ps_to_consider :> other_ps = p2c ps+       rejected_ps = if whichch == Last || whichch == FirstReversed then ps_to_consider else other_ps+       (init_pc, init_tps) = patch_choices_tps $ case whichch of Last -> other_ps+                                                                 FirstReversed -> other_ps+                                                                 _ -> ps_to_consider+       ps_len = lengthFL init_tps++patches_to_consider :: Patchy p => Maybe WhichChanges+                    -> [FilePath]  -- ^ files+                    -> FL p     -- ^ patches+                    -> (FL p :> FL p)+patches_to_consider mwhichch fs ps =+  let ps' = if mwhichch == Just LastReversed || mwhichch == Just FirstReversed then invert ps else ps+      f = case mwhichch of Just Last -> separate_middle_last_from_first+                           Just FirstReversed -> separate_middle_last_from_first+                           _ -> separate_first_middle_from_last+      deal_with_fs = case mwhichch of Just Last -> select_not_touching   fs+                                      Just FirstReversed -> select_not_touching   fs+                                      _ -> deselect_not_touching fs+  in if null fs then if mwhichch == Just Last || mwhichch == Just FirstReversed then NilFL :> ps' else ps' :> NilFL+                else tp_patches $ f $ deal_with_fs $ patch_choices ps'++patches_to_consider' :: RepoPatch p => Maybe WhichChanges+                     -> [FilePath]  -- ^ files+                     -> [DarcsFlag] -- ^ opts+                     -> FL (PatchInfoAnd p) -- ^ patches+                     -> FL (PatchInfoAnd p) :> FL (PatchInfoAnd p)+patches_to_consider' mwhichch fs opts ps =+  let ps' = if mwhichch == Just LastReversed || mwhichch == Just FirstReversed then invert ps else ps+      f = case mwhichch of Just Last -> separate_middle_last_from_first+                           Just FirstReversed -> separate_middle_last_from_first+                           _ -> separate_first_middle_from_last+      deal_with_fs = case mwhichch of Just Last -> select_not_touching   fs+                                      Just FirstReversed -> select_not_touching   fs+                                      _ -> deselect_not_touching fs+      deselect_unwanted pc =+        if have_nonrange_match opts+        then case mwhichch of+             Just Last ->  bug "don't support patch matching with Last in wasp"+             Just FirstReversed ->  bug "don't support patch matching with FirstReversed in wasp"+             _ -> if DontGrabDeps `elem` opts+                  then force_matching_last (not.iswanted) pc+                  else make_everything_later $ force_matching_first iswanted pc+        else pc+      iswanted = let maybe_invert = if mwhichch == Just LastReversed || mwhichch == Just FirstReversed then invert else id+                 in (match_a_patch opts . hopefully . maybe_invert . tp_patch)+  in if null fs && not (have_nonrange_match opts)+     then if mwhichch == Just Last || mwhichch == Just FirstReversed then NilFL :> ps' else ps' :> NilFL+     else tp_patches $ f $ deal_with_fs $ deselect_unwanted $ patch_choices ps'++-- | Returns the results of a patch selection user interaction+selected_patches :: Patchy p => WhichChanges+                 -> FL p -- ^ patches set aside+                 -> PatchChoices p+                 -> (FL p :> FL p)+selected_patches whichch other_ps pc =+  case whichch of+  Last -> case separate_last_from_first_middle pc of+          xs :> ys -> other_ps +>+ mapFL_FL tp_patch xs :> mapFL_FL tp_patch ys+  First -> case separate_first_from_middle_last pc of+           xs :> ys -> mapFL_FL tp_patch xs :> mapFL_FL tp_patch ys +>+ other_ps+  LastReversed -> case separate_first_from_middle_last pc of+                  xs :> ys -> invert (mapFL_FL tp_patch ys +>+ other_ps) :> invert (mapFL_FL tp_patch xs)+  FirstReversed -> case separate_last_from_first_middle pc of+                   xs :> ys -> invert (mapFL_FL tp_patch ys) :> invert (other_ps +>+ mapFL_FL tp_patch xs)++text_select :: Patchy p => String -> WhichChanges -> [DarcsFlag] -> Int -> Int+            -> RL (TaggedPatch p) -> FL (TaggedPatch p) -> PatchChoices p+            -> IO (PatchChoices p)++text_select _ _ _ _ _ _ NilFL pc = return pc+text_select jn whichch opts n_max n+            tps_done tps_todo@(tp:>:tps_todo') pc = do+      printFriendly opts viewp+      repeat_this -- prompt the user+    where+        do_next_action ja je = tentatively_text_select ja jn je whichch opts+                                          n_max+                                          (n+1) (tp:<:tps_done) tps_todo'+        do_next = do_next_action "" (Noun "patch")+        helper :: PatchChoices p -> p+        helper = undefined+        thing  = Darcs.Patch.thing (helper pc)+        things = Darcs.Patch.things (helper pc)+        options_basic =+           [ KeyPress 'y' (jn++" this "++thing)+           , KeyPress 'n' ("don't "++jn++" it")+           , KeyPress 'w' ("wait and decide later, defaulting to no") ]+        options_file =+           [ KeyPress 's' ("don't "++jn++" the rest of the changes to this file")+           , KeyPress 'f' (jn++" the rest of the changes to this file") ]+        options_view =+           [ KeyPress 'v' ("view this "++thing++" in full")+           , KeyPress 'p' ("view this "++thing++" in full with pager") ]+        options_summary =+           [ KeyPress 'x' ("view a summary of this "++thing) ]+        options_quit =+           [ KeyPress 'd' (jn++" selected "++things++", skipping all the remaining "++things)+           , KeyPress 'a' (jn++" all the remaining "++things)+           , KeyPress 'q' ("cancel "++jn) ]+        options_nav =+           [ KeyPress 'j' ("skip to next "++thing)+           , KeyPress 'k' ("back up to previous "++thing) ]+        options = [options_basic]+                  ++ (if is_single_file_patch then [options_file] else [])+                  ++ [options_view +++                      if Summary `elem` opts then [] else options_summary]+                  ++ [options_quit]+                  ++ [options_nav ]+        prompt = "Shall I "++jn++" this "++thing++"? "+               ++ "(" ++ show (n+1) ++ "/" ++ show n_max ++ ") "+        repeat_this = do+          yorn <- promptCharFancy prompt (keysFor options) (Just the_default) "?h"+          case yorn of+            'y' -> do_next $ force_yes (tag tp) pc+            'n' -> do_next $ force_no (tag tp) pc+            'w' -> do_next $ make_uncertain (tag tp) pc+            's' -> do_next_action "Skipped"  (Noun "change") $ skip_file+            'f' -> do_next_action "Included" (Noun "change") $ do_file+            'v' -> printPatch viewp >> repeat_this+            'p' -> printPatchPager viewp >> repeat_this+            'x' -> do putDocLn $ prefix "    " $ summary viewp+                      repeat_this+            'd' -> return pc+            'a' -> do ask_confirmation+                      return $ select_all_middles (whichch == Last || whichch == FirstReversed) pc+            'q' -> do putStrLn $ jn_cap++" cancelled."+                      exitWith $ ExitSuccess+            'j' -> case tps_todo' of+                       NilFL -> -- May as well work out the length now we have all+                                -- the patches in memory+                                text_select jn whichch opts+                                    n_max n tps_done tps_todo pc+                       _ -> text_select jn whichch opts+                                n_max (n+1) (tp:<:tps_done) tps_todo' pc+            'k' -> case tps_done of+                        NilRL -> repeat_this+                        (tp':<:tps_done') ->+                           text_select jn whichch opts+                               n_max (n-1) tps_done' (tp':>:tps_todo) pc+            'c' -> text_select jn whichch opts+                                        n_max n tps_done tps_todo pc+            _   -> do putStrLn $ helpFor jn options+                      repeat_this+        force_yes = if whichch == Last || whichch == FirstReversed then force_last else force_first+        force_no  = if whichch == Last || whichch == FirstReversed then force_first else force_last+        patches_to_skip = (tag tp:) $ catMaybes+                        $ mapFL (\tp' -> if list_touched_files tp' == touched_files+                                         then Just (tag tp')+                                         else Nothing) tps_todo'+        skip_file = foldr force_no pc patches_to_skip+        do_file = foldr force_yes pc patches_to_skip+        the_default = get_default (whichch == Last || whichch == FirstReversed) $ is_patch_first tp pc+        jn_cap = (toUpper $ head jn) : tail jn+        touched_files = list_touched_files $ tp_patch tp+        is_single_file_patch = length touched_files == 1+        viewp = if whichch == LastReversed || whichch == FirstReversed then invert (tp_patch tp) else tp_patch tp+        ask_confirmation =+            if jn `elem` ["unpull", "unrecord", "obliterate"]+            then do yorn <- askUser $ "Really " ++ jn ++ " all undecided patches? "+                    case yorn of+                     ('y':_) -> return ()+                     _ -> exitWith $ ExitSuccess+            else return ()++text_view :: Patchy p => [DarcsFlag] -> Int -> Int+            -> RL (TaggedPatch p) -> FL (TaggedPatch p) -> PatchChoices p+            -> IO (PatchChoices p)++text_view _ _ _ _ NilFL _ = return $ patch_choices NilFL --return pc+text_view opts n_max n+            tps_done tps_todo@(tp:>:tps_todo') pc = do+      printFriendly opts (tp_patch tp)+      putStr "\n"+      repeat_this -- prompt the user+    where+        prev_patch = case tps_done of+                       NilRL -> repeat_this+                       (tp':<:tps_done') ->+                         text_view opts+                            n_max (n-1) tps_done' (tp':>:tps_todo) pc+        next_patch = case tps_todo' of+                         NilFL -> -- May as well work out the length now we have all+                                  -- the patches in memory+                               text_view opts n_max+                                   n tps_done tps_todo' pc+                         _ -> text_view opts n_max+                                  (n+1) (tp:<:tps_done) tps_todo' pc+        options_yn =+          [ KeyPress 'y' "view this patch and go to the next"+          , KeyPress 'n' "skip to the next patch" ]+        options_view =+          [ KeyPress 'v' "view this patch in full"+          , KeyPress 'p' "view this patch in fill with pager" ]+        options_summary =+          [ KeyPress 'x' "view a summary of this patch" ]+        options_nav =+          [ KeyPress 'q' ("quit view changes")+          , KeyPress 'k' "back up to previous patch"+          , KeyPress 'j' "skip to next patch" ]+        options = [ options_yn ]+                  ++ [ options_view +++                       if Summary `elem` opts then [] else options_summary ]+                  ++ [ options_nav ]+        prompt = "Shall I view this patch? "+               ++ "(" ++ show (n+1) ++ "/" ++ show n_max ++ ")"+        repeat_this = do+          yorn <- promptCharFancy prompt (keysFor options) (Just 'n') "?h"+          case yorn of+            'y' -> printPatch (tp_patch tp) >> next_patch+            'n' -> next_patch+            'v' -> printPatch (tp_patch tp) >> repeat_this+            'p' -> printPatchPager (tp_patch tp) >> repeat_this+            'x' -> do putDocLn $ prefix "    " $ summary (tp_patch tp)+                      repeat_this+            'q' -> exitWith ExitSuccess+            'k' -> prev_patch+            'j' -> next_patch+            'c' -> text_view opts+                       n_max n tps_done tps_todo pc+            _   -> do putStrLn $ helpFor "view changes" options+                      repeat_this++tentatively_text_select :: Patchy p => String -> String -> Noun -> WhichChanges -> [DarcsFlag]+                        -> Int -> Int -> RL (TaggedPatch p) -> FL (TaggedPatch p)+                        -> PatchChoices p+                        -> IO (PatchChoices p)+tentatively_text_select _ _ _ _ _ _ _ _ NilFL pc = return pc+tentatively_text_select jobaction jobname jobelement whichch opts n_max n ps_done+                        ps_todo pc = do+  when (numSkipped > 0) show_skipped+  text_select jobname whichch opts n_max (n + numSkipped)+    (reverseFL skipped +<+ ps_done) unskipped pc+ where+  skipped :> unskipped = spanFL (\p -> isJust $ is_patch_first p pc) ps_todo+  numSkipped  = lengthFL skipped+  show_skipped = do putStrLn $ _doing_ ++ _with_ ++ "."+                    when (Verbose `elem` opts) $ showskippedpatch skipped+    where+      _doing_  = _action_ ++ " " ++ jobname+      _with_   = " of " ++ show numSkipped ++ " " ++ _elem_ ""+      _action_ = if (length jobaction) == 0 then "Skipped" else jobaction+      _elem_ = englishNum numSkipped jobelement+      showskippedpatch (tp:>:tps) = (putDocLn $ prefix "    " $ summary (tp_patch tp)) >> showskippedpatch tps+      showskippedpatch NilFL = return ()++get_default :: Bool -> Maybe Bool -> Char+get_default _ Nothing = 'w'+get_default True (Just True) = 'n'+get_default True (Just False) = 'y'+get_default False (Just True) = 'y'+get_default False (Just False) = 'n'+\end{code}++\begin{code}+tp_patches :: (FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x y)+           -> (FL p :> FL p) C(x y)+tp_patches (x:>y) = mapFL_FL tp_patch x :> mapFL_FL tp_patch y+\end{code}
+ src/Darcs/Show.lhs view
@@ -0,0 +1,26 @@+\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.Show(Show1(..), Show2(..), showOp2, app_prec) where++#include "gadts.h"++class Show1 a where+    show1 :: a C(x) -> String+    show1 x = showsPrec1 0 x ""+    showsPrec1 :: Int -> a C(x) -> ShowS+    showsPrec1 _ x s = show1 x ++ s++class Show2 a where+    show2 :: a C(x y) -> String+    show2 x = showsPrec2 0 x ""+    showsPrec2 :: Int -> a C(x y) -> ShowS+    showsPrec2 _ x s = show2 x ++ s++showOp2 :: (Show2 a, Show2 b) => Int -> String -> Int -> a C(w x) -> b C(y z) -> String -> String+showOp2 prec opstr d x y = showParen (d > prec) $ showsPrec2 (prec + 1) x .+                          showString opstr . showsPrec2 (prec + 1) y++app_prec :: Int+app_prec = 10++\end{code}
+ src/Darcs/SignalHandler.lhs view
@@ -0,0 +1,130 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+module Darcs.SignalHandler ( withSignalsHandled, withSignalsBlocked,+                             catchNonSignal, tryNonSignal, stdout_is_a_pipe ) where++import System.IO.Error ( isUserError, ioeGetErrorString, ioeGetFileName )+import Control.Exception ( dynExceptions, ioErrors, catchJust, Exception ( IOException ) )+import System.Exit ( exitWith, ExitCode ( ExitFailure ) )+import Control.Concurrent ( ThreadId, myThreadId )+import Control.Exception ( catchDyn, throwDynTo, block )+import System.Posix.Files ( getFdStatus, isNamedPipe )+import System.Posix.IO ( stdOutput )+import Data.Dynamic ( Typeable, fromDynamic )+import System.IO ( hPutStrLn, stderr )+import Control.Monad ( when )++import Workaround ( installHandler, raiseSignal, Handler(..), Signal,+                    sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE )+#ifdef WIN32+import CtrlC ( withCtrlCHandler )+#endif+\end{code}++\begin{code}++stdout_is_a_pipe :: IO Bool+stdout_is_a_pipe+ = catchJust ioErrors+        (do stat <- getFdStatus stdOutput+            return (isNamedPipe stat))+        (\_ -> return False)++withSignalsHandled :: IO a -> IO a+newtype SignalException = SignalException Signal deriving (Typeable)++withSignalsHandled job = do+    thid <- myThreadId+    mapM_ (ih thid) [sigINT, sigHUP, sigABRT, sigTERM, sigPIPE]+    catchJust just_usererrors (job' thid `catchSignal` defaults)+              die_with_string+    where defaults s | s == sigINT = ew s "Interrupted!"+                     | s == sigHUP = ew s "HUP"+                     | s == sigABRT = ew s "ABRT"+                     | s == sigTERM = ew s "TERM"+                     | s == sigPIPE = exitWith $ ExitFailure $ 1+                     | otherwise = ew s "Unhandled signal!"+          ew sig s = do hPutStrLn stderr $ ("withSignalsHandled: " ++ s)+                        resethandler sig+                        raiseSignal sig -- ensure that our caller knows how we died+                        exitWith $ ExitFailure $ 1+          die_with_string e | take 6 e == "STDOUT" =+                do is_pipe <- stdout_is_a_pipe+                   when (not is_pipe) $+                        hPutStrLn stderr $ "\ndarcs failed:  "++drop 6 e+                   exitWith $ ExitFailure $ 2+          die_with_string e = do hPutStrLn stderr $ "\ndarcs failed:  "++e+                                 exitWith $ ExitFailure $ 2+#ifdef WIN32+          job' thid =+             withCtrlCHandler (throwDynTo thid $ SignalException sigINT) job+#else+          job' _ = job+#endif++resethandler :: Signal -> IO ()+resethandler s = do installHandler s Default Nothing+                    return ()++ih :: ThreadId -> Signal -> IO ()+ih thid s =+  do installHandler s (Catch $ throwDynTo thid $ SignalException s) Nothing+     return ()++catchSignal :: IO a -> (Signal -> IO a) -> IO a+catchSignal job handler =+    job `Control.Exception.catchDyn` (\(SignalException sig) -> handler sig)++-- catchNonSignal is a drop-in replacement for Control.Exception.catch, which allows+-- us to catch anything but a signal.  Useful for situations where we want+-- don't want to inhibit ctrl-C.++catchNonSignal :: IO a -> (Control.Exception.Exception -> IO a) -> IO a+catchNonSignal = Control.Exception.catchJust notSig+    where notSig x = case dynExceptions x of+                     Nothing -> Just x+                     Just d -> case fromDynamic d :: Maybe SignalException of+                               Just _ -> Nothing+                               Nothing -> Just x++tryNonSignal :: IO a -> IO (Either Control.Exception.Exception a)+tryNonSignal j = (Right `fmap` j) `catchNonSignal` \e -> return (Left e)++just_usererrors :: Control.Exception.Exception -> Maybe String+just_usererrors (IOException e) | isUserError e = Just $ ioeGetErrorString e+just_usererrors (IOException e) | ioeGetFileName e == Just "<stdout>"+                                      = Just $ "STDOUT"++ioeGetErrorString e+just_usererrors _ = Nothing+\end{code}++\begin{code}+withSignalsBlocked :: IO () -> IO ()+withSignalsBlocked job = (block job) `catchSignal` couldnt_do+    where couldnt_do s | s == sigINT = oops "interrupt"+                       | s ==  sigHUP = oops "HUP"+                       | s ==  sigABRT = oops "ABRT"+                       | s ==  sigALRM = oops "ALRM"+                       | s ==  sigTERM = oops "TERM"+                       | s ==  sigPIPE = return ()+                       | otherwise = oops "unknown signal"+          oops s = hPutStrLn stderr $ "Couldn't handle " ++ s +++                   " since darcs was in a sensitive job."+\end{code}
+ src/Darcs/SlurpDirectory.lhs view
@@ -0,0 +1,648 @@+%  Copyright (C) 2002-2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\chapter{SlurpDirectory}++\section{Introduction}++SlurpDirectory is intended to give a nice lazy way of traversing directory+trees.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Darcs.SlurpDirectory ( Slurpy(..), FileContents, empty_slurpy,+                        slurp, mmap_slurp, slurp_unboring, co_slurp,+                        slurp_name, is_file, is_dir,+                        get_filecontents, get_dircontents, get_mtime,+                        get_length, get_slurp,+                        get_slurp_context, get_slurp_context_maybe,+                        get_slurp_context_list,+                        slurp_removefile, slurp_removedir,+                        slurp_remove,+                        slurp_modfile, slurp_hasfile, slurp_hasdir,+                        slurp_has_anycase, wait_a_moment, undefined_time,+                        undefined_size,+                        slurp_has, list_slurpy, list_slurpy_files,+                        get_path_list,+                        list_slurpy_dirs,+                        isFileReallySymlink,+                        doesFileReallyExist, doesDirectoryReallyExist,+                        SlurpMonad(..), withSlurpy, write_files+                      ) where++import System.IO+import System.Directory hiding ( getCurrentDirectory, renameFile )+import Workaround ( getCurrentDirectory )+import Darcs.Utils ( withCurrentDirectory, formatPath )+import System.IO.Unsafe ( unsafeInterleaveIO )+import Data.List ( sort, tails, isPrefixOf )+import Control.Monad ( MonadPlus(..) )+import Data.Char ( toLower )+import System.Posix.Types ( EpochTime, FileOffset )+import System.Posix.Files+        ( getSymbolicLinkStatus, modificationTime,+          fileSize,+          isRegularFile, isDirectory, isSymbolicLink+        )+import System.Posix ( sleep )+import Data.Maybe ( catMaybes, isJust, maybeToList )++import Darcs.SignalHandler ( tryNonSignal )+import Darcs.CheckFileSystem ( can_I_use_mmap )+import Darcs.IO ( ReadableDirectory(..), WriteableDirectory(..) )+import FastPackedString+import FileName ( FileName, fn2fp, fp2fn, norm_path, break_on_dir,+                  own_name, super_name,+                )+#include "impossible.h"++data Slurpy = SlurpDir FileName (Maybe String) [Slurpy]+            | SlurpFile FileName (Maybe String,EpochTime,FileOffset) FileContents+type FileContents = PackedString++instance Show Slurpy where+    show (SlurpDir fn _ l) =+        "Dir " ++ (fn2fp fn) ++ "\n" +++              concat (map show l) ++ "End Dir " ++ (fn2fp fn) ++ "\n"+    show (SlurpFile fn _ _) = "File " ++ (fn2fp fn) ++ "\n"++slurp :: FilePath -> IO Slurpy+mmap_slurp :: FilePath -> IO Slurpy+slurp_unboring :: (FilePath->Bool) -> FilePath -> IO Slurpy+empty_slurpy :: Slurpy+empty_slurpy = SlurpDir (fp2fn ".") Nothing []+slurp_name :: Slurpy -> FilePath+is_file :: Slurpy -> Bool+is_dir :: Slurpy -> Bool++get_filecontents :: Slurpy -> FileContents+get_dircontents :: Slurpy -> [Slurpy]+get_mtime :: Slurpy -> EpochTime+get_length :: Slurpy -> FileOffset++instance Eq Slurpy where+    s1 == s2 = (slurp_name s1) == (slurp_name s2)+instance Ord Slurpy where+    s1 <= s2 = (slurp_name s1) <= (slurp_name s2)+\end{code}++\begin{code}+data SlurpMonad a = SM ((Either String Slurpy)+                        -> Either String (Slurpy, a))+mksm :: (Slurpy -> Either String (Slurpy, a)) -> SlurpMonad a+mksm x = SM sm where sm (Left e) = Left e+                     sm (Right s) = x s++instance Monad SlurpMonad where+    (SM p) >>= k  =  SM sm+        where sm e = case p e of+                     Left er -> Left er+                     Right (s, a) -> case k a of+                                     (SM q) -> q (Right s)+    return a = SM ( \s -> case s of+                          Left e -> Left e+                          Right x -> Right (x, a) )+    fail e = SM ( \s -> case s of+                        Left x -> Left x+                        _ -> Left e )++instance MonadPlus SlurpMonad where+    mzero = fail "SlurpMonad mzero"+    (SM p) `mplus` (SM q) = SM sm+        where sm e = case p e of+                     Left _ -> q e+                     okay -> okay++instance ReadableDirectory SlurpMonad where+    mDoesDirectoryExist d = smDoesDirectoryExist d+    mDoesFileExist f = smDoesFileExist f+    mInCurrentDirectory = smInSlurpy+    mGetDirectoryContents = smGetDirContents+    mReadFilePS = smReadFilePS+    mReadFilePSs = smReadFilePSs++instance WriteableDirectory SlurpMonad where+    mWithCurrentDirectory = modifySubSlurpy+    mSetFileExecutable _ _ = return ()+    mWriteFilePS = smWriteFilePS+    mCreateDirectory = smCreateDirectory+    mRename = smRename+    mRemoveDirectory = smRemoveDirectory+    mRemoveFile = smRemoveFile+\end{code}++\begin{code}+++write_file :: Slurpy -> FileName -> IO ()+write_file s fn = case withSlurpy s $ smReadFilePS fn of+                     Left err -> fail err+                     Right (_, c) -> do+                       ensureDirectories (super_name fn)+                       mWriteFilePS fn c+                       +try_write_file :: Slurpy -> FilePath -> IO ()+try_write_file s fp = let fn = fp2fn fp in+  if slurp_hasfile fn s+      then write_file s fn+      else if slurp_hasdir fn s+               then ensureDirectories fn+               else return ()++ensureDirectories :: WriteableDirectory m => FileName -> m ()+ensureDirectories d = do+          isPar <- mDoesDirectoryExist d+          if isPar +            then return ()+            else ensureDirectories (super_name d) >> (mCreateDirectory d)++write_files ::  Slurpy -> [FilePath] -> IO ()+write_files s fps = mapM_ (try_write_file s) fps+++withSlurpy :: Slurpy -> SlurpMonad a -> Either String (Slurpy, a)+withSlurpy s (SM f) = f (Right s)++smDoesDirectoryExist :: FileName -> SlurpMonad Bool+smDoesDirectoryExist d = mksm $ \s -> (Right (s, slurp_hasdir d s))++smDoesFileExist :: FileName -> SlurpMonad Bool+smDoesFileExist f = mksm $ \s -> (Right (s, slurp_hasfile f s))++-- smInSlurpy doesn't make any changes to the subdirectory.+smInSlurpy :: FileName -> SlurpMonad a -> SlurpMonad a+smInSlurpy d job = mksm sm+    where sm s = case get_slurp d s of+                 Just s' | is_dir s' -> case withSlurpy s' job of+                                        Left e -> Left e+                                        Right (_,a) -> Right (s, a)+                 _ -> Left $ "smInSlurpy:  Couldn't find directory " +++                             formatPath (fn2fp d)++fromSlurpFile :: FileName -> (Slurpy -> a) -> SlurpMonad a+fromSlurpFile f job = mksm sm+    where sm s = case get_slurp f s of+                 Just s' | is_file s' -> Right (s, job s')+                 _ -> Left $ "fromSlurpFile:  Couldn't find file " +++                             formatPath (fn2fp f)++modifySubSlurpy :: FileName -> SlurpMonad a -> SlurpMonad a+modifySubSlurpy d job = mksm sm+    where sm s = case get_slurp_context d s of+                 Just (ctx, sub@(SlurpDir _ _ _)) ->+                     case withSlurpy sub job of+                     Left e -> Left e+                     Right (sub',a) -> Right (ctx sub', a)+                 _ -> Left $ "modifySubSlurpy:  Couldn't find directory " +++                             formatPath (fn2fp d)++modifyFileSlurpy :: FileName -> (Slurpy -> Slurpy) -> SlurpMonad ()+modifyFileSlurpy f job = mksm sm+    where sm s = case get_slurp_context f s of+                 Just (ctx, sf@(SlurpFile _ _ _)) -> Right (ctx $ job sf, ())+                 _ -> Left $ "modifyFileSlurpy:  Couldn't find file " +++                             formatPath (fn2fp f)++insertSlurpy :: FileName -> Slurpy -> SlurpMonad ()+insertSlurpy f news = mksm $ \s ->+                      if slurp_hasfile f s || slurp_hasdir f s || not (slurp_hasdir (super_name f) s)+                      then Left $ "Error creating file "++fn2fp f+                      else Right (addslurp f news s, ())++smReadFilePS :: FileName -> SlurpMonad PackedString+smReadFilePS f = fromSlurpFile f get_filecontents++smReadFilePSs :: FileName -> SlurpMonad [PackedString]+smReadFilePSs f = fromSlurpFile f (linesPS . get_filecontents)++smGetDirContents :: SlurpMonad [FileName]+smGetDirContents = mksm $ \s -> Right (s, map slurp_fn $ get_dircontents s)++smWriteFilePS :: FileName -> PackedString -> SlurpMonad ()+smWriteFilePS f ps = modifyFileSlurpy f (\_ -> sl)+                     `mplus` insertSlurpy f sl+    where sl = SlurpFile (own_name f) undef_time_size ps++smCreateDirectory :: FileName -> SlurpMonad ()+smCreateDirectory a = mksm sm+    where sm s = case slurp_adddir a s of+                 Just s' -> Right (s', ())+                 Nothing -> Left $ "Error creating directory "++fn2fp a++smRename :: FileName -> FileName -> SlurpMonad ()+smRename a b = mksm sm+    where sm s = case slurp_move a b s of+                 Just s' -> Right (s', ())+                 Nothing -> +                     -- Workaround for some old patches having moves when the source file doesn't exist.+                     if (slurp_has (fn2fp a) s)+                         then Left $ "Error moving "++fn2fp a++" to "++fn2fp b+                         else Right (s, ())++smRemove :: FileName -> SlurpMonad ()+smRemove f = mksm sm+    where sm s = case slurp_remove f s of+                 Nothing -> Left $ fn2fp f++" does not exist."+                 Just s' -> Right (s', ())++smRemoveFile :: FileName -> SlurpMonad ()+smRemoveFile f =+    do exists <- mDoesFileExist f+       if exists then smRemove f+                 else fail $ "File "++fn2fp f++" does not exist."++smRemoveDirectory :: FileName -> SlurpMonad ()+smRemoveDirectory f =+    do exists <- mDoesDirectoryExist f+       if exists then smRemove f+                 else fail $ "Directory "++fn2fp f++" does not exist."+\end{code}++Here are a few access functions.++\begin{code}+slurp_name (SlurpFile f _ _) = fn2fp f+slurp_name (SlurpDir d _ _) = fn2fp d+slurp_fn :: Slurpy -> FileName+slurp_fn (SlurpFile f _ _) = f+slurp_fn (SlurpDir d _ _) = d+slurp_setname :: FileName -> Slurpy -> Slurpy+slurp_setname f (SlurpDir _ x c) = SlurpDir f x c+slurp_setname f (SlurpFile _ m c) = SlurpFile f m c++is_file (SlurpDir _ _ _) = False+is_file (SlurpFile _ _ _) = True++is_dir (SlurpDir _ _ _) = True+is_dir (SlurpFile _ _ _) = False++get_filecontents (SlurpFile _ _ c) = c+get_filecontents _ = bug "Can't get_filecontents on SlurpDir."++get_dircontents (SlurpDir _ _ c) = sort c+get_dircontents _ = bug "Can't get_dircontents on SlurpFile."++get_mtime (SlurpFile _ (_,t,_) _) = t+get_mtime _ = bug "can't get_mtime on SlurpDir."+get_length (SlurpFile _ (_,_,l) _) = l+get_length _ = bug "can't get_length on SlurpDir."++undefined_time :: EpochTime+undefined_time = -1+undefined_size :: FileOffset+undefined_size = -1+undef_time_size :: (Maybe String, EpochTime, FileOffset)+undef_time_size = (Nothing, undefined_time, undefined_size)++wait_a_moment :: IO ()+wait_a_moment = do { sleep 1; return () }+    -- HACKERY: In ghc 6.1, sleep has the type signature IO Int; it+    -- returns an integer just like sleep(3) does. To stay compatible+    -- with older versions, though, we just ignore sleep's return+    -- value. Hackery, like I said.++isFileReallySymlink :: FilePath -> IO Bool+isFileReallySymlink f = do fs <- getSymbolicLinkStatus f+                           return (isSymbolicLink fs)++doesFileReallyExist :: FilePath -> IO Bool+doesFileReallyExist f = do fs <- getSymbolicLinkStatus f+                           return (isRegularFile fs)++doesDirectoryReallyExist :: FilePath -> IO Bool+doesDirectoryReallyExist f = do fs <- getSymbolicLinkStatus f+                                return (isDirectory fs)+\end{code}++slurp is how we get a slurpy in the first place\ldots++\begin{code}+slurp = slurp_unboring (\_->True)+mmap_slurp d = do canmmap <- can_I_use_mmap+                  if canmmap then genslurp True (\_->True) d+                             else genslurp False (\_->True) d+slurp_unboring = genslurp False+genslurp :: Bool -> (FilePath -> Bool)+         -> FilePath -> IO Slurpy+genslurp usemm nb dirname = do+    isdir <- doesDirectoryExist dirname+    ms <- if isdir+          then withCurrentDirectory dirname $+               do actualname <- getCurrentDirectory+                  genslurp_helper usemm nb (reverse actualname) "" "."+          else do former_dir <- getCurrentDirectory+                  genslurp_helper usemm nb (reverse former_dir) "" dirname+    case ms of+      Just s -> return s+      Nothing -> fail $ "Unable to read directory " ++ dirname +++                 " (it appears to be neither file nor directory)"++unsafeInterleaveMapIO :: (a -> IO b) -> [a] -> IO [b]+unsafeInterleaveMapIO _ [] = return []+unsafeInterleaveMapIO f (x:xs)+ = do x' <- f x+      xs' <- unsafeInterleaveIO $ unsafeInterleaveMapIO f xs+      return (x':xs')++genslurp_helper :: Bool -> (FilePath -> Bool)+                -> FilePath -> String -> String -> IO (Maybe Slurpy)+genslurp_helper usemm nb formerdir fullpath dirname = do+    fs <- getSymbolicLinkStatus fulldirname+    if isRegularFile fs+     then do let mtime = (Nothing, modificationTime fs, fileSize fs)+             ls <- unsafeInterleaveIO $ myReadFileLinesPSetc fulldirname+             return $ Just $ SlurpFile (fp2fn dirname) mtime ls+     else if isDirectory fs || (isSymbolicLink fs && dirname == ".")+          then do sl <- unsafeInterleaveIO $+                        do fnames <- getDirectoryContents fulldirname+                           unsafeInterleaveMapIO+                                             (\f -> genslurp_helper usemm nb fulldirname'+                                              (fullpath///f) f)+                                             $ filter (nb . (fullpath///)) $ filter not_hidden fnames+                  return $ Just $ SlurpDir (fp2fn dirname) Nothing $ catMaybes sl+          else return Nothing+    where fulldirname' = formerdir\\\dirname+          fulldirname = reverse fulldirname'+          myReadFileLinesPSetc = if usemm then mmapFilePS+                                          else readFilePS++not_hidden :: FilePath -> Bool+not_hidden "." = False+not_hidden ".." = False+not_hidden _ = True++(\\\) :: FilePath -> FilePath -> FilePath+(\\\) "" d = d+(\\\) d "." = d+(\\\) d subdir = reverse subdir ++ "/" ++ d++(///) :: FilePath -> FilePath -> FilePath+(///) "" d = d+(///) d "." = d+(///) d subdir = d ++ "/" ++ subdir++co_slurp :: Slurpy -> FilePath -> IO Slurpy+co_slurp guide dirname = do+    isdir <- doesDirectoryExist dirname+    if isdir+       then withCurrentDirectory dirname $ do+              actualname <- getCurrentDirectory+              Just slurpy <- co_slurp_helper (reverse actualname) guide+              return slurpy+       else error "Error coslurping!!! Please report this."++co_slurp_helper :: FilePath -> Slurpy -> IO (Maybe Slurpy)+co_slurp_helper former_dir (SlurpDir d _ c) = unsafeInterleaveIO $ do+    let d' = fn2fp d+        fn' = former_dir\\\d'+        fn = reverse fn'+    efs <- tryNonSignal $ getSymbolicLinkStatus fn+    case efs of+        Right fs+         | isDirectory fs || (isSymbolicLink fs && d' == ".") ->+            do sl <- unsafeInterleaveIO+                   $ unsafeInterleaveMapIO (co_slurp_helper fn') c+               return $ Just $ SlurpDir d Nothing $ catMaybes sl+        _ -> return Nothing+co_slurp_helper former_dir (SlurpFile f _ _) = unsafeInterleaveIO $ do+   let fn' = former_dir\\\fn2fp f+       fn = reverse fn'+   efs <- tryNonSignal $ getSymbolicLinkStatus fn+   case efs of+       Right fs+        | isRegularFile fs ->+           do let mtime = (Nothing, modificationTime fs, fileSize fs)+              ls <- unsafeInterleaveIO $ readFilePS fn+              return $ Just $ SlurpFile f mtime ls+       _ -> return Nothing+\end{code}++\begin{code}+get_slurp_context_generic :: (Slurpy -> a) -> (a -> [Slurpy]) -> FileName -> Slurpy -> Maybe (a -> a, Slurpy)+get_slurp_context_generic h1 h2 fn0 s0 =+    let norm_fn0 = norm_path fn0 in+    if norm_fn0 == empty+        then Just (id, s0)+        else slurp_context_private norm_fn0 id s0+  where+    slurp_context_private f ctx s@(SlurpFile f' _ _) =+        if f == f' then Just (ctx, s)+        else Nothing+    slurp_context_private f ctx s@(SlurpDir d _ c)+      | f == d = Just (ctx, s)+      | d == dot =+            case break_on_dir f of+                Just (dn,fn) | dn == dot ->+                    descend fn+                _ ->+                    descend f+      | otherwise =+            case break_on_dir f of+                Just (dn,fn) ->+                    if dn == d+                        then descend fn+                        else Nothing+                _ -> Nothing+      where+        descend fname =+            let l = [ slurp_context_private +                        fname+                        (\x -> ctx (h1 (SlurpDir d Nothing (pre ++ h2 x ++ post))))+                        this+                    | (pre, this:post) <- zip (inits' c) (tails c) +                    ]+            in+            case filter isJust l of+                [] -> Nothing+                [msf] -> msf+                _ -> impossible++    -- a lazier implementation of inits+    inits' l = [ take i l | i <- [0 .. length l] ]+    dot = fp2fn "."+    empty = fp2fn ""+\end{code}++\begin{code}+get_slurp_context :: FileName -> Slurpy -> Maybe (Slurpy -> Slurpy, Slurpy)+get_slurp_context = get_slurp_context_generic id return++get_slurp_context_maybe :: FileName -> Slurpy -> Maybe (Maybe Slurpy -> Maybe Slurpy, Slurpy)+get_slurp_context_maybe = get_slurp_context_generic Just maybeToList++get_slurp_context_list :: FileName -> Slurpy -> Maybe ([Slurpy] -> [Slurpy], Slurpy)+get_slurp_context_list = get_slurp_context_generic return id+\end{code}++It is important to be able to readily modify a slurpy.++\begin{code}+slurp_remove :: FileName -> Slurpy -> Maybe Slurpy+slurp_remove fname s@(SlurpDir _ _ _) =+    case get_slurp_context_maybe fname s of+        Just (ctx, _) -> ctx Nothing+        Nothing -> Nothing+slurp_remove _ _ = bug "slurp_remove only acts on SlurpDirs"++slurp_removefile :: FileName -> Slurpy -> Maybe Slurpy+slurp_removefile f s =+  if slurp_hasfile f s+  then case slurp_remove f s of+       Just (SlurpDir d x c) -> Just $ SlurpDir d x c+       _ -> impossible+  else Nothing+\end{code}++\begin{code}+slurp_move :: FileName -> FileName -> Slurpy -> Maybe Slurpy+slurp_move f f' s =+    if not (slurp_has (fn2fp f') s) && slurp_hasdir (super_name f') s+    then case get_slurp f s of+         Nothing -> Nothing+         Just sf ->+             case slurp_remove f s of+             Nothing -> Nothing+             Just (SlurpDir d x c) ->+                 Just $ addslurp f' (slurp_setname (own_name f') sf)+                           $ SlurpDir d x c+             _ -> impossible+    else Nothing++addslurp :: FileName -> Slurpy -> Slurpy -> Slurpy+addslurp fname s s' =+    case get_slurp_context (super_name fname) s' of+        Just (ctx, SlurpDir d _ c) -> ctx (SlurpDir d Nothing (s:c))+        _ -> s'++get_slurp :: FileName -> Slurpy -> Maybe Slurpy+get_slurp f s = fmap snd (get_slurp_context f s)+\end{code}++\begin{code}+slurp_removedir :: FileName -> Slurpy -> Maybe Slurpy+slurp_removedir f s =+    case get_slurp f s of+    Just (SlurpDir _ _ []) ->+        case slurp_remove f s of+        Just (SlurpDir d x c) -> Just $ SlurpDir d x c+        _ -> impossible+    _ -> Nothing+\end{code}++\begin{code}+slurp_adddir :: FileName -> Slurpy -> Maybe Slurpy+slurp_adddir f s =+  if slurp_hasfile f s || slurp_hasdir f s || not (slurp_hasdir (super_name f) s)+  then Nothing+  else Just $ addslurp f (SlurpDir (own_name f) Nothing []) s+\end{code}++Code to modify a given file in a slurpy.++\begin{code}+slurp_modfile :: FileName -> (FileContents -> Maybe FileContents)+              -> Slurpy -> Maybe Slurpy+slurp_modfile fname modify sl =+    case get_slurp_context fname sl of+        Just (ctx, SlurpFile ff _ c) ->+            case modify c of+                Nothing -> Nothing+                Just c' -> Just (ctx (SlurpFile ff undef_time_size c'))+        _ -> +            Nothing+\end{code}++\begin{code}+slurp_hasfile :: FileName -> Slurpy -> Bool+slurp_hasfile f s =+    case get_slurp f s of+        Just s' | is_file s' -> True+        _ -> False++slurp_has :: FilePath -> Slurpy -> Bool+slurp_has f s = isJust (get_slurp (fp2fn f) s)++slurp_has_anycase :: FilePath -> Slurpy -> Bool+slurp_has_anycase fname (SlurpDir _ _ contents) =+  seq normed_name $ or $ map (hasany_private normed_name) contents+  where normed_name = norm_path $ fp2fn $ map toLower fname+        hasany_private f (SlurpFile f' _ _) = f == tolower f'+        hasany_private f (SlurpDir d _ c)+            | f == tolower d = True+            | otherwise =+                case break_on_dir f of+                Just (dn,fn) -> if tolower dn == tolower d+                                then or $ map (hasany_private fn) c+                                else False+                _ -> False+slurp_has_anycase f (SlurpFile f' _ _) =+    (norm_path $ fp2fn $ map toLower f) == tolower f'+tolower :: FileName -> FileName+tolower = fp2fn . (map toLower) . fn2fp++slurp_hasdir :: FileName -> Slurpy -> Bool+slurp_hasdir d _ | norm_path d == fp2fn "" = True+slurp_hasdir f (SlurpDir _ _ c) =+    seq f $ or $ map (slurp_hasdir_private $ norm_path f) c+slurp_hasdir _ _ = False++slurp_hasdir_private :: FileName -> Slurpy -> Bool+slurp_hasdir_private _ (SlurpFile _ _ _) = False+slurp_hasdir_private f (SlurpDir d _ c)+  | f == d = True+  | otherwise =+       case break_on_dir f of+       Just (dn,fn) ->+           if dn == d+           then or $ map (slurp_hasdir_private fn) c+           else False+       _ -> False+\end{code}++\begin{code}+get_path_list :: Slurpy -> FilePath -> [FilePath]+get_path_list s fp = get_path_list' s ("./" ++ fp)++get_path_list' :: Slurpy -> FilePath -> [FilePath]+get_path_list' s "" = list_slurpy s+get_path_list' (SlurpFile f _ _) fp+ | f' == fp = [f']+    where f' = fn2fp f+get_path_list' (SlurpDir d _ ss) fp+ | (d' ++ "/") `isPrefixOf` (fp ++ "/")+    = let fp' = drop (length d' + 1) fp+      in map (d' ///) $ concatMap (\s -> get_path_list' s fp') ss+    where d' = fn2fp d+get_path_list' _ _ = []++list_slurpy :: Slurpy -> [FilePath]+list_slurpy (SlurpFile f _ _) = [fn2fp f]+list_slurpy (SlurpDir dd _ ss) = d : map (d ///) (concatMap list_slurpy ss)+    where d = fn2fp dd++list_slurpy_files :: Slurpy -> [FilePath]+list_slurpy_files (SlurpFile f _ _) = [fn2fp f]+list_slurpy_files (SlurpDir dd _ ss) =+    map ((fn2fp dd) ///) (concatMap list_slurpy_files ss)++list_slurpy_dirs :: Slurpy -> [FilePath]+list_slurpy_dirs (SlurpFile _ _ _) = []+list_slurpy_dirs (SlurpDir dd _ ss) =+    d : map (d ///) (concatMap list_slurpy_dirs ss)+    where d = fn2fp dd+\end{code}+
+ src/Darcs/Test.lhs view
@@ -0,0 +1,136 @@+%  Copyright (C) 2002-2005 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.Test ( run_test, get_test,+                    run_posthook, run_prehook ) +where+import Data.Maybe ( isNothing )+import Darcs.Utils ( withCurrentDirectory )+import System.Exit ( ExitCode(..) )+import System.Cmd ( system )+import Control.Monad ( when )++import Darcs.Arguments ( DarcsFlag( Verbose, Quiet,+                                   NoPosthook, RunPosthook,+                                   NoPrehook,  RunPrehook ),+                        get_posthook_cmd, get_prehook_cmd )+import Darcs.Repository.Prefs ( get_prefval )+import Darcs.Utils ( askUser )+import System.IO ( hPutStr, stderr )+\end{code}++If you like, you can configure your repository to be able to run a test+suite of some sort.  You can do this by using ``setpref'' to set the+``test'' value to be a command to run, e.g.+\begin{verbatim}+% darcs setpref test "sh configure && make && make test"+\end{verbatim}+Or, if you want to define a test specific to one copy of the repository,+you could do this by editing the file \verb!_darcs/prefs/prefs!.++\begin{options}+--leave-test-directory, --remove-test-directory+\end{options}++Normally darcs deletes the directory in which the test was run afterwards.+Sometimes (especially when the test fails) you'd prefer to be able to be+able to examine the test directory after the test is run.  You can do this+by specifying the \verb!--leave-test-directory! flag.  Alas, there is no+way to make darcs leave the test directory only if the test fails.  The+opposite of \verb!--leave-test-directory! is+\verb!--remove-test-directory!, which could come in handy if you choose to+make \verb!--leave-test-directory! the default (see+section~\ref{defaults}).++\begin{code}+run_test :: [DarcsFlag] -> FilePath -> IO ExitCode+run_test opts testdir = do test <- get_test opts+                           withCurrentDirectory testdir test++get_test :: [DarcsFlag] -> IO (IO ExitCode)+get_test opts =+ let putInfo s = when (not $ Quiet `elem` opts) $ putStr s+ in do+ testline <- get_prefval "test"+ return $+   case testline of+   Nothing -> return ExitSuccess+   Just testcode -> do+     putInfo "Running test...\n"+     ec <- system testcode+     if ec == ExitSuccess+       then putInfo "Test ran successfully.\n"+       else putInfo "Test failed!\n"+     return ec+\end{code}++\begin{code}+run_posthook :: [DarcsFlag] -> FilePath -> IO ExitCode+run_posthook opts repodir+             | NoPosthook `elem` opts = return ExitSuccess+             | otherwise = withCurrentDirectory repodir $ get_posthook opts++get_posthook :: [DarcsFlag] -> IO ExitCode+get_posthook opts =+ let putInfo s = when (Verbose `elem` opts) $ putStr s+     putErr  s = when (Quiet `notElem` opts) $ hPutStr stderr s+ in case get_posthook_cmd opts of+    Nothing -> return ExitSuccess+    Just command -> do+      yorn <- maybeAskUser("\nThe following command is set to execute.\n"+++                           "Execute the following command now (yes or no)?\n"+++                            command++"\n")+      case yorn of ('y':_) -> do ec <- system command+                                 if ec == ExitSuccess+                                    then putInfo "Posthook ran successfully.\n"+                                    else putErr  "Posthook failed!\n"+                                 return ec+                   _ -> do putInfo "Posthook cancelled..."+                           return ExitSuccess+          where maybeAskUser+                    | RunPosthook `elem` opts = \_ -> return "yes"+                    | otherwise = askUser+\end{code}++\begin{code}+run_prehook :: [DarcsFlag] -> FilePath -> IO ExitCode+run_prehook opts repodir +            | NoPrehook `elem` opts || isNothing (get_prehook_cmd opts) = return ExitSuccess+            | otherwise = withCurrentDirectory repodir $ get_prehook opts++get_prehook :: [DarcsFlag] -> IO ExitCode+get_prehook opts =+ let putInfo s = when (Verbose `elem` opts) $ putStr s+     putErr  s = when (Quiet `notElem` opts) $ hPutStr stderr s+ in case get_prehook_cmd opts of+    Nothing -> return ExitSuccess+    Just command -> do+      yorn <- maybeAskUser("\nThe following command is set to execute.\n"+++                           "Execute the following command now (yes or no)?\n"+++                            command++"\n")+      case yorn of ('y':_) -> do ec <- system command+                                 if ec == ExitSuccess+                                    then putInfo "Prehook ran successfully.\n"+                                    else putErr  "Prehook failed!\n"+                                 return ec+                   _ -> do putInfo "Prehook cancelled..."+                           return ExitSuccess+      where maybeAskUser+                | RunPrehook `elem` opts = const $ return "yes"+                | otherwise = askUser+\end{code}
+ src/Darcs/TheCommands.lhs view
@@ -0,0 +1,96 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\begin{code}+module Darcs.TheCommands ( command_control_list ) where++import Darcs.Commands.Add ( add )+import Darcs.Commands.AmendRecord ( amendrecord )+import Darcs.Commands.Annotate ( annotate )+import Darcs.Commands.Apply ( apply )+import Darcs.Commands.Changes ( changes )+import Darcs.Commands.Check ( check )+import Darcs.Commands.Convert ( convert )+import Darcs.Commands.Diff+import Darcs.Commands.Dist ( dist )+import Darcs.Commands.Get ( get )+import Darcs.Commands.Init ( initialize )+import Darcs.Commands.Show ( show_command, list, query )+import Darcs.Commands.MarkConflicts ( markconflicts, resolve )+import Darcs.Commands.Mv ( mv, move )+import Darcs.Commands.Optimize ( optimize )+import Darcs.Commands.Pull ( pull )+import Darcs.Commands.Push ( push )+import Darcs.Commands.Put ( put )+import Darcs.Commands.Record ( record, commit )+import Darcs.Commands.Remove ( remove, rm, unadd )+import Darcs.Commands.Repair ( repair )+import Darcs.Commands.Replace ( replace )+import Darcs.Commands.Revert ( revert )+import Darcs.Commands.Rollback ( rollback )+import Darcs.Commands.Send ( send )+import Darcs.Commands.SetPref ( setpref )+import Darcs.Commands.Tag ( tag )+import Darcs.Commands.TrackDown ( trackdown )+import Darcs.Commands.TransferMode ( transfer_mode )+import Darcs.Commands.Unrecord ( unrecord, unpull, obliterate )+import Darcs.Commands.Unrevert ( unrevert )+import Darcs.Commands.WhatsNew ( whatsnew )+import Darcs.Commands ( CommandControl(Command_data,Hidden_command,Group_name) )++command_control_list :: [CommandControl]+command_control_list = [Group_name "Changing and querying the working copy:",+                Command_data add,+                Command_data remove, Hidden_command unadd, Hidden_command rm,+                Command_data mv, Hidden_command move,+                Command_data replace,+                Command_data revert,+                Command_data unrevert,+                Command_data whatsnew,+                Group_name "Copying changes between the working copy and the repository:",+                Command_data record, Hidden_command commit,+                Command_data unrecord,+                Command_data amendrecord,+                Command_data markconflicts, Hidden_command resolve,+                Group_name "Direct modification of the repository:",+                Command_data tag,+                Command_data setpref,+                Group_name "Querying the repository:",+                Command_data diff_command,+                Command_data changes,+                Command_data annotate,+                Command_data dist,+                Command_data trackdown,+                Command_data show_command, Hidden_command list, Hidden_command query,+                Hidden_command transfer_mode,+                Group_name "Copying patches between repositories with working copy update:",+                Command_data pull,+                Command_data obliterate, Hidden_command unpull,+                Command_data rollback,+                Command_data push,+                Command_data send,+                Command_data apply,+                Command_data get,+                Command_data put,+                Group_name "Administrating repositories:",+                Command_data initialize,+                Command_data optimize,+                Command_data check,+                Command_data repair,+                Command_data convert]++\end{code}
+ src/Darcs/URL.hs view
@@ -0,0 +1,76 @@+{-# OPTIONS_GHC -cpp #-}+{-+Copyright (C) 2004 David Roundy++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, 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; see the file COPYING.  If not, write to+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+Boston, MA 02110-1301, USA.+-}++module Darcs.URL (+    is_file, is_url, is_ssh, is_relative, is_absolute,+    is_ssh_nopath+  ) where++import Data.Maybe ( isNothing, isJust )++import Text.Regex ( Regex, mkRegex, matchRegex )+#include "impossible.h"++{-+  Path resolving:+    * A URL contains the sequence "://".+    * A local filepath does not contain colons, except+      as second character (windows drives).+    * A path that is neither a URL nor a local file+      is an ssh-path.++  Examples:+    /usr/repo/foo                 - local file+    c:/src/darcs                  - local file+    http://darcs.net/             - URL+    peter@host:/path              - ssh+    host:/path                    - ssh+++  This means that single-letter hosts in ssh-paths doesn't work,+  unless a username is provided.++  Perhaps ssh-paths should use "ssh://user@host/path"-syntax instead?+-}++match_not_file :: Regex+match_not_file = mkRegex "..+:.+"+match_url :: Regex+match_url = mkRegex ".+://.+"+match_ssh_nopath :: Regex+match_ssh_nopath = mkRegex "^[^:]{2,}:$"++is_relative :: String -> Bool+is_absolute :: String -> Bool+is_file :: String -> Bool+is_url :: String -> Bool+is_ssh :: String -> Bool+is_ssh_nopath :: String -> Bool++is_relative (_:':':_) = False+is_relative f@(c:_) = is_file f && c /= '/' && c /= '~'+is_relative "" = bug "Empty filename in is_relative"++is_absolute f = is_file f && (not $ is_relative f)++is_file fou = isNothing $ matchRegex match_not_file fou+is_url s = isJust $ matchRegex match_url s+is_ssh s = not (is_file s || is_url s)+is_ssh_nopath s = isJust $ matchRegex match_ssh_nopath s
+ src/Darcs/Utils.lhs view
@@ -0,0 +1,287 @@+% Various utility functions that do not belong anywhere else.++\begin{code}+{-# OPTIONS_GHC -cpp -fffi #-}++module Darcs.Utils ( catchall, ortryrunning, nubsort, breakCommand,+                     clarify_errors, prettyException,+                    putStrLnError, putDocLnError,+                    withCurrentDirectory, withUMask, askUser, stripCr,+                    showHexLen, add_to_error_loc,+                    maybeGetEnv, firstNotBlank, firstJustM, firstJustIO,+                    isUnsupportedOperationError, isHardwareFaultError,+                    get_viewer, edit_file, promptYorn, promptCharFancy, without_buffering,+                    formatPath ) where++import Prelude hiding ( catch )+import Control.Exception ( bracket, bracket_, catch, Exception(IOException) )+import Control.Concurrent ( threadWaitRead, newEmptyMVar, takeMVar, putMVar, forkIO )+import GHC.IOBase ( IOException(ioe_location),+                    IOErrorType(UnsupportedOperation, HardwareFault) )+import System.IO.Error ( isUserError, ioeGetErrorType, ioeGetErrorString )++import Darcs.SignalHandler ( catchNonSignal )+import Numeric ( showHex )+import System.Exit ( ExitCode(..) )+import System.Environment ( getEnv )+import System.IO ( hFlush, hPutStrLn, stderr, stdout, stdin,+                   BufferMode ( NoBuffering ),+                   hLookAhead, hReady, hSetBuffering, hGetBuffering, hIsTerminalDevice )+import Data.Char ( toUpper )+import System.Directory ( setCurrentDirectory )+import Workaround ( getCurrentDirectory )+import Data.Maybe ( listToMaybe, isJust )+import Data.List ( group, sort )+import Control.Monad ( when )+import Exec ( exec_interactive )+import Printer ( Doc, hPutDocLn )+import Foreign.C.String ( CString, withCString )+import Foreign.C.Error ( throwErrno )+import Foreign.C.Types ( CInt )++import Darcs.Progress ( withoutProgress )++#ifdef WIN32+import Control.Monad ( liftM )+import System.Posix.Internals ( getEcho, setCooked, setEcho )+#endif++showHexLen :: (Integral a) => Int -> a -> String+showHexLen n x = let s = showHex x ""+                 in replicate (n - length s) ' ' ++ s++add_to_error_loc :: Exception -> String -> Exception+add_to_error_loc (IOException ioe) s+    = IOException $ ioe { ioe_location = s ++ ": " ++ ioe_location ioe }+add_to_error_loc e _ = e++isUnsupportedOperationError :: IOError -> Bool+isUnsupportedOperationError = isUnsupportedOperationErrorType . ioeGetErrorType++isUnsupportedOperationErrorType :: IOErrorType -> Bool+isUnsupportedOperationErrorType UnsupportedOperation = True+isUnsupportedOperationErrorType _ = False++isHardwareFaultError :: IOError -> Bool+isHardwareFaultError = isHardwareFaultErrorType . ioeGetErrorType++isHardwareFaultErrorType :: IOErrorType -> Bool+isHardwareFaultErrorType HardwareFault = True+isHardwareFaultErrorType _ = False++catchall :: IO a -> IO a -> IO a+a `catchall` b = a `catchNonSignal` (\_ -> b)++maybeGetEnv :: String -> IO (Maybe String)+maybeGetEnv s = (getEnv s >>= return.Just) `catchall` return Nothing -- err can only be isDoesNotExist+++-- |The firstJustM returns the first Just entry in a list of monadic operations.  This is close to+--  `listToMaybe `fmap` sequence`, but the sequence operator evaluates all monadic members of the+--  list before passing it along (i.e. sequence is strict).  The firstJustM is lazy in that list+--  member monads are only evaluated up to the point where the first Just entry is obtained.+firstJustM :: Monad m => [m (Maybe a)] -> m (Maybe a)+firstJustM [] = return Nothing+firstJustM (e:es) = e >>= (\v -> if isJust v then return v else firstJustM es)++-- |The firstJustIO is a slight modification to firstJustM: the+--  entries in the list must be IO monad operations and the+--  firstJustIO will silently turn any monad call that throws an+--  exception into Nothing, basically causing it to be ignored.+firstJustIO :: [IO (Maybe a)] -> IO (Maybe a)+firstJustIO = firstJustM . map (\o -> o `catchall` return Nothing)+++clarify_errors :: IO a -> String -> IO a+clarify_errors a e = a `catch` (\x -> fail $ unlines [prettyException x,e])++prettyException :: Control.Exception.Exception -> String+prettyException (IOException e) | isUserError e = ioeGetErrorString e+prettyException e = show e++ortryrunning :: Monad m => m ExitCode -> m ExitCode -> m ExitCode+a `ortryrunning` b = do ret <- a+                        if ret == ExitSuccess+                           then return ret+                           else b++putStrLnError :: String -> IO ()+putStrLnError = hPutStrLn stderr++putDocLnError :: Doc -> IO ()+putDocLnError = hPutDocLn stderr++withCurrentDirectory :: FilePath -> IO a -> IO a+withCurrentDirectory name m =+    bracket+        (do cwd <- getCurrentDirectory+            when (name /= "") (setCurrentDirectory name)+            return cwd)+        (\oldwd -> setCurrentDirectory oldwd `catchall` return ())+        (const m)++foreign import ccall unsafe "umask.h set_umask" set_umask+    :: CString -> IO CInt+foreign import ccall unsafe "umask.h reset_umask" reset_umask+    :: CInt -> IO CInt++withUMask :: String -> IO a -> IO a+withUMask umask job =+    do rc <-withCString umask set_umask+       when (rc < 0) (throwErrno "Couldn't set umask")+       bracket_+           (return ())+           (reset_umask rc)+           job++-- withThread is used to allow ctrl-C to work even while we're waiting+-- for user input.+withThread :: IO a -> IO a+withThread j = do m <- newEmptyMVar+                  forkIO (j >>= putMVar m)+                  takeMVar m++askUser :: String -> IO String+askUser prompt = withThread $ withoutProgress $ do putStr prompt+                                                   hFlush stdout+                                                   threadWaitRead 0+#ifndef WIN32+                                                   getLine+#else+                                                   stripCr `fmap` getLine+#endif++stripCr :: String -> String+stripCr ""     = ""+stripCr "\r"   = ""+stripCr (c:cs) = c : stripCr cs++-- |Returns Just l where l is first non-blank string in input array; Nothing if no non-blank entries+firstNotBlank :: [String] -> Maybe String+firstNotBlank = listToMaybe . filter ((/=) "")+++-- Format a path for screen output,+-- so that the user sees where the path begins and ends.+-- Could (should?) also warn about unprintable characters here.+formatPath :: String -> String+formatPath path = "\"" ++ quote path ++ "\""+    where quote "" = ""+          quote (c:cs) = if c=='\\' || c=='"'+                         then '\\':c:quote cs+                         else c:quote cs++breakCommand :: String -> (String, [String])+breakCommand s = case words s of+                   (arg0:args) -> (arg0,args)+                   [] -> (s,[])++nubsort :: Ord a => [a] -> [a]+nubsort = map head . group . sort++\end{code}++\begin{code}+edit_file :: String -> IO ExitCode+edit_file f = do+  ed <- get_editor+  exec_interactive ed f+             `ortryrunning` exec_interactive "emacs" f+             `ortryrunning` exec_interactive "emacs -nw" f+             `ortryrunning` exec_interactive "nano" f+#ifdef WIN32+             `ortryrunning` exec_interactive "edit" f+#endif+get_editor :: IO String+get_editor = getEnv "DARCS_EDITOR" `catchall`+             getEnv "DARCSEDITOR" `catchall`+             getEnv "VISUAL" `catchall`+             getEnv "EDITOR" `catchall` return "vi"+\end{code}++\begin{code}+get_viewer :: IO String+get_viewer = getEnv "DARCS_PAGER" `catchall`+             getEnv "PAGER" `catchall` return "less"+\end{code}++\begin{code}+promptYorn :: [Char] -> IO Char+promptYorn p = promptCharFancy p "yn" Nothing []++promptCharFancy :: String -> [Char] -> Maybe Char -> [Char] -> IO Char+promptCharFancy p chs md help_chs =+ do a <- withThread $ without_buffering $+           do putStr $ p ++ " ["++ setDefault chs ++"]" ++ helpStr+              hFlush stdout+              threadWaitRead 0+              getChar+    when (a /= '\n') $ putStr "\n" +    case () of +     _ | a `elem` chs                   -> return a+       | a == ' ' -> case md of Nothing -> tryAgain +                                Just d  -> return d+       | a `elem` help_chs              -> return a+       | otherwise                      -> tryAgain+ where + helpStr = case help_chs of+           []    -> ""+           (h:_) -> ", or " ++ (h:" for help: ")+ tryAgain = do putStrLn "Invalid response, try again!"+               promptCharFancy p chs md help_chs+ setDefault s = case md of Nothing -> s+                           Just d  -> map (setUpper d) s+ setUpper d c = if d == c then toUpper c else c++without_buffering :: IO a -> IO a+without_buffering job = withoutProgress $ do+    bracket nobuf rebuf $ \_ -> job+    where nobuf = do is_term <- hIsTerminalDevice stdin+                     bi <- hGetBuffering stdin+                     raw <- get_raw_mode+                     when is_term $ do hSetBuffering stdin NoBuffering `catch` \_ -> return ()+                                       set_raw_mode True+                     return (bi,raw)+          rebuf (bi,raw) = do is_term <- hIsTerminalDevice stdin+#if SYS == windows+                              buffers <- hGetBuffering stdin+                              hSetBuffering stdin NoBuffering `catch` \_ -> return ()+                              drop_returns+                              hSetBuffering stdin buffers `catch` \_ -> return ()+#else+                              drop_returns+#endif+                              when is_term $ do hSetBuffering stdin bi `catch` \_ -> return ()+                                                set_raw_mode raw+          drop_returns = do is_ready <- hReady stdin+                            when is_ready $+                              do threadWaitRead 0+                                 c <- hLookAhead stdin `catch` \_ -> return ' '+                                 when (c == '\n') $+                                   do getChar+                                      drop_returns+\end{code}++Code which was in the module RawMode before. Moved here to break cyclic imports++\begin{code}+#ifdef WIN32++get_raw_mode :: IO Bool+get_raw_mode = not `liftM` getEcho 0+  `catchall` return False -- getEcho sometimes fails when called from scripts++set_raw_mode :: Bool -> IO ()+set_raw_mode raw = setCooked 0 normal >> setEcho 0 normal+ where normal = not raw++#else++get_raw_mode :: IO Bool+get_raw_mode = return False++set_raw_mode :: Bool -> IO ()+set_raw_mode _ = return ()++#endif+\end{code}
+ src/DateMatcher.lhs view
@@ -0,0 +1,142 @@+%  Copyright (C) 2004 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -fglasgow-exts #-}+module DateMatcher ( parseDateMatcher+                   -- for debugging only+                   , DateMatcher(..), getMatchers ) where++import Control.Exception ( catchJust, userErrors )+import Data.Maybe ( isJust )+import System.Time+import IsoDate ( parseDate, englishDateTime, englishInterval, englishLast, iso8601_interval,+                 resetCalendar, subtractFromMCal, getLocalTz,+                 MCalendarTime(..), toMCalendarTime, unsafeToCalendarTime,+                 unsetTime,+               )+import Control.Monad ( liftM )+import Text.ParserCombinators.Parsec ( eof, parse, ParseError )++-- note that we avoid comparing the fields ctYear, etc directly+-- because we want to avoid timezone-related issues (our+-- two dates may not be in the same zone), so we want to normalise+-- for that+withinDay :: CalendarTime -> CalendarTime -> Bool+withinDay a b = within (toClockTime a)+                       (addToClockTime day $ toClockTime a)+                       (toClockTime b)+ where day = TimeDiff 0 0 1 0 0 0 0++dateRange :: MCalendarTime -> MCalendarTime -> CalendarTime -> Bool+dateRange a b c = cDateRange (unsafeToCalendarTime a) (unsafeToCalendarTime b) c++cDateRange :: CalendarTime -> CalendarTime -> CalendarTime -> Bool+cDateRange a b c = within (toClockTime a) (toClockTime b) (toClockTime c)++within :: ClockTime -> ClockTime -> ClockTime -> Bool+within a b c = a <= c && b > c++-- either the same exact date, or within a range+-- we make the simplifying assumption that, for example, if the+-- month is unset, so is the day of month+samePartialDate :: MCalendarTime -> CalendarTime -> Bool+samePartialDate a b_ =+ within clockA+        (addToClockTime interval clockA)+        (toClockTime calB)+ where interval+         | isJust (mctSec a)   = second+         | isJust (mctMin a)   = minute+         | isJust (mctHour a)  = hour+         | isJust (mctYDay a)  = day+         | mctWeek a = maybe week (const day) (mctWDay a)+         | isJust (mctDay a)   = day+         | isJust (mctMonth a) = month+         | otherwise           = year+       year  = TimeDiff 1 0 0 0 0 0 0+       month = TimeDiff 0 1 0 0 0 0 0+       week  = TimeDiff 0 0 7 0 0 0 0+       day   = TimeDiff 0 0 1 0 0 0 0+       hour   = TimeDiff 0 0 0 1 0 0 0+       minute = TimeDiff 0 0 0 0 1 0 0+       second = TimeDiff 0 0 0 0 0 1 0+       --+       clockA = toClockTime $ unsafeToCalendarTime a+       calB   = resetCalendar b_++data DateMatcher = forall d . (Show d) =>+       DM String --  name+          (Either ParseError d) --  parser+          (d -> CalendarTime -> Bool) --  matcher++parseDateMatcher :: String -> IO (CalendarTime -> Bool)+parseDateMatcher d = + do matcher <- tryMatchers `fmap` getMatchers d+    -- Hack: test the matcher against the current date and discard the results.+    -- We just want to make sure it won't throw any exceptions when we use it for real.+    matcher `liftM` now >>= (`seq` return matcher)+ `catchUserError`+    -- If the user enters a date > maxint seconds ago, the toClockTime+    -- function cannot work.+    \e -> if e == "Time.toClockTime: invalid input"+          then error "Can't handle dates that far back!"+          else error e+ where+   catchUserError = catchJust userErrors++getMatchers :: String -> IO [DateMatcher]+getMatchers d =+ do rightNow <- now+    let midnightToday = unsetTime rightNow+        mRightNow = toMCalendarTime rightNow+        matchIsoInterval (Left dur) = dateRange (dur `subtractFromMCal` mRightNow) mRightNow+        matchIsoInterval (Right (a,b)) = dateRange a b+    tzNow <- getLocalTz+    return -- note that the order of these is quite important as some matchers+           -- can match the same date.+          [ DM "from English date"+                (parseDateWith $ englishLast midnightToday)+                (\(a,_) -> cDateRange a rightNow)+          , DM "specific English date"+                (parseDateWith $ englishDateTime midnightToday)+                withinDay+          , DM "English interval"+                (parseDateWith $ englishInterval rightNow)+                (uncurry cDateRange)+          , DM "ISO 8601 interval"+                (parseDateWith $ iso8601_interval tzNow)+                matchIsoInterval+          , DM "CVS, ISO 8601, or old style date"+                (parseDate tzNow d)+                samePartialDate ]+ where+   tillEof p = do { x <- p; eof; return x }+   parseDateWith p = parse (tillEof p) "" d++tryMatchers :: [DateMatcher] -> (CalendarTime -> Bool)+tryMatchers (DM _ parsed matcher : ms) =+  case parsed of+  Left _   -> tryMatchers ms+  Right  d -> matcher d+tryMatchers [] = error "Can't support fancy dates."++now :: IO CalendarTime+now = getClockTime >>= toCalendarTime+\end{code}+
+ src/English.lhs view
@@ -0,0 +1,44 @@+%  Copyright (C) 2008 Eric Kow+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+module English where++englishNum :: Numbered n => Int -> n -> ShowS+englishNum x = if x == 1 then singular else plural++class Numbered a where+  plural :: a -> ShowS+  singular :: a -> ShowS++newtype Noun = Noun String++instance Numbered Noun where+  plural (Noun "") = id+  -- note that this is wrong! consider 'cat-es' and 'dog-es'+  -- but it works for darcs 'patch-es' and 'change-s'+  plural (Noun s) | last s == 'e' = showString s .  showChar 's'+  plural (Noun s) = showString s . showString "es"+  singular (Noun s) =  showString s++data This = This Noun++instance Numbered This where+  plural (This s)   = showString "these "  . plural s+  singular (This s) = showString "this "   . singular s+\end{code}
+ src/Exec.lhs view
@@ -0,0 +1,179 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+{-# OPTIONS_GHC -cpp -fffi -fglasgow-exts #-}+module Exec ( exec, exec_interactive,+              withoutNonBlock,+              Redirects, Redirect(..),+              ExecException(..)+            ) where++import Data.Typeable ( Typeable )++#ifndef WIN32+import Control.Exception ( bracket )+import System.Posix.Env ( setEnv, getEnv, unsetEnv )+import System.Posix.IO ( queryFdOption, setFdOption, FdOption(..), stdInput )+import System.IO	( stdin )+#else+import Control.Exception ( catchJust, Exception(IOException) )+-- WARNING: isInfixOf is not present in ghc 6.4.2!+import Data.List ( isInfixOf )+#endif++import System.Exit ( ExitCode (..) )+import System.Cmd ( system )+import System.IO	( IOMode(..), openBinaryFile, stdout )+import System.Process+import GHC.Handle	( hDuplicate )+        -- urgh.  hDuplicate isn't available from a standard place.+import Workaround       ( bracketOnError )++import Darcs.Global ( whenDebugMode )++{-+   A redirection is a three-tuple of values (in, out, err).+   The most common values are:++     AsIs    don't change it+     Null    /dev/null on Unix, NUL on Windows+     File    open a file for reading or writing++   There is also the value Stdout, which is only meaningful for+   redirection of errors, and is performed AFTER stdout is+   redirected so that output and errors mix together. StdIn and+   StdErr could be added as well if they are useful.++   NOTE: Lots of care must be taken when redirecting stdin, stdout+   and stderr to one of EACH OTHER, since the ORDER in which they+   are changed have a significant effect on the result.+-}++type Redirects = (Redirect, Redirect, Redirect)+data Redirect = AsIs | Null | File FilePath+              | Stdout+                deriving Show++{-+  ExecException is thrown by exec if any system call fails,+  for example because the executable we're trying to run+  doesn't exist.+-}+--                   ExecException cmd    args     redirecs  errorDesc+data ExecException = ExecException String [String] Redirects String+                     deriving (Typeable,Show)+++_dev_null :: FilePath+#ifdef WIN32+_dev_null = "NUL"+#else+_dev_null = "/dev/null"+#endif++{-+  We use System.Process, which does the necessary quoting+  and redirection for us behind the scenes.+-}++exec  :: String -> [String] -> Redirects -> IO ExitCode+exec cmd args (inp,out,err) = do+  h_stdin  <- redirect inp ReadMode+  h_stdout <- redirect out WriteMode+  h_stderr <- redirect err WriteMode+--  putStrLn (unwords (cmd:args ++ map show [inp,out,err]))+  withExit127 $ bracketOnError+    (do whenDebugMode $ putStrLn $ unwords $ cmd:args ++ ["; #"] ++ map show [inp,out,err]+        runProcess cmd args Nothing Nothing h_stdin h_stdout h_stderr)+    (terminateProcess)+    (waitForProcess)+  where+    redirect AsIs               _    = return Nothing+    redirect Null               mode = Just `fmap` openBinaryFile _dev_null mode+    redirect (File "/dev/null") mode = redirect Null mode+    redirect (File f)           mode = Just `fmap` openBinaryFile f mode+    redirect Stdout             _    = Just `fmap` hDuplicate stdout+        -- hDuplicate stdout rather than passing stdout itself,+        -- because runProcess closes the Handles we pass it.++exec_interactive :: String -> String -> IO ExitCode++#ifndef WIN32+{-+This should handle arbitrary commands interpreted by the shell on Unix since+that's what people expect. But we don't want to allow the shell to interpret+the argument in any way, so we set an environment variable and call+cmd "$DARCS_ARGUMENT"+-}+exec_interactive cmd arg = do+  let var = "DARCS_ARGUMENT"+  stdin `seq` return ()+  withoutNonBlock $ bracket+    (do oldval <- getEnv var+        setEnv var arg True+        return oldval)+    (\oldval ->+       do case oldval of+            Nothing -> unsetEnv var+            Just val -> setEnv var val True)+    (\_ -> withExit127 $ system $ cmd++" \"$"++var++"\"")++#else++exec_interactive cmd arg = do+  system $ cmd ++ " " ++ arg+#endif++withoutNonBlock :: IO a -> IO a++#ifndef WIN32+{-+Do IO without NonBlockingRead on stdInput.++This is needed when running unsuspecting external commands with interactive+mode - if read from terminal is non-blocking also write to terminal is+non-blocking.+-}+withoutNonBlock x =+    do nb <- queryFdOption stdInput NonBlockingRead+       if nb+          then bracket+                   (do setFdOption stdInput NonBlockingRead False)+                   (\_ -> setFdOption stdInput NonBlockingRead True)+                   (\_ -> x)+          else do x+#else+withoutNonBlock x = do x+#endif++{-+Ensure that we exit 127 if the thing we are trying to run does not exist+(Only needed under Windows)+-}+withExit127 :: IO ExitCode -> IO ExitCode+#ifdef WIN32+withExit127 a = catchJust notFoundError a (const $ return $ ExitFailure 127)++notFoundError :: Exception -> Maybe ()+notFoundError (IOException e) | "runProcess: does not exist" `isInfixOf` show e = Just ()+notFoundError _ = Nothing+#else+withExit127 = id+#endif+\end{code}
+ src/FastPackedString.hs view
@@ -0,0 +1,741 @@+{-# OPTIONS_GHC -fffi -cpp #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  FastPackedString+-- Copyright   :  (c) The University of Glasgow 2001,+--                    David Roundy 2003-2005+-- License : GPL (I'm happy to also license this file BSD style but don't+--           want to bother distributing two license files with darcs.+--+-- Maintainer  :  droundy@abridgegame.org+-- Stability   :  experimental+-- Portability :  portable+--+-- An efficient implementation of strings.+--+-----------------------------------------------------------------------------++-- Original GHC implementation by Bryan O\'Sullivan,+-- rewritten to use UArray by Simon Marlow.+-- rewritten to support slices and use ForeignPtr by David Roundy++module FastPackedString (+        -- * The @PackedString@ type+        PackedString,    -- abstract, instances: Eq, Ord, Show, Typeable+        unsafeWithInternals, -- :: PackedString -> (Ptr Word8 -> Int -> IO a) -> IO a++         -- * Converting to and from @PackedString@s+    generatePS,  -- :: Int -> (Ptr Word8 -> Int -> IO Int) -> IO PackedString+        packString,  -- :: String -> PackedString+        withCStringPS, -- :: PackedString -> (CString -> IO a) -> IO a+        unsafeWithCStringLenPS, -- :: PackedString -> ((CString,Int) -> IO a) -> IO a+        packWords,   -- :: [Word8] -> PackedString+        unpackPS,    -- :: PackedString -> String+        unpackPSfromUTF8, -- :: PackedString -> String++        -- * I\/O with @PackedString@s+        hPutPS,      -- :: Handle -> PackedString -> IO ()+        hGetPS,      -- :: Handle -> Int -> IO PackedString+    hGetContentsPS, -- :: Handle -> IO PackedString+        readFilePS,  -- :: FilePath -> IO PackedString+        writeFilePS, -- :: FilePath -> PackedString -> IO ()+        gzReadFilePS,-- :: FilePath -> IO PackedString+        mmapFilePS,  -- :: FilePath -> IO PackedString+        gzWriteFilePS,  -- :: FilePath -> PackedString -> IO ()+        gzWriteFilePSs, -- :: FilePath -> [PackedString] -> IO ()++        -- * List-like manipulation functions+        nilPS,       -- :: PackedString+        ifHeadThenTail, -- :: Word8 -> PackedString -> Maybe PackedString+        headPS,      -- :: PackedString -> Char+        tailPS,      -- :: PackedString -> PackedString+        initPS,      -- :: PackedString -> PackedString+        lastPS,      -- :: PackedString -> Char+        nullPS,      -- :: PackedString -> Bool+        appendPS,    -- :: PackedString -> PackedString -> PackedString+        lengthPS,    -- :: PackedString -> Int+        indexPS,     -- :: PackedString -> Int -> Char+        indexPSW,    -- :: PackedString -> Int -> Word8+        reversePS,   -- :: PackedString -> PackedString+        concatPS,    -- :: [PackedString] -> PackedString+        takePS,      -- :: Int -> PackedString -> PackedString+        dropPS,      -- :: Int -> PackedString -> PackedString+        splitAtPS,   -- :: Int -> PackedString -> (PackedString, PackedString)++        anyPS,+        takeWhilePS, -- :: (Char -> Bool) -> PackedString -> PackedString+        dropWhilePS, -- :: (Char -> Bool) -> PackedString -> PackedString+        dropWhitePS, -- :: PackedString -> PackedString+        breakWhitePS,-- :: PackedString -> Maybe (PackedString,PackedString)+        spanEndPS,   -- :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)+        breakPS,     -- :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)+        breakOnPS,   -- :: Char -> PackedString -> (PackedString, PackedString)+        linesPS,     -- :: PackedString -> [PackedString]+        unlinesPS,     -- :: [PackedString] -> PackedString+        findPS,+        hashPS,++        splitPS,     -- :: Char -> PackedString -> [PackedString]++        breakFirstPS,-- :: Char -> PackedString -> Maybe (PackedString,PackedString)+        breakLastPS, -- :: Char -> PackedString -> Maybe (PackedString,PackedString)+        substrPS,    -- :: PackedString -> PackedString -> Maybe Int+        readIntPS,   -- :: PackedString -> Maybe (Int, PackedString)+        is_funky,    -- :: PackedString -> Bool+        fromHex2PS,  -- :: PackedString -> PackedString+        fromPS2Hex,  -- :: PackedString -> PackedString+        betweenLinesPS,--  :: PackedString -> PackedString -> PackedString -> Maybe (PackedString)+        break_after_nth_newline,+        break_before_nth_newline,+    ) where++#ifndef HAVE_BYTESTRING+import OldFastPackedString+#else+import System.IO ( Handle, hClose, hFileSize, IOMode(ReadMode),+            hSeek, SeekMode(SeekFromEnd), hGetChar )+import Autoconf ( use_mmap )++import Foreign.Storable ( peekElemOff, peek )+import Foreign.Marshal.Alloc ( free )+import Foreign.Marshal.Array ( pokeArray, mallocArray,+                               peekArray, advancePtr )+import Foreign.C.String+import Foreign.C.Types ( CInt, CSize )+import Data.Bits ( rotateL )+import Data.Char+import Data.Word+import Data.Int ( Int32 )+import qualified Data.List as L+import Control.Monad ( liftM, when )++import System.IO.Unsafe ( unsafePerformIO )+import System.IO ( hGetBuf )++import System.IO ( openBinaryFile, )++import Foreign.Ptr ( nullPtr, plusPtr, Ptr )+import Foreign.ForeignPtr( ForeignPtr, withForeignPtr )+#if defined(__GLASGOW_HASKELL__)+import qualified Foreign.Concurrent as FC ( newForeignPtr )+import System.Posix ( handleToFd )+#endif++#ifdef DEBUG_PS+import Foreign.ForeignPtr ( addForeignPtrFinalizer )+import Foreign.Ptr ( FunPtr )+#endif+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC+import qualified Data.ByteString.Internal as BI+import qualified Data.ByteString.Unsafe as BU++debugForeignPtr :: ForeignPtr a -> String -> IO ()+#ifdef DEBUG_PS+foreign import ccall unsafe "static fpstring.h debug_alloc" debug_alloc+    :: Ptr a -> CString -> IO ()+foreign import ccall unsafe "static fpstring.h & debug_free" debug_free+    :: FunPtr (Ptr a -> IO ())+debugForeignPtr fp n =+    withCString n $ \cname-> withForeignPtr fp $ \p->+    do debug_alloc p cname+       addForeignPtrFinalizer debug_free fp+#else+debugForeignPtr _ _ = return ()+#endif++mallocForeignPtr :: Int -> IO (ForeignPtr Word8)+mallocForeignPtr = BI.mallocByteString++----------------------------------------------------------------------------+--A way of creating ForeignPtrs outside the IO monad (althogh it still+--isn't entirely "safe", but at least it's convenient.++createPS :: Int -> (Ptr Word8 -> IO ()) -> PackedString+createPS = BI.unsafeCreate++-- -----------------------------------------------------------------------------+-- PackedString type declaration++-- | A space-efficient representation of a 'String', which supports various+-- efficient operations.  A 'PackedString' contains full Unicode 'Char's.+type PackedString = BC.ByteString++-- -----------------------------------------------------------------------------+-- unsafeWithInternals++-- | Do something with the internals of a PackedString. Beware of+-- altering the contents!+unsafeWithInternals :: PackedString -> (Ptr Word8 -> Int -> IO a) -> IO a+unsafeWithInternals ps f+ = case BI.toForeignPtr ps of+   (fp,s,l) -> withForeignPtr fp $ \p -> f (p `plusPtr` s) l++-- -----------------------------------------------------------------------------+-- generatePS++-- | Given the maximum size needed and a function to make the contents+-- of a PackedString, generatePS makes the PackedString. The generating+-- function is required to return the actual size (<= the maximum size).++generatePS :: Int -> (Ptr Word8 -> IO Int) -> IO PackedString+generatePS = BI.createAndTrim++-- -----------------------------------------------------------------------------+-- Constructor functions++nilPS :: PackedString+nilPS = BC.empty++-- | Convert a 'String' into a 'PackedString'+packString :: String -> PackedString+packString = BC.pack++packWords :: [Word8] -> PackedString+packWords s = createPS (length s) $ \p -> pokeArray p s++withCStringPS :: PackedString -> (CString -> IO a) -> IO a+withCStringPS = BC.useAsCString++unsafeWithCStringLenPS :: PackedString -> ((CString, Int) -> IO a) -> IO a+unsafeWithCStringLenPS = BU.unsafeUseAsCStringLen++-- -----------------------------------------------------------------------------+-- Destructor functions (taking PackedStrings apart)++-- | Convert a 'PackedString' into a 'String'+unpackPS :: PackedString -> String+unpackPS = BC.unpack++unpackPSfromUTF8 :: PackedString -> String+unpackPSfromUTF8 ps =+ case BI.toForeignPtr ps of+   (_,_, 0) -> ""+   (x,s,l)  ->+    unsafePerformIO $ withForeignPtr x $ \p->+    do outbuf <- mallocArray l+       lout <- fromIntegral `liftM`+               utf8_to_ints outbuf (p `plusPtr` s) (fromIntegral l)+       when (lout < 0) $ error "Bad UTF8!"+       str <- (map (chr . fromIntegral)) `liftM` peekArray lout outbuf+       free outbuf+       return str++foreign import ccall unsafe "static fpstring.h utf8_to_ints" utf8_to_ints+    :: Ptr Int -> Ptr Word8 -> CInt -> IO CInt++-- -----------------------------------------------------------------------------+-- List-mimicking functions for PackedStrings++{-# INLINE lengthPS #-}+lengthPS :: PackedString -> Int+lengthPS = BC.length++{-# INLINE indexPSW #-}+indexPSW :: PackedString -> Int -> Word8+indexPSW ps i = BI.c2w $ BC.index ps i++{-# INLINE indexPS #-}+indexPS :: PackedString -> Int -> Char+indexPS p i = BC.index p i++{-# INLINE lastPS #-}+lastPS :: PackedString -> Char+lastPS = BC.last++{-# INLINE ifHeadThenTail #-}+ifHeadThenTail :: Word8 -> PackedString -> Maybe PackedString+ifHeadThenTail w ps =+   case BI.toForeignPtr ps of+   (x,s,l) ->+    if l > 0 && w == unsafePerformIO (withForeignPtr x $ \p -> peekElemOff p s)+    then Just $ BI.fromForeignPtr x (s+1) (l-1)+    else Nothing++{-# INLINE headPS #-}+headPS :: PackedString -> Char+headPS = BC.head++-- | Extract the elements after the head of a packed string, which must be non-empty.+{-# INLINE tailPS #-}+tailPS :: PackedString -> PackedString+tailPS = BC.tail++-- | Return all the elements of a packed string except the last one.+-- The string must be finite and non-empty.+{-# INLINE initPS #-}+initPS :: PackedString -> PackedString+initPS = BC.init++{-# INLINE nullPS #-}+nullPS :: PackedString -> Bool+nullPS = BC.null++appendPS :: PackedString -> PackedString -> PackedString+appendPS = BC.append++{-# INLINE takePS #-}+takePS :: Int -> PackedString -> PackedString+takePS = BC.take++{-# INLINE dropPS #-}+dropPS  :: Int -> PackedString -> PackedString+dropPS = BC.drop++{-# INLINE splitAtPS #-}+splitAtPS :: Int -> PackedString -> (PackedString, PackedString)+splitAtPS  = BC.splitAt++-- This must be fast, it's used heavily in Printer. -- jch+anyPS :: (Char -> Bool) -> PackedString -> Bool+anyPS = BC.any++{-# INLINE takeWhilePS #-}+takeWhilePS :: (Char -> Bool) -> PackedString -> PackedString+takeWhilePS = BC.takeWhile++{-# INLINE dropWhilePS #-}+dropWhilePS :: (Char -> Bool) -> PackedString -> PackedString+dropWhilePS = BC.dropWhile++{-# INLINE dropWhitePS #-}+dropWhitePS :: PackedString -> PackedString+dropWhitePS ps =+   case BI.toForeignPtr ps of+   (x,s,l) ->+    unsafePerformIO $ withForeignPtr x $ \p->+    do i <- fromIntegral `liftM`+            first_nonwhite (p `plusPtr` s) (fromIntegral l)+       return $ if i == l then nilPS+                else BI.fromForeignPtr x (s+i) (l-i)++foreign import ccall unsafe "fpstring.h first_nonwhite" first_nonwhite+    :: Ptr Word8 -> CInt -> IO CInt+foreign import ccall unsafe "fpstring.h first_white" first_white+    :: Ptr Word8 -> CInt -> IO CInt++{-# INLINE is_funky #-}+is_funky :: PackedString -> Bool+is_funky ps = case BI.toForeignPtr ps of+   (x,s,l) ->+    unsafePerformIO $ withForeignPtr x $ \p->+    (/=0) `liftM` has_funky_char (p `plusPtr` s) (fromIntegral l)++foreign import ccall unsafe "fpstring.h has_funky_char" has_funky_char+    :: Ptr Word8 -> CInt -> IO CInt++spanEndPS :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)+spanEndPS  = BC.spanEnd++breakPS :: (Char -> Bool) -> PackedString -> (PackedString, PackedString)+breakPS = BC.break++{-# INLINE breakOnPS #-}+breakOnPS :: Char -> PackedString -> (PackedString, PackedString)+breakOnPS c p = case findPS c p of+                Nothing -> (p,nilPS)+                Just n -> (takePS n p, dropPS n p)++{-# INLINE hashPS #-}+hashPS :: PackedString -> Int32+hashPS ps =+   case BI.toForeignPtr ps of+   (x,s,l) ->+    unsafePerformIO $ withForeignPtr x $ \p->+    do hash (p `plusPtr` s) l++hash :: Ptr Word8 -> Int -> IO Int32+hash ptr len = f (0 :: Int32) ptr len+ where f h _ 0 = return h+       f h p n = do x <- peek p+                    let h' =  (fromIntegral x) + (rotateL h 8)+                    f h' (p `advancePtr` 1) (n-1)++{-# INLINE substrPS #-}+substrPS :: PackedString -> PackedString -> Maybe Int+substrPS tok str+    | nullPS tok = Just 0+    | lengthPS tok > lengthPS str = Nothing+    | otherwise = do n <- findPS (headPS tok) str+                     let ttok = tailPS tok+                         reststr = dropPS (n+1) str+                     if ttok == takePS (lengthPS ttok) reststr+                        then Just n+                        else ((n+1)+) `fmap` substrPS tok reststr++{-# INLINE breakWhitePS #-}+breakWhitePS :: PackedString -> (PackedString,PackedString)+breakWhitePS ps =+   case BI.toForeignPtr ps of+   (x,s,l) ->+    unsafePerformIO $ withForeignPtr x $ \p->+    do i <- fromIntegral `liftM` first_white (p `plusPtr` s) (fromIntegral l)+       if i == 0 then return (nilPS, BI.fromForeignPtr x s l)+                 else if i == l+                      then return (BI.fromForeignPtr x s l, nilPS)+                      else return (BI.fromForeignPtr x s i, BI.fromForeignPtr x (s+i) (l-i))++-- TODO: replace breakFirstPS and breakLastPS with definitions based on+-- ByteString's break/breakEnd+{-# INLINE breakFirstPS #-}+breakFirstPS :: Char -> PackedString -> Maybe (PackedString,PackedString)+breakFirstPS c p = case findPS c p of+                   Nothing -> Nothing+                   Just n -> Just (takePS n p, dropPS (n+1) p)++{-# INLINE breakLastPS #-}+breakLastPS :: Char -> PackedString -> Maybe (PackedString,PackedString)+breakLastPS c p = case findLastPS c p of+                  Nothing -> Nothing+                  Just n -> Just (takePS n p, dropPS (n+1) p)++-- TODO: rename+{-# INLINE linesPS #-}+linesPS :: PackedString -> [PackedString]+linesPS ps+         | ps == BC.empty = [BC.pack ""]+         | otherwise = BC.split '\n' ps+{- QuickCheck property:++import Test.QuickCheck+import qualified Data.ByteString.Char8 as BC+import Data.Char+instance Arbitrary BC.ByteString where+    arbitrary = fmap BC.pack arbitrary+instance Arbitrary Char where+  arbitrary = chr `fmap` choose (32,127)+deepCheck = check (defaultConfig { configMaxTest = 10000})+testLines =  deepCheck (\x -> (linesPS x == linesPSOld x))+linesPSOld ps = case  BC.elemIndex '\n' ps of+             Nothing -> [ps]+             Just n -> takePS n ps : linesPS (dropPS (n+1) ps) -}++{-| This function acts exactly like the "Prelude" unlines function, or like+"Data.ByteString.Char8" 'unlines', but with one important difference: it will+produce a string which may not end with a newline! That is:++> unlinesPS ["foo", "bar"]++evaluates to \"foo\nbar\", not \"foo\nbar\n"! This point should hold true for+'linesPS' as well.++TODO: rename this function. -}+{-# INLINE unlinesPS #-}+unlinesPS :: [PackedString] -> PackedString+unlinesPS [] = BC.empty+unlinesPS x  = BC.init $ BC.unlines x+{- QuickCheck property:++testUnlines = deepCheck (\x -> (unlinesPS x == unlinesPSOld x))+unlinesPSOld ss = BC.concat $ intersperse_newlines ss+    where intersperse_newlines (a:b:s) = a : newline : intersperse_newlines (b:s)+          intersperse_newlines s = s+          newline = BC.pack "\n" -}++reversePS :: PackedString -> PackedString+reversePS = BC.reverse++concatPS :: [PackedString] -> PackedString+concatPS = BC.concat++{-# INLINE findPS #-}+findPS :: Char -> PackedString -> Maybe Int+findPS = BC.elemIndex++{-# INLINE findLastPS #-}+findLastPS :: Char -> PackedString -> Maybe Int+findLastPS = BC.elemIndexEnd++------------------------------------------------------------++{-# INLINE splitPS #-}+splitPS :: Char -> PackedString -> [PackedString]+splitPS = BC.split++-- -----------------------------------------------------------------------------+-- hPutPS++-- | Outputs a 'PackedString' to the specified 'Handle'.+--+-- NOTE: the representation of the 'PackedString' in the file is assumed to+-- be in the ISO-8859-1 encoding.  In other words, only the least signficant+-- byte is taken from each character in the 'PackedString'.+hPutPS :: Handle -> PackedString -> IO ()+hPutPS = B.hPut++-- -----------------------------------------------------------------------------+-- hGetPS++-- | Read a 'PackedString' directly from the specified 'Handle'.  This+-- is far more efficient than reading the characters into a 'String'+-- and then using 'packString'.+--+-- NOTE: as with 'hPutPS', the string representation in the file is+-- assumed to be ISO-8859-1.+hGetPS :: Handle -> Int -> IO PackedString+hGetPS = B.hGet++-- -----------------------------------------------------------------------------+-- hGetContentsPS++-- | Read entire handle contents into a 'PackedString'. Note that since we use strict+-- ByteString, hGetContentsPS is not lazy either (unlike most 'getContents' functions).+--+-- NOTE: as with 'hGetPS', the string representation in the file is+-- assumed to be ISO-8859-1.+hGetContentsPS :: Handle -> IO PackedString+hGetContentsPS = B.hGetContents -- ratify hGetContents: just a Data.ByteString import++-- -----------------------------------------------------------------------------+-- readFilePS++-- | Read an entire file directly into a 'PackedString'.  This is far more+-- efficient than reading the characters into a 'String' and then using+-- 'packString'.  It also may be more efficient than opening the file and+-- reading it using hGetPS.+--+-- NOTE: as with 'hGetPS', the string representation in the file is+-- assumed to be ISO-8859-1.++readFilePS :: FilePath -> IO PackedString+readFilePS = B.readFile -- ratify readFile: just a Data.ByteString import++-- -----------------------------------------------------------------------------+-- writeFilePS++-- | Write a 'PackedString' to a file.++writeFilePS :: FilePath -> PackedString -> IO ()+writeFilePS = B.writeFile++-- -----------------------------------------------------------------------------+-- gzReadFilePS++-- | Read an entire file, which may or may not be gzip compressed, directly+-- into a 'PackedString'.++foreign import ccall unsafe "static zlib.h gzopen" c_gzopen+    :: CString -> CString -> IO (Ptr ())+foreign import ccall unsafe "static zlib.h gzclose" c_gzclose+    :: Ptr () -> IO ()+foreign import ccall unsafe "static zlib.h gzread" c_gzread+    :: Ptr () -> Ptr Word8 -> CInt -> IO CInt+foreign import ccall unsafe "static zlib.h gzwrite" c_gzwrite+    :: Ptr () -> Ptr Word8 -> CInt -> IO CInt++gzReadFilePS :: FilePath -> IO PackedString+gzReadFilePS f = do+    h <- openBinaryFile f ReadMode+    header <- hGetPS h 2+    if header /= packString "\31\139"+       then do hClose h+               mmapFilePS f+       else do hSeek h SeekFromEnd (-4)+               len <- hGetLittleEndInt h+               hClose h+               withCString f $ \fstr-> withCString "rb" $ \rb-> do+                 gzf <- c_gzopen fstr rb+                 when (gzf == nullPtr) $ fail $ "problem opening file "++f+                 fp <- mallocForeignPtr len+                 debugForeignPtr fp $ "gzReadFilePS "++f+                 lread <- withForeignPtr fp $ \p ->+                          c_gzread gzf p (fromIntegral len)+                 c_gzclose gzf+                 when (fromIntegral lread /= len) $+                      fail $ "problem gzreading file "++f+                 return $ BI.fromForeignPtr fp 0 len++hGetLittleEndInt :: Handle -> IO Int+hGetLittleEndInt h = do+    b1 <- ord `liftM` hGetChar h+    b2 <- ord `liftM` hGetChar h+    b3 <- ord `liftM` hGetChar h+    b4 <- ord `liftM` hGetChar h+    return $ b1 + 256*b2 + 65536*b3 + 16777216*b4++gzWriteFilePS :: FilePath -> PackedString -> IO ()+gzWriteFilePS f ps = gzWriteFilePSs f [ps]++gzWriteFilePSs :: FilePath -> [PackedString] -> IO ()+gzWriteFilePSs f pss  =+    withCString f $ \fstr -> withCString "wb" $ \wb -> do+    gzf <- c_gzopen fstr wb+    when (gzf == nullPtr) $ fail $ "problem gzopening file for write: "++f+    mapM_ (gzWriteToGzf gzf) pss `catch`+              \_ -> fail $ "problem gzwriting file: "++f+    c_gzclose gzf++gzWriteToGzf :: Ptr () -> PackedString -> IO ()+gzWriteToGzf gzf ps = case BI.toForeignPtr ps of+ (x,s,l) -> do+    lw <- withForeignPtr x $ \p -> c_gzwrite gzf (p `plusPtr` s)+                                                 (fromIntegral l)+    when (fromIntegral lw /= l) $ fail $ "problem in gzWriteToGzf"++-- -----------------------------------------------------------------------------+-- mmapFilePS++-- | Like readFilePS, this reads an entire file directly into a+-- 'PackedString', but it is even more efficient.  It involves directly+-- mapping the file to memory.  This has the advantage that the contents of+-- the file never need to be copied.  Also, under memory pressure the page+-- may simply be discarded, wile in the case of readFilePS it would need to+-- be written to swap.  If you read many small files, mmapFilePS will be+-- less memory-efficient than readFilePS, since each mmapFilePS takes up a+-- separate page of memory.  Also, you can run into bus errors if the file+-- is modified.  NOTE: as with 'readFilePS', the string representation in+-- the file is assumed to be ISO-8859-1.++mmapFilePS :: FilePath -> IO PackedString+mmapFilePS f = if use_mmap+               then do (fp,l) <- mmap f+                       return $ BI.fromForeignPtr fp 0 l+               else readFilePS f++#if defined(__GLASGOW_HASKELL__)+foreign import ccall unsafe "static fpstring.h my_mmap" my_mmap+    :: CSize -> CInt -> IO (Ptr Word8)+foreign import ccall unsafe "static sys/mman.h munmap" c_munmap+    :: Ptr Word8 -> CSize -> IO CInt+foreign import ccall unsafe "static unistd.h close" c_close+    :: CInt -> IO CInt+#endif++mmap :: FilePath -> IO (ForeignPtr Word8, Int)+mmap f = do+    h <- openBinaryFile f ReadMode+    l <- fromIntegral `liftM` hFileSize h+    -- Don't bother mmaping small files because each mmapped file takes up+    -- at least one full VM block.+    if l < mmap_limit+       then do thefp <- mallocForeignPtr l+               debugForeignPtr thefp $ "mmap short file "++f+               withForeignPtr thefp $ \p-> hGetBuf h p l+               hClose h+               return (thefp, l)+       else do+#if defined(__GLASGOW_HASKELL__)+               fd <- fromIntegral `liftM` handleToFd h+               p <- my_mmap (fromIntegral l) fd+               fp <- if p == nullPtr+                     then+#else+               fp <-+#endif+                          do thefp <- mallocForeignPtr l+                             debugForeignPtr thefp $ "mmap short file "++f+                             withForeignPtr thefp $ \p' -> hGetBuf h p' l+                             return thefp+#if defined(__GLASGOW_HASKELL__)+                     else do+                             fp <- FC.newForeignPtr p+                                   (do {c_munmap p $ fromIntegral l;+                                        return (); })+                             debugForeignPtr fp $ "mmap "++f+                             return fp+               c_close fd+#endif+               hClose h+               return (fp, l)+    where mmap_limit = 16*1024+++-- -------------------------------------------------------------------------+-- readIntPS++-- | readIntPS skips any whitespace at the beginning of its argument, and+-- reads an Int from the beginning of the PackedString.  If there is no+-- integer at the beginning of the string, it returns Nothing, otherwise it+-- just returns the int read, along with a PackedString containing the+-- remainder of its input.++readIntPS :: PackedString -> Maybe (Int, PackedString)+readIntPS = BC.readInt . BC.dropWhile isSpace++-- -------------------------------------------------------------------------+-- fromPS2Hex++foreign import ccall unsafe "static fpstring.h conv_to_hex" conv_to_hex+    :: Ptr Word8 -> Ptr Word8 -> CInt -> IO ()++fromPS2Hex :: PackedString -> PackedString+fromPS2Hex ps = case BI.toForeignPtr ps of+          (x,s,l) ->+           createPS (2*l) $ \p -> withForeignPtr x $ \f ->+           conv_to_hex p (f `plusPtr` s) $ fromIntegral l++-- -------------------------------------------------------------------------+-- fromHex2PS++foreign import ccall unsafe "static fpstring.h conv_from_hex" conv_from_hex+    :: Ptr Word8 -> Ptr Word8 -> CInt -> IO ()++fromHex2PS :: PackedString -> PackedString+fromHex2PS ps = case BI.toForeignPtr ps of+          (x,s,l) ->+           createPS (l `div` 2) $ \p -> withForeignPtr x $ \f ->+           conv_from_hex p (f `plusPtr` s) (fromIntegral $ l `div` 2)++-- -------------------------------------------------------------------------+-- betweenLinesPS++-- | betweenLinesPS returns the PackedString between the two lines given,+-- or Nothing if they do not appear.++betweenLinesPS :: PackedString -> PackedString -> PackedString+               -> Maybe (PackedString)+betweenLinesPS start end ps+ = case break (start ==) (linesPS ps) of+       (_, _:rest@(bs1:_)) ->+           case BI.toForeignPtr bs1 of+            (ps1,s1,_) ->+             case break (end ==) rest of+               (_, bs2:_) -> case BI.toForeignPtr bs2 of (_,s2,_) -> Just $ BI.fromForeignPtr ps1 s1 (s2 - s1)+               _ -> Nothing+       _ -> Nothing++-- -------------------------------------------------------------------------+-- break_after_nth_newline++break_after_nth_newline :: Int -> PackedString+                        -> Maybe (PackedString, PackedString)+break_after_nth_newline 0 the_ps | nullPS the_ps = Just (nilPS, nilPS)+break_after_nth_newline n the_ps =+  case BI.toForeignPtr the_ps of+  (fp,the_s,l) ->+   unsafePerformIO $ withForeignPtr fp $ \p ->+   do let findit 0 s | s == end = return $ Just (the_ps, nilPS)+          findit _ s | s == end = return Nothing+          findit 0 s = let left_l = s - the_s+                       in return $ Just (BI.fromForeignPtr fp the_s left_l,+                                         BI.fromForeignPtr fp s (l - left_l))+          findit i s = do w <- peekElemOff p s+                          if w == nl then findit (i-1) (s+1)+                                     else findit i (s+1)+          nl = BI.c2w '\n'+          end = the_s + l+      findit n the_s++-- -------------------------------------------------------------------------+-- break_before_nth_newline++break_before_nth_newline :: Int -> PackedString -> (PackedString, PackedString)+break_before_nth_newline 0 the_ps+ | nullPS the_ps = (nilPS, nilPS)+break_before_nth_newline n the_ps =+ case BI.toForeignPtr the_ps of+ (fp,the_s,l) ->+   unsafePerformIO $ withForeignPtr fp $ \p ->+   do let findit _ s | s == end = return (the_ps, nilPS)+          findit i s = do w <- peekElemOff p s+                          if w == nl+                            then if i == 0+                                 then let left_l = s - the_s+                                      in return (BI.fromForeignPtr fp the_s left_l,+                                                 BI.fromForeignPtr fp s (l - left_l))+                                 else findit (i-1) (s+1)+                            else findit i (s+1)+          nl = BI.c2w '\n'+          end = the_s + l+      findit n the_s+#endif
+ src/FileName.lhs view
@@ -0,0 +1,170 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++FileName is an abstract type intended to facilitate the input and output of+unicode filenames.++\begin{code}+module FileName ( FileName( ),+                  fp2fn, fn2fp,+                  fn2ps, ps2fn,+                  niceps2fn, fn2niceps,+                  break_on_dir, norm_path, own_name, super_name,+                  patch_filename,+                  movedirfilename,+                  encode_white, decode_white,+                  (///),+                  breakup, is_explicitly_relative,+                ) where++import System.IO+import Data.Char ( isAlpha, isSpace, isDigit, chr, ord, toLower )+import qualified UTF8 ( encode )+import Data.Word ( Word8( ) )+import FastPackedString ( PackedString( ),+                          packWords, unpackPSfromUTF8, unpackPS, packString )+\end{code}++\begin{code}+newtype FileName = FN FilePath deriving ( Eq, Ord )+encode :: [Char] -> [Word8]+encode = UTF8.encode++instance Show FileName where+   showsPrec d (FN fp) = showParen (d > app_prec) $ showString "fp2fn " . showsPrec (app_prec + 1) fp+      where app_prec = 10++{-# INLINE fp2fn #-}+fp2fn :: FilePath -> FileName+fp2fn fp = FN fp++{-# INLINE fn2fp #-}+fn2fp :: FileName -> FilePath+fn2fp (FN fp) = fp++{-# INLINE niceps2fn #-}+niceps2fn :: PackedString -> FileName+niceps2fn = FN . decode_white . unpackPS++{-# INLINE fn2niceps #-}+fn2niceps :: FileName -> PackedString+fn2niceps (FN fp) = packString $ encode_white fp++{-# INLINE fn2ps #-}+fn2ps :: FileName -> PackedString+fn2ps (FN fp) = packWords $ encode $ encode_white fp++{-# INLINE ps2fn #-}+ps2fn :: PackedString -> FileName+ps2fn ps = FN $ decode_white $ unpackPSfromUTF8 ps++encode_white :: FilePath -> String+encode_white (c:cs) | isSpace c || c == '\\' =+    '\\' : (show $ ord c) ++ "\\" ++ encode_white cs+encode_white (c:cs) = c : encode_white cs+encode_white [] = []++decode_white :: String -> FilePath+decode_white ('\\':cs) =+    case break (=='\\') cs of+    (theord, '\\':rest) ->+        chr (read theord) : decode_white rest+    _ -> error "malformed filename"+decode_white (c:cs) = c: decode_white cs+decode_white "" = ""+\end{code}++\begin{code}+own_name :: FileName -> FileName+own_name (FN f) = case breakLast '/' f of Nothing -> FN f+                                          Just (_,f') -> FN f'+super_name :: FileName -> FileName+super_name fn = case norm_path fn of+                FN f -> case breakLast '/' f of+                        Nothing -> FN "."+                        Just (d,_) -> FN d+break_on_dir :: FileName -> Maybe (FileName,FileName)+break_on_dir (FN p) = case breakFirst '/' p of+                      Nothing -> Nothing+                      Just (d,f) | d == "." -> break_on_dir $ FN f+                                 | otherwise -> Just (FN d, FN f)+norm_path :: FileName -> FileName -- remove "./"+norm_path (FN p) = FN $ repath $ drop_dotdot $ breakup p++repath :: [String] -> String+repath [] = ""+repath [f] = f+repath (d:p) = d ++ "/" ++ repath p++drop_dotdot :: [String] -> [String]+drop_dotdot ("":p) = drop_dotdot p+drop_dotdot (".":p) = drop_dotdot p+drop_dotdot ("..":p) = ".." : (drop_dotdot p)+drop_dotdot (_:"..":p) = drop_dotdot p+drop_dotdot (d:p) = case drop_dotdot p of+                    ("..":p') -> p'+                    p' -> d : p'+drop_dotdot [] = []++breakup :: String -> [String]+breakup p = case break (=='/') p of+            (d,"") -> [d]+            (d,p') -> d : breakup (tail p')++breakFirst :: Char -> String -> Maybe (String,String)+breakFirst c l = bf [] l+    where bf a (r:rs) | r == c = Just (reverse a,rs)+                      | otherwise = bf (r:a) rs+          bf _ [] = Nothing+breakLast :: Char -> String -> Maybe (String,String)+breakLast c l = case breakFirst c (reverse l) of+                Nothing -> Nothing+                Just (a,b) -> Just (reverse b, reverse a)++(///) :: FileName -> FileName -> FileName+(FN "")///b = norm_path b+a///b = norm_path $ fp2fn $ fn2fp a ++ "/" ++ fn2fp b++safeFileChar :: Char -> Char+safeFileChar c | isAlpha c = toLower c+               | isDigit c = c+               | isSpace c = '-'+safeFileChar _ = '_'++patch_filename :: String -> String+patch_filename summary = name ++ ".dpatch"+    where name = map safeFileChar summary++movedirfilename :: FileName -> FileName -> FileName -> FileName+movedirfilename old new name =+    if name' == old' then new+                     else if length name' > length old' &&+                             take (length old'+1) name' == old'++"/"+                          then fp2fn ("./"++new'++drop (length old') name')+                          else name+    where old' = fn2fp $ norm_path old+          new' = fn2fp $ norm_path new+          name' = fn2fp $ norm_path name++\end{code}++\begin{code}+is_explicitly_relative :: String -> Bool+is_explicitly_relative ('.':'/':_) = True  -- begins with "./"+is_explicitly_relative _ = False+\end{code}
+ src/FileSystem.hs view
@@ -0,0 +1,42 @@+{-# OPTIONS_GHC -cpp #-}+-- Copyright (C) 2004 Karel Gardas+--+-- 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, 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; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++module FileSystem ( make_executable ) where++--+-- This module is intended to provide various filesystem related+-- functions and to hide under-laying OS functionality+--++#ifndef WIN32+import System.Posix ( getFileStatus, setFileMode, unionFileModes,+                      ownerExecuteMode, groupExecuteMode,+                      fileMode+                    )+#endif++make_executable :: FilePath -> IO ()++#ifndef WIN32+make_executable fp = do+                     stat <- getFileStatus fp+                     setFileMode fp (unionFileModes (unionFileModes (fileMode stat) ownerExecuteMode) groupExecuteMode)+#else+make_executable _ = return ()+#endif+
+ src/HTTP.hs view
@@ -0,0 +1,69 @@+{-# OPTIONS_GHC -cpp #-}+module HTTP(copyUrl,fetchUrl,postUrl,exists) where++#ifdef HAVE_HTTP+import Network.HTTP+import Network.URI+import Darcs.Global ( debugMessage )+#endif++copyUrl :: String -> String -> a -> IO ()+copyUrl url file _cache = fetchUrl url >>= writeFile file++exists :: Bool+fetchUrl :: String -> IO String+postUrl+    :: String     -- ^ url+    -> String     -- ^ body+    -> String     -- ^ mime type+    -> IO ()  -- ^ result++#ifdef HAVE_HTTP++headers :: [Header]+headers =  [Header HdrUserAgent $ "darcs-HTTP/" ++ PACKAGE_VERSION]++exists = True++fetchUrl url = case parseURI url of+    Nothing -> fail $ "Invalid URI: " ++ url+    Just uri -> do debugMessage $ "Fetching over HTTP:  "++url+                   resp <- simpleHTTP $ Request { rqURI = uri,+                                                  rqMethod = GET,+                                                  rqHeaders = headers,+                                                  rqBody = "" }+                   case resp of+                     Right res@Response { rspCode = (2,0,0) } -> return (rspBody res)+                     Right Response { rspCode = (x,y,z) } ->+                         fail $ "HTTP " ++ show x ++ show y ++ show z ++ " error getting " ++ show uri+                     Left err -> fail $ show err++postUrl url body mime = case parseURI url of+    Nothing -> fail $ "Invalid URI: " ++ url+    Just uri -> do debugMessage $ "Posting to HTTP:  "++url+                   resp <- simpleHTTP $ Request { rqURI = uri,+                                                  rqMethod = POST,+                                                  rqHeaders = headers ++ [Header HdrContentType mime,+                                                                          Header HdrAccept "text/plain",+                                                                          Header HdrContentLength+                                                                                     (show $ length body) ],+                                                  rqBody = body }+                   case resp of+                     Right res@Response { rspCode = (2,y,z) } -> do+                        putStrLn $ "Success 2" ++ show y ++ show z+                        putStrLn (rspBody res)+                        return ()+                     Right res@Response { rspCode = (x,y,z) } -> do+                        putStrLn $ rspBody res+                        fail $ "HTTP " ++ show x ++ show y ++ show z ++ " error posting to " ++ show uri+                     Left err -> fail $ show err++#else++exists = False+fetchUrl _ = fail "Network.HTTP does not exist"+postUrl _ _ _ = fail "Cannot use http POST because darcs was not compiled with Network.HTTP."++#endif++
+ src/IsoDate.lhs view
@@ -0,0 +1,639 @@+%  Copyright (C) 2003 Peter Simons+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+module IsoDate ( getIsoDateTime, readLocalDate, readUTCDate,+                 parseDate, getLocalTz,+                 englishDateTime, englishInterval, englishLast,+                 iso8601_interval, iso8601_duration,+                 addToCal, subtractFromCal,+                 showIsoDateTime, cleanLocalDate, resetCalendar,+                 MCalendarTime(..), subtractFromMCal, addToMCal,+                 nullMCalendar, toMCalendarTime, unsafeToCalendarTime,+                 unsetTime,+               ) where++import Text.ParserCombinators.Parsec+import System.Time+import System.IO.Unsafe ( unsafePerformIO )+import Data.Char ( toUpper, isDigit )+import Data.Maybe ( fromMaybe )+import Control.Monad ( liftM, liftM2 )++-- | Read/interpret a date string, assuming UTC if timezone+--   is not specified in the string+readUTCDate :: String -> CalendarTime+readUTCDate = readDate 0++-- | Convert a date string into ISO 8601 format (yyyymmdd variant)+--   assuming local timezone if not specified in the string+cleanLocalDate :: String -> String+cleanLocalDate = cleanDate (unsafePerformIO getLocalTz)++-- | Read/interpret a date string, assuming local timezone if not+--   specified in the string+readLocalDate :: String -> CalendarTime+readLocalDate = readDate (unsafePerformIO getLocalTz)++-- | Return the local timezone offset from UTC in seconds+getLocalTz :: IO Int+getLocalTz = ctTZ `liftM` (getClockTime >>= toCalendarTime)++cleanDate :: Int -> String -> String+cleanDate tz d = showIsoDateTime.resetCalendar $ readDate tz d++readDate :: Int -> String -> CalendarTime+readDate tz d =+             case parseDate tz d of+             Left e -> error $ "bad date: "++d++" - "++show e+             Right ct -> resetCalendar $ unsafeToCalendarTime ct++parseDate :: Int -> String -> Either ParseError MCalendarTime+parseDate tz d =+              if length d >= 14 && and (map isDigit $ take 14 d)+              then Right $ toMCalendarTime $+                   CalendarTime (read $ take 4 d)+                                (toEnum $ (+ (-1)) $ read $ take 2 $ drop 4 d)+                                (read $ take 2 $ drop 6 d) -- Day+                                (read $ take 2 $ drop 8 d) -- Hour+                                (read $ take 2 $ drop 10 d) -- Minute+                                (read $ take 2 $ drop 12 d) -- Second+                                0 Sunday 0 -- Picosecond, weekday and day of year unknown+                                "GMT" 0 False+              else let dt = do { x <- date_time tz; eof; return x }+                   in parse dt "" d++showIsoDateTime :: CalendarTime -> String+showIsoDateTime ct = concat [ show $ ctYear ct+                            , twoDigit . show . (+1) . fromEnum $ ctMonth ct+                            , twoDigit . show $ ctDay ct+                            , twoDigit . show $ ctHour ct+                            , twoDigit . show $ ctMin ct+                            , twoDigit . show $ ctSec ct+                            ]+    where twoDigit []          = undefined+          twoDigit x@(_:[])    = '0' : x+          twoDigit x@(_:_:[])  = x+          twoDigit _           = undefined++getIsoDateTime          :: IO String+getIsoDateTime = (showIsoDateTime . toUTCTime) `liftM` getClockTime++----- Parser Combinators ---------------------------------------------++-- |Case-insensitive variant of Parsec's 'char' function.++caseChar        :: Char -> GenParser Char a Char+caseChar c       = satisfy (\x -> toUpper x == toUpper c)++-- |Case-insensitive variant of Parsec's 'string' function.++caseString      :: String -> GenParser Char a ()+caseString cs    = mapM_ caseChar cs <?> cs++-- |Match a parser at least @n@ times.++manyN           :: Int -> GenParser a b c -> GenParser a b [c]+manyN n p+    | n <= 0     = return []+    | otherwise  = liftM2 (++) (count n p) (many p)++-- |Match a parser at least @n@ times, but no more than @m@ times.++manyNtoM        :: Int -> Int -> GenParser a b c -> GenParser a b [c]+manyNtoM n m p+    | n < 0      = return []+    | n > m      = return []+    | n == m     = count n p+    | n == 0     = foldr (<|>) (return []) (map (\x -> try $ count x p) (reverse [1..m]))+    | otherwise  = liftM2 (++) (count n p) (manyNtoM 0 (m-n) p)+++----- Date/Time Parser -----------------------------------------------++date_time :: Int -> CharParser a MCalendarTime+date_time tz =+            choice [try $ toMCalendarTime `fmap` cvs_date_time tz,+                    try $ iso8601_date_time tz,+                    toMCalendarTime `fmap` old_date_time]++cvs_date_time :: Int -> CharParser a CalendarTime+cvs_date_time tz =+                do y <- year+                   char '/'+                   mon <- month_num +                   char '/'+                   d <- day+                   my_spaces+                   h <- hour+                   char ':'+                   m <- minute+                   char ':'+                   s <- second+                   z <- option tz $ my_spaces >> zone+                   return (CalendarTime y mon d h m s 0 Monday 0 "" z False)++old_date_time   :: CharParser a CalendarTime+old_date_time    = do wd <- day_name+                      my_spaces+                      mon <- month_name+                      my_spaces+                      d <- day+                      my_spaces+                      h <- hour+                      char ':'+                      m <- minute+                      char ':'+                      s <- second+                      my_spaces+                      z <- zone+                      my_spaces+                      y <- year+                      return (CalendarTime y mon d h m s 0 wd 0 "" z False)++{- FIXME: In case you ever want to use this outside of darcs, you should note +   that this implementation of ISO 8601 is not complete.  ++   reluctant to implement (ambiguous!): +     * years > 9999  +     * truncated representations with implied century (89 for 1989) +   unimplemented: +     * repeated durations (not relevant)+     * lowest order component fractions in intervals+     * negative dates (BC)                    +   unverified or too relaxed:+     * the difference between 24h and 0h+     * allows stuff like 2005-1212; either you use the hyphen all the way +       (2005-12-12) or you don't use it at all (20051212), but you don't use+       it halfway, likewise with time +     * No bounds checking whatsoever on intervals! +       (next action: read iso doc to see if bounds-checking required?) -}+iso8601_date_time   :: Int -> CharParser a MCalendarTime+iso8601_date_time localTz = try $ +  do d <- iso8601_date+     t <- option id $ try $ do optional $ oneOf " T" +                               iso8601_time  +     return $ t $ d { mctTZ = Just localTz }++iso8601_date :: CharParser a MCalendarTime+iso8601_date = +  do d <- calendar_date <|> week_date <|> ordinal_date+     return $ foldr ($) nullMCalendar d+  where +    calendar_date = -- yyyy-mm-dd+      try $ do d <- optchain year_ [ (dash, month_), (dash, day_) ]+               -- allow other variants to be parsed correctly +               notFollowedBy (digit <|> char 'W')+               return d+    week_date = --yyyy-Www-dd +      try $ do yfn <- year_+               optional dash+               char 'W'+               -- offset human 'week 1' -> computer 'week 0'+               w'  <- (\x -> x-1) `liftM` two_digits+               mwd  <- option Nothing $ do { optional dash; Just `fmap` n_digits 1 }+               let y = resetCalendar . unsafeToCalendarTime . yfn $ nullMCalendar { mctDay = Just 1 }+                   firstDay = ctWDay y+               -- things that make this complicated+               -- 1. iso8601 weeks start from Monday; Haskell weeks start from Sunday+               -- 2. the first week is the one that contains at least Thursday+               --    if the year starts after Thursday, then some days of the year+               --    will have already passed before the first week+               let afterThursday = firstDay == Sunday || firstDay > Thursday+                   w  = if afterThursday then w'+1 else w'+                   yday = (7 * w) + fromMaybe 1 mwd+                   diff c = c { mctWeek = True+                              , mctWDay = toEnum `fmap` mwd+                              , mctDay  = Just yday }+               return [(diff.yfn)]+    ordinal_date = -- yyyy-ddd+      try $ optchain year_ [ (dash, yearDay_) ]+    --+    year_  = try $ do y <- four_digits <?> "year (0000-9999)"+                      return $ \c -> c { mctYear = Just y }+    month_ = try $ do m <- two_digits <?> "month (1 to 12)"+                      return $ \c -> c { mctMonth = Just $ intToMonth m }+    day_   = try $ do d <- two_digits <?> "day in month (1 to 31)"+                      return $ \c -> c { mctDay = Just d }+    yearDay_ = try $ do d <- n_digits 3 <?> "day in year (001 to 366)"+                        return $ \c -> c { mctDay = Just d+                                         , mctYDay = Just (d - 1) }+    dash = char '-'++-- we return a function which sets the time on another calendar+iso8601_time :: CharParser a (MCalendarTime -> MCalendarTime)+iso8601_time = try $+  do ts <- optchain hour_ [ (colon     , min_)+                          , (colon     , sec_)+                          , (oneOf ",.", pico_) ] +     z  <- option id $ choice [ zulu , offset ]+     return $ foldr (.) id (z:ts)+  where +    hour_ = do h <- two_digits+               return $ \c -> c { mctHour = Just h }+    min_  = do m <- two_digits+               return $ \c -> c { mctMin = Just m }+    sec_  = do s <- two_digits+               return $ \c -> c { mctSec = Just s }+    pico_ = do digs <- many digit+               let picoExp = 12+                   digsExp = length digs+               let frac | null digs = 0+                        | digsExp > picoExp = read $ take picoExp digs+                        | otherwise = 10 ^ (picoExp - digsExp) * (read digs)+               return $ \c -> c { mctPicosec = Just $ frac }+    zulu   = do { char 'Z'; return (\c -> c { mctTZ = Just 0 }) }+    offset = do sign <- choice [ do { char '+' >> return   1  }+                               , do { char '-' >> return (-1) } ]+                h <- two_digits+                m <- option 0 $ do { optional colon; two_digits }+                return $ \c -> c { mctTZ = Just $ sign * 60 * ((h*60)+m) }+    colon = char ':'++iso8601_interval :: Int -> CharParser a (Either TimeDiff (MCalendarTime, MCalendarTime))+iso8601_interval localTz = leftDur <|> rightDur where+  leftDur  = +    do dur <- iso8601_duration +       end <- option Nothing $ do { char '/'; Just `liftM` isoDt }+       return $ case end of +                Nothing -> Left dur+                Just e  -> Right (dur `subtractFromMCal` e, e)+  rightDur =+    do start <- isoDt+       char '/'+       durOrEnd <- Left `liftM` iso8601_duration <|> Right `liftM` isoDt+       return $ case durOrEnd of+                Left dur  -> Right (start, dur `addToMCal` start)+                Right end -> Right (start, end)+  isoDt   = iso8601_date_time localTz+   +iso8601_duration :: CharParser a TimeDiff+iso8601_duration = +  do char 'P'+     y   <- block 0 'Y'+     mon <- block 0 'M'+     d   <- block 0 'D'+     (h,m,s) <- option (0,0,0) $ +       do char 'T'+          h' <- block (-1) 'H'+          m' <- block (-1) 'M'+          s' <- block (-1) 'S'+          let unset = (== (-1))+          if all unset [h',m',s'] +             then fail "T should be omitted if time is unspecified"+             else let clear x = if (unset x) then 0 else x+                  in return (clear h', clear m', clear s')+     --+     return $ TimeDiff y mon d h m s 0+  where block d c = option d $ try $+          do n <- many1 digit+             char c +             return $ read n++optchain :: CharParser a b -> [(CharParser a c, CharParser a b)] -> CharParser a [b]+optchain p next = try $ +  do r1 <- p+     r2 <- case next of +           [] -> return []+           ((sep,p2):next2) -> option [] $ do { optional sep; optchain p2 next2 }+     return (r1:r2)++n_digits :: Int -> CharParser a Int +n_digits n = read `liftM` count n digit++two_digits, four_digits :: CharParser a Int+two_digits = n_digits 2+four_digits = n_digits 4++my_spaces :: CharParser a String+my_spaces = manyN 1 $ char ' '++day_name        :: CharParser a Day+day_name         = choice+                       [ caseString "Mon"       >> return Monday+                       , try (caseString "Tue") >> return Tuesday+                       , caseString "Wed"       >> return Wednesday+                       , caseString "Thu"       >> return Thursday+                       , caseString "Fri"       >> return Friday+                       , try (caseString "Sat") >> return Saturday+                       , caseString "Sun"       >> return Sunday+                       ]++year            :: CharParser a Int+year             = four_digits++month_num       :: CharParser a Month+month_num = do mn <- manyNtoM 1 2 digit +               return $ intToMonth $ (read mn :: Int)++intToMonth :: Int -> Month+intToMonth 1 = January+intToMonth 2 = February+intToMonth 3 = March+intToMonth 4 = April+intToMonth 5 = May+intToMonth 6 = June+intToMonth 7 = July+intToMonth 8 = August+intToMonth 9 = September+intToMonth 10 = October+intToMonth 11 = November+intToMonth 12 = December+intToMonth _  = error "invalid month!"++month_name      :: CharParser a Month+month_name       = choice+                       [ try (caseString "Jan") >> return January+                       , caseString "Feb"       >> return February+                       , try (caseString "Mar") >> return March+                       , try (caseString "Apr") >> return April+                       , caseString "May"       >> return May+                       , try (caseString "Jun") >> return June+                       , caseString "Jul"       >> return July+                       , caseString "Aug"       >> return August+                       , caseString "Sep"       >> return September+                       , caseString "Oct"       >> return October+                       , caseString "Nov"       >> return November+                       , caseString "Dec"       >> return December+                       ]++day             :: CharParser a Int+day              = do d <- manyNtoM 1 2 digit+                      return (read d :: Int)++hour            :: CharParser a Int+hour             = two_digits++minute          :: CharParser a Int+minute           = two_digits++second          :: CharParser a Int+second           = two_digits++zone            :: CharParser a Int+zone             = choice+                       [ do { char '+'; h <- hour; m <- minute; return (((h*60)+m)*60) }+                       , do { char '-'; h <- hour; m <- minute; return (-((h*60)+m)*60) }+                       , mkZone "UTC"  0+                       , mkZone "UT"  0+                       , mkZone "GMT" 0+                       , mkZone "EST" (-5)+                       , mkZone "EDT" (-4)+                       , mkZone "CST" (-6)+                       , mkZone "CDT" (-5)+                       , mkZone "MST" (-7)+                       , mkZone "MDT" (-6)+                       , mkZone "PST" (-8)+                       , mkZone "PDT" (-7)+                       , mkZone "CEST" 2+                       , mkZone "EEST" 3+                         -- if we don't understand it, just give a GMT answer...+                       , do { manyTill (oneOf $ ['a'..'z']++['A'..'Z']++[' '])+                                       (lookAhead space_digit);+                              return 0 }+                       ]+     where mkZone n o  = try $ do { caseString n; return (o*60*60) }+           space_digit = try $ do { char ' '; oneOf ['0'..'9'] }++----- English dates and intervals -----------------------------------------------++englishDateTime :: CalendarTime -> CharParser a CalendarTime+englishDateTime now = +  try $ dateMaybeAtTime <|> timeThenDate      +  where +   -- yesterday (at) noon+   dateMaybeAtTime = try $ +     do ed <- englishDate now+        t  <- option Nothing $ try $+                do { space; optional $ caseString "at "; Just `liftM` englishTime }+        return $ fromMaybe id t $ ed+   -- tea time 2005-12-04+   timeThenDate = try $+     do t  <- englishTime +        optional $ char ','+        space+        ed <- englishDate now+        return $ t $ unsetTime $ ed++englishDate :: CalendarTime -> CharParser a CalendarTime+englishDate now = try $ +      (caseString "today"     >> (return $ resetCalendar now))+  <|> (caseString "yesterday" >> (return $ oneDay `subtractFromCal` now) )+  <|> fst `fmap` englishLast now+  <|> englishAgo now+  where oneDay    = TimeDiff 0 0 1 0 0 0 0++englishAgo :: CalendarTime -> CharParser a CalendarTime+englishAgo now =+  -- 4 months ago, 1 day ago, day before yesterday+  try $ do p <- englishDuration+           try $ do space+           (m,ref) <- (try $ caseString "ago" >> return ((-1), now))+                   <|> do m <- beforeMod <|> afterMod+                          space+                          d <- englishDate now+                               <|> fst `fmap` englishLast now+                               <|> unsafeToCalendarTime `fmap` iso8601_date_time (ctTZ now)+                          return (m,d)+           return $ multiplyDiff m p `addToCal` ref+  where+    beforeMod = try $ caseString "before" >> return (-1)+    afterMod  = try $ caseString "after"  >> return 1++englishInterval :: CalendarTime -> CharParser a (CalendarTime, CalendarTime)+englishInterval now = twixt <|> before <|> after <|> inTheLast <|> lastetc+  where +   englishDT = (unsafeToCalendarTime `fmap` iso8601_date_time (ctTZ now)+                <|> englishDateTime now)+   before = try $+     do caseString "before"+        space+        end <- englishDT +        return (theBeginning, end)+   after = try $+     do caseString "after"+        space+        start <- englishDT+        return (start, now)+   twixt = try $ +     do caseString "between"+        space+        start <- englishDT+        space+        caseString "and" +        space+        end <- englishDT +        return (start, end)+   inTheLast = try $+     do caseString "in the last"+        space+        dur <- englishDuration+        return (dur `subtractFromCal` now, now)+   lastetc =+     do l <- englishAgo now+        return (l, now)++englishLast :: CalendarTime -> CharParser a (CalendarTime, CalendarTime)+englishLast now =+    -- last year, last week, last 3 years, etc+    try $ do caseString "last"+             space+             d <- englishDuration+             return (d `subtractFromCal` now, now)++englishTime :: CharParser a (CalendarTime->CalendarTime)+englishTime = try $ +  choice [ wrapM `fmap` iso8601_time+         , namedTime "noon"            12  0 +         , namedTime "midnight"         0  0+         , namedTime "tea time"        16 30+         , namedTime "bed time"         2 30    +         , namedTime "proper bed time" 21 30 ]+  where namedTime name h m = try $ +          do caseString name+             return $ \c -> c { ctHour = h, ctMin = m }+        wrapM f = unsafeToCalendarTime . f . toMCalendarTime++-- this slightly overgenerates, but who cares?+englishDuration :: CharParser a TimeDiff+englishDuration = try $+  do n <- option 1 $ do { x <- many1 digit; space; (return $ read x) }+     b <- base+     optional (caseString "es" <|> caseString "s")+     let current = multiplyDiff n b+     next <- option noTimeDiff $ try $ do +              { optional space; char ',' ; optional space ; englishDuration }+     return $ addDiff current next +  where +  base = choice +         [ try $ caseString "score"      >> (return $ TimeDiff 20 0  0 0 0 0 0) -- why not?+         ,       caseString "year"       >> (return $ TimeDiff  1 0  0 0 0 0 0)+         , try $ caseString "month"      >> (return $ TimeDiff  0 1  0 0 0 0 0)+         ,       caseString "fortnight"  >> (return $ TimeDiff  0 0 14 0 0 0 0)+         ,       caseString "week"       >> (return $ TimeDiff  0 0  7 0 0 0 0)+         ,       caseString "day"        >> (return $ TimeDiff  0 0  1 0 0 0 0)+         ,       caseString "hour"       >> (return $ TimeDiff  0 0  0 1 0 0 0)+         ,       caseString "minute"     >> (return $ TimeDiff  0 0  0 0 1 0 0) +         ,       caseString "second"     >> (return $ TimeDiff  0 0  0 0 0 1 0) ]+   +----- Calendar and TimeDiff manipulation ---------------------------------------------++theBeginning :: CalendarTime+theBeginning = unsafePerformIO $ toCalendarTime $ TOD 0 0++-- | See 'System.Time.CalendarTime', but note the following new fields:+--    'mctWeek'+data MCalendarTime = MCalendarTime+ { mctYear  :: Maybe Int+ , mctMonth :: Maybe Month+ , mctDay   :: Maybe Int+ , mctHour  :: Maybe Int+ , mctMin   :: Maybe Int+ , mctSec   :: Maybe Int+ , mctPicosec :: Maybe Integer+ , mctWDay     :: Maybe Day+ , mctYDay     :: Maybe Int+ , mctTZName   :: Maybe String+ , mctTZ       :: Maybe Int+ , mctIsDST    :: Maybe Bool+ , mctWeek     :: Bool -- is set or not+} deriving Show++toMCalendarTime :: CalendarTime -> MCalendarTime+toMCalendarTime (CalendarTime a b c d e f g h i j k l) =+  MCalendarTime (Just a) (Just b) (Just c) (Just d) (Just e) (Just f)+                (Just g) (Just h) (Just i) (Just j) (Just k) (Just l)+                False++-- | Unsafe in that it plugs in default values for unset fields.+--   See also 'resetCalendar'+unsafeToCalendarTime :: MCalendarTime -> CalendarTime+unsafeToCalendarTime m =+ CalendarTime+  { ctYear = fromMaybe 0 $ mctYear m+  , ctMonth = fromMaybe January $ mctMonth m+  , ctDay = fromMaybe 1 $ mctDay m+  , ctHour = fromMaybe 0 $ mctHour m+  , ctMin = fromMaybe 0 $ mctMin m+  , ctSec = fromMaybe 0 $ mctSec m+  , ctPicosec = fromMaybe 0 $ mctPicosec m+  , ctWDay = fromMaybe Sunday $ mctWDay m+  , ctYDay = fromMaybe 0 $ mctYDay m+  , ctTZName = fromMaybe "" $ mctTZName m+  , ctTZ = fromMaybe 0 $ mctTZ m+  , ctIsDST = fromMaybe False $ mctIsDST m+ }++addToCal :: TimeDiff -> CalendarTime -> CalendarTime+addToCal td = toUTCTime . addToClockTime td . toClockTime++subtractFromCal :: TimeDiff -> CalendarTime -> CalendarTime+subtractFromCal = addToCal . multiplyDiff (-1)++addToMCal :: TimeDiff -> MCalendarTime -> MCalendarTime+addToMCal td mc =+ copyCalendar (addToCal td $ unsafeToCalendarTime mc) mc++subtractFromMCal :: TimeDiff -> MCalendarTime -> MCalendarTime+subtractFromMCal = addToMCal . multiplyDiff (-1)++-- surely there is a more concise way to express these+addDiff :: TimeDiff -> TimeDiff -> TimeDiff+addDiff (TimeDiff a1 a2 a3 a4 a5 a6 a7) (TimeDiff b1 b2 b3 b4 b5 b6 b7) =+  TimeDiff (a1+b1) (a2+b2) (a3+b3) (a4+b4) (a5+b5) (a6+b6) (a7 + b7)++multiplyDiff :: Int -> TimeDiff -> TimeDiff+multiplyDiff m (TimeDiff a1 a2 a3 a4 a5 a6 a7) =+  TimeDiff (a1*m) (a2*m) (a3*m) (a4*m) (a5*m) (a6*m) (a7 * (toInteger m))++nullMCalendar :: MCalendarTime+nullMCalendar = MCalendarTime Nothing Nothing Nothing Nothing Nothing Nothing+                              Nothing Nothing Nothing Nothing Nothing Nothing+                              False++-- | set a calendar to UTC time any eliminate any inconsistencies within+--   (for example, where the weekday is given as "Thursday", but this does not+--   match what the numerical date would lead one to expect)+resetCalendar :: CalendarTime -> CalendarTime+resetCalendar = toUTCTime . toClockTime++copyCalendar :: CalendarTime -> MCalendarTime -> MCalendarTime+copyCalendar c mc = mc+  { mctYear  = mctYear mc  >> Just (ctYear c)+  , mctMonth = mctMonth mc >> Just (ctMonth c)+  , mctDay   = mctDay mc   >> Just (ctDay c)+  , mctHour  = mctHour mc  >> Just (ctHour c)+  , mctMin   = mctMin mc   >> Just (ctMin c)+  , mctSec   = mctSec mc   >> Just (ctSec c)+  , mctPicosec = mctPicosec mc >> Just (ctPicosec c)+  , mctWDay = mctWDay mc   >> Just (ctWDay c)+  , mctYDay = mctYDay mc   >> Just (ctYDay c)+  , mctTZName = mctTZName mc >> Just (ctTZName c)+  , mctTZ     = mctTZ mc    >> Just (ctTZ c)+  , mctIsDST  = mctIsDST mc >> Just (ctIsDST c)+  }++unsetTime :: CalendarTime -> CalendarTime+unsetTime mc = mc+  { ctHour  = 0+  , ctMin   = 0+  , ctSec   = 0+  , ctPicosec = 0+  }+\end{code}
+ src/Lcs.lhs view
@@ -0,0 +1,493 @@+%  Copyright (C) 2002 David Roundy+%  Copyright (C) 2005 Benedikt Schmidt+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\chapter{LCS}++\section{Introduction}+``LCS'' stands for ``Longest Common Subsequence,'' and it is a relatively+challenging problem to find an LCS efficiently.  This module implements+the algorithm described in:+   "An O(ND) Difference Algorithm and its Variations", Eugene Myers,+   Algorithmica Vol. 1 No. 2, 1986, pp. 251-266;+especially the variation described in section 4.2 and most refinements+implemented in GNU diff (D is the edit-distance).+There is currently no heuristic to reduce the running time and produce+suboptimal output for large inputs with many differences. It behaves like+GNU diff with the -d option in this regard.++\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Lcs ( getChanges, aLen,+             BArray, PArray, BSTArray,+             shiftBoundaries ) where++import Control.Monad+import Data.Int+import Control.Monad.ST+import Data.Maybe+import FastPackedString+import Data.Array.Base+import Data.Array.Unboxed+import qualified Data.Map as Map ( lookup, empty, insertWith )+#include "impossible.h"++\end{code}++In the first step, a hash value for every line is calculated and collisions+are marked with a special value. This reduces a string comparison to an+int comparison for line tuples where at least one of the hash values is+not equal to the special value. After that, lines which only exists in one+of the files are removed and marked as changed which reduces the running+time of the following difference algorithm. GNU diff additionally removes+lines that appear very often in the other file in some cases.+The last step tries to create longer changed regions and line up deletions+in the first file to insertions in the second by shifting changed lines+forward and backward.  ++\begin{code}+-- | create a list of changes between a and b, each change has the form+--   (starta, lima, startb, limb) which means that a[starta, lima)+--   has to be replaced by b[startb, limb)+getChanges ::  [PackedString] -> [PackedString]+           -> [(Int,[PackedString],[PackedString])]+getChanges a b = dropStart (initP a) (initP b) 1++dropStart ::  PArray -> PArray -> Int+           -> [(Int,[PackedString],[PackedString])]+dropStart a b off+  | off > (aLen a) = [(off - 1, [], getSlice b off (aLen b))]+  | off > (aLen b) = [(off - 1, getSlice a off (aLen a), [])]+  | a!off == b!off = dropStart a b (off + 1)+  | otherwise      = dropEnd a b off 0++dropEnd ::  PArray -> PArray -> Int -> Int+        -> [(Int,[PackedString],[PackedString])]+dropEnd a b off end+    | off > alast        = [(off - 1, [], getSlice b off blast)]+    | off > blast        = [(off - 1, getSlice a off alast, [])]+    | a!alast == b!blast = dropEnd a b off (end + 1)+    | otherwise          = getChanges' (a, (off, alast)) (b, (off, blast))+  where alast = aLen a - end+        blast = aLen b - end++getSlice :: PArray -> Int -> Int -> [PackedString]+getSlice a from to+  | from > to = []+  | otherwise = (a!(from)):(getSlice a (from + 1) to)++getChanges' :: (PArray, (Int, Int)) -> (PArray, (Int, Int))+            -> [(Int,[PackedString],[PackedString])]+getChanges' (a, abounds) (b, bbounds) =+    map (convertPatch 0 a b) $ createPatch c_a c_b+  where toHash x bnds = listArray bnds [ hashPS $ x!i | i <- range bnds]+        ah = toHash a abounds :: HArray+        mkAMap m (i:is) =+            let ins (_,_,_,new) (collision,_,_,old) =+                    (collision || not (new == old), True, False, old)+                m' = Map.insertWith ins (ah!i) (False, True, False, a!i) m+            in mkAMap m' is+        mkAMap m _ = m+        hm_a = mkAMap Map.empty (range abounds)+        --+        bh = toHash b bbounds :: HArray+        mkBMap m (i:is) =+            let ins (_,_,_,new) (collision,in_a,_,old) =+                    (collision || not (new == old), in_a, True, old)+                m' = Map.insertWith ins (bh!i) (False, False, True, b!i) m+            in mkBMap m' is+        mkBMap m _ = m+        hm = mkBMap hm_a (range bbounds)+        -- take care of collisions, if there are different lines with the+        -- same hash in both files, then set the hash to markColl,+        -- PackedStrings are compared for two lines with the hash markColl+        get (i, h) = case Map.lookup h hm of+                      Just (_,False,_,_) -> Nothing+                      Just (_,_,False,_) -> Nothing+                      Just (False,True,True,_) -> Just (i, h)+                      Just (True,True,True,_) -> Just (i, markColl)+                      Nothing -> impossible++        a' = catMaybes $ map get [(i, ah!i) | i <- range (bounds ah)]+        b' = catMaybes $ map get [(i, bh!i) | i <- range (bounds bh)]++        (c_a, c_b) = diffArr a' b' (a, abounds) (b, bbounds)++-- | mark hash value where collision occured+markColl :: Int32+markColl = 2345677++-- | return arrays with changes in a and b (1 indexed), offsets start with 0+diffArr :: [(Int,Int32)] -> [(Int,Int32)]+        -> (PArray, (Int, Int)) -> (PArray, (Int, Int))+        -> (BArray, BArray)+diffArr a b (p_a, (off_a, l_a)) (p_b, (off_b, l_b)) = runST (+  do let h_a = initH (map snd a)+         h_b = initH (map snd b)+         m_a = initM (map fst a)+         m_b = initM (map fst b)+         end_a = (aLen p_a)+         end_b = (aLen p_b)+     c_a <- initVChanged end_a+     c_b <- initVChanged end_b+     mapM_ (\ (l,_) -> writeArray c_a l False) $ a+     mapM_ (\ (l,_) -> writeArray c_b l False) $ b+     _ <- cmpseq h_a h_b p_a p_b m_a m_b c_a c_b 0 0 (aLen h_a) (aLen h_b)+     let unchanged ar = do {xs <- getElems ar; return $ (length $ filter not $ xs) -1}+     err <- liftM2 (/=) (unchanged c_a) (unchanged c_b)+     when (err) impossible+     -- Mark common lines at beginning and end+     mapM_ (\ i -> writeArray c_a i False ) $ [1..(off_a - 1)]+     mapM_ (\ i -> writeArray c_b i False ) $ [1..(off_b - 1)]+     mapM_ (\ i -> writeArray c_a i False ) $ [(l_a + 1) .. (end_a)]+     mapM_ (\ i -> writeArray c_b i False ) $ [(l_b + 1) .. (end_b)]+     shiftBoundaries c_a c_b p_a 1 1+     shiftBoundaries c_b c_a p_b 1 1+     err1 <- liftM2 (/=) (unchanged c_a) (unchanged c_b)+     when (err1) impossible+     c_a' <- unsafeFreeze c_a+     c_b' <- unsafeFreeze c_b+     return (c_a', c_b'))++-- | set changes array for a and b and return number of changed lines+cmpseq :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray+       -> BSTArray s -> BSTArray s -> Int -> Int -> Int -> Int -> ST s Int+cmpseq _ _ _ _ _ _ _ _ _ _ 0 0 = do return 0+cmpseq h_a h_b p_a p_b m_a m_b c_a c_b off_a off_b l_a l_b = do+  let lim_a = off_a+l_a+      lim_b = off_b+l_b+      off_a' = findSnake h_a h_b p_a p_b m_a m_b off_a off_b l_a l_b off_a off_b+      off_b' = off_b+off_a'-off_a+      lim_a' = findSnakeRev h_a h_b p_a p_b m_a m_b lim_a lim_b off_a' off_b'+      lim_b' = lim_b+lim_a'-lim_a+      l_a' = lim_a'-off_a'+      l_b' = lim_b'-off_b'+  if l_a' == 0 || l_b' == 0+     then if l_a' == 0+             then do when (l_b' > 0) $+                          mapM_ (\i -> writeArray c_b (m_b!i) True)+                                [(off_b' + 1) .. lim_b']+                     return l_b'+             else do when (l_a' > 0) $+                          mapM_ (\i -> writeArray c_a (m_a!i) True)+                                [(off_a' + 1) .. lim_a']+                     return l_a'+     else do let m = l_a' + l_b'+                 del = l_a' - l_b'+                 dodd = odd $ del+             v <- initV m+             vrev <- initVRev m l_a'+             writeArray vrev 0 l_a'+             writeArray v 0 0+             (xmid, ymid, _) <- findDiag 1 h_a h_b p_a p_b m_a m_b v vrev+                                off_a' off_b' l_a' l_b' del dodd+             when ((xmid == 0 && ymid == 0) || (xmid == l_a' && ymid == l_b')+                   || (xmid < 0 || ymid < 0 || xmid > l_a' || ymid > l_b')) +                     impossible+             c1 <- cmpseq h_a h_b p_a p_b m_a m_b c_a c_b+                          off_a' off_b' xmid ymid+             c2 <- cmpseq h_a h_b p_a p_b m_a m_b c_a c_b+                          (off_a' + xmid) (off_b' + ymid)+                          (l_a' - xmid) (l_b' - ymid)+             return $ c1 + c2++-- | return (xmid, ymid, cost) for the two substrings+--   a[off_a+1..off_a+1+l_a] and b+findDiag :: Int -> HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray+         -> VSTArray s -> VSTArray s -> Int -> Int -> Int -> Int -> Int -> Bool+         -> ST s (Int, Int, Int)+findDiag c h_a h_b p_a p_b m_a m_b v vrev off_a off_b l_a l_b del dodd = do+  if c > l_a + l_b then error "findDiag failed" else return ()+  r <- findF+  case r of+    Just (xmid, ymid) -> return (xmid, ymid, (c*2 - 1))+    Nothing ->+      do r' <- findR+         case r' of+           Just (xmid, ymid) -> return (xmid, ymid, c*2)+           Nothing -> findDiag (c + 1) h_a h_b p_a p_b m_a m_b v vrev+                      off_a off_b l_a l_b del dodd+ where fdmax = if c <= l_a then c else l_a - ((l_a + c) `mod` 2)+       rdmax = if c <= l_b then c else l_b - ((l_b + c) `mod` 2)+       lastrdmax = if (c-1) <= l_b then c-1 else l_b-((l_b + (c-1) `mod` 2))+       lastrdmin = -(if (c-1) <= l_a then c-1 else l_a-((l_a + (c-1)) `mod` 2))+       fdmin = -rdmax+       rdmin = -fdmax+       findF = findF' fdmax+       findR = findR' rdmax+       findF' d = do x <- findOne h_a h_b p_a p_b m_a m_b v d off_a off_b l_a l_b+                     if dodd && d - del >= lastrdmin && d - del <= lastrdmax+                        then do xr <- readArray vrev (d - del)+                                if xr <= x then return $ Just (x, x - d)+                                           else if d <= fdmin then return Nothing+                                                              else findF' (d-2)+                        else if d <= fdmin then return Nothing else findF' (d-2)+       findR' d = do x <- findOneRev h_a h_b p_a p_b m_a m_b vrev d del off_a off_b+                     if not dodd && (d + del >= fdmin) && (d + del <= fdmax)+                        then do xf <- readArray v (d + del)+                                if x <= xf then return $ Just (x,x-del-d)+                                           else if d <= rdmin then return Nothing+                                                              else findR' (d-2)+                        else if d <= rdmin then return Nothing else findR' (d-2)++-- | find position on diag d with one more insert/delete going forward+findOne  :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray+         -> VSTArray s -> Int -> Int -> Int -> Int -> Int -> ST s Int +findOne h_a h_b p_a p_b m_a m_b v d off_a off_b l_a l_b = do+  x0 <- do xbelow <- readArray v (d - 1)+           xover <- readArray v (d + 1)+           return $ if xover > xbelow then xover else xbelow + 1+  let y0 = x0 - d+      x = findSnake h_a h_b p_a p_b  m_a m_b (x0+off_a) (y0+off_b)+            l_a l_b off_a off_b+  writeArray v d (x - off_a)+  return (x-off_a)++-- | follow snake from northwest to southeast, x and y are absolute positions+findSnake :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray+          -> Int -> Int -> Int -> Int -> Int -> Int -> Int+findSnake h_a h_b p_a p_b  m_a m_b x y l_a l_b off_a off_b =+  if x < l_a + off_a && y < l_b + off_b && h_a!(x+1) == h_b!(y+1)+       && (h_a!(x+1) /= markColl || p_a!(m_a!(x+1)) == p_b!(m_b!(y+1)))+     then findSnake h_a h_b p_a p_b m_a m_b (x + 1) (y + 1) l_a l_b off_a off_b+     else x++-- | find position on diag d with one more insert/delete going backward+findOneRev :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray+           -> VSTArray s -> Int -> Int -> Int -> Int -> ST s Int +findOneRev h_a h_b p_a p_b m_a m_b v d del off_a off_b = do+  x0 <- do xbelow <- readArray v (d - 1)+           xover <- readArray v (d + 1)+           return $ if xbelow < xover then xbelow else xover-1+  let y0 = x0 - del - d+      x = findSnakeRev h_a h_b p_a p_b m_a m_b (x0+off_a) (y0+off_b)+            off_a off_b+  writeArray v d (x-off_a)+  return (x-off_a)++-- | follow snake from southeast to northwest, x and y are absolute positions+findSnakeRev :: HArray -> HArray -> PArray -> PArray -> MapArray -> MapArray+             -> Int -> Int -> Int -> Int -> Int+findSnakeRev h_a h_b p_a p_b m_a m_b x y off_a off_b =+  if x > off_a && y > off_b && h_a!x == h_b!y+       && (h_a!x /= markColl || p_a!(m_a!x) == p_b!(m_b!y))+     then findSnakeRev h_a h_b p_a p_b m_a m_b (x - 1) (y - 1) off_a off_b+     else x+\end{code}++\begin{code}++-- | try to create nicer diffs by shifting around regions of changed lines+shiftBoundaries :: BSTArray s -> BSTArray s -> PArray -> Int -> Int -> ST s ()+shiftBoundaries c_a c_b p_a i_ j_ =+  do x <- nextChanged c_a i_+     case x of+       Just start ->+             do let skipped = start - i_+                j1 <- nextUnchangedN c_b skipped j_+                end <- nextUnchanged c_a start+                j2 <- nextUnchanged c_b j1+                (i3,j3) <- expand start end j2+                shiftBoundaries c_a c_b p_a i3 j3+       Nothing -> return () -- no change up to end of file+ where noline = (aLen p_a) + 1+       expand start i j =+         do let len = i - start+            (start0,i0,j0) <- shiftBackward start i j+            b <- if j0 > 1 then readArray c_b (j0-1) else return False+            let corr = if b then i0 else noline+            let blank = if p_a!(i0-1) == nilPS then i0+                                               else noline+            (start1,i1,j1,corr1,blank1) <- shiftForward start0 i0 j0 corr blank+            -- prefer corresponding to ending with blank line+            let newi = if corr1 == noline then blank1+                                          else corr1+            (start2,i2,j2) <- moveCorr start1 i1 j1 newi+            if len /= i2 - start2+                then expand start2 i2 j2+                else return (i2, j2)+       shiftBackward start i j =+         if start > 1 && p_a!(i-1) == p_a!(start-1)+            then do when (i == start) impossible+                    b1 <- readArray c_a (i-1)+                    b2 <- readArray c_a (start-1)+                    when ((not b1) || b2) impossible+                    writeArray c_a (i-1) False+                    writeArray c_a (start-1) True+                    b <- if start > 2 then readArray c_a (start-2)+                                      else return False+                    start' <- if b then liftM (1+) (prevUnchanged c_a (start-2))+                                   else return (start-1)+                    j' <- prevUnchanged c_b (j-1)+                    shiftBackward start' (i-1) j'+            else do return (start,i,j)+       shiftForward start i j corr blank =+         if i <= aLen p_a && p_a!i == p_a!start &&+             -- nilPS at the end of file marks empty line after final newline+             not ((i == aLen p_a) && (p_a!i == nilPS))+            then do when (i == start) impossible+                    b1 <- readArray c_a i+                    b2 <- readArray c_a start+                    when ((not b2) ||  b1) impossible+                    writeArray c_a i True+                    writeArray c_a start False+                    i0 <- nextUnchanged c_a (i+1)+                    j0 <- nextUnchanged c_b (j+1)+                    let corr0 = if i0 > (i+1) then noline+                                              else if j0-j > 2 then i0 else corr+                    let blank0 = if i0 > i+1 then noline+                                 else if p_a!(i0-1) == nilPS then i0+                                                             else blank+                    shiftForward (start+1) i0 j0 corr0 blank0+            else do return (start,i,j,corr,blank)+       moveCorr start i j corr =+         if corr >= i+            then return (start,i,j)+            else do b1 <- readArray c_a (i-1)+                    b2 <- readArray c_a (start-1)+                    when ((not b1) || b2) impossible+                    when (p_a!(i-1) /= p_a!(start-1)) impossible+                    writeArray c_a (i-1) False+                    writeArray c_a (start-1) True       +                    j' <- prevUnchanged c_b (j-1)+                    moveCorr (start-1) (i-1) j' corr++-- | goto next unchanged line, return the given line if unchanged+nextUnchanged :: BSTArray s -> Int -> ST s Int+nextUnchanged c i = do+  len <- aLenM c+  if i == len + 1 then return i+     else do b <- readArray c i+             if b then nextUnchanged c (i+1)+                  else return i++-- | skip at least one unchanged line, if there is none advance+--   behind the last line+skipOneUnChanged :: BSTArray s -> Int -> ST s Int+skipOneUnChanged c i = do+  len <- aLenM c+  if i == len + 1+     then return i+     else do b <- readArray c i+             if not b then return (i+1)+                      else skipOneUnChanged c (i+1)++-- | goto n-th next unchanged line+nextUnchangedN :: BSTArray s -> Int -> Int -> ST s Int+nextUnchangedN c n i = do+  if n == 0 then return i+            else do i' <- skipOneUnChanged c i+                    nextUnchangedN c (n-1) i'++-- | goto next changed line, return the given line if changed+nextChanged :: BSTArray s -> Int -> ST s (Maybe Int)+nextChanged c i = do+  len <- aLenM c+  if i <= len+    then do b <- readArray c i+            if not b then nextChanged c (i+1)+                     else return $ Just i+    else return Nothing++-- | goto previous unchanged line, return the given line if unchanged+prevUnchanged :: BSTArray s -> Int -> ST s Int+prevUnchanged c i = do+  b <- readArray c i+  if b then prevUnchanged c (i-1)+       else return i+\end{code}++\begin{code}+type HArray = UArray Int Int32+type BArray = UArray Int Bool+type PArray = Array Int PackedString+type MapArray = UArray Int Int+type VSTArray s = STUArray s Int Int+type BSTArray s = STUArray s Int Bool++initV :: Int -> ST s (VSTArray s)+initV dmax = do+  newArray (-(dmax + 1), dmax + 1) (-1)++initVRev :: Int -> Int -> ST s (VSTArray s)+initVRev dmax xmax = do+  newArray (-(dmax + 1), dmax + 1) (xmax + 1)++-- 1 indexed, v[0] is used as a guard element+initVChanged :: Int -> ST s (BSTArray s)+initVChanged l = do+  a <- newArray (0, l) True+  writeArray a 0 False+  return a+  -- set to false for all lines which have a mapping later+  -- other lines are only present in one of the files++initH :: [Int32] -> HArray+initH a = listArray (0, length a) (0:a)++initM :: [Int] -> MapArray+initM a = listArray (0, length a) (0:a)++initP :: [PackedString] -> PArray+initP a = listArray (0, length a) (nilPS:a)++#if __GLASGOW_HASKELL__ > 604+aLen :: (IArray a e) => a Int e -> Int+aLen a = snd $ bounds a+aLenM :: (MArray a e m) => a Int e -> m Int+aLenM a = getBounds a >>= return . snd+#else+aLen :: HasBounds a => a Int e -> Int+aLen a = snd $ bounds a+aLenM :: (HasBounds a, Monad m) => a Int e -> m Int+aLenM = return . snd . bounds+#endif+\end{code}++\begin{code}+convertPatch :: Int -> PArray -> PArray -> (Int, Int, Int, Int)+             -> (Int,[PackedString],[PackedString])+convertPatch off a b (a0,a1,b0,b1)+ | b0 == b1 = (b0+off,getDelete a a0 a1,[])+ | a0 == a1 = (b0+off,[],getInsert b b0 b1)+ | otherwise = (b0+off,getDelete a a0 a1,getInsert b b0 b1)++getInsert :: PArray -> Int -> Int -> [PackedString]+getInsert b from to+  | from >= to = []+  | otherwise = (b!(from+1)):(getInsert b (from+1) to)+getDelete :: PArray -> Int -> Int -> [PackedString]+getDelete a from to+  | from >= to = []+  | otherwise = (a!(from+1)):(getDelete a (from+1) to)++createPatch :: BArray -> BArray -> [(Int, Int, Int, Int)]+createPatch c_a c_b =+  reverse $ createP c_a c_b (aLen c_a) (aLen c_b)++createP :: BArray -> BArray -> Int -> Int -> [(Int, Int, Int, Int)]+createP _ _ 0 0 = []+createP c_a c_b ia ib =+  if c_a!ia || c_b!ib+     then let ia' = skipChangedRev c_a ia+              ib' = skipChangedRev c_b ib+          in (ia',ia,ib',ib):(createP c_a c_b ia' ib')+     else createP c_a c_b (ia-1) (ib-1)++skipChangedRev :: BArray -> Int -> Int+skipChangedRev c i = if i >= 0 && c!i then skipChangedRev c (i-1) else i+\end{code}
+ src/OldDate.lhs view
@@ -0,0 +1,348 @@+%  Copyright (C) 2003 Peter Simons+%  Copyright (C) 2003,2008 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++This module is intended to provide backwards-compatibility in the parsing+of darcs patches.  In other words: don't change it, new features don't get+added here.  The only user should be Darcs.Patch.Info.++\begin{code}+module OldDate ( readUTCDate, showIsoDateTime ) where++import Text.ParserCombinators.Parsec+import System.Time+import Data.Char ( toUpper, isDigit )+import Control.Monad ( liftM, liftM2 )++-- | Read/interpret a date string, assuming UTC if timezone+--   is not specified in the string+readUTCDate :: String -> CalendarTime+readUTCDate = readDate 0++readDate :: Int -> String -> CalendarTime+readDate tz d =+             case parseDate tz d of+             Left e -> error e+             Right ct -> ct++parseDate :: Int -> String -> Either String CalendarTime+parseDate tz d =+              if length d >= 14 && and (map isDigit $ take 14 d)+              then Right $+                   CalendarTime (read $ take 4 d)+                                (toEnum $ (+ (-1)) $ read $ take 2 $ drop 4 d)+                                (read $ take 2 $ drop 6 d) -- Day+                                (read $ take 2 $ drop 8 d) -- Hour+                                (read $ take 2 $ drop 10 d) -- Minute+                                (read $ take 2 $ drop 12 d) -- Second+                                0 Sunday 0 -- Picosecond, weekday and day of year unknown+                                "GMT" 0 False+              else let dt = do { x <- date_time tz; eof; return x }+                   in case parse dt "" d of+                      Left e -> Left $ "bad date: "++d++" - "++show e+                      Right ct -> Right ct++showIsoDateTime :: CalendarTime -> String+showIsoDateTime ct = concat [ show $ ctYear ct+                            , twoDigit . show . (+1) . fromEnum $ ctMonth ct+                            , twoDigit . show $ ctDay ct+                            , twoDigit . show $ ctHour ct+                            , twoDigit . show $ ctMin ct+                            , twoDigit . show $ ctSec ct+                            ]+    where twoDigit []          = undefined+          twoDigit x@(_:[])    = '0' : x+          twoDigit x@(_:_:[])  = x+          twoDigit _           = undefined++----- Parser Combinators ---------------------------------------------++-- |Case-insensitive variant of Parsec's 'char' function.++caseChar        :: Char -> GenParser Char a Char+caseChar c       = satisfy (\x -> toUpper x == toUpper c)++-- |Case-insensitive variant of Parsec's 'string' function.++caseString      :: String -> GenParser Char a ()+caseString cs    = mapM_ caseChar cs <?> cs++-- |Match a parser at least @n@ times.++manyN           :: Int -> GenParser a b c -> GenParser a b [c]+manyN n p+    | n <= 0     = return []+    | otherwise  = liftM2 (++) (count n p) (many p)++-- |Match a parser at least @n@ times, but no more than @m@ times.++manyNtoM        :: Int -> Int -> GenParser a b c -> GenParser a b [c]+manyNtoM n m p+    | n < 0      = return []+    | n > m      = return []+    | n == m     = count n p+    | n == 0     = foldr (<|>) (return []) (map (\x -> try $ count x p) (reverse [1..m]))+    | otherwise  = liftM2 (++) (count n p) (manyNtoM 0 (m-n) p)+++----- Date/Time Parser -----------------------------------------------++date_time :: Int -> CharParser a CalendarTime+date_time tz =+            choice [try $ cvs_date_time tz,+                    try $ iso8601_date_time tz,+                    old_date_time]++cvs_date_time :: Int -> CharParser a CalendarTime+cvs_date_time tz =+                do y <- year+                   char '/'+                   mon <- month_num +                   char '/'+                   d <- day+                   my_spaces+                   h <- hour+                   char ':'+                   m <- minute+                   char ':'+                   s <- second+                   z <- option tz $ my_spaces >> zone+                   return (CalendarTime y mon d h m s 0 Monday 0 "" z False)++old_date_time   :: CharParser a CalendarTime+old_date_time    = do wd <- day_name+                      my_spaces+                      mon <- month_name+                      my_spaces+                      d <- day+                      my_spaces+                      h <- hour+                      char ':'+                      m <- minute+                      char ':'+                      s <- second+                      my_spaces+                      z <- zone+                      my_spaces+                      y <- year+                      return (CalendarTime y mon d h m s 0 wd 0 "" z False)++{- FIXME: In case you ever want to use this outside of darcs, you should note +   that this implementation of ISO 8601 is not complete.  ++   reluctant to implement (ambiguous!): +     * years > 9999  +     * truncated representations with implied century (89 for 1989) +   unimplemented: +     * repeated durations (not relevant)+     * lowest order component fractions in intervals+     * negative dates (BC)                    +   unverified or too relaxed:+     * the difference between 24h and 0h+     * allows stuff like 2005-1212; either you use the hyphen all the way +       (2005-12-12) or you don't use it at all (20051212), but you don't use+       it halfway, likewise with time +     * No bounds checking whatsoever on intervals! +       (next action: read iso doc to see if bounds-checking required?) -}+iso8601_date_time   :: Int -> CharParser a CalendarTime+iso8601_date_time localTz = try $ +  do d <- iso8601_date+     t <- option id $ try $ do optional $ oneOf " T" +                               iso8601_time  +     return $ t $ d { ctTZ = localTz }++iso8601_date :: CharParser a CalendarTime+iso8601_date = +  do d <- calendar_date <|> week_date <|> ordinal_date+     return $ foldr ($) nullCalendar d+  where +    calendar_date = -- yyyy-mm-dd+      try $ do d <- optchain year_ [ (dash, month_), (dash, day_) ]+               -- allow other variants to be parsed correctly +               notFollowedBy (digit <|> char 'W')+               return d+    week_date = --yyyy-Www-dd +      try $ do yfn <- year_+               optional dash+               char 'W'+               -- offset human 'week 1' -> computer 'week 0'+               w'  <- (\x -> x-1) `liftM` two_digits+               wd  <- option 1 $ do { optional dash; n_digits 1 }+               let y = yfn nullCalendar+                   firstDay = ctWDay y+               -- things that make this complicated+               -- 1. iso8601 weeks start from Monday; Haskell weeks start from Sunday+               -- 2. the first week is the one that contains at least Thursday+               --    if the year starts after Thursday, then some days of the year+               --    will have already passed before the first week+               let afterThursday = firstDay == Sunday || firstDay > Thursday+                   w  = if afterThursday then w'+1 else w'+                   diff c = c { ctDay = (7 * w) + wd - (fromEnum firstDay) }+               return [(toUTCTime.toClockTime.diff.yfn)]+    ordinal_date = -- yyyy-ddd+      try $ optchain year_ [ (dash, yearDay_) ]+    --+    year_  = try $ do y <- four_digits <?> "year (0000-9999)"+                      return $ \c -> c { ctYear = y }+    month_ = try $ do m <- two_digits <?> "month (1 to 12)"+                      -- we (artificially) use ctPicosec to indicate+                      -- whether the month has been specified.+                      return $ \c -> c { ctMonth = intToMonth m, ctPicosec = 0 }+    day_   = try $ do d <- two_digits <?> "day in month (1 to 31)"+                      return $ \c -> c { ctDay = d }+    yearDay_ = try $ do d <- n_digits 3 <?> "day in year (1 to 366)"+                        return $ \c -> c { ctYDay = d }+    dash = char '-'++-- we return a function which sets the time on another calendar+iso8601_time :: CharParser a (CalendarTime -> CalendarTime)+iso8601_time = try $+  do ts <- optchain hour_ [ (colon     , min_)+                          , (colon     , sec_)+                          , (oneOf ",.", pico_) ] +     z  <- option id $ choice [ zulu , offset ]+     return $ foldr (.) id (z:ts)+  where +    hour_ = do h <- two_digits+               return $ \c -> c { ctHour = h }+    min_  = do m <- two_digits+               return $ \c -> c { ctMin = m }+    sec_  = do s <- two_digits+               return $ \c -> c { ctSec = s }+    pico_ = do digs <- many digit+               let picoExp = 12+                   digsExp = length digs+               let frac | null digs = 0+                        | digsExp > picoExp = read $ take picoExp digs+                        | otherwise = 10 ^ (picoExp - digsExp) * (read digs)+               return $ \c -> c { ctPicosec = frac }+    zulu   = do { char 'Z'; return (\c -> c { ctTZ = 0 }) }+    offset = do sign <- choice [ do { char '+' >> return   1  }+                               , do { char '-' >> return (-1) } ]+                h <- two_digits+                m <- option 0 $ do { optional colon; two_digits }+                return $ \c -> c { ctTZ = sign * 60 * ((h*60)+m) }+    colon = char ':'++optchain :: CharParser a b -> [(CharParser a c, CharParser a b)] -> CharParser a [b]+optchain p next = try $ +  do r1 <- p+     r2 <- case next of +           [] -> return []+           ((sep,p2):next2) -> option [] $ do { optional sep; optchain p2 next2 }+     return (r1:r2)++n_digits :: Int -> CharParser a Int +n_digits n = read `liftM` count n digit++two_digits, four_digits :: CharParser a Int+two_digits = n_digits 2+four_digits = n_digits 4++my_spaces :: CharParser a String+my_spaces = manyN 1 $ char ' '++day_name        :: CharParser a Day+day_name         = choice+                       [ caseString "Mon"       >> return Monday+                       , try (caseString "Tue") >> return Tuesday+                       , caseString "Wed"       >> return Wednesday+                       , caseString "Thu"       >> return Thursday+                       , caseString "Fri"       >> return Friday+                       , try (caseString "Sat") >> return Saturday+                       , caseString "Sun"       >> return Sunday+                       ]++year            :: CharParser a Int+year             = four_digits++month_num       :: CharParser a Month+month_num = do mn <- manyNtoM 1 2 digit +               return $ intToMonth $ (read mn :: Int)++intToMonth :: Int -> Month+intToMonth 1 = January+intToMonth 2 = February+intToMonth 3 = March+intToMonth 4 = April+intToMonth 5 = May+intToMonth 6 = June+intToMonth 7 = July+intToMonth 8 = August+intToMonth 9 = September+intToMonth 10 = October+intToMonth 11 = November+intToMonth 12 = December+intToMonth _  = error "invalid month!"++month_name      :: CharParser a Month+month_name       = choice+                       [ try (caseString "Jan") >> return January+                       , caseString "Feb"       >> return February+                       , try (caseString "Mar") >> return March+                       , try (caseString "Apr") >> return April+                       , caseString "May"       >> return May+                       , try (caseString "Jun") >> return June+                       , caseString "Jul"       >> return July+                       , caseString "Aug"       >> return August+                       , caseString "Sep"       >> return September+                       , caseString "Oct"       >> return October+                       , caseString "Nov"       >> return November+                       , caseString "Dec"       >> return December+                       ]++day             :: CharParser a Int+day              = do d <- manyNtoM 1 2 digit+                      return (read d :: Int)++hour            :: CharParser a Int+hour             = two_digits++minute          :: CharParser a Int+minute           = two_digits++second          :: CharParser a Int+second           = two_digits++zone            :: CharParser a Int+zone             = choice+                       [ do { char '+'; h <- hour; m <- minute; return (((h*60)+m)*60) }+                       , do { char '-'; h <- hour; m <- minute; return (-((h*60)+m)*60) }+                       , mkZone "UTC"  0+                       , mkZone "UT"  0+                       , mkZone "GMT" 0+                       , mkZone "EST" (-5)+                       , mkZone "EDT" (-4)+                       , mkZone "CST" (-6)+                       , mkZone "CDT" (-5)+                       , mkZone "MST" (-7)+                       , mkZone "MDT" (-6)+                       , mkZone "PST" (-8)+                       , mkZone "PDT" (-7)+                       , mkZone "CEST" 2+                       , mkZone "EEST" 3+                         -- if we don't understand it, just give a GMT answer...+                       , do { manyTill (oneOf $ ['a'..'z']++['A'..'Z']++[' '])+                                       (lookAhead space_digit);+                              return 0 }+                       ]+     where mkZone n o  = try $ do { caseString n; return (o*60*60) }+           space_digit = try $ do { char ' '; oneOf ['0'..'9'] }++nullCalendar :: CalendarTime +nullCalendar = CalendarTime 0 January 0 0 0 0 1 Sunday 0 "" 0 False+\end{code}
+ src/Printer.lhs view
@@ -0,0 +1,329 @@++A Document is at heart ShowS from the prelude+\htmladdnormallink{http://www.haskell.org/onlinereport/standard-prelude.html#\$tShowS}++Essentially, if you give a Doc a string it'll print out whatever it+wants followed by that string. So \verb!(text "foo")! makes the Doc that+prints \verb!"foo"! followed by its argument. The combinator names are taken+from Text.PrettyPrint.HughesPJ, although the behaviour of the two libraries is+slightly different.++The advantage of Printer over simple string appending/concatenating is+that the appends end up associating to the right, e.g.:++\begin{verbatim}+  (text "foo" <> text "bar") <> (text "baz" <> text "quux") ""+= \s -> (text "foo" <> text "bar") ((text "baz" <> text "quux") s) ""+= (text "foo" <> text "bar") ((text "baz" <> text "quux") "")+= (\s -> (text "foo") (text "bar" s)) ((text "baz" <> text "quux") "")+= text "foo" (text "bar" ((text "baz" <> text "quux") ""))+= (\s -> "foo" ++ s) (text "bar" ((text "baz" <> text "quux") ""))+= "foo" ++ (text "bar" ((text "baz" <> text "quux") ""))+= "foo" ++ ("bar" ++ ((text "baz" <> text "quux") ""))+= "foo" ++ ("bar" ++ ((\s -> text "baz" (text "quux" s)) ""))+= "foo" ++ ("bar" ++ (text "baz" (text "quux" "")))+= "foo" ++ ("bar" ++ ("baz" ++ (text "quux" "")))+= "foo" ++ ("bar" ++ ("baz" ++ ("quux" ++ "")))+\end{verbatim}++The Empty alternative comes in because you want+\begin{verbatim}+    text "a" $$ vcat xs $$ text "b"+\end{verbatim}+(\verb!$$! means ``above'', vcat is the list version of \verb!$$!) to be+\verb!"a\nb"! when \verb!xs!  is \verb![]!, but without the concept of an+Empty Document each \verb!$$! would add a \verb!'\n'! and you'd end up with+\verb!"a\n\nb"!. Note that \verb!Empty /= text ""! (the latter would cause two+\verb!'\n'!s).++This code was made generic in the element type by Juliusz Chroboczek.+\begin{code}+module Printer (Printable(..), Doc(Doc,unDoc), Printers, Printers'(..), Printer, Color(..),+                hPutDoc,     hPutDocLn,     putDoc,     putDocLn,+                hPutDocWith, hPutDocLnWith, putDocWith, putDocLnWith,+                renderString, renderStringWith, renderPS, renderPSWith,+                renderPSs, renderPSsWith, lineColor,+                prefix, colorText, invisibleText, hiddenText, hiddenPrefix, userchunk, text,+                printable, wrap_text,+                blueText, redText, greenText, magentaText, cyanText,+                unsafeText, unsafeBoth, unsafeBothText, unsafeChar,+                invisiblePS, packedString, unsafePackedString, userchunkPS,+                simplePrinters, invisiblePrinter, simplePrinter,+                doc, empty, (<>), (<?>), (<+>), ($$), vcat, vsep, hcat,+                minus, newline, plus, space, backslash, lparen, rparen,+                parens,+                errorDoc,+               ) where++import Control.Monad.Reader (Reader, runReader, ask, asks, local)+import Data.List (intersperse)+import System.IO (Handle, stdout, hPutStr)+import FastPackedString (PackedString, packString, hPutPS, unpackPS, concatPS)++data Printable = S !String+               | PS !PackedString+               | Both !String !PackedString++space_p, newline_p :: Printable+space_p   = Both " "  (packString " ")+newline_p = S "\n"++space, newline, plus, minus, backslash :: Doc+space     = unsafeBoth " "  (packString " ")+newline   = unsafeChar '\n'+minus     = unsafeBoth "-"  (packString "-")+plus      = unsafeBoth "+"  (packString "+")+backslash = unsafeBoth "\\" (packString "\\")++lparen, rparen :: Doc+lparen = unsafeBoth  "(" (packString "(")+rparen = unsafeBoth ")" (packString ")")++parens :: Doc -> Doc+parens d = lparen <> d <> rparen++errorDoc :: Doc -> a+errorDoc = error . renderStringWith simplePrinters'++putDocWith, putDocLnWith :: Printers -> Doc -> IO ()+putDocWith prs = hPutDocWith prs stdout+putDocLnWith prs = hPutDocLnWith prs stdout++putDoc, putDocLn :: Doc -> IO ()+putDoc = hPutDoc stdout+putDocLn = hPutDocLn stdout++hPutDocWith, hPutDocLnWith :: Printers -> Handle -> Doc -> IO ()+hPutDocWith prs h d = hPrintPrintables h (renderWith (prs h) d)+hPutDocLnWith prs h d = hPutDocWith prs h (d <?> newline)++hPutDoc, hPutDocLn :: Handle -> Doc -> IO ()+hPutDoc = hPutDocWith simplePrinters+hPutDocLn = hPutDocLnWith simplePrinters++hPrintPrintables :: Handle -> [Printable] -> IO ()+hPrintPrintables h = mapM_ (hPrintPrintable h)++hPrintPrintable :: Handle -> Printable -> IO ()+hPrintPrintable h (S ps) = hPutStr h ps+hPrintPrintable h (PS ps) = hPutPS h ps+hPrintPrintable h (Both _ ps) = hPutPS h ps++newtype Doc = Doc { unDoc :: Reader St Document }++data St = St { printers :: !Printers', current_prefix :: !DocumentInternals }+type Printers = Handle -> Printers'+data Printers' = Printers {colorP :: !(Color -> Printer),+                           invisibleP :: !Printer,+                           hiddenP :: !Printer,+                           userchunkP :: !Printer,+                           defP :: !Printer,+                           lineColorT :: !(Color -> Doc -> Doc),+                           lineColorS :: !DocumentInternals+                          }+type Printer = Printable -> Reader St Document++data Color = Blue | Red | Green | Cyan | Magenta++type DocumentInternals = [Printable] -> [Printable]+data Document = Document DocumentInternals+              | Empty++renderString :: Doc -> String+renderString = renderStringWith simplePrinters'++renderStringWith :: Printers' -> Doc -> String+renderStringWith prs d = concatMap toString $ renderWith prs d+    where toString (S s) = s+          toString (PS ps) = unpackPS ps+          toString (Both s _) = s++renderPS :: Doc -> PackedString+renderPS = renderPSWith simplePrinters'++renderPSs :: Doc -> [PackedString]+renderPSs = renderPSsWith simplePrinters'++renderPSWith :: Printers' -> Doc -> PackedString+renderPSWith prs d = concatPS $ renderPSsWith prs d++renderPSsWith :: Printers' -> Doc -> [PackedString]+renderPSsWith prs d = map toPS $ renderWith prs d+    where toPS (S s) = packString s+          toPS (PS ps) = ps+          toPS (Both _ ps) = ps++renderWith :: Printers' -> Doc -> [Printable]+renderWith ps (Doc d) = case runReader d (init_state ps) of+                        Empty -> []+                        Document f -> f []++init_state :: Printers' -> St+init_state prs = St { printers = prs, current_prefix = id }++prefix :: String -> Doc -> Doc+prefix s (Doc d) =+    Doc $ local (\st -> st { current_prefix = current_prefix st . (p:) })+                   (do d' <- d+                       case d' of+                           Document d'' -> return $ Document $ (p:) . d''+                           Empty -> return Empty)+    where p = S s++lineColor :: Color -> Doc -> Doc+lineColor c d =+    Doc $ do pr <- asks printers+             unDoc $ lineColorT pr c d++hiddenPrefix :: String -> Doc -> Doc+hiddenPrefix s (Doc d) =+    Doc $ do pr <- asks printers+             let p = S (renderStringWith pr $ hiddenText s)+             local (\st -> st { current_prefix = current_prefix st . (p:) })+                       (do d' <- d+                           case d' of+                             Document d'' -> return $ Document $ (p:) . d''+                             Empty -> return Empty)++unsafeBoth :: String -> PackedString -> Doc+unsafeBoth s ps = Doc $ simplePrinter (Both s ps)++unsafeBothText :: String -> Doc+unsafeBothText s = Doc $ simplePrinter (Both s (packString s))++packedString, unsafePackedString, invisiblePS, userchunkPS :: PackedString -> Doc+packedString = printable . PS+unsafePackedString = Doc . simplePrinter . PS+invisiblePS = invisiblePrintable . PS+userchunkPS = userchunkPrintable . PS++unsafeChar :: Char -> Doc+unsafeChar = unsafeText . return++text, unsafeText, invisibleText, hiddenText, userchunk, blueText, redText, greenText, magentaText, cyanText :: String -> Doc+text = printable . S+unsafeText = Doc . simplePrinter . S+invisibleText = invisiblePrintable . S+hiddenText = hiddenPrintable . S+userchunk = userchunkPrintable . S+blueText = colorText Blue+redText = colorText Red+greenText = colorText Green+magentaText = colorText Magenta+cyanText = colorText Cyan++colorText :: Color -> String -> Doc+colorText c = mkColorPrintable c . S++wrap_text :: Int -> String -> Doc+wrap_text n s =+    vcat $ map text $ reverse $ "": (foldl add_to_line [] $ words s)+  where add_to_line [] a = [a]+        add_to_line ("":d) a = (a:d)+        add_to_line (l:ls) new | length l + length new > n = new:l:ls+        add_to_line (l:ls) new = (l ++ " " ++ new):ls++printable, invisiblePrintable, hiddenPrintable, userchunkPrintable :: Printable -> Doc+printable x = Doc $ do st <- ask+                       defP (printers st) x+mkColorPrintable :: Color -> Printable -> Doc+mkColorPrintable c x = Doc $ do st <- ask+                                colorP (printers st) c x+invisiblePrintable x = Doc $ do st <- ask+                                invisibleP (printers st) x+hiddenPrintable x = Doc $ do st <- ask+                             hiddenP (printers st) x+userchunkPrintable x = Doc $ do st <- ask+                                userchunkP (printers st) x++simplePrinters :: Printers+simplePrinters _ = simplePrinters'++simplePrinters' :: Printers'+simplePrinters'  = Printers { colorP = const simplePrinter,+                              invisibleP = simplePrinter,+                              hiddenP = invisiblePrinter,+                              userchunkP = simplePrinter,+                              defP = simplePrinter,+                              lineColorT = const id,+                              lineColorS = id+                            }++simplePrinter :: Printer+invisiblePrinter :: Printer+simplePrinter x = unDoc $ doc (\s -> x:s)+invisiblePrinter _ = unDoc empty++infixr 6 <>+infixr 6 <+>+infixr 5 $$++empty :: Doc+empty = Doc $ return Empty+doc :: ([Printable] -> [Printable]) -> Doc+doc f = Doc $ return $ Document f++(<>), (<?>), (<+>), ($$) :: Doc -> Doc -> Doc+-- a then b+Doc a <> Doc b =+   Doc $ do ad <- a+            case ad of+                Empty -> b+                Document af ->+                    do bd <- b+                       return $ Document (\s -> af $ case bd of+                                                         Empty -> s+                                                         Document bf -> bf s)++-- empty if a empty, else a then b+Doc a <?> Doc b =+    Doc $ do ad <- a+             case ad of+                 Empty -> return Empty+                 Document af ->+                     do bd <- b+                        return $ Document (\s -> af $ case bd of+                                                          Empty -> s+                                                          Document bf -> bf s)++-- a then space then b+Doc a <+> Doc b =+    Doc $ do ad <- a+             case ad of+                 Empty -> b+                 Document af ->+                     do bd <- b+                        return $ Document (\s -> af $ case bd of+                                                          Empty -> s+                                                          Document bf ->+                                                              space_p:bf s)++-- a above b+Doc a $$ Doc b =+   Doc $ do ad <- a+            case ad of+                Empty -> b+                Document af ->+                    do bd <- b+                       st <- ask+                       let pf = current_prefix st+                           sf = lineColorS $ printers st+                       return $ Document (\s -> af+                                              $ case bd of+                                                    Empty -> s+                                                    Document bf ->+                                                        sf (newline_p:pf (bf s)))++vcat :: [Doc] -> Doc+vcat [] = empty+vcat ds = foldr1 ($$) ds++vsep :: [Doc] -> Doc+vsep [] = empty+vsep ds = foldr1 ($$) $ intersperse (text "") ds++hcat :: [Doc] -> Doc+hcat [] = empty+hcat ds = foldr1 (<>) ds+\end{code}+
+ src/RegChars.lhs view
@@ -0,0 +1,54 @@+%  Copyright (C) 2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.+++\begin{code}+module RegChars ( regChars,+                ) where++(&&&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)+(&&&) a b c = a c && b c++(|||) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)+(|||) a b c = a c || b c++{-# INLINE regChars #-}+regChars :: String -> (Char -> Bool)+regChars ('^':cs) = not . normalRegChars (unescapeChars cs)+regChars ('\\':'^':cs) = normalRegChars $ unescapeChars $ '^':cs+regChars cs = normalRegChars $ unescapeChars cs++{-# INLINE unescapeChars #-}+unescapeChars :: String -> String+unescapeChars ('\\':'n':cs) = '\n' : unescapeChars cs+unescapeChars ('\\':'t':cs) = '\t' : unescapeChars cs+unescapeChars ('\\':'^':cs) = '^' : unescapeChars cs+unescapeChars (c:cs) = c : unescapeChars cs+unescapeChars [] = []++{-# INLINE normalRegChars #-}+normalRegChars :: String -> (Char -> Bool)+normalRegChars ('\\':'.':cs) = (=='.') ||| normalRegChars cs+normalRegChars ('\\':'-':cs) = (=='-') ||| normalRegChars cs+normalRegChars ('\\':'\\':cs) = (=='\\') ||| normalRegChars cs+normalRegChars ('\\':c:_) = error $ "'\\"++[c]++"' not supported."+normalRegChars (c1:'-':c2:cs) = ((>= c1) &&& (<= c2)) ||| normalRegChars cs+normalRegChars (c:cs) = (== c) ||| normalRegChars cs+normalRegChars [] = \_ -> False+\end{code}++
+ src/SHA1.lhs view
@@ -0,0 +1,210 @@+% Copyright (C) 2001, 2004 Ian Lynagh <igloo@earth.li>++% 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, 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; see the file COPYING.  If not, write to+% the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+% Boston, MA 02110-1301, USA.++\begin{code}+{-# OPTIONS_GHC -fglasgow-exts -fno-warn-name-shadowing #-}+-- -fglasgow-exts needed for nasty hack below+-- name shadowing disabled because a,b,c,d,e are shadowed loads in step 4+module SHA1 (sha1PS) where++import Autoconf (big_endian)+import FastPackedString (PackedString, unsafeWithInternals,+                         concatPS, packWords, lengthPS)++import Control.Monad (unless)+import Data.Char (intToDigit)+import Data.Bits (xor, (.&.), (.|.), complement, rotateL, shiftL, shiftR)+import Data.Word (Word8, Word32)+import Foreign.Ptr (Ptr, castPtr)+import Foreign.Marshal.Array (advancePtr)+import Foreign.Storable (peek, poke)+import System.IO.Unsafe (unsafePerformIO)++data ABCDE = ABCDE !Word32 !Word32 !Word32 !Word32 !Word32+data XYZ = XYZ !Word32 !Word32 !Word32++sha1PS :: PackedString -> String+sha1PS s = s5+ where s1_2 = sha1_step_1_2_pad_length s+       abcde = sha1_step_3_init+       abcde' = unsafePerformIO+              $ unsafeWithInternals s1_2 (\ptr len ->+                    do let ptr' = castPtr ptr+                       unless big_endian $ fiddle_endianness ptr' len+                       sha1_step_4_main abcde ptr' len)+       s5 = sha1_step_5_display abcde'++fiddle_endianness :: Ptr Word32 -> Int -> IO ()+fiddle_endianness p 0 = p `seq` return ()+fiddle_endianness p n+ = do x <- peek p+      poke p $ shiftL x 24+           .|. shiftL (x .&. 0xff00) 8+           .|. (shiftR x 8 .&. 0xff00)+           .|. shiftR x 24+      fiddle_endianness (p `advancePtr` 1) (n - 4)+\end{code}++sha1_step_1_2_pad_length assumes the length is at most 2^61.+This seems reasonable as the Int used to represent it is normally 32bit,+but obviously could go wrong with large inputs on 64bit machines.+The PackedString library should probably move to Word64s if this is an+issue, though.++\begin{code}+sha1_step_1_2_pad_length :: PackedString -> PackedString+sha1_step_1_2_pad_length s+ = let len = lengthPS s+       num_nuls = (55 - len) `mod` 64+       padding = 128:replicate num_nuls 0+       len_w8s = reverse $ size_split 8 (fromIntegral len*8)+   in concatPS [s, packWords padding, packWords len_w8s]++size_split :: Int -> Integer -> [Word8]+size_split 0 _ = []+size_split p n = fromIntegral d:size_split (p-1) n'+ where (n', d) = divMod n 256++sha1_step_3_init :: ABCDE+sha1_step_3_init = ABCDE 0x67452301 0xefcdab89 0x98badcfe 0x10325476 0xc3d2e1f0+\end{code}++\begin{code}+sha1_step_4_main :: ABCDE -> Ptr Word32 -> Int -> IO ABCDE+sha1_step_4_main abcde _ 0 = return $! abcde+sha1_step_4_main (ABCDE a0@a b0@b c0@c d0@d e0@e) s len+    = do+         (e, b) <- doit f1 0x5a827999 (x 0) a b c d e+         (d, a) <- doit f1 0x5a827999 (x 1) e a b c d+         (c, e) <- doit f1 0x5a827999 (x 2) d e a b c+         (b, d) <- doit f1 0x5a827999 (x 3) c d e a b+         (a, c) <- doit f1 0x5a827999 (x 4) b c d e a+         (e, b) <- doit f1 0x5a827999 (x 5) a b c d e+         (d, a) <- doit f1 0x5a827999 (x 6) e a b c d+         (c, e) <- doit f1 0x5a827999 (x 7) d e a b c+         (b, d) <- doit f1 0x5a827999 (x 8) c d e a b+         (a, c) <- doit f1 0x5a827999 (x 9) b c d e a+         (e, b) <- doit f1 0x5a827999 (x 10) a b c d e+         (d, a) <- doit f1 0x5a827999 (x 11) e a b c d+         (c, e) <- doit f1 0x5a827999 (x 12) d e a b c+         (b, d) <- doit f1 0x5a827999 (x 13) c d e a b+         (a, c) <- doit f1 0x5a827999 (x 14) b c d e a+         (e, b) <- doit f1 0x5a827999 (x 15) a b c d e+         (d, a) <- doit f1 0x5a827999 (m 16) e a b c d+         (c, e) <- doit f1 0x5a827999 (m 17) d e a b c+         (b, d) <- doit f1 0x5a827999 (m 18) c d e a b+         (a, c) <- doit f1 0x5a827999 (m 19) b c d e a+         (e, b) <- doit f2 0x6ed9eba1 (m 20) a b c d e+         (d, a) <- doit f2 0x6ed9eba1 (m 21) e a b c d+         (c, e) <- doit f2 0x6ed9eba1 (m 22) d e a b c+         (b, d) <- doit f2 0x6ed9eba1 (m 23) c d e a b+         (a, c) <- doit f2 0x6ed9eba1 (m 24) b c d e a+         (e, b) <- doit f2 0x6ed9eba1 (m 25) a b c d e+         (d, a) <- doit f2 0x6ed9eba1 (m 26) e a b c d+         (c, e) <- doit f2 0x6ed9eba1 (m 27) d e a b c+         (b, d) <- doit f2 0x6ed9eba1 (m 28) c d e a b+         (a, c) <- doit f2 0x6ed9eba1 (m 29) b c d e a+         (e, b) <- doit f2 0x6ed9eba1 (m 30) a b c d e+         (d, a) <- doit f2 0x6ed9eba1 (m 31) e a b c d+         (c, e) <- doit f2 0x6ed9eba1 (m 32) d e a b c+         (b, d) <- doit f2 0x6ed9eba1 (m 33) c d e a b+         (a, c) <- doit f2 0x6ed9eba1 (m 34) b c d e a+         (e, b) <- doit f2 0x6ed9eba1 (m 35) a b c d e+         (d, a) <- doit f2 0x6ed9eba1 (m 36) e a b c d+         (c, e) <- doit f2 0x6ed9eba1 (m 37) d e a b c+         (b, d) <- doit f2 0x6ed9eba1 (m 38) c d e a b+         (a, c) <- doit f2 0x6ed9eba1 (m 39) b c d e a+         (e, b) <- doit f3 0x8f1bbcdc (m 40) a b c d e+         (d, a) <- doit f3 0x8f1bbcdc (m 41) e a b c d+         (c, e) <- doit f3 0x8f1bbcdc (m 42) d e a b c+         (b, d) <- doit f3 0x8f1bbcdc (m 43) c d e a b+         (a, c) <- doit f3 0x8f1bbcdc (m 44) b c d e a+         (e, b) <- doit f3 0x8f1bbcdc (m 45) a b c d e+         (d, a) <- doit f3 0x8f1bbcdc (m 46) e a b c d+         (c, e) <- doit f3 0x8f1bbcdc (m 47) d e a b c+         (b, d) <- doit f3 0x8f1bbcdc (m 48) c d e a b+         (a, c) <- doit f3 0x8f1bbcdc (m 49) b c d e a+         (e, b) <- doit f3 0x8f1bbcdc (m 50) a b c d e+         (d, a) <- doit f3 0x8f1bbcdc (m 51) e a b c d+         (c, e) <- doit f3 0x8f1bbcdc (m 52) d e a b c+         (b, d) <- doit f3 0x8f1bbcdc (m 53) c d e a b+         (a, c) <- doit f3 0x8f1bbcdc (m 54) b c d e a+         (e, b) <- doit f3 0x8f1bbcdc (m 55) a b c d e+         (d, a) <- doit f3 0x8f1bbcdc (m 56) e a b c d+         (c, e) <- doit f3 0x8f1bbcdc (m 57) d e a b c+         (b, d) <- doit f3 0x8f1bbcdc (m 58) c d e a b+         (a, c) <- doit f3 0x8f1bbcdc (m 59) b c d e a+         (e, b) <- doit f2 0xca62c1d6 (m 60) a b c d e+         (d, a) <- doit f2 0xca62c1d6 (m 61) e a b c d+         (c, e) <- doit f2 0xca62c1d6 (m 62) d e a b c+         (b, d) <- doit f2 0xca62c1d6 (m 63) c d e a b+         (a, c) <- doit f2 0xca62c1d6 (m 64) b c d e a+         (e, b) <- doit f2 0xca62c1d6 (m 65) a b c d e+         (d, a) <- doit f2 0xca62c1d6 (m 66) e a b c d+         (c, e) <- doit f2 0xca62c1d6 (m 67) d e a b c+         (b, d) <- doit f2 0xca62c1d6 (m 68) c d e a b+         (a, c) <- doit f2 0xca62c1d6 (m 69) b c d e a+         (e, b) <- doit f2 0xca62c1d6 (m 70) a b c d e+         (d, a) <- doit f2 0xca62c1d6 (m 71) e a b c d+         (c, e) <- doit f2 0xca62c1d6 (m 72) d e a b c+         (b, d) <- doit f2 0xca62c1d6 (m 73) c d e a b+         (a, c) <- doit f2 0xca62c1d6 (m 74) b c d e a+         (e, b) <- doit f2 0xca62c1d6 (m 75) a b c d e+         (d, a) <- doit f2 0xca62c1d6 (m 76) e a b c d+         (c, e) <- doit f2 0xca62c1d6 (m 77) d e a b c+         (b, d) <- doit f2 0xca62c1d6 (m 78) c d e a b+         (a, c) <- doit f2 0xca62c1d6 (m 79) b c d e a+         let abcde' = ABCDE (a0 + a) (b0 + b) (c0 + c) (d0 + d) (e0 + e)+         sha1_step_4_main abcde' (s `advancePtr` 16) (len - 64)+ where {-# INLINE f1 #-}+       f1 (XYZ x y z) = (x .&. y) .|. ((complement x) .&. z)+       {-# INLINE f2 #-}+       f2 (XYZ x y z) = x `xor` y `xor` z+       {-# INLINE f3 #-}+       f3 (XYZ x y z) = (x .&. y) .|. (x .&. z) .|. (y .&. z)+       {-# INLINE x #-}+       x n = peek (s `advancePtr` n)+       {-# INLINE m #-}+       m n = do let base = s `advancePtr` (n .&. 15)+                x0 <- peek base+                x1 <- peek (s `advancePtr` ((n - 14) .&. 15))+                x2 <- peek (s `advancePtr` ((n - 8) .&. 15))+                x3 <- peek (s `advancePtr` ((n - 3) .&. 15))+                let res = rotateL (x0 `xor` x1 `xor` x2 `xor` x3) 1+                poke base res+                return res+       {-# INLINE doit #-}+       doit f k i a b c d e = a `seq` c `seq`+           do i' <- i+              return (rotateL a 5 + f (XYZ b c d) + e + i' + k,+                      rotateL b 30)++sha1_step_5_display :: ABCDE -> String+sha1_step_5_display (ABCDE a b c d e)+ = concatMap showAsHex [a, b, c, d, e]++showAsHex :: Word32 -> String+showAsHex n = showIt 8 n ""+   where+    showIt :: Int -> Word32 -> String -> String+    showIt 0 _ r = r+    showIt i x r = case quotRem x 16 of+                       (y, z) -> let c = intToDigit (fromIntegral z)+                                 in c `seq` showIt (i-1) y (c:r)++\end{code}+
+ src/Ssh.hs view
@@ -0,0 +1,272 @@+{-# OPTIONS_GHC -cpp -fffi #-}++module Ssh ( grabSSH, runSSH, getSSH, copySSH, copySSHs, SSHCmd(..) ) where++import Prelude hiding ( lookup, catch )++import System.Exit ( ExitCode(..) )+import System.Environment ( getEnv )+#ifndef WIN32+import System.Posix.Process ( getProcessID )+#else+import Darcs.Utils ( showHexLen )+import Data.Bits ( (.&.) )+import System.Random ( randomIO )+#endif+import System.IO ( Handle, hPutStr, hPutStrLn, hGetLine, hGetContents, hClose, hFlush )+import System.IO.Unsafe ( unsafePerformIO )+import System.Directory ( doesFileExist )+import Control.Monad ( when )+import System.Process ( runInteractiveProcess )++import Data.Map ( Map, empty, insert, lookup )+import Data.IORef ( IORef, newIORef, readIORef, modifyIORef )++import Darcs.SignalHandler ( catchNonSignal )+import Workaround ( createDirectoryIfMissing )+import Darcs.Utils ( withCurrentDirectory, breakCommand, prettyException, catchall )+import Darcs.Global ( atexit, sshControlMasterDisabled, darcsdir )+import Darcs.Lock ( withTemp, withOpenTemp, tempdir_loc, removeFileMayNotExist )+import Exec ( exec, Redirects, Redirect(..), )+import Darcs.Progress ( debugMessage, debugFail, progressList )++import FastPackedString ( PackedString, unpackPS, readFilePS, writeFilePS, hGetPS )+#include "impossible.h"++{-# NOINLINE sshConnections #-}+sshConnections :: IORef (Map String (Maybe Connection))+sshConnections = unsafePerformIO $ newIORef empty++data Connection = C { inp :: !Handle, out :: !Handle, err :: !Handle, deb :: String -> IO () }++withSSHConnection :: String -> (Connection -> IO a) -> IO a -> IO a+withSSHConnection x withconnection withoutconnection =+    do cs <- readIORef sshConnections+       let uhost = takeWhile (/= ':') x+           url = cleanrepourl x+       case lookup url (cs :: Map String (Maybe Connection)) of+         Just Nothing -> withoutconnection+         Just (Just c) -> withconnection c+         Nothing -> do (ssh,sshargs_) <- getSSHOnly SSH+                       let sshargs = sshargs_ ++ [uhost,"darcs","transfer-mode","--repodir",cleanrepodir x]+                       debugMessage $ "ssh "++unwords sshargs+                       (i,o,e,_) <- runInteractiveProcess ssh sshargs Nothing Nothing+                       l <- hGetLine o+                       if l == "Hello user, I am darcs transfer mode"+                           then return ()+                           else debugFail "Couldn't start darcs transfer-mode on server"+                       let c = C { inp = i, out = o, err = e,+                                   deb = \s -> debugMessage ("with ssh "++uhost++": "++s) }+                       modifyIORef sshConnections (insert url (Just c))+                       withconnection c+                    `catchNonSignal`+                            \e -> do debugMessage $ "Failed to start ssh connection:\n    "+++                                                    prettyException e+                                     severSSHConnection x+                                     withoutconnection++severSSHConnection :: String -> IO ()+severSSHConnection x = do debugMessage $ "Severing ssh failed connection to "++x+                          modifyIORef sshConnections (insert (cleanrepourl x) Nothing)++cleanrepourl :: String -> String+cleanrepourl zzz | take (length dd) zzz == dd = ""+                 where dd = darcsdir++"/"+cleanrepourl (z:zs) = z : cleanrepourl zs+cleanrepourl "" = ""++cleanrepodir :: String -> String+cleanrepodir = cleanrepourl . drop 1 . dropWhile (/= ':')++grabSSH :: String -> Connection -> IO PackedString+grabSSH x c = do+               let dir = drop 1 $ dropWhile (/= ':') x+                   dd = darcsdir++"/"+                   clean zzz | take (length dd) zzz == dd = drop (length dd) zzz+                   clean (_:zs) = clean zs+                   clean "" = bug $ "Buggy path in grabSSH: "++x+                   file = clean dir+                   failwith e = do severSSHConnection x+                                   eee <- hGetContents (err c) -- ratify hGetContents: it's okay+                                                               -- here because we're only grabbing+                                                               -- stderr, and we're also about to+                                                               -- throw the contents.+                                   debugFail $ e ++ " grabbing ssh file "++x++"\n"++eee+               deb c $ "get "++file+               hPutStrLn (inp c) $ "get " ++ file+               hFlush (inp c)+               l2 <- hGetLine (out c)+               if l2 == "got "++file+                  then do showlen <- hGetLine (out c)+                          case reads showlen of+                            [(len,"")] -> hGetPS (out c) len+                            _ -> failwith "Couldn't get length"+                  else if l2 == "error "++file+                       then do e <- hGetLine (out c)+                               case reads e of+                                 (msg,_):_ -> debugFail $ "Error reading file remotely:\n"++msg+                                 [] -> failwith "An error occurred"+                       else failwith "Error"++copySSH :: String -> FilePath -> IO ()+copySSH uRaw f = withSSHConnection uRaw (\c -> grabSSH uRaw c >>= writeFilePS f) $+              do let u = escape_dollar uRaw+                 r <- runSSH SCP u [] [u,f] (AsIs,AsIs,AsIs)+                 when (r /= ExitSuccess) $+                      debugFail $ "(scp) failed to fetch: " ++ u+    where {- '$' in filenames is troublesome for scp, for some reason.. -}+          escape_dollar :: String -> String+          escape_dollar = concatMap tr+           where tr '$' = "\\$"+                 tr c = [c]++copySSHs :: String -> [String] -> FilePath -> IO ()+copySSHs u ns d =+  withSSHConnection u (\c -> withCurrentDirectory d $+                             mapM_ (\n -> grabSSH (u++"/"++n) c >>= writeFilePS n) $+                             progressList "Copying via ssh" ns) $+  do let path = drop 1 $ dropWhile (/= ':') u+         host = takeWhile (/= ':') u+         cd = "cd "++path++"\n"+         input = cd++(unlines $ map ("get "++) ns)+     withCurrentDirectory d $ withOpenTemp $ \(th,tn) ->+         withTemp $ \sftpoutput ->+         do hPutStr th input+            hClose th+            r <- runSSH SFTP u [] [host] (File tn, File sftpoutput, AsIs)+            let files = if length ns > 5+                          then (take 5 ns) ++ ["and "+                               ++ (show (length ns - 5)) ++ " more"]+                          else ns+                hint = if take 1 path == "~"+                         then ["sftp doesn't expand ~, use path/ instead of ~/path/"]+                         else []+            when (r /= ExitSuccess) $ do+                 outputPS <- readFilePS sftpoutput+                 debugFail $ unlines $+                          ["(sftp) failed to fetch files.",+                           "source directory: " ++ path,+                           "source files:"] ++ files +++                          ["sftp output:",unpackPS outputPS] +++                          hint++-- ---------------------------------------------------------------------+-- older ssh helper functions+-- ---------------------------------------------------------------------++data SSHCmd = SSH | SCP | SFTP++instance Show SSHCmd where+  show SSH  = "ssh"+  show SCP  = "scp"+  show SFTP = "sftp"++runSSH :: SSHCmd -> String -> [String] -> [String] -> Redirects -> IO ExitCode+runSSH cmd remoteAddr preArgs postArgs redirs =+ do (ssh, args) <- getSSH cmd remoteAddr+    exec ssh (preArgs ++ args ++ postArgs) redirs++-- | Return the command and arguments needed to run an ssh command+--   along with any extra features like use of the control master.+--   See 'getSSHOnly'+getSSH :: SSHCmd -> String -- ^ remote path+       -> IO (String, [String])+getSSH cmd remoteAddr =+ do (ssh, ssh_args) <- getSSHOnly cmd+    cm_args <- if sshControlMasterDisabled+               then return []+               else do -- control master+                       cmPath <- controlMasterPath remoteAddr+                       hasLaunchedCm <- doesFileExist cmPath+                       when (not hasLaunchedCm) $ launchSSHControlMaster remoteAddr+                       hasCmFeature <- doesFileExist cmPath+                       return $ if hasCmFeature then [ "-o ControlPath=" ++ cmPath ] else []+    let verbosity = case cmd of+                    SCP  -> ["-q"] -- (p)scp is the only one that recognises -q+                                   -- sftp and (p)sftp do not, and plink neither+                    _    -> []+    --+    return (ssh, verbosity ++ ssh_args ++ cm_args)++-- | Return the command and arguments needed to run an ssh command.+--   First try the appropriate darcs environment variable and SSH_PORT+--   defaulting to "ssh" and no specified port.+getSSHOnly :: SSHCmd -> IO (String, [String])+getSSHOnly cmd =+ do ssh_command <- getEnv (evar cmd) `catchall` return (show cmd)+    -- port+    port <- (portFlag cmd `fmap` getEnv "SSH_PORT") `catchall` return []+    let (ssh, ssh_args) = breakCommand ssh_command+    --+    return (ssh, ssh_args ++ port)+    where+     evar SSH  = "DARCS_SSH"+     evar SCP  = "DARCS_SCP"+     evar SFTP = "DARCS_SFTP"+     portFlag SSH  x = ["-p", x]+     portFlag SCP  x = ["-P", x]+     portFlag SFTP x = ["-oPort="++x]++-- | Return True if this version of ssh has a ControlMaster feature+-- The ControlMaster functionality allows for ssh multiplexing+hasSSHControlMaster :: Bool+hasSSHControlMaster = unsafePerformIO hasSSHControlMasterIO++-- Because of the unsafePerformIO above, this can be called at any+-- point.  It cannot rely on any state, not even the current directory.+hasSSHControlMasterIO :: IO Bool+hasSSHControlMasterIO = do+  (ssh, _) <- getSSHOnly SSH+  -- If ssh has the ControlMaster feature, it will recognise the+  -- the -O flag, but exit with status 255 because of the nonsense+  -- command.  If it does not have the feature, it will simply dump+  -- a help message on the screen and exit with 1.+  sx <- exec ssh ["-O", "an_invalid_command"] (Null,Null,Null)+  case sx of+    ExitFailure 255 -> return True+    _ -> return False++-- | Launch an SSH control master in the background, if available.+--   We don't have to wait for it or anything.+--   Note also that this will cleanup after itself when darcs exits+launchSSHControlMaster :: String -> IO ()+launchSSHControlMaster rawAddr =+  when hasSSHControlMaster $ do+  let addr = takeWhile (/= ':') rawAddr+  (ssh, ssh_args) <- getSSHOnly SSH+  cmPath <- controlMasterPath addr+  removeFileMayNotExist cmPath+  -- -f : put ssh in the background once it succeeds in logging you in+  -- -M : launch as the control master for addr+  -- -N : don't run any commands+  -- -S : use cmPath as the ControlPath.  Equivalent to -oControlPath=+  exec ssh (ssh_args ++ [addr, "-S", cmPath, "-N", "-f", "-M"]) (Null,Null,AsIs)+  atexit $ exitSSHControlMaster addr+  return ()++-- | Tell the SSH control master for a given path to exit.+exitSSHControlMaster :: String -> IO ()+exitSSHControlMaster addr = do+  (ssh, ssh_args) <- getSSHOnly SSH+  cmPath <- controlMasterPath addr+  exec ssh (ssh_args ++ [addr, "-S", cmPath, "-O", "exit"]) (Null,Null,Null)+  return ()++-- | Create the directory ssh control master path for a given address+controlMasterPath :: String -- ^ remote path (foo\@bar.com:file is ok; the file part with be stripped)+                  -> IO FilePath+controlMasterPath rawAddr = do+  let addr = takeWhile (/= ':') rawAddr+  tmp <- (fmap (/// ".darcs") $ getEnv "HOME") `catchall` tempdir_loc+#ifdef WIN32+  r <- randomIO+  let suffix = (showHexLen 6 (r .&. 0xFFFFFF :: Int))+#else+  suffix <- show `fmap` getProcessID+#endif+  let tmpDarcsSsh = tmp /// "darcs-ssh"+  createDirectoryIfMissing True tmpDarcsSsh+  return $ tmpDarcsSsh /// addr ++ suffix++(///) :: FilePath -> FilePath -> FilePath+d /// f = d ++ "/" ++ f
+ src/ThisVersion.lhs view
@@ -0,0 +1,11 @@+%+% Version information created at compile time by make.+%+\begin{code}+module ThisVersion ( darcs_version ) where++{-# NOINLINE darcs_version #-}+darcs_version :: String+darcs_version = "2.0.2 (+ 11 patches)"+\end{code}+
+ src/ThisVersion.lhs.in view
@@ -0,0 +1,11 @@+%+% Version information created at compile time by make.+%+\begin{code}+module ThisVersion ( darcs_version ) where++{-# NOINLINE darcs_version #-}+darcs_version :: String+darcs_version = "@DARCS_VERSION@ (@DARCS_VERSION_STATE@)"+\end{code}+
+ src/URL.hs view
@@ -0,0 +1,215 @@+{-# OPTIONS_GHC -cpp -fffi #-}+module URL ( copyUrl, copyUrlFirst, waitUrl,+             Cachable(Cachable, Uncachable, MaxAge)+           ) where++import Data.IORef+import Data.Map ( Map )+import Data.List ( delete )+import qualified Data.Map as Map+import System.IO.Unsafe ( unsafePerformIO )+import Control.Monad ( when )+import Autoconf ( have_libwww )+import Foreign.C.Types ( CInt )+import Foreign.C.String ( withCString, peekCString, CString )++import Workaround ( renameFile )+import Darcs.Progress ( debugMessage, debugFail )+import Darcs.Global ( atexit )+import Darcs.Lock ( removeFileMayNotExist )++#if !defined(HAVE_CURL) || !defined(HAVE_LIBWWW)+import Foreign.Ptr ( nullPtr )+#endif+#include "impossible.h"++data Cachable = Cachable | Uncachable | MaxAge !CInt deriving Eq++data UrlState = UrlState { inProgress :: Map String FilePath,+                           waitToStart :: Q (String, String, Cachable),+                           pipeLength :: Int+                         }++data Q a = Q [a] [a]++readQ :: Q a -> Maybe (a, Q a)+readQ (Q (x:xs) ys) = Just (x, Q xs ys)+readQ (Q [] ys) = do x:xs <- Just $ reverse ys+                     Just (x, Q xs [])++insertQ :: a -> Q a -> Q a+insertQ y (Q xs ys) = Q xs (y:ys)++pushQ :: a -> Q a -> Q a+pushQ x (Q xs ys) = Q (x:xs) ys++deleteQ :: Eq a => a -> Q a -> Q a+deleteQ x (Q xs ys) = Q (delete x xs) (delete x ys)++elemQ :: Eq a => a -> Q a -> Bool+elemQ x (Q xs ys) = x `elem` xs || x `elem` ys++emptyQ :: Q a+emptyQ = Q [] []++data Priority = High | Low deriving Eq++maxPipeLength :: Int+maxPipeLength = if have_libwww then 100+#ifdef CURL_PIPELINING+                               else 100+#else+                               else 1+#endif++urlState :: IORef UrlState+urlState = unsafePerformIO $ newIORef (UrlState Map.empty emptyQ 0)++copyUrlWithPriority :: Priority -> String -> String -> Cachable -> IO ()+copyUrlWithPriority prio url file c = do+  st <- readIORef urlState+  let p = inProgress st+      w = waitToStart st+      new_w = case prio of+                High -> pushQ (url, file, c) w+                Low  -> insertQ (url, file, c) w+      new_st = st { inProgress = Map.insert url file p,+                    waitToStart = new_w+                  }+  if Map.member url p+     then if prio == High && (url, file, c) `elemQ` w+          then do writeIORef urlState (st { waitToStart = pushQ (url, file, c) (deleteQ (url, file, c) w) })+                  debugMessage $ "Moving "++url++" to head of download queue."+                  checkWaitToStart+          else debugMessage "Ignoring copyUrlWithPriority of file that's already queued."+     else do writeIORef urlState new_st+             checkWaitToStart++copyUrlFirst :: String -> String -> Cachable -> IO ()+copyUrlFirst = copyUrlWithPriority High++copyUrl :: String -> String -> Cachable -> IO ()+copyUrl = copyUrlWithPriority Low++waitNextUrl :: IO (String, Maybe String)+waitNextUrl = do st <- readIORef urlState+                 let l = pipeLength st+                 if l > 0+                    then do err <- waitNextUrl'+                            url <- lastUrl'+                            let p = inProgress st+                                new_st = st { inProgress = Map.delete url p,+                                              pipeLength = l - 1+                                            }+                            if null err+                               then+                                 case Map.lookup url p of+                                 Just f -> do renameFile (f++"-new") f+                                              debugMessage $ "URL.waitNextUrl succeeded: "++url++" "++f+                                 Nothing -> bug $ "Possible bug in URL.waitNextUrl: "++url+                               else when (not $ null url) $ case Map.lookup url p of+                                      Just f -> do removeFileMayNotExist (f++"-new")+                                                   debugMessage $ "URL.waitNextUrl failed: "+++                                                                url++" "++f++" "++err+                                      Nothing -> bug $ "Another possible bug in URL.waitNextUrl: "++url++" "++err+                            when (not $ null url) $ do+                              writeIORef urlState new_st+                              checkWaitToStart+                            return (url, if null err then Nothing else Just err)+                    else return ("", Nothing)+    where waitNextUrl' = do let fn = if have_libwww then libwww_wait_next_url+                                                    else curl_wait_next_url+                            err <- fn >>= peekCString+                            return err+          lastUrl' = let fn = if have_libwww then libwww_last_url+                                             else curl_last_url+                     in fn >>= peekCString++waitUrl :: String -> IO ()+waitUrl u = do st <- readIORef urlState+               when (u `Map.member` inProgress st) waitUrl'+               debugMessage ("URL.waitUrl "++u++" succeeded")+    where waitUrl' = do (url, merr) <- waitNextUrl+                        if u /= url+                           then waitUrl'+                           else case merr of+                                Just err -> debugFail $ "Failed to download URL "++url++": "++err+                                Nothing -> return ()++checkWaitToStart :: IO ()+checkWaitToStart = do st <- readIORef urlState+                      let l = pipeLength st+                      when (l < maxPipeLength) $+                           do let w = waitToStart st+                              case readQ w of+                                Just ((u,f,c),rest) -> do+                                       let new_st = st { waitToStart = rest,+                                                         pipeLength = l + 1+                                                       }+                                       writeIORef urlState new_st+                                       err <- copyUrl' u f c+                                       when (not $ null err) (debugFail $ "Failed to start download URL "+                                                                     ++u++": "++err)+                                       checkWaitToStart+                                _ -> return ()+    where copyUrl' u f cache = withCString u $ \ustr ->+                               withCString (f++"-new") $ \fstr -> do+                               atexit $ removeFileMayNotExist (f++"-new")+                               debugMessage ("URL.copyUrl ("++u++"\n"+++                                             "          -> "++f++")")+                               let fn = if have_libwww then libwww_request_url+                                                       else curl_request_url+                               err <- fn ustr fstr (cachableToInt cache) >>= peekCString+                               when (null err) (debugMessage "URL.copyUrl succeeded")+                               return err++cachableToInt :: Cachable -> CInt+cachableToInt Cachable = -1+cachableToInt Uncachable = 0+cachableToInt (MaxAge n) = n++#ifdef HAVE_CURL+foreign import ccall "hscurl.h curl_request_url"+  curl_request_url :: CString -> CString -> CInt -> IO CString++foreign import ccall "hscurl.h curl_wait_next_url"+  curl_wait_next_url :: IO CString++foreign import ccall "hscurl.h curl_last_url"+  curl_last_url :: IO CString+#else+no_curl :: IO ()+no_curl = debugFail "There is no libcurl!"++curl_request_url :: CString -> CString -> CInt -> IO CString+curl_request_url _ _ _ = no_curl >> return nullPtr++curl_wait_next_url :: IO CString+curl_wait_next_url = no_curl >> return nullPtr++curl_last_url :: IO CString+curl_last_url = no_curl >> return nullPtr+#endif++#ifdef HAVE_LIBWWW+foreign import ccall "hslibwww.h libwww_request_url"+  libwww_request_url :: CString -> CString -> CInt -> IO CString++foreign import ccall "hslibwww.h libwww_wait_next_url"+  libwww_wait_next_url :: IO CString++foreign import ccall "hslibwww.h libwww_last_url"+  libwww_last_url :: IO CString+#else+no_libwww :: IO ()+no_libwww = debugFail "There is no libwww!"++libwww_request_url :: CString -> CString -> CInt -> IO CString+libwww_request_url _ _ _ = no_libwww >> return nullPtr++libwww_wait_next_url :: IO CString+libwww_wait_next_url = no_libwww >> return nullPtr++libwww_last_url :: IO CString+libwww_last_url = no_libwww >> return nullPtr+#endif
+ src/UTF8.lhs view
@@ -0,0 +1,343 @@+Copyright (c) 2002, members of the Haskell Internationalisation Working+Group All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice,+   this list of conditions and the following disclaimer.+* Redistributions in binary form must reproduce the above copyright notice,+   this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.+* Neither the name of the Haskell Internationalisation Working Group nor+   the names of its contributors may be used to endorse or promote products+   derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.++This module provides lazy stream encoding/decoding facilities for UTF-8,+the Unicode Transformation Format with 8-bit words.++2002-09-02  Sven Moritz Hallberg <pesco@gmx.de>+++> module UTF8+>   ( encode, decode,+>     encodeOne, decodeOne,+>   ) where++> import Data.Char (ord, chr)+> import Data.Word (Word8, Word16, Word32)+> import Data.Bits (Bits, shiftL, shiftR, (.&.), (.|.))++++///- UTF-8 in General -///++Adapted from the Unicode standard, version 3.2,+Table 3.1 "UTF-8 Bit Distribution" (excluded are UTF-16 encodings):++  Scalar                    1st Byte  2nd Byte  3rd Byte  4th Byte+          000000000xxxxxxx  0xxxxxxx+          00000yyyyyxxxxxx  110yyyyy  10xxxxxx+          zzzzyyyyyyxxxxxx  1110zzzz  10yyyyyy  10xxxxxx+  000uuuzzzzzzyyyyyyxxxxxx  11110uuu  10zzzzzz  10yyyyyy  10xxxxxx++Also from the Unicode standard, version 3.2,+Table 3.1B "Legal UTF-8 Byte Sequences":++  Code Points         1st Byte  2nd Byte  3rd Byte  4th Byte+    U+0000..U+007F    00..7F+    U+0080..U+07FF    C2..DF    80..BF+    U+0800..U+0FFF    E0        A0..BF    80..BF+    U+1000..U+CFFF    E1..EC    80..BF    80..BF+    U+D000..U+D7FF    ED        80..9F    80..BF+    U+D800..U+DFFF    ill-formed+    U+E000..U+FFFF    EE..EF    80..BF    80..BF+   U+10000..U+3FFFF   F0        90..BF    80..BF    80..BF+   U+40000..U+FFFFF   F1..F3    80..BF    80..BF    80..BF+  U+100000..U+10FFFF  F4        80..8F    80..BF    80..BF++++///- Encoding Functions -///++Must the encoder ensure that no illegal byte sequences are output or+can we trust the Haskell system to supply only legal values?+For now I include error case for the surrogate values U+D800..U+DFFF and+out-of-range scalars.++The function is pretty much a transscript of table 3.1B with error checks.+It dispatches the actual encoding to functions specific to the number of+required bytes.++> encodeOne :: Char -> [Word8]+> encodeOne c+>-- The report guarantees in (6.1.2) that this won't happen:+>--   | n < 0       = error "encodeUTF8: ord returned a negative value"+>     | n < 0x0080  = encodeOne_onebyte n8+>     | n < 0x0800  = encodeOne_twobyte n16+>     | n < 0xD800  = encodeOne_threebyte n16+>     | n < 0xE000  = error "encodeUTF8: ord returned a surrogate value"+>     | n < 0x10000       = encodeOne_threebyte n16+>-- Haskell 98 only talks about 16 bit characters, but ghc handles 20.1.+>     | n < 0x10FFFF      = encodeOne_fourbyte n32+>     | otherwise  = error "encodeUTF8: ord returned a value above 0x10FFFF"+>     where+>     n = ord c            :: Int+>     n8 = fromIntegral n  :: Word8+>     n16 = fromIntegral n :: Word16+>     n32 = fromIntegral n :: Word32+++With the above, a stream decoder is trivial:++> encode :: [Char] -> [Word8]+> encode = concatMap encodeOne+++Now follow the individual encoders for certain numbers of bytes...+          _+         / |  __  ___  __ __+        / ^| //  /__/ // //+       /.==| \\ //_  // //+It's  //  || // \_/_//_//_  and it's here to stay!++> encodeOne_onebyte :: Word8 -> [Word8]+> encodeOne_onebyte cp = [cp]+++00000yyyyyxxxxxx -> 110yyyyy 10xxxxxx++> encodeOne_twobyte :: Word16 -> [Word8]+> encodeOne_twobyte cp = [(0xC0.|.ys), (0x80.|.xs)]+>     where+>     xs, ys :: Word8+>     ys = fromIntegral (shiftR cp 6)+>     xs = (fromIntegral cp) .&. 0x3F+++zzzzyyyyyyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx++> encodeOne_threebyte :: Word16 -> [Word8]+> encodeOne_threebyte cp = [(0xE0.|.zs), (0x80.|.ys), (0x80.|.xs)]+>     where+>     xs, ys, zs :: Word8+>     xs = (fromIntegral cp) .&. 0x3F+>     ys = (fromIntegral (shiftR cp 6)) .&. 0x3F+>     zs = fromIntegral (shiftR cp 12)+++000uuuzzzzzzyyyyyyxxxxxx -> 11110uuu 10zzzzzz 10yyyyyy 10xxxxxx++> encodeOne_fourbyte :: Word32 -> [Word8]+> encodeOne_fourbyte cp = [0xF0.|.us, 0x80.|.zs, 0x80.|.ys, 0x80.|.xs]+>     where+>     xs, ys, zs, us :: Word8+>     xs = (fromIntegral cp) .&. 0x3F+>     ys = (fromIntegral (shiftR cp 6)) .&. 0x3F+>     zs = (fromIntegral (shiftR cp 12)) .&. 0x3F+>     us = fromIntegral (shiftR cp 18)++++///- Decoding -///++The decoding is a bit more involved. The byte sequence could contain all+sorts of corruptions. The user must be able to either notice or ignore these+errors.++I will first look at the decoding of a single character. The process+consumes a certain number of bytes from the input. It returns the+remaining input and either an error and the index of its occurance in the+byte sequence or the decoded character.++> data Error++The first byte in a sequence starts with either zero, two, three, or four+ones and one zero to indicate the length of the sequence. If it doesn't,+it is invalid. It is dropped and the next byte interpreted as the start+of a new sequence.++>     = InvalidFirstByte++All bytes in the sequence except the first match the bit pattern 10xxxxxx.+If one doesn't, it is invalid. The sequence up to that point is dropped+and the "invalid" byte interpreted as the start of a new sequence. The error+includes the length of the partial sequence and the number of expected bytes.++>     | InvalidLaterByte Int      -- the byte at relative index n was invalid++If a sequence ends prematurely, it has been truncated. It dropped and+decoding stops. The error reports the actual and expected lengths of the+sequence.++>     | Truncated Int Int         -- only n of m expected bytes were present++Some sequences would represent code points which would be encoded as a+shorter sequence by a conformant encoder. Such non-shortest sequences are+considered erroneous and dropped. The error reports the actual and+expected number of bytes used.++>     | NonShortest Int Int       -- n instead of m bytes were used++Unicode code points are in the range of [0..0x10FFFF]. Any values outside+of those bounds are simply invalid.++>     | ValueOutOfBounds++There is no such thing as "surrogate pairs" any more in UTF-8. The+corresponding code points now form illegal byte sequences.++>     | Surrogate+>       deriving (Show, Eq)+++Second, third, and fourth bytes share the common requirement to start+with the bit sequence 10. So, here's the function to check that property.++> first_bits_not_10 :: Word8 -> Bool+> first_bits_not_10 b+>     | (b.&.0xC0) /= 0x80  = True+>     | otherwise           = False+++Erm, OK, the single-character decoding function's return type is a bit+longish. It is a tripel:++ - The first component contains the decoded character or an error+   if the byte sequence was erroneous.+ - The second component contains the number of bytes that were consumed+   from the input.+ - The third component contains the remaining bytes of input.++> decodeOne :: [Word8] -> (Either Error Char, Int, [Word8])+> decodeOne bs@(b1:rest)+>     | b1 < 0x80   = decodeOne_onebyte bs+>     | b1 < 0xC0   = (Left InvalidFirstByte, 1, rest)+>     | b1 < 0xE0   = decodeOne_twobyte bs+>     | b1 < 0xEE   = decodeOne_threebyte bs+>     | b1 < 0xF5   = decodeOne_fourbyte bs+>     | otherwise   = (Left ValueOutOfBounds, 1, rest)+> decodeOne [] = error "UTF8.decodeOne: No input"+++0xxxxxxx -> 000000000xxxxxxx++> decodeOne_onebyte :: [Word8] -> (Either Error Char, Int, [Word8])+> decodeOne_onebyte (b:bs) = (Right (cpToChar b), 1, bs)+> decodeOne_onebyte[] = error "UTF8.decodeOne_onebyte: No input (can't happen)"++> cpToChar :: Integral a => a -> Char+> cpToChar = chr . fromIntegral+++110yyyyy 10xxxxxx -> 00000yyyyyxxxxxx++> decodeOne_twobyte :: [Word8] -> (Either Error Char, Int, [Word8])+> decodeOne_twobyte (_:[])+>     = (Left (Truncated 1 2), 1, [])+> decodeOne_twobyte (b1:b2:bs)+>     | b1 < 0xC2            = (Left (NonShortest 2 1), 2, bs)+>     | first_bits_not_10 b2 = (Left (InvalidLaterByte 1), 1, (b2:bs))+>     | otherwise            = (Right (cpToChar result), 2, bs)+>     where+>     xs, ys, result :: Word32+>     xs = fromIntegral (b2.&.0x3F)+>     ys = fromIntegral (b1.&.0x1F)+>     result = shiftL ys 6 .|. xs+> decodeOne_twobyte[] = error "UTF8.decodeOne_twobyte: No input (can't happen)"+++1110zzzz 10yyyyyy 10xxxxxx -> zzzzyyyyyyxxxxxx++> decodeOne_threebyte :: [Word8] -> (Either Error Char, Int, [Word8])+> decodeOne_threebyte (_:[])   = threebyte_truncated 1+> decodeOne_threebyte (_:_:[]) = threebyte_truncated 2+> decodeOne_threebyte bs@(b1:b2:b3:rest)+>     | first_bits_not_10 b2+>         = (Left (InvalidLaterByte 1), 1, drop 1 bs)+>     | first_bits_not_10 b3+>         = (Left (InvalidLaterByte 2), 2, drop 2 bs)+>     | result < 0x0080+>         = (Left (NonShortest 3 1), 3, rest)+>     | result < 0x0800+>         = (Left (NonShortest 3 2), 3, rest)+>     | result >= 0xD800 && result < 0xE000+>         = (Left Surrogate, 3, rest)+>     | otherwise+>         = (Right (cpToChar result), 3, rest)+>     where+>     xs, ys, zs, result :: Word32+>     xs = fromIntegral (b3.&.0x3F)+>     ys = fromIntegral (b2.&.0x3F)+>     zs = fromIntegral (b1.&.0x0F)+>     result = shiftL zs 12 .|. shiftL ys 6 .|. xs+> decodeOne_threebyte[]+>  = error "UTF8.decodeOne_threebyte: No input (can't happen)"++> threebyte_truncated :: Int -> (Either Error Char, Int, [Word8])+> threebyte_truncated n = (Left (Truncated n 3), n, [])+++11110uuu 10zzzzzz 10yyyyyy 10xxxxxx -> 000uuuzzzzzzyyyyyyxxxxxx++> decodeOne_fourbyte :: [Word8] -> (Either Error Char, Int, [Word8])+> decodeOne_fourbyte (_:[])     = fourbyte_truncated 1+> decodeOne_fourbyte (_:_:[])   = fourbyte_truncated 2+> decodeOne_fourbyte (_:_:_:[]) = fourbyte_truncated 3+> decodeOne_fourbyte bs@(b1:b2:b3:b4:rest)+>     | first_bits_not_10 b2+>         = (Left (InvalidLaterByte 1), 1, drop 1 bs)+>     | first_bits_not_10 b3+>         = (Left (InvalidLaterByte 2), 2, drop 2 bs)+>     | first_bits_not_10 b4+>         = (Left (InvalidLaterByte 3), 3, drop 3 bs)+>     | result < 0x0080+>         = (Left (NonShortest 4 1), 4, rest)+>     | result < 0x0800+>         = (Left (NonShortest 4 2), 4, rest)+>     | result < 0x10000+>         = (Left (NonShortest 4 3), 4, rest)+>     | result > 0x10FFFF+>         = (Left ValueOutOfBounds, 4, rest)+>     | otherwise+>         = (Right (cpToChar result), 4, rest)+>     where+>     xs, ys, zs, us, result :: Word32+>     xs = fromIntegral (b4 .&. 0x3F)+>     ys = fromIntegral (b3 .&. 0x3F)+>     zs = fromIntegral (b2 .&. 0x3F)+>     us = fromIntegral (b1 .&. 0x07)+>     result = xs .|. shiftL ys 6 .|. shiftL zs 12 .|. shiftL us 18+> decodeOne_fourbyte[]+>  = error "UTF8.decodeOne_fourbyte: No input (can't happen)"++> fourbyte_truncated :: Int -> (Either Error Char, Int, [Word8])+> fourbyte_truncated n = (Left (Truncated n 4), n, [])+++The decoder examines all input, recording decoded characters as well as+error-index pairs along the way.++> decode :: [Word8] -> ([Char], [(Error,Int)])+> decode bytes = iter 0 [] [] bytes+>     where+>     iter :: Int -> [Char] -> [(Error,Int)] -> [Word8]+>          -> ([Char], [(Error,Int)])+>     iter _ cs es [] = (reverse cs, reverse es)+>     iter idx cs es bs+>         = case decodeOne bs of+>           (Left e, n, rest)  -> iter (idx+n) cs     ((e,idx):es) rest+>           (Right c, n, rest) -> iter (idx+n) (c:cs) es           rest+
+ src/Workaround.hs view
@@ -0,0 +1,63 @@+{-# OPTIONS -w #-}+{- Workaround.hs++This file was created automatically by configure.  We disable warnings to+avoid issues with duplicate imports.++-}++module Workaround(+           openFd,+installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,+           getCurrentDirectory,+           createLink,+           createDirectoryIfMissing,+           renameFile,+           bracketOnError,+           fileMode, getFileStatus, setFileMode,+           setExecutable,+ ) where++import qualified GHC.Handle ( fdToHandle' )+import System.IO ( Handle, IOMode )+import System.Posix.Internals ( FDType )++import System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal,+                         sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE,)+import System.Directory(getCurrentDirectory)+import System.Posix.Files( createLink )+import System.Directory(createDirectoryIfMissing)+import System.Directory ( renameFile )+import Control.Exception( bracketOnError )+import System.Posix.Files(fileMode,getFileStatus,setFileMode)++import System.Posix.Files (fileMode,getFileStatus, setFileMode, nullFileMode,+                           setFileCreationMask,+                           ownerReadMode, ownerWriteMode, ownerExecuteMode,+                           groupReadMode, groupWriteMode, groupExecuteMode,+                           otherReadMode, otherWriteMode, otherExecuteMode)+import Data.Bits ( (.&.), (.|.), complement )++setExecutable :: FilePath -> Bool -> IO ()+setExecutable f ex =+  do st <- getFileStatus f+     umask <- setFileCreationMask 0+     setFileCreationMask umask+     let rw = fileMode st .&.+              (ownerReadMode .|. ownerWriteMode .|.+               groupReadMode .|. groupWriteMode .|.+               otherReadMode .|. otherWriteMode)+         total = if ex then rw .|.+                           ((ownerExecuteMode .|. groupExecuteMode .|. otherExecuteMode)+                            .&. complement umask)+                       else rw+     setFileMode f total+++{-+Work around renaming of GHC.Handle.openFd and change in its API.+-}+openFd :: Int -> Maybe FDType -> FilePath -> IOMode -> Bool -> Bool -> IO Handle+openFd fd x y z a b = GHC.Handle.fdToHandle' (fromIntegral fd) x b y z a+
+ src/atomic_create.c view
@@ -0,0 +1,181 @@+/*+  Copyright (C) 2005 Juliusz Chroboczek++  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, 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; see the file COPYING.  If not, write to+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+  Boston, MA 02110-1301, USA.+*/++#include <sys/types.h>+#include <sys/stat.h>+#include <fcntl.h>+#include <string.h>+#include <stdio.h>+#include <stdlib.h>++#include <unistd.h>+#include <errno.h>+#include <sys/time.h>++#ifdef _WIN32+#include <windows.h>+#include <io.h>+#endif++int sloppy_atomic_create(const char *p)+{+    int fd;+    fd = open(p, O_WRONLY | O_EXCL | O_CREAT, 0666);+    if(fd < 0)+        return -1;+    close(fd);+    return 1;+}++#ifdef _WIN32++int atomic_create(const char *p)+{+    return sloppy_atomic_create(p);+}++#else++static int careful_atomic_create(const char *p)+{+    /* O_EXCL is not available over NFSv2, and even under NFSv3, it is+       broken on many systems.  The following protocol is provably+       safe assuming that:+       - creation of hard links is atomic;+       - stat hits the server rather than working from the cache.+    */++    static char hostname[65] = {'\0'};+    int fd, rc, saved_errno;+#define FILENAME_SIZE (11 + 15 + 8 + 1)+    char *filename;+    char *lastslash;+    int dirlen;+    struct timeval now;+    struct stat sb;++    if(hostname[0] == '\0') {+        char *c;+        int i;+        /* POSIX guarantees 65 is enough. */+        rc = gethostname(hostname, 65);+        if(rc < 0 || rc >= 65) {+            fprintf(stderr, "Error reading hostname when locking.\n");+            strcpy(hostname, "kremvax");+        }+        c = strchr(hostname, '.');+        if(c != NULL)+            *c = '\0';+        hostname[15] = '\0';+        /* clean up a few possible nasty characters folks might put in their hostname */+        for (i=0;i<15;i++)+          if (hostname[i] == ':' || hostname[i] == '/' || hostname[i] == '\\')+            hostname[i] = '-';+    }++    lastslash = strrchr(p, '/');+    dirlen = lastslash ? lastslash - p + 1 : 0;++    filename = malloc(dirlen + FILENAME_SIZE);+    if(filename == NULL)+        return -1;++    if(dirlen > 0)+        memcpy(filename, p, dirlen);+    filename[dirlen] = '\0';++    gettimeofday(&now, NULL);++    rc = snprintf(filename + dirlen, FILENAME_SIZE, "darcs_lock_%s%04x%04x",+                  hostname, ((unsigned)getpid()) & 0xFFFF,+                  ((unsigned)(now.tv_usec ^ (now.tv_usec >> 16))) & 0xFFFF);+    if(rc < 0 || rc >= FILENAME_SIZE) {+        fprintf(stderr, "Error writing to lock filename (%d)\n", +                rc < 0 ? errno : 0);+        goto fail2;+    }++    fd = open(filename, O_WRONLY | O_EXCL | O_CREAT, 0666);+    if(fd < 0)+        goto fail2;++    /* Paranoia: should cause the client to flush its metadata cache. */+    rc = close(fd);+    if(rc < 0) {+        fprintf(stderr, "Error closing file %s. (%d)\n", filename, errno);+        goto fail;+    }++    rc = link(filename, p);+    if(rc >= 0)+        goto success;+    else if(errno == EPERM || errno == EOPNOTSUPP) {+        /* Linux returns EPERM when making hard links on filesystems+           that don't support them. */+        /* It seems that MacOS returns EOPNOTSUPP on filesystems that+           don't support hard links. */+        unlink(filename);+        free(filename);+        return sloppy_atomic_create(p);+    } else if(errno != EEXIST && errno != EIO)+        goto fail;++    /* The link may still have been successful if we're running over+       UDP and got EEXIST or EIO.  Check the file's link count. */++    rc = stat(filename, &sb);+    if(rc < 0) {+        goto fail;+    }++    if(sb.st_nlink != 2) {+        errno = EEXIST;+        goto fail;+    }++ success:+    unlink(filename);+    free(filename);+    return 1;++ fail:+    saved_errno = errno;+    unlink(filename);+    errno = saved_errno;+ fail2:+    free(filename);+    return -1;+}++int atomic_create(const char *p)+{+    static int sloppy = -1;++    if(sloppy < 0) {+        char *s = getenv("DARCS_SLOPPY_LOCKS");+        sloppy = (s != NULL);+    }++    if(sloppy)+        return sloppy_atomic_create(p);+    else+        return careful_atomic_create(p);+}++#endif
+ src/atomic_create.h view
@@ -0,0 +1,25 @@++#include <sys/stat.h>+#include <string.h>+#include <stdlib.h>++int sloppy_atomic_create(const char *p);+int atomic_create(const char *p);++#ifdef _WIN32+int mkstemp(char *p);+int pipe( int fildes[2] );+int renamefile(const char *from, const char *to);+#endif++int open_read(const char *fname);+int open_write(const char *fname);+int smart_wait(int pid);++int execvp_no_vtalarm(const char *file, char *const argv[]);++int is_symlink(const char *file);++int stdout_is_a_pipe();++int maybe_relink(const char *src, const char *dst, int careful);
+ src/best_practices.tex view
@@ -0,0 +1,584 @@+% This file (unlike the rest of darcs) is in the public domain.+ ++\chapter{Best practices}++\section{Introduction}++This chapter is intended to review various scenarios and describe in each+case effective ways of using darcs.  There is no one ``best practice'', and+darcs is a sufficiently low-level tool that there are many high-level ways+one can use it, which can be confusing to new users.  The plan (and hope)+is that various users will contribute here describing how they use darcs in+different environments.  However, this is not a wiki, and contributions+will be edited and reviewed for consistency and wisdom.+++\section{Creating patches}++This section will lay down the concepts around patch creation.+The aim is to develop a way of thinking+that corresponds well to how darcs is behaving+--- even in complicated situations.++	In a single darcs repository you can think of two ``versions'' of the source tree.+	They are called the \emph{working} and \emph{pristine} trees.+    \emph{Working} is your normal source tree, with or without darcs alongside.+	The only thing that makes it part of a darcs repository+	is the \verb!_darcs! directory in its root.+    \emph{Pristine} is the recorded state of the source tree.+	The pristine tree is constructed from groups of changes,+        called {\em patches\/} (some other version control systems use the+	term {\em changeset\/} instead of {\em patch\/}).\footnote{If+	you look inside \_darcs you will find files or directories named+	{\tt patches} and {\tt inventories}, which store all the patches+          ever recorded.  If the repository holds a cached pristine tree, it+          is stored in a directory called {\tt pristine} or {\tt current\/};+          otherwise, the fact that there is no pristine tree is marked+          by the presence of a file called {\tt pristine.none} or {\tt+            current.none}.}+	Darcs will create and store these patches+	based on the changes you make in \emph{working}.+++\subsection{Changes}+	If \emph{working} and \emph{pristine} are the same,+	there are ``no changes'' in the repository.+	Changes can be introduced (or removed) by editing the files in \emph{working}.+	They can also be caused by darcs commands,+	which can modify \emph{both} \emph{working} and \emph{pristine}.+	It is important to understand for each darcs command+	how it modifies \emph{working}, \emph{pristine} or both of them.++	\verb!whatsnew! (as well as \verb!diff!) can show+	the difference between \emph{working} and \emph{pristine} to you.+	It will be shown as a difference in \emph{working}.+	In advanced cases it need \emph{not} be \emph{working} that has changed;+	it can just as well have been \emph{pristine}, or both.+	The important thing is the difference and what darcs can do with it.++\subsection{Keeping or discarding changes}+    If you have a difference in \emph{working}, you do two things+    with it: \verb!record! it to keep it, or \verb!revert! it to lose the changes.%+		\footnote{%+		Revert can undo precious work in a blink.+		To protect you from great grief,+		the discarded changes are saved temporarily+		so the latest revert can be undone with unrevert.}++	If you have a difference between \emph{working} and \emph{pristine}%+	---for example after editing some files in \emph{working}---%+	\verb!whatsnew! will show some ``unrecorded changes''.+	To save these changes, use \verb!record!.+	It will create a new patch in \emph{pristine} with the same changes,+	so \emph{working} and \emph{pristine} are no longer different.+	To instead undo the changes in \emph{working}, use \verb!revert!.+	It will modify the files in \emph{working} to be the same as in \emph{pristine}+	(where the changes do not exist).+++\subsection{Unrecording changes}+    \verb!unrecord! is a command meant to be run only in private+    repositories. Its intended purpose is to allow developers the flexibility+    to undo patches that haven't been distributed yet.++    However, darcs does not prevent you from unrecording a patch that+    has been copied to another repository. Be aware of this danger!++	If you \verb!unrecord! a patch, that patch will be deleted from \emph{pristine}.+	This will cause \emph{working} to be different from \emph{pristine},+	and \verb!whatsnew! to report unrecorded changes.+	The difference will be the same as just before that patch was \verb!record!ed.+	Think about it.+	\verb!record! examines what's different with \emph{working}+	and constructs a patch with the same changes in \emph{pristine}+	so they are no longer different.+	\verb!unrecord! deletes this patch;+	the changes in \emph{pristine} disappear and the difference is back.++	If the recorded changes included an error,+	the resulting flawed patch can be unrecorded.+	When the changes have been fixed,+	they can be recorded again as a new---hopefully flawless---patch.++	If the whole change was wrong it can be discarded from \emph{working} too,+	with \verb!revert!.+	\verb!revert! will update \emph{working} to the state of \emph{pristine},+	in which the changes do no longer exist after the patch was deleted.++	Keep in mind that the patches are your history,+	so deleting them with \verb!unrecord! makes it impossible to track+	what changes you \emph{really} made.+	Redoing the patches is how you ``cover the tracks''.+	On the other hand,+	it can be a very convenient way to manage and organize changes+	while you try them out in your private repository.+	When all is ready for shipping,+	the changes can be reorganized in what seems as useful and impressive patches.+	Use it with care.++	All patches are global,+	so don't \emph{ever} replace an already ``shipped'' patch in this way!+	If an erroneous patch is deleted and replaced with a better one,+	you have to replace it in \emph{all} repositories that have a copy of it.+	This may not be feasible, unless it's all private repositories.+	If other developers have already made patches or tags in their repositories+	that depend on the old patch, things will get complicated.+++\subsection{Special patches and pending}++The patches described in the previous sections have mostly been hunks.+A \emph{hunk} is one of darcs' primitive patch types,+and it is used to remove old lines and/or insert new lines.+There are other types of primitive patches,+such as \emph{adddir} and \emph{addfile}+which add new directories and files,+and \emph{replace}+which does a search-and-replace on tokens in files.++Hunks are always calculated in place with a diff algorithm+just before \verb!whatsnew! or \verb!record!.+But other types of primitive patches need to be explicitly created+with a darcs command.+They are kept in \emph{pending}%+\footnote{In the file {\tt\_darcs/patches/pending}.}+until they are either recorded or reverted.++\emph{Pending} can be thought of as a special extension of \emph{working}.+When you issue, e.g., a darcs \verb!replace! command,+the replace is performed on the files in \emph{working}+and at the same time a replace patch is put in \emph{pending}.+Patches in \emph{pending} describe special changes made in \emph{working}.+The diff algorithm will fictively apply these changes to \emph{pristine}+before it compares it to \emph{working},+so all lines in \emph{working} that are changed by a \verb!replace! command+will also be changed in \emph{pending}$+$\emph{pristine}+when the hunks are calculated.+That's why no hunks with the replaced lines will be shown by \verb!whatsnew!;+it only shows the replace patch in \emph{pending} responsible for the change.++If a special patch is recorded, it will simply be moved to \emph{pristine}.+If it is instead reverted, it will be deleted from \emph{pending}+and the accompanying change will be removed from \emph{working}.++Note that reverting a patch in pending is \emph{not} the same as+simply removing it from pending.+It actually applies the inverse of the change to \emph{working}.+Most notable is that reverting an addfile patch+will delete the file in \emph{working} (the inverse of adding it).+So if you add the wrong file to darcs by mistake,+\emph{don't} \verb!revert! the addfile.+Instead use \verb!remove!, which cancels out the addfile in pending.+++\section{Using patches} % still basics++This section will lay down the concepts around patch distribution and branches.+The aim is to develop a way of thinking+that corresponds well to how darcs is behaving+--- even in complicated situations.++A repository is a collection of patches.+Patches have no defined order,+but patches can have dependencies on other patches.+Patches can be added to a repository in any order+as long as all patches depended upon are there.+Patches can be removed from a repository in any order,+as long as no remaining patches depend on them.++Repositories can be cloned to create branches.+Patches created in different branches may conflict.+A conflict is a valid state of a repository.+A conflict makes the working tree ambiguous until the conflict is resolved.+++\subsection{Dependencies}++There are two kinds of dependencies:+implicit dependencies and explicit dependencies.++Implicit dependencies is the far most common kind.+These are calculated automatically by darcs.+If a patch removes a file or a line of code,+it will have to depend on the patch that added that file or line of code.\footnote{%+Actually it doesn't have to---in theory---,+but in practice it's hard to create ``negative'' files or lines in the working tree.+See the chapter about Theory of patches for other constraints.}+If a patch adds a line of code,+it will usually have to depend on the patch or patches that added the adjacent lines.++Explicit dependencies can be created if you give the \verb|--ask-deps| option to \verb|darcs record|.+This is good for assuring that logical dependencies hold between patches.+It can also be used to group patches---%+a patch with explicit dependencies doesn't need to change anything---%+and pulling the patch also pulls all patches it was made to depend on.+++\subsection{Branches: just normal repositories}++Darcs does not have branches---it doesn't need to.+Every repository can be used as a branch.+This means that any two repositories are ``branches'' in darcs,+but it is not of much use unless they have a large portion of patches in common.+If they are different projects they will have nothing in common,+but darcs may still very well be able to merge them,+although the result probably is nonsense.+Therefore the word ``branch'' isn't a technical term in darcs;+it's just the way we think of one repository in relation to another.++Branches are \emph{very} useful in darcs.+They are in fact \emph{necessary} if you want to do more than only simple work.+When you \verb|get| someone's repository from the Internet,+you are actually creating a branch of it.+It may first seem inefficient (or if you come from CVS---frightening),+not to say plain awkward.+But darcs is designed this way, and it has means to make it efficient.+The answer to many questions about how to do a thing with darcs is: ``use a branch''.+It is a simple and elegant solution with great power and flexibility,+which contributes to darcs' uncomplicated user interface.++You create new branches (i.e., clone repositories)+with the \verb|get| and \verb|put| commands.+++\subsection{Moving patches around---no versions}++Patches are global, and a copy of a patch either is or is not present in a branch.+This way you can rig a branch almost any way you like,+as long as dependencies are fulfilled---%+darcs \emph{won't} let you break dependencies.+If you suspect a certain feature from some time ago introduced a bug,+you can remove the patch/patches that adds the feature,+and try without it.\footnote{%+darcs even has a special command, {\tt trackdown}+that automatically removes patches+until a specified test no longer fails.}++Patches are added to a repository with \verb|pull|+and removed from the repositories with \verb|obliterate|.+Don't confuse these two commands with \verb|record| and \verb|unrecord|,+which constructs and deconstructs patches.++It is important not to lose patches when (re)moving them around.+\verb|pull| needs a source repository to copy the patch from,+whereas \verb|obliterate| just erases the patch.+Beware that if you obliterate \emph{all} copies of a patch+it is completely lost---forever.+Therefore you should work with branches when you obliterate patches.+The \verb|obliterate| command can wisely be disabled in a dedicated main repository+by adding \verb|obliterate disable| to the repository's defaults file.++For convenience, there is a \verb|push| command.+It works like \verb|pull| but in the other direction.+It also differs from \verb|pull| in an important way:+it starts a second instance of darcs to apply the patch in the target repository,+even if it's on the same computer.+It can cause surprises if you have a ``wrong'' darcs in your PATH.+++\subsection{Tags---versions}++While \verb|pull| and \verb|obliterate| can be used to+construct different ``versions'' in a repository,+it is often desirable to name specific configurations of patches+so they can be identified and retrieved easily later.+This is how darcs implements what is usually known as versions.+The command for this is \verb|tag|,+and it records a tag in the current repository.++A tag is just a patch, but it only contains explicit dependencies.+It will depend on all the patches in the current repository.\footnote{%+It will omit patches already depended upon by other patches,+since they will be indirectly depended upon anyway.}+Darcs can recognize if a patch is as a tag;+tags are sometimes treated specially by darcs commands.++While traditional revision control systems tag versions in the time line history,+darcs lets you tag any configuration of patches at any time,+and pass the tags around between branches.++With the option \verb|--tag| to \verb|get| you can easily get+a named version in the repository+as a new branch.+++\subsection{Conflicts}++This part of darcs becomes a bit complicated,+and the description given here is slightly simplified.++Conflicting patches are created when+you record changes to the same line in two different repositories.+Same line does \emph{not} mean the same line number and file name,+but the same line added by a common depended-upon patch.++If you are using a darcs-2 repository (Section \ref{initialize}),+darcs does \emph{not} consider two patches making the \emph{same} change to be a+conflict, much in the same fashion as other version control systems.+(The caveat here is two non-identical patches with some identical+changes may conflict.  For the most part, darcs should just do what you+expect).++A conflict \emph{happens} when two conflicting patches meet in the same repository.+This is no problem for darcs; it can happily pull together just any patches.+But it is a problem for the files in \emph{working} (and \emph{pristine}).+The conflict can be thought of as+two patches telling darcs different things about what a file should look like.++Darcs escapes this problem+by ignoring those parts\footnote{%+The primitive patches making up the total patch.}+of the patches that conflict.+They are ignored in \emph{both} patches.+If patch~A changes the line ``FIXME'' to ``FIXED'',+and patch~B changes the same line to ``DONE'',+the two patches together will produce the line ``FIXME''.+Darcs doesn't care which one you pulled into the repository first,+you still get the same result when the conflicting patches meet.+All other changes made by A and B are performed as normal.++Darcs can mark a conflict for you in \emph{working}.+This is done with \verb|mark-conflicts|.+Conflicts are marked such that both conflicting changes+are inserted with special delimiter lines around them.+Then you can merge the two changes by hand,+and remove the delimiters.++When you pull patches,+darcs automatically performs a \verb|mark-conflicts| for you if a conflict happens.+You can remove the markup with \verb|revert|,+Remember that the result will be the lines from+the previous version common to both conflicting patches.+The conflict marking can be redone again with \verb|mark-conflicts|.++A special case is when a pulled patch conflicts with unrecorded changes in the repository.+The conflict will be automatically marked as usual,+but since the markup is \emph{also} an unrecorded change,+it will get mixed in with your unrecorded changes.+There is no guarantee you can revert \emph{only} the markup after this,+and \verb|resolve| will not be able to redo this markup later if you remove it.+It is good practice to record important changes before pulling.++\verb|mark-conflicts| can't mark complicated conflicts.+In that case you'll have to use \verb|darcs diff| and other commands+to understand what the conflict is all about.+If for example two conflicting patches create the same file,+\verb|mark-conflicts| will pick just one of them,+and no delimiters are inserted.+So watch out if darcs tells you about a conflict.++\verb|mark-conflicts| can also be used to check for unresolved conflicts.+If there are none, darcs replies ``No conflicts to resolve''.+While \verb|pull| reports when a conflict happens,+\verb|obliterate| and \verb|get| don't.+++\subsection{Resolving conflicts}++A conflict is resolved+(not marked, as with the command \verb|mark-conflicts|)+as soon as some new patch depends on the conflicting patches.+This will usually be the resolve patch you record after manually putting together the pieces+from the conflict markup produced by \verb|mark-conflicts| (or \verb|pull|).+But it can just as well be a tag.+So don't forget to fix conflicts before you accidently ``resolve'' them by recording other patches.++If the conflict is with one of your not-yet-published patches,+you may choose to amend that patch rather than creating a resolve patch.++If you want to back out and wait with the conflict,+you can \verb|obliterate| the conflicting patch you just pulled.+Before you can do that you have to \verb|revert| the conflict markups+that \verb|pull| inserted when the conflict happened.+++\section{Distributed development with one primary developer}+\label{darcs-development-practices}++This is how darcs itself is developed.  There are many contributors to+darcs, but every contribution is reviewed and manually applied by myself.+For this sort of a situation, \verb|darcs send| is ideal, since the barrier for+contributions is very low, which helps encourage contributors.++One could simply set the \verb!_darcs/prefs/email! value to the project+mailing list, but I also use darcs send to send my changes to the main+server, so instead the email address is set to+``\verb!Davids Darcs Repo <droundy@abridgegame.org>!''.  My+\verb-.procmailrc-+file on the server has the following rule:+\begin{verbatim}+:0+* ^TODavids Darcs Repo+|(umask 022; darcs apply --reply darcs-devel@abridgegame.org \+             --repodir /path/to/repo --verify /path/to/allowed_keys)+\end{verbatim}+This causes darcs apply to be run on any email sent to ``Davids Darcs+Repo''.+\verb'apply' actually applies them only if they are signed by an+authorized key.  Currently, the only authorized key is mine, but of course+this could be extended easily enough.++The central darcs repository contains the following values in its+\verb!_darcs/prefs/defaults!:+\begin{verbatim}+apply test+apply verbose+apply happy-forwarding+\end{verbatim}+The first line tells apply to always run the test suite.  The test suite is+in fact the main reason I use send rather than push, since it allows me to+easily continue working (or put my computer to sleep) while the tests are+being run on the main server.  The second line is just there to improve the+email response that I get when a patch has either been applied or failed+the tests.  The third line makes darcs not complain about unsigned patches,+but just to forward them to \verb!darcs-devel!.++On my development computer, I have in my \verb!.muttrc! the following+alias, which allows me to easily apply patches that I get via email+directly to my darcs working directory:+\begin{verbatim}+macro pager A "<pipe-entry>(umask 022; darcs apply --no-test -v \+        --repodir ~/darcs)"+\end{verbatim}+++\section{Development by a small group of developers in one office}+\label{dft-development-practices}++This section describes the development method used for the density+functional theory code DFT++, which is available at+\verb!http://dft.physics.cornell.edu/dft!.++We have a number of workstations which all mount the same \verb!/home! via NFS.+We created a special ``dft'' user, with the central repository living in that+user's home directory.  The ssh public keys of authorized persons are added to+the ``dft'' user's \verb!.ssh/allowed_keys!, and we commit patches to this+repository using+\verb'darcs push'.  As in Section~\ref{darcs-development-practices},+we have the central repository set to run the test suite before the push goes+through.++Note that no one ever runs as the dft user.++A subtlety that we ran into showed up in the running of the test suite.+Since our test suite includes the running of MPI programs, it must be run+in a directory that is mounted across our cluster.  To achieve this, we set+the \verb!$DARCS_TMPDIR! % following is added to make emacs color right:$+environment variable to \verb!~/tmp!.++Note that even though there are only four active developers at the moment,+the distributed nature of darcs still plays a large role.  Each developer+works on a feature until it is stable, a process that often takes quite a+few patches, and only once it is stable does he+\verb'push' to the central repository.++\section{Personal development}++It's easy to have several personal development trees using darcs, even+when working on a team or with shared code.  The number and method of+using each personal tree is limited only by such grand limitations as:+your disk space, your imagination, available time, etc.++For example, if the central darcs repository for your development team+is $R_{c}$, you can create a local working directory for feature+$f_1$.  This local working directory contains a full copy of $R_c$+(as of the time of the ``darcs get'' operation) and can be denoted+$R_1$.  In the midst of working on feature $f_1$, you realize it+requires the development of a separate feature $f_2$.  Rather than+intermingling $f_1$ and $f_2$ in the same working tree, you can create+a new working tree for working on $f_2$, where that working tree+contains the repository $R_2$.++While working on $f_2$, other developers may have made other changes;+these changes can be retrieved on a per-patch selection basis by+periodic ``darcs pull'' operations.++When your work on $f_2$ is completed, you can publish it for the use+of other developers by a ``darcs push'' (or ``darcs send'') from $R_2$+to $R_c$.  Independently of the publishing of $f_2$, you can merge+your $f_2$ work into your $f_1$ working tree by a ``darcs pull $R_2$''+in the $R_1$ development tree (or ``darcs push'' from $R_2$ to $R_1$).++When your work on $f_1$ is completed, you publish it as well by a+``darcs push'' from $R_1$ to $R_c$.  ++Your local feature development efforts for $f_1$ or $f_2$ can each+consist of multiple patches.  When pushing or pulling to other trees,+these patches can either all be selected or specific patches can be+selected.  Thus, if you introduce a set of debugging calls into the+code, you can commit the debugging code in a distictly separate patch+(or patches) that you will not push to $R_c$.++\subsection{Private patches}++As discussed in the section above, a developer may have various+changes to their local development repositories that they do not ever+wish to publish to a group repository (e.g. personal debugging code),+but which they would like to keep in their local repository, and+perhaps even share amongst their local repositories.++This is easily done via darcs, since those private changes can be+committed in patches that are separate from other patches; during the+process of pushing patches to the common repository ($R_c$), the+developer is queried for which patches should be moved to ($R_c$) on a+patch-by-patch basis.++The \verb!--complement! flag for the ``darcs pull'' operation can+further simplify this effort.  If the developer copies (via ``darcs+push'' or ``darcs pull'') all private patches into a special+repository/working tree ($R_p$), then those patches are easily+disregarded for pulling by adding \verb!--complement! to the ``darcs+pull'' line and listing $R_p$ after the primary source repository.++The \verb!--complement! flag is only available for ``darcs pull'', and+not ``darcs push'' or ``darcs send'', requiring the user to have pull+access to the target repository.  While the actual public repository+is often not shared in this manner, it's simple to create a local+version of the public repository to act as the staging area for that+public repository.++The following example extends the two feature addition example in the+previous section using a local staging repository ($R_l$) and a+private patch repository:++\begin{verbatim}+$ cd working-dir+$ darcs get http://server/repos/Rc Rl++$ darcs get Rl R1+$ cd R1+...development of f1+$ darcs record -m'p1: f1 initial work'+...+$ darcs record -m'p2: my debugging tracepoints'+...++$ cd ..+$ darcs get http://server/repos/Rc R2+$ cd R2+$ darcs pull -p p2 ../R1+... development of f2+$ darcs record -m'p3: f2 finished'++$ cd ..+$ darcs get Rl Rp+$ cd Rp+$ darcs pull -p p2 ../R2++$ cd ../Rl+$ darcs pull --complement ../R2 ../Rp+$ darcs send+... for publishing f2 patches to Rc++$ cd ../R1+$ darcs pull ../R2+... updates R1 with f2 changes from R2+... more development of f1+$ darcs record -m'p4: f1 feature finished.'++$ cd ../Rl+$ darcs pull --complement ../R1 ../Rp+$ darcs send+\end{verbatim}+
+ src/building_darcs.tex view
@@ -0,0 +1,155 @@+\chapter{Building darcs}++This chapter should walk you through the steps necessary to build darcs for+yourself.  There are in general two ways to build darcs.  One is for+building released versions from tarballs, and the other is to build the+latest and greatest darcs, from the darcs repo itself.++Please let me know if you have any problems building darcs, or don't have+problems described in this chapter and think there's something obsolete+here, so I can keep this page up-to-date.++\section{Prerequisites}+To build darcs you will need to have {\tt ghc}, the Glorious Glasgow+Haskell Compiler. You should have at the very minimum version 6.4.++It is a good idea (but not required) to have software installed that provide darcs+network access. The {\tt libwww-dev}, {\tt libwww-ssl-dev} or {\tt libcurl} packages+newer than than 7.18.0 are recommended because they provide pipelining support speed+up HTTP access. They have to be explicitly chosen with {\tt --with-libwww} or+{\tt --with-curl-pipelining}. Otherwise, darcs will automatically look for one of+libcurl, {\tt curl} or {\tt wget}.  You also might want to have scp+available if you want to grab your repos over ssh\ldots++To use the \verb!diff! command of darcs, a \verb!diff! program supporting+options \verb!-r! (recursive diff) and \verb!-N! (show new files as+differences against an empty file) is required. The \verb!configure!+script will look for \verb!gdiff!, \verb!gnudiff! and \verb!diff! in this+order. You can force the use of another program by setting the \verb!DIFF!+environment variable before running \verb!configure!.++To rebuild the documentation (which should not be necessary since it is+included in html form with the tarballs), you will need to have latex+installed, as well as latex2html if you want to build it in html form.+++\section{Building on Mac~OS~X}+To build on Mac~OS~X, you will need the Apple Developer Tools and the ghc+6.4 package installed.++\section{Building on Microsoft Windows}+To build on Microsoft Windows, you will need:++\begin{itemize}+\item \htmladdnormallinkfoot{MinGW}{http://www.mingw.org/} which provides the GCC+  toolchain for win32.+\item \htmladdnormallinkfoot{MSYS}{http://www.mingw.org/msys.shtml} which provides+  a unix build environment for win32.  Be sure to download the separate+  msysDTK, autoconf and automake.+\item \htmladdnormallinkfoot{zlib-1.2.1+}{http://www.gzip.org/zlib/} library+  and headers.+\item \htmladdnormallinkfoot{curl-7.12.2+}{http://curl.haxx.se/} library+  and headers.+\item If building with an SSL enabled curl you will need the OpenSSL+  libraries, unofficial builds are available at\\+  \htmladdnormallink{http://www.slproweb.com/products/Win32OpenSSL.html}{http://www.slproweb.com/products/Win32OpenSSL.html}.+\end{itemize}++Copy the zlib and curl libraries and headers to both GHC and MinGW.  GHC+stores C headers in \verb!<ghc-dir>/gcc-lib/include! and libraries in+\verb!<ghc-dir>/gcc-lib!.  MinGW stores headers in+\verb!<mingw-dir>/include! and libraries in \verb!<mingw-dir>/lib!.++Set PATH to include the \verb!<msys-dir>/bin!, \verb!<mingw-dir>/bin!,+\verb!<curl-dir>!, and a directory containing a pre-built darcs.exe if you+want the build's patch context stored for `\verb!darcs --exact-version!'.++\begin{verbatim}+C:\darcs> cd <darcs-source-dir>+C:\darcs> sh++$ export GHC=/c/<ghc-dir>/bin/ghc.exe+$ autoconf+$ ./configure --target=mingw+$ make+\end{verbatim}++\section{Building from tarball}+If you get darcs from a tarball, the procedure (after unpacking the tarball+itself) is as follows:+\begin{verbatim}+% ./configure+% make+# Optional, but recommended+% make test+% make install+\end{verbatim}++There are options to configure that you may want to check out with+\begin{verbatim}+% ./configure --help+\end{verbatim}++If your header files are installed in a non-standard location, you may need+to define the \verb!CFLAGS! and \verb!CPPFLAGS! environment variables to+include the path to the headers.  e.g. on NetBSD, you may need to run+\begin{verbatim}+% CFLAGS=-I/usr/pkg/include CPPFLAGS=-I/usr/pkg/include ./configure+\end{verbatim}++\section{Building darcs from the repository}+To build the latest darcs from its repository, you will first need a+working copy of Darcs 2. You can get darcs using:+\begin{verbatim}+% darcs get -v http://darcs.net/+\end{verbatim}+and once you have the darcs repository you can bring it up to date with a+\begin{verbatim}+% darcs pull+\end{verbatim}++The repository doesn't hold automatically generated files, which include+the configure script and the HTML documentation, so you need to run+\verb!autoconf! first.++You'll need \verb!autoconf! 2.50 or higher. Some systems have more than one+version of \verb!autoconf! installed. For example, \verb!autoconf! may point to+version 2.13, while \verb!autoconf259!  runs version 2.59.++Also note that \verb!make! is really "GNU make". On some systems, such as+the *BSDs, you may need to type \verb!gmake! instead of make for this to work.++If you want to create readable documentation you'll need to have latex installed.+\begin{verbatim}+% autoconf+% ./configure+% make+% make install+\end{verbatim}++If you want to tweak the configure options, you'll need to run {\tt+  ./configure} yourself after the make, and then run make again.++\section{Submitting patches to darcs}+I know, this doesn't really belong in this chapter, but if you're using the+repository version of darcs it's really easy to submit patches to me using+darcs. In fact, even if you don't know any Haskell, you could submit fixes+or additions to this document (by editing \verb!building_darcs.tex!) based+on your experience building darcs\ldots++To do so, just record your changes (which you made in the darcs repository)+\begin{verbatim}+% darcs record --no-test+\end{verbatim}+making sure to give the patch a nice descriptive name.  The+\verb!--no-test! options keeps darcs from trying to run the unit tests,+which can be rather time-consuming.  Then you can send the patch to the+darcs-devel mailing list by email by+\begin{verbatim}+% darcs send -u+\end{verbatim}+The darcs repository stores the email address to which patches should be+sent by default.  The email address you see is actually my own, but when+darcs notices that you haven't signed the patch with my GPG key, it will+forward the message to darcs-devel.+
+ src/c_compat.c view
@@ -0,0 +1,88 @@++#include <sys/types.h>+#include <sys/stat.h>+#include <fcntl.h>+#include <string.h>+#include <stdio.h>+#include <stdlib.h>++#include <unistd.h>+#include <errno.h>+#include <sys/time.h>+#include <time.h>++#ifdef _WIN32+#include <windows.h>+#include <io.h>+#endif++#ifndef _WIN32++int open_read(const char *fname) {+  return open(fname, O_RDONLY);+}++int open_write(const char *fname) {+  return open(fname, O_WRONLY | O_TRUNC | O_CREAT,+              S_IWUSR | S_IRUSR | S_IROTH | S_IRGRP);+}++int get_errno() {+  return errno;+}++#include <sys/wait.h>+#include <signal.h>+#if  HAVE_SIGINFO_H+#include <siginfo.h>+#endif++/* This waits and then returns the exit status of the process that was+   waited for. */+int smart_wait(int pid) {+  int stat;+  pid_t rc;++  do {+      rc = waitpid(pid, &stat, 0);+  } while(rc < 0 && errno == EINTR);++  if(rc < 0) {+    perror("waitpid");+    return -138;+  } else if (WIFEXITED(stat)) {+    return WEXITSTATUS(stat);+  } else if (WIFSIGNALED(stat)) {+    /* Fixme: psignal isn't portable (not in POSIX).  */+    psignal(WTERMSIG(stat), "Error in subprocess");+    return - WTERMSIG(stat);+  } else {+    return -137;+  }+}++#include <unistd.h>+#include <sys/time.h>+#include <errno.h>+#include <stdio.h>++int execvp_no_vtalarm(const char *file, char *const argv[]) {+  /* Reset the itimers in the child, so it doesn't get plagued+   * by SIGVTALRM interrupts.+   */+  struct timeval tv_null = { 0, 0 };+  struct itimerval itv;+  itv.it_interval = tv_null;+  itv.it_value = tv_null;+  setitimer(ITIMER_REAL, &itv, NULL);+  setitimer(ITIMER_VIRTUAL, &itv, NULL);+  setitimer(ITIMER_PROF, &itv, NULL);+  execvp(file, argv);+  perror("Error in execvp");+  return errno;+}++#include <sys/types.h>+#include <sys/stat.h>+#endif+
+ src/compat.h view
@@ -0,0 +1,12 @@++#include <sys/stat.h>+#include <string.h>+#include <stdlib.h>++int open_read(const char *fname);+int open_write(const char *fname);+int smart_wait(int pid);+int get_errno();++int execvp_no_vtalarm(const char *file, char *const argv[]);+
+ src/configuring_darcs.tex view
@@ -0,0 +1,296 @@+%  Copyright (C) 2004 David Roundy+%+%  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, 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.++\chapter{Configuring darcs}\label{configuring}++There are several ways you can adjust darcs' behavior to suit your needs.+The first is to edit files in the \verb!_darcs/prefs/! directory of a+repository.  Such configuration only applies when working with that+repository.  To configure darcs on a per-user rather than per-repository+basis (but with essentially the same methods), you can edit (or create)+files in the \verb!~/.darcs/! directory.  Finally, the behavior of some+darcs commands can be modified by setting appropriate environment+variables.++\input{Darcs/Repository/Prefs.lhs}++\input{Darcs/Repository/Motd.lhs}++\section{Environment variables}++There are a few environment variables whose contents affect darcs'+behavior.  Here is a quick list of all the variables and their+documentation in the rest of the manual:++\begin{tabular}{|l|r|}+\hline+\textbf{Variable} & \textbf{Section} \\+\hline+DARCS\_EDITOR, EDITOR, VISUAL & \ref{env:DARCS_EDITOR} \\+DARCS\_PAGER, PAGER &  \ref{env:DARCS_PAGER} \\+HOME & \ref{env:HOME} \\+TERM & \ref{env:TERM} \\+\hline+DARCS\_EMAIL, EMAIL  & \ref{env:DARCS_EMAIL} \\+\hline+DARCS\_APPLY\_FOO & \ref{env:DARCS_X_FOO} \\+DARCS\_GET\_FOO & \ref{env:DARCS_X_FOO} \\+DARCS\_MGET\_FOO & \ref{env:DARCS_X_FOO} \\+DARCS\_MGETMAX & \ref{env:DARCS_MGETMAX} \\+DARCS\_PROXYUSERPWD & \ref{env:DARCS_PROXYUSERPWD} \\+DARCS\_WGET & \ref{env:DARCS_WGET} \\+DARCS\_SSH & \ref{env:DARCS_SSH} \\+DARCS\_SCP & \ref{env:DARCS_SCP} \\+DARCS\_SFTP & \ref{env:DARCS_SFTP} \\+SSH\_PORT & \ref{env:SSH_PORT} \\+\hline+DARCS\_ALTERNATIVE\_COLOR & \ref{env:DARCS_ALWAYS_COLOR}\\+DARCS\_ALWAYS\_COLOR & \ref{env:DARCS_ALWAYS_COLOR}\\+DARCS\_DO\_COLOR\_LINES & \ref{env:DARCS_DO_COLOR_LINES}\\+DARCS\_DONT\_COLOR   & \ref{env:DARCS_ALWAYS_COLOR} \\+DARCS\_DONT\_ESCAPE\_TRAILING\_CR     & \ref{env:DARCS_DONT_ESCAPE_white}\\+DARCS\_DONT\_ESCAPE\_TRAILING\_SPACES & \ref{env:DARCS_DONT_ESCAPE_white} \\+DARCS\_DONT\_ESCAPE\_8BIT & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\+DARCS\_DONT\_ESCAPE\_ANYTHING & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\+DARCS\_DONT\_ESCAPE\_ISPRINT & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\+DARCS\_ESCAPE\_EXTRA & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\+DARCS\_DONT\_ESCAPE\_EXTRA & \ref{env:DARCS_DONT_ESCAPE_nonascii}\\+\hline+\end{tabular}++\section{General-purpose variables}++\paragraph{DARCS\_EDITOR}+\label{env:DARCS_EDITOR}+When pulling up an editor (for example, when adding a long comment in+record), darcs uses the contents of DARCS\_EDITOR if it is defined.  If+not, it tries the contents of VISUAL, and if that isn't defined (or fails+for some reason), it tries EDITOR\@.  If none of those environment variables+are defined, darcs tries \verb!vi!, \verb!emacs!, \verb!emacs -nw! and+\verb!nano! in that order.++\paragraph{DARCS\_PAGER}+\label{env:DARCS_PAGER}+When using a pager for displaying a patch, darcs uses the contents of+DARCS\_PAGER if it is defined.  If not, it tries the contents of PAGER+and then \verb!more!.++\paragraph{DARCS\_TMPDIR}+\label{env:DARCS_TMPDIR}+If the environment variable DARCS\_TMPDIR is defined, darcs will use that+directory for its temporaries.  Otherwise it will use TMPDIR, if that is+defined, and if not that then \verb!/tmp! and if \verb!/tmp! doesn't exist,+it'll put the temporaries in \verb!_darcs!.++This is very helpful, for example, when recording with a test suite that+uses MPI, in which case using \verb!/tmp! to hold the test copy is no good,+as \verb!/tmp! isn't shared over NFS and thus the \verb!mpirun! call will+fail, since the binary isn't present on the compute nodes.++\paragraph{HOME}+\label{env:HOME}+HOME is used to find the per-user prefs directory, which is located at+\verb!$HOME/.darcs!.++%$ this dollar is a comment to make my emacs leave math mode... (stupid+%  emacs)++\paragraph{TERM}+\label{env:TERM}+If darcs is compiled with libcurses support and support for color output,+it uses the environment variable TERM to decide whether or not color is+supported on the output terminal.++\section{Remote repositories}++\paragraph{SSH\_PORT}+\label{env:SSH_PORT}+When using ssh, if the SSH\_PORT environment variable is defined, darcs will+use that port rather than the default ssh port (which is 22).++\paragraph{DARCS\_SSH}+\label{env:DARCS_SSH}+The DARCS\_SSH environment variable defines the command that darcs will use+when asked to run ssh.  This command is \emph{not} interpreted by a shell,+so you cannot use shell metacharacters, and the first word in the command+must be the name of an executable located in your path.++\paragraph{DARCS\_SCP and DARCS\_SFTP}+\label{env:DARCS_SCP}+\label{env:DARCS_SFTP}+The DARCS\_SCP and DARCS\_SFTP environment variables define the+commands that darcs will use when asked to run scp or sftp.  Darcs uses+scp and sftp to access repositories whose address is of the+form \verb!user@foo.org:foo! or \verb!foo.org:foo!.  Darcs will use+scp to copy single files (e.g.\ repository meta-information), and sftp+to copy multiple files in batches (e.g.\ patches).  These commands are+\emph{not} interpreted by a shell, so you cannot use shell+metacharacters, and the first word in the command must be the name of+an executable located in your path.  By default, \verb!scp! and \verb!sftp!+are used.  When you can use sftp, but not scp (e.g.\ some ISP web sites), it+works to set DARCS\_SCP to `sftp'.  The other way around does not work, i.e.\ +DARCS\_FTP must reference an sftp program, not scp.++\paragraph{DARCS\_PROXYUSERPWD}+\label{env:DARCS_PROXYUSERPWD}+This environment variable allows DARCS and libcurl to access remote repositories+via a password-protected HTTP proxy. The proxy itself is specified with the standard+environment variable for this purpose, namely 'http\_proxy'. The DARCS\_PROXYUSERPWD+environment variable specifies the proxy username and password. It must be given in +the form \emph{username:password}.++\paragraph{DARCS\_GET\_FOO, DARCS\_MGET\_FOO and DARCS\_APPLY\_FOO}+\label{env:DARCS_X_FOO}+When trying to access a repository with a URL beginning foo://,+darcs will invoke the program specified by the DARCS\_GET\_FOO+environment variable (if defined) to download each file, and the+command specified by the DARCS\_APPLY\_FOO environment variable (if+defined) when pushing to a foo:// URL.  ++This method overrides all other ways of getting \verb!foo://xxx! URLs.++Note that each command should be constructed so that it sends the downloaded+content to STDOUT, and the next argument to it should be the URL\@.  Here are some+examples that should work for DARCS\_GET\_HTTP:++\begin{verbatim}+fetch -q -o -  +curl -s -f+lynx -source +wget -q -O -+\end{verbatim}++If set, DARCS\_MGET\_FOO+will be used to fetch many files from a single repository simultaneously.+Replace FOO and foo as appropriate to handle other URL schemes.+These commands are \emph{not} interpreted by a shell, so you cannot+use shell metacharacters, and the first word in the command must+be the name of an executable located in your path. The GET command+will be called with a URL for each file.  The MGET command will be+invoked with a number of URLs and is expected to download the files+to the current directory, preserving the file name but not the path.+The APPLY command will be called with a darcs patchfile piped into+its standard input. Example:++\begin{verbatim}+wget -q +\end{verbatim}++\paragraph{DARCS\_MGETMAX}+\label{env:DARCS_MGETMAX}+When invoking a DARCS\_MGET\_FOO command, darcs will limit the+number of URLs presented to the command to the value of this variable,+if set, or 200.++\paragraph{DARCS\_WGET}+\label{env:DARCS_WGET}+This is a very old option that is only used if libcurl is not compiled+in and one of the DARCS\_GET\_FOO is not used. Using one of those+is recommended instead.++The DARCS\_WGET environment variable defines the command that darcs+will use to fetch all URLs for remote repositories.  The first word in+the command must be the name of an executable located in your path.+Extra arguments can be included as well, such as:++\begin{verbatim}+wget -q +\end{verbatim}++Darcs will append \verb!-i! to the argument list, which it uses to provide a+list of URLS to download. This allows wget to download multiple patches at the+same time. It's possible to use another command besides \verb!wget! with this+environment variable, but it must support the \verb!-i! option in the same way. ++These commands are \emph{not} interpreted by a shell, so you cannot use shell+meta-characters.+++\section{Highlighted output}+\label{env:DARCS_ALWAYS_COLOR}+\label{env:DARCS_DO_COLOR_LINES}+\label{env:DARCS_DONT_ESCAPE_white}++If the terminal understands ANSI color escape sequences,+darcs will highlight certain keywords and delimiters when printing patches.+This can be turned off by setting the environment variable DARCS\_DONT\_COLOR to 1.+If you use a pager that happens to understand ANSI colors, like \verb!less -R!,+darcs can be forced always to highlight the output+by setting DARCS\_ALWAYS\_COLOR to 1.+If you can't see colors you can set DARCS\_ALTERNATIVE\_COLOR to 1,+and darcs will use ANSI codes for bold and reverse video instead of colors.+In addition, there is an extra-colorful mode, which is not enabled by+default, which can be activated with DARCS\_DO\_COLOR\_LINES.++By default darcs will escape (by highlighting if possible) any kind of spaces at the end of lines+when showing patch contents.+If you don't want this you can turn it off by setting+DARCS\_DONT\_ESCAPE\_TRAILING\_SPACES to 1.+A special case exists for only carriage returns:+DARCS\_DONT\_ESCAPE\_TRAILING\_CR.+++\section{Character escaping and non-ASCII character encodings}+\label{env:DARCS_DONT_ESCAPE_nonascii}++Darcs needs to escape certain characters when printing patch contents to a terminal.+Characters like \emph{backspace} can otherwise hide patch content from the user,+and other character sequences can even in some cases redirect commands to the shell+if the terminal allows it.++By default darcs will only allow printable 7-bit ASCII characters (including space),+and the two control characters \emph{tab} and \emph{newline}.+(See the last paragraph in this section for a way to tailor this behavior.)+All other octets are printed in quoted form (as \verb!^<control letter>! or+\verb!\!\verb!<hex code>!).++Darcs has some limited support for locales.+If the system's locale is a single-byte character encoding,+like the Latin encodings,+you can set the environment variable DARCS\_DONT\_ESCAPE\_ISPRINT to 1+and darcs will display all the printables in the current system locale+instead of just the ASCII ones.+NOTE: This curently does not work on some architectures if darcs is+compiled with GHC~6.4. Some non-ASCII control characters might be printed+and can possibly spoof the terminal.++For multi-byte character encodings things are less smooth.+UTF-8 will work if you set DARCS\_DONT\_ESCAPE\_8BIT to 1,+but non-printables outside the 7-bit ASCII range are no longer escaped.+E.g., the extra control characters from Latin-1+might leave your terminal at the mercy of the patch contents.+Space characters outside the 7-bit ASCII range are no longer recognized+and will not be properly escaped at line endings.++As a last resort you can set DARCS\_DONT\_ESCAPE\_ANYTHING to 1.+Then everything that doesn't flip code sets should work,+and so will all the bells and whistles in your terminal.+This environment variable can also be handy+if you pipe the output to a pager or external filter+that knows better than darcs how to handle your encoding.+Note that \emph{all} escaping,+including the special escaping of any line ending spaces,+will be turned off by this setting.++There are two environment variables you can set+to explicitly tell darcs to not escape or escape octets.+They are+DARCS\_DONT\_ESCAPE\_EXTRA and DARCS\_ESCAPE\_EXTRA.+Their values should be strings consisting of the verbatim octets in question.+The do-escapes take precedence over the dont-escapes.+Space characters are still escaped at line endings though.+The special environment variable DARCS\_DONT\_ESCAPE\_TRAILING\_CR+turns off escaping of carriage return last on the line (DOS style).
+ src/darcs.lhs view
@@ -0,0 +1,835 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\documentclass{book}+%\usepackage{color}++\usepackage{verbatim}+\usepackage{html}+\usepackage{fancyvrb}+\newenvironment{code}{\comment}{\endcomment}+% \newenvironment{code}{\color{blue}\verbatim}{\endverbatim}++\begin{document}++\begin{code}+{-# OPTIONS_GHC -cpp #-}+module Main (main) where++import System.IO ( hSetBinaryMode)+import System.IO ( stdin, stdout )+import System.Exit ( exitWith, ExitCode(..) )+import System.Environment ( getArgs )+import Control.Monad ( when )+import Control.Exception ( Exception( AssertionFailed ), handleJust, catchDyn )+import Workaround ( getCurrentDirectory )++import Darcs.Commands ( command_command, command_name, command_prereq, extract_commands,+                       run_the_command, usage )+import Darcs.Flags ( DarcsFlag(Verbose) )+import Darcs.Commands.Help ( command_control_list, help, print_version )+import Autoconf( darcs_version )+import Darcs.SignalHandler ( withSignalsHandled )+import Darcs.Utils ( withCurrentDirectory )+import Context ( context )+import Darcs.Global ( with_atexit )+import Exec ( ExecException(..) )+#include "impossible.h"+\end{code}++% Definition of title page:+\title{+    Darcs \haskell{darcs_version}\\+{\Large\itshape Darcs}+}+\author{+    David Roundy+}++\maketitle++\tableofcontents++\chapter{Introduction}++Darcs is a revision control system, along the lines of CVS or arch.  That+means that it keeps track of various revisions and branches of your+project, allows for changes to propagate from one branch to another.  Darcs+is intended to be an ``advanced'' revision control system.  Darcs has two+particularly distinctive features which differ from other revision control+systems: 1) each copy of the source is a fully functional branch, and 2)+underlying darcs is a consistent and powerful theory of patches.++\paragraph{Every source tree a branch}+The primary simplifying notion of darcs is that \emph{every} copy of your+source code is a full repository. This is dramatically different from CVS,+in which the normal usage is for there to be one central repository from+which source code will be checked out. It is closer to the notion of arch,+since the `normal' use of arch is for each developer to create his own+repository. However, darcs makes it even easier, since simply checking out+the code is all it takes to create a new repository. This has several+advantages, since you can harness the full power of darcs in any scratch+copy of your code, without committing your possibly destabilizing changes to+a central repository.++\paragraph{Theory of patches}+The development of a simplified theory of patches is what originally+motivated me to create darcs. This patch formalism means that darcs patches+have a set of properties, which make possible manipulations that couldn't be+done in other revision control systems. First, every patch is invertible.+Secondly, sequential patches (i.e.\ patches that are created in sequence, one+after the other) can be reordered, although this reordering can fail, which+means the second patch is dependent on the first. Thirdly, patches which are+in parallel (i.e.\ both patches were created by modifying identical trees)+can be merged, and the result of a set of merges is independent of the order+in which the merges are performed. This last property is critical to darcs'+philosophy, as it means that a particular version of a source tree is fully+defined by the list of patches that are in it, i.e.\ there is no issue+regarding the order in which merges are performed. For a more thorough+discussion of darcs' theory of patches, see Appendix~\ref{Patch}.++\paragraph{A simple advanced tool}+Besides being ``advanced'' as discussed above, darcs is actually also quite+simple. Versioning tools can be seen as three layers. At the foundation is+the ability to manipulate changes. On top of that must be placed some kind+of database system to keep track of the changes. Finally, at the very top is+some sort of distribution system for getting changes from one place to+another.++Really, only the first of these three layers is of particular interest to+me, so the other two are done as simply as possible.  At the database+layer, darcs just has an ordered list of patches along with the patches+themselves, each stored as an individual file.  Darcs' distribution system+is strongly inspired by that of arch.  Like arch, darcs uses a dumb server,+typically apache or just a local or network file system when pulling+patches.  darcs has built-in support for using \verb!ssh! to write to a remote file+system. A darcs executable is called on the remote system to apply the patches.+Arbitrary other transport protocols are supported, through an environment+variable describing a command that will run darcs on the remote system.+See the documentation for DARCS\_APPLY\_FOO in Chapter~\ref{configuring}+for details.++The recommended method is to send patches through gpg-signed email+messages, which has the advantage of being mostly asynchronous.++\paragraph{Keeping track of changes rather than versions}++In the last paragraph, I explained revision control systems in terms of+three layers.  One can also look at them as having two distinct uses.  One+is to provide a history of previous versions.  The other is to keep track+of changes that are made to the repository, and to allow these changes to+be merged and moved from one repository to another.  These two uses are+distinct, and almost orthogonal, in the sense that a tool can support one+of the two uses optimally while providing no support for the other.  Darcs+is not intended to maintain a history of versions, although it is possible+to kludge together such a revision history, either by making each new patch+depend on all previous patches, or by tagging regularly.  In a sense, this+is what the tag feature is for, but the intention is that tagging will be+used only to mark particularly notable versions (e.g.\ released versions, or+perhaps versions that pass a time consuming test suite).++Other revision control systems are centered upon the job of keeping track+of a history of versions, with the ability to merge changes being added as+it was seen that this would be desirable.  But the fundamental object+remained the versions themselves.++In such a system, a patch (I am using patch here to mean an encapsulated+set of changes) is uniquely determined by two trees.  Merging changes that+are in two trees consists of finding a common parent tree, computing the+diffs of each tree with their parent, and then cleverly combining those two+diffs and applying the combined diff to the parent tree, possibly at some+point in the process allowing human intervention, to allow for fixing up+problems in the merge such as conflicts.++In the world of darcs, the source tree is \emph{not} the fundamental+object, but rather the patch is the fundamental object.  Rather than a+patch being defined in terms of the difference between two trees, a tree is+defined as the result of applying a given set of patches to an empty tree.+Moreover, these patches may be reordered (unless there are dependencies+between the patches involved) without changing the tree.  As a result,+there is no need to find a common parent when performing a merge.  Or, if+you like, their common parent is defined by the set of common patches, and+may not correspond to any version in the version history.++One useful consequence of darcs' patch-oriented philosophy is that since a+patch need not be uniquely defined by a pair of trees (old and new), we can+have several ways of representing the same change, which differ only in how+they commute and what the result of merging them is.  Of course, creating+such a patch will require some sort of user input.  This is a Good Thing,+since the user \emph{creating} the patch should be the one forced to think+about what he really wants to change, rather than the users merging the+patch.  An example of this is the token replace patch (See+Section~\ref{token_replace}).  This feature makes it possible to create a+patch, for example, which changes every instance of the variable+``stupidly\_named\_var'' to ``better\_var\_name'', while leaving+``other\_stupidly\_named\_var'' untouched.  When this patch is merged with+any other patch involving the ``stupidly\_named\_var'', that instance will+also be modified to ``better\_var\_name''.  This is in contrast to a more+conventional merging method which would not only fail to change new+instances of the variable, but would also involve conflicts when merging+with any patch that modifies lines containing the variable.  By more using+additional information about the programmer's intent, darcs is thus able to+make the process of changing a variable name the trivial task that it+really is, which is really just a trivial search and replace, modulo+tokenizing the code appropriately.++The patch formalism discussed in Appendix~\ref{Patch} is what makes darcs'+approach possible.  In order for a tree to consist of a set of patches,+there must be a deterministic merge of any set of patches, regardless of the+order in which they must be merged.  This requires that one be able to+reorder patches.  While I don't know that the patches are required to be+invertible as well, my implementation certainly requires invertibility.  In+particular, invertibility is required to make use of+Theorem~\ref{merge_thm}, which is used extensively in the manipulation of+merges.++\input{features.tex}++\input{switching.tex}++\input{building_darcs.tex}++\chapter{Getting started}++This chapter will lead you through an example use of darcs, which hopefully+will allow you to get started using darcs with your project.++\section{Creating your repository}++Creating your repository in the first place just involves telling darcs to+create the special directory (called {\tt \_darcs}) in your project tree,+which will hold the revision information.  This is done by simply calling+from the root directory of your project:+\begin{verbatim}+% cd my_project/+% darcs initialize --darcs-2+\end{verbatim}+This creates the \verb|_darcs| directory and populates it with whatever+files and directories are needed to describe an empty project.  You now+need to tell darcs what files and directories in your project should be+under revision control.  You do this using the command \verb|darcs add|%+\footnote{Note that darcs does not do wildcard expansion, instead relying+on the command shell.  The Windows port of darcs has a limited form of+expansion provided by the C runtime}:+\begin{verbatim}+% darcs add *.c Makefile.am configure.ac+\end{verbatim}+When you have added all your files (or at least, think you have), you will+want to record your changes.  ``Recording'' always includes adding a note+as to why the change was made, or what it does.  In this case, we'll just+note that this is the initial version.+\begin{verbatim}+% darcs record --all+What is the patch name? Initial revision.+\end{verbatim}+Note that since we didn't specify a patch name on the command line we were+prompted for one.  If the environment variable `EMAIL' isn't set, you will+also be prompted for your email address.  Each patch that is recorded is+given a unique identifier consisting of the patch name, its creator's email+address, and the date when it was created.++\section{Making changes}++Now that we have created our repository, make a change to one or more of+your files.  After making the modification run:+\begin{verbatim}+% darcs whatsnew+\end{verbatim}+This should show you the modifications that you just made, in the darcs+patch format.  If you prefer to see your changes in a different format,+read Section~\ref{whatsnew}, which describes the whatsnew command in+detail.++Let's say you have now made a change to your project.  The next thing to do+is to record a patch.  Recording a patch consists of grouping together a+set of related changes, and giving them a name.  It also tags the patch+with the date it was recorded and your email address.++To record a patch simply type:+\begin{verbatim}+% darcs record+\end{verbatim}+darcs will then prompt you with all the changes that you have made that+have not yet been recorded, asking you which ones you want to include in+the new patch.  Finally, darcs will ask you for a name for the patch.++You can now rerun whatsnew, and see that indeed the changes you have+recorded are no longer marked as new.++\section{Making your repository visible to others}+How do you let the world know about these wonderful changes?  Obviously,+they must be able to see your repository.  Currently the easiest way to do+this is typically by http using any web server.  The recommended way to do+this (using apache in a UNIX environment) is to create a directory called+{\tt /var/www/repos}, and then put a symlink to your repository there:+\begin{verbatim}+% cd /var/www/repos+% ln -s /home/username/myproject .+\end{verbatim}++As long as you're running a web server and making your repository available to+the world, you may as well make it easy for people to see what changes+you've made.  You can do this by running \verb!make installserver!, which+installs the program \verb|darcs_cgi| at \verb|/usr/lib/cgi-bin/darcs|.  You+also will need to create a cache directory named+\verb!/var/cache/darcs_cgi!, and make sure the owner of that directory is+the same user that your web server runs its cgi scripts as.  For me,+this is www-data.  Now your friends and enemies should be able to easily+browse your repositories by pointing their web browsers at+\verb|http://your.server.org/cgi-bin/darcs|.++\section{Getting changes made to another repository}+Ok, so I can now browse your repository using my web browser\ldots\ so+what? How do I get your changes into \emph{my} repository, where they can+do some good? It couldn't be easier.  I just \verb|cd| into my repository,+and there type:+\begin{verbatim}+% darcs pull http://your.server.org/repos/yourproject+\end{verbatim}+Darcs will check to see if you have recorded any changes that aren't in my+current repository.  If so, it'll prompt me for each one, to see which ones+I want to add to my repository.  Note that you may see a different series+of prompts depending on your answers, since sometimes one patch depends on+another, so if you answer yes to the first one, you won't be prompted for+the second if the first depends on it.++Of course, maybe I don't even have a copy of your repository.  In that case+I'd want to do a+\begin{verbatim}+% darcs get http://your.server.org/repos/yourproject+\end{verbatim}+which gets the whole repository.++I could instead create an empty repository and fetch all of your patches+with pull.  Get is just a more efficient way to clone a whole repository.++Get, pull and push also work over ssh.  Ssh-paths are of the same form+accepted by scp, namely \verb|[username@]host:/path/to/repository|.++\section{Moving patches from one repository to another}++Darcs is flexible as to how you move patches from one repository to another.+This section will introduce all the ways you can get patches from one place+to another, starting with the simplest and moving to the most complicated.++\subsection{All pulls}++The simplest method is the ``all-pull'' method.  This involves making each+repository readable (by http, ftp, nfs-mounted disk, whatever), and you+run \verb|darcs pull| in the repository you want to move the patch to.  This is nice,+as it doesn't require you to give write access to anyone else, and is+reasonably simple.++\subsection{Send and apply manually}++Sometimes you have a machine on which it is not convenient to set up a web+server, perhaps because it's behind a firewall or perhaps for security+reasons, or because it is often turned off.  In this case you can use+\verb|darcs send|+from that computer to generate a patch bundle destined for another+repository.  You can either let darcs email the patch for you, or save it+as a file and transfer it by hand.  Then in the destination repository you+(or the owner of that repository) run \verb|darcs apply| to apply the patches contained+in the bundle.  This is also quite a simple method since, like the all-pull+method, it doesn't require that you give anyone write access to your+repository.  But it's less convenient, since you have to keep track of the+patch bundle (in the email, or whatever).++If you use the send and apply method with email, you'll probably want to+create a \verb!_darcs/prefs/email! file containing your email address.+This way anyone who sends to your repository will automatically send the+patch bundle to your email address.++If you receive many patches by email, you probably will benefit by running+darcs apply directly from your mail program.  I have in my \verb!.muttrc!+the following:+\begin{verbatim}+auto_view text/x-patch text/x-darcs-patch+macro pager A "<pipe-entry>darcs apply --verbose --mark-conflicts \+        --reply droundy@abridgegame.org --repodir ~/darcs"+\end{verbatim}+which allows me to view a sent patch, and then apply the patch directly from \verb!mutt!, sending a+confirmation email to the person who sent me the patch. The autoview line relies on on the following+lines, or something like them, being present in one's \verb!.mailcap!:+\begin{verbatim}+text/x-patch;                           cat; copiousoutput+text/x-darcs-patch;                     cat; copiousoutput+\end{verbatim}++\subsection{Push}++If you use ssh (and preferably also ssh-agent, so you won't have to keep+retyping your password), you can use the push method to transfer changes+(using the scp protocol for communication).  This method is again not very+complicated, since you presumably already have the ssh permissions set up.+Push can also be used when the target repository is local, in which case+ssh isn't needed.  On the other hand, in this situation you could as easily+run a pull, so there isn't much benefit.++Note that you can use push to administer a multiple-user repository.  You+just need to create a user for the repository (or repositories), and give+everyone with write access ssh access, perhaps using+\verb!.ssh/authorized_keys!.  Then they run+\begin{verbatim}+% darcs push repouser@repo.server:repo/directory+\end{verbatim}++\subsection{Push ---apply-as}++Now we get more subtle.  If you like the idea in the previous paragraph+about creating a repository user to own a repository which is writable by+a number of users, you have one other option.++Push \verb!--apply-as! can run on either a local repository or one accessed+with ssh, but uses \verb!sudo! to run a darcs apply command (having created+a patch bundle as in send) as another user.  You can add the following line+in your \verb|sudoers| file to allow the users to apply their patches to a+centralized repository:+{\small+\begin{verbatim}+ALL   ALL = (repo-user) NOPASSWD: /usr/bin/darcs apply --all --repodir /repo/path*+\end{verbatim}+}+This method is ideal for a centralized repository when all the users have+accounts on the same computer, if you don't want your users to be able to+run arbitrary commands as repo-user.++\subsection{Sending signed patches by email}++Most of the previous methods are a bit clumsy if you don't want to give+each person with write access to a repository an account on your server.  Darcs+send can be configured to send a cryptographically signed patch by email.+You can then set up your mail system to have darcs verify that patches were+signed by an authorized user and apply them when a patch is received by+email.  The results of the apply can be returned to the user by email.+Unsigned patches (or patches signed by unauthorized users) will be+forwarded to the repository owner (or whoever you configure them to be+forwarded to\ldots).++This method is especially nice when combined with the \verb!--test! option+of darcs apply, since it allows you to run the test suite (assuming you+have one) and reject patches that fail---and it's all done on the server,+so you can happily go on working on your development machine without+slowdown while the server runs the tests.++Setting up darcs to run automatically in response to email is by far the+most complicated way to get patches from one repository to another\ldots\ so it'll+take a few sections to explain how to go about it.++\paragraph{Security considerations}++When you set up darcs to run apply on signed patches, you should assume+that a user with write access can write to any file or directory that is+writable by the user under which the apply process runs.  Unless you+specify the \verb!--no-test! flag to darcs apply (and this is \emph{not}+the default), you are also allowing anyone with write access to that+repository to run arbitrary code on your machine (since they can run a test+suite---which they can modify however they like).  This is quite a+potential security hole.++For these reasons, if you don't implicitly trust your users, it is+recommended that you create a user for each repository to limit the damage+an attacker can do with access to your repository.  When considering who to+trust, keep in mind that a security breach on any developer's machine could+give an attacker access to their private key and passphrase, and thus to+your repository.++\paragraph{Installing necessary programs}++You also must install the following programs: gnupg, a mailer configured to+receive mail (e.g.\ exim, sendmail or postfix), and a web server (usually+apache).  If you want to be able to browse your repository on the web you+must also configure your web server to run cgi scripts and make sure the+darcs cgi script was properly installed (by either a darcs-server package,+or `make install-server').++\paragraph{Granting access to a repository}++You create your gpg key by running (as your normal user):+\begin{verbatim}+% gpg --gen-key+\end{verbatim}+You will be prompted for your name and email address, among other options.+%%To add your public key to the allowed keys keyring.+Of course, you can+skip this step if you already have a gpg key you wish to use.++You now need to export the public key so we can tell the patcher about it.+You can do this with the following command (again as your normal user):+\begin{verbatim}+% gpg --export "email@address" > /tmp/exported_key+\end{verbatim}+And now we can add your key to the \verb!allowed_keys!:+\begin{verbatim}+(as root)> gpg --keyring /var/lib/darcs/repos/myproject/allowed_keys \+               --no-default-keyring --import /tmp/exported_key+\end{verbatim}+You can repeat this process any number of times to authorize multiple users+to send patches to the repository.++You should now be able to send a patch to the repository by running as your+normal user, in a working copy of the repository:+\begin{verbatim}+% darcs send --sign http://your.computer/repos/myproject+\end{verbatim}+You may want to add ``send sign'' to the file \verb!_darcs/prefs/defaults!+so that you won't need to type \verb!--sign! every time you want to+send\ldots++If your gpg key is protected by a passphrase, then executing \verb!send!+with the \verb!--sign! option might give you the following error:+\begin{verbatim}+darcs failed:  Error running external program 'gpg'+\end{verbatim}+The most likely cause of this error is that you have a misconfigured+gpg that tries to automatically use a non-existent gpg-agent+program. GnuPG will still work without gpg-agent when you try to sign+or encrypt your data with a passphrase protected key. However, it will+exit with an error code 2 (\verb!ENOENT!) causing \verb!darcs! to+fail. To fix this, you will need to edit your \verb!~/.gnupg/gpg.conf!+file and comment out or remove the line that says:+\begin{verbatim}+use-agent+\end{verbatim}+If after commenting out or removing the \verb!use-agent! line in your+gpg configuration file you still get the same error, then you probably+have a modified GnuPG with use-agent as a hard-coded option. In that+case, you should change \verb!use-agent! to \verb!no-use-agent! to+disable it explicitly.++\paragraph{Setting up a sendable repository using procmail}+If you don't have root access on your machine, or perhaps simply don't want+to bother creating a separate user, you can set up a darcs repository using+procmail to filter your mail.  I will assume that you already use procmail+to filter your email.  If not, you will need to read up on it, or perhaps+should use a different method for routing the email to darcs.++To begin with, you must configure your repository so that a darcs send to+your repository will know where to send the email.  Do this by creating a+file in \verb!/path/to/your/repo/_darcs/prefs! called \verb!email!+containing your email address.  As a trick (to be explained below), we will+create the email address with ``darcs repo'' as your name, in an email+address of the form ``David Roundy $<$droundy@abridgegame.org$>$.''+\begin{verbatim}+% echo 'my darcs repo <user@host.com>' \+      > /path/to/your/repo/_darcs/prefs/email+\end{verbatim}++The next step is to set up a gnupg keyring containing the public keys of+people authorized to send to your repository.  Here I'll give a second way of+going about this (see above for the first).  This time I'll assume you+want to give me write access to your repository.  You can do this by:+\begin{verbatim}+gpg --no-default-keyring \+    --keyring /path/to/the/allowed_keys --recv-keys D3D5BCEC+\end{verbatim}+This works because ``D3D5BCEC'' is the ID of my gpg key, and I have+uploaded my key to the gpg keyservers.  Actually, this also requires that+you have configured gpg to access a valid keyserver.  You can, of course,+repeat this command for all keys you want to allow access to.++Finally, we add a few lines to your \verb!.procmailrc!:+\begin{verbatim}+:0+* ^TOmy darcs repo+|(umask 022; darcs apply --reply user@host.com \+    --repodir /path/to/your/repo --verify /path/to/the/allowed_keys)+\end{verbatim}+The purpose for the ``my darcs repo'' trick is partially to make it easier+to recognize patches sent to the repository, but is even more crucial to+avoid nasty bounce loops by making the \verb!--reply! option have an email+address that won't go back to the repository.  This means that unsigned+patches that are sent to your repository will be forwarded to your ordinary+email.++Like most mail-processing programs, Procmail by default sets a tight umask.+However, this will prevent the repository from remaining world-readable;+thus, the ``umask 022'' is required to relax the umask.+(Alternatively, you could set Procmail's global \verb!UMASK! variable+to a more suitable value.)++\paragraph{Checking if your e-mail patch was applied}++After sending a patch with \verb!darcs send!, you may not receive any feedback,+even if the patch is applied. You can confirm whether or not your patch was applied+to the remote repository by pointing \verb!darcs changes! at a remote repository:+\begin{verbatim}+darcs changes --last=10 --repo=http://darcs.net/+\end{verbatim}++That shows you the last 10 changes in the remote repository. You can adjust the options given+to \verb!changes! if a more advanced query is needed.++\section{Reducing disk space usage}+\label{disk-usage}++A Darcs repository contains the patches that Darcs uses to store+history, the working directory, and a \emph{pristine tree} (a copy of+the working directory files with no local modifications).  For large+repositories, this can add up to a fair amount of disk usage.++There are two techniques that can be used to reduce the amount of+space used by Darcs repositories: linking and using no pristine tree.+The former can be used on any repository; the latter is only suitable+in special circumstances, as it makes some operations much slower.++\subsection{Linking between repositories}++A number of filesystems support \emph{linking} files, sharing a+single file data between different directories.  Under some+circumstances, when repositories are very similar (typically because+they represent different branches of the same piece of software),+Darcs will use linking to avoid storing the same file multiple times.++Whenever you invoke \verb|darcs get| to copy a repository from a local+filesystem onto the same filesystem, Darcs will link patches whenever+possible.++In order to save time, \verb|darcs get| does not link pristine trees+even when individual files are identical.  Additionally, as you pull+patches into trees, patches will become unlinked.  This will result in+a lot of wasted space if two repositories have been living for a long+time but are similar.  In such a case, you should \emph{relink} files+between the two repositories.++Relinking is an asymmetric operation: you relink one repository (to+which you must have write access) to another repository, called the+\emph{sibling}.  This is done with \verb|darcs optimize --relink|, with+--the \verb|--sibling| flag specifying the sibling.+\begin{verbatim}+  $ cd /var/repos/darcs.net+  $ darcs optimize --relink --sibling /var/repos/darcs+\end{verbatim}+The \verb|--sibling| flag can be repeated multiple times, in which+case Darcs will try to find a file to link to in all of the siblings.+If a default repository is defined, Darcs will try, as a last resort,+to link against the default repository.++Additional space savings can be achieved by relinking files in the+pristine tree (see below) by using the \verb|--relink-pristine| flag.+However, doing this prevents Darcs from having precise timestamps on+the pristine files, which carries a moderate performance penalty.++\subsection{Alternate formats for the pristine tree}++By default, every Darcs repository contains a complete copy of the+\emph{pristine tree}, the working tree as it would be if there were no+local edits.  By avoiding the need to consult a possibly large number+of patches just to find out if a file is modified, the pristine tree+makes a lot of operations much faster than they would otherwise be.++Under some circumstances, keeping a whole pristine tree is not+desirable.  This is the case when preparing a repository to back up,+when publishing a repository on a public web server with limited+space, or when storing a repository on floppies or small USB keys.  In+such cases, it is possible to use a repository with no pristine tree.++Darcs automatically recognizes a repository with no pristine+tree.  In order to create such a tree, specify the+\verb|--no-pristine-tree| flag to \verb|darcs initialize| or+\verb|darcs get|.  There is currently no way to switch an existing+repository to use no pristine tree.++The support for \verb|--no-pristine-tree| repositories is fairly new,+and has not been extensively optimized yet.  Please let us know if you+use this functionality, and which operations you find are too slow.++\input{configuring_darcs.tex}++\input{best_practices.tex}++\chapter{Darcs commands}++\input{Darcs/Commands.lhs}++\begin{code}+assertions :: Control.Exception.Exception -> Maybe String+assertions (AssertionFailed s) = Just s+assertions _ = Nothing++execExceptionHandler :: ExecException -> IO a+execExceptionHandler (ExecException cmd args redirects reason) =+    do putStrLn $ "Failed to execute external command: " ++ unwords (cmd:args) ++ "\n"+                    ++ "Lowlevel error: " ++ reason ++ "\n"+                    ++ "Redirects: " ++ show redirects ++"\n"+       exitWith $ ExitFailure 3++main :: IO ()+main = with_atexit $ withSignalsHandled $+  flip catchDyn execExceptionHandler $+  handleJust assertions bug $ do+  argv <- getArgs;+  when (length argv < 1) $+       do print_version+          putStr $ usage command_control_list+          exitWith $ ExitFailure 2+\end{code}+\section{Options apart from darcs commands}+\begin{options}+--help, --overview+\end{options}+Calling darcs with just \verb|--help| as an argument gives a brief+summary of what commands are available.+The \verb|--overview| option gives a more technical summary of+what the commands actually \emph{do}.+\begin{code}+  when (length argv == 1 && (argv!!0 == "-h" || argv!!0 == "--help")) $+       command_command help [] []+  when (length argv == 1 && (argv!!0 == "--overview")) $+       command_command help [Verbose] []+\end{code}+\begin{options}+--version, --exact-version+\end{options}+Calling darcs with the flag \verb|--version| tells you the version of+darcs you are using.  Calling darcs with the flag \verb|--exact-version|+gives the precise version of darcs, even if that version doesn't correspond+to a released version number.  This is helpful with bug reports, especially+when running with a ``latest'' version of darcs.+\begin{code}+  when (length argv == 1 && (argv!!0 == "-v" || argv!!0 == "--version")) $+       do putStrLn darcs_version+          exitWith $ ExitSuccess+  when (length argv == 1 && (argv!!0 == "--exact-version")) $+       do putStrLn $ "darcs compiled on "++__DATE__++", at "++__TIME__+          putStrLn context+          exitWith $ ExitSuccess+\end{code}+\begin{options}+--commands+\end{options}+Similarly calling darcs with only \verb|--commands| gives a simple list+of available commands.  This latter arrangement is primarily intended for+the use of command-line autocompletion facilities, as are available in+bash.+\begin{code}+  when (length argv == 1 && argv!!0 == "--commands") $+       do here <- getCurrentDirectory+          is_valid <- sequence $ map+                      (\c-> withCurrentDirectory here $ (command_prereq c) [])+                      (extract_commands command_control_list)+          putStr $ unlines $ map (command_name . fst) $+                   filter (isRight.snd) $+                   zip (extract_commands command_control_list) is_valid+          putStrLn "--help"+          putStrLn "--version"+          putStrLn "--exact-version"+          putStrLn "--overview"+          exitWith $ ExitSuccess+  hSetBinaryMode stdin True+  hSetBinaryMode stdout True+  run_the_command (head argv) (tail argv) command_control_list where+    isRight (Right _) = True+    isRight _ = False+\end{code}++\section{Getting help}++\input{Darcs/Commands/Help.lhs}++\section{Creating repositories}++\input{Darcs/Commands/Init.lhs}++\input{Darcs/Commands/Get.lhs}++\input{Darcs/Commands/Put.lhs}++\section{Modifying the contents of a repository}++\input{Darcs/Commands/Add.lhs}++\input{Darcs/Commands/Remove.lhs}++\input{Darcs/Commands/Mv.lhs}++\input{Darcs/Commands/Replace.lhs}++\section{Working with changes}++\input{Darcs/Commands/Record.lhs}++\input{Darcs/Commands/Pull.lhs}++\input{Darcs/Commands/Push.lhs}++\input{Darcs/Commands/Send.lhs}++\input{Darcs/Commands/Apply.lhs}++\section{Seeing what you've done}++\input{Darcs/Commands/WhatsNew.lhs}++\input{Darcs/Commands/Changes.lhs}++\input{Darcs/Commands/Show.lhs}++\section{More advanced commands}++\input{Darcs/Commands/Tag.lhs}++\input{Darcs/Commands/SetPref.lhs}++\input{Darcs/Commands/Check.lhs}++\input{Darcs/Commands/Optimize.lhs}++\section{Undoing, redoing and running in circles}++\input{Darcs/Commands/AmendRecord.lhs}++\input{Darcs/Commands/Rollback.lhs}++\input{Darcs/Commands/Unrecord.lhs}++\input{Darcs/Commands/Revert.lhs}++\input{Darcs/Commands/Unrevert.lhs}++\section{Advanced examination of the repository}++\input{Darcs/Commands/Diff.lhs}++\input{Darcs/Commands/Annotate.lhs}++% Includes the show commands.+\input{Darcs/Commands/Show.lhs}++\section{Rarely needed and obscure commands}++\input{Darcs/Commands/Convert.lhs}++\input{Darcs/Commands/MarkConflicts.lhs}++\input{Darcs/Commands/Dist.lhs}++\input{Darcs/Commands/TrackDown.lhs}++\input{Darcs/Commands/Repair.lhs}++\appendix++\input{Darcs/Patch.lhs}++\input{Darcs/Repository/DarcsRepo.lhs}++\input{gpl.tex}++\end{document}++
+ src/darcs_print.pdf view

binary file changed (absent → 493279 bytes)

+ src/darcs_print.ps view
@@ -0,0 +1,12785 @@+%!PS-Adobe-2.0+%%Creator: dvips(k) 5.95b Copyright 2005 Radical Eye Software+%%Title: src/darcs_print.dvi+%%Pages: 120+%%PageOrder: Ascend+%%BoundingBox: 0 0 612 792+%%DocumentFonts: CMR17 CMTI12 CMR12 CMR10 CMBX12 CMBX10 CMSL10 CMTI10+%%+ CMTT10 CMR6 CMTT8 CMSY10 CMR7 CMR8 CMTT9 CMMI10 CMMI7 CMEX10 CMMI8+%%+ CMSY8 CMSY7 CMTI8 CMCSC10+%%DocumentPaperSizes: Letter+%%EndComments+%DVIPSWebPage: (www.radicaleye.com)+%DVIPSCommandLine: dvips -t letter -o src/darcs_print.ps+%+ src/darcs_print.dvi+%DVIPSParameters: dpi=600+%DVIPSSource:  TeX output 2008.04.23:1335+%%BeginProcSet: tex.pro 0 0+%!+/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S+N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72+mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0+0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{+landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize+mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[+matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round+exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{+statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]+N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin+/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array+/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2+array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N+df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A+definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get+}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}+B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr+1 add N}if}B/CharBuilder{save 3 1 roll S A/base get 2 index get S+/BitMaps get S get/Cd X pop/ctr 0 N Cdx 0 Cx Cy Ch sub Cx Cw add Cy+setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx sub Cy .1 sub]{Ci}imagemask+restore}B/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn+/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put+}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{+bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A+mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{+SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{+userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X+1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4+index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N+/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{+/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)+(LaserWriter 16/600)]{A length product length le{A length product exch 0+exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse+end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask+grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}+imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round+exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto+fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p+delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}+B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{+p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S+rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end++%%EndProcSet+%%BeginProcSet: texps.pro 0 0+%!+TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2+index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll+exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]FontType 0+ne{/Metrics exch def dict begin Encoding{exch dup type/integertype ne{+pop pop 1 sub dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get+div def}ifelse}forall Metrics/Metrics currentdict end def}{{1 index type+/nametype eq{exit}if exch pop}loop}ifelse[2 index currentdict end+definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{dup+sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1 roll+mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def dup[+exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}if}+forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}def+end++%%EndProcSet+%%BeginFont: CMCSC10+%!PS-AdobeFont-1.1: CMCSC10 1.0+%%CreationDate: 1991 Aug 18 17:46:49+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMCSC10) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMCSC10 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 34 /quotedblright put+dup 40 /parenleft put+dup 41 /parenright put+dup 44 /comma put+dup 45 /hyphen put+dup 46 /period put+dup 47 /slash put+dup 66 /B put+dup 67 /C put+dup 68 /D put+dup 69 /E put+dup 70 /F put+dup 71 /G put+dup 73 /I put+dup 76 /L put+dup 77 /M put+dup 78 /N put+dup 80 /P put+dup 83 /S put+dup 84 /T put+dup 85 /U put+dup 87 /W put+dup 92 /quotedblleft put+dup 97 /a put+dup 98 /b put+dup 99 /c put+dup 100 /d put+dup 101 /e put+dup 102 /f put+dup 103 /g put+dup 104 /h put+dup 105 /i put+dup 107 /k put+dup 108 /l put+dup 109 /m put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 113 /q put+dup 114 /r put+dup 115 /s put+dup 116 /t put+dup 117 /u put+dup 118 /v put+dup 119 /w put+dup 120 /x put+dup 121 /y put+readonly def+/FontBBox{14 -250 1077 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE+D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A30EB76029337+900ECFB1390CA5C0C3A04528044F266BA17BE487C79B94FAC6D6484684C5BFEA+87BCCC77D40AD11552035E95E3007126418ED49B68468B38A14E88E68A267B98+076F1C9769A5AFBC285E5B158EAC9F926F1D6C0B8F1D57D9C31D25AE27123518+9D2CD92E5689E0213089BD268DA5E47525CB8EABAA4B78A15AEA34705889AB3A+FFB8953B5B3482E52BFA0940630ADF8C0AC2177D907324299EE980E850F203CD+B627962F43D5A678C44243CDE97853BDC6AB45FD5C09AD274DAF89929F583CC9+CCC24BDFC68B92111055ABA5F26D2DC67C70906F71C2957701D65AE746A60C30+40E6CB24B97FCDAD0487AE38A201FBF0E41BABD2181981A71940F1E707F91E5D+C8CA50CB16D8702D188E56D014D92F76CE0B52ABDB9110E32438D2BBF3E6A40B+7B005F10BB437812CAC6ED2996F7606DC962C4FDE207FF322782C343DF44CEC5+FF06A55C630C20E9AE1B0D1C5673753C43BA0767D65D1B451CC6380D8BB3C4DC+81E8FD8AA79BE993218686F29D3CD925566DD587F541A0DA1B1CC3BCEA2E6C7D+5E1016F6917A871F1BBAD96AF9E867735017119A381FCF33EB2D3E1E7093FD90+CDB0CED4818CFD9E201A03430CEC713620BE0D3254158931FB657C6AD4B2482A+0E7D070D7497892E9E942DF58E88CAF0C8221BF36BF7C435BF2C683A4A2EF4CB+E85820A8AD3486155A40143011BA9D76297F46DEF69ECA4596D6E4CAABF84091+22A96A4BC78A8DD072FEB759A68A44BE1164638B6D952147EE3C628F9A022060+1D1941E73310943FA782532ABB1116532AD67AEFE0758C051241E301C7E13A98+6447EB0180BF6799814BEA4DC0F727D0A40B7BC3B1269CDE174453D6A3C4479C+146001CF717DE25AC1BE5AEA5F2F1C17719251C429D3AED19EFD3F97E98E887F+1CE00D98D1663C55CF1A9D0E0FF4BF70D17AD3B7A99DC71EC87E2EC7793CFEFE+2E2092D78A85561C3917D1EAD1495921C70E528D0B17B26FBA9F6F50AA659976+9A5621EFA26992042A2F4D209690E3E335115082332256C5022756536EBC0015+88CB192818F167DBED68E135E0A0B05A6AE1D059A28B20A6EFCD1FF5193B01BF+EFB7D26D152BC7B625F678948E1C2DB6AC126800611F1B4C0FDDAF18ECEC2E3E+C634C417D87F3E68404AF43A8C0880443E7F0CF9FFD23E51ACD64CD9C1D5F3FD+5ECA07965DD42D5A7179B119AC0A441CE857A47AE00F5AD59740FCA1FDD45272+9D8442897FBD07A39E678C7AF20B6B7D0D86961E17F5F3776855636DF5CB5928+E165A22B7A355A4639841CF49019173AF0E21B57906D0769DC85EBDC251F2802+2D20998BBE09EC712F4DEDEAA6FA40F30368F5F930B06E86469134769F41653D+63CDB976C91530598FEEB87457432DEC203A5A5D6C0E2BBDFACFCD8CAFE9541F+C6064D1D104191C273EE8CFC230FDC1555FCFDD74582FE1A53BEFE2371412613+7B0AE945B62D7F868B905ABB8FA5359473F0EA159C7984983EA3BC13A7C3299C+683D4F607745EE04512A87E608199E6FD3024ABE00687ADDDA915D17524DCCAA+84BB78F4F236391B12991433F8C1E682757ECFCC1AB1135429F8D49A560662A3+08C8FD6816AACD91F1A9F578A8D1B38A843FEB090E474BA8923263D0EEA79249+606A1CDF870859C8803E7394FF7D18D387B03F295C96CFE9AD7B9B6AFD227607+16AD12DCDC2D9402330C09528DFA18EAE53034024886B36CB3A56AC90427E52D+0729FEA7F359B424DE3B58569F2D1F8AF7A5368831C44E7C7D5CC60AB0DF2F4E+B7E2BBF1013855A4B65F009DEBD18C41F23C2017D64AF3E12D5608A5B9AD88D4+61FCA81D930DA8235838794EBC691A987A7F5BAA4E09C882BE726D17A2E9F1E2+DE6EFED0BEB79657E03B78CF967FCC340ADA7480A2957E205E40D2D77437E80C+BE092EE2DE8D8F1D04CF801A35125BFCB497490DA5D43CF7C60467C33BD1F864+4A06DAF3014D6BB30732E567F74CD8ED527D7E8045D143472F4C67359B697A9A+902BBB01EAAD9FF16712A7605C0903EC5A98C375116FE26BEBC166D8BDB1C0A7+4D1B5BBE96DCCA72E345DB884E382F4C02CBE7F111816EAD0A92285269D767F6+1CF634165FB1CCF9BE7C8AFD8DB8489D6658D08CEB3B6A87EDC1783486D1DE58+9A2B5F668B3FFA3090E92CCD056ED97626C3B7EAD0A1F231E4E63383A89EEB37+78D690E5730BE915AAE7EAAA7D7EB441EB2BA1F5EF10FD161C0CB41490D146D9+0593E690288111BCDC68D8B5A2313195D4E9B93EF880037BC985CD127B544E5E+7DBF148D5323CEB25601D51475B74ECA1F4FEBF5C286BFE6E418A14EFF66E509+4B8CA23A22888F0280E8F13542253B38FE00600A980EA5A3A42151193B90A0A7+E0D74DA2DC719906EE37AFF2A9432BF33E85CA05F4342A187F2901FE192599F5+AE81F7C531561300F78C4DC9CDB5B9691D8A16E72607EA159968912B8C196C82+BEE08B2BF17FE0E0AE5AEDF10CC7228863101CE467298A055A838ED6DD3547BF+B3665BEC0C8913953E121ECD13C68DA7924833D6ED47294D5E01B1241B8D82C7+2B3F074882153FEF4BE64A64DE95B1CDFCEBD3F9932CCD6450DC0CF10A14970F+6C0D7CE2328D03086E183FB3857FCB3C747958DDDC6F621493E77DB5D9FFD014+BCC90F8F8BFA4EAC97A7FC9FC2FA81222128E5FEC7E0BF4836380E90ED9F9A0D+94E38C5169CB6CA4CCCE244CA94807CEE2CE5A22F92FEBA891A6FB6DF421A5F6+5B7C212FD8DAD5D40E0797444DADE1940853106826D252C2939FD1FF3C39C4CD+11FA1671FE34CAF6B0E6EF0AB5A1F8CCE5CD2F3F11DBFDF48DFDD1A21EC039AF+2FBD9D74875AB3F846698362C00CEE0AED534C25889A4EBC307FA92864168E70+2CC82F18552924A0541DF23D8E29FA1EF1A0145263A4BD9968BD6A5DAB1B5F5E+50583A53206962305E78CFD7A14A07866AB946B52711E7D239AE7F0BD7EFA596+54F4873387DDB62785E294934E4219E707C82184D25B2CCC8473D34CF4D2A97F+1C13D7787D1BCCE89E251101DCD5C66C7FED6C1106B57CACF495A0492D252BB2+DF067D775FBB40D61D7B6D50D4055B8F8ED6C1AB53694B6EFE4BD72EEB490696+5AB4EBDE1A43333C3B1A14BE4FFBAB356925D693495BC1BC6CAD99ABC2C4490E+94CEC94DD66DC5A214D1B5E56B9244552E47C35B2442429AC0081733F56C85EF+5D9B537C1EDE169443D141E7080A2C95BC68731DA98EF0D0BDC3876FEEA0211F+C6F830F8B3522039EC2930EB0D3E2B28689332439126A62841D3A81AABDAE9CF+15990972B51608A6761861AE0DCBD2BC2B3E82F6D649902D71D7CE1BD8670904+272CDE13616251870F27F2ECED8E3D1CF1056389295576320EA66FCA683EFB8E+B4CF43F56868CCA4949B6B56751CA2487D018184AAB01ABC56F7878CAC407469+684F632EC32CC042A5D98004907607E049F5B8B9E6517F93CCE3E6E5A7DB91CD+DF0B89FC189F48918938B49F5A213EBB9AADD47F86B2BE58E0822B1D3E1C2204+9DB0636D782BAE6904E028645EAEF80BA7122C8237D0BF03B69E3BD160D9DCF3+20143B75FC4C95DAF808006419D753A40BB58AADA110976D9F0D68C6CDE58B98+9F2A3A92140A6B534F2E8DB550D72CA07B0149894541ABEA69582BE6FFDFBCC1+849DD3BDCE068118B31DFE511F552AAA186CD0647FE9EC039DD8354E699F3667+60541CD40C994B6DA9D9224B2DFEA5E779148CDBF6318A35C9D938EF652C0FF5+6698263E3B911FFB850612ECD43C2CEA40EF76337C3A513DB85A9028FD78C39C+D249447256452F89C902BEDFE91B2CB983D70DCDD905106D2BEAE1C0519721EA+E6E345206427256711B7946B70E82676C96E559E7FB11520DC3A86D9E709F8DE+781D3749D555D547F67E5F4519E77C87D03DD770F39990D5B83EBFDE14E2CF4F+13A4E00772588C430B4F75844EC30C760FA76D660A5C0F4B77AB390E33ABEBFE+F33FBCA3222F100F884E89D09627D7081EF0E2632070C739E1B29261AAD0814C+91173E58D245349468CBD88DA830F7E7AA1CB4B57FD30FA51E0526FE2AC57E33+579AE2D9B7F2EF9866D5F95B946E40392A7583CC6E11B6986213E53C1986EC58+6CB5DAE9020138693297A566889DF510EBB128C6C44A866AA5219197F7B0579D+F40B0CE2529481865CF72267C0ECE5B5FE854CB767E7A959D7D43C8E22634328+868D240C4E84EB7EE18D393FED850235CF8B6A0CCFA39652AB9936E07B71F1A5+E49DB9FB7B40C18526D119A25B2B12F9C5CD52E03A8E8C1345ED820C12AFBAF4+9AB0DCCC423AE8F84810F848E04F16F3490D1E8B59F66CDCF60C44D50844CC26+D3D3372559521B676258F2FA4C3DA09C092EBD3AA13223AFF77B6405C4368650+6E43CCB312471858DAB42DF8360A7C67CBB09521AFF87C5475BFD93D9845C5C1+857FDBAC5AF7A7132D90A353D45380D70B5B0BA4C79E74ADC4D9F52289FB65FD+5830B264FD2F17F775CFB0D39BF9E67F36949309AF7DF9A0ACBE081A1BA900A8+CB63B9057E0EA689D23594B373D2E84C43CC8D2568E4D8BDA04C025B44F085C5+615104E6B6137B3CA9CEDF94BD904A7D4F8B3FD421308E4396E58AAA86D7A3E2+CFC44C9666A26383828224BF5DE846D2AF06461D8CFC014341F457EFD47291E4+ECD032CB1E79D4687028AA4D8093175659041DE0067C66DC0E08E53795AA0B41+19BF1DCA560A5A6ABC584121626440851D741A52E696BC704193E3F6E4F704E4+A5A3B42212F49B2A6E8007D7D5D5669B777C6A70108448A0EABD6C4F0B15C0C6+B037C3AB95376F9BD2A4E4EC914CEB8FA5A880F4E8597868A271C968E786FACB+3495AFA34C78E00333EE8D961D98617249D5071143D7DBB553E42950A5728B05+128914F183F85415F3564E7C87C8931BDDA830787208F52E4F50178316A7115C+312BE56E229E30ABDB154B0745022A308CAFD98D96B9567786A525D6D768715C+478D849429A56E06D7131B377EDCA4BD644FE69B4EAFC1167D52056828F34B73+F0F851D1ACC9C43837BAF4D28D20BB37C33474CE63B507C46BCAA08A73867DA6+D1DCACE2B65BFC032C70078B232889633751748CD2044796FF4A48ED3F3535E9+63575691181FF1BA4DB126B365FA63A98BA10BED156523D305697C6DF8964DCA+E2E18F19CE60A7354BB9F910BD7F231788904C499AC72BBBCA9F288C70E6D685+519BEDE2AB488CE9F277FDB14EB7852FAE11F3725F027475FFA20477970CFE3E+D8C05EE53C0754ADB0C02AE0029FD3174B01DD296B7CBCB6FABDD4BFAA9D2F3F+2C79F91A7B68BA62027A9BAA4FA9E92F7309A8302C43DB6760A1D6489DBEF0C6+1463CC976728486C7B3814CD95BA1EE4CD8310040FB882BB91D81A179A9D4A40+F55BD2548FA46CBB7B8C632C395F41B7D613718707237C091DF823CEACC69E3B+5C8A6B0B88A4CC1286F97093021DB662841672E75110F93384E8550E8C235A70+FD0988E3F7731812C1F3043AC00396330CA77B5087B2D50BF58CC5218F6D27FE+80029CE22C93EB898BC38FDBAC68BF74B258834EF994422E79FA520A422A90E0+F1E407A873AFA7E31A940A5584F990D6902A376B4366A7CC6FD8F7ACEBAD8EAB+D0BEF2A8C972B3F822DD39BBE1ACEE0C33A9835524B1E60EAFA946499C573061+9F83EA7A2C12F51E272514DEED9E8B3E23E2D5E1FF04DD307B41583B789A96D7+483C6FBEB75A834A67CF9A511E086A565C9AF1BAC5B506BB7B0F54216485C031+1A7F0D884545EC3B5E11A02E01B511054DC613C2E48CC59676BD958FB9F7F273+9737D373C8130801207F3294D5CD66F07904C64EEABC98B5242A0AD0FD5D6547+742225DC8422D7CF8CF37918DB062B392199A98A9F726F910A516DC87CBA9D6C+F136B7AB89B8921B6EA451C8B3B64258AA15EAFD7F6C60BB7F72C6BAA1B7D644+1A853A259FF59D6F18E14B6DB9501DAD6B4AC7B5528B16231E9FCEE6F998AF6F+3AD666A373C9F97F928DB4A88A3EFA2546D457F6AFC16D738436B474D4D5AB9B+9D827796E5D1E0905DC611730AF67FFF8D1545C258B488A1C09FF9E1F5504A2B+B87317AD8D0577D9DD82C522FEC232A5DFE72D31B6079667ED484A5B4919E890+B6B0BAF46F09AE11ED45CE3DDE82D370B07BCA88F4C17790CC19BDC42D23ADBA+1996E1626ADC02D2A4B6DFD46273FA9574C9DD74C5410460FCC574D9915BBAEA+A4FAC2CF30636FC4564882530046467349DA213EFA0A71EFB7A64C0F63F18ED8+BE31549ECE0EDF006B298129CC7FA4F2665B95B85F8BAC7235A300486DA78D2C+6D7136C6995DEEAA1502D947523C60E42E8D804B087968991F367B51815EE8A7+818F6694CA39B0CCF9B119C07C0F7D3F2F04D10833020B756102FB8A54BA20BA+45FA19904D610FECB0A8C9E38B864D6AA315EF16AC7221BF2B7CE4D535CE4322+FF094C84185FF8E6AB47CF248822A9673FD6B963669B45E84417DB5DAE51856C+F451B7FB2F1AA1D820CD3885ACF09B5E3B725A40678D48529B3AF50606A944B9+ED32219420744796718F87A84768C24A6C10DE23E8535B758D2C8987CDFFD74F+C5F671F1F4908E6BF834B3A3411439E0DE3E96CE4A35C2A0285C4AC0D23F2957+80FE61B851AE0693B348542172F769123F70752048E39A581C9D96367955D0F7+515139ABA777F209B55547543035343239403CEE3978DF10B7D0A1FD11313715+73D26C40E87461849FA6F3C5FED40BE6ADA15D798C6536AEF9B243552F8E3D49+37D261F78BA80AA6A7BF20178935EFBD3EDB809CD33268C5C9C960EB7DB0E0AA+96AE516C8958476A7D8867A82EB91B0210FA1C152666A9FA4BACA0AA3E6AACBC+3FB35D93AB87C3AE61D984149AFFB8CD017AAC28CB5F31F781C0687F1D89C2FD+DB423587ADFDD2AF661AC2A416EE9FB3E13C6A2B1E447FAB328D7A80518D9869+3628B4717D8437C11F5F05BEE16F7B38249A503257F6B08349CD37F5C046142C+B9E63891FC1A472E276A054F4AEFA9EE029D004C73FFFE4AEFFC46CB137EEBA8+8F416C57BEAF1299F39F4C83E9DC3295C01B2ED645A25249ED217E711556A04B+4D72B040A9FC09ECEEA126D2BF9A9B30EABA9F7419D6E6457C4691F391404B11+401BC01AE7F577BE25837ADAD72424F0BB387400694684ECA46DFF83BC620CCC+77F80B82B170D68433093CCE32D872177D1EF303F8FD14B044F5C07105D96DB7+B91C6909F636639370CBD161F703DF89CFAD8CB4213F955F81408E60A1A686E6+725B850ACE79D3C7E6AC5DAD780A314A55EDE7FB3EC1FCC8F14C8933619E85CE+AD734540D620FEA63ADB1CC611C31A4858F97950E3CB6D793CA59C0EBC58FAD2+A6B8E70AB2A15E613A82CC7BE0135D81E5B4B29EFAE57749C74B50B779617813+92F8D2635FC94F18CFF60C23E943E7912B42C0F14B5F8BA132E59B948FCBABC8+026DA561D58979903FE3FAE434C355592A0674501E1C316C623EF89A86A0FF7E+B513D6CF52B06554903E11EE9057BBBDA07C076FACCC124C501D918FF95C50D1+D9B06F27818968507E41F380ED7DEEC2446AAA85B617EA047A5F303237869F15+FA3FB6BD9E65B0F535B685124B8F2D124397A6814CB8DC101B4C8D374EB88C70+3AA78F370915F793EC9F5CE78202B643427F8640A21D50B446B90A66831A3AA1+0CB73CF7F3E1D8C2456824994D9F1960991B12EB51CC44227BE830CC6A315496+F500EC97E8C0CFC3887646D45707BD57B113D859A04E7F01459294E2CC0F1F99+9E2502CE1A8A9700E1AAADB36A55E319FA56AEB958F39BFF9419D3CC2348BA26+E694EF81E198EA319D69B78B5C305A2F0B147BBE3875A863F05EC17223290B8C+304A877A215EEE6C88CB2B6FFF2B4097F9BCADD7C11F92F7A7B719FFAFFEEC53+74487AAABF9966BE628872F0EF0DC9BAB11831E56BAF57DFDDE90B70E03E6448+A53043C5A93FA47F01B073B916B380E0CB0A21D1153BBDD36F5A59E5530AB302+126E4CDCA4C1DD6AED7E70C2AD5345842EF8F48324BEC4FBE5AF2DBC0C56BD93+98EE20C50C8081AEC01F8B8C9DAA03C4CC9820650B79CF1E12C0516F24632B13+958AC9DAFEAB3DD63B3CE7D3D8DAD7BABE2E8CBDCDE306F175EFB586CF6D63EC+6286148D8FBE9A7F87AF49D492BA806580B643CC2C2685FC1CAC2FACFD1CFE68+9DDFC8E5F7261447BD3384AFEDA8D233A52DDBF677036D0FBD0C238777CDC596+B69DDC6170E0EF2C51D60CA27F434830F4DF1B3C81FE8CCA758EF8EE67FCA85E+2E75E924FBCFE5EEFB5B255792E258C29292DF65C1DA1E4E0F490158EA092CD2+C88BE1AFA494A15F859E72C7F18D9B4D4983119D50CDA31511FE1C7733A03E00+AC8D58DBB2B02EC0B09EC6F9408E71576F0A8B91981C9DFCC611A3FF619DB4EF+FE96EAF2CD1DBAEC5544BB3DA1371001AE66BD3F9830E62B8736A1A0AACF1E48+0C601D164ADCF74C0A3FBD90BF1BB017D276E27D6D641187756FB8EB4FBF562C+6DBB4AC7AF5A225C025BF7680C5988D2BB016C790DAF4AAC43EBC25D19157C60+B40CF222159DBE36229949CB0EA311EAFFDCD5322622C5C6C67482E5125C6C28+A00CFFEC3CAB1A0837ED67FB6BC289C19F294D98B65AF181E9CA34777C03F48E+CBB9B805FA75936F5A821F80A6F08D727FCB3EDE7E2A7462BA0090400B746571+4BC10558BBA4C1D8D55C43419B5AD304237641F8D4FE3090CD5875AED5770A69+A71473ECFF4DD706C62E7AC0A86A4D053245DF26AB5F681AA7F0C3223A08270E+E28F5DA6C3817F773611ACB111AB6745BFF1EEFE81E74E3CE9D0019A3ABDAF5A+15D1B3D6E811CA4DC0F4FFA1FF9F11B7A86AE3E8DB557C4ED81C9774A0592D62+30A8803FEBB6A9C061C72B16151E2142E6F73B7AEF1B02E75A5C503C618AB0D5+6BE42D318846D9B1CF004ED910BAEC0B8623DB3BB97399F5C90BAE7E13CF03C0+4A8780D86D072989225EB4A4C2960AAB403A486E56AA89DC62AF888B27A5F03B+B09894843DE6B4704C517A4EFF72020DBA9F8603713A6D2D22147BDEA5E1629B+BF1D3A3A4CE0D1A50093FD6488679DE6B4F41CFF3FC1CD7D13447AFD2C57A1D9+315F6DE3DBFF92A9C441BABC91316DBBA5B5FEDF76EFBB45280B8DDA30E30340+2D13BDA6A4AE549D1033DB6CAD96D45D0E3F9E0D06676C6622756FF425E961E9+984C070C2775C855BF18C7972ADB93743C6AE98F7104AC46D52FC198561D499A+7F8680C45827649747105549372E20950D59226E326302C99F812343D7E73963+33F41132AD4029E5D924BD198E440EB3969F202C8B4A112AE1E84F74FB7920D0+D760F1CD5A2FE692B739FAD6249E5542C0CC0144186600047F58260015ED02EE+8135A7114446A18AC25C5032789AC35D2DCB558F1258EE280D28A05CD937E0F0+D03321369E8AE054ED0727B4D0C7E444C8D2F52425A11004D9A03EA2CFC2A2A8+5543BFE17D4135CB3687E99C8A078D6CC9EB6F75189F4D5210EDA3DC96E609A8+F111B49A61AFBDB94536029C788789456B026CEEFD676994FEC9E09F0E649C86+6961FEE46BEA05EDCDCA778042D2776F97625592E8D791411BA30402E36E136C+77F8AC85069A48EBB768FFDF62DB8907451B242BCEADAEB0BE1EFE10AF8594B6+BDFD707EAEB8A003CC6BD6DBA58CF4C5635795C5253741D535E9A01EB77221E2+273C1E6F773D0BF441E724BEFD775CB1ED2F9F39AF825166D2352A667CAC9157+8FC006D9180146DB11CFEDB1EA2BF341A77150E3311E63960BA8C0E6169CC361+10E58B4CA8074C8E42CC64A89BBC22A999A4A63C93B843BDC4E6DA2C01255843+37A3CB78045F61AC8D129B0A624A965B8A25AF664411792BC173FC15F6E9AF8B+A77526C9CF977280CC7619318ACEBE6028AA6F814E286D2A1DBF56CCF7BFE281+8E019F4EAF0E4C77EDB211E6631317149728AF9D3FA56081AC80DF82A89F16AB+D80AA999C07AAE26F8981184859F5E5B894608EEFA8AD8D0C48BB154A351B792+E053AFB21C8B4BF4ACB8272EA17933E93F45510A72C6362474F09E3A79CC697A+A02F447C716C8AFC67AE851E56B5964D2EFF1B39C50CAD5B049BE83FCD005FB5+EDB1EFF8C3C2B8D9873D206A8D7659175482947F020FF55C0A9B0D72F9AB691B+8D34701B101D53EF4BEF01F1F8D1038F7743770CF6F47F14084FF73E969C99AA+C6C4993410A001EF348E76FE40CFBA5A0CBAF965D06CCE6115C051F8E3A384AA+E0B2C0024BAB2C9046A9631721207D19154E27FC0CB676321629F0221FBB120F+3AD8C9A458342AB9C2ADA767CDAB863EFCBF66D6C1ABDC0CE751B2C192D80069+8D372B364FDEC1B654AB42DEC74452440539E5F659B703F6C197F3700B2057C9+80C8FADF934F94D46EFB88003A8C194234217829556FAF698560D8378EDDE244+6F902C7EABDEE176D86C1924A6510E502ADF749FEC0888E6C96889F0C38F6992+EA310959F698137399EE43ED74BBC5F75DF3CEA1AAB9ED2D376BC55494C8C59C+69A370CA402518C8ACCC2BC07131D24376E078CF751846161F42AC22185D0181+341D791EE58DA4A4397B4B46FB112CCB2B51187B72B23C5E5FE4E57D3955F335+9A7C86000F267133C7CEF17890D1080FDA3430E122E1C201ACDF24D91B645031+F76B504B65BF2335054F2F58D8929984AAC2D756DEA4865446C301BA2A52B153+3CD53847C33A178A072F8DC5758472E37A40C2A6A12E8C7B005D8F178D9CFC73+07286751CC96A9500773AFB1C0B42CA2106E43D91B9FBDC3F4FF2E77530CF76C+EFFE152ECD877CC5A2547612019DC06C0A9CA45AEA6C38A7A1EFF57670C636FD+6443052C7B7E0F1EC5FFEB243D1A002B1D50DC1A197678DE40FE7C1D4BEBFF58+9B3C4C1BF42F153B6B63C5439CC55D01253C6FDDD3DE36A2D2374336C409F6DA+090AF57564AC7BE5E19E3FAB98FCDC24AA78997BF503C51CFBE9FCF30411C3E7+77C08B3E51048217E0A7B4B7A0E393ADECADCB5A639A76EE1F423C36B6C6B284+04E28D3800CC53D11FD1F3BB629A06FDBCD2368DF301BE7866B8F749A1F87F1F+49D1F11D25F25660C6EB13FBAF9CDE4A66D1B23344CB9D7C1A3FAC9330B5F698+32979313A4DE5CD6718B8C398B5E5477D9E7F56DAB81B4D30EF39FD20888DA34+CE58A5DA8117336E1B48F4E9720B098DE464AE3FCC34B1F4E3DA9B50267AEA34+8613CB883F0BE722DD31AFD2AD2166464436669ABCFAB02FB8205F9885A834CF+2C7985E1CB7264743115F0E2EB269FAA7125152C25038601F64F29AC920B8F94+AB6B3614D00E11539F2EDFE860908A5FC1F45EC2DDFF131EB9EB03006A422870+0743FEB52FCC7EF769550AD325C84B42721C5832BE11E2C72F655F7EAF4F2389+FD57478F5B80FD99AB7864F176DAD89D1026BF28704E8F352D909DF8526D451C+396C6829C76655856C45B9685E531603A865C5D805E39063D2B472AFF493AB49+FA9688A2440CA114B248ADC16E049DD76D824142E047423CAC2CCF24D7155211+8E+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMTI8+%!PS-AdobeFont-1.1: CMTI8 1.0+%%CreationDate: 1991 Aug 18 21:07:42+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMTI8) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -14.04 def+/isFixedPitch false def+end readonly def+/FontName /CMTI8 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 97 /a put+dup 99 /c put+dup 110 /n put+readonly def+/FontBBox{-35 -250 1190 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE+D919C2DDD26BDC0D99398B9F4D03D6A8F05B47AF95EF28A9C561DBDC98C47CF5+525003F3DAD7933EB57E7DB1462E9D906F6D8F5BF740206C1EC5F36E00AAFF68+F3EF6F3A2540E5F9564D1C215BC1E7E69C7D04DA5DB1CF195613C9CBF4BAA360+84AEF3E10E24877FBE36AD731DC97305BDE6DB1F934909FAF60B8E28561FBC57+0F5B6225425BFDE8F0C71CD4507B82FF803E9A301397975E38A259DE1E1B4FC0+06BB1DC2D45B987A2268A77CE8DC025CB0D1B39788BBEE149103950650171C94+5FED1063050A90BD38605BD9365D1C2AE42A7DA3DDB9A263FE10BD487F63D908+D4F02758BD9D7BE53E6353A25BEFA29E42B50C1D078A8B3A746EEDB381CCE36C+93FC4BD1A8D1D6ACD0D355E948CFE397B74D243EB51597D251D0BAE6884D70E8+FEE119462E1939A9783414DF59EEA5FF1529F13869D1FF0A44935C5198CC5DAA+E1FD2A17AEEBF4974052D06734A409E26C457C06700C55896C90BB33E044A737+46590D9FA242819B9527FD59818D8829D4EB2D26A34CC05A2CC063E66F2DF193+8E4F9670014BC243180E45B51DDB05AD1E6A7F619EE1CE09CFC1A4F02CB7270E+4482FEDF673EDED38EF3173C475C34BFB3F6623C5E942A7797FEDDD0EF1D54E9+1D90D7076C0A9687E334907C22F2E7C603388D8D626B0E5A62B7543DCBB575D7+9A6BE1528EC9BC18570001092524E4FBB02F3B29293BCB4F0EF14A2DD9DB22A5+BB33455799E8120D2A4862424AA4A382972E2845E042506FC8F6E201D11DD0F2+09FAD8DC29C3E12B66293ACBFB13FA0F26238981F2CD52B47A8CDE6DF5CDFAAF+3113E1A6366B806EABA9C34E5D41167CD10D7B639021FB4CFDAE28CE72A93F3C+E8929A4EDAAEC294405C3213CD7849EA7E008DE244EEE07398249D78BE4FE639+692A869E5E353FCA3A59DC18312B695AC26541862807EA8F9C7E723A5FB0CCC0+7C60CCD9EB9016B2A36E5C08857119EAD2C94AAF1DEEC8182C72F3C5E2B36755+D704F61AF1CAE6080032CEC8B1EAAF632D5ACC2480D67860894778CAB509D0E7+37C346F18ED99FC1984A71D6F28DE1AFFC7DFFB2F3BC704976A5C365B972F7D5+449273161E7EBA647C59F909BCFB2CC64FC4508864902DD3626F1B72E2B1CE74+7628F5181C3926868D5F59E761A6C15090B25FEF5314C5CF2820A166E2BCDA5A+486CD26DC28A0C569B60ED7F6695E6C749E31A962F15C3353E1C176C5C4FD5B2+7812F6EAA341AA8E92F8EA30CD00A5F861F56BF0A6CB5C4051B7416D4C6E7091+1CDB6C20707D3C739D8174FEFA981C53DE331E1A802A33F4CE29E74D5474AB95+40658ED1B6C006AC7F998ADDC16E48C54AF5A4087C9CA4E7751D5EBB5B5B68EC+E72D79F4F82828E87FCA21204B23AFE0BEA2A119474E035C260AFB0E14FF8323+38397785F469EE597526B6296B3807EF4041E2F2B8F5E2F9050F408093475A26+494F08B7BB22A58DB14E97242F00635BB54D2A4CC4102D157A23C8F6DB1E0177+2EBED2B7532CC94F08313DD9DC9E165DFB966E036B89F6A13A614EFAAB973A8F+9CA439BECA31EA3D9E707DA4246DB1A05F7696AC04D217FCAF8CA9E46190CE1A+914C78BD07B20452FE015288AB1B65D01BE972CDA8FD0616072941B89E9CB33A+A8B0EC22F096540C73A75AD3D2001C8DD2BE0B856B7C5CFFDE16670ED6665A52+45E6B38962594A32D3CEC79149697BAB2D5F894C19989943EEA1E13BFC3438B0+B404399EDCA76CFB5272F532BEB68872C26E4F78B33A2A5829BD4132D09F40EB+E16256A6347901D02CE66ABC6F6689791E3CA18EFB09E3FA061C528F00A29762+35484880FA04B2715ACF5AC4BE69378731B25BD157F52056F11B682AA4349D26+378BAD90DADAE522+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMSY7+%!PS-AdobeFont-1.1: CMSY7 1.0+%%CreationDate: 1991 Aug 15 07:21:52+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMSY7) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -14.035 def+/isFixedPitch false def+end readonly def+/FontName /CMSY7 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 0 /minus put+dup 48 /prime put+readonly def+/FontBBox{-15 -951 1252 782}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052F09F9C8ADE9D907C058B87E9B6964+7D53359E51216774A4EAA1E2B58EC3176BD1184A633B951372B4198D4E8C5EF4+A213ACB58AA0A658908035BF2ED8531779838A960DFE2B27EA49C37156989C85+E21B3ABF72E39A89232CD9F4237FC80C9E64E8425AA3BEF7DED60B122A52922A+221A37D9A807DD01161779DDE7D251491EBF65A98C9FE2B1CF8D725A70281949+8F4AFFE638BBA6B12386C7F32BA350D62EA218D5B24EE612C2C20F43CD3BFD0D+F02B185B692D7B27BEC7290EEFDCF92F95DDEB507068DE0B0B0351E3ECB8E443+E611BE0A41A1F8C89C3BC16B352C3443AB6F665EAC5E0CC4229DECFC58E15765+424C919C273E7FA240BE7B2E951AB789D127625BBCB7033E005050EB2E12B1C8+E5F3AD1F44A71957AD2CC53D917BFD09235601155886EE36D0C3DD6E7AA2EF9C+C402C77FF1549E609A711FC3C211E64E8F263D60A57E9F2B47E3480B978AAF63+868AEA25DA3D5413467B76D2F02F8097D2841FE9D089F27B314C2B7095381853+3E28E2A3EA5E789DA4343DB3BE83B18FE9D7725C3A96CFD8038B3518C10A68BC+9A67AF6D30543F6C7CBF40C7875E5E2AE8A0AA5E69E169CDDEB9958F11724338+CFDE66C32301830F03E713231FAFFACB9DBF58438D5EEB82A848BDD41ADE36B8+706776A8BA69BDFFE475BEF2DC4132506CEB0A9C86E3C6A84C126FF4962ABC81+44201BAD8034020B73C306926E892A27C84DFD6474F2BB7A94C82EF5EEB908F4+85B4AF889342EA7177DF14881FF6228281B538E90CE91BF934B3A0E18FD8933E+89B7EF32ED04E2E621769276A9498B6E4EAE691E08AF3DA827C893808047302C+6030A0B13D1E31861221D202AFD5DDBC81883AF4676F0921F3AB6E2006CA8923+BF54B19FC3764A233EDC6C2A7883F678061E11A7080A56B0AE2D4F01F1E84689+98+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMSY8+%!PS-AdobeFont-1.1: CMSY8 1.0+%%CreationDate: 1991 Aug 15 07:22:10+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMSY8) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -14.035 def+/isFixedPitch false def+end readonly def+/FontName /CMSY8 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 33 /arrowright put+dup 59 /emptyset put+dup 110 /backslash put+readonly def+/FontBBox{-30 -955 1185 779}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052F09F9C8ADE9D907C058B87E9B6964+7D53359E51216774A4EAA1E2B58EC3176BD1184A633B951372B4198D4E8C5EF4+A213ACB58AA0A658908035BF2ED8531779838A960DFE2B27EA49C37156989C85+E21B3ABF72E39A89232CD9F4237FC80C9E64E8425AA3BEF7DED60B122A52922A+221A37D9A807DD01161779DDE7D5FC1B2109839E5B52DFBB2A7C1B5D8E7E8AA0+5B10EA43D6A8ED61AF5B23D49920D8F79DAB6A59062134D84AC0100187A6CD1F+80F5DDD9D222ACB1C23326A7656A635C4A241CCD32CBFDF8363206B8AA36E107+1477F5496111E055C7491002AFF272E46ECC46422F0380D093284870022523FB+DA1716CC4F2E2CCAD5F173FCBE6EDDB874AD255CD5E5C0F86214393FCB5F5C20+9C3C2BB5886E36FC3CCC21483C3AC193485A46E9D22BD7201894E4D45ADD9BF1+CC5CF6A5010B5654AC0BE0DA903DB563B13840BA3015F72E51E3BC80156388BA+F83C7D393392BCBC227771CDCB976E933025375FFCDD9E2FD073678A57A333F9+6BDA68191279495C97701D1209E0C7735348B6FB00A5D07EC2A85F9B932CBFAE+08FC16C942504C640013B2ADD8083D02E9336F91F93CD88EE4982DE0A23D77DF+5E36753DC1569410E787652766EFA43E49576F99533F597754A6F0D59E986322+861FC20FE63210E8B5197CF82D1EA06094B71EAA10EBD05F80323C497E83C3B7+D5C7ADB0D76013773E3B8414089F6126A439B775D2B1AA3C4412F64F4A2E19C7+1AB864FE3F2A6FCA6BDEF9ADD8F3F263682D2A00709E791D1BAB7C1E2F32CB6C+D911876E59A9076812B5DAFBC5444E1B24005F0A8215DBFD5D120A3436DEF555+B3187072ECFC9EC7DE097DB1A815BE21C3B78C11378E3DE20D4982000D1663CA+1542ABCAF6E4360D98EDD37A37CC9D3AF180FB9434B55D002FBF4F633A8FB55E+FFE378D5C97E62A34AFAA83B1F8CB3E80406C89CB341DF87B89DA028297A2ACB+D02C3A06C7251BC6917C4C63B36B7990968C221194FDB5C394D9089975F2B5BC+628E62AA31BB0D7A5647868D0FF627FDCE62804A651CC5BDD8B1CC37B491B731+C8667581E18336C9D33D3DFED8F623502DF849381DDB9DD65442B3B98BD750AA+1D91F12C07A434B8CBCB83A801E7B11E120CA4839A43DD24E0957E94FD023AD7+C8047146872EAC30569D6E4F267F0C31E34FD87F2EFEF3F68FA1FD5C5A7CD91C+DF0B800ECB3E0E18E365E221D99D7B70EF7F1393F426A9B62F428411361BD2AA+4F95157512BB75B3361E980AB1EF9E150E9E171462845B1DFC45C12F5431B69C+11C21B913B6C4E85D96017BAB6985091CBAE95C2E7B9DCA37C27843F8043B1A2+403E946F3DFD26C87CB689525FC50E21B855E652A09D25269AFF324FAFE7A3ED+16A1E7+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMMI8+%!PS-AdobeFont-1.1: CMMI8 1.100+%%CreationDate: 1996 Jul 23 07:53:54+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.100) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMMI8) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -14.04 def+/isFixedPitch false def+end readonly def+/FontName /CMMI8 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 83 /S put+dup 95 /slurabove put+readonly def+/FontBBox{-24 -250 1110 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE+D919C2DDD26BDC0D99398B9F4D03D6A8F05B47AF95EF28A9C561DBDC98C47CF5+5250011D19E9366EB6FD153D3A100CAA6212E3D5D93990737F8D326D347B7EDC+4391C9DF440285B8FC159D0E98D4258FC57892DDF753642CD526A96ACEDA4120+788F22B1D09F149794E66DD1AC2C2B3BC6FEC59D626F427CD5AE9C54C7F78F62+C36F49B3C2E5E62AFB56DCEE87445A12A942C14AE618D1FE1B11A9CF9FAA1F32+617B598CE5058715EF3051E228F72F651040AD99A741F247C68007E68C84E9D1+D0BF99AA5D777D88A7D3CED2EA67F4AE61E8BC0495E7DA382E82DDB2B009DD63+532C74E3BE5EC555A014BCBB6AB31B8286D7712E0E926F8696830672B8214E9B+5D0740C16ADF0AFD47C4938F373575C6CA91E46D88DE24E682DEC44B57EA8AF8+4E57D45646073250D82C4B50CBBB0B369932618301F3D4186277103B53B3C9E6+DB42D6B30115F67B9D078220D5752644930643BDF9FACF684EBE13E39B65055E+B1BD054C324962025EC79E1D155936FE32D9F2224353F2A46C3558EF216F6BB2+A304BAF752BEEC36C4440B556AEFECF454BA7CBBA7537BCB10EBC21047333A89+8936419D857CD9F59EBA20B0A3D9BA4A0D3395336B4CDA4BA6451B6E4D1370FA+D9BDABB7F271BC1C6C48D9DF1E5A6FAE788F5609DE3C48D47A67097C547D9817+AD3A7CCE2B771843D69F860DA4059A71494281C0AD8D4BAB3F67BB6739723C04+AE05F9E35B2B2CB9C7874C114F57A185C8563C0DCCA93F8096384D71A2994748+A3C7C8B8AF54961A8838AD279441D9A5EB6C1FE26C98BD025F353124DA68A827+AE2AF8D25CA48031C242AA433EEEBB8ABA4B96821786C38BACB5F58C3D5DA011+85B385124DFAE11BA4AB27032F02AB84277DB8B54826F1D921E540A5F0E50D81+C0D6D39CF4D929C84FF5B21A1D135B8EA12B31829F9CB241CB4BE00DF2B03D27+1DA8EDE6F3E97834C3A4EE452F9C775581F8D8229290C431C77C389820E3C647+A25F07EC8730E151BF55EC58BCB72898C732959CFFC5AA9779D7390D43F22EF7+E5D1856543ED8C2ED4ACAFF76F88F3BE2C1DD787D9B8C8DCDD8D629FD10C5667+5C007EBEA6252A4EBF307301C6415DAD607B1B046CBCFC5D6857DCEF5C320404+64D1EB0C42590FFB8745E36E6E765A7DE9A4A258691CD974CA8FA983D86C9B93+FD8A0EB3D94361565B3480C3BA645DA61CCF94B0B034D26172C031E1B03D2998+051F117C44A3EB86C9BFEDCA7A8432249DF546F7B98394C233E75AE9F1DE58B2+2A272E60CE58F35180E67E0CC5FC6CE167B999508902B96D0AB9F119DCC1F65C+9255C47FB329D58C80BF3BB294A914B0F9092D7262846965EE9902BFD1037A10+A799205AB8B97E297203E4B9B21FBCF1740F832D5A5A13A01CA5BB20386BED15+2AE779C7804D579999E6137275CA98EBE65B9EC9E87458374E9ED7F08EA9E9BE+4E5F421F358EBE0D52B648C7EE9C888677D345377463624A7199941AF0F7806D+336C6CCE6B991F5C778AB119400453AECAF9C60AF3544D2F74938FB2BDA52602+D1693D93FF4BF44DFFD5B2ED04F22D23804CB869CA04480363D6EF55C905D384+CB11A28F8555F2641801E97E84355979CB41EE876C9845+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMEX10+%!PS-AdobeFont-1.1: CMEX10 1.00+%%CreationDate: 1992 Jul 23 21:22:48+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.00) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMEX10) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMEX10 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 83 /uniontext put+dup 84 /intersectiontext put+readonly def+/FontBBox{-24 -2960 1454 772}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5CF5B8CAC6A7BEB5D02276E511FFAF2AE11910+DE076F24311D94D07CACC323F360887F1EA11BDDA7927FF3325986FDB0ABDFC8+8E4B40E7988921D551EC0867EBCA44C05657F0DC913E7B3004A5F3E1337B6987+FEBC45F989C8DC6DC0AD577E903F05D0D54208A0AE7F28C734F130C133B48422+BED48639A2B74E4C08F2E710E24A99F347E0F4394CE64EACB549576E89044E52+EABE595BC964156D9D8C2BAB0F49664E951D7C1A3D1789C47F03C7051A63D5E8+DF04FAAC47351E82CAE0794AA9692C6452688A74A7A6A7AD09B8A9783C235EC1+EA2156261B8FB331827145DE315B6EC1B3D8B67B3323F761EAF4C223BB214C4C+6B062D1B281F5041D068319F4911058376D8EFBA59884BA3318C5BC95684F281+E0591BC0D1B2A4592A137FF301610019B8AC46AE6E48BC091E888E4487688350+E9AD5074EE4848271CE4ACC38D8CBC8F3DB32813DDD5B341AF9A6601281ABA38+4A978B98483A63FCC458D0E3BCE6FD830E7E09B0DB987A6B63B74638FC9F21A5+8C68479E1A85225670D79CDDE5AC0B77F5A994CA700B5F0FF1F97FC63EFDE023+8135F04A9D20C31998B12AE06676C362141AAAA395CDEF0A49E0141D335965F2+FB4198499799CECCC8AA5D255264784CD30A3E8295888EFBC2060ADDD7BAC45A+EEEECDFF7A47A88E69D84C9E572616C1AC69A34B5F0D0DE8EE4EDF9F4ADE0387+680924D8D5B73EF04EAD7F45977CA8AD73D4DD45DE1966A3B8251C0386164C35+5880DD2609C80E96D1AB861C9259748E98F6711D4E241A269ED51FF328344664+3AF9F18DCE671611DB2F5D3EA77EE734D2BED623F973E6840B8DAD1E2C3C2666+DD4DD1C1C9C622FAEAB9D3E54476B49A2A026565F10A93E741988A380B96665B+B74033E6AC08E135060F5C07D6D0892E1FE6F3AFE978594C5332910C65F7EF04+AA939F3FB69F10221D713AB2795CF42F8748AC13870F1E3B005F79970EBEBD1C+B210EDF48092DEF09AB5AE821357D7539D10E7288E82BA15D9BCE0DA0B6BACB2+68BFE76B48F42BE179920E3B13EAAA84FFF7768656AA270C2A25FABCAD83F220+84246F260D0F8A671B8F595E0BD0720091146FB0792470276697A16305013BF5+03DB878C84D25BE6A0711ECBB0080F70360F54F56BA6F13D1BE6E3E729AF7E9C+289B4A664DD52DC1AEE42DD410008E08A56E6B4E310F32A71EA68184106DD712+68472DCA17B73F3ACF7855C89CC3048E2510AE462E8CE99E08B18AA94598696C+52446F769DB39CA52F02B47F70DB684E982C93F27EA160536B7026C264D07A3E+69DA9D591FCB3A6F0C3578CB580153AC9A7A8B56552BEEF055F7F620F26635EA+0A654AFE8508639728184D19408E74061FC0A1FEDDEF9C288F1EB414EE8375C3+DC85C80EA85D719A13CC4A2C341822AA0C+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMMI7+%!PS-AdobeFont-1.1: CMMI7 1.100+%%CreationDate: 1996 Jul 23 07:53:53+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.100) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMMI7) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -14.04 def+/isFixedPitch false def+end readonly def+/FontName /CMMI7 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 99 /c put+dup 108 /l put+dup 112 /p put+readonly def+/FontBBox{0 -250 1171 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE+D919C2DDD26BDC0D99398B9F4D03D77639DF1232A4D6233A9CAF69B151DFD33F+C0962EAC6E3EBFB8AD256A3C654EAAF9A50C51BC6FA90B61B60401C235AFAB7B+B078D20B4B8A6D7F0300CF694E6956FF9C29C84FCC5C9E8890AA56B1BC60E868+DA8488AC4435E6B5CE34EA88E904D5C978514D7E476BF8971D419363125D4811+4D886EDDDCDDA8A6B0FDA5CF0603EA9FA5D4393BEBB26E1AB11C2D74FFA6FEE3+FAFBC6F05B801C1C3276B11080F5023902B56593F3F6B1F37997038F36B9E3AB+76C2E97E1F492D27A8E99F3E947A47166D0D0D063E4E6A9B535DC9F1BED129C5+123775D5D68787A58C93009FD5DA55B19511B95168C83429BD2D878207C39770+012318EA7AA39900C97B9D3859E3D0B04750B8390BF1F1BC29DC22BCAD50ECC6+A3C633D0937A59E859E5185AF9F56704708D5F1C50F78F43DFAC43C4E7DC9413+44CEFE43279AFD3C167C942889A352F2FF806C2FF8B3EB4908D50778AA58CFFC+4D1B14597A06A994ED8414BBE8B26E74D49F6CF54176B7297CDA112A69518050+01337CBA5478EB984CDD22020DAED9CA8311C33FBCC84177F5CE870E709FC608+D28B3A7208EFF72988C136142CE79B4E9C7B3FE588E9824ABC6F04D141E589B3+914A73A42801305439862414F893D5B6C327A7EE2730DEDE6A1597B09C258F05+261BC634F64C9F8477CD51634BA648FC70F659C90DC042C0D6B68CD1DF36D615+24F362B85A58D65A8E6DFD583EF9A79A428F2390A0B5398EEB78F4B5A89D9AD2+A517E0361749554ABD6547072398FFDD863E40501C316F28FDDF8B550FF8D663+9843D0BEA42289F85BD844891DB42EC7C51229D33EE7E83B1290404C799B8E8C+889787CDC7AA8BEF7021B3C18A0A61A68CCEA80153A2E0D2CE57F7AC2679BFBA+A3AB2339F6F346902AA97E0E9DB69A5AF8866C0BDD446CF4C05FC407AE4247EC+1CDFCEDC8918342AAF8FD62832FB5AE27584547CE795B34CD5002EA00C5347F8+20C07629B8E0E0B9D9A23798366ED20EEC38A093ECB42306EEA6D36F53774A56+07614B4587EF285720B48EEB2E440BD583D2F682BDB236666CA6D675503A3B99+21596D49136EDD0EF6315090B59D129344D07681E4239AA2C4AE62E0DDEDABCD+2DB83812AD063AB725754DE0199A89A740DFDFE31ED87E02D6BF7BFE362FEAB5+AABBBF64A2DE3B0908A31C267D2879F62D7441EBAF84BB6C3396639140981913+93AAA18E6ABC7A7E519FCABA8CF5963F19723EEBFE91B3BF1C84C21E45EF47DD+E83C5B72BF43D7962BF24D9EDD4443B6341EC76BDD8C734CAD0AD5E89D810547+6F8F240AE4D0512C283E9CBC75233DB83B542C3EAB56FC4A10C9789B76ED8EEF+5162765DC8E81FF005558238D0623784D1767E0A85DC4B8EA233107F4A871B26+02105FFEC50F373CEF60F58C3D981637A3B48CF6A8DC51971F732684AD87BB5B+00CE8358E04438FED44686E1F39B69B6F9D9300C232E4E997D9C3AEEB52DB6FE+55E250F8DC466D237C815E19E7C2CB10C89513CD99E9D38581D4E505947B5021+833C1055A577D57BD4BC6D8E847174807047063C936886526CBA530A0EC0AAC6+EF264F940B9EFB50001F5BF55CB4D7BEB4C426D553132C8CA690D173E3AD9C4C+FDBD351382965111AC8D2E10A695D9F12E668E843501F64D81994DB817510E98+A66FF5AC08EAD8546B0CE7C0C50F1066804DB5888C285FC606C25468C38CE234+BC07A65EC40C803EA263ACC6F4D53EBE0C2B16662136BFA0E10D8C503D2CC409+7A992D9C5B8957D05CB408E42B38FBE10846BB017D44DF1B8E45913286E28744+991FDB+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMMI10+%!PS-AdobeFont-1.1: CMMI10 1.100+%%CreationDate: 1996 Jul 23 07:53:57+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.100) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMMI10) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -14.04 def+/isFixedPitch false def+end readonly def+/FontName /CMMI10 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 58 /period put+dup 60 /less put+dup 62 /greater put+dup 65 /A put+dup 67 /C put+dup 80 /P put+dup 82 /R put+dup 102 /f put+readonly def+/FontBBox{-32 -250 1048 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE+D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958+9E394A533A081C36D456A09920001A3D2199583EB9B84B4DEE08E3D12939E321+990CD249827D9648574955F61BAAA11263A91B6C3D47A5190165B0C25ABF6D3E+6EC187E4B05182126BB0D0323D943170B795255260F9FD25F2248D04F45DFBFB+DEF7FF8B19BFEF637B210018AE02572B389B3F76282BEB29CC301905D388C721+59616893E774413F48DE0B408BC66DCE3FE17CB9F84D205839D58014D6A88823+D9320AE93AF96D97A02C4D5A2BB2B8C7925C4578003959C46E3CE1A2F0EAC4BF+8B9B325E46435BDE60BC54D72BC8ACB5C0A34413AC87045DC7B84646A324B808+6FD8E34217213E131C3B1510415CE45420688ED9C1D27890EC68BD7C1235FAF9+1DAB3A369DD2FC3BE5CF9655C7B7EDA7361D7E05E5831B6B8E2EEC542A7B38EE+03BE4BAC6079D038ACB3C7C916279764547C2D51976BABA94BA9866D79F13909+95AA39B0F03103A07CBDF441B8C5669F729020AF284B7FF52A29C6255FCAACF1+74109050FBA2602E72593FBCBFC26E726EE4AEF97B7632BC4F5F353B5C67FED2+3EA752A4A57B8F7FEFF1D7341D895F0A3A0BE1D8E3391970457A967EFF84F6D8+47750B1145B8CC5BD96EE7AA99DDC9E06939E383BDA41175233D58AD263EBF19+AFC27E4A7E07D09FB08355F6EA74E530B0743143F2A871732D62D80F35B19FD2+C7FDF08105847F13D50934419AC647CBA71DF74F4531DC02BBDA22AEEA3FBBBB+407E0ACC52BDC60D01A29407CC4F93EB8BF6D4813E9BA858D54F38918AC82720+4956D50291F0546E50FCAFA6DBD0099123F5ECD4AB338DB310DB4CAE11337A89+8ED99B6F483940C97544F888EAF0CBEB11094A13C073D0061808662A04A82BA0+AD35E8782F854AF66C20C0FEF18D0ECDD1646321B93D327E53D88CA0E825FA95+05AA57BD7B9CB0427096384740AE85618987DAC35C7A054B6B9D342F2C395D16+E42D2BCDB792D37C96E5D44D13B253C311C58031AC11425CA97A82EF4DB5B1E4+3608EED63196EEB4AE58D2CA4B2D128F13CC875C71BE0C06269DAF49BF8D6175+2D8E6DBA3834A401DE630AA266A3176F542FAF00B3D4ECFE2BB3B8C2C03BF302+2F4ECC8595284FE8E138020ED01E55E14D48BE5EC381584F742F25DF89F93745+0C7120CD711E6522ADBFDCA1AF4D9524795020CFD40ADDEAC3055E73D9011150+A0572EC8CCEE0034E5914CF9F1C57F2C689D1F54C20197F0DBE1E2EE16B7D71C+AAFE31391FDFDAED801D740B419F9E6DC54C42F8D8AFD15337A6529D60C7CBE4+2E939B6FD59287767403007359AACD221983D3202B031FC4C33A28F534105B1E+D464C53E103552FE99C905A751599986120676ED11527CAE7D6362E979BD5E96+1DEB0D8CD1D44BCD456F9A6C369B3DCBCE3879E24BB16DFE1A8CC40D065BE7A1+2A8B8AB514B6677B0A2B691EF1F7C1373D60F09D83C473E7B56BE2A46E054D4F+46603E7CFBF6E743B061D813916CBB9B7D13098F2D61A7A5F8887E8F712BBA29+83B6887CA2F8F7ED5DD114C406358842299C5E0E30FE0C6C19CB70C3230975EE+90A50EA30BDE3E91441B89E87DDBE5432F4E77C4E468BA6BB90742E03D33A78C+D3E62AE0F028FDAA27DFA19D28824981D84F74F1BC8821F77BF2661199B06D30+EDA2433F7A07BAF867A2F6CD5E87E47D8D23385710F12D416ECDA18A66210FDB+A70DA66C033A4F88A454B7A16257FE9A660659BFF4F0CC4D9B1265D3431372BA+7B57751A0FFAAD3EAC84AA702DB0C55A44F046C0A4BC5A086857C3BE43E4A868+F00198D9B709CF98FBD749EC74D30ABE3C0D314D000A9E9EDFABDF4F9B8F9EB1+3D29B75B36176C93F06AAA0C482EAEF6D6F16D2EB944C7B55A1C2BE6FD5DC339+23BB125F122FD9B03C537D7F655C2593AFF0BB888D966EB1E9E3EEA228022F28+C3A18C469893EA51B907C0215A5E78585E8AF52C624C9E44945F8FB73C38476F+4C43FF30014CFF918F15CA88FBD34CDA1D7944D3ED221A182D3A1A578CF85A6B+CA71C1F8F577D5AB1240AADEAD8A6963F694250E2E66162C979D439A4C9A4CA7+D53C0B2BC6BA5D8734F3A1682698AA0DA9AA60C96979F1FA62EA98714CC787C1+93C36C01842C9CDEFE92CCDCE6F5BDD8DC2E0376A3A48FA17907A72AB1452CCD+ED50B93200C4190099B8F92F9BBD82899AB2132ECC6DFF00A19BD707E7F6891B+8CD2115590831179F2939DD94131993329E27DE8E61FF624FE4F8C20A78E277D+0ED098CA45307F7647230DF1ED5E71FF7EF784C009870B974323BDCA1B7D9C11+E25E0BE95C00DE75213835B6ECE9F855B867C6F6D0E2039C801D61B4C01BBF5D+8A3C0CE6FD755F17D7426291F8A3252D4968797D1CB94F3B227B601F751870B9+6ABE3BD7C708E2BC4743B3BB420AA65E42D576A37F979135F97E26F5E0D1C3BA+E88A23D65FE8D279EE14EB589063C587247990F33C619DE3C8FF8816AF58464D+3EB93D7BCD7BFDF96FA9037201CE772291D4ED7775A09283360CB8FD6A0EAAF7+9339E5C641B2DA1E8F8AD79A5C7BD500FF70605575820E9748FAC4FEB9D0051B+AB1D4115D9D581BB4BBCF15DC946E77D44D2AD3612C31837BEF890246F4F3E4A+BBEBB71B43AB83DD600B35962FECA88463F187B87731825A5092221B5AEB950D+67E9E0E15D05F83D3C824CCCCB7227FAB5D9A9F9123FA366589BACBE9C3D11A9+89FD2645B3F8A1376B0C2C314BAE23790AE57D34CEE458119B7DC2E684AF4E59+F8736E8FC9E56AEF1599A87CFF243685305B49C257F197A10F220B92D5F49843+C6882B8714A39C8767F205014D3ECF32616FABADF5C4E8D9124CADB1A3CF02D8+DDF63EC83D11D17E0F412490E32FE7195359A90545F48ADB94615F1C66B01869+41A03C946942DF3E26B11DF09E2CECBBF0EFFC68B484228FA4A2396137C6834A+E0A86D7C0608A8580D923A5695A5C5A845B812C5D9D7AB5E09276E1F10B2906C+E7A287EFE3080F67C438A06930E5C9DDB272945B97B61EA7D463C7D86ADB451B+ED525C5F770E6F24CEB0EE2E022FDA69F86199B1376CEDC03E9483BBE8114D0E+AE28FAA423+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMTT9+%!PS-AdobeFont-1.1: CMTT9 1.0+%%CreationDate: 1991 Aug 20 16:46:24+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMTT9) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch true def+end readonly def+/FontName /CMTT9 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 40 /parenleft put+dup 41 /parenright put+dup 42 /asterisk put+dup 45 /hyphen put+dup 47 /slash put+dup 58 /colon put+dup 61 /equal put+dup 65 /A put+dup 68 /D put+dup 76 /L put+dup 78 /N put+dup 79 /O put+dup 80 /P put+dup 83 /S put+dup 87 /W put+dup 97 /a put+dup 98 /b put+dup 99 /c put+dup 100 /d put+dup 101 /e put+dup 104 /h put+dup 105 /i put+dup 108 /l put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 114 /r put+dup 115 /s put+dup 116 /t put+dup 117 /u put+dup 121 /y put+readonly def+/FontBBox{-6 -233 542 698}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5F00F963068B8232429ED8B7CF6A3D879A2D1E+2931CE5F5D18C658602059F07BE66E6EFC9239D7AB2FB8A4CBD41675B8ECF279+650C29E53B14AC0E392A664848C1844B1CECBB2D5CFB72D0916B675C9A9A1E35+F12696A6F628473C604A95376468E06E295AD6F76CEB939D94113532050B9D5A+D2F41A9EFB9424D986612313B89EFE9C8A71313340B248F6853B1EDBF02B7F9E+F447220FE131D7D54CFB8AA1281DBAEA73E665BACB1F164552CC0CEDB63BD4B1+4A9AE8AC6FA02242DBE8DA46B64B6BFC11762F0784F216FC8B9120D688D1705A+438B14F5E5DEAF2A98408B3B64620DE3732A4DAE6D08D5D97E34C75DAE19EABD+BA0796165C1151BCBFB1DF8D29A63A8300DBDB9E3323CB82D0337598B83F4F2B+A97CF5196D4D1CEC1EDB8966E548C0D9C194C932319610FB43EA1B86322FE641+AB48770FF13BD475A7267E142388563D1A400419C585B22A9886074687BEDF74+D905BE8EE440BA2ABF28EAB673399B7F129B9729DD5564C681954621903B84BB+CAF89AC5ADB2932472DF29ADA2BDBDB4D05F65F28F5F4C529613D61858E0074A+082A852710A62A147C966F2B85B51B0BE85F11D2057C66FDD61F6C5755367980+9F4DE680601D4DA41B46F8D2148450000413C27AA39B586B74B977B25F0FD3C0+4BA1EBFAFDBEC531EA13DFBD6700E53818CE04D23886B8AE75DCC36BCD3189B1+0D55FAE27D0D126E82AEF31D7B5DF27E58C30BB0867D6D7AC1DA9EFB8A2DF095+B5B934A68EE122DA0A83B36C952431586B957990206194E89339048AA6EE4C53+703763505ED57C494DD907D0EEA04F6B1D4C8F3BA778F4E7AA832AAB4D75F024+61E91C6D25FD6823CB24FC863AA7E80C15BB542E4BE0532A46C15455B106B5AF+810D77DCD3481F37A038A396CD8FB5E54A644B5E10FC2AB50C04F3674B2F52E5+CDCBA8A1EC7ACA7829EBE8B50D76AEC9FE001295A8874541E450881FE55E5C21+11AAD7377E5FB9937C8562D9C28EB5A3F9BA53A876E1CED557EABB95F130B955+7595E66F04EF7ABB904C45B2ED0BEB7F256176357D449DB54EEDD2F3A7E7B011+BA184368568418B849B07F7778810F55BA29087E40773067905E555D7FA8EDF4+DC78CD7D26C92D622C6D8899CE803521CB3646AB6FA74CA1A10F0E15EC03AB0B+448C01D35AC3888978CAADB577624A42FF6C687270A57247A7B2D76ADF0B9463+BF9C61A75995DE2C2B5CF98C1AAF6A91BB6FF7243B106DBF043DBD54AC1AD213+B95AC4B184A5E404967E4D471AF19C2047AC111E36D9C6C7AFE07A727BBF42EA+E0A8BE01B6A5897B9F508D956BB2CC47DAAF97B481DA7FE6B6CEA20400262105+F7CC4766710A143CA7FCCDA9B38FD36B6DFFD1DA0288D835D3C04110D29248CB+8A0F4753053E897925B001815C5B742FEA91B6A1731681E5E1B21CBFEC066E90+F68D73C86427F24577C08441694796BBF1730921EE2C0CFA534FCFD46D42C68A+CBC38B4D608DFC0CDA766066CB7123E10861CCB97CA43787F5A86050194A36E3+CD0EB69F7BB9389FE10A0E48CB69A4BFE7D63F55159150B0FF3ADF0A4B7746AC+7259E53E917313209DD75C707112F4F21CB1B754DEF96194D456D73AAC7C4CE4+8484644F95BA77009B867BFA2E31959E4DE47B24E70E1C08AF826F535F138BFE+9F6F77F5BF4DCB4050F337C0A63EC1C0877D28A1AF989B57442CD5E653B472EF+F788419751F96F12C5E3E4B81A19DAA45909EFE010F2A42E03157C8D70E19448+EF432F2CC0E909F8C0E69CD559FB0EC298573755637A53A0FD31CB254FA38BF9+644D40F69FF58F1005A315E5DB17BCA7E96AC8ECAD932351C1F153C21E8FC6BB+0307FD33256444C89FA83B8D9475C6DF5CDC6D272BE57CCC2378186CD6F80F43+47176FEFCC36D3AD853FCEC4F89BD08CE546DA14E3BDB023075EF11A674F0712+E32601FF9F6916A7415EEFA4939FA43B79B2F315218F3D72B5A9332BA310F876+1948284AF9DA245BCCA758A6F71D4B4AB110CE2D30C748076DD921EF136B99FA+3A72D0DCE34A6E106DB6E07E9229E91EBBC8B042597F394232AF6132283666A2+39FA237795F107D22CD6E3DE6715DBAF9505850CAA58DFCA67B1F9D96235403B+90ADAA8421B21442873A5F344D78F68974E653BF2908732F2F074A56DB03602B+696349E0C9BF82E20506019030DEA1366C2E917916D22B57929830323B85B06F+C249C6D35ACB13F9CC010A96BD14CCF592D89B0A921218FD938F53799664C79D+D1846762B796A0316FEFF977857F4E5AD50022615BC20B579270DC8D190515CF+3ADFE2BD6997CC2998D5DC93A9A9B172A75052FC3926B5B6839E12A0AB4B077F+73328469E0C1A7BDC059AD295781C95FBA2045B13BEA2878DFBF8C9D3A71EA2E+F4B2E3D3C5C4C1918E280F68E4785785A1DEFB6A641A8F8AE5881EE5DACD8322+35955CD693B456DB2E1D27463C4C25BF15B22C1F562F652FE403C72479A11D29+1E128F3A12457A664F1B9B384EF5B010031473CBCA19FEB57600A315D8C008A2+A06922A92FB3329970BE3631256B47E72084D76632F34A648E97888F1D3190C7+F05BF1676A9EE3582A1041BFC5CF9771E57D935213DFAC34ECE18229E378AC28+6F164F7B006AF57DDBC68553C72C163DA6FBB24B7A466002D74F51F193567ED5+524C96521FC8492F70227B2C74938E2BED721E1BB7534A25DC7CCF754BADD597+D44F780DFAC39002F2C9DDEA91CD5E2727952C0D0A38EBA36872244D6283D0BE+C197DEB368099E9C0B0885E21772723C6406D21FAFC7B0414CBF6683BF759A4C+C796B5C2FBDB8E0A0D29B71EDB131B4ED32D67939FE5404695469E7EED899015+4EC5D2C92809502404E84381ABD4A66E8FFB11AF78D4EC04A9E0FCCC9DDDF7FD+889925FC4FDF7BD242EAF76B20B7986511F43CDD39669AFF5D4A9CFC3CFB598C+33BD11EB2938298BB0E244BD5A49C9F941A65465756B3E1B6FC3C10ED92FF584+1C1D476B0B2A138913E0247D0EC1B8E30B6C83C3A75F3A27265EAF66F669A55E+72EB2B33E63E94A190B82E73A229E4CA579AFD6D5D94462A362230E955914B5B+CAB4033C3CFF423D0474ABE43BED06CB6A838DC71BE104AF4739C4CE35E4A04D+BD054FEC6147F2399B06B58C870BFE51186F97AE95944656FCAB73A344BD74E2+F7C7DB581B2831D5F8C49F7E092FB5FC9584059026E8FACA49E5F362A6595EE5+CA2EF5B39C25C4CE39AB6D9C78256DFF0D6877E5D1522A88E4AD9DDCA2692F0F+2B24E8CBD132D10E3D2F80E2218D6EBC97BE068F35FA2D849415E536652E6EF9+CB6C23F94EAB864E06EF0D7250E31091A822A0BC9200474E5A9CE0D68E83DDE4+EAE24A966CBABDA0EC57EEB4DC81F3B4779DAB085E4D58A15B337A02AD4BEC43+AABDB6758827849003F51DE244CB1BAF35433B79EE2810FCD6BF44287D762124+B3B4B551B77DAC38DA483C9EF23540735AFF616AD78B0179C8991AB8024449F3+D1B437FE89BC8DDAA5AF846E67CF815A6176A143210399A9DBD23240017E314F+96AB14BB5F3BBA05C335AF4B047EB029374BFD39E409DC62DA4F1EB1EB9B2BFC+BE36530BF9DAAB290070FB984A81E52C5B4838EBF0EEC1AD870BFAC1D28B110F+5BFAD0A6616287693236175406AA691F30E3BCF455D9CE7570407017E9833C30+0EB426EC9BC14011298EAC2CFA3D9079471B4609B7A3B1DDB6CDE7CBCDBC98CA+2C158FE3FDF2F2330CD7831101CE4159A6058F1B59493F1F28B38C24D5513040+25148287A58B39A006AABE5BA317A6737159CBF5A1228DBA779536E94156DECF+8FCD90E32F6571AD8F888A24159D877E430116042CF7002CEAD5B095ABD0C5CD+C7C7E394CC6EE8DB3882106B734914A09693F15058CCF3E9ED05186B2E59E55C+824495DF434AB10C6BEBF90A3F31DDCBC7BB9FFFA1B689B733DF4A2B781D1E47+8BF64EF3FA589D6C9C5667AFFE3B35B13B6D5C051D05619D35D13FF63535EC38+C086277561372B10210A80C24DE3B56FA40C9982322AD85826D7131A7389E961+A8E38D1E932F7A6EC931E83748E72389667838F920F7E3123EC751356E4A662D+6BC8B7056545AB9A7C639626614FC310F43265193F38D27D027C02A72CE02BA1+93589DBB06BB31AF882FF67CABD8E57B69B6BCF8FEBCE1CB5E45E7B9104BBDDC+3ADF7C453A919EDB68563D0C056629348F159F2B46EBF7ADA55E9756999D4F39+C233F6B313E572BBB80F734C9EF773851350E4236537D5F097A68A73AFADCC3E+CE131F2B78999FC93C39138F9D7410CB6A67E0C1494E111985D772E9EE8CBEBE+E60F676BA8824AF83DFF27C9711DFE6B76F9E05A1D5E8F95A55A763029362134+2416A6876240A36F46BCE67355A4E818BFCC28BD127416759645CE934935935C+2C9A73A917E56293D7B80FAD5B009909CC14E84872292748B6D5E02EA0C5F8A2+5EB3FA7EBC4962C7200E03AE6D43EA91F8C2CE063CBC051E1F7BDDF224E8E02F+1418291C54CAB234AD191B3BDC095CA23CC3753718D9FDB7412496D20C3BE2C2+C27750CC7E2ABCD186B5F649ACA233F521E1A21327931C3BC2ED95D88C33A6C7+D96D83E4F909CF83400DAF68B88C57304AD1EDE4EAD62A3F97DE6034D246D959+80CCD9E48AC316E30DA8079F9F92E2BDE3030EDF56DF3961B77E69CEB3BDE050+D999B7EEAD52185FAEACB5E8E105D7C34FE5228A2873AC127563368ECB17920F+24ABB4DBAA602AF95CC8486FCC2C21B0A1170989101ADD5BBC561DCDB5A2E3AD+B6F0B573CD0003C7F804E0750A7D621A954E9B5DA428B3A2A9DB49165799D25B+08BFD059FCB3EC0B260214DD0C180BAA63AFF175F780CC6B6996F1B973905172+0A7216E4AD9D7C80AF1BC7609DF8EEA6B70A50793D28C7A985EB4F9542D5A1D0+1223637358285A5CD5AF3A6997D1986EE9B50E71964AF49A488118F95B7D3442+7D12BC62D436BAE4DB9737D376BE398A9CBC3D0C9C463D27658DB97EDA5F2AE8+87205A971779B742E778684DE0298A82031A5012CA23203E50C669E9E6C47046+672B7E8833F6F729049F4AF69D9B62628D47CF6D3B1D66857DE5D7F579AE4D1B+214DAE2757423C54ADDE5DAEB49CE7D77DA39CB388D22274BE421D97928FFC5A+D21E615D16FAC3FA148191F5F2D6D82FB179D13F4E6276D4991D9CC93977097A+6586F02088127D8FCE38A7708DEA1A6E27928FE964FAFDACE527CF5A11799CA8+562F9937D47A01B636733E5B00654C5DF6F8FF8BAB08ED233E8B4CFCD3A7A9BD+02403543E8B5247E7FEA05E2D1555A45BFB7EE7624C30DA4E19FCB7251F4CD13+139EFDBBC8535178648D7E68B853CFCACBC33C85D35C6E848DAB0315275FD6BE+3B5C14E0C4548D07A43738724814FA3E9A9AA44A8BAF580605EAD194B9A1DB46+B326BCB57325002205D31DC24D0607627DE442EFF285677B17C7805C8FFB7FCA+AD9E0224EA968B5D07C0181652F18E8B6C0D58FFF95702C5766CF44263CF350B+9BF01ED6BC04DD5AC32DA64E11CE4C88B9D0B0E9B63E0A377CB5401E5BC593E6+E6AC72DE875E62D7768251F921A81D33ECA0B0A8413B0DCB40AD295215303800+6755AA52B29FED6E2EA6CF78D6573C9D63AF9F893F5D52F166779AC0B8C60467+0A7836436EA407DDDB35D201B4751BA21E8E9F445E40230C87635517BBC2569A+766F89D408F2CB7661882F2758C04309FD45FD38634670351279DDE24F69EC54+034B420659540C65904B508C7E362ADF632AEAAEFA6F93349547E6BA3A6497C0+B8650F09E4EA2B744B41F35D20DD7BC2E613E697C7F513F57C351A5469F78428+A06CD2FB1BF80260D6F72F4778EA2E03BBEC99D67079407F36702B1E86E2E225+9B0B3D31377BE594847799B1B4D4BF6933E0FEF1E9849DD9754B952C3DB25444+7D1B98BB9851577E090A63D0C6553344FBC4B88DE5BBB96FD869273E64925784+CF1A9794A52588E215DF72B5B07D3CF35545A7EB8136E5E13835D9A23AAC4EC3+A335022933180FD5E2ABC1A54213855FE520C62732883EF50F5CB69955490E1C+3072D4F7EBD4A1FA16D5E63D88C4ED70E33F369A652B40D27E3321BEB0B43420+2610777F1A6532D1E886402468464161F73BC406D0215D503C4422D23D295C9E+064C7AD18D8DDC9C6CAE3B49498529E23E5CC5FE0FA83FEF45A211664C6B7BC5+1130A5CDC991AD34E6EFBC6EED274AB416ECA422FAF5EF13EF8CFFB3C663DD12+40B1B50C8339081E54223BD9DDDFF6E592E05883196A8456C58F2834C635EDF1+33C2B921BCD5B1B5DEB4038AEAE4B33147903B03CB0D143D6779C11ADE04DB83+40F6D8C05F509FF0034FCA7E0D92916B37CF9C95F98C0B37A44A14AF908E1972+1AC838D0BBD7B95E5F4F31F6E1C005A3828461FC7FD7D81B5A5876DFB2E052EC+8C26ED7EC10BFCE4B32552C38A602E6EF3BDB6756B7D30FCC628AED4549C2843+62E81CF97634BB6065FBCA85C54B77D6E538E9344D6154B1F551BC6136A4B0E1+A35153445ED68B37802F0CA565E70F8B94E86BC0C038F2E968B2640A8144535C+3E0E308336DA61403012677B043BEC23E4EF48FC7CB253D90E14515F8B17C391+2C056D074336BF4066DDB9F1E5932DF4C8041C450F2DCC3B08BB218B5095F320+6DDC836DC904C33D526CCB9D0671DFA2EA636E19125F01DABC32E76BFED2DCC7+D0277DECAFA86E8C3EA100F8A80E4686470CBE5F81B189984F19345F1588D193+6545DD927FDB9E71DE921CF0D584B2DC27271021BE02113ED285ED291A4E1009+BC3013A4379FD0A11A446D8F50156E464B0154A3210E027EF45C263D6D6A6ACA+5D919D7A5A950194D1B82624A241604B723DB56F6C743C6F4C125FB0B933A413+52AEB566339C14AE4EAE03330FCC8EA6643E3EF43F78E79D5793C00AF55F4C1E+6116BFAC01D78D6D8BC6C6A8056D06D1DE453C94C044B9793F20EC38E6D1571E+053D59F16D3CA22DB109662900CD2CDD39FF3451B49D458EDDBE0AD53F58CFE6+5F3ED20434AE545B7E5CFB1BC409B0239C03DF700773C1600871+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMBX12+%!PS-AdobeFont-1.1: CMBX12 1.0+%%CreationDate: 1991 Aug 20 16:34:54+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMBX12) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Bold) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMBX12 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 11 /ff put+dup 12 /fi put+dup 13 /fl put+dup 14 /ffi put+dup 39 /quoteright put+dup 44 /comma put+dup 45 /hyphen put+dup 46 /period put+dup 48 /zero put+dup 49 /one put+dup 50 /two put+dup 51 /three put+dup 52 /four put+dup 53 /five put+dup 54 /six put+dup 55 /seven put+dup 56 /eight put+dup 57 /nine put+dup 58 /colon put+dup 65 /A put+dup 66 /B put+dup 67 /C put+dup 68 /D put+dup 69 /E put+dup 70 /F put+dup 71 /G put+dup 72 /H put+dup 73 /I put+dup 74 /J put+dup 75 /K put+dup 76 /L put+dup 77 /M put+dup 78 /N put+dup 79 /O put+dup 80 /P put+dup 82 /R put+dup 83 /S put+dup 84 /T put+dup 85 /U put+dup 86 /V put+dup 87 /W put+dup 88 /X put+dup 89 /Y put+dup 97 /a put+dup 98 /b put+dup 99 /c put+dup 100 /d put+dup 101 /e put+dup 102 /f put+dup 103 /g put+dup 104 /h put+dup 105 /i put+dup 106 /j put+dup 107 /k put+dup 108 /l put+dup 109 /m put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 113 /q put+dup 114 /r put+dup 115 /s put+dup 116 /t put+dup 117 /u put+dup 118 /v put+dup 119 /w put+dup 120 /x put+dup 121 /y put+dup 122 /z put+dup 124 /emdash put+readonly def+/FontBBox{-53 -251 1139 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5F0364CD5660F74BEE96790DE35AFA90CCF712+B1805DA88AE375A04D99598EADFC625BDC1F9C315B6CF28C9BD427F32C745C99+AEBE70DAAED49EA45AF94F081934AA47894A370D698ABABDA4215500B190AF26+7FCFB7DDA2BC68605A4EF61ECCA3D61C684B47FFB5887A3BEDE0B4D30E8EBABF+20980C23312618EB0EAF289B2924FF4A334B85D98FD68545FDADB47F991E7390+B10EE86A46A5AF8866C010225024D5E5862D49DEB5D8ECCB95D94283C50A363D+68A49071445610F03CE3600945118A6BC0B3AA4593104E727261C68C4A47F809+D77E4CF27B3681F6B6F3AC498E45361BF9E01FAF5527F5E3CC790D3084674B3E+26296F3E03321B5C555D2458578A89E72D3166A3C5D740B3ABB127CF420C316D+F957873DA04CF0DB25A73574A4DE2E4F2D5D4E8E0B430654CF7F341A1BDB3E26+77C194764EAD58C585F49EF10843FE020F9FDFD9008D660DE50B9BD7A2A87299+BC319E66D781101BB956E30643A19B93C8967E1AE4719F300BFE5866F0D6DA5E+C55E171A24D3B707EFA325D47F473764E99BC8B1108D815CF2ACADFA6C4663E8+30855D673CE98AB78F5F829F7FA226AB57F07B3E7D4E7CE30ED3B7EB0D3035C5+148DA8D9FA34483414FDA8E3DC9E6C479E3EEE9A11A0547FC9085FA4631AD19C+E936E0598E3197207FA7BB6E55CFD5EF72AEC12D9A9675241C7A71316B2E148D+E2A1732B3627109EA446CB320EBBE2E78281CDF0890E2E72B6711335857F1E23+337C75E729701E93D5BEC0630CDC7F4E957233EC09F917E5CA703C7E93841598+0E73843FC6619DE017C8473A6D1B2BE5142DEBA285B98FA1CC5E64D2ADB981E6+472971848451A245DDF6AA3B8225E9AC8E4630B0FF32D679EC27ACAD85C6394E+A6F71023B660EE883D8B676837E9EBA4E42BA8F365433A900F1DC3A9F0E88A26+31BE19DF88DD7791F8799A8787033F1BDB4329E0340CCCDDDE404B73185DFC08+9E49D5D9FC8CAE37820C3605C3D6AD5731A154518405098CF41485DB5987FFAD+024DA9124B96855E275FB4AB8C3FCC80B986CDA5BD5761A65AFFABB4845F7D31+A67A4FA8B9ED03208505137B69CC0B30B6F61C9B6BB78DDE9134AD156628CF7C+AB6B1B80A7E05BDE2FADDD2FA14DA1F5AF588E831A1D4EFC8AF4DD904C92075D+679C3AA115FE78996DC4F672B6276EABCABA45C646A9E6076DBB8EE2EF9338BE+6DC8411CBFD1187E6311FDE37AF5708406094B32F5D198A81D9AB795245C8CF7+670A19B8201736A818C182419E16B14C5C83F0DDB6A1457B593058AE0BF98438+8B81FC61C6DFA5A17E32704F714C036D2D235BE5401C992118EA4FF5DC6C3B16+9D80D1D48DF791787FA5A08E54A951916187C8BA0EC3CDE053EE011B5ECD292F+3650199BBC733008589A6EF7FD2FB0AEF44AD685F593489942EABD142B8F52A6+0D7B658E6EA31903B751D75FA55231FDF23752725003956F1D505DFA345C112C+D8F421ED4A1BAAF2A8F076F0E93B66B8B592A9803957E58A1FD65A2D19CC0F34+80128924D95440890BF6A03C2748E0A64A6694F4F04939A21EEFB0C980FE3CD3+0928329E185FAA080861059B78E43E849F985F7364E0F7FF89839327E4947529+EF8FCE892D99D2B1F37FCD160BF44BD9CCE40C6469E76E8DC294689D620DFD81+7282067907BC839F35BA7A10B8EBAFA118338E44AA745AADC824F014A3BD7290+1516DAF498E175686F3D0BF51258873614396717524746D08D7C57A79153582B+587B6C5EAD71C8ABA7F0526EBE863E6140943A55756EE4AD680BCB284ED9961A+4370E7F0B321D15560D72682F299FFCC314D5811EF8E0924DB721E46E9A202EE+1CC8E26179035002C656C123167EE83EB7B8B9409AAB46E6F9D604F696D51198+AED64BDE818FFAC41A65920E3D4E256E2ABDCDE2CAEFFEA7015DE0A030D274AC+5604C3A41941A6F9E54301600C9CB2682F61C0A20C5F40AE9CF09242029B240E+3D38D2636CBFCDD2DC43A4256D3F34666F49C9DED929165FFB1BE9EA25D167A2+491FE2AC1C40478807863A4109625ECFDD2F5116AF16D24EAC934BB8118B93FE+A21433A30A5337E835A1F25818AAF011C42099AC20B8C9F0BF480CBA3DB91078+3C7256EFC3D49BC6CED58BD60C358DD1996A8D2A0A92D864F36181EC6334BB9F+7BC6B9DA8A0CD536791B439DE76107B430691AD02186F38CD8C9DA6BF0C233F7+EF89DA2062352987EF93E8D3D5FC7EF84046483C214881F564A4C628937AE2A6+DAAF7A9F09246D20F2B28967D3A13ECFFE9FFE60084EF82DFA94D891F1D73F2F+E7A43880CE7042C9C2F37FEB8B230A06168025CD0F254CBC8E3125B26D4CFE54+AFE0F0FF771B7752817CF2896A898DC43254E00224D245B4B1902C30B251ED07+990B1342D37BD25E4EC19554570337FEB2931F56EE016CACC62B291771E1B57A+AAC8311AC32DA2FCA671757DF69FCE22690639283F2D4736885882C74B1AEE57+B23C1073DAD9480B2CFDACDCC385AE3CC94A94F64AFA103AE7CDACEDED42106C+CE95F86EB0949E877A1CC37AEE854A6917C2229FABF3320C2A1DCD9A400B0D49+82AF78222E469081168BE62341E7EBA87859FB935AF03A9AD39D71C08B519026+12BE5983753CB3DDDF2A6E58510225AF7B11EB9ED87146944E65FB8FEB0A6608+8C8C85DCD0F71AEFB8A87446C32103BA40B9A0AC168687CCECEEB656826D727E+A148569866CA62949C079947E316809536F1AAF051C204C6B4374B284C9C1E22+817B33514657D1B57FD22417DD31E305FEF717DC9444B351ED11755EF12DEB17+6746A70EAF80B41F1CD5CCB91C0E4AA08F0FF35322E93A843F3B17FFD2CBC463+1DD31F839373A51E4CFBF99DF01E766C1322002138D00B4C56C31ED0CFE80366+013477E1A76B90981E17A9996A1812C602C32D6635A7E116FD83367BDF6E65DF+C24C20CB8B303828937612BBDE47E7D40206BCE98555500D82AEB363A90CC349+53A451E5B5549E56CCAB2C0833AEABE0DE3EF6FFE83ADA0B71EB84ADE47BD4CC+3C89B7FEB91FEBFD992577342A5CA896DE525AE9C8EB7BADE8CF0F984032F0CE+52AAC493CE70CEB93FB86DCFD1302B838C71D35ED297F4D42AB268B28552C34B+DF62B4F3D9AF4ABB0C18660A5E1ECEB82203D5BDC18E97D032A93FC80D0A8F59+EDF97BA2E78FEF86765645E228907D68F768B9F5C99ACBF4E531A676C4FA82A1+99C5CF4520010417888CCBFC3724CB0B00115FFDF517E0AF14129B13DB6D5933+F62948F391F145FBD43447B1C6649B9575AB194518C28685B59A920BB2F8B4BF+9A0E7C775E19CD39D225A6446871BF2FF33B96BBF1BB8442BD70987371D2973C+2638AC99DAA1D8D53D1677EC8ACE344F97426A148DE1EC6708A307B59F200192+13F59ACE5F65F4AFAB1354718A916F54461D4EE7BE6CD72018E65E73E832CC77+EC812B7DEB7DA2B170625BF72E0AE4C14F0F5EFC09FE3AD2457F10EF46C24668+57369F9C3178AF0DB2091B3A3AD9C8BA74F023D2F083DEE812A2814C1BAAECD6+4E587715196F5B8CB49E642706E9E7D3FEF6EC2C1F4665FB3EA67CD72DBCBC81+AB3D1EC331618D0A9D355742D0693D5A9DA79D461A92CB93DAAAA4E210B159C6+21A4DDDD90F3F427C22D71B9287A1B454DC2779D733F3BB835AC0BC049DA5AEB+F4E049BEB5497547779DD2476BA728FE8DF6B23F509EC59AB65F299A90440916+9794048A3C21329353A6BCEC3782154FDF09CE5A348C8E15AE387D6FFF8BFD1E+469E410041F31F29083B16102460A520987473F2881EA20F1667D72C5DDB3816+60B458D2A695AFA687A5B101977AC763F1C8D21A77D2234F58D235053683A246+51AE8BCE308D353CE82F1FF82FD161DA0BDFE85542FD63F68B377177E3AA189A+A34E5F2E8A97145395DBA1A9A93824D1E9341B2741066C2C5BC0B488C837EE25+516CE88E8FF6279292EEB467C6FB3BECB9F8D2E2210FF5732A39F1A6CC199988+A44E579AAD1244E2771787D74635B4C4F9A5F929B1545E074EE7098F5CCE3ED9+2AE401852C5D105BC317A9522C9C56153BFEE8AE1F2896918027DA7B67578404+ADFB48687E3E455F24CEE63507BA2CF7C9B2314DFCD59ABC351C3955FB2A496C+A0822D210123FF235DA68A5047341BDD6E446846EA74C9BBC5981B33737EE24D+95933271D72A79E8EF597390C7BCA5109F72F8D3ED289AC46E481728007E1649+FA3B1224DA25F558E7819A76399C0753AE8DDC322C09356EACA1C214E0010C58+948E2AA166E6C16DBA874CF378A59289385378A47BA7AE75E19A87D1FE2DD6CD+69F826F9DF2CFC51B66634C9C09FF98158F4FA6DA929CF54210D93BF7FA8530D+4F359C495DFDCE2A3EF4AAC6D304B2023D7E2B72991D4FF1F5FCC9EA22E7E3DF+05D0E50A3DDBDA84E6D38355A61CFA76F32EEB64F7A4084164707502F8EFE94C+6F5FF7115B0DA2AA9E59D4D636185C5789F14201D510F036CAA0A272A8C63CC7+F73F40076D05011F947307458A230C7ACB541549F36222D95707D5AEA1EB029C+600E2C1BD1CDCC30279AD4E2F3A6977274FB307BD8BB7961475FEF659CA07DFB+3ED5588FEE5AEE4F9E1505C1C8504A2CC99A8EA3AB51EABC000DEF763B5E6FBE+CB93D7C370CD46C19E6CD03B5708F494BB705E79384A9778A0BD7243A97175E4+CF047E76E513E053919B58CF4480906CCCCCD6890AB60B98F2D61CC705CD3194+EEC84CC1A60044B878422ED34962E08AC73BA2C719A0B1A3144D60164034BA3C+D272FF438CAA0B936C7782651B286CE95F55798BDA454283DBAF82417295E14A+97465FD683C6EA24FDB9646ED2A02F8AF508C8BEC84CEC289B3D793BFEED6696+BE01434A24089AB484578D531509F64ED5A1031FF0076ADB495C42A963C11B4E+71987394ACC7D50938102E5CD4CF81ACFD9C1EAA796E86FB08D39A79773A6CE4+7818A118D781DB967C44DD93D2419A190070C4A4D1DB66EAED9C5564DE913193+BD2B9E25A6012639F09BDC40B3AD1C43D567E8574A6D60ADE4322A016C7B4786+DD0DFC619D9306F9A33DB8692DCF3956BE0D085D20575623C900AB6A5FC40E04+942BA4052548E375AC083ADEA788D53D223002B367808D6659195EF47BE5C54D+92874BDC46E7F5B77E2BD5F895D4B9BC1A7188403D2FE38A8F9174C76D4495F0+3B8B2A264AA753D09F8813718E5BB1F4C3F7EE216A51A1AB1F05A4BE0C206A7E+09A0D819B3BD025D6B5D7BE879999A089CC66860E3668914B30DBF1C03F3C0E7+D4D447B65D56CDE2CFF14EE577ECBD73D195174BDFF0A28D766C38289F4C53D1+BC4288750A32226676A9C256408183F7A9E2229B4556157573ADE9579FF41C15+0820C431A7EF3DF037E00806B1CD9AAF59DB9374D58D7D246DA693664414C0AD+C0993A53789F880DE4C11D996F8210DEF22CAEABD0AA727DB9BE89401F412A15+6108B7A2833C65BC3F079CFC59E1326E5CE3C9EDC935D8DD0BBD9410A95E7268+78BB2C7136458E78BFE6757654EEA4369AA5CC1D5FD996115634010F54C68836+37C232EFD6791805DAAEF786385DC9B26E5D4960B0C68873EB62FAC4DCE442BE+EC2D0B82E6D5B308DB51D755CD939FBFD5335362127145938C79075A8E388B89+DBC4834B8F4B47D6505AC89B57ECDF28F6E3C7CD733BAFF3725F1B7A0E54737A+EB360C1742B77978CC0FAEDEF29A74F2430E9817F7DC37F654B31AB7C49536F5+709EAC62608BC98193DB8DE36F6D53AAF4F5B02E8E1A69B956858053E62522F4+333D8E5CEA4158E69DADA7B715835FB0D4B4491C51DE5201DB968EED629702F6+B385D083E76A442BBE565D17E4464AE3ACA949CE60B2F7CD7543F8E45C1C24B2+2D4EB701047B4A02BC41AC00C2C7DF801BE7E0A05CBEEE7C5436214D0755AFD5+846D209E66F0F5A79C4308681BE4FBD5750D6640BA682FDE257A9EDC44F1A383+8812B294F6AAEBCE36711351274ED5C2B9DCA86ABAF841EE35AE79AA3F576EC6+34CE7E6A3846ADE1EDE979BFA55E851FC28E21DFFB415DED91B4672B51CC3908+93C0B359982C92C619CB047A97FCB9583185D1970B2167A61A4CB6CDF0EF7ADA+15958E6DA9CE497A959DB1750232FF2A48E6AED40007E5E8AD875B2FE65916DC+E002B730F11154E8CD007A9EEF9A9ADAA8D264888A86F36F1891794B94376686+81E631794CA0E4E89364D7C1564CA6A093E4185BA2FE0B7E741C2F01E1672649+2672FDA4879916C45783B1C45E08E111383A6E874397921689D4D037ED6C64BC+D264259C4509DB46D1F11D9CE414F3A55F10E25FC08BDB9F4C6C8F8DCD2CC265+6130DFC28AC3D198C4D6A9D989E14310B17F66D9EB233F6E6F29ADE86CF72F16+CE9FA0A641488F2635A3179AB9B9F3FFEFF6934B85601CDD8EC3205CDEAF5EDA+F0E17DFE835B6A1AFA4F180D00BBDA5E725E2C5E2D889C4FF9823AC0DE9EEBF4+01D81BB23A18BBF9ED858C7788C18D4F2A9FC40B9BA771BB9BF48A3508706C51+95950C3E4138BA803E002ABC3525EFC51BE876740FAB2C2BA633EFF86BE29814+C832CB110A1B5DD4E466C49E4DDD19830DBA1EA74B51FE289E4D34CCDA366B99+84CE2DA0D6A48BEF7C2F7A492C35465C78D5790D9B3F86A7E2B4B79BCDC0E8C6+866739EF77986276AE0CF2D251CA4C565A919A1669832E8088917E96D5157924+6C3BA1F6FE9668E2E7472786450BF1D2591BA5D495267C4FE07BA5CEBB87B80E+8BB9A25AACFBCDF555B9BBD7D004F8D060F33D6EE0FF5A528E60C93E8E75EB3C+C07462B485C63C526B9B39F17623CBD5D6B3F88AC168AE5B798F7B87EBFFF6E7+2316F61A11CFA9104E65E65EDBE6F5E704F23D9E1A16CD09FA25351895DBF1E7+53FA7F3CDF3D9E98DB4DC4A3A310D4FFE51EE2A97A7FB4EC05232C639337F0EB+A6F7AEC9869BE2543A6B15FB52D2F235AEAA90B56C98CBBE072FD879F00C3FA2+7AEED22C60FC40B66034E75F675178E1012F2DB47C991480755E91B1CA7B817B+0D96277547EFA4E24397C95796D3E16EACDD8DA404895FC8205DEF2E0FFA75AE+D05AC52F2685A3EABFBDB7DD865D618360E2884FCF14F6FB46A0686AADAC9278+E16AF093AEE64A841BC7268509A3CA5EA15129262C75E7353351BCD999546245+3576AE64DC30FE5C98457493FBA51B2C6E1CBB4975A7F996E3D488E92FC1A66E+B8ADD9451866A66516E810979C95F797E62C3A9201064ED3CD921B5D95022D61+BEFA7D09C6845A379A2CBB34B4459E15E47B29E74E921DCB46B02F1E0DA9693F+BA6683269AFA0E8AE4FF1C7B3EF89C72CB4F3B923CB67E3DB5277BA73D3A4B99+0170D1E35742EAA81DF08E2C1CC916B05244DD0522178CF01FE2E97FB649BD53+D8B5EEAE435C3B655928904D13291D0C4E087C7524450620756E28B264C749D6+3C751C87422D688758FA736FB7A233EBFA67FDA7BC36572FBDEFB6025E746C77+9C45755F7C80281E5F45C44137ADE144D14EDC830536E68480424A838FBA46A3+5C3DD65064F5CA918E01C12F409478BE23CE7BD3EBC68D71A72E9765F3D4D007+6AD50FB62EA40D4D5EDC58E571A739813EC97B2FEDFC4B8666685E8C87086FF3+269C791ECE1994CC78877735A7C924F643D8E1B44F34181AB8C37A896DC72F4F+CD720A48A2D70210721C3FAA6215A6A906776B9F74C261C1962A7FC030E10C4D+1258CE82CDC2D3FA3447A72584B1FA7B751FABC2C0F7FAAA9EAB460AA615DD88+DACD49A2E00DFE383B80D6583678AC27F5E5AFC244834ADA4A4779BB2A01AAC8+1E46D8D1842A28A5CDD455EACA27D5AFE1D3F1341F3891DEA5B23B3F854C9F89+E0291C258ED54D4F7989792939317E8F4B233AF0AE90F0A992920CE66D51A82B+8A8F9459D6CB720BC4E150531D589C39C5F511C7FFA9A2E6E75A9D1DC2B0C90F+FA9EABEB8D8CF41FA474345311211591F01CE874877EF390D87D04FE86120165+2DB04F1AC70607024AFDE20689C89F7F9F477BA00CB34878DD25009F6ED1383E+A3B967D9D9B3D236C9E8F6566D1CB04F584793B80105B082BE77580BEDB2C95B+2E7F98400776F1B9ACD63990F99DB4207C7169E057B430C478A244FC468A2AA7+92A4E41449FCF0683191A9D559DEDA861B80BD689A95B578A06A50C6952282C9+F6FBE449852C9E9ED6B6E3FAA8914818735A47914D62781B1F17DDA2CE7233D0+C26946E530570FB08D08E070123833511381DBCEFD984AD56A850E9FA7BAF325+4884EEAEEF82C7303486B945CB3C473F171B4966795BF3E5D6D7414D2DD1D79A+425EA0ECE7E7B0D98A77622DBA29D7EACA6443C95716653EFA8B24094FD2AF01+D69FD6D7D20B492C8C97EB2670C1979A33B9F7DC1E6ABBAE907A3B7FDACFC5F1+22DFD4BDF8B180D8A885B975372B22C490BDE2BA85675C8B3910DE1521604B85+56B4C90495E92672E6C2DA51114A1436B34CCC15DEEF9499982FC3AA8AD99652+11064E76126C1547477BF305041EEDF1AC6F9E90D9AA0337775B1FE13D4A81F5+E9F41AD583C9750F5086B3922DBCC3859DE946FF02CBB01948C83B2799760FAC+4B44ACA84BA8D42C4FE6968BBCF4AD0EC66AC1309E666FFDB09F60A39C89B54A+393704BA3FFA9DB648904AE49469C2AF4F1A9770C7CB7E389E8845266922D4B4+F24876CA2713EEA5DEDD3C88A74D85809AAEBB7ADC7B9796732B41EF668B3704+BD7A5056FEB85F64787F545ECC2E3E8A3FFCC6AB7537CF1E74D913FDF6C62F03+C47781957E600BA6F73AAB5A238F15B37313DAB30F0BDF55BDB0CFC15B0DE91E+08817394000F77674B667A4F8E09D81740A020A7DDB3F51157FEE1130A82BC74+D94575996209DD7F84D06D8CD949C5855FE20F66E2741D04AB23139D772BD48F+D6D71E01E39DC25CD146D8820682AE5E1FFAD4688A00BE9571FC461D98B49773+78C85974798EB053005A4D8BCEF5F49F8497F4086561E2B964D023E98E41C0F4+FA1611A33DF3813019C7C114CECC1BE5E990B8CC2775651F6D8F438725514837+605AC832ED28BDB2390B5CAB6A5E479FB03E09B8349264F85529B62AB75B974D+61E9B1C57CDC79EFF7F018B0FA4381F2F8FA0C961494F3F29423050F2815ABC6+7AF0131BBDACA255D0D3967C91AD261D4137B7120AD32944C252CFEBFBCF5D27+78688BB54657BFC547D835D086570032164FCC6820C3863AA0A1E3397BB265E2+268EBF53F54391310553B1DE55E9D017428DA69154C0A361B6F8F2F051FEB0CB+03E791EFC846D5A9607CABF4B9F79122025132424D5E876DC8069A29FA92C16F+A6E4791BE64B15B5885450DA81286B8F0DDF14E805EB970A1ED62E0DA03AF60F+CF5A111E58A9B98BA00A6D22CFDE504ED85EE739EA6AE42C0DCB928E0CB41916+4BDA2AC5C5DFD523FE7168E0109191DFBBFDDEAE2278D28B7B507F5919662D3B+673AB4826E35FBB34E8E6D044C04C2ECEFA812352D328B5C96A0EC5169C9AB5B+8B9D2DF37175807D2E83A658389DD4ECF2E271AE027667736CE9A2035C07E758+E5E8E285AEB1CB97DF9D284969990BA0587B44DD86C4651F7750EE256A6E2D08+4547F53B1EEF8B7D410B667344CD8835F49CFF1C4CC619F214560AD7112F42C9+C74D619186D9C4055ABEC0C39C0F467FB3A20D26CB3A4FF9C0988BC99C7692FF+1B875E973AF435CF0CD52ABDF9D0C798DA1772571F85A9DB011CE0269CA0B1EC+1F2AD9DF515C493F636321ACFE7AE3E886D47EE86B9A76A464A72F82310BD3FE+5E33885D134C216570D71F88B9F32107FA74EEC3A21774610085478840E872F4+73CCF7AB5DEB8622F489F9B820DA790D35FB23367CF4751AC99A019CAE124A8A+126483C15E5D08CE1FB9E1279E21E2DE6E9B6FAEF614FF014FB252AACAE76BFE+F24B205324C9230F653443A2B0B067A1DB982ED19C921F55EB07D741D6778B7C+E55C89287D03B0A3CB65399BF439B7057648B98D5B2A341947B7FF5679A56927+D45C612258B03289A04AF5A35393847C3BD08CB37C0DC393B63005163AD7EBFF+C2AA544C9A05D87BD8A995E77F1DA2FC22E5E65B3C0FC5E437FDF97181E3BBB4+545FF18F9F70D9F49DE351B6ACC155D5589AA8F22C658EB93EC1872DDE6D95E3+41CB99D700596EE8BAED61AC16E95822B6CBA3D9E793029621557BF16ABF406C+46F3DD88B26C468A0D9A999566600DE97A0C2FF5064234535C397C0A8B081482+47BC11F127863B5D888010837CE5AC1B6F83B50226E3121DCDC366B77D7D330F+2C297CD4197C033264931208CBBBC61CD5FFB4B8F68CCE08661B6A47084312DD+FD03BE04D4E54CF3E0C34B94B33C3ABAAC0E4324D11200FB0302201E05E3ABB1+9F535F9AABD3A0C81B1074A799554B696CA720670CCF6540163F52757A74F098+62572B86F5E2247E58C7C14B4240A440233E9014C2DA89166B734CC4DD5A040A+4903535390AA227A72A4058496C33D52A89364BAADD09AF896FD588F53D51FFE+C2B1260C42C277780B5CDF3EF2460F3A718B5D1CC0D7908082D675C46CCE0EE2+BEAC95CC76D1229B3A07AD24714F7718874CCE89F471BA10DC66EB283C0EB3AF+79A31022C83EECD33AA75D47A65C5D8785737FB5A4A0884739DF7C24BF3FB875+711533849BCA297DDFE3E938B13DE209D95FAB80D215F3DEB29F66316BCEF371+5F06680C0D540C8A5A692560DF26CBCF32472D76D5C8FAB1C505A7C31D984634+40EC6B8E5D38C03766010F702D4F2AC1B61F0ADA7EB2C2FDAFB4CE93746268F0+DC95B7A04FFDDC618CCCE41A5C2780FCE367E2C5EBAB510C5EF81D360395E680+81278A499C9928375AC7CCD588C77F635361D2A7352099B3641EE9683BFD6ACC+6F6F51A74B6E21525A9B7DE06A9305AAB6A7F3761287341103EC128A918E4755+53F90F04371BD25554DB30EC9124B885111D78DB7BA76E93384CBA6548690237+534F9BA4D7B2E62296A8413CAFB1C2AE84C87B3925E52BA322F27E88215BD5AA+1A15B148B748BE3CCBB00C779BDE76DE1F80C6220570FB0B45FB66C347C280AE+E23071822B71C1C941E412E3D72E67F2B588193CF253ACA8D9F2FCE38954A35E+8D37DED50954B0389E21D601E5FD4B45AE2AAF78C0C2BEC3AF1CDBF0857496C4+B6B85BF64EB8950AB9FC56EAEE5AD01929928EBF023907913243D340272B8DE6+45C6F7DD4C61034CD1AF684DBB57A799DC40F0E4B733CC9ED288BAF504F31C6E+7C9D2EC971B2B48B58962509F2A1F89A42691683957B66C488AE3385C494C2C3+DC8E31B372CE774D5D143D4A557C3A85336231ED2D755F69C991AF10B2BD8016+A0FF6270C7F044225C8050F5436A074B8C589365B0846113E1A9E99F41BFB99F+5CEEB8839C03AB458EC4A5FA7FEEB94D22F1CAC668B12D24FFD1DFF4C4198F13+F655105C124F0A8ACFFEA56617C9133FF07F5A0469EAF3008944640CC7EDAE05+F9B5D507BDF9938D5FBC7DF2CE58AA64045E35409F039FBEA74D084B051304A7+0E00C2ADF7D0C9785354B9F483DE5CF79FA854F1DD7BD70A9A525C28104067BC+13C8E9E1A230ECAE00BF3D8338E878B3A1B9971234E29D4EC203BBC88C44FDF8+C762F7B72FD67E31B5ACFE65E6F5F9319EDD37122BD3521F909275F172B991FD+E14704060FF35C0A1116B8C169DC4EA746544C3BAB50766F557617650B17F2F8+43986C8CD8F081442EB3A21DAE020A8A24C732F7A5B9FD54DC2EC0EDFD9AAD35+FF99AB82738724988834245C026913F393ACF2124E1E69ED188244F79A63D994+AD6D9CC261FE8C2BBE3FD07FCEFA274E3296F0CC551C460EFAA4D376719E7964+567C057E5C1BA87954341F6BE8FF9E5F4DBD2C8AFB19B7EC76CB239C912B3035+7E374993F0A85CE52F2EEF0D546335C962BE148BA578FE5B8E8F8AE08BD27E94+3C315F8D9C6B872060A2447841F179697175ACB6D6D2DFABDF72EDE01EDDA7FE+43C406808FAD1B23FDD1542FAAE1E5F69F43FE9A2CE50315DA9F5D8ED722332D+B422580D085DF4C1BC3DC0013E91B2468A9360C8A70E8F64EA2C3AC6E179FD25+FD31D9DF4FAF1F2FCE81A949185A1FD11D60B5A879246295690E23B87D8BD93B+36A4CAD2B907935C13264E3212F8EBB4D8E6789452C54B7D1D68F190F59ABB7B+B3FF72161925A954B94E43BB058B63F2D3DDB838158C2011BA9C7790A9EDF193+328C3B4F802A5BF06C1F5FC96C834B9F456EE46C012F437EA9F6D5179F45F894+E1C04E1A9508007AEBC449BED632DB87492AE97ED579C4595D9448F077A00339+1437C6817E61EE402DA11DDA758AD837E56E2F038509C44B1C437134813DB70C+51E9AB830D378F7469AB962BF16DDA0B0DB858FA335E0106947F35DFF2555D24+9A91A1F71970601172B494964830B5808678B3532D1088CF4D97D858B2A74226+C118FFF34CB4F1EAB748302E53D6E5D8343C0885093FE36310728001F1640FD6+4C38203243B1C035933CECF2D1CA9E0D799FF1A10F59CBB4C64E59AD072B9AD0+CABA8C7A9FACEA40ED8FF34C1A9D769C0DB4C5540296FC7876144F795A68D05C+DD3096B7B9BC73B1B04518F2CDC4A55A67D6A18455ACAF1036D5F8F3FCA7F6B2+87A267D0AD57CCE61DB0CE0C2691C65AB1F1B72D9751C615ABDEDC2C96EDD751+5192666CFB313227E71CB72BED9D8DC552CF806AFAA597361755A83F556816D9+BC3681347FC74861C76C89BBD64EE8A8BA2391C4A8B7C9BE7A234D9ADD6C62A2+0AAC02D7657A2669309D8083B664F59DF2A0D301F92D26FFBBDAED386850FD01+200EA3BD8A8300FC51EF37E2EDAA054E3C56C6F4CD2760FABD5B6E298C4B50BC+2B6078FE07BAF2405D66BEBF6DF614520C5C15DF5D9F57EC6F955146156342A1+C5509D9618A698D50475DB6D0C8F656FAEC83B6294AB2392721B48AC9FB8272F+E136135A2CA42132BCD8DA637FBBEF7F3C32341C69D750CA36AC0B0134ADC67C+66749BA0977B3CA543898533D176CA8C19558ED541583F87EFD3A1650AB6CCC3+C54EAB797F91F568F8F25A0926647925065532A9B929CEA30BAB6116A83AF479+FB881E3B08C7FCEA08B0D1BEFE30F9FB0A51173614FF1C85524E215C0119B78F+37241D20103AE24AA8236073040E1198A996A5135948ED7F994E453CE0B36690+AC3A3DF8D052F4D81F8B58FB8040F9032E5E3285478D207A8BD3A823782114DB+D7C9046987A9C81EF066B8CDC0F12F19B29390E220BADB11EB59F75D4F075065+CE2641D24F70720E7FECB439AAD658DCDA9B6AC457200ADA2FB3C89792886679+A64415FB49283FAB8B84FB1429A1C8890B61DF5E8B338E15D067A2FC13C8CE2C+68EAC5A24C3FBECD81E58614253DF849714A9F7882413B6025C135FD7F469668+AF940CB665D5CF74E8AA1347949179FCDE3FF73416985E5033032A57B92607FC+271B90768E98AAEE80F3AEF606FF8B15BEE99EA5E248DA0ACCBE860065A87732+FFC5FBBB820CE2A12E02369B474F0CAFDC565E4D56E1B81DDEE6616D8066CBA8+721625130F7C8AE2587ECF2787066DDAE5C9576D804D73DFDA176EA9BB6EBA70+D8F7A328588C1A12044558E3EB1B376463064746B02F1978CFB99F06AEDE8AC2+3CCD85B57C0471384447A0E366D2492AAE0E45FBAA76E9DC74E3579B7630D9FF+DA8371F8852F9CA7C8A639C5A741FFA10C61B3CC5F4F6056DDA3D154818759D3+118540EE3411B75D435472595C1AA307AE9B95E77560C0DCEB8073EB9A6632E6+05225FA7D20F6C69253618681A949B2B818318946EFACB79A3AE04CAE351F992+0B82C6FFE79D59C17F619A19B737CA3524C175AA61A96CCDCE716B46B6956528+88D6621D6C17C77BE1FDF5A090B620F3A41C57215F9D600A8E3DAC8F184BDC2E+AC6FBF168E154034E0E484CAE62CE2DD7B41A294E30643619906852F6BF050D0+4ED4CB58A813A0B7361CB9A5B292128DA978961746B28E693D7F37940B3F6AE8+FF40BD4703CDA258C7AF6B75992D410A0DEABE274BFA9D8D019F5E8F526BCD58+9114D3F91AAE8472DDE19B084E25A51142A967DCDEEA40E218C5941B83F9584C+EA45FB285DC6391D8F079F3C7674D6E99C24F1A2B421CF7A7C50D2F016D44F38+F135A4DA44C7CAD4A50F41678D0ACC581FF3827A28082016F242B1C5705B43F8+2E799ED5B91C29F50FC86430F62ACB2DD52306BDB658F99E1AEEB225B5A70AA1+2DD4F028C544C7D8D0F49EC70EF351B99CBFD07D63D21AE92AB8EBF7BEC2942A+13D465606993ABE28EB3D5E46D6664B02E6058A926ADDC2B56994E1DEDEC8F44+F378671EDBC24ED0FACF0F40B186169708EB18B4B0F53473726739156A0067A0+EA4686C5A75F923EC4F7FC76227399C8B29E23D544311D75EB99A5AD843CEF0C+E5387B5A18FBF70EE9825C2B52BD3340892474B30F47A10CC3A6F762B4C3113B+DC7FEF96C220FA64FD656D80A2B006676BFCC790522A6714289A8AB926C86CA9+AE40208EDD4BE5EDA389DA317E5072051948233BB023EFB82734DB0627FF7061+B3E2C0FFCA65453FCF3D286C7F54D182E3B34B645C3A664007C4F6C657D5CA8B+5690233E06E624924FAAE08DBF1D49061860B5EEFEFDA2296F89846B06EA781C+5D84CCBEBBA3F340EDACFB3853A5465FDF05A36EF0377314D9B66B4998ECBEBF+131E0F8A5327D417A73DE943108082CB0F752CDAEB684005678D378AA5548A32+4FB0F012A7F0F129EFB5A23B7957C475F610B25D456D61562BD4934A5F57EDA5+D80E9F451C595087C7941928C4C7E6111BAB029DDB1EEDD9DAEF7A1C3DE37561+A41779DA057CF67A4C5DFDAC75EA692F17F3C6DE712A4EB412AD2AF8030DA0A0+D57DEBA089880468D2A0A523447EE765E43B521DEEBC7B05A1D8B9B158B2DDF5+1B7B1DEA2D6C655F783B2DF5C82C9373552D29648ACA45ED206BD4A3BCF5DE3E+8A0DFEDF95C1AC813701D87757A9318EABE227CCF2A50A20968BF2AEDF3B3187+BEB00C9A3C8B08A6E5BD48014F58406E54D65E885C2C80E20999C79C4FAF5707+ED69CF305726670AC005E0B3FDD135D8D2A09785776BCCBEFE78A71F805BEA2B+D0ED50393513C8EF09ADD2721E848AD735FE4DDE742C0084BBF5EE0127F81DC0+F320BB01FBCB1CED5B8068AE4FF81D91AD54B055BA68F78414C2F709A867F806+AB027E1DD7EB6E750BB607F70E0F397D529108D2A20DEFF173EC8A5252256C3F+7556AAD5E64C8B39F10E37539F4010644C2644ED9A229FFB33E392F7CA09EC22+E95486A1206F23235ED99326B0FBF04DA3744A22DB94FBD280DE2A77E64E7E1E+B9C1A11F35330F966544C89072A568277B1D2A49F0C1ADD88D8154A05076F384+E1B82039BFC0B91C23B0F967B153BE3922381319CF260C4D4612E6AFCC64484D+4F4AC2DE6FEA8E06AB00438F2105F3167E8B364EBB0871DF7EA97A8D7C141D0D+3A379708C513C3A52F4AC7BCBE6632A5D856049CE66F5E819FD6C9EB70C7107B+8E4E84B3A10342F347DF0D3BFF9251395FAFEB8CC629D9E9B1297B75E707F5AD+0A92604389B35E18EE2D458C21C136BF87AF9A46547A776C1F6195E8331D476D+E6DF03198652E7B5AB64A16BAC9FB8206EA8C25ADF415DA33D01C67EF08E1BD0+C55FFB9610FFD0BFA520B47F0023A2163BDF26AB06C67CF56889DAE98D02563E+A43C299B327F9124382BFCDA52DC34424A7DE5544BE723BC8B0F418A2ED327DF+A4E187DC22DAFABF668F73F246D1F2192A15F307BC886C7026E0DD07FB58DC37+69E30B1CCABC97C66E6B4E9677353CDCB92A57309E54E6D28770334D8339A2A6+60543A3248788D4839F4D8E870103F553FEBDC9CF13A106FC3FA5B2D3F3E2A2A+F1D3D550398B0DB3EE25E515FE2DA3B6B9C274092C063837687DA6025F2BF2BD+19649307820AA3CB4D7F1C1E4DB8717C69BBE360177347E44C411CE71008BDE5+3977A11760644DC71259B89EC6C30A07CEE1D14156F3E125FB0C849AAA9B88C8+97F3C4E2DFB703486101C73C151ABD9C475F252B9DAB6B687D3D5651CA0039D4+D828089D3F91138775AC6C0DB3298ED7AC61701989ACD8EDE5D44E07F784322A+47D95DC9C12F19E59AFEC0562D42B1F42A26EE53D14FF5185CEC967118407A53+55D21B18B30E75DA03FC86D623CD293D111A549E41+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMR8+%!PS-AdobeFont-1.1: CMR8 1.0+%%CreationDate: 1991 Aug 20 16:39:40+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMR8) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMR8 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 11 /ff put+dup 12 /fi put+dup 33 /exclam put+dup 34 /quotedblright put+dup 39 /quoteright put+dup 40 /parenleft put+dup 41 /parenright put+dup 44 /comma put+dup 45 /hyphen put+dup 46 /period put+dup 58 /colon put+dup 59 /semicolon put+dup 63 /question put+dup 65 /A put+dup 66 /B put+dup 67 /C put+dup 70 /F put+dup 72 /H put+dup 73 /I put+dup 78 /N put+dup 79 /O put+dup 82 /R put+dup 83 /S put+dup 84 /T put+dup 87 /W put+dup 92 /quotedblleft put+dup 97 /a put+dup 98 /b put+dup 99 /c put+dup 100 /d put+dup 101 /e put+dup 102 /f put+dup 103 /g put+dup 104 /h put+dup 105 /i put+dup 107 /k put+dup 108 /l put+dup 109 /m put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 113 /q put+dup 114 /r put+dup 115 /s put+dup 116 /t put+dup 117 /u put+dup 118 /v put+dup 119 /w put+dup 120 /x put+dup 121 /y put+dup 122 /z put+dup 124 /emdash put+dup 127 /dieresis put+readonly def+/FontBBox{-36 -250 1070 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5CF4E9D2405B169CD5365D6ECED5D768D66D6C+68618B8C482B341F8CA38E9BB9BAFCFAAD9C2F3FD033B62690986ED43D9C9361+3645B82392D5CAE11A7CB49D7E2E82DCD485CBA1772CE422BB1D7283AD675B65+48A7EA0069A883EC1DAA3E1F9ECE7586D6CF0A128CD557C7E5D7AA3EA97EBAD3+9619D1BFCF4A6D64768741EDEA0A5B0EFBBF347CDCBE2E03D756967A16B613DB+0FC45FA2A3312E0C46A5FD0466AB097C58FFEEC40601B8395E52775D0AFCD7DB+8AB317333110531E5C44A4CB4B5ACD571A1A60960B15E450948A5EEA14DD330F+EA209265DB8E1A1FC80DCD3860323FD26C113B041A88C88A21655878680A4466+FA10403D24BB97152A49B842C180E4D258C9D48F21D057782D90623116830BA3+9902B3C5F2F2DD01433B0D7099C07DBDE268D0FFED5169BCD03D48B2F058AD62+D8678C626DC7A3F352152C99BA963EF95F8AD11DB8B0D351210A17E4C2C55AD8+9EB64172935D3C20A398F3EEEEC31551966A7438EF3FEE422C6D4E05337620D5+ACC7B52BED984BFAAD36EF9D20748B05D07BE4414A63975125D272FAD83F76E6+10FFF8363014BE526D580873C5A42B70FA911EC7B86905F13AFE55EB0273F582+83158793B8CC296B8DE1DCCF1250FD57CB0E035C7EDA3B0092ED940D37A05493+2EC54E09B984FCA4AB7D2EA182BCF1263AA244B07EC0EA912A2BCC6CA6105B29+044005DDBEAF88E0F05541BBD233977A447B469F013D8535A9D7023CC0FB7B49+A95CD2B6F18935C37F49E9A73E97A8602C5C26EE13D7A04A188336FCAB4CDEE0+23DE9D803FD6E8D846B3F729BD36137E834E016242CD2F7BF048959DD45AD413+19B985D05E5D422F3D0968375EA6A90FBEBF8B42B15F15280469D69629C08A42+1C298CC027CC288B9C984239ABB96B6A891C1360D08F9ECC22202861E4CE9B39+8BF14B2AF3C30B82D9BC63F882FDC5737C4EF9C32FC3F1644F71D61D73665873+2E64D2387BFE326CD410969256C059F17AE1050BC3932509AB6F233A69CFFB39+83070F99051EC19DF4D269DF036DCFAC4370E0D2F5F72DF446162F9235095BCD+2F834D1CC6429D0D5864B8CF87A5F4B095ACC986B1AB5D705A9A654C0B969088+9EE40B33BDAAABC2C6374854D545BCB62EDC40AEBED2B943D29D25B2821ECDFF+AB8FE2F6D8512B4FC5D0CE203160B709634F7FF267DC03FF54728055D7F58065+F06A375D7B9B171BF74AB6CD35872C3205C7DD513D0D85C3E7FA3D5A09F41757+6E9798C65A25CCE1ACE7FC8420A4A3EB0D1081E0FB159632D1C011420DCF7094+7113873C46BD812C97A3AF6E354405DE6C3BF2C388F138E3632F38C91CAB3D73+9DEA600271B0CA2F44BAC4A759AD6F287C09017AF288DE68885812E9FE4230C0+C182E10DF4A921219B7D94A45304571B59F60AEAB09CDBFF8D07E3DD143968D3+59C04964DAA36FB3B2D8014F13CA042A3CF751A8BDDAD4A72BFEE6A99D00CE7A+5EEECAEAD72015F1A679B9D1E32F59B4B11E0B9B88A593A5FE4991B0C9AB0D5C+2DA6EEC7C52AE715D92610A05E3D11CF7093ABACD9BCF612F829FF1EB273FFBD+7D2660042DF733BB2C7C16E99BA9748AD71FDF6ADB42E6BD19858A374F54D203+0290B058B02D2BB9956E733E76B89187D4401FA10E3C01139F317D74546A4929+19D22F4E649955E089DB5B5D44CCB655129A3FF2899989A93D464008F8B56246+5962D3E0A9B7D403B8D4B8CBD7AE53B16F3827A8385EC3D1D9D264D38D4965DF+8B4D389343A94523A2036E0A0489C95BC6C266418D1019688889677363D78292+254A38FA50E2341C0414B8C7C8D494EBF8CB345FAE105A62AE035F21193B2BAB+55D945D5F6325ADC4B49021965572EE0AC37D0678E8289990D4B6A99641D04B4+79E7EDE23425BBD61680DE6596B2AF98DE50CD7FC2DDDCE0204E23B1D578746F+7F0C35223C50278D64E0F748D68AD0588BAD0EDB7091FEC5A310BE1F9D5C27FD+7E0666A426A6FA19C2BDC65BFE7D222B4444B253C148AFF044843A8A39EBC887+6EC73F3C7F5607EDDE66F3616A430CDD7AADBBA9A8B640726FC775CC8916BF34+300EEEA08492CED815BB5A7E0C6154C1CD677480EBF52976153377321634B7AE+16E3A18154DDAB76DE6EF29C86E6C9DC44F71BCB97479306DFE570A4249E88D7+E35D8DA58D055B4AA5C753857F2D5F4C09990DB841B4B96A9D083D420856B24F+99A305472F72619BC4C467B2A297C2093663C172DF0280E24F6BFEAEB49B2709+7C77A7C5BCAF3C14A66CDF561D796BB7CE748EF0DB0ABB20855BE166E5913989+359E2818D2360C481093D26A1C88C8343E4C280D9BE6F4FC39084C267B761086+4F596646054D53499AB6E24338844BB2796C5BA3BE7804E9F98F1744C2F7E032+5A28B4E700A6C49428910D41EBCE0620F83BFD79E3E29F6AC957DCD9A1D13DAA+9E4474D59C9688B239E225489906E2F99BEE7FA443C85C109AD47DF72FFBB183+8AD6BAB82CC3FF5CC7EBFAD9A5F0E590D3C0C76ED414E945555C617BD212AAF2+ADE2EFCC8D84ABCE42B448E78172A02F30D34DB7832924CEE1D9A6C7F59F3B80+A49AA254933654F33993EB9722D6A73FAD0E2BF30AC1F9C2B831B9DA66051E27+FA7EF2A4A44F2B666207D7BDBCF1F4F52F8CB418BB2D7BDA48B6CA0AE79806EF+91598CB48C647ACD8E139389FD41AB761628D86F90F2326557DE1ED6FF01BDF7+399A2B19A25221CC8998D3745BC333BA37AB962CB995D67DC3F51559757C7A9B+962D755CE2079876B6DC75C7243BE536063F1AC203FC1910E0007D115BBC592B+C3BA719D5C440799C8B71868DDFA9CEE2C69EE6C761AD6521F942E180DC33E61+8B14CABD0F5C67471D275D54D93178FE30FECA2ABF573BF1B428455F9E7E1177+BD139FA801BBEA6B602C8DA036C985F06014ACC933E15D2AD89C6BFFAAD9AB67+4E29012796D7AF6D35065AEA074729CB8F64EBB2785CD0967F838308DDC15954+F899196DD9C93CB533E18BE8BDF392FCEF0D6CD6BF2E85CE9F3F6C6434350C3A+998C39E2088302B94AEBD579F6B7C3218A5E3BAA9B247E63E41F1D380DC0B3D0+B275EE89CF1221FD6457E77AC2A4DA93D1BDE8CBB96D2BA40231D9F31B3AD679+B59B06A6BE90048DE418E1D278223571B5C520E4FA0112676132D0208C2265CD+541627FD533F2DBB7D388E21A8C41F94B9322AE0054543266179D98C96C412D4+B96C2D9F645C0DE5F7C05F1554327ABAAC542B13181DA1290DCC48B1402AF3D5+57736CA23C1357265C95AB7331140C90D82CA88F7A84F4A298017B4B586CCE95+6F12485361BBDE009AAD646D424EAFCE10FC8F85AF1C622BADFF5E66495BC56C+BB6EEE646D9AFAD36C08DDED945340E66EAB38BAB461165B3C6275FFA75F2643+D5A1C456F99D6D69BB9919B2E91CD67444FF3C3E8D64B7765FEBC784090EC08F+1ED2E0DE98280EC6B25220788246BC6870DA1101AA6AEF2FC01564CC438C3A3C+4A20B2DDBFA50B7D3EACF433F93075098E6973A7F7C66A5091CBA3FCB83AB138+7BABAB965C135DB20E7B4F7EBE36BE4B7E78353F9A46EC33A025BB9275378890+8B55D891C1791CDD05C3227227D3DD7DC59A4F2F98D13CF988D0C804FA3B2A95+4FCD540EBD60C6ADF58055B7EC46C169658B9306CC5B8BBCE4538EC74A81D400+2F1AB6CFAF235B6ED98A09D03F9D3A5E604C053F9B153B582C03B0EE3F3B340E+CAFB953F6D065B802CF4D5D8A8488338A0AE83D5D75B85760A1FA518883775D6+A6BB6AA7C9C45E55B5DF755E1359455EC7CF54A67FD7E7D6F9DA875D9CCBCD76+113EBB85DA51C9B44A0B9830403D1CE0574D01512B2FCD900217AA928E933CAD+E3FB78ACBE38188C80A1A0F45C4E1517CD868134DAFDE5E0F5290D4583EE1C65+984C18B55F46CD1704430474A3EF9882380BAD44FD8837123621CD50B1FDC010+CBCFED591CBD026A2E16E28BB1316331FE424A5F06CE89FA8AF1EA4468982CDD+757C0C77D1EB18FC47BD710F816E6840765A5D37A6EC04B364CF1C1F0116B025+F3347ECDE7BA18377DF6B6BDEC86B4459ACE511EEA4971FD324438B37984C4E8+6D1E1CEC0187D6149D76C5A34590E580BAC21EEEBD77570FB000935993FE79F4+AE15ACAAB5F0B3F26EBC234A5C21F6736D77DC1A954B720D6F5B6A42CA74CF23+0822547D9472F470F43A0632DF54CF91FAB2ED8AC14682DB2CEA95FD5E116B08+FBD4EBF13F670F7D3989BCDFB354743F636A4B0732F5CDEC5962DB70AC6F3D0D+8352839DB17C35A4C437F5D4B1453BC4CD8BB0359164277A9A986D2688897435+6089E9D4C05A9B483D4F1AC13FAB9D4023BD47472C9C4DFB2A75A6EE0268E264+AD9F67954A956AE525065DBCBB32F593BFC29B0287C877CE144C8E9C95BB452B+7A816FE8DE2B7D5CEFF1847CEF2AF809FFC3C490AEB65370650C7AA3687FB383+67A2665796D03F969F5B4853738E2A13BC96872C968F89B36544D6F1E2F09F41+764D559FC2C049AE375D61C61464525F1A0040FDE97DF6C430E55927C8E1FF41+C5B9855559B32AE2AA29018A527EBE0E8846905D5D8B6CB4CFE3BA7A1A6F4F3D+B005009642691DB7AD280B3CC7CE8E081FF706681FCD495EE37BEEB20D7E1C52+06B86A14F8352F4689570E37AE45F0F37E715BAE2AEB4E058EB39C28B1E3DBA2+EFAC8C34A99745BAE915218F95F2E29010409EBE04E7CBE643ECA6AE2580B87E+3E9095735E2413A25706ED4718299ADEFE785259FAFA91738927C4C34F81AE69+A27B69DF80F9F4FA85A3572BD28A6BF734EAAF1AA4F753062731969A6459DF9A+B10983F2E42306BDC6671BD8FC2C1ACD02E7AEC2D748F18673249EEEBBF4254F+61859CEBFF8C8A50F017E6750FE7BB4BEAF1A306625A220E24BD0FEABD7C2966+FE196411CA77FEDC42711231758B3DC5F194B3964E9AB55301ECBB12BE718319+FB63C52566F3DA4158D971E3406E504A14D8306E69FF896C2C34DB04C9C9C04E+AD8D81C34550246679C7D536B1D3CCC4BD9BCA78A79B44CFD0290FDA1FABA20C+0023F95ABE4C3F2B1777C603D98B8856C6A9ADBBCD8E9FBD52191A45595A334A+4B448949721A6734665BEFA5A029B5F9E22688650F8224468E083AF142B9B8F6+071EB2493BAEEB49C2CE928A3B1F6CA90C958091D8903DDF9FEDD0384B9DBBE3+1FFD93EC61505B2635A911883AEEBB96AA80A8DE4989F0478B480120EF95B436+0BCB263E4EB1C556FA9DB34BB662DE5308FA6C4BF40DF4F3ECE4AC83B4EDADB2+0AB8BA971A5A383A83C0B4051006ABE11F53E26147597E39BD59E0D6DD5F06C8+9C4999AA9A5F9778E607B94912BBC3DDB708EA9BCD72669F39BBC2EB2C9A69BA+A16FF47BE6EA36389B07CC4381E3D5DBCBC5133390B40DCC1984323ED6985D07+1D87EA1FDD2FBE5A8725637B42F5E56888A5BFCCEE264BE52726CF85852AB329+16ED7347CA59C888A794C491FBA35CD97716A5006645067991F13B01DEAA27FC+6AA1B4E6A4968FF3D9F5D67417FEEC359D0EE97EAC142504436B1650157A1E01+CC17804C0D73E4B7C4B30578DAE9FF37585A7C5274008935CD82763891E694EE+E3F5B38FF2C914458AFD7AB05576AB2AF1A3E82F088B8132A9C255E4A8D70055+2E6D99EBFEB4FAAF56F3866FF7F81AC261753C9038B6121ED55AB0C880993D9B+C86EEB280D2972B73D0048D201739F47BB28292058D8A38450B85DDD7F283124+159AF951BF6E382EF9CACA685E414CCB720E75103EB692153B843A803CFE640B+269E7A717872A395EE1C93DB28F7E91E5C335E056F121CFDBC0EE1AF53C9F34C+D2A23FFB77B8E5896B6C74F5DBA781FC585F5505C1898A08E0D55F42E7395F7E+35BA0C868E919C1B110BD3AE149196898DDD4B2700D7E4866AF9C11C754F902D+63D3BB72D1852EE68DAAEFD24F0CC4626DCD242CD0D438FAD4C649E985052769+9F60953F8AC1DC4F71C7527DE6E011BE52768C84D84F491663F79D54864C8053+5FD53AC5A4BA465079EA23F5123C062FF0DAD95B9D0E5459F85EC340E625A024+028CD7C866A54F3AF5BB6189E6F3DDA7756B19848C778C75BA65F9944E2C2F56+C2A0FC0C23F1B966B18F4E65FFCA972025D5022F4E2DA28A2C823E169B2ED791+4CF6E1C094AD8D9B3E6C7A3546D628C05F10A3F048C387549B0C64CFA8C83832+739D1DC63195DB760EF1F62C6DC22FFBDF222C603D1ECEE1AD4B613EE9772EAB+9E27DAB7416C3CD506CA024E66CE478F8C15A1B19095FC50C696ABCDF2F61D59+0D775F64A272A202913580562E51D5B08E7D194B21DEF132994BC9EBB66DA817+2178C0A5D2A46EB820B10F327FA390461FAAFC2F7C286CA3F0E66E783DB73D67+A64EFF2933F4DB2B4BADC32B4C34791631D791A196F21298796C2BC1868F8797+8D26CEC51AE943D11616D2FAB03FD98E574BB107401D42CF0F47E423DBD39C2A+C820115774E693F051D3219592AFFDD0C396B70D8CEB16016FC0900573FFEA64+7ACEDC880764A95FB45955CE3487346ABFD680AE01F76BF379113F0A15E135B9+7295BFD6A0FAC99096F7AFED37E4579525BACC418427F92DBC1D8CFA888095CD+8A46779F98DADC6F7BFCB81ED74F16011E28017B4BBF2820B0D977BDE040A350+5314DF7BBCDAB648913D22FBAE87BE93C71E9308E98E7D7B1D6CD53729B3B086+85019B2F14B53D12CCD57EA28B5B811CDCDA71FF8C6F211EE7DD25A30B9AF2CD+6D107A680B8237C3DDB410DE286582C571C11DB3DD2D99012D0688B2D03530AF+9F03C79C166184949D9A699B66CA9F9DB6C5524FC0D3214A7D5BE67F238E5AAB+160B894BAA7402C704D57A89FB009A09CF8EBEC029A0E884DCE3F693CCA30626+DAB89590AC987D7C92C5B9AB5A262865BCC6C39AF454071F9282908CC35FDF8C+9BFF67D032142CCF9055C7166C3D104F3E91889D7ACCDB5876846AF4F416ADFE+89654A024F99DD1349D426170E6C5310B56B731960037478FCC545E0D3D82A38+BDFAA352DA0C21A4207039C30AB5CB86E3572805785E0B1D99BE3521E2A7405F+8E009BFEBE20A67FE0D22D75212E2CBE1A51B3F6EF44B90B027BB11F961A108A+5F468D28B8F441E9F1F15B5C41A7EEC83E74CB3BA1C06DDC9A44EB58C88AC4EF+8ABB02DBD489AFA9F806BE180E4FD82241803B07D2EC52FD6D981E19229D4099+7AB7FF9AE9ED18FD299C7581DC09E9164EA303DA1ADD5994EA6FF1EB04F95EC8+7564C688FE1F92EF54BCC4B33A666287D7983D98F7978A845879DB4059382282+B07A42DFAF1CB873AC3DFAFBE9583B11BF1BB34747D318D9B471095605B0DFF5+DAA6E53527C81B501A0794F045EB04C2C28FC263C66B808A0CDF0F5E68C727B8+8E8C594A06065AC07529213B04D8BC831D0D25EAB4F6167709E91C666CAD0987+DBF9A9C79526ED48372065D76BDF1C28F5D3F33B7FDFE10E7533FF8AD3D095BB+5B263315E2C2829DFC3EA474026DB0DAF6A954DBAB5C158AFE58A577BD784966+153EE8836FB5B0B852DFFF130846EC237ACEE15E4C89CBE450F0D843080DC2BF+0F80794AF7088270EEF94FDFFE453A67189C782ED994599254F1B8305792529C+D9D714CEABB2F8360E22CEEBCD434CF0CF2D2C8B02C0BBEA99821C93C1DFF813+1AEBDA12F3F768BB22270D627B1316651868590EBFFD93497E3CCD763F5CD9C0+9DA20A3C771D8D2E3015D7CFFD239955EAE724A279D75137F6594F428E73B31E+B0F7A4D180E794E83AD330E996F71991DC89927E9D7B58D18FC301235D68D9DD+DA02D93324424F30DE712F69E1CE12DF98E86580AFAC03C014BB9F0FDE297869+062B06D5C008A1CE213CEAF151B1EE3E065482DD0B0821815820A6C71D81428A+6D7E71F933B2EC0354A851DB05AA363275C0A810D44B8B6C08AD05D24C80D155+B4465086F8E096A200910D5591DF16B7AADB712876A48CF4F3C1A587FAF30C33+5A06236785173B321AF4152C457C17D5A27B52D91422BE080C0B25E89BA365C5+1D98FB6A9DF78D0DB760D7FCF1F7A9EAC6E24C85ED7754D21DCC45D31E2F2564+666CDCE9E600E890DA4C316F6C7890824A8EEFB54437EA1C3137BACE8358860C+9B24AF9E3194BDA1511FFB0F3DE236AA260ED0B4E6E72BD97D2A8E56CB462D81+65D5F5D6704BDC5D16E18B444598787809E00AF402BFC8CAF63C1D0E67092CC0+30E6D0374675C3E7088EDC12406F976DCFEF3B1A6C133FF869D0E88D38921C64+AC31C52D5B87CBACBD1FE586F999ABDDB90A49B95DD78CAD40625A9E9EFEDC4F+9DB78AC4769AB1375336985E291E297CBBDD3D3F53AC99EE42870AF659CC1BD1+2855C3404502C1209934427452077B9173B27E282924415C9B37FC297019802D+9FCA0182C67252B24D8D7FBFD9B6519E4AEB160FB8F9E786F62DF8E84968B2ED+0C191E1DC2B666CCAF8BF03FF2CCD5AE4E98EE68FF27D7B10CF051754A672285+2664A3D4D79494ADB6ACD2251357ED0089409883265BB79BA0F317420E6B39ED+C9FAD82460D2BE6AFBB678A3D4E022B93273143D8F27C73812235A8E948D216D+017E4A2392CBA704FE76F4C1F01DE5245BE5914BA9D4DC594535FBB3BD355632+5C7B89BB69478D1E7E0621303986D38482FFEE4CE0049F7824F75F65F8F771F5+8B6461E0A989797DC2CC5ADB7686C8658EF367AA9834DDAE1C3B99E6728CF4BA+836AD11E39D4A1275C328F9A1A47C63516AC73475387EA931A511E36132A059B+579C6556DB826621366CD4ACCD2E698B2E349522B12DD8CE75762AC5F01BAF71+849B142DF2E0F6B788246F1F4FFF8A105BD2690B55CE83D6747D1166FE0802AD+7A6CF990CEC7878BF8E5D51E14A0AF85266AC54FF1A4CA12EBCD1B084D227EEE+928FA35A7B73A2913A54396A73AEF7FD0314FDF43AF5322114A0B896358DCD21+10ED2555D467C3D262E4ADE720628F9346C66BDEC3136B7836F4918A98AFE188+33B468E200399D99C5BDB4BC293650790EE1D85B00C3F1086C076BE0B0E046B8+C1D4383656C8A5ABC729BE0E2F372E9FB3A92819C019097FCD62E796CC09B8C7+B45E266B95489F5A2552C4081A49A6A79898E9A24BF6CAADE0D9083AF9A2A6FA+944743090C6D72B2D6C3E9E9380BA1694489C10C3CF41DBC4D45303BABC3C222+C5F15E8641B5BBD6CF2D9D3A34A5F52F41A2622707D0E17D1CEB13F0E9FECAC8+E560F3321A194C69E47AD9AAC2DD030820DA43C373B5F5E12286B7F32AFFC9C4+7ECF64CC2D1736A20FA15C68C63383A64DA0968A6530F8767BAAB035047320BC+C45C254D91B508AEA5AB252EBE3B0741E4060013EF79BB739C5F1B7A7EF2B604+28D1BAED003FD846065726E9F7DFEBE8ECAEB1C4AE5F22C7E6967FEC2AD99FC5+A84536E7C1C14A873146A845A7EF4A3681FDE36488D0BD69B954F1A974499807+5D5F9B26C5A0DA144D61AE4D2F38633C597D0BB0705482B5739DF2551DDDD19C+93B090985B34D488AA340EA5A0AB0EA0DE7D5EFA617C40109EAF918896D55286+EADDBB79B5FD830B3DED15DD918773E7104B24434DE57693454F767B8242B429+9B435AE625B2AFBA037E304AFA54E3FB1321827D813959520DA4DEDFC7675DBB+92E442D048C2A3594DAF1EC6E235A1310ABA6F355F62ACA55F24A5E52008E384+E2EC0793CF20875FDC65829351ACAA407775F1CBD25AC8E3CE45CB97E24BC32C+AE981FBB1B68CCD173D087600D04B346B3DD1927C148C41D245D8844818F8486+3364608FB716D8E40B8FAFAF43A6E7AA596A0CF994B5179E014F0F39B96D51B8+A88CE40BE658B4E6B850DED0C6ED96C34EAD4C6E0B99E6B5D701E51877257BCB+DB4F7AA959E4D80FDF52159B0E4EBADD349A90DC7C46D74B7AD794BB156C6FAB+35ED3C6D5DF12036C1E61246529608D11D610AC9D16BD403D47C92BBE1EC67BD+47BCF3A7864651E7131DD9DCDB21AC6E011F9DECA7252A99D3D5275CA472B444+5D764241A58B8FC251413FE5035C712024D5CDCAD51E17FE20FD13DBEE404B92+22B62D981929425B0762B94440F76AB94FC5C09FAD2904B6FBB540EFFBB1B811+6B0332274231EEB54BE207C925035ABC1B094E310CBFDE06EC66EAD1E894FA89+AEBE81AB94EE8884317809D97DD41F0A669C329DB237188A4A998D019CE7D86D+A66DC7A6AA1BFDEE007CE521BF4E4B2208BC074944C8B2B46A8712B8192025DA+AA10AA08196338E2E59C71996F0BC051DC0827C5260F261791BB82A2B7696B3F+E79F06823C22E2CB48BE3320EA16DA631F0EDCB800B23E5C7BDA8D8114CF29AA+643389EAE3F60F8362F4891950753CEFE1FC378BA590612B9F88C7D1380E9369+7D0D0F81923AFF0C21AE23C30EBCF3C25AB994893AE6E987DBBC1DF6B2D338D1+83FB59E306CB88228B8B923D4CF724D86F5917AAFE89BBCE9E66FF90283CFF90+4DF1471A9B6F759DFEAA68A31D66A5472B54EFB2FB36BD947E48B0531B883B3B+6E0FA342EEDFF8F2FCAB0F0DD74D98EAF69651A90AC0AEF3A4AE9357DB65F97B+5048FCE227CA5036C30C1AA0708EACDAAA191D2BAC6F348305D67A7A5FCB6F73+09632407B0AC8F99B335F2466CB2AE31A95129BF6D16336189002C1C7BD56751+CABE5C7D7E033C23406D4D12491D4024E3B183C435ADCC3BC682AB559B0BC33A+8D0036B5C9C38513418834E5DCBE1610117E118A032666CD3DDDAC9B7953223A+90F579EF3A64C342B6EAEC01FBB8EF91A2701B34D5DE3AA3421110CFD592E045+51024402F04AD27FE81232410D8F57508B2BD45C620919CD560D7FBADF35B5AB+4C245397FC777773D90CB2DF7218028FF78D2679C7DC57EB2917E13AE6BF8F46+9FC60D0A596F8615EF491CA7EC7A0C6BABFA95DD34A7BFAB776BF364E1AF3870+53B74FCC9F4D97702DB0BA88CACC279791B28A96DFE09DDCDDE0480E0BD94E38+1CC5C41C917BDB33BD5DC9855F4C1FBC742A8A8AE546E02A9138038410209B29+A441C652FF9C9227E7E6EA09273A0E3F6442B9B5C6DC014DDFDCC47396ED7A20+02052CD44BD3754CD8F17CE9D9FA3CFEB84AE91F2DA4FAF4A704402D09C6F19C+568BC5845BB05F78953A53EDB160308DE8A2AEEC9D291F0A8E4DE8FED9E50D53+862F858644A1B3791BCA7D61828A19FF6768DAF78B21A580C43E08E7C6239DCB+E39BDDA0065146ADC0F37426C1AC502B2DFE31395D1137BED8C0C0AC3085CB32+8BB213E43B946152774A204C975145488D0B6A13EBB1E63A44919941D4FA1BCF+87AC507462AB68F4C53BDD1C31E3481E01EEF7A24631B50437556B07B3C4ACAC+7C1E38CCD78AEE28975F1241AA4F7CF93D7E9FDD1313FA895B7B6C655FEEE244+4C9B8E92EAF22B5D57B0DB06856CC79FA4F75290591A66E59CE89A0750F84565+D41FD27703036AE27734A74CE995B7F00598459988C387470824B67030D59016+87CCA4A18FF987D457052F59BFFCD54C3860743AB90B42BF163E208FF9B92F33+B280F42E9C6A780A0D8C369021BAA98414ED562329F62443C0DFF93FDFB374FE+0E4A95D3B69AF4C8CB349B4BFD37778F63F7A5069B6E7532822B71638DD4638A+57A253FA275B210D56A2129C90D058F0D2A7E4954E829F41C1155BDCFADF20C6+6257FE35C847EBCF086A6582F9B0958D8FDBC5E508A4DE9185A5BA80C724B18B+2DA15FEE7725753B6E94D42F0E41BDF38222C3848C308358AA7CF2CF56DC69E0+91C630064F3DB6B25B1E10719AF3296A11C464C36F4F749C7A748E1E50CC4637+33E37C205CBB0BBD63E28FDF85579240A1D12F0EB60B9522C21B7535ED3DC6EE+A11D1AF09C8B0440FF69CF569066B2E82496C6BE14078D15712A354D31DC400D+829F3B202DFED5435B09EDE25E57E5FAE845C4AE6D5E7228CFA86B7F36D09068+B8292571521E172315103F3D9582D886FF7D3E3536490D052571C4E043F658D9+D9BB7D7BC52F0968DE84C6BFE9C70D27C9E23BE83A8507DA7FA580A292CF19B4+A4F583B9D5F6D2D44DAC2C2C029473AF8389652213765C853155C205255266C1+A93F2A3B22523997071FC0380E52676B4AACE4F20754ACE2A419C3F3FD7F649C+8DE18AEDCFF989CC675709E04A8CB060A05537E56B0FF7B02358489856157F40+DB4CD09EF6BB658AA5BED911AE37B3F94F8B1E365A1105D1694552AFCD3240F1+0A7AB4D2438409460D50325633CAFAE9B5AE21A81415287B495EF965FBF426BF+52B4ED9F63319DC3C0A9A0E77945F7CF676E979E358AFCFC87DB4B08D1F42365+F193DE6DDF5CE0E085760B5428250296174B3346E3870603174F6B20242EE3BD+80797AA9D3BCC3B5C1D1579CAA214E217D40556FEFBEB6E1BA3A6220600B0269+0CFB5F3F904F1909C46C90F080E1118D65228F20C40203F5E8A477F9FCAC2E50+F6F8CA4CB634482699ADC6437C24498A164066D30CECA4A89D91CFCE3ECC6E26+4458056B8619C5D5B868273AC529394344554E6C319BA40180A90755AB5E3B5E+EB53DFDE1C9112DB35771C4EC37F6162435B0B6D8ED0929326ABCB80256DB4CA+0BD3BECDCB5F9C5B7C7FDD4F4B662E21D789DA6A1F556CBE2C468DDB085477D3+1A720549D92115E097536CF6FC04EB7E72BD90C7E5B44E1A4CB2554819030D65+43B86A57DF5A908FBD796514F9D7A897499B891AFEC26E69FD0C748A94664573+1688B7C59D09B05DC005+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMR7+%!PS-AdobeFont-1.1: CMR7 1.0+%%CreationDate: 1991 Aug 20 16:39:21+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMR7) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMR7 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 49 /one put+dup 50 /two put+dup 51 /three put+dup 52 /four put+dup 53 /five put+dup 54 /six put+dup 55 /seven put+readonly def+/FontBBox{-27 -250 1122 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5CF5B8CABB9FFC6CC3F1E9AE32F234EB60FE7D+E34995B1ACFF52428EA20C8ED4FD73E3935CEBD40E0EAD70C0887A451E1B1AC8+47AEDE4191CCDB8B61345FD070FD30C4F375D8418DDD454729A251B3F61DAE7C+8882384282FDD6102AE8EEFEDE6447576AFA181F27A48216A9CAD730561469E4+78B286F22328F2AE84EF183DE4119C402771A249AAC1FA5435690A28D1B47486+1060C8000D3FE1BF45133CF847A24B4F8464A63CEA01EC84AA22FD005E74847E+01426B6890951A7DD1F50A5F3285E1F958F11FC7F00EE26FEE7C63998EA1328B+C9841C57C80946D2C2FC81346249A664ECFB08A2CE075036CEA7359FCA1E90C0+F686C3BB27EEFA45D548F7BD074CE60E626A4F83C69FE93A5324133A78362F30+8E8DCC80DD0C49E137CDC9AC08BAE39282E26A7A4D8C159B95F227BDA2A281AF+A9DAEBF31F504380B20812A211CF9FEB112EC29A3FB3BD3E81809FC6293487A7+455EB3B879D2B4BD46942BB1243896264722CB59146C3F65BD59B96A74B12BB2+9A1354AF174932210C6E19FE584B1B14C00E746089CBB17E68845D7B3EA05105+EEE461E3697FCF835CBE6D46C75523478E766832751CF6D96EC338BDAD57D53B+52F5340FAC9FE0456AD13101824234B262AC0CABA43B62EBDA39795BAE6CFE97+563A50AAE1F195888739F2676086A9811E5C9A4A7E0BF34F3E25568930ADF80F+0BDDAC3B634AD4BA6A59720EA4749236CF0F79ABA4716C340F98517F6F06D9AB+7ED8F46FC1868B5F3D3678DF71AA772CF1F7DD222C6BF19D8EF0CFB7A76FC6D1+0AD323C176134907AB375F20CFCD667AB094E2C7CB2179C4283329C9E435E7A4+1E042AD0BAA059B3F862236180B34D3FCED833472577BACD472A47CD4FFE5D78+D8A2086B7832F31FAFBCE074564736D2D7673D94DD4A77DC31AC2F4AE296C0AB+F044676C06C4C7389D83EAEB86999FC447B3FE644556C7134F92E74655E24180+F789C29579791407D3E1923F89331D8E2E186014E59F999FCE0E7A8A04375A8C+B267DC8B088882A496BA94CB22873419F4492DC60195EA32D0D5914A598829AA+24113B884DD03B5106B51FE3CE68D2C3EFEF24129C258D318614952809EE9D7D+F04505D3DE4D9CB0677734BEE157A3F649EC4D786218EEDA2305B8FCDF78B4FD+1B57B95EF295365CFBEC303BD9AD468511A96F22692C456E4F7A86DDC2E574AC+ECFCD9A2C13CCC5172E4722D34CF808E806390CF969B8E8A3DEB5FCC5FE247C0+54DAF98B4A974F3BD20B7A61556F7D59981CEF39B8ED96C07D4A6B632069CB1B+8A3717CB669CD1DDCFA148EDE466C94BBD3A62A5C66F88823CEDADF0964BE0A6+91CDE7C29C977F2F505AC9103BF08DE495000B06EA660DCD506DBCE55B0E1EA4+56C7F052726778B0984ACD67772AA82EB1C8042881B75EE97DFB314865B28F0F+D1BBFC3A6D7C48F3874A641FEE5D1CFB1C52D1A30499350B08D6F4A051B1267E+D3233D03B1A754B325FC1B63CA64ECD4A4C4832AEBA556ABBAA0D4BAF1960B3D+140E35F15BFB70868AA50DF3E144220EF983F84B9CFEF61E0D6CF7BD54C554BF+B61600B5168145F2BA9C140E86849DD2C6B190E4782004E021BDEE83C236FC4E+68F9154E4F24F6FCB6DBE864EA3FF215A398D0DE90F6FA7879BB52D616224AD0+C65543F07565E7A95AB08F6EA31CAC548B55A6216A22D004F9BC188F559D631F+8D7B0C4DEF80D7893E2E84F01B688798ADCF5473EF9135EC4BAD90EFD52764D6+C7CF7E38747CC91F67D8D8135FC3E6F7A9819E47D39CC84F153480441FB453BC+EA52121446C06D2588D59E07CF0DB97389F5997B8D867A81FFA7DB8D69EA9F42+B95D821A1CFE2047E9650B8F452E49BC04B3230302BD8CFE436774FAB82B7706+516878E186B8C599BBE96578FB62F2E6703E248C017AD2A2B4209976EB87685D+DDC9CDE03FDE61641B98A2110201485F3BF95211D0C2618CEC42AE0D635346F0+95302D059AC126F57E432F369006A26DCF6675377685422F39E4D15B628EC9DC+7C20BF097B9F3C58AB72F26B7DD76A565B0F589EB5F0EB05B5C3ED972A22CB3D+59322E1C796CBE47997CE66D972995FDA937CDB04B6CA2EBE7CC449DA9139E28+B582FBB0B130F1D3B9EDC7472CEBC2310E0E7441CAEBC64E2D6A90A46CCB93C6+9AF9AB8E861FA4CF5A93481927C12E91D0DBFB4EFDE06C7907D373B054460298+CEE5987CA18F762B66C8FA2C8C46129F29E44467DCAD31A41905B33B4F292E73+86EE98FB22F4C1413C287E9101A329F1161DC6E5126B76ADDA245CBDB9ECADF3+561326E73689BE900EB53CF0F8AF0D239084B3E73B476F63B2CEB1596D827A44+718D9DA0A03089237BB8FCB08E06C11E5A595CF34DF508738F841450728A5455+94E68DC3FF1FC34D4325322B2E3C4CC0154D1C8B5EECE8D2831DBA9C820D0AF7+4786331A24792DAC8B59504DAF1A4DF0DBBEB6AA8863FA0FD1752C954C3EF37E+5753C71BCC3DBFEBF51809CE56B33DF0D56342FA6F8B5EFCBF82858C85DB6A08+E7D9450CE79E423BD3D732F29E91A68704D3ADFD2279447A8502423DFD6419AE+81927E269C2556BBECFC56AD833687DA5BE86E2E6A814705ED822078D14C3015+40D9164EF58BAA840FB4F16C67F1EC3633BFE389D046A4395827C219E0ABE55D+503D1260A24CFA7ED5F22D83B45F5435FD3D83B4F518980A4B8B012A+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMSY10+%!PS-AdobeFont-1.1: CMSY10 1.0+%%CreationDate: 1991 Aug 15 07:20:57+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMSY10) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -14.035 def+/isFixedPitch false def+end readonly def+/FontName /CMSY10 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 13 /circlecopyrt put+dup 15 /bullet put+dup 32 /arrowleft put+dup 33 /arrowright put+dup 41 /arrowdblright put+dup 107 /bardbl put+dup 110 /backslash put+readonly def+/FontBBox{-29 -960 1116 775}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052F09F9C8ADE9D907C058B87E9B6964+7D53359E51216774A4EAA1E2B58EC3176BD1184A633B951372B4198D4E8C5EF4+A213ACB58AA0A658908035BF2ED8531779838A960DFE2B27EA49C37156989C85+E21B3ABF72E39A89232CD9F4237FC80C9E64E8425AA3BEF7DED60B122A52922A+221A37D9A807DD01161779DDE7D31FF2B87F97C73D63EECDDA4C49501773468A+27D1663E0B62F461F6E40A5D6676D1D12B51E641C1D4E8E2771864FC104F8CBF+5B78EC1D88228725F1C453A678F58A7E1B7BD7CA700717D288EB8DA1F57C4F09+0ABF1D42C5DDD0C384C7E22F8F8047BE1D4C1CC8E33368FB1AC82B4E96146730+DE3302B2E6B819CB6AE455B1AF3187FFE8071AA57EF8A6616B9CB7941D44EC7A+71A7BB3DF755178D7D2E4BB69859EFA4BBC30BD6BB1531133FD4D9438FF99F09+4ECC068A324D75B5F696B8688EEB2F17E5ED34CCD6D047A4E3806D000C199D7C+515DB70A8D4F6146FE068DC1E5DE8BC5703D288CAFFEFC421ABEC649FD87E34B+8152B84EF6F2F80C01287BB5420043D975C294B09A974021BFB8B2BC0E1A7437+FBD84FB8A0A62727F0FE7E854E8DF91FB6C74A6001DEC74BCB54C02D6672BF04+6DE245BDEA78D19C1B025238395ED3BBF685F8475B902A00ACE9C7D0B4795509+78A61A1DFF22EDA7060362C344DBA8461968857DE16BF7E99D314651FE132F44+A25C3A585EB7534C1E1FF2D968FE939C2CA318D3698605EBBDF013A5A26952FA+1F8A97BFD9DCD05F8763BA2A48145A1D2409CC240162AA704DDBA89A33354EE5+5D17E7F0F6FFF96A8975FCA2DA770810BCEF856BAFC8278837796429152C65E8+0E8896CDFB27403AB8F033EBF7437AF2C6ECBA7167F00D4A13A8C5FD7342F810+7CA2B94A31CCB7D92C6B9342438B1DA3F756F4E6E5B0107BC2EBEE4C2F9C6BB9+0B3BD0043374B81CA1EDD03C4703673A0167B111483D127E09CCA21BD4FDF3C0+398DBEBAEA18C18A98E793A99FCC07F4033E7F2BB4DCC14776392F8D87D5F812+CC1382283FD52261288740A31DF0EF1437FA067770DC0926E9EB9CEF14C28AB9+6E80E5B46C9914ED4854D4C4040FA8A8D362C7B87619C06830C913BA2724BBCB+2A3A7C268F976A6CF4F5018B2D5A76FDC1B3FBCBCB26485A3E0BC74A7E5619C1+6B35C97502377A0CBD7D07AB06F6CFDC18140DEAB29336686A01DA722E96AC27+F69B40E2E6DBDA79ED97D75ED87FF6D1D059D1AA16B60DA1FB2C5CEC665EEE21+CDCE5300AD2F80E4FA8C13E9BDEBD9F2E82B463C3BBF34C27174A1DA54C95F70+F0E2F61490D92DD5455693FA3D2C1F364160DEB97E87CB8B0FE792A08CAA7C0E+06565C61A40AF0FFE2C5D2C2341FF74E174D0C29EA803E78759A5E7016C4C30E+48A487FE5AE32086519EF588C817BD1C5E562E5D5FB1372FE3B4BE2039E5D73A+689F933A4F3FA33FDC1D142B7BA32DE865DDF3A0CCA0B1956BF2BB559132D653+3C8D26B34FD2EACE9313682A46E261129A827C05FF2FCA0F972AC8C7D4FD92C3+6BCAE59F37D1DCA3333B99065C97687F0EA16252AD66894443D1B24E10F622C4+A60BF917BE8B62A4F0DB5FB26884538354F2EB02D5836DB82D9F95880A1041DC+639CA673AEF3AA29CD16C90863FB6696BFDDA10C6C3718CC8CD832072ADD8129+7864358DC30B5835A2637BE00FBED9760CABC52C6E1894A06C89E23678FB074D+C93A0F1AAEF16769443EF72B95ECCF377B615836F92FC28A07BD00541A78CB41+5BC7C0194EC2079E6151467AF879E61B2C58B602723D2DDD04DB97BC0F788087+30F859EF2B415DF314FDAFBC2689884067F86CF3702C5142E44424D22DDF9CEE+B502BAE96ED03025176BC5D4E510A3162138C1F3E3FBCD60A691028230+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMTT8+%!PS-AdobeFont-1.1: CMTT8 1.0+%%CreationDate: 1991 Aug 20 16:46:05+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMTT8) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch true def+end readonly def+/FontName /CMTT8 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 45 /hyphen put+dup 46 /period put+dup 47 /slash put+dup 49 /one put+dup 50 /two put+dup 51 /three put+dup 58 /colon put+dup 59 /semicolon put+dup 65 /A put+dup 67 /C put+dup 68 /D put+dup 69 /E put+dup 70 /F put+dup 78 /N put+dup 79 /O put+dup 82 /R put+dup 84 /T put+dup 87 /W put+dup 97 /a put+dup 98 /b put+dup 99 /c put+dup 100 /d put+dup 101 /e put+dup 102 /f put+dup 103 /g put+dup 104 /h put+dup 105 /i put+dup 107 /k put+dup 108 /l put+dup 109 /m put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 114 /r put+dup 115 /s put+dup 116 /t put+dup 117 /u put+dup 118 /v put+dup 119 /w put+dup 120 /x put+dup 121 /y put+dup 122 /z put+readonly def+/FontBBox{-5 -232 545 699}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5F0187316F83DDE3E2D27FCDF6C5CE4F95B6EE+3317BD91B7921F3039DD35FEA387D5CFB6C6E9DC84C178F3432994FC7FAC6E5A+ED41A1E2EBA350178FBFEB45944511731BA827167DDAC238FC69A5486B995477+C469E2E27493B0B711DF8E267D3D5613B450011921685147114106C9472580BD+F531022F6DF5432B2A4EBC51A8032C7F9689B6FA942D849B29709631613DA68D+4DF7B6F059A19304F40A3C3580CE3B51D79D42984194D4F178801720892FB6E7+61FF43C63F9256B5E9F4227B1378222BAAD4D52C77462DF01892220E11129C16+6C9E45BB9F01ED7C1AD5D8B4D72BE0E12969AFEA90FEF170603CDB91CB243173+B19A56084D10293B80A35275F41BF78A054DDC98F4A1FFF592463D944960FB31+6BE5F03960F9B1F213CBCC7FD448657FE388F10104D42B0715FC9571CC60CF23+C72560CBB8835A0CA208FE06676B3B48B093CB7FB2C0C53AF17EC5B372A9771B+BFD52FFB7062B4FE0106A01A2A1A1DD4EF5C8C7623EC9324A2CB3B402FCC1FCE+52BFC8662F8A39D5F1B41C97E7CE34E16AC28A1E94007AEA7D4C519399F1B7A9+48FA7DDB671067244F09C29F95DD60668223F45BBDA8B1C452E930A9F3F341C5+351D59EA87462FFB30277D3B24E2104D4AAB873BB2B16DA5B23BEE25BE2C8128+C4CF2F4F438A4E520CD864F3EAFB5363753B82978F6FD664A14E5D6F3A929348+5839EA752FD635619C4FABF1E1454510BD9D6B538A343BE748AE05B47F917367+1BA5EDB15F1BDBE806E51B294257D7087334165419A6520462D794D670A1D6E1+3BB03BF689391D056D55AD660D15A386E6D222C9572BDC4DC8A46EEC75124BB5+F0E8978FD6031A90E4768CCBF62A5ED8C8087FD66D2033011947634878BDC0AB+6501DA7E6D96E227068E993DBB0072F037CA4112F5EB7D630D541F4BD38DDC44+20AE405F0321C26DEED0D6AC82683F260D23CB9446ECB7EA8A383AAB4DBBEB7F+9D86CE5DAF4FC5718AF1B896B641568DBB7964D54B9B4F60A4D8E87D3236CB09+B48E618D22A3E109FD44BB534DB77D73DED93DA0D8FB5DBC11776CBEDE459B67+B5CCC6AAF01F1E90F2EE643D9DC8DE7A13D222D640D3A9B435B0D71F5403FBBD+B7D564144BFAFA18621F328B1B4F94625EACC6A514A92980CFB4CF48A741971A+956EB2AF07291C0FF73EFC31D0D037BA9D23811E7C7EB1D3DDF351260DF0A89F+65B9250CD3A458013011E62FF47FFF2E49AB1F4CBC9D6C95B1189194AA7E30A6+7FB8B79CF9AB0D990744D6AB475E4EFEC4C0AEBA970FF3C49B41C3E7ABADAEB5+398AB52840CB363351830FD546246528F81DE6233C25D62373C3BD3BF260EC6C+7100A38CA4DE2022C0D170397B239884BCFEC99FC78D17397C11A7898AC2BCED+56B82A4E2C7A8609F795BC98CD632BB48BA05CF526394617CC0B6E653377FB4C+DED16966EC97A64F1C3F9B807805634B8C137FE601B82A114DD624E7095B0625+0C208409F7A66477A56D05A23D4B7EAC4E9368D9CDAD29D490936750E5200A87+D35C612FE71529CB20E6269710B19566F782B4B3B90C41685402E787CDD4AB1C+A41556EFF079D3E3BAB19BAD10C287F9B9602F53123E724370E38932B197438E+B2656527FCBBE872255783D2CEDD4358DE9C776EB3A5DA0F2F2DFC124991CA86+6489F4BAE8194E0414E9D8AB5A3CB4E5D5086D1C10B0109B933B0D4065EEF6AC+500E65E78FCC82F2F21792CEB6B49BAD848F188D1D164E725B3BDAD975159BAF+00AB06814CABC75059768AFB49DCD6F7449073EFC6C9E497E2391666C7943046+5E1EEB3FA3A055D7E177AB10747472D0E79584FCD96A25E074099189F9CCEB18+E234FB0321F362EB7C06D5E1F7ADD98C3CFBE66C2E4FFF5283A01B84785DC763+0548050567DB1546F63810F8D697832E5E755BC18C7028C1C528917C4114F6E0+8C4702F8EB3E6D922E5C626C993EC8813FA79621B7EF92A1BFA6516EBD74878B+0438D4CB68BB27940165BFD5F3AD7EBBB7E1592CD6ACE2A08B8C14ED33692A6C+BD13ECCA5072100CAA0D125EAA8FF08F1E3BB9A45D418C65DFA89E11C2FD762F+DA3DD61F5E9A50B1537B4D3E142D1C2F035C8EA9F0B4261DCDA952629B56CAF5+9E73C5291281E626D36B164A3662B5831D106890090D8A9590A58E56E392B1A8+5EBD88F5AD04B93F87C138907E675F105357C9023892562499450A7EF59F492C+705E1A97BBFC758D01ED199D6BD0FC43DB1EB47210D99F16BEBA0DDD757F42E1+D52671E2311481BAC3B12E1381C5E16253003D62D8BF0E69A88EEB7480FA09E2+A451DE0FAB5A1A095AD4E369B90E6321917E1F3D99443982F0EFEF5ED63E7990+E89D99B3432322ED8ACF2B9D3961F4A5DFAEC9DEF3170B1FF08C6578E6BA8A68+2803A59A4404232708B85D0DF7FC59A11A5BBFA16A816B0778668CC76725BC85+C4AC747DD03D649DE15FB0D9A5DAA9C36827C19D65DFDF8F75BCFEC4E8A2C490+B2C063700C9B984962CA599D76A5CB231EAAFA842E31400B57CD83E3D4BC5E56+CAE791A8D0E43C0B561265482D2A20CEA40B0A961FBD3BF7CA480234F393E1A3+7EAFAD7C5698F5925DC4D7A7291E3359664F7E6706B39B4F31383B8DD913907A+734CD593D41AD6C44627F467BDFB9C7FAE63B765E3337AD04C3F400406C7F880+B9006B1800085DBB945EC154E974019A6C04D4D3765D849937466267D6672D26+517F54586795D547071464A75291FA46CEBE79FC4A43B0054E36FAD5D19606D1+B5BB2C9B3E250D34F47E2B75FE6FDAE04B0A4C2624A8B90FDFFFAB78B0623791+6CA192069CB94CA9C6009F9769190B3B4A6A8A824ED5A5C61577AE2039F970EC+815F5D1B7FEDE75581A3154D8FE0AD4A3FBBAD0F8B1DC054ABAF6B48EE77EFA5+6E5B45D49FF5FC2BF7FCC420823EA88E01653E6C11DDF8DA59FDC9FF7DAFC3AA+B7D54CCF3E8F921DBBBF60E0D564AEF8ADEA0F3D84A270E1E15021418BC2686F+223DBD42BBC8167402F5EA10A5F0B869337B8E6C2C01FA7E5F0B739E0D879071+0E93377106028261ECBEEFDFC896747CF9CB85A7B4D52BE3FB595035A383C01E+E6881839028D7EAB060F89C5CC1B919BED6C6B4B56895FAF05BCE0699229D533+349B7C58903027FA60501A56AE6BD79A2F54C880BDD9CED2B408C0A79E6E7985+01A93916CC1BB84E96470B81B5FC3BEC5C1FDA120B76FC8D969DBEC299DA9107+0AE11E6033D7CABE1B4398357FFA049AC542DC67A3F5649D5164C49CE9D03ADE+25583AB66AE6D4D87616C2800B959135499E248A2B06BF1C7DC20B732AAB4A39+2C847329C48628D153D16049189CD0EF0CCAEEC8677B40C6262278EFA6E300C5+1F6D752AA92B51174504B34D0E8B95A6FA8F1A3DDE3323ADC44E67D67E06AF12+BEB9AE86E8069AC8C75A55ECD51131BA8F3FB0D61A9D6BF1567C088131B66BA1+52A6ABE14E63FBC3BB63014692AA5CACCE2818DEE6905B901E9B3C6369C7CCD6+3EB473FD9796637568B128BD63F8C54E8972321F3DA686804A16ABB45C90FBC0+DB82D48806219B12E32E4BF27B686B20469EB49D493CC477F57377E460AB317C+CB807627C18728E2838182A5C0B6FD23295F8769C112995C83AB1C30ABE578C9+EB12FF0E3B4745F055FCC98DEECE1E09394FD8228B6EEB81C74A4CAC1FA18AC5+77AC39C168F3D6029E2E029E9FF2932CAC3AA7ED77675F3990C2D111A7E38C88+0F3E685314291B2B0E031D3BA4F745DC04A3DE6062DB41E6177A62DAE94B7DCD+AE882F0CD488E1BE39421C4241EF63E0054005EE4D6215C408EE241C7C11D7FC+879C630A5124DC997D9CD4955045B1314FE3E7ECD218C4F424DBB65C55DD6347+2AB6E3E1F2251864A639DAA3AB2CBBA7D26A5E9A17979DA76C75532D2E08E097+149CDDCE7056913D84999F00DF9009BE8D44574FFA91FFFE40674ED830559BCF+B5882F4C2A2C4A310EDC6B137C6AEDE43E8B32843C5D17612505621686346F2C+6E78E2FEA952392318B836901E6E1BCBA9C0497339C9F9F02212F001953F17B1+FFC1FE3B32700F3D50A6E3D623A4FACB0F1922CD133C416B5FAF5A07D0B8D739+D815A9B54C8B76630D7129748F3F5817F45D381C65BE1412422872C8E1C74549+F58EED6CA1788C6BCE4725FA03A91B464A440E43DDDB32A88D8354CDE75304C7+55D1078E72E5DDEF44DDCD00C0BEF4F42F596B5DEE8FEB04BA80ED55342ECD8F+DF7E1D9E2EDD4C1A8DCA1B5F5A790A6855AA3054C8A2CE4ADD288CD86CC2FD56+5D6726B7B47D633D91BD5D6E0611406771872D186D74499ACAF2DF4B7CBA6D65+E79905C381184B970E3FE2643DF97D518D250D0EF610831FBB9090DE5775C371+0A963B25505A03E220D8123C2F78A6C24F87C70A445FD59F628A994AD795A979+BB6F158C3F1264F77AD3831A9944BCD430FBFB4C45DFBE6D87E36A8805597473+9E52E686D504022B8EC4B5C6D671973F065762625054F8DB68A86A184AA03A68+33C7685C3315FC923B4559167A19F26231914599557A627FBC1AF3E8BD75E0C3+4D7742017283A81EDF01670CAACF95C6A853C75F8A82B5DAE19D90D4A26AF6B4+BE9A328A16C0676C58CFB25CF2879DFE5B8E7832BACCA0CE02A612A237EB7597+734FC5AC753C78100754E98BA47E65990697811857BE6F68C88E48C632688A75+C977952BF1A043D70625EF69B4F5775343CE08C1257A7998EA2F79FF7B3E927E+BCE10A1291017F2398B953F362D8345D0358668B08E990D16B441785751E333B+368BBF3B300F7C93F21795D0F19B71738B4D35286A874A02A1B7027175E8C829+B85D986793FE9A6625B1BC9BBBC37D80232768DB1A595FA38F367579798ECC02+5694DC26215822ADF116A7CDA0EDD70719C13F3186E8D493F3A67CD9B4D92E18+0D9DE2B676E7FA014735B908FCF9D3D8A3BD9283564E6DB2DE30E99598A08191+7B2EFC4F076463517666E21D2B3334E864FA0A776BE179F3FC2D99D786B3567F+5F2D8388C57823A8C573347C31AEA0CDDD6C65D4678CC1857BECEABD4B51A0C8+9FB765672F5B53C5C2A5E44BD619503858BDC9F036A59EDDEC975242F3D8C4E3+89C8EFC04DD9CE0FC5EE412AFCA88C7ACFDEC8EBA91756D73861CAA2F8728BB7+88FAFADBF507202448582C8EB92424FC554C25A956A97FE7A54B859A3F12982A+7DF6CFD8339062906297BCD1ADBCF5E94E463968F5C49502F02CEACECB1E97A3+8D2E1CC4EE3EFDDB918CDEECFBC1D80022207C36AC1EE101C7549DF2239AD961+09D086952C535749DEC1C87D722AAE047756E06124423D8288BCA75AF9D72EA1+67D6B6FD2E1924C24654AF39A647EC00D15E3620168B0A22D4177E8F6AE975DA+7D3056AC5664BCB58704A66675264043E781F2730E4CD7515A17F0257FA78C71+CEAAF1CA0294C78EE95D937649940D8181D8C2DD9D986284CFB5F755286966D8+1AFCF6DB31F44752E75D62A1216CCAFC9D51BFA0E8B2E76C20F889B4FA21B776+D10472DC46896C6FB5CC475ED25B425EC5C14E6BE93DAEB4D3FD19677615C08A+D5BA14E6E3730FC43830203C5F2913D38D6F808DA6D719E596420A0B7F089A38+4CB1817BA3C48817E98F755182FD7900991BD29852B57E99115F194DD50B2D6B+F45AACEBAB7E9CFDB794F4A9A837DAFFFFF92B391DF77CA716113BE2CE1E9F05+B808104A11ABFF2A0CCFA92C21732D5FEDB41FD1394F9F8DBB5550F974FEACAA+C0584EA2D8955163DC767CC622175B9836056BE5CBBF3D88269EBAC9A0B65632+052C2F837B8ACAF28067C23E7C882E216E78EE88B99DD03D110C805821667610+2B2978A33575D195BFD68DD950A7111FEDB684DB02F37AF64BBD3CC24785B6F5+8C0837A428E8FAD9ADB37B9FACF7251D3D3289A07A2C6003981A984CBAAAC70C+E0A044491348CCE0C6188938B079F9E773CB68370A9B8E202513902783E81630+10484B74E6D09146EF556B1B79C6AAECF5CCCB066E2E48D414B86606FFFB6A10+4086DC6F74073F18842C266F3091950F34F441558CF90B165CEAF0FA38B8AE3F+CB4AEDE2B2393898C5A7A45C0DA65747AC7A35E8258BCD3B84EA34C73A951D99+8385518077D12B77412888B400CD625869CCD4B512440D607A1572AD35DD2214+6663C53449C097E4336BDD211D71E99CB2D61F7BE280F22DFC16C24877FC57DC+C611B49B0103F16283C4606AAB588A6811B6C2882D765B1675E5C5912A3F7B66+23AF96AF166902B9354B58F27F3CE7F1FD38D940FC1055CE26FD98D90032B049+2C589732EB90D2F996815EE70CA5B5B2DA95D801FF575FDE2D831762E801FAC3+223231E020A6BB64BD3A082D64966725A722D9EC9FBE17872B657B67A0E28030+D475B59F4B4B43DCA2B85B397A57D0C844BC0E10FC72E1D6B87248C358055841+CCDA354ACF75B9EB289C11BAC418E3DD1235A71F6646F74B063696366CBB2771+9606618CC5A0C0C13A048F3CE11544D2C5686F77650291A1ADA19A4DEBD8987A+110B04D21716D9B9DF2789727F163806E5548448BCDB6EFC12068AC66098E1F1+063A5AD509F2CCF52989C6D1BC8138E940CFCC7587E4B531A01CBE6E30D9384D+AC8A75B2CAFDA59E8517345B56D0E95BE4E34427D017C6CF1C571BF4B9408021+2F2085AB7DB61F98C7DF95B8CE2E525A25EEACB25D54D2C0517A591A4BE27E3A+FF0DEEFE363E03130DE69675972235DF728D6829D1A72DAE603707DED6FC7DFB+3BB0A6AFC11CC64A9FD2CCC8F665B991540B69DA982989C29FABAFED5DFED450+E505F80F40E94CC3DEDF8C6D3AB7F49385F8F8228DF5C2987CAFB5DF642A6FF7+F426B540B2B42A886B6CF04574046CBD1A4A363365E49B228F9C81498008A7CD+3F7043EE4919A7C138EB00106084BA2FAFA2D835C2CD3F4C07D85229DDE62884+C44130574DCF1CDFFE9CB9B3E2BA97BBC206E24031B12CDF3BBE143FE6AD2C3F+123B8259BB6EA11336BBACD2F14D241A99D66FE3283B43E1C552096F4355CB79+5C0C6AAAB0ECC1CE2003E3117C137DDC2EC48135316F6624A5B3B916D2CC98EA+9A9DF9F60E2A2B1236E7E55BC6DD0E750A4244D2A9B2B2FCD85B6AAD9B3580D9+A52638F1CC6593E8A859E27EA477906C0863ABC55765D7595151B93BBA74FC27+1407C251FFDC1217C81700EE7F9C7097394E749AE7478A4C89DAC67EF714E94E+99C1DBAC2D1DDE84CBBB1A3FB9B8123BD797979F3C72509762E25738400605EC+740FFA8F49CE5ED4E3C19140EB1915708AD69C18B6B04131BF12C0F44F93BF8C+15F3BDB376C993643C630F3E973733B3BD4383EC10CE3D33F46A5CF69833025C+B0EF58F7101BBCFB1FD55986DB202DFC6B6C378562B74C5C0F2433E79E05885C+260097BF71D49BB848C4187E982C1EF43B7DC10482DF7FB0FA3DBD790FF8C169+B78F4C80C0A876EB58A8EFA96B635C609805883A2C1F174361D53C07FCD84B92+98AAF3301A7963FAD28DF27B51C7FD0157B67E17F6A7A7761B5541AEE64F43EF+777B88B5CFA8DB7769BDDEC34726E2098A13044999E2416DFADD22B1315EF95D+03642DA8EB681E8989533F6C83340CD8B8BED6DBB2C8C1C42D85B699F6F560ED+F923F217C2BA35EEED7468686932D0244ABA36E3AF271B51A3A4625E1A16A29C+222301E459D4339A8B05D3447844558240B39738E3FDDD58DF6704667C29BC6B+60203EC6584CE4D621645C5573DBA4843088F357606F5ED2172A263F55BC2D76+FE2EC2718987C83CBBE660FB5D44F25C415481434E518B6E49AEA6935CE12B8F+40D5AAF8846B132591054363028C06E0B3890703030C3D6F9922EFAD0F6C3142+31D40A09F844088F2FAE7C7572E8819255A362807C45601B8DAECDA5D63DCDC3+A47965F4DC07CE56F5E9ED22499DEBF2E9C42B649E9C264E7884FC89EA1AD214+359900A562A459E5CADF404C5208AC86CD269BC828D3BEE1F4BA2721719AB252+D7C7D06900BA76B8F99892F2264CF0C2A491B1EC3AA7B5A123392E578D51B3A1+34900C5CBFDF7C2F9B92201ABE39F681B512A745FDF8C8D77A80E6EA7CD356B1+F8D0CCF6083DC6908FE09BD7F6A6D8F3BBBF4C6BD04F347588F82E9B464A5BC5+4DB0BFCFFC3AF46506F134E5CF55DAA2FEB43AB463A176096348461EC8025FC6+C7C119DFC0563AB814B65C9657846B578AE674D321C303397655CD7C79DCC300+85C2D7357BC0BBE92B6893911A74B6582D9F71D331C19EC21CBB6F20762BC754+BE6A0167E28AE0675E38EADDE84EE290B33E6255945D088BB538ACD00C3F12FA+37150462B7215F226B1E6D364448AF06AEB2BFA8D1EE8B6E281FB6A7D231F25A+AFF6511E90E0514A0B4F66E1B2B611B94346696DD327FFB4AC1F32266DDDD4B0+462536331CC9513FB4E7E3992B8F9C45CAEAF4E5B98185E3FDCE7A55381DE956+4A9D73AB1761F9EEED49E5DCA8FF34994038A477941B7B8039E1634D86F6D35E+CFFBBA593A3CDD30E9FC2190AC82067E1AD60292D81EBF2D49148443ECCF1E2D+ED3D137EEF5F841E72BEA65330A1F511C683ACBB98D672B3A68816C515737519+DB70DA8922AED96118BC1A2EA807AB262EF0CE08F4D4356DABD712A610011AE6+407AE3D5F8252AF3338539026F36DC0DD7C47B6514B8E5B92F230612144353D3+41ED8C1D10CFBB9A7A3C17E69A606AF4B1228FDA61B9DD4C0AEBEA867BAF776A+2E40CBC080C35BFFFD7A0BA88441F6FD71066FED5E298C33CC2A991B6028835F+9A3FC7048F294F880756B3D70FF0FB57EBFA69D93C3F15381A4A47514C8EA252+3CF46A67533E1ED2A4075E0BB3D366321F793F9C984A1E4B77BE913DF2B30F43+7ADD734D580A91F1502A659C9C2F1C6C04A093704394600199D34767B8623EC5+AA8A5255D3A7511CF9F476852153896FA8D01DE3690F19AC2E13C7CC04D37E2A+E153DC5A6E2D850337419C81D6C9A852C96A3E9D7C8142A08691B725E4A70C19+AB6FDA4731BAF33C6721152DD1F4427F9A2C729898E7FD33D64BB80647021391+AE9701F0C9E910D41AE3231AC5AEA50F0DFE28F3F0A9CE901DC7039DDAA85A8E+9609A7A23D513B28E5E772561342C85F64A484333EC1BCB8FEB43EBB80078030+71F88D8D9D87473414E3E7862DAE2DD3D21D74DD915DC4707336CA855F4F499F+F1D60659233AF924023D6D3A09219D3F9DFAF40A4AEDB2CFC122CB6B4258386F+437FC979AEEDB3E6FF8827711F7D03F4E6501B6697B3884508453BA4C5560027+C90050244499CDC691093AA817CD72AC0808E5FA2FE23998D1BF3358FF26DA15+71C8266D006C089E5AD3F9584FBF0D7FE52BCD8F2232FE7C2ED553A1D5DB8739+321EAD0632E11932D9FF109927D3D59959F54A5362504BE66B42B1B1C6E69C0B+0CFFA02F6D252A9D0E6A773CE33DA7746AC3441F400B5F355DDC51A2BA1683C6+782C5EED355ABA3F8CF17F09DE661A503C2A7398908A948465B29C8703DDDAF7+B72BE0ADF634CDA1B3E9CB85B5F91EC2E9F4427461205FD282DCFBF3FE8BA114+39ED9920AAF9145147446ADEE2F350ED50611F72C720618638C12FE2247EDA23+DCAAE01BA82A4702C7C0742311C683598B15FD676BDBB408CEF9E7773D112382+7038D5D2EF24823610AF8E6B4F58F8A193E447517CF8441861F0F243B57B6533+7060F5FE46DE73328E29F46C0D9EA9905A480ED00D8CBA86B5AF5C1A0F22082D+72A49DC40C07C5A874DBCCDE8E0C9D218E240720517BF9EAB6F7F9E487B1B1E0+7073EB672A670595F9B0ECA256678A925B548D33320B7844DCD7C443E98DA09D+7F2714974D02A8D6A68965244747B1A52270CF099B43097F14BBEEF9847A7891+4DC06FC6CA83C17AD94D37D68BF81E2051421DB88A7062D5C2B55E8A08341A74+E46934D5F23E077A80604EC292B2D8E0EDD0784B0416D6431406445B25939A5D+E9EFF54FCBAC4DD6E4C2755F9D036C4BA98F8E9705E91B4C08A7682413+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMR6+%!PS-AdobeFont-1.1: CMR6 1.0+%%CreationDate: 1991 Aug 20 16:39:02+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMR6) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMR6 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 48 /zero put+dup 49 /one put+dup 50 /two put+dup 51 /three put+dup 52 /four put+dup 53 /five put+dup 54 /six put+dup 55 /seven put+readonly def+/FontBBox{-20 -250 1193 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5CF4E9D2405B169CD5365D6ECED5D768D66D6C+68618B8C482B341F8CA38E9BB9BAFCFAAD9C2F3FD033B62690986ED43D9C9361+3645B82392D5CAE11A7CB49D7E2E82DCD485CBA17D1AFFF95F4224CF7ECEE45C+BFB7C8C77C22A01C345078D28D3ECBF804CDC2FE5025FA0D05CCC5EFC0C4F87E+CBED13DDDF8F34E404F471C6DD2E43331D73E89BBC71E7BF889F6293793FEF5A+C9DD3792F032E37A364C70914843F7AA314413D022AE3238730B420A7E9D0CF5+D0E24F501451F9CDECE10AF7E14FF15C4F12F3FCA47DD9CD3C7AEA8D1551017D+23131C09ED104C052054520268A4FA3C6338BA6CF14C3DE3BAF2EA35296EE3D8+D6496277E11DFF6076FE64C8A8C3419FA774473D63223FFA41CBAE609C3D976B+93DFB4079ADC7C4EF07303F93808DDA9F651F61BCCF79555059A44CBAF84A711+6D98083CEF58230D54AD486C74C4A257FC703ACF918219D0A597A5F680B606E4+EF94ADF8BF91A5096A806DB64EC96636A98397D22A74932EB7346A9C4B5EE953+CB3C80AA634BFC28AA938C704BDA8DC4D13551CCFE2B2784BE8BF54502EBA9AF+D49B79237B9C56310550BC30E9108BB06EAC755D6AA4E688EFE2A0AAB17F20FE+00CD0BFF1B9CB6BDA0FA3A29A3117388B6686657A150CE6421FD5D420F4F7FB5+B0DAA1BA19D638676E9CF159AC7325EF17B9F74E082BEF75E10A31C7011C0FFA+99B797CE549B5C45238DD0FADD6B99D233AC69282DF0D91EA2DBD08CE0083904+A6D968D5AE3BD159D01BDFF42D16111BC0A517C66B43972080D9DD4F3B9AE7FB+11B035CE715C1218B2D779761D8D7E9DEBE277531BD58F313EBD27E33BEF9DC5+50C7821A8BBC3B9FDF899D7EAA0B94493B97AFEAC503EB5ED7A7AB6D9A929A8D+D186043A1A15F89EDE60FC17A13CAD7F1FCE081BEFC2864447FAE30B0AEFD59E+3F1A3890297A203003CE8D309197234A7F5D2D82C831907B3E5C1D27208F094C+F5A41E0BF1FA2DACBE0AB52EE28A0D87E7BE07A2EFCD52016DCE87182C6C3FF6+D0246B1A71FDFFD46444DDC4B560663C5FB49826D54F03764C975DCF1D49BAD4+388965C52B7E1A13581695D7598DCCF499743D52B5E0297A0A0DC0034ED2082D+18822809266C51AAD54308AE120190F9CA896BAAF35538558DF06A3C2316E61A+9AD6303C7280C8F734CEDC4BA3CDDFA89183B5EFE420FD4D6F838A43FA50460A+6E16C83F85FAE72E745CFB88FC13D6F837870BD55E3F2DE62C67953237538105+979CE2859874FAC2F90593C24C009A126B066B8298C9708F03F9605906648B6F+BBCCFEF6975D9DBA0F54ABC3F679ED9B84ED209F83EAD5E0AA4D309F24F21FA2+C2ABD1A14E9D3DBD43DC9360B21E8B3A8F3E95678368638E3C6F824AA6061E0E+26DBE54CBD233EADA3DEF5E22F88050770D83272E39A4E2768A68F74B2FDD39E+A2980F56690C25FDE55BE282E2842D7B0CC6125C7EDC137124125112313F0601+F587BBB2627F547567C968E34B23AADCD7AB84C2D7235FA21FAC77CF4AED6E6B+CF47A588F2738B127178763908BEF394D7999B971BCDB420D0C0CC1122140ED5+A60B0E440C314D32B4D3FD1CAABA2B01901E55B812AF042442889D7D850B2035+445ADA4F52A4A89A5279A0B84F612DE970BEB4DCF466DE06CBB89060139CADDE+3528FDA94C281ED71D3D961361A0DEB949AF48A8E4015769274AD8145822CD9F+D9C571D2C860BD1EDA9D39C0CEC1F5835FDD750F9AEE6D658D05AE0475920E24+53E443EF23D74127FAE6EE2DE134F721821191C7BEA795DFA5562226F2CC6CDC+7BFD7ECAA1455DD046C41967F3A1ADF24F8A2EBAD19A197C19301D51C5E3FD0D+4CF3101D607EA3D1CE223A674934E3C1030D2FB46B02A1B85D1DC489B2A79D07+FB021EAA22F8376A6F47EBFC78D38ACB8827B6408E7CB8DAFB809E30FCD99CA1+002012749AD80858537F798B9762083E8969867AC2B4CFD5AF2028D0CBEB4630+5FC08AE7BA8F68C2003C5956D644D568D732FF488B5295BD8FCAFC9D978EE6CA+5F8924AE11B875C2717D053C1F0A5A0EC051CD6B542A45A75E3A2103CBB34243+656BB24B014023172A31639E630A8E0E0C594B7602D007E287978EE88AF643EF+EBBED2A4380E756878495E851D8CC25800F82131A6FD8C616DC3FE68D7006BD4+200A29376CC460CFC3FD3A611F3978A656348FBF04A0AD5EC880B4E5D13C5E38+8B26266CD59A84507B9CF3B6101E04F3A18FC24BABDCC71B3DC82198B5F5D7AA+9ECBE68821985ECE0E0F1427BA2E68E9325EEAB3E3E90DA568AFE9162BC60CF1+FD412469838985D23544FC1B7665CA88E000E1A1F24C4B8C6F12F02C65B20189+58251C06E92C262D08878D0C789AD17A2CB1A4C36F7E6DC16977767285421CB7+3EE915B73EC552BD2BFBC9BB7B5D6FC9D4DDD5F018F7B530038165A93E476E2B+3A21AA4FD9D1CB2A09B25B24029580F581F62E61D785977C37D02B0108AF392C+EF1EA5027562773353B32743C9E06225A9441C34A7126A5F66B4CB3017B834C5+129CEFB47624B7C722527E40AE09E224568EAC35C5C0ABD474FCCFC77D209B3E+CB5FEBC186689394C900489A19C87DEDBC51522D506EDBB33B236D594739FCF9+4461ACA1FABCBAB699540B4B341C86D52F36DD66D42573C4B757A8D92817648C+7E459778CC7FA3E829925D3FBE21266546EA54F3F254C94AC8359494E1E35A49+5CE8B576EBB16D767A3CFAF555D34F6CF9245CF40D3537EE315B93FEEAAC2C86+8EFE4D27E85F52E48520476E87B9C9A35D3DA06023877E6B7597F728C0107C7C+C722B6CA30EFC9B5532436F61C5C5DFA9DC45E1C4AB092409D4903C0AA1FE833+3D73A0FAB63AF2D5BB83647E4914735534DEF6F9B47B22B7DDF4B1A90124AD32+6225264265913FEC81839FE8E6EE2CF3A585E3733208963F+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMTT10+%!PS-AdobeFont-1.1: CMTT10 1.00B+%%CreationDate: 1992 Apr 26 10:42:42+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.00B) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMTT10) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch true def+end readonly def+/FontName /CMTT10 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 33 /exclam put+dup 34 /quotedbl put+dup 35 /numbersign put+dup 36 /dollar put+dup 37 /percent put+dup 38 /ampersand put+dup 39 /quoteright put+dup 40 /parenleft put+dup 41 /parenright put+dup 42 /asterisk put+dup 43 /plus put+dup 44 /comma put+dup 45 /hyphen put+dup 46 /period put+dup 47 /slash put+dup 48 /zero put+dup 49 /one put+dup 50 /two put+dup 51 /three put+dup 52 /four put+dup 53 /five put+dup 54 /six put+dup 55 /seven put+dup 56 /eight put+dup 57 /nine put+dup 58 /colon put+dup 59 /semicolon put+dup 60 /less put+dup 61 /equal put+dup 62 /greater put+dup 63 /question put+dup 64 /at put+dup 65 /A put+dup 66 /B put+dup 67 /C put+dup 68 /D put+dup 69 /E put+dup 70 /F put+dup 71 /G put+dup 72 /H put+dup 73 /I put+dup 74 /J put+dup 75 /K put+dup 76 /L put+dup 77 /M put+dup 78 /N put+dup 79 /O put+dup 80 /P put+dup 82 /R put+dup 83 /S put+dup 84 /T put+dup 85 /U put+dup 86 /V put+dup 87 /W put+dup 88 /X put+dup 89 /Y put+dup 90 /Z put+dup 91 /bracketleft put+dup 92 /backslash put+dup 93 /bracketright put+dup 94 /asciicircum put+dup 95 /underscore put+dup 96 /quoteleft put+dup 97 /a put+dup 98 /b put+dup 99 /c put+dup 100 /d put+dup 101 /e put+dup 102 /f put+dup 103 /g put+dup 104 /h put+dup 105 /i put+dup 106 /j put+dup 107 /k put+dup 108 /l put+dup 109 /m put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 113 /q put+dup 114 /r put+dup 115 /s put+dup 116 /t put+dup 117 /u put+dup 118 /v put+dup 119 /w put+dup 120 /x put+dup 121 /y put+dup 122 /z put+dup 123 /braceleft put+dup 124 /bar put+dup 125 /braceright put+dup 126 /asciitilde put+readonly def+/FontBBox{-4 -235 731 800}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5F00F963068B8232429ED8B7CF6A3D879A2D19+38DD5C4467F9DD8C5D1A2000B3A6BF2F25629BAEC199AE8BD4BA6ED9BBF7DABF+D0E153BAB1C17900D4FCE209622ACD19E7C74C2807D0397357ED07AB460D5204+EB3A45B7AC4D106B7303AD8348853032A745F417943F9B4FED652B835AA49727+A8B4117AFF1D4BCE831EB510B6851796D0BE6982B76620CB3CE0C22CACDD4593+F244C14EEC0E5A7C4AC42392F81C01BC4257FE12AF33F4BFEA9108FF11CF9714+4DD6EC70A2C4C1E4F328A1EB25E43525FB1E16C07E28CC359DF61F426B7D41EA+6A0C84DD63275395A503AAE908E1C82D389FD12A21E86999799E7F24A994472E+A10EAE77096709BE0D11AAD24A30D96E15A51D720AFB3B10D2E0AC8DC1A1204B+E8725E00D7E3A96F9978BC19377034D93D080C4391E579C34FF9FC2379CB119F+1E5BBEA91AE20F343C6420BE1E2BD0636B04FCCC0BEE0DC2D56D66F06DB22438+452822CBEAF03EE9EAA8398F276EC0D92A7FB978C17805DB2F4A7DFBA56FD6AF+8670EB364F01DE8FCAFBAF657D68C3A03112915736CEABAA8BA5C0AC25288369+5D49BD891FABEFE8699A0AE3ED85B48ACB22229E15623399C93DE7D935734ADA+DA7A1462C111D44AD53EA35B57E5D0B5FC0B481820E43222DB8EFCD5D30E15F9+BA304FA879392EE0BCC0E1A61E74B3A1FC3A3D170218D7244580C7AA0DC65D19+741FA5FE6F8CBF60250ACC27454BBF0897CA4B909C83A56672958752ED4B5E79+E18660764F155E86F09EFA9F7685F2F5027EC85A775287B30E2069DE4E4D5712+E7D033481A53A2702BA7542C71062173039030CF28D8B9C63B5596A9B42B33E7+D922944A38713383D3648A4AF160A3B0C8F3379BA4372BE2E7EA49AABA75AEEE+C5DDE1D8BF68483C3D21271280ABB91D54CC819680322EAB72E1250A760BC8DA+726405EFE420635B5B7F0B48752C06083E92BDE06401C42A2C528C8A60381227+CEBEF0C9440DC034DAD9C19FB27DB399BDAEE22053591D6538587C768C1B7B0B+7D1E222D2D8AF3A6473CC4C0D6C3E0DB49068CEB8C9BD1C5CD486A50DAA10BC7+7D6286142355E3F21DD254E27C00C442728A0BAEC9D3F17AE9CE320D365152E9+EB0D5E3874F2BCEDA98521D23FCFC30B4B69DAD2ADBE80E5964ED0ABEF6C73B6+DAD30E2C5061E3747FE536E1A5D190D028F2130AF608F5DDF9DDDF1E77DC8437+ECB3EC93B33505DF47884DDBD1DC6BBE4098DF04A29AF6FA3AE344600D0AAB53+B3820DD7ECB600A3B8001C51AF2CA7A39AE1485A087FD1752DF68F55B52B4DA7+48030F2AA7E570B3D56C4EAD367B9B73FBC0A7356253233006178B9A6BC19081+B815B5988AE76FE6FAFD7AC239072B1106A3F509381AAEE79B2F2154CAC4727B+D199CDC8B4D05DF4BA006982512ABD7539E28D937B0F87FF79A3F84C29ECF943+A8DCB8BDF8EA9E7A0E7CD60BC2308C96B3E889C797D0FF28FF4847016B3DA141+E76FC6BE78A6EE9CE07E651FF86E720A1A1F075972D36E5C55162E3FE26BCE3A+814BFEB12D4C5FD24340CFFED499C7CA183E57EC4F12CFFBE3291D43F7270575+C6C3306F832EF182ADD0AA14C4D8669A17C09F632406AFA195F90C4DDC39779E+EC0A77E590211592D6EE19563963225C06C2F13265EBB5A6CFB7C17D9E77650D+11958305727AF662AE73AD0E3ED5F7E7086C5A0C3548A8129575980B06C715AF+DD55C8DF869BED0A7883491030B1A7E82C5EB04E5A7D952E716DD8F2EF6275EE+087614CFAB55FCE2BBECD7E8D9C90FD8359E929D5E0A416A23BD58158318B4FF+87B095EB63F7F052B3A77F136FD66EB2C52BD46CD7DB3091A4B78A607112B12C+4D171B2A00B78B0E1C44B0D90C20D9244281F5123DC1F6063F91E9E3E48DE78B+C862D848BAD073A4FCB5EEC9FF54B5AB8E234CCC3C7439C62ABC4A13EF1B8897+ABBF21F900C564C9A305FC36FC7224932F766E6E72C2EBB55953DFE2AFC2E3FD+33A0C6F0FDFF086E9FD796E7242596AE85B877223532667625E371D2156E4C04+0D7FFCD3337B93DF066CB6FE1E13960719EB7CB409EE805C08ACD2C06303ED9C+E34C898787A43C1B428B896551C6FEB50A831C6F8CE2073EFC662EC286CB7555+A3B42E58772E82FEE206948B8C439FEC5E4ECB9E11DC3A4CBC7611E30890E408+637A01A2118441B4F9467A98BB2A1B03BB2F5D8E3DB7D1D15C188D9E856088EC+B762F07B1C06024F7EF53A2FBD60C0A1F4C0275D07164545250ECEEF8CB15B04+A2D8AC44DDE818C4E3CBD2A5FA0FE49750886CD7CFAAF8B780255F89DF7F4F5C+BB594FE7C1597DA71813C2952AD3E811524459EB71D29696B450C924B6A5C843+8F36A0F1D7DFE796FB9564333666D74AE614D0D698FAFF20F83C86524C894BB0+272221C060544F3B653CB0E4E4F82B20D7530B3806E6A5830852C58070177815+E287C847F19F64E854F1463C23DDD80093D6FEB8BAA22C5F05C21F99FBA7193A+EB7CD49CFDF4308C6C68CC955A45FCFB54FCADA9A3BFBDE086B057DE88BE335D+280F5338D7E66AD39FD08F9B55884F1F377FB6869FBABE3EAA4B7ACCD85BE672+724B4B8F236B0889B6E7049CBA558A89F17863E82DF145DB8C7ED1F36332DE23+3C0053B74E850FA14F9EC9EFC23AF18E153CC96FB0FFD910347370E57F0D81E9+4A83E2D189EE5635E85A2BEAB5B1CB974546BFB2FC2ABA1E15DC0EC1BB3AF1DB+B2F93538B92F504CBD7AAFE36F5F3AD45EB16378F169B17869FE81464CB826CB+400D2F5441A496B6C60A4F15FD20ECCAC1F8F91015E7E1C1A10B7992A1554E52+9FBEE905A3005336E49CB04BA7223F1674C0BBDFA06ACA34F7BFDA56906E04A7+4DD79EC7E79B021A5008F3B1E04712D689366F520B0FA66A558F957011992728+561BF4B75C2BE07C4024C172085E51CCC5CFA439F570297154CDDBB3AA25CD6A+3004B936488851BA1E814260C06CD5479DCAB1A6AE21A5F4563024F973D738B4+0DDB6C6DD2E3AC21B4F6D95CF9AACA782919F5D3E613D61F3224A982AF485C8D+EA0037410EB70AB7D3EC174C6D5DE5C9C5A1220EF7C2B74499ADCEEFF077D1D3+50C1124535F88C3C3F66477E42F1932665AD323E06B398D2805B9CEA632F5B1E+50FA587B102A35E2F15EC22DD66E4DF06A3F4BB717A3ED7FBBE2458EB4D896DD+AF00D1BC71FE1CCA27890ECBF9F0AF01D3E65CAA29427FAF06B3BE1E640522E0+73B213D04491B93DB29113EF72211E31F4C5A7FD58451946CFC15FD805112FE2+547D1131A46710DFB75659A33695FFAF3CDD40AE5260AD6766DA81DAB0A6E96B+E89D57AAEF32B5EDBBE9F7CC033BB2595CA3FEDA2ABAC8E5395EBC35BC112FE9+67EAF1F123228538091483050847F8FB5194203609502D3A09CDE811EADC18B9+F039593782C27EFA7697182D6367E88E326AD5622C5A457FE2644FEADA88615D+9DE3E483BFD9329667953CDB86F9D2F0D4F02DAB8A98FDEB1D17CAAED9B6E2E6+0C55C1FEE25AB98FF59FC235876029CE03E4A713B75B3163BE3B2DC0D4472DBC+473E10400C0F57E627AE97FD0C1CB0F78FD8E2FA831A3D2B1C2BB3F2D4E812A4+194C8732B0C525361DC8480CB27C30CD4DCFF01318D2EB4F5234B4A42EA8C23E+7B3EECA41B8E4F54D5458B37EF0FB2F49EB19F4EA8AD2B53820FA36E93DD309E+48847F5C01B1118ECE7D0186E6B8953344EB775D655AAAD7BCDA642EA2E39A15+855C027CBC0E3FA752900EEB464E2D39404D1B85072B40834748C6F9C74C5B6C+3CEDE988343FD984CFE4B856A481E60E2E65D3BB41BAF2FA80AC0BFE381071C4+573C6ED65C524FF777F34D82E9661E4A75E3878CC77BC59218244612219C5A92+E95B90EC2C38614665550026F1730D11162F19D841681C04C401E102C047541B+97B9264D86F47E25A347696AE5EF0FF3ECD9BA32C92901DEDD816F7D73ED1216+0A98771892472CD625A8F7F19DEFCF5CA2AE57F8AD3898F2C1005B187DEC6F2A+A31C32720EBC934178E0E9979013B3C9AEDA4051DF63D8C903A399DC88F83DCB+A73F1B2083819D1BBEA5235F8FE1D098F32A2BA6274424A99A4975FE4BFD59AD+79B40A8003CC0AA728EA79D6BDCBBD73DF45B7918BC099C5BE4A068BF64A30B1+C39442CED98AAE1BD495F6CA32D564A72E3BF753B49E4178927E4BBC0F06048F+96DE7C30AF580B0BFFDB330B3B87D7F6532A24F403680BD9F15E758CDF04EB94+E83C7E644FDE5BEE7CE73EFAC75669E41BDFB20A5B8ADE1137378DD8102A0DBE+19499A623770417CBF5211395A6BA9F4490F4707A46F1F9B3FBE642DEA0CA053+9ABC307B1E71DC2B069DDDBB4EAE378BCC75AD61DA900AF8BA6DF0E27A8D2258+DC80205305AB6ABFE3726703E60869BFAFF1874F3C0E05FAD9C05D7D89ECECA9+DD2AF5F777D7514208697E712B52448B364D3ECEFD8127043DDC9D0757B7CC37+5CDE8001D007A6E961EA24D7FFC92410F3B13A32946F12A50DFFA256249BC8D7+C1842FB84AD51B41008EC4604F6B70990510EE13E6DA34F864A572D99A13FFC7+3609EF2BB1FCDEDF37A6018248C545E086EAD1BA1143E74AC60B684E755E59E7+36557B915F92EF78FC177621D49F777A2AF39F3C2AA6EC74750AAAE08BCC21CA+A71CCDC91DD45E6050D83ABA49ECE425B55EEE137C55619037F1C30530BD0A6E+CD2004B6A040405064D7E87C55536680364E09248BFAA3FDF95CDA0708E55F4C+F7D0A92A93DEE0C7B69638F171B28B7F854CCC6EBC6AEE14864BF5144EA36D46+A9C297225AB0325E28EF6BD06D7E40E3A724EA1E50C4C6163B195CFFD5DD291D+D7BBE9AF4324A69394117EFD62F08D6BA6A8F0AC3E2353492999AF28FBA758C3+A50B6840CC72054355E6CBDBD86F683537A4115049BC1616BA35C2B0B6F5CC32+3F6831DE4E6029310738DE23D36D2C6E82F04EB675FB89789F74AFE3B8854250+51812FBEFBCF162947554324FADAB765C74B6DA89F60A734076D44BBE45263B1+3FEFEEA90EC7948F23F34D4049087AF6563692417DDBCDD5A9552A373C2528F8+0318D3C0669279F292127CBA40B0ABE08A1476BC9EBFA8BD5D622BC5CE7DBA20+C689BDAF50D5B1EAA89E296787CC53845DB2BA54FDE363DCC98A7BA256663869+E9E02E09077884DF1A2A41AA698B7EDE8DAFA621B552DDA91AD1E671D636FB36+91C62B4D2D4112F2C169E0023EB7521F570CECC54ECA5EBA462049AABBE2ADEF+E3234BFD71B26DFDD9D34DFA69E5E80FD90406E6505A6798F030A4B5172A7BC2+C9B765A86ED55C0590E0432719BCD7BDE7CCC7F6B33BD467063D886276C8879D+E04897A4623111C14A1EDBBF69E2FEDDFEAEB2A785C6D2F0711DF4B93AAA291E+7F4E0CF9CC3FF0D31953C594DAD014097DA02CBD5AE8828C7E7B5BDA09188B05+0D7263F164E1E78CC430ACAD1E8FA71001E9BCEFAE47C79846916A5F819CA366+5734089BCDD458CA1A9E8E17BFF357A91F9A7A8A6E1DEFB121353AA80F1906A5+AF7CD2E59EE6776FC0DA6574DA0DE522918CAC4E566F13FB9B64EFE79F3A3BC0+689E3B0676741C90FF3BF85C7A0FA9716F4ED0E329512B66BFB8AEB56C3DD6B2+24F8D6E23751A8485F7EB46719E9D22618FEE86D5E01ECCF4C6E74368A8E9B49+245D80E7484DFBC916FB2447852B36EF3F99A82B6C106F786707D7689DCD7AEC+A0C51AC1A3F67034C16B74994403FAE7743BF02149BEBEF554814BEF31B79184+3FAB4D2C887E1BEE81B465D12DCDDAD03DE5ABE9E763C440B2CFD42FD16D96EB+C21FE788C8C2688F79F148AA7090BE64B0EA710D376222FD1590301BA9A2E715+D33B8C1D95F2589AB0EE476F7046537E27DBBCDADEA1E7357C9D7FA92C2F93A6+7BDDF58A44966590821023380C97CDE37EF6D449E35EF32BCA6E69DC8458511E+8DC8AB63171A6018AC9A334829E5978484C4C6E917A5F1C254E6669F4037C691+36980250A80673E0F18C9E0FBA1E5CCA3BE30B8E7B7188062B25F8E1E16528A2+F217C18D6A1955482E5463FBF097ABAF7314E449C6FEE56E2695407A8AA9648C+61AC2BF3B2D9CB6317A9B16CE931D318C8BC9676CD908505568C197D90C2BB46+06431C999EB68C8216409E4CABACB2BB34A05B697B9DD1E91471A404B4969519+E25209EF4EDD420944BED17B18DB3566FCB8059699FE416789191EC2B35086AA+2E10C139E3C9FA0A535DEE9255A867A26656213E85851DE5F51F9780D3A6E572+F1F5CE64DA176CA810799DC1C60A8FD2A5ED42E613021A19928EC4572059B2C1+EE441E79CDF7DD4AF7B6E3D3230419ACAED329388044B107DCB4DE91B71EB838+904B1F969738BBDA064FFE75C6623639BE9924602DDF0C166B433B9D54ACDA5E+018680477FB8F10621FF32319E58DB672D744959A33E7314A1B3CDE0C038F7D6+0C8A195AF191E36B0325334A711CD8E25D9C1D257E46A734779E486567481108+E0281DE96907D460546578DE83A0A01A9ABF64402B48DEF739F4308E14145753+719CEF720FE5CF8DAD7845E74D502B69DC18D172C3A27411259B8042F3FF82C3+B157BE242C351830255CF0EDA96577375A70657BD9A2E9FFC54AF0AE563D73F2+E510279FEF48D79F5F7745DBB492F1D74DA738E6A4FE4364799B5BEC93B4CAF6+B06B9B8C8D164F8FA1FBBA693204064F2C1806C39910910E02ECA8D092558CB8+33338B359D56483B7B99A1D8137204EC1AE70ED3D75881FC3B00BB9349AD934C+81A9F285312FDDC77FA923B18B1873D288C2AAF2E6D0AF90BF25A982B843789D+5662D6A2DD58E065026885601ABED4B09CAAA3116DEE6B430B15BE0A121FC1BB+FDEA5A501F0798CFFFFEAB5101E707F1A00C8E014A3561FD39972EA9AB108EBB+960AEA7FF60C301AD6CBFCAA7D35CBF6F8462A4D76C4FBA6F3DF6BB762DF7900+9F69529AB4EAF96C2866444B257160E8822533A7A1240C83EC18C364F577407B+4CB314678D2511735308A1660AD94B8B818CEA4A3DC00C5A1C978F8BB4E0491C+49328F6CDF95BF620AE53056364423841D84418B23C2A447B0CCF8D8633FE2E8+4A4AC1C6C74627EECDC994059F1BAE9E6B10FA80D767B3FE97BFFAD413DCB0A8+495039744B48266278194D60422D6E7C74D0DB45ACF217797D0C0678EEB60759+6231438CFEFB346553A7A447B50807EBB6E885B5A49CA9A350EC4A8C76EDFBB3+A4DA1C9E3EFA193CDF08553302998F20055C84420A4C5252F764CC4B7A4BEF6A+A09170EC417B296DD9E2301CD8EABE4A087E648E0525A9FFAF26374C47FDC123+82F18C9884843864F418ACB08041E7896FDD395225532460A8194A8DB4DBD824+1C68C6665F85059E365EC0972EC6465E2D8867449907DA6692A021F026F437BD+D02654BC11381BB6557663E0B0B8C4F2FF69E4776F4EABA69311BC1AF8155F7D+6D3A418BDC912CC7CF1A4BBC8A1376D8B4DEEB6585416959BCA4AA08D4520C33+EB054DE53140992D0707210593BE62B3659E3E493C4562C2E99CECA143791DAC+679896BCDA0699E405957E17DDBD243E65CDD7C9C8629F29A2078658746A7779+0F75BE24E2DDBB672B95F26366BAF036B3C23BE4132D7362E76D4183A469E0F7+29174711ECAF4FD9A923E72FE58DF2854C5537E3626317D471D1E8A922C9BBA4+CE9163A4086AC4A231C2BF35FBC39A5BBCFE41843CAC7D81A054509D31572BE1+596E0B0B563DF2BF0E57DB4943DAEE35CA26C8433FEE4FC61145C77F65DADE75+62DA18DFABC7F4194906F53884E62E77D8AB3E099776AB93B2B4D0C98FA44C71+597202A2643942795EE8CE098FE26F1AF8134F1E75FAE18D563B1FF43A511C9E+EAFB9EFCF61490A1A4FD2CF354927B72C5EDD5D62B2F3F5006D6130562A13BCB+1B988A994A8D68B051A5A821CCD5D0F8D9D49FE7CD04EECCFD7A554CCDFFD77E+27AC4AB5BF9FE40F90EBD066C483796CE1A364E95C5E0CF2154834760522F128+B2DBD1F4F73347D42635B2875A23597C35A0823CC6F71E49598125411BC9B2C2+72470D36DD967C947AFB031BFCF770FE50551A134DF8C5D1AB1F09819569A57E+E23D4E87C0B52CD02B0A2E3FAA7D27A94359E82AF047756BB769BC5950A75207+78ABD49D174F2F69810AFFA9336A52D6B93B004DCA5CDE58475C0210E0BA1D20+FD4FFD6838EC56A0922472D4C4EE0CC481574BC30618179E733EA40A48847E14+A75BE7717CC5DDCB5B0718074EAB6FF07CFFE794D335B3A13EB968EA8FC5B08A+13B38AD1C2C964E4B07E90B9732C458216B028E07DD593A5B767A2B415EFE7DA+951FC07800F11C7E2EF9BDD152BC6815B7F32117F49FE08BD79BEB949003512A+327F3F8FAE1767E7842348BA4373649F1A21DB2C56C081BCF9FA4EA86C8DFF00+FF45C4F1386CF8C2C4120F3F6019CEBB639F2D272D08C1763A470D4BF6330DC8+43C069A6333113C3A0C93471486EFE9BFC02B760C7CBB2E9156087D09EE8A178+5EF50B34994094C3F0015EA2ADB6C920F4302FDEF128711994875551C4E883E2+DDEFFAAE11F2234AFDD96400BB69C1B4E6EFD75734C586A10A54A98E7D790F28+DEF7C7DF61FB23BF91AA700AE585EBDE74E215DA49F4ED466F46129022722086+8884D8E026F35C4BEE7E866DF8E0846D5EC3534069B713FAB02D4B4EE3B44E1B+656F30D629D40AA1337786C1FDA08EA1217AFA4A6E2498B334DAB5461A70DFBB+5AA5686C89FFA4EE82D81CE2B28334DC5C032487CCE998616F48150BA1281911+076E626E5BFCC56A0A4CDC559F878F14C2BD7A5148C1D8CC303FF9EC473354D2+D4FB0F0F2AD0CF182A28074ED6552E179222570DE0E0D44E8FF4DB36C3AD6487+C4BA53C8548714A69FCF8E3E5202F09469D7447C6519AE902C1D611A720BAFB5+59E27A6DBA73624F44B4ABE0988BA3450F82E03521CCE8EDE8BE7EE1223B575A+DF9A52650E85545525E6F121FF2D1531F156EA9D5594239AEA2CD09EE28ACB15+A445E11FD1C031188DB61881F474D49425C084489A88A47D681EA68E7FC4B1F9+DBB552063A02A0EB51125E9B2CC646B940D46FF457415F9565892DEAC030F08B+E4C10DC38D825C7597394C844CB863CE6C843F67F2E1C42C4EF86AC7FB727BF0+224B5E91BAD99CC6638AB2C64469A81D8B1789981872ED037B3A34BDF3130137+80FE80FDA65EFBC11A08B98A1AE595F980B577E22D3CB7FED1D4016F5290ADF5+47D7D9BAFE39F294582F2C084003E9C83FDB9EBC87C8B477CB8BB359EDD9BBC9+9368D6605E1468A20909831BF602EFCEC0D5EBA99A2223E5A269275C8B221B3A+F9226654185929F794E1979ED18B4CD36152F973433AC67BE24B9D953254FBBD+B644CDF3BF0E29A2C72113DC486E46DED2CE8F8DFA8B0F8478D1F18C9AA8E054+A31C3DBE84ECEDD85DF6AF9467AC2990ECAA3384FBCA1BBE598AA0D6813C859E+1520B88BF30ADA910A6AC3068A5B8CFD76B7F0F6F4AF4C32450D628B5320C384+F23A2B5E8756895584155226A30F8B0437E028978491DCD00E79C0ED58DF261E+79B9DA17E57AEE03EE92102EAB2D63E69A88EE0B1E2087ED0C0CF6475EBDC3BE+0324D1FC8F7B90D8D807533E5436F2C2583B9629EC390403437FDAC908557894+03054A6DD6A3586043A9C8BFD0C7EDE1229DBB9F69F7A5D20F55664D061F6517+0051C6B3CD7338241FB403F2AF77DAB1A8EBE1650156D40863EC1957372BFDEA+BA8D0BB1193CC5BEB5A68C8274802E14FFA3ADCEBE19070325B1BDB960CF2988+C0F5A9BFD843C515ADEC8B8AB02B2891EDD7502D9F28F4E58D8F67D1ACAFD0C3+3531E0C7D1554344CCF90AC8696E83A3F968252981CAC09653956F4343B99D3D+4F17CB8BBE4506B354439B70F2024871D16668F9DECD8EDB872BE5E6ACC406F1+1DF4E3ADF60EFED57D1C426292970199BB663405236C6A907B6891C6190E87F2+78D9142220FF295C7BF44AF61470798FB8CFBEE6973C69DA1CC24ECB058AA753+DDBFD92FBB15560EA19D5D92F0005B74F06F0EA5901D231996E0866389DCA433+E62BE48479687084C1D67BC592E592939F806FA8BF5F0D3F644B1FA6F056DE0D+51D3F212C6818CB6166317058C2A0C07AE2E324CD90D4EC83CF4819B10CC348C+6DBABA024A5FCDAE6E288F82DA060BCD16437F07DCA43BF1E5A1B402F16C78FC+075BEE900B4021A1019C4A5ADC33230047FF11FDE8FB775DDA267040A22B4E5D+6012F7E72B8BC8DD3A81369A08FB81C6C4873C2147D03D4181D6D8032DD2B610+9C44CAB50C5BD8F489EBF01C72D4198B66EEA4E976462F8874143640B82AE57C+A51EDEDE75A9A55D31587C14F8DEFFE69F75EA7B95BF725CE9991FB2F07AF568+5AFEB39447B728B99BE0502BF28DE1D92B15926BE4E3DA2E7BB44A24836A97C6+EE3A2080E01DC6514180DAF9C055F4C94929D34F193920020505E62804461630+9F42C652F9D5681C91BE23DCB0C634247E739135F925EF3D5424767D5F5C5879+C46F2E32C7B3BE9E90FD6ABE693A6016AB77670129B58B8FE719FA97FE320842+6488CB85B6BCC0012975D22E75A2E086131DE676AB825A386C086FBE1B65DDDD+A19F06AA4C1D3EC84751C649F4A62CFDC48A7CF88CFEC68B959C211B60DCB045+6BFF922FD7349B98E1769394E6CEA4F764AC4B6536AAE4E6BE69099A39A6A33C+97671C3AB4E7A94DCB829FBA97DFE5F71B1728FC81F826699DFDB0ACE9BC60E0+6EC15D35EC479F3F53EE4D0398BAC138FED504A84A13B78568E3F9C86BAE8B88+61830A80F8B994D0D66A8FA3FCD6C5099C29FC285ABF096EF9A3BFDBB522157C+DCE9F0D6AAFB1F8D7B0A3C573D0C170357175DD56EAF37BAAEF4C92FBE17E26C+7D2BDAACB9B8F33D09651FBE0D49A8BE66B78D075485BCD38DED5056FCE48A12+D28E9670EC7CF4E9A277D6ABC2F7AB30BFF290B5452582F372FC9DE6CEA9EC0B+84328269F14FE7F47620B1042B283C54161AFCF84B46E6B1410587295E4F8958+C1800F120B59639C85D46D46A4C64309931A8C91F138EB52F779189EF75B9157+D624045F4B8846856ADF0AD735FC6FA41F7B6C002E9D1EBD92468E86C843AFB7+4D78E3D54D866029DE5DF865EE3F7313AC358EDA70A792E22F2F806EF86A6B57+64AAD565C57E64B1A6635B7394B4B5729189319FCAC8529ADE30633B9BDEE0D2+AF1F8944EFDC7C408FD8FC270822CC01E7BA355C856219B3AC5D05CA37EB0EF1+6766D62383AEDDA1F7CDAD1DF0172E766BB46C5FCCDDD61BB019D283EDEF312A+B2DBA38C9BB0928FB93F50E8516AB353BE04403D132805B5AAAA17163AB9C847+F1B54946B0775FD21325C82E4EC7F2186C54B4396BC4B0B913A59E4444D11B39+8AB56F2FD5788A9BA45DA5499A50BA74D28707F62086907BF8342E0C753A31A8+DE293B592F51D74DECA52858CCF76C69BAF2224F640069BEF2604983FB478173+792D68030D7A6E3FE083AFFE9488D872897ABFC88CA8BFE484A75201D73058D4+72A8A26A50BA1F2B50CBF98D46DFED0BA057619BF370E435A0400147928D7C06+28DF2A03527E3BE925D6A664E4640E63BD22D54A038D934B3DB5B500E075B8AB+06DB5279274E65FF870F1E5106E190AB0FD8849EEE2D605FD4F0DED2C3F86831+4EECBFAAD8B2A895F08DBA692A8176F9080045519CC6C46B52F0F31DF112AD79+8E46B9899C5527A011AB63FA443ACE90F09434C295A5D9E6753AF2645407488E+D29E7711546F87265C130B76B4632242E43962A5C886D4DB6316A2F3420FCAEA+3055AB5A9E1325EA870CE87F34BB2B3110E4919E1AFEE67606B00B03DD6824F0+20BA42968B81DAE198C88057438E36056D46C550E3E5E03A99BD4B07E66A2179+BBC5B3FB06D5D72022C53A3F3A1B759472D5A50D7F7A1F4E31D3F7A30EDC1D45+4B00AEB5DF680146701B09521D4783F17561A26D8570C8E6FDC87756E2B8C62A+7F8ACC673C3CAC7489FD1AC49A382B8064E4BCD0EA2F5748F1693A0DA3B2AD6E+AC389F3328CE43F5784DA07F07D8DD7E0E5C0EBA2A145F14EDBF05D7156CFEF8+2FF8D4CF1945907902C635DA71B4DED5B41FCAE4821684682BFD112FB7C24FE8+8C3712BD0E3633687DCC7B54A6FEA613B65162D3F3604BA46FDD54CC0A9A17DF+BEA550FED0093BC70A7FF0953ABA45FCE07D95919D05CB5FABC96CE8DBC786F9+2A4156E27E7D7936E72C442B06F90A3C1F90D7D834A1E90B57C1B9D65477D84D+3B80E83AD61AAB5E0549CC2C22C006344C2F6C4B7284EE0B68D369573513E1BD+BEB2ED991892E736C00E5B3DC74A0EC7AF73C7DDAC52793CC7694B0F7B1C7BB0+E48EB50FD8307A07A6FA745504CD74A451E4B1E98F4200A38635E5E2F702F07B+2726A23B76667B83BF6677725AC69BC2B4003C10CE2C81EDBFB59D467CAE21C5+0ED56BC05D601A6FDD76193B9901C7E67AE487E9346A1ECDCBA088DED9942599+647624BEDE113398EC1F35C95CDE1CA02FBAEFDADF9FB2DF20F02F174CBFC91C+77A415CA95AEB08815138E39CA016B8FA3458ADD6FAA846A92C1DD299894F27F+E859BCA99DC05DB2E670089A3AF6BFDA9A25FA11828A7D6F21AEC34E9EE8BB27+2FE85A6437D9184585E77F6647EA0F4DA72A89137E856124AF903E6B0E55EC42+59CE614A14FB720D74E4C24906F3CE9A62525B6C01076DC69BEC770416EE058B+EE546DAC1E016EDBF1D393FFEF75E5A3B0CC5B61540236CFC9BF96F9204C2941+4DE14BDCA550CC2E1C57137BC218D30484448D1E86E6DD1F7AB0BAAA2737F0E1+CC26207B8CAA95EB70E667A869AAD913D2BF28C3F82518B4882CFF9DE5FBBC73+38D80C98B5849AA567A259CB9B3A3C3C4076E77406C82903B078B648D7F90148+FFA9A3DBB2674C10F2604A8ECF0791A84604CC4754BB25651D9BE5B349062B37+7EA9C23A7E7D109B6375E93F2AA60748722044D88049E95FC95D9E1E28AC4EC6+64B2818668E6E9B81619AD009B5A9C7F8D6AF3C2802A149A43D83B28E90E84FE+1342A4898FD6EEB253701C01D1677103298A3EBCC5266F8587E85099076A1C1E+A9422E1D3957CC3BDE93C2723572E5F2A080B0C5234CDEABA4665F18309315E8+1DCD49DF3C64477DBE924F41B1EC5A40834124BCAC663E35F35807BDEEE82AC1+594F00661929AF7B30669B0F0624D65713C7CB6CBAF6B0E9B87C8C0897C4D5EE+A157F2B948995E569C3888FC0F7C6E17BBBEC4D433DB358A4158F7D969F17BCC+F66A405E41A738B3C6032F1C5B63240173C2D7145A85567679B2A32A5A9812FA+CECBFD7626B207264D7C2174EC6421ED91220195C414F6D5985CF233686D73EF+586F501083E9AFED343493AF9F00056A4872D6C0DEECFE0560479C7CD9AE53BE+C046ED2395F9EE2F69E71D7E03272C506CA6BE9C4999ED0E88ACFC513CC962CD+EF42DD55B8E047D412D74F87CE3A30F69BAF90C5C56E4F39E688B5591AE36E11+F314377EA7B7873081C1B6F413F8F21179F2A8DCB59E2EFFFBE4C2D254208D63+E6A57EBFE68D8A64670C348C3D94C8214F5D5C006E8DF9763D1B0BA18A537481+09D85006A2F9A2B8ACBCF9FE838F520F3804C11673BDA2693945E5BD6A621C85+0E11D8CA8F5CF920BA9B12AD96E61F61A3E0A703B4581D4884878CD811A28484+F5A7063E0950BFE6DEA14FBD4828BA6A76E9EC6547A5D3C3BD74368FABDFC648+CAB21B4EBFEF035B64373E108C71AE283DA23BC2A2A99A0A52DA2C908766F9B0+B293DC341877580FE61A79B7903DDB85202DDD17B83A12F2C42E51E594074F64+73562A8BE527288215B1B86B1DA9E3F533FA1E4E88D3743D78013C3D29D05B8A+4B16509514F94E91CFD996C6D9B851FB8B3357D37A18200A37B87F48DD779413+83E52BE01C3A61F200328830C5F045A22191CEC751E7C225DB0856DC60558B02+01640027846783B98185E3FDD94A332B55B42144315E20FEE9F364626BEBB197+0A1068BDF8E3522A73F8328956F16BAD4105170B4FF26162D68C6A68260AE036+9531D8510089C43666CF22AB2FEDDF8489C48E1C47BC64734950010EAE833E64+1CA0701D957C99F5D7BF9322DECDDA6F87544A8FF9E456F2BEC88211161BA732+56D8D53144562E258EC0F93817C76BCBE26E007E338AF80E888F578E721CCDB6+6798210B665F3C6EAB3BF2AD40CBE334935B3A4F2291D2C2DFB56A827D3BBCEB+CEEBAE1C1E087E5251E96A3EEAFB06A297C608D334792AA11E8513BCFD39F5A8+6A4FA25F8743DD5C4F30B8235AB8D6823938FC111D4C94A04E6E36F8D118B367+3AABFA3BB2879A2668B7BAC5479397AF69E73D48A23A63A30F99A3A728CE2CD6+E47254CFF40B5ACB48987692C15B5EDC2794D4A9916E5030CAB96236424C2A99+92B798BE0872CE7F3BC51C07F4BF8A65053227E7AD4FEF8C7948052823FA0287+3535227522EA6E986EEA7E8247CDEB96512BE2EB1A8ABE670A4D338E262AE145+722651E61E25602A960C9917D5451625932681E360AA3D914F79CCA59A6C3101+7BC1B76F25958E41552F034114631F20972DB2D9D673835C44B9C36B93C7AE13+D26F8532D476157004326A91E76ED5968465AE10E045ABB256B52D2DEFCC7562+48AD209837F03B15DF07FD40867DA8CE15AC5C7ABBEFDBD33B219BFC5C19BAA8+B79E6DBE75C66B984B01FD992E79D7CF582C3682BC5C95902D3A2EDCB6B54CEE+34B1ACED85A61B9648B5985626AC5D0CCA561949BC935F4E090BB25FEBFF669A+E6BD34F4A548A66078F82D58C1C4B056A75C6B4509C9732F11E8BC29C7C3CB7C+FAE567EFCD0808B25276A284EB40618F0A8C7CBFA8A0DA4E8B901B19E67D0F87+F2DD7C86A84C50AEC7C7F36E19F1339DD2AB3D6696C20180DEED506185FC26B8+9716D71BB6DD8DF870501F461878EA3076BB54C571583742D01EBE097A5D8DD2+363B5D341D843B0859A1B524A338C7987A48AB966022C251D8DFC632B2D0EB2D+C040FFDB821A73836E623325C7FA6D7FEB9A5AD72C24213CA665FB79901DCE71+315E16E4CC9DCF140DA91EBBB084EBECBDA107AD1D0EC7A0D171ECB3D800FC37+27940AFF08AD095F27492BEAD1497A49B80A3B0F28F0F4CFD693CD24EB963316+7206B529DE83396B46BB2B1A501BBFD5D4608AC96C893D8AEE8ACAAA3F0D8BED+F35B349084DEE13F7A00622F6AC7D5263B812D31AC6135B16791E72CB268B185+6644720EF4F946DEE78DD2CB727D1CE5DCE5DA0ED8F6BD538FB73F2C2B0BD956+8D6B27420BC8C7C6AB257993520EF00BFF30F7C7C6DEFAB773AB26DB0A74774A+789F03C0CF63745A4ED65607BFA9DFBBDF33AB507C2CC585C41848DC37596B32+8757958CD50F4B6E8B523E480C82310961C3F7491743EF09C6BD99B601CF6822+FFA70FBA0698A7C51D8CD06328742DD26BC6C09BD8653CCA06A16E5660C310C7+862844B36CA9747057A95C2BFD449A17CF387DDB7EBBB53521AFBF567D32125E+554BC7DBB5D21576E47C8D7981AF850B6BE3D24CDA9F33DF487FBDF447D55348+B5C61E2B618746262D0BE032BA364673B24DDD95364C86534390445BCD0CA165+75DDD124E7DC07A22E4943C33BC0C98403351E6F636FEBDEE846D9707A4FA480+FF0CE24F09A03C56453149E79AB5D46F6DE3D9B5769071DB50889274FFC70FA5+E52B519552FD74FBCBB119300E9BE6237B4385541D8A1221854E22F0E01E87D7+DB3B25A0CD2CC40CC7870E2CC73F23E1160F6F37AFDE0B607D5C209CC24E020C+E8201B76D9FDC9EE9DA3B699CCE78BD1F324A0843CAF64E0AB799A9E96D5D0FE+8ADC953C0CA308F3AF5C424E8C2F0B45115623A2B90961A197FD5ADA4E76630F+71474BF7F27C947D86A680983681520081DC30215335AEB9275B979929B64D39+6FC03BE71E26FA49D545783C668572EA61DD6E82A8379079493E1C647F00BF26+8B3A443F7079F39D9515DCB0D9E23A3E03187E56D635701BA7EA3AA4C3B80F84+C2D9C84E19C649F7977BD55A2243ACDCDA125F0930EF29DE79896CFA51746DF6+2D02746D77338F77471EDB5F6D8AA8FE56D86BBEC867D21FB7A26AA8E39AA42C+0713A16B1CC567D21B88CF4618FC38BC19BB84B534242BA6132FD57677E442E4+E8ED2D8834DDBD23EA503CC7A8CA936F7759EBB856A95176DBE54805D5DD1D00+48DA4E05964AE85F036C49F6C54E79717C7B7C01CACC78E92967448A536EA7A8+A305DA5DF1441E5A7B1984166B8A0B6705B715112DEC87DDDF5ABD40A08C3E41+B8CFD73A17E2DE636736A2EB226C2A0C3C0AF890105F91104C07CFDDB7ED94F6+28344A83705EF381A1EC3EBB1EA00ED92831F4BE7E503A961F94C7F3A70032A6+4170D4B5FEB47BBF53217FEAF95C91B4A2FE7CBEEB1EC2B36FE72D823221A52C+EBAF02035B0ED20D465F4104BCCB10138C37D312EA06E6AB9350F912532BEB4B+39199C26B1B1E082528AF09D779EA5F5A9B8CC70AD7A54EBC336C8DF7F8AAF43+DC9392B1EB8F1B91D7E5A0AB212C97939AD28559F2A591C33AD9D94A4966DA6D+3AB23E8F59325833BC96176461D475C75BF82883A2009E94CBA067165CA83E91+30A04EBFAFE4456C92DA9FB7BECF5802EAFC6DEDED5D2C4DADFDE4099CADE258+1AEC9F3FA790392E58826987A13E550E1DFE6E58C881FC09122E6D1825546EA7+932820315A78DE599A4F9A6D4B6AE07244E5163580C729C6AEFCBFC9C5E8802D+3D44CFE439662B6B0A2B0DFC144840A884D4F5AC60D9B10D35C85632238138C3+0D8699165BCF03E773DEAA63E77040071FF7AE8CB766C65D57EF00A0C97E6A08+84301CD70746B0A624DE957031CB66837942D1B0BA06B8D2D9602303ACDAAE81+7BE55CFD91BDEAF439F98EF05501AFF8A1536BA0A0648C1C69F83BF8E96CC1BD+CA1762DE87B8C0CD9990992C3E4DC1E09AD6A02DF90D5F2789989B5E91F1E25C+CCC3DF6DA5655F032CF773FE85D9EDF4331A8764BE614C96C310F156A41866ED+1220951293898E88C2A4503DC57AD3E3348FD75B3E2F5BFD51849ED78E51AD78+0D9BB011E64AC65CE5489D4CCDD0817E5066EA810040936642D34F5CC2C27B35+3946232664E346AD4CE3D4E2FA32439EF8EF75ABF0A177DF00AB74BE2EB094C8+630DD42EDDD4ECCD7A17F87F4D2BE68C7B8FC833AAA8C8F68477D7B9608627A4+38BA77ADF5CFC0CCA1984C197F563607D75EABF535BD56089CA5A2BC9725F965+133D18A2C2BBBA9FE43C8B47EC5E51DE331A04DE0B8153161E007FCA4B718F3F+1A76A70E495A03745509E80F6E77AF068A9D8F8564C2342839BDFE82C0998374+D23FE0DE0C8D12019CB877E1810F4F18E0762B0FA0658779F9BD6F03530874C3+CC61DDDEFDE7009FB442637BE035ABE5F7C278652194EC1B61742247B3680E2C+3C1D762F44C2815C5A3045E6923D3956BD7B7FBC91FD9EB0F76E029CF87D41E4+BA318D0F3CBB876B9824BCFDD224D9802ABD39FDC406AFC5733C59E40BBEF1C8+5FD919873D6B1BCBD5EBA4DFC917A2F5C0BBE283654F6CF76F9024BB81AF9116+31CD00A202DE486E5EDEBD36C760C1163AF8E3A18A0B3D42A8AA85E5F02CACCB+FD62C4CE3DA650F8102456B9E83C807B6E1C89FA8AC3CF771BBDC1214DAE1028+67D110C444CED13D487E62FE8BD3C4CC4D437E46D0751EE126A92E7753477965+8D6393A934BB86A51519AA094780C972E280F65AE961A0DEE76C483BB6ACF072+7F6F2060BF1C2387BDA1B0E490F16309E3FE8EF36463BDB353C52CA443222235+48FEDEFC1F619E0D88D71D0ED393FB04365C914821F5CBED3754A91FE2D6976A+5CA899DF498CB1ADE55C7CB19E664C779F42F5D54B2711D1283B5139A18DCBC4+805D25ECF550523B9D054744483E111A9DB09E86F4B5CEC9F8237514745B09C9+95A8B1D1246969763BD383315FDEB0682F214B2289FE58A738365F4386BFEC5F+A9F4E301D91296ADD968C593F2EAD48038899D0A574AF9A41C9EE5F2070170E9+7D3BC9F5070621ACDC45259C708025D9646C30506D15F595DE9D52A59D5240AD+791754D5C1F9CB18431604FC580560C2DBC4F4DFBEDD16BE991E95F3ACF3E6F5+1A1CA0FA6130CEC9767D305E68AFE7EB21F542F51D335D34C3AC4B8FDDB321F0+0EB412DC5D4666DB96639FCA38B58567C79223E24FEC94430095EFF8DD4186A6+6C5284FD7B54711936AC92C6C63F8E30193B0574E2433723745321700F6C3481+1FDCD2A9CE747F58E459D2F4D4DAD9793D6F86D906DD44F56A0B60B754AFBC68+81E2EDE1F0139338455D04EF3D7B9F5BAA355547BC421E7345A9C4BD13600440+4F3A256C63B2012EB41D8C726569FD3EAB944F2F411E5F71AED7266B98F3E1FA+CEA5397B8BA2672EB95FD1494769B5FE124407398ABCA0E4111B2DB86326ECAB+7D83AFB11122E6B95B9B2EBACA77F9762BF59A37F40072D606100802C8CE9AC3+C099C7BB9684BF31F7824310C80D51ED3F6A58DB78CA47B6596061D46552CE87+A23BA1A16FB4500CA5BBFA1AC4245039C93CD0B5321EE1EBA8B407B53606214E+E02A13058A636D634335EA7BCC6C4D0700C7FFE779A429441ECADCA4037FF685+F926D984E2B12AB11A40606B737395C35D8E30C33A5B31F66E8C43418FD233C2+225FE0569D1EB0C536E76326D34551AA63C29825C0EDC342A455BAA9954138BD+A57EB71DAE1ABB41A32D8AA8874457796973DBAB2BBE4A359530B92A07C2A6E5+532C82F624BC19DF709F1950466CD9CB1A71E1BD19E6CF0809469247968503A0+389ED3A563D71ED8096735B06E3DF0E6185E66D7DF6251EA4F032C1776D0CBD9+6887ACDA5F68C861571E4C06D94DCBCC2CC185AB1B860A4C060D7DA7C3C6C45A+CB7E77E344CC6A6A13848C82694B47AD81E1BF1FBD9525233BDACBC0B14E9E7A+C22E08E6776BE1C98924AD78C97378834C4A883822B00E07A3B0EE9E213A7127+36A01BFC83AC4685CA333CC083D9A6A01480326E4462B542A4218BBD03C45B46+197F97E1686102157BAE3E83F7ED4C239B8A20D63FA0D85EC9AE6C20223DD663+E64B141DEA90D67A352753D74CC6F63298FC4F4AE42E42BA6802857A22821225+3755D8262FD0082783DEEB54D0312FD159972CB025E2DD9608D9E311BD0E36CB+68237A79F882BFD8F300A8B9E72334F06394DED9F146D4806CB9B5FB337D64D2+8905FF61942F2F13DBFAED72955D9C1D3394733E5369DE0FE24475745C6165B7+31D66CF7F562B0CFAB014608857B2404416AAA7FE34954B7D2E203BA9FF1A3AA+EAC0145241059D70D587278354C3A4E9070E832721181B99E3839ED01FF75AC9+AC53CA3741749F34643751596BD7325654025CC1AA24CA77A203873BDA6656AB+19A13B9DF88206EE367CE8792FB94C1B979A0808FD023E017249072D00AFA568+51E393476F7C707BFBCC593E20579F85B9518BC2CBEF5AE585D1C893431BF26B+EBC991CF40F1FBC243C56D0BC6BC7918C2CA7B3B4E8F3BF65464D216D04C9499+17ABAF5D7149A3755708C35EBC45F9827F21CA959233CBD27F3EA263AB102ED4+EEFB95E5FC2F174027FE408A6505008453894C8DC380B873B6D39A00539969B9+9716816DE1989AA0DBEDBC836E652D17F69AC88E00DAFB5EC411CA49F9A7F5FB+1BC1EA2C392A9EA01DA0539B2F1EF5AE890C614936F38A662667BE099941A3FF+2CF5E236978CA08095CF16BAA505DC400877FA4EA4B91859BA22D98F24E1FD4C+3681573D19A251C7CC5C86BC3353AEDE58953D713DBA6989487B5DDB871C5A67+330D93140005E69F827735DF83E6433B868ED6487AE842E3AB0FCBAACF904908+881986B7872E01632507F384E8B7B1A29268341E8D8A0D85BD49CDAEAC220718+2F34F6EE1544B4C946B67AC8E53F554743A45EFA0C284F065BF37A6683ABADEC+487279A372AEF04A20A9BEBAE9747FA31C61795D3427B8C2C21B37EA4259663A+02C890EC52365C0D3CCB94EBC98E8EDE27C092963F8B6E68ED5FB22C439B8A33+75169AB348C7ADE951BEBC57E2B499075C16B9DEA4AF3517C6C94257D7F91B13+9DF0B703550374A762704C1C1CC6A79961858825B8D33F7C0DEE5608CF320D03+AC8DA37A7FF0DEE7FFA434AAB7A944ED7770631A472993816CEB860A81B3EA83+8D9E0E0311D9FD36211313DE61937905EF38C90F86E4BA638957041EC66D95CA+65451505C65A1E8EFD292B9D6F35568D79F6595721168F6CFAFA2081DA371905+F19BC7587AAC8A19793477FD3C06B08434BFD14579F0F4978F3C4508E78D348C+40A488DE2435C109E4C664A3C27CDA8B595A834639320B1129A4170F9454A2E8+651F9DB03A08F9B7EE48B950C0A50F26D638BEC979D4A3EADA012A37C99A7F20+86F8C225D2FFDE8C24EF081FED489773D85B638E7F7BF43CAD4B6ADE65C27DA0+6AF7B07EE6E981A03AD33BD602E4464E15C0B37B80CB0F62A7F299B66105E64D+8A0EABF0D78DB68E991F0A01BDC5C993FA8C93889AE315EA0454E9DB83185722+8F6AE27D1C44C08439CF954D74074C253815D17BEFA3564FE8F4E119942FE137+B1FE897A4B0B1DC9057411797B492AAECDEADBDF1D4C010A739298EAF05BECD0+65CA5F53E8CE323320F53CA3F5D55834FC4B8F65BF356252155DB9AFB697F86B+183B904F1054FC772704D3F85C4A244FFB072CD568521FB55D38900AE4695C58+69708A15DED92315D61CAFFDA6FCE038443C35895976C25A3858350F9CD87C9B+ECA9DF1D0C6CED204D089C17F586611399B17425DF74C3E26B01CE56DE3B50A8+80A92147600A8038CF337D5C3A8D43AF4E32984F3C6F5570D776A50DE50F80D8+BA6D21E6543B3B032245EC122D5C5A4580F720C9B545209BDC47E4012F2C9089+554DB1272E0A0A6BD17719C7B9AECB7C6A62F5AB861C7B8946FF36C09FA9DDD5+EA32C2E2B722A827A7063876628B59EB9A50B5ACBBFD72C2B0356C06B6B336F1+210FC5B3958E518AC4A27598FA9B102C6629015633B5DA676015AA907AA9F1BC+E16DFF086253015CF76D7F7D24A76D35202C3C2430D721935785551864815866+E63B35C9D4A1EE0BAA08ABDCCE20B20148FB9E3E227691EFBE546297DD400034+1B80B839405B908CCDB581AAA8FE63802E9FA4522DB6DC22EA33D769A943F028+7653DA725C63E963C048E0A25D10CB2226DABB0165575C5A97C9AD1ED92C4826+FA3BC93EE2C80B3CC344AB5C96BC4226304903D5C2EF97D9E3+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMTI10+%!PS-AdobeFont-1.1: CMTI10 1.00B+%%CreationDate: 1992 Feb 19 19:56:16+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.00B) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMTI10) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -14.04 def+/isFixedPitch false def+end readonly def+/FontName /CMTI10 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 11 /ff put+dup 12 /fi put+dup 33 /exclam put+dup 34 /quotedblright put+dup 39 /quoteright put+dup 44 /comma put+dup 46 /period put+dup 47 /slash put+dup 58 /colon put+dup 65 /A put+dup 71 /G put+dup 72 /H put+dup 73 /I put+dup 78 /N put+dup 80 /P put+dup 82 /R put+dup 84 /T put+dup 87 /W put+dup 92 /quotedblleft put+dup 97 /a put+dup 98 /b put+dup 99 /c put+dup 100 /d put+dup 101 /e put+dup 102 /f put+dup 103 /g put+dup 104 /h put+dup 105 /i put+dup 107 /k put+dup 108 /l put+dup 109 /m put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 113 /q put+dup 114 /r put+dup 115 /s put+dup 116 /t put+dup 117 /u put+dup 118 /v put+dup 119 /w put+dup 120 /x put+dup 121 /y put+readonly def+/FontBBox{-163 -250 1146 969}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE+D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958+9E3948FFB0B4E70F212EC976D65099D84E0D37A7A771C3101D6AD26A0513378F+21EC3643079EECE0C9AB54B4772E5DCA82D0D4ACC7F42FB493AA04A3BF4A1BD6+06ECE186315DBE9CFDCB1A0303E8D3E83027CD3AFA8F0BD466A8E8CA0E7164CF+55B332FAD43482748DD4A1CB3F40CB1F5E67192B8216A0D8FE30F9F05BF016F5+B5CC130A4B0796EE065495422FBA55BEE9BFD99D04464D987AC4D237C208FA86+0B112E55CE7B3782A34BC22E3DE31755D9AFF19E490C8E43B85E17ECE87FA8B9+1485831624D24F37C39BF9972D74E6EC4784727AC00B9C4A3AD3DA1C22BD6961+7E0ADAF55422F22ACA5E4DCD4DF9FCD187A566B7FB661D0530454D0DD6C6C50A+7A3875C6CBF8EC7769F32A1F3F7FC1C072BADEC97794D4E90E0035282A170402+356E5A9CD9ABD80AC4342A5283E458A7269252F4541CBB6452B39ED54D336D0B+19928E9CD1AB26AD83EB209E2EC75011A2643813053B5DBB0246097C4821B5F2+C92554E9140BE35B2DBFCD98809A8EC9FC910FDE9E0D86457C70ACB056EBF90F+244DC0A5BBD455E15D6E3180311D52CF50B0BF7D0A7F64F3A1821E0AEDBC2E7B+AEB549FE1D51088C153799C6E089B5D5D65E1C4E2D2B430CDF1FFA23CCB25D95+5C4DD885310A706B320AB25C8D742C6F29953254FA54DAAEE60ED477877D19BC+D28E9AB576B0EA088171FD000B60D73B3C57F754BC07EBC9BF751B7D2B32459D+993861B7C4B0D98C422A11BECEF76F4EFC0ECAEE89723E6CED53E3678D733363+2DF068AEF0FE7DFB57393BDAA439A6A4C396F86032A98009EAE1247B7DE83B3B+E46DF2898598FF5E6CA6953127432A967E4FD41CDD60D6E413059A58FA556EF3+309178B57C16A763CFC9BEEC276944BDEA255789EF4E1ECDE1EA43EEDB955513+F42EDDCF39AE522A1DC2DC523F046EEC4CCAE25792B702C288732F5B13B5CCE7+E8B6A1A1DB86B1EA38883E481BEAB54023EDD9BB94E7780DEEA577ADAA169E66+AB7D8607B409619E79F242CF52E618AC0DAE43317C507CDB27EA8A1472D4E8D9+17E62C98DFB049C78AD15560CE44A39581BD6B555165091C5D41071212A9D2E3+05965AA02B8A67AEB04D915DADC1B84A531A1D672AAA06E9F720BA88419A3183+63D1F9A3BEF8CB2E23CD1F9C003BD7849F093D3B4C83C153A5A790C1F9E37948+5799C02F004C61A6FFDEAA1F9AE884DDD40DEB1539CFE3C3BE03C7C33CB54D56+2C2A0F467049797B56D407AA43EE6B8C3F978A7D945A80BF711C12D6BFFA3DED+35FA8B22E68BBE4FEC59E4C56D3C57E14995A8ADFA51CC6C3A84D3D775CAFA87+A1A0F45C0283139FB485B8FB0BEF5232494C0CB564F966DFE0D0566031392619+3FE8F0BB6747BDA591DFB26132947872D3B209FFD838A17EB1D5047FFA1D8031+3310283D8B93CFB23026149CCC83A182E75131F99A73B433D93A5383012559F4+78815ADA620C077FD96F85432DDFC635E26566823EACAFFCDF9AB4CCD0EFA06A+690F3B255126D1D8A238010A3C8E47A99F5CBC8F9B0F2ABDDBA49DB4F7D48FCA+A38B6087C1FE5F285F7D2B6781139C6FD1723A9467C912003A82B22822FDFB16+1B5A784C8953EFC745D0ED2C0846ECDA1C0E8A978F6D8F1E9185FEFE6EE70D56+B9FCD83EA4A074732AC5721202047A3F576C34C7A211F33D3F270D880D5BD69A+8B62F8F170CFC2DD7A62D06C9493EB295351B7DC3428517BD3504B10F9BA7998+466BE84D7AAF2F79D9412FACF96FC8DB1F3D1A51F526BC8461CCD41ED5E8331A+ED2BA485882838BFC871E212C570157C18DF907CE39F6890757198B256684B61+4AF68D85018F2368226A808018D5041BB24682C17D431F8DAFD194062894C006+AA1AC171343F767DD4A4AB494CCF4A5D26E6A4C3D450F0435238D445FDE7CFF3+2F4D6F61C8BFC73DF0C7F43CA7DEA812235D4ABCA5F416671003B029AAB0982C+E18F361254BB35B995F16703865659CB6BD9302F1CF335C90A22CE956CD90AE7+3A6049C41933F2DA6AC1351C841A32F581F308EA6EB1F2DFB8768A47D9FC8DE6+ABF0921BD80BCA56A14F2ED7709C0260E3F0D6905FA5B595310FD0E9AE237FDC+65FFADB6E02E1B6F05FC0A16EC0019563AC86408F41C1A9D0EAC8100BC2C647B+2AD226070763F1D5BD9B98E68C9C8034C3BEA0159EEBD0295472EEFD098FC620+EA7E603F272D2426458E429E9F2E110E4B092CFEC45AB5C2C4FF258E9B359BF9+24D9929339712B965A1353BCAA1274160EB2CE6ABF3C25DC621C906EEE75479E+C733ED61F2EE35D0E573502D4D030721A5202FB1E819E63B557C0CAA23CCA8CE+9E15CB1B92A145271B6C884F2FC2FA37144AD5587A90DA4A85B3CB6A5D26B4C3+D7A99BBC9D38A04385F2007D65940283BB042185E6DF4434D96504C8703C39DE+BFD9BE5DEF6F41DCD1930C9E17C98E4E6D23D8FB851ABDCE7E995463473C9824+C4BBE1324A981A9A9DDC004783547561247337D6C5145383B3F149DF99096B41+20FB5CD5A93E6B4CB21761E7330D52A16657712BB9B9FC7CE9C680819686DA66+9FBA0B17FAEC5A91AF6AB1DF7E4BCEF2FDDCFB6B2F01419CBB0423988F81BDAF+619AFBFCDA241F092A383DB564F8E0780F920A80B3B7747F2AD8A99D06AA2E77+10239EDFC09D1C444379479F701BF860E970B8058BAC3AC34B2C5B4316A2D111+3BF9E79E6F571012FD551C1C7BEF0253D96ECAB265D0F8D1F2866B14CDA03856+11DD7B4AA8BB6BC1E873D7461493AC9B1DAB536C96B865E6F16D6765922A5C16+973B02BA30073133A9AA0B8C7AC54FD59548BA42560F5996702F3DDB24FDD5B9+CB13110A3B3090582C3C8C24FEDA9B85B2A16D1B72D84399F9DD7D84E7F4A4C0+B3B50BD0F70A156B223C70D0F5E171B7DCE8291F91D9A2E78FAECF4306BC4073+2588EDC6BFE9C9B15F4EE383E1D4C3B23865B5DACACE8815BC7158408F36EE94+86DD8253EE56624A6AA7ACEA86E6DEDF5BCC6C15A295391E489E2025685EBFDD+6352854DB3A519F57AC5D7286EF844FCCD5A741C9129FAE241DF7D5D37CA79AE+83562B443E04375422218D6E39A8816254821478155FDB1C0AB4EE4BA36BBA71+8B8473A744863FB9CD4DCABB6F447E772D0211198F54D6D5565FF3DDE3847948+4B1BCB91A89A789FC24102852815EA099DA16532C559F811788DD2A8C919BC2F+1F41A1D5EB1A951F38E45E273F379C57DF79C71C10D7536FDEC701D92473EF9D+107D0A773100BE430C18515A83FF0508A5B3E3C2436037D61A2D83335AECB68B+13FDED028BDFB66F8558148EB7B5EAB82221F51A00851D0D470FD941BE0DD334+FF0C056D5F5A95A9C34F9CAABD13FC906AA92DCAB4024915490C524F98584AA5+C2E9F6FE041091687A6DEC6D0C10345225CE56F61D1AD413D7FF662C5251BD8E+8649CF78E4FE5FE2C3CE19A6290FD192FA9168F24B75AB3EC7C10C043CDBA8BA+A5430D32E1C3E75B540B1BC92D1F4C595617996FEE1BF04A67DD05B404E0C6B0+4922EAD89A11C2599070730AA78D8E30431A1FBC6F60BCFFDB7C70E1538C1BFF+C5CA56950F88D5B8FAE3DD30A5DA91D74A106706D1C6D90A9EF1034E89B915DB+D235886FA9701649CEBCDBCCAE6096FECD11FADB7572DCECEA5E4306D1CC73C4+14D1978813065DE714D4C870C5DD7E07C700A2779F84ED53C9FE77DAA37DEB89+EE573EB37C22E470041318B9AE42CE7BA8DBFAF1014E9E60CABFC0754548D3F6+F13D1AEEAA4F345F9E6423E808BD815F074D696A23DF7CC0FA10C0BE9DA4DA55+C88ACFD5B7B97B9DF21AE198C26A9B4629BC3897D3D0C641AC2BE639538EAFC5+963C96B330D623FCD75970922DE9800F491D0F4EFAD183EDE78AB2B098C57BA9+38CA7E28DDE3DE12F8DA4CE0722C31EB8764E226A60A22AC0630E2BB1115017E+75E0F46CF60B0210DB1776E7A3B56ABE33934D0F7243B488A718F83324CF6790+230633F3E77D799EA94B38BFE9921F591496DAD9508DCC49FC83663EE1130995+DA6797DE5F6B0CE43C93DE177B8B79FF646CB248D6A14225EF61B32B20CC64D7+D68D630D88F946C17FD25764A91EA11B713BBA1C8BD171B139CC59320D5903AE+6DE657AD128A27CC9D5FB97FE506F1F49AD2A8733300009A2B2B9B6F4BA3AE03+510609EC24103DE5E471003357FF11FA2997CB2CC354073F2D111C502FC537B2+84831E22382022EE408F3CFCC1FEEC917678028EF6A27E63FAABE49104A6DB3E+379D730BBBD8A8C93719E0D867C46840D9AD3B22E85BD0AC2518EAAE6EDCF701+6758DA389A983783967968BE9DC1204E7C19E6D7B08A45B4A74B368143EBDD7A+4E17363B79A441BE28D49946C16DDD12608218AA999C1C272EE62F6E5A84A722+31AF81BC4CB84B46B5A9122DDE71F80666943F7F2EC601386A0104ABA8AAB54A+EF467C6A6FD8ACA1CC1B305FE0A58D6423AAE37C095ED5AC74AD060CB28BFF52+3233B09DB79F9F321CEC4F66444D60A4320B3F02E871830A437E0790BF3E6D66+8673FD6938E5C121B147AB49C2B2E31EAC51C9ED95882FCE2BCC24F2559BCE56+602814022ED1609C0AD5EC91301F95251BFE9B1906F3C1A9EE972381284907F8+B617FE5A832BEE7D6266C54A237DCA15D0251C4795874CFEBB5D841F38920A4D+DE2BD1478A2CB4264F2834DBC92DFD72E64B4CF3CBCBAC362F0DD42A42AE7204+7DE8EBAA47583EE226DE0D5597C78EBA701B2A341A5F8B7E59F295551200958C+41715772815367957CA21AF7668116963883FE2AC03602F26DDB6AEB9D9121DA+12750A8A7B09A7F25F6F9165575433AD79F2DC9035B10405FD4772A1B3221952+9C96CB1DCDFB758651CD0C2976323FC42AD077B29A2254EEE838FA48D62B7FBC+FC2B5E90B235C3E5754423CA944C181DCF0394792567BF157175A9AE9D56D612+FF59DC86E817C01A768BB1FAB0AA2A2B18939EAB6934BFF558375F3C37D123A5+90C17D86BDAEA6B3F52E58445DE967819903479FA3BF45B8852B213F08380B39+7F2C9132DDE774DC25154672C1BF5B294B251C959AEAE06CCF6566819F806B87+D0E286FBFC93133D9E48C0AF0C82F1695C13E8FB1017AEFFFE36013E7590A3EA+F488C3AFB75DAA247AFE646C50415DF08CD5219DB3B852DCA18863ADF40DD0AE+25A7413C7AB068D7C054B451325C319B901958FC92E14A75B16E6A3F095B5600+F155C9CED8E098D51A120E293B94CC4ADC240E95199F322389AA0AC27D3358FC+947AAAD9226E5A72E7EDA7204455BF2702645F64354AE4F2CE0247CA7B115CB8+DDF9E5ABE08EEC6BE345FA44FE5C167E0F05E9EF497D0BEF1E924F49508D6096+344DFC5C9C3483C7388B1DA9D6725F19F820BCC7D9EBD7ACA59EFDD2275C1CB6+A105F9A52C1E18D039A143AD027E8D7713BCEE5703B12B7AA2867FFB56626AF9+0BCCEE502A5A197AF03478A022828672DB8DB019AF680C1CD3F123DB54804E95+DF2888202ADA0C13E511AC8A86D772DD4523EABF79B1187B7BAC891717570B49+F98858105F7CE3AA9F79CF7D6690EE2D876EC6C9495F7B2D851A50C79172AA9C+4E05FC735A9A22F33413FE86C74F7859A4892DF001788BCCD7BCBC43A9003712+0F659522BF50A19EAEDB8E4A8185DF567E9CA98048E38E4291F979E47A5E73DC+57B216832E3EED035CC1911425A3A0BCACFFA0F6211D86622735BCA7BA0DBEDB+C47ABE237310B5C6E044283C6DB33CB0AD2B1EBCA99D4E3D397D7B5A4B64CD13+29C10F1DE1CF36F14B036511A0CB50665CE3AFD12F97D3371B3361723F69C021+ABC66FFA0C01D70461F8911422069FCCF734C0241B9B214F38AD5DC8AC24284B+126A2280389B2C1887939317C465E03B01D89E89D9318595AB889284A3980BAB+D96DF8CD03713423C3183802D4CB5145FA7BB8048BD30F0C94D29601C93962FA+871B615CB64BFC5422E4CEBDC362B7AAA5A82B7AD45948F00782B1EA3EBF6A9F+98BA8E42C10981FF30A53478E0C127D058295AE326B5AB8133E162F487F281BE+D276668A26A3FBE0A0E7022351FD068A81486AC1D383C6B08612BA94D64A422B+E151310480DC3879DFA8D1050B77D99B717C2A887488F7E83044640521F02723+1DFB998AF874D28A1D53C0BA7C4CA749D518B594917ED280E35FE2D811C49D38+0D9CBB2B4595FCABCF918867DC4936BFBF8AD9FD725F80F0810C32CB3A659BD6+5A26AC64250DF918758B4F1B160C8AABDE4B8A92E32D0D6755C984A265BC9A30+CF8AA9F27A29640E5B6B54A9F8F4EB815415731E47FC358CCC58ADA20AC09051+9853C3170EA974722F4422B85B78B702035FD8160D165F4829A4535680C081B0+B7B5F11CF1C130CE49E7E4968FC543679DC814C66E4362B1CEBC87CA337D133E+5B48FC7B790988434060CDF97D108C19E8E8AAEB4046C0ADC56032AA3EBEF1B6+321AFB43402F081839CC4C9D58A1DD4217A4D22F425DAA74519052FCD816208A+23DA5DF70E48212F802BAE6781EE35805C83BCF7778FD3F1601322180F05A49F+50FAC763457A75900F19DE731D91B44A8F43B2394A4A1F3B500F4B923D29638E+E61E3E39C572A12E83E3E1C4088BFC179678080350F20B53175B1CBEB2BDD5E6+9317DCF2B8805E9324ACBC738595625AA30F00C316474F241E8057CEE8B312BA+23627F8F3EAB9FEB4F2C2CA7E419364D1C0C3838A43884008620DFDC6F8938B5+864C0E61E11BFC90ED8692C55ECDB7580E293C6EB802CF5BBB75FC6BEF71D54B+54C6FEE33D24E714AA1132271C10D185189C6C4B1FEAB7E3139697C11C91CAA2+86AF883B4134AC1FD202AE66D84D21279528B6802405486F700666F64076851B+A9495B9B2F4C6796E9C4305F1D461A1F94F5E2D3ECAAFEAE424599981561C693+26D1BFA26AE5D703F4CC216DEB5D9594B83AC851883F32290E4F1900B7D44D12+D7D9909F6FDA38D89C9E5BD22566DAA9EA5CDB6EFA3BE18097DD00C6AF060F8C+8DE84106C29496C8D4BA05C37F3975F0DDAA8ED54D6E7C9A175D0748BD5917A3+D4B02005D44CA8270D1E2758DA9B125FFA050CD4A46EAFE469C29395BD3FFDE4+45A909B0AE34DA68AD8E5E4BF231D4A8EDC1F49000B67D8F10D0C7433D7B5C4E+7B523EF05887FD38CAA294F1284DC967F131ECC7DA57F54EE1EEC6D7FFD9C741+2AB156307A50219351F0DCF7EF16F6810F3EF35758A587304209FAC8D0D97500+880522CFB900F0526811BF020053AA6147040722B4BCD0F4BE04DD787069F896+B2DE779604896E7B8E8E2C4B3FA88C2C51A3FCB8F8385D68D8521224B562E072+A8F814837967DAAC46A1D205A00D08E9C351F267297C001AA0C9692DF08FBA5E+3D9466E0BFC7FE1395FB9A9B112CCA3775FF3127CC83CA33D53E346C8D42DEE7+CB9EF23894C8DEEB5BE618F2D25EF4FA195008E48643DCDCC3BCDD774B23810F+D50D8F4DECBC3C609BB618DE16BBD3399630E6414411DF00CD7CFFD54D57E4DB+E5E6AE1B1341AF20488104F13D24C71C832662601081CB6EBA73D690D19FE4E2+9B6197550DBFCCD5B2E87F004AF1B82CB79236693F7B4FB4661081B9F0980757+A2A3E71B6952CCAC37F35E1C9C8B5D3BD86AC11CC44BDAEF80358DE607B29BCC+5681643583E8C21339867E32FDB4A7ABCACAFAF9EFA9768798F6E1033CD83185+EF57D0805939B5F54CCEC03E8845BDE0B704E760F1A23CCD642CC21902C69D15+20A6E8883A346EDE422DE52094504A3195A24028C79451B0EC98636222360519+AB48D9C8B619D58ED6FF62F010199FE8FCF738DEFA5BC046353CE511B8A8CFDC+C37B3C2ECC13CB074BDA926991100C680E43A0A410E989AE6A3990E82B6DDA75+1876E7D5390C512B7852AC968684C000AEF4EA031E2468D0760C1D381AD7BDC4+37FBB7FC1F5C4DD78ED78B0E9E9117FC2951B5E71EDF2B5ABE557C25F7F4FA6B+B4F4308CBAAC08D3139759C98ACD82A271A1500615483F0A054E650713222573+77D0AA8904796B6D7AB4047B474BBB6CBF5A911E1462D023C8C13B9C1F6A077C+F9906E34992930B5FC2B68C3CEFB9D38BE1CE1F3AF216CB615018BC65F777A59+A0570A435BF1F4C5C0BC7CB5681C4760256DF84881AA38A5638D3643B32C7AD7+27E57799381170E4FE59744B210B0F13668A6AD137D7C707C965386B4D591A60+5BFCA8EDCDF58E2AFE19596AFAFCF689BF93810CDB1690B6549159C535C18FAC+FEC358E2FF465947960DF6387D2430483C9B6F4759712C1B395A9532C9D1231B+E0741952AE91608331BFA17C14566A232EB409E16504964D6DE18A4DF5571C48+740B4C798DD2155776BD32EDA617F9E4BD592773DE8F39A34968699DF3C90582+5661CB396582B5592CBC75344A1B415B418BD7ACFE9D38545E0247FD9F00E3D8+ACD3E6F17980A903CC4BC3DB98EBE8EABE7F3EC0D40E24D2D533E3CDE2F2D11C+3A20E6BD0B6789AFC7ECC03DB3A190272762AE233463F50504F52594A120F8D4+F6A70882C55BE51A786F4CCEA0A4F2D89344AACE030D7F94C09B35DDC395929A+9EF8AB1C0668E8FE131F9C8674ABF8936FA2828DE9C78F3C06EE7B7D83F8AA84+03EC1622168A91B599FE51134AC07328A41AB4064CA1DCB2BE2091C911718915+337606A85101826799D2CF7BC88EDCBD38E11AC423D24A7F3DE4B90B605F129A+05396B33B7FE25C63AE69F1162AC18F073D6895619194A84F16B930277E9C07F+729D00D71998F2C1D12754F37C03BCF7D102860A6689BBD0BE0F069942D570AB+AF9F8E63B0694E5B6904E1C54E156A5A89FD63B92A403C7CB45B9052637B8624+4ADE046267DFB5152396AA03495B9424F56A1413D08A9B565D2FD135A6E74796+10926DBC90BB99BF3AFD501A3D4DF936AFD64C71E1CF727D6CA669477371987C+C315DCF89A76F30103EDC2C1DED5891FAF1D172358F587850F5112B0DADBCF72+E19F21942D4A79BF0CF62620C7C94A408D4A0BDFBA69052074A15F12567FFD8E+4BCF71010E593C6D9C2E51FA6F292882D26635E54A6CD9DC64FEC6B7037F6842+8AADFE8AF06ACC22273D36996BE904F881FDC40765CA0793AEA370BE0AF89029+264148BC09C73C9F0B45E55072A44A878324B3AE0AFE30638F60D1DA36114977+BBB69A31C9E331B909C010A6676D499FFC22638D22E0AA44846EEEE4D2D199C0+CB7DF974745FD463B69BB5D679AA446EB8FD789FBEFC3CBAB6D8F90B59968F72+7F81F364FDD2898B553FB2F977327714ADF271CDE6AA94CC84349113FA602E27+9DD6B0B222B24E3BA3A67EEF366317C44C252A708EBFFE041E481A4C13492EF4+48512C1F8BE0FD73792637F615FF46813D3D8316708DF8C7F9E10D2C2BECA814+B5EE9913E335E68ECA7277C2A5E24AB1ED932F09918567197FC4BC6F43C5DDD0+208BEA11CC8C496CF0559F329F1F5621E289EF06CB5BE64D1194BEF0A000BEE2+6EC1CA69C63909A41F2361D7EFE50BB81B44241293B2A975725E045AF3BDD0FD+2098D1C42584E59CB08656E984760C85686D82DD43D499533AF2BA2E071DBF3A+0E54F92456A986BD7A8F4BF6A5B8CDA1B18EA977F891C9AC24833680BE9021F6+8D6BDBD269FD39EB3F786B51B6E5B05408CD44D306B31983B3076FB0C3159F7C+90644AE505A4E8BA150B9E682079E43BE8D919B8EA8154AB5C405CCEC40D6EA0+756FAAD38593C9DDAD10D23B44A5ADFE9A0BABB0D60344FA3E0BF64AF11BDC30+FB2925E4C9F47F6FB9B0500009D28FFE9F23AFF5855BB8A13093EC9A3BD7F08E+7FACD0141C5BCB984282BD7C35687A163EE79FBD0CEA90EB7CFAB4147DB0BA12+1E55ACFDA262BDC5A099BF1649AD377330D0B1BD5BFA8869FD47EF0B4E486510+D99CB04AF42B75C8492405061DF43AA1DC8CD87E388EE5FCC91E723F74FABCEF+1D081650B0AF743E94EB4177111A15BF32B7C418A2BF8DAC32CC34E7D602B85E+BBC060F06CE788D30D92F166E1794732BF9D795990F9360A13A9ED49AB439CFC+3A417D8FB59D44146B07BD47A9F5216F29897CCF32AD68262C6E2EFDC1CC1B50+B77274BEC0CEB772C3B8DA80685331E5C170B4A2E5AC9A92B76BEDE8DE12CF38+2F32DA4D2799BB36E005AB2E2D131C4CBE6CAEBDD63154FFD60E31222A77474C+F1D3D4C20925A39340E47430CB61915D435699737FCB2D9407EE5D565AD4A7DE+C0CEFFA44B6CB52CA6D438D61FF8C5A9B406F6F660F450100D3FC4F5BE9769C0+053C5C0F06C21F6F4A4F5A0A18A06AA1043708A79C54288399B5FA8F0F64DB25+4FE172B8A7ECBF728D598BED3CDA29B5CDAE2FC1541085CA15A427AE95111790+F46992DE5D45ED03CDB1FF88E95C51F7E068F550005E0505F726766A58FBC820+1EB6429C7CC6C94BF7BC4C94948982296AADE1AFA188D0E4973E649B8B1487F4+1653E1DAEFB1BCE82D2CAF5EE6902D42A81A96AD19E70E8C257A4D255CE9A8C8+7E7EB4E68DC8E3AB43D7C7D4EAF3EE63BD5201C5B9607C92F17B26860945597F+7D8C1DF39EB59EA3760A2AE373011E35DC8401746917EB5CE597ECBDE3304C7A+0B7F92574933CD8E238715E65AC400EAFE087C031E2E81227CFC94E717C8BE62+34A75552393945834FB3A1E4C5BD0BFA936D151C0D13C076A0EC657E082A5910+BBE68C8F161040BD95533FF64A566AA092F0DB232F6664395FC8AC9E7C660790+26B14C51DB4AE49D8A577B9FBEF47AA22B4AA169F7DE28E1356A7FF67051CDF2+03661FDB539DE88C2DB9CCA576556CD3A79D7A0A9F2A937CB0879BDB70C299CA+0103872AAE24BC6578A97A726E1C15C8E1134D170A3B931103A9908A2530D4F0+EE5CDA9919BC878C2055FB370192910D5E0761945362746143D9286CF5F6FF44+6E90A1157781CF24BD89A9DEC93DC8122E040A60A65FDBC465C6D8A8D3F459FE+9EE924B56A0A5BB600D5A1AD0569522225F8E23975C48DA5F3458E844D1A160A+A7D3567F9DBF359A6423E08FB96EBAFAB12ED3DB4CEF5962AE81C7ABF32EFFD1+D2B82A2AF2CAD8330EDC66A779EF6411B296F7F9A0165185765DFD759E1D70C8+5A88A55A64AE6ED39610B3D6CF69D0D903D4B37456243B9343EABD836F9F0029+43C50EB9E6D0F410D755F95D3C6D860B845BBCE8FF4C16D122941052861A93DF+BBBDEB88D1E18B0E499E47FD62F1CBEE5FDFD71602744D24DB5167B82C198687+A387C97FEB6E86C84DA0EBB3D1375653BC3BE542D19728BAA64B8703E08860DC+E3E1BDA52CB695519CBBE44705BE29180ECE2EC2F4FB9080E5F574249908DBE6+7057BD7460981EAC9FC2F7A7D814739ED3FC4A4777F121CEEFE4EDA88941BDBA+7EB292FB68BCCDBFAE40F6E67EC484A3981BE6B3AE3974E81576E4F1A8EC79F0+D88D349525D5BD308ACB08CB74FB4646DC525F82B9B950B602451588B10E3BB2+BBDB73A56CC7F7892311F7DE58E1C2CE21F5306777364B5670258577D232EC68+A0616A3423A73E7DD5326998EABB5BC27732BBB85667945445F1516CDD9DF8A0+13D6CC2161B682E43BBE3BCAEDBAFE48C5D2520E87133A0E33A29D75D4647F36+2B77440B1897C8414B01D9385BC0867E268861756746B128D6B672AB88E4DCB7+07720D7953008498CC51E8FB0E029038A5F12C0462CB25B14689FE34568EBD3D+F056897B23174907216293EBFB9800E8F065B65B214B4F7AC5E77BCF4806ADF0+8B34D4C48389BA3245B0015438D7BA643E35DE881809E60705083C3995AFBDD3+37BA3BE0786E74678D8238953E948EEF80981D04190ED9F8D1CF4F95D6E6C508+5AF689D7B19A04315BFF34303D4C17AF70852B989A8843531F2F6F24375610B5+FDCC9C79DA56BE3FF752A8F6D5C95A1F7DF67FBC080E2FE0EC677746A671292D+AB11B8EA3B6FC783186F46DEB3241825AB4A5E1AC1F33D81C0B8472F58073E6E+2CED81E7C7E6915448BCEC50EF9420036B75CB5FCFD900E83F0CDE519D1D7D6C+E56EC34A4ACC2CAA45E709523EA749449550BCD83FE909D3B5B8DE183158C4C7+0E06A732365034D1FBEDA9BED72C0643A123E7F67A1803E1AE7608C98483C1C6+AFDAE5657CCA48B56F5F2599BA20610BAB2E4E8C0F47D6D9A8195DB3F2A175C8+34BCFAF32D12CB9B75EE033B83347C16F0FD188403D21755F023AA189D28219E+BF74A18F5872CDC456F486C75D707A206F36BFD75F4ED143354CD9CEF83AB9CC+1F996238F43877BAC8DA090CCC6D0ABD92DCA7FB0F9634CCD057ADFEEFAA5010+CA86625263AAEC1F97C314F37A8117664E7CC8049A5847C7ED9E4B7A34252728+24D56E8CE2160DD1775FD481E63181C1677E9F1A01C51F52D0F0478D50D5CA55+48E881CB36323C944A95BF73735FF52D5462726BA960D2BFC21197EC854476C8+24B5F240A51FEF845F64258B5D2C13EB77A2722A031AB9BB514DC961D0010162+8C39F0EB16AE848A07747B10B118C1C647C45A3D6140E5AEB7971126FC951CFC+137ACB7A5C94647691102010A574A2FE019539E2828E88036583054F19856752+539D5D55722742E2C0A7FCCA43B9E0610F0C0F84B2E72327DB2AC7E7613D7E59+75A63485F3C4D76D3DAE434113AC3BD922ACE4F6662C3464E853B6E11E3C1430+0C37D7E004653AC666DD1389478EAFD5276F2620FC0C4009E2E6202040ADF455+A9AA6D808ACB88067984A45CBB16CCE1C35203693FAA3DA9518A88FCCE511277+72B160DE45E37E8960DD690C170FD11607020C0B4F2392D07118A05397B540D1+E2942CD57DFCC51CA3B3053E5E473C03EB7FCD0EF371ADA6693FC8F617113527+ABD75BB23D3A9B7A91121DFDC03065C2721A053D6575A69B5633B8AAE074906A+7AC314259676ACD13FB060DB88634620D3834EC818726E3BF79E4894E23CBB5D+70C124DBA13521A553D594ADD6E5056229BB237204AC1BAC593567B71C82AAD2+1E2E9C95FE4521B3D3447743B3998E887431D577A9FD63ECBD57E79DCEDFCDAB+F01448D3241F42B4CBBB7AACD353CB491B7B7912354A845E779BC0D9EFD2BEF9+52B30DF49A4D845D515261F376832D17E405D36E253D422B70A5C050EA9F7155+130A77C999B77C3F39724846AACB2CD0376EEF83B3D00515FC8B12B29042ED8C+0AF668DFB50521DE13063B162ECA4BAF72D42BE6BDD4A172B6969313B9C09D1C+D1DDF444FD4C73343F428B0CCA7CD9024167F130168194DA462707DBC3F92AC4+33F9AC505DB8F198556E3FA755E79CB53567B02F5926AADD35C5CB2BA42AEC96+C1CA98BF1C81A837B4E80968D9A08D5613BA4FCAAA93B83AE9B62FDF59EC942C+9BB101D7FA827F6F2BF766CCEBD5D3AA87DDD15E94F1C70C9C3E148B9E7FFB76+710D178C2C3B39AFE890B1F0490B8668C9274C0927B79824C17F5394AE359EFA+60C9D2129F38220A77A4DF87AB5DA58946BF6F0B2F258E89E933885A752D518F+263BAE4E6DA2668F41C4C972325EF740CE2E4115AB6ACF8B260F14C94338053B+8444B4C852D0B5C0F989B9DC9B81BCF830E244910608CD0EC301BD78EC9A55D4+082ACCD3117285B3443D7E99F18C21253AE6E4913EB67296EB1DB466E3DF6178+68F68B355721160B6424D665BF1ED7E49FB4AEB705632C12A82FB363F250E950+C5D45FEDD017495C52B8A392+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMSL10+%!PS-AdobeFont-1.1: CMSL10 1.0+%%CreationDate: 1991 Aug 20 16:40:20+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMSL10) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -9.46 def+/isFixedPitch false def+end readonly def+/FontName /CMSL10 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 39 /quoteright put+dup 44 /comma put+dup 45 /hyphen put+dup 46 /period put+dup 48 /zero put+dup 49 /one put+dup 50 /two put+dup 51 /three put+dup 52 /four put+dup 53 /five put+dup 54 /six put+dup 55 /seven put+dup 56 /eight put+dup 57 /nine put+dup 58 /colon put+dup 65 /A put+dup 66 /B put+dup 67 /C put+dup 68 /D put+dup 69 /E put+dup 70 /F put+dup 71 /G put+dup 72 /H put+dup 73 /I put+dup 75 /K put+dup 76 /L put+dup 77 /M put+dup 78 /N put+dup 79 /O put+dup 80 /P put+dup 82 /R put+dup 83 /S put+dup 84 /T put+dup 85 /U put+dup 86 /V put+dup 87 /W put+dup 88 /X put+dup 89 /Y put+readonly def+/FontBBox{-62 -250 1123 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE+D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958+9429B9D40924DC059325D9D4CC0344F3F997A99E6CC0676735EBCD685AAC9142+08DAFEC78BB41AFC2F1C219910BDF41D6279284EF600B69776CA15BC8A34347C+30783C52AFA60FBE3E353E2AE354CF87B558776A22C776C7A0B5AB5CE1F941EF+C2D9CAC37294BF407A671F10E4743BF842143F4F7DFEE643BA3BBD8BB9E3F24A+BCCF7F0ADF8BA500620C81033EAE8C4EF2C1DEF13AC575F1B3BBB66F093D3B78+5412B82B67FFA087AF57182B2230F9F2137180CA58A7D9B2C822FF04BE6CD01D+43B2CA7058C7B953F6D9B5D6E91ECBAA5CDE1159B0E59C83DBAD96D6C8C8BAB1+374EF652D10C0F3EE7104472C98DD3572AAF2D45A70BF7061447E21EE3C3BF23+DF39C2D1B35B42CD5297BEBE6BC94F7C9DC6E61EC67E4F677256FED9064BD3E4+B51A71B1D27CA4E5AA9E1D8080E6DAB5310711EEF87C40859FA935B19524AE83+63B163FA8397BDFF443227FEDF7DB27DC35D89FB1C5E435DA0619A5C88AFC73B+89A2DF5E767C5B536BC7167A840A0C32BD57A14DE69A7D0D819AC36FF32F908A+5070F32983BB007437E3500799DF5E0AD3710A4C0000F0098D5BE99F2EB9C1C2+C444FD9552D0DCA098A94B3BF176F511CEE13DB7EFFAED7C47B5ADCF8D4700F5+7A5FD1B49560969BF5C44F3749370663A04776F749DDD7B50674D93254426C4B+EFE264BEE7810EC93784B7C01A7F29EFD92547E13A2C7851A2E709FBD5B87850+4A44F08F56A542DBE072D2FBC58D9E6468E1AB858DC35240E30D31C7AC13D6C5+7D2BB634BEE96FA0E10F842B11A789F72A333DD6DDCB1BC23227EBC406E50B40+30AF0C48E6359AB0C46898CDAF1118E46BFF8B00F54EACBC2AC262AB898C42B9+2E080C10DE923C1F7BD11CA700DA95F7E94C4C77EB24EFB7D5DD20F841657F2F+2A98CA53167252E235CBF74A9CC33BC9B728A1A25744F3FE704E248F1A595421+F0004C202035B7423E4672A0B06153CCAB32A7F0244729F9E6C8619F7A9DA257+CB332193B00FE4CE4476A289AE36484DBA30B2CB3A0B994C742CB2FA90880BBB+D0AF67C5BEA3FC6B11D73440CE8EA5BF894751DEE41BBB7BB88446468DD68B6A+7E1DB7ABFB509DB0F1C444D40F3F5B4B481037010B4858A081EA83862B3DEB8C+A1915AB5732DDE41A6D8A8720A094AB0724E2F8417C7B9AC7C0A2BB15317E744+58703BC2F6C225B688949DA552ACC693163EEBEA5B508716864081AB7620944F+79350755F4EECD448A6613362E3B4591998681090A6A36389ED4D5571BF2399F+FC4CF5D90A0371F684E364BCF04B67627B5100958685E60BC9E3C19DF1FDBF5E+32EAA52638A786476E99FA12FC5A8DD89B1BB835E53E966052BD0DC343BF4C7E+E0C0F46E7E4756A306FF56AF7B6E4506F9559EE7DFE6607717CA4D771131606D+910E86E944BC45147EB50059F03FAE14ED0087F7C4661C8C5DB644A46B4B64AC+42EA834C9BFDE292ED377E861642DA6ACD38BEC2E635B21FCCB078817B89FE07+3E5B6D018ABCC8BC819C7E2861635496924EE9D1292833A2B36386413783D1AA+6266F6078D3B1CB6BB75B18A8649DA6590C592F9C5AF83C74731C6743C3EDC85+3F38F761ECD49139D84FFEF52B9D63BDBB7FC8994987CD108E8EBCB6932C5476+35080A90FD383001CD2205700AAF27E289E3C1B2AB4AE32141FF177A2EA516A6+BD7F2A157EEAD178E2E735FA155C3E3F70549BBE9BCDCDF9C0C5892FEC998DA4+CDFA80689DCF5A42AB3DC68DA2C355DF28F536C70ECEEEB2E38AE50179F35C5D+E4B87691D649DD34FC09FD1345629E33EEF1A7D0DC55757D5EC80D7C3CABFC1B+989F36CC1663A2CB7C63C9D124B60D46DD1F07DF3FEBB5B02F9D82808AB66F78+F95CEC8F5D4331697DD12E31E5C37E9A27086182BB6BC4A5885C64A9B317CDFC+56F57C5F8EB5AA6CFBF2B63562731C26CBE80348B8EA6B7755BB4DA7E61B3C79+AE5521E1BF3E2A5EB2024227162C2F9F65CBE9F2844D1D6069DC136D5A8F232B+0CCC3B797FE45E8C6420F0E48FEB0D54FA610A1614A4A5525B54DBCC44FA107A+D2414312D348F053FD45AEC8C7635A4933A17C2032FAAC5AA117BF31F7ED6CD6+B78F3768C466B09B748E7F50CC28B93AD727C10FD30CDA5CDC178C038129E4A3+330D74167B9D0C1FFAF7E8472E846B705450BBBD5ADA730AF7F33B52C7633752+254C6BD8C152F3422A55A44F3E41B595BF79642529C2B78DD06805ECC52A8EEB+9092EF4D71E1536C88EBF86FF73636CF6D187BEAFAF9BE7FD2ED9C8BB4BE24B0+3CF01675C10EC037930822002CC48433A9095BD4B5A2173EECB03E95FB2D4AB7+FAEB8D8766FAB47A1FB6D841E7B975762ABBE13CD8C3933CE8AC70D91E4B616D+9040D8575BA77B76F7B11953054CDF372632E6C1BE6ED8DFBF753A8B45CA62AD+DD77F54499884CB72DFC5FB2BC4EABADAD83C124803E21483593594A540F632C+BE94073C38599032B0C9DDA5293EE80624C7FB51277FF822BA7696B23015F79C+55F4E09F1D73A560F8DE681FB8F90C8C7F6DD41CD4894529B252733B0208F875+72B727B3B05506048BD822A24C0346E8E712F1BAAB312BC97405CC2411C032DB+0310D02CD0426228C8B6747B662FD3F5C8D02DB51D410C04CED213535F2652C4+DA65AAC7E790481F7EC31126152E7990FE5CBDB7114BADCAEF2F54989F356863+733BF6F36C27D733572EE858D7E1C6986AE7F72E2F35D70711D551087A71826F+9CD2DC7650140C16F8B7E3208B68B651C2204A2A22EA123E7AAD87E72B911E27+A9EE894320E5AB636DB4928D0A1A610532EB51EBBF0F53EDEC612A19EE1AE64A+B1E1977973344BB6AC13267DC826EABA7231EAEEC4BE162EE2A5A49F754C5446+245F8EB61E512611B721FC50B7C194A07AEFA3CAD7EC554C550B88BFE0433943+C33C4C5DD6EECB6E91ED1759F40E4933F13123A4D45FC62E2E016D5D5957324A+08A4F8C7A24CD314794700AC9D2A1BD84BCCF965917A582A16F9AF4BE4C4CF3B+5778E6E0CE2412574DD0D4524BF8CC6832AA77844816825CB5658008CF72E779+505743C063078CB054020BF0C21EE41F454BE7937B2AD9FB40CCFAE88F0EB1BA+94F7AD4DDE47B07B9722EF72736C584A4969DE0EEBB136347A46AE223D32E1F6+A23FAC1E731DEFE1B895B210F8B4DAC17EAF4875E5DF34EA77FA6598D436EB58+ABF4C164FF739A0DFF080D4DC32655715226F0BE21919E0E71A90683E32B8F43+42F9B868BAD21E603446222153EDFCC344E8C3B5BDBEBE36CA56507C17AF5F65+8E6CE5ED1B8643260B4261C1D82FBCAEB51EC4402620FABCF1ABFDA22E6ADF45+A2EB8C2F4EBF40721D300149DEF3963F491AD78E9590302388B251EBCF70FFA2+F55AC2E0C2F1688C840CF6B9EC26E84F373010229C03CB52E450E0B152B1AED0+6C7B12338C26D07DFB46C4B282A69093C2BC2B334D5D6C868F7938B460B6D9FB+12A3F2D7F3B6404E054135D0647C383EA5FC2CF02D3560DC15A8EE62652C1E46+1E8195C2BC29D5D43D7EA920E8F75E9C6EAC89D91864534CE73343A866DC9535+192478C8947B834785C520A290B21A024016919EAC84701D2973AC0A7DC2F772+89D1FA76ED8684077B120EA10DF3EF71889AB6528AB76F7A8B0917E5FEBCB59C+8F36A9DB812633CE0D9046953135AD47DEC9B14D0249444C0949FE89F0037A78+744ED9A76645D51A3EEECAD8847FBB1723AC590F9509593D76D6C6B4CB926A21+8E8A3607D3076A106EE223BC909CCA7F3718FB81AB35E887E6737F3E1AF2987E+BDA4351CC7DA2F7D8671AEA1E1A7C343B7A2D78D318A75E2C57C762FBAE2A97D+DC51B8286A1151D30AC721AE6D492E2D8A091756E5AA0B088F883C7C4892CE81+786F3962EC166753843C2734BDD51DFD05DD35114817B6C64D0D130673D6D777+64080E37475BA0ACC677C4B71EE5ED0D3AF18531D5C9AA64A6FE6E09AC533873+D0D31A433606F1668FC27ECF953C682F3F71416B890565A78AECC9F0C0B1D52A+EB6D71C20392A53D3F79F921533209103C52A57AF18A7E03A1D5933447764191+1569F94A8A840EC3909BF9477D4E322E52E28717D0482563883566F3182B02D1+5EFF180228963C2D770BE56E82A06992B2F85AC53188C49443CD7CB0A22AB214+A6379D919ADE2E6F6B65E777E35FE1470A88979A689F103847E8B909ACD5373C+6AE91EEB97B690D0B3013B0A48F15D959868EEDABADB538FED47B4A6A4B1C650+F4F82EA81545C61B8ED953709701CB90CBA14FA7774AA25B8FFFF474970AD4F4+832160A30D2F55AB11AC3396BDD03553509C64B31B6DBA41130BBEEFE591E585+FB6167A500EC256D0F925E431E9127DFC9576427C973948E0E6BCA00038F630C+CD143AAE8EBD1E839F88B9344931F6DDB9A562CA3CC722DE32F41E6E934A9A57+D07C25AF447F38891CA3BCEFEDA7602A2A2621512C67D96A5E94F76A47A9DDFE+82318C1DDA7B2855E0669497E0E24AD1CE1CD51F59746A5BEC44F2801B003E29+122F934B52D944CFBC749E17FA227B6E6642A193F73FDB3021D2390B2BE6DDD4+C2057C8F3B7A5D5C949E97F42E3F5107B604A4D9705AF40BD83FABEA605BABC4+91C8E5B5EBCEB5475F5A9019BCCAFB92478107D8F276F9561D6942453C32CCCD+331052BECCE6765888E4F00ADF4CAE2D8DD13433A5ABF7FED4EA4AB00E6E6056+9F8C3CD73A07EC3060CF03D7A4A66572201EE4680653D8BC4BE22B1B5339BE32+37D67800EAB78AB57D119F11BB77D2A19F6871644EB014D3EC0EDFCBAFBD90D0+88AB1099196F84D2E5D5DC394F0B5DF3251F9375CE58C2DBF674201407652864+3237A80E1795A4FA734849350C99A65CC05520FCB6BE7FFBD0CED739A1F53C07+44DB87C807908E489185264F3C940A7536DC21DCC1A93E7E50B906D57FCC8F54+54D11CB3552EF0984FDAEBFBAA4D5ED15E2E5B5D2AD9674AB5EEFC71A02F8B8D+6A04AE8D34D2ECA0777DA51059ED5F1AF8D390A60EC139EFF51F923E1B323FD8+FF15874EA79261281B25BDD12E10375CD9A5B73AE2B91C862C3EFA64010D9AF8+C781D180D5923C7EE8096A0B206D5371B3016B196992D0F5F7CF182AAD9B5F36+6692608E8AC1F5529D2EDEF49ABDACDDDB3272A1613745DA5F0772D54E4D3A64+FC74499F7CC5E9FB5BA6076855F8233BBE9400B880E289EDEC9CB66686034BB8+671497097D73100A5E270EFBF84FA76A19CA324390023232C5DB66113F15E20C+2820EF1BC38C86B12B1B9F70DB1A21DAF49237521887D61ACD1FC4AF79AC7858+C7E62641328ED1E9EE20374188F149E2BF6EADDED03F41D1D71C08774ABF4747+54914248F6A914D1E7BE7E175DD2D60C72F18D913FA7C05FBD8058497629C24E+B96E9274733952BFFD659DE6097E575B79F95051C4B209FEC2F21A77DD60AC40+2F8E462623879E45A2906E05901332CF4C9F0A80B13970113BC1ECDE7693028F+FBC05EAD390BC63A8ABDCA629F32AB2CA94ADEF4B4DC9F3B309024A286B20E09+FFCACEAE651C42491C88A1426F280C15318433A0DB6E8109CB119F6D37B4D0E6+345663D39AF6DFC0A28B7A663969BB7006E5409DAEF1FE3BC9A0149A74A5C241+66B086A5379377093B00CCFC708BA3DA28846E21102C88595828CC43D978796E+99DD8EC1B1F80E425E58D089C7EF75F32AE1215159B066E9F5327917B9D00690+72CAE1BF4ACBFCD0EC71BCBE7F200C093A8006C37FBE8A0F89D7CF0EBC3B9D15+E2729E8F5FB8E37DE034F691A2634E827801D696CCB2BBA0AA310CECBE54042F+0E12E27488127301EF5D45804368E149F2296CF975B539DBE7646DD12EEABC29+D1C649CA24867F25FC2A68988FBF883C8B4C3BFCA98A05036D0544CBE581BE97+919AC385AB55F31AA73C7DC943778992552FE0555DFD3A56442885F07D4BB1F0+8767EFA1A677663AABBC20A39B827BFC208F064CA965A983AD0523A21BDD1074+20336C4F67452586DDA327335E867B134364D876090E2E18AC1CF6F9366EE3A3+51AE5E818E04EE81773D3D2B194F6A396332802DDDA900C60F5641677DD0C429+85A8F324D8D9696AA65D24CEF9F87A5AEC7B392151B7F378DED7D9C3D310E065+DDC486D56DCF4947D26EE091D0889CB99FB22895932E608BE9A427E44C78C90D+EBE9BFD48CCAEB5083F5F4A9F9479350B22DAFE848F0DF87D5035D6CDFE49B6C+DE380DFD13E059A26CE01A0C2B76730CF016B506EFDAA52B6AA591601BD3264F+993A41AAF52800BCAD660E64629BFAC061BA1D8E411FBF0F7E945C4A1335E27C+F39544BB6C65E412571259B857837C0C3059999B4B1C94E8BC56871B97C48D29+34976B9C16294E11C414B1F1FF22A8EAD1202B97A1133A6827BD99B50B7A8CE5+BD5BECEA52660165A32288C71A1011D92F0F46885EA0429B89B2F0B0B09DD6F2+8143D8703A64537B802E2CF0CEF5224F5A570DE8AFBAD463DB8BE466F0F68C7E+E0A5EE3F05AD11FD2331B0B32ABED8771C7B479A6E067561D7F92701E22B63C2+D5D8AB3063CF7EFB9AE2F4C03A8A35975CC4096ECA46C9F86EF54A0FA538A207+E5FA8DD87621DD61CF81BF8D996974E1F12529DBFBBA52C5739DC486F5AA2EB3+013B7146A18B21F27844637F78945212B82DD3C0A78CA349CCA92F895C54D231+D0BC2DEAD64CE229B606D54F5F6F5131181069596BE723AA2881D983EABF968B+25864ACBBA0EB46D40D1AD5BF556C9C5A6BBE379B924E6E065A182A9BDD4E3C4+E3B2F9AA6EC8525ABB9E064552455412F333BF1A3A347D984357507FF5889E94+AD3F130FC2C00FDCA548333B282A22713091DC707F50E8D7BFC48EF733C387A7+DB6B8F966763FE94CEF77ACCB374A7D5C6F7A103F309F0361A1648469B59AF40+71896938528BF366DF382AF887FA5B5FB2B1413AF64660958F1D5D86252CD823+420BAFBFC170CE858055080602AC3496247579549C56CE2C548FCE11A80BD8FD+22FE16EB906B23703C9DE64C0DEADB5B835E466C0233243F8BA241776EBFFF90+6EDCE42A1D882CC87B46CD1671D4742D879E71B437B2192A06FB2F591443D85B+C4D948A7742C62274A193EE16BFC487C1B9E943294F709321CD4BDE6BF00B4C9+2E32697642CB2A8880C85C1457CA55A901039A39D29F327684C52602F1B1A729+56A5618F09D2D411EDC9F67796071045FB6EAA89DC405064B8ECA92683A738D4+2AA81C0972071419F02D03EDA1DAFE0A27D318D98A9F6F81CCE794DEB802A4FA+A51E52C8CED359E409984C38E0F327F5FA7148FE3C8593254A0522124FE447E0+6643CCC1FAA9E7C0A670D88EC2D839FFBFE190BB83DD031AD61511D8247C9C38+41A5E5DA3FD91B046CCBCF9B32C4DE864E51D656A0521AACF4666E8E955DACD1+9D0E8EE6C58BED96DF86E60532E4CC586A6FE42F8CE7447C91C9BE29A1461C7A+F532A0C1378F11932E0B5069D30E8DBCA1E8E74245D6673FC903E7FF5E3B45A6+E532E6FF33586ABC9919A1FD64B8CC92F007D9543C79A4A4A2A7B682178F840B+B716FFED906F924D826AC93FF1E319428CD6517AA2723096C4D674A5FC7AF2EB+DFB08EC1FC2CDEFECBEB35D9A073B1685FF18F0B5AB6E50DE744F135E0F90D7B+4EBB35439276AB948A7C045E8E13FAC40B62634AE92BD1D687564DCBB257C5EC+0D05E2841F59C3B71F246B83FD6D42CDC0F6662BCB515B7738D2ABD4CEF410C6+37821FF621B191CDB0A59C83489AE0856F689FED1EC3FDCA0C6AD90F5E80FB1D+A04FEAC58F6C194CF999EA197E3EE3FA7A9F0C798E76E6DA10514BF37E95C3AE+ECA42CC37774FD049BFAF0AF1AA309273B8CF8FFA3B174F5D8DD0F67BC2623F8+FCD12232FCCCBE4418C8A9D8B348665DB77080CDD9652E99E117333CDF0215A4+D24C2F97523FF99C32E894591456F1559F919472F48A7DFCB59D3C3E3EEFB61D+58A15423BD215B99CF77898EB796E960CCE6FB30EF0FF99BC2BCB5172E9D4B16+8AB8AB28ABE6147B623F5092E2693BF1BC623F42E64C67190A0EBCB50A5B3C6B+3DB33B2B3A238BF80FB7A59A85EB44D9961CFBC4AEA9E176F90F0D9226A017DD+F3257B66990498AA0C5E34F6A073FD12914D1C010BD1940869466D65CE8C0F80+A1691B85DB8A3B73E2E16FB4F6D1862AE043E4241E3CE3BEAD33BE233C050E1D+44CA25CB8B3AF849FCDC051D8ABD3DE1E5E0646D9A06EECF280A01243D367346+1B4A5AB7EBDDC67C1514FFD8F3D5E09B813F8DB05CC3088F2993676D4325EE93+4552D8AED53C0D4AC0CFA844B9F9D9AF34DE8ECF4067B932D16577A1A5C59884+9B15650168268E574DB224736B91850D28EF4018B48FCA7558D969F12D0D9F14+44C250EB3286749BC16C7C6505CD54B4C43861960801E87C6873D11AEFE75D7D+B7A9D271F0C0D1837C205A98A113CE8F34849CCAA80E294779A7D81AA105D76F+12C15BF148147BBB4F5DD512F3A619418AFCD55C7CA060452B0B7A27F569B0C1+B1472C6D79124595890890F16B2799EB67D14519D2A974CFFCFD080A02A7122E+B215263848173DEAB558E3C3A7522F087E494202DABDF3349CE341FCD5587DD3+016F8A05A3EB92638B0BDB8E1C4DF869D9B10885C0C36E27FE52E8A7869679B4+5ED7584D15137994796F0F37F35A8A4DD33BEB6607D310ABE85E99C7C19B9558+FC381A5F7DF47ED86018A0601FFAAF646D46E1046FC8E5B4F0467D6C7B54A18A+BC38A3554C8ABB6555747631E480912F7AA1227FC00C2A392B7339A0C42D5ED7+004933F4DC3495C0013541DDCAE933DA8188D2712E3B2127925EC670488D12C9+93866BCD68808F27C788C10AFF07CE5D0C6A6B26816F2E1B914907C8C78261A1+D4C2923390A071ACB30D3B1440257F344448F1FD6452F0E5832F6E8C5998B727+99C3D020DCA253DD885B9AF8047CF4DB49FACCE4A1BEC37FE92CBFF095C48896+09A7A26288D3DB2C729E8B79944816ED61038E5A033CCA838B82C042472A6816+330877D53E61E21C1EFB7464D5001561ABD8696F8FDE6D7546731D54AADFB006+EA5C03DF308650CCC80E2B3A1C261BC61EFB0E70D4D8415A435AABDB1258855E+510BBD1599B29EB3D393899BC2411DB7FBD0CA2C35491F9AB4C23D283BA5FA4E+C8B76D6524CDDFBD9F4165E4C2A7D4E7C0F285E1D86950C96027EA6264CA1FC3+4E295289C067333DCBCD5A2916D425C1E116E46E94CC40578FDA16DBF5FED5B7+B1E96770C9B95266FD6EADA56DB9A1D7A5C873B42619BFF3863F1EA5070FDE60+0FBB48F623B787069FF086F0801B02366D81BBA2650A5EF69199368ACF13C5C6+C6D6BE49575CD3A03CA21E523F647DE0152A8C69AA3370118DE4A407AEF3DE2A+DE7B1665D3D1B1CA613731AF5EC860807599C3D11E797A6DCC5724FA5AF0B054+E9EA14892715FAA59DB3A6CC3A03991D3C6C545562B24742CB728105BFC2FC64+120BFA38175DB9735F05AE23C79CAA63441A57254566C8A0D39E1DC9BE2D0991+303276EFBCECF0B37106332A08C1CACFF93CAA9E8E89E0D3CF30847A3D32EACB+3B094699AD722B117393BAA30A6F2F7B91C11C40ECAE3204F6B8BF391A70EFCF+D08E264160CF6F136CFF26BBBFE989B7516AF99314766D406A25A579B593FCA3+9B1CCD1299BEF54B4177B38C3E6893457A0574AB94BA37B0469B0D7EC799E94C+FFA256C0AD2506B545D8D999886E641BCA8A005F92574FA717F6A3DE79F6F7F7+FBCF0073F61FC1E1AF3FFC8F8E7FF568884DF3386CC802597076C2715DB67CFD+2026E3B547F258690D166CF3DC8B00E1416FDFABD0B93D2388FBE884C8755349+308C280A8E2E19C555325CC9C255D325AD6BD8EFB9F129F0489CE5BDE84C3093+BF200E6F85FC12AA982404527C2AA8C228EC3E78F828C51B6CD82EA2AC62AC07+6AE16002ED3B0BEE6344D96BE3D47C028F6618730AE508B3A3B84B3CDD84229E+2DCDECC63E062C4E35F8656AAC03B7856CB1BD209656780B4CC9A52FBD13A057+58EC3BFFA47FDE95D972E805EFB31BFE3FA98BEE487EEED284AFDDA2E8E444CA+80762B9596E125628870FD0923C094B25E29D00A698639BB077A0DBD82F993F0+D021BDC6211BBFF56224F5ADB8762B1F5695EB908BF1288AAFF89EC7099788A5+F0C994608B8F33F22EF51883F2DE00C067920E5103B5470400E0439FD3D74EFD+EF3B48912956915D55E7E87EC8F65E02AC674453170C2B5D59FF174E10823526+117B56CE410273CBE8F6523EFC56268FDF5D1167F196D1C8F0BD68D057E8B6BC+709F7D3CC609589F6C1963C6081E7F22CEDBC9EB729B17154FD23F6D876CBE76+021EACF305A25AC7F116C2A7A268DA4B185205F8C86012FA613433EFE4F215A6+B1753E796E5E073FC2E71A993B38F91D573F364AF20CE341F129840D485CB7CE+EB67089842DA734304EE9E3B28BF7C5D8D8A3A519DD26AAA4E0E5496435DF8A6+D208C042FF745057616F8149D51943B9003264DAC21F0D28CADE3742BBC64CC9+CA269737B1023F888B22FF6DF15EF46DF16153E741722036D412E5C68AF7BA21+D5F234FC7F96E62D2E7E4512EF2B7ED906F9A72CD22B5F7BED8B1B32882288F8+43D3D328582732FD916489FCB5BD16FD50F4620922B1+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMBX10+%!PS-AdobeFont-1.1: CMBX10 1.00B+%%CreationDate: 1992 Feb 19 19:54:06+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.00B) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMBX10) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Bold) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMBX10 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 12 /fi put+dup 13 /fl put+dup 44 /comma put+dup 45 /hyphen put+dup 48 /zero put+dup 49 /one put+dup 50 /two put+dup 51 /three put+dup 52 /four put+dup 53 /five put+dup 54 /six put+dup 55 /seven put+dup 57 /nine put+dup 58 /colon put+dup 65 /A put+dup 66 /B put+dup 67 /C put+dup 68 /D put+dup 69 /E put+dup 70 /F put+dup 71 /G put+dup 72 /H put+dup 73 /I put+dup 75 /K put+dup 76 /L put+dup 77 /M put+dup 78 /N put+dup 79 /O put+dup 80 /P put+dup 82 /R put+dup 83 /S put+dup 84 /T put+dup 85 /U put+dup 86 /V put+dup 87 /W put+dup 88 /X put+dup 89 /Y put+dup 97 /a put+dup 98 /b put+dup 99 /c put+dup 100 /d put+dup 101 /e put+dup 102 /f put+dup 103 /g put+dup 104 /h put+dup 105 /i put+dup 107 /k put+dup 108 /l put+dup 109 /m put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 114 /r put+dup 115 /s put+dup 116 /t put+dup 117 /u put+dup 118 /v put+dup 119 /w put+dup 120 /x put+dup 121 /y put+readonly def+/FontBBox{-301 -250 1164 946}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5F00F963068B8B731A88D7740B0DDAED1B3F82+7DB9DFB4372D3935C286E39EE7AC9FB6A9B5CE4D2FAE1BC0E55AE02BFC464378+77B9F65C23E3BAB41EFAE344DDC9AB1B3CCBC0618290D83DC756F9D5BEFECB18+2DB0E39997F264D408BD076F65A50E7E94C9C88D849AB2E92005CFA316ACCD91+FF524AAD7262B10351C50EBAD08FB4CD55D2E369F6E836C82C591606E1E5C73F+DE3FA3CAD272C67C6CBF43B66FE4B8677DAFEEA19288428D07FEB1F4001BAA68+7AAD6DDBE432714E799CFA49D8A1A128F32E8B280524BC8041F1E64ECE4053C4+9F0AEC699A75B827002E9F95826DB3F643338F858011008E338A899020962176+CF66A62E3AEF046D91C88C87DEB03CE6CCDF4FB651990F0E86D17409F121773D+6877DF0085DFB269A3C07AA6660419BD0F0EF3C53DA2318BA1860AB34E28BAC6+E82DDB1C43E5203AC9DF9277098F2E42C0F7BD03C6D90B629DE97730245B8E8E+8903B9225098079C55A37E4E59AE2A9E36B6349FA2C09BB1F5F4433E4EEFC75E+3F9830EB085E7E6FBE2666AC5A398C2DF228062ACF9FCA5656390A15837C4A99+EC3740D873CFEF2E248B44CA134693A782594DD0692B4DBF1F16C4CDECA692C4+0E44FDBEF704101118BC53575BF22731E7F7717934AD715AC33B5D3679B784C9+4046E6CD3C0AD80ED1F65626B14E33CFDA6EB2825DC444FA6209615BC08173FF+1805BDFCCA4B11F50D6BD483FD8639F9E8D0245B463D65A0F12C26C8A8EE2910+757696C3F13144D8EA5649816AAD61A949C3A723ABB585990593F20A35CD6B7E+0FA0AD8551CEE41F61924DC36A464A10A1B14C33FAFB04862E30C66C1BC55665+6D07D93B8C0D596E109EE2B1AAB479F7FAA35279ADB468A624BE26D527BFF5ED+E067598E1B8B78188FA4BCFB0B51692D07B0BEBB930C6F0997B437E2C51B876B+61A563A2673932C2045833FAA35DB22ADE12102335D5DC734AE3AC5EEE6658D7+92EB62131E1DFBA441F53EFF9021D9D4C491F26BE8F54C61165CAD778CE8695C+EEAF70E3B20C64D4C2B34A084B5770BAB2A974E898F62BFE90F132A37E2DCA4F+43E13DB13C94DFA8ECE2B7374827AE168634FA007F8981ADA046CED3448BF453+FCD9A4F194FA648F9FC0971734BB69CB73439CB0DD021D44A7C11BF295E81733+4DFBA460FF3D654F9FB337E99E6D66FBA87A817EB9CA1536C84833870E3626DA+55D48DE850D3E6F6B29DA0E7C9D681283586F208DB8D58042E3A7CE55BE84822+C98237911453E479EAB65AFEBA3F61A763B40E74535BE56C9D8D06DDF9441741+5C9D9D917439368736619717FAB4F06E2C329AE0BA411F3FD522D9C33AD8369B+D7DCC9DF993778482F35F965973DE876FA19E109AA198A00658AB3F0D8E3DDD1+08A573F2D525202EDF2C3F52D34947E0964D0E8E89F6043C0D2C9C394D2615D3+5E1E123BD76D4E60AC8600305C844091278B74194D938A402F66FCF1A12B17FB+64C1F829392A4308CA536545C02DD6D3F4EAA9260F62719F5051781F56C6C079+9FC3AFAF5E973ED7F059ADB6655BEF2710A5A8CDC905404F26C04988D38198AD+377F5FD879E3F511D5BBA61EF3A7313971AA8878E61C6176FEC09C92CAB6B6F7+9D4494A95C08CC426800B049B12EA5EB668D4E321590DC69C752CFC0EBB51703+430B1D30B335F948102D4761972FCBD77119425F375565923E68A114C25D3B5B+4D020F90F467614A113E3F11BB1215EA2DFFE4D82E847DC7161B360AAAFB09D6+0C505E24D1FB30F9831F1A0ABA3EC1427D7C4310523B30CCA64668329ADDD369+BC652849083A43B1AB78567467BD8E6F9BE7BE71C0A01AC7994C36B9EAEDEA11+15846E0E91F5207ACED1EA72EB570656B95F323B984C36A7ECA589A25CD8977E+083D56E26973779B1EC4B757074564193231D967A978433C254A96AF9565FC1B+E303AB1147403E4F7F86400F9913449F59ED573A530FEAD1E8834CE2899664CA+7DAF1E1C2FAB4698E28B99F81ABDAB12E119A76AF48619DC24CB9A1A8115CF0D+D497388553FFF051890ACEC249A364C1936C2084A70A7FFA1E46552280182DA3+AC45F303AC495C5D85F5543B1C872FE9AA515F68E3BF50747FCCBCF1C50AAC34+DF6C7894EC4EDB18254EE7C5039D50F5FB9B42ACAD360EA047823B7D485FA95A+82026B58FFADFF4D4B38B1893A855B4C764552FD199CC9AD11D7A028140C77DF+43E91706ADA1B5B7C7B719C10C5A1B5B3D52CA5666CB67B37870A6C57B2D52DF+0E0EA39BE95F3440352F7D9A1C3E6D85E03E615A60A0C94B72B75EF14ABAEBF7+7BECCFD65464C0535E8BA881654D023C202FE24769259E20C2DF579A8C1E5ABC+2BC115941504778CE68399E218BDFBFE6A02944BE236A3C3B522C0CC6CBB15DA+7FF83A5661CD26A842641D5B25876D32D2C06115DE320EC6E61FBB7439955833+604D82E1ED89105807B9C3C17866226360EF6D7975C3D2EDC2E7C2F5D2C8CFC5+F6FDA3736DAC36E3E6634DAF1D8BFD3227B03F4302B5CF9DBBA14758482A1BC5+559D6993BB7455CB374C40070D55CEFEEB3B5817292FE3F5F19042DBE2CA7DF4+DD711BCC0AF1C4A01E067DB113812EFA84A60ED600F9E8B23D8D88D92434D7D6+92C0A81321666D6C273D6395CA4A47A9AF31274A75068E54A1ACBF9D35CA35EE+D966DAED1A85F62F2BE67BE1229022D99FD99184FAAF6DDF9173B040F0FF521F+EE8FE60D5C1E50BDFFE52FC4B770298F6C4582C5BB9C66EFFBF1A8E32B4CA3B9+B19E6556E80A5841AC360AAA59EF44EB9754B65DD75E77A55DA3D73A3BF4F801+D2A3A6F78C5C18CE2A116EC9480F08C5D6EE20D2234953FA24D32D8447A74916+103CC1D62C4CD5FBA405D6F411E68DE99CE34C46B23A9163324A89A64E8B8707+1150C512195F928B8CF7531979796439624308641BF580552DC9022F48FE095D+72B36A20AF237DC4F6238F099D15A8E17D6CDE1B6960E33823A560541CDFFE4E+9C9CC7C96697957C8A0B28A788F8CCE7D6F7D87D39D31256105BC1148922E18A+A22CB60F5D97CEB4677DE5558B402127F2D544E1E84513F18DABA2C7369AB33F+40CBDADD8E87975F12E83E0F64071BABBAD733DF03B23D7825B9708E356F416F+BE824D5EB6DFBA552FF36F06D3C8C7FD42C33CC4395E28B5F0460DC6A3D6E0A7+1D30025AA294B67C5E49C1E83DC50158D545C5B1BB950BAA567A2EABA98215A0+8AF958036ED385D7D6E8AC188C4F828C17D9C97F18B165F2B1A3DBA495503CA9+996268EA507F9A1547F1BCAA0EE081F28679848A3D1C5B2628D118685F5EEBD2+B7B26E73E35FD12365D351D4A1D4CC95B67B0506C18CBE4680BAE59CE5500892+ED0F9D7471B499B5ABF11CA755595E20726D79719D26172A356D63317F30E051+36BB50E66AE6837F9846CC0961850EA5F396662DE12B165F04CE1B01FF542941+EE8A07AC745225590854C6115F2E7306795689C812DD61457996FC3FE09FA463+B598CC9DF5A1095F49F796348D17AF81AE4432D2A27D24D16724AD85FF4F3C26+456DC8EB277DD5D121943F9B4BA98E446982ED2A745B0E0AE8CB82D8ECCD7D2C+71169A2B94AD8806A546621E148D9AE59BD1E41520C14DCE6389DFEA4F0765DF+92264D9988E3D3E4761D477AC71A9D203F4A590A3067AEAF339962F94639C7D4+54982D66166E1F260D01533130B370BAD62B65E6C75F4DF365590EA3B000A41D+36F29FF50A83A371DC6BBF7026F36CA21F900CA5B84D355DFCDA1B4EA4650F39+CDA0906FDCF5EEB345AABF7C6F7A5E22A93F64007EBC180A276D333D2B248AC6+C732FB7B0774A5194815BF6EB820B3EC9BE8C9B02ECED1AD764B81CE290B641B+CCB586A3BEC189718015344463536D5B42336ADBF97FC6A96AC2657E8779B95A+698B229073A60FF3B53F2CBBC7F881BB62E13BECA7C0DEFD8909D7CFFBF64559+858B0D4816AC3876D686B5785E71DD6047698715ADE8E1FC391F82EAC99EF125+2C739A35036539723326D31ADCA107FD1F5A35A90B3FFBB05CB5F939E1E0EBC5+C215D20E9C1BE9F91B7A502D50075B6196EEC3EB92A4234C963B7921C39A4516+70568C040835242F8C7E5EDB9C614A429C6692E500EF178940D4791FC186B9D4+53966325CC6FA53B4E30F032962481B3CD14E04F82CA5DE57B0276658F19B6D6+A04C9E77DC6C0617CBC5CDAF6C970281A554555A94928E1AFCDC070FDFF2E76C+CC7A406A144E48BA86FEE673A247A60CC467852A98C9DCB931EAC786F39EB694+30C36D393B8050FA3E395555646D130A1A275B9E35406928EBC652EEE245C933+1224E8CEEA4AFDC0BF88E11D0262BC64EED2CE55E0F4FD34C170CAA72F7731C6+75B652DC7FD420D53FB457A27CF69BA199B472F7577D6D1879D6D5A010B1E4D6+7F3FC85D2E1F0C95E0096CB64BAA847D967BA3B814E1D17D8A620B007219B781+9E6C1904F478D3F10A8EE641A5EF4C0F49A1F91F293DC4AE5E9FD53FD8E69487+7D542323C1B6364534BA7F779DC680F732D75915E2346F0B1C261C34422ED9B7+D6B73A258B4DED0BBD69FF58A904AF7819A323FA11C02C9E5B46ADEF7ADDD103+3ECCC03B1A1164822AEB5F6ECA1ABB5AB5E71133B768D6EDE136201FE514FAD3+3743FEF4509273DD53408C072E649C692C9756539427BED7B3BC3141E37482B2+63D6D6E3576093A639878CDF9EC553FCD5EC1F3A4A0A05DFF580E5AA0C1FB644+BA444CB98D7D3D2A843F39FE746F558F71B72935CB9E479ED3CD35DAE3B1BD15+869E17059B7788F894617167A0F7686797255A745FA78A153490C3A5A9BB16FB+BEC955DC70D2864FD0B52DEFFBC676B953C53681D85E62448FA5B95166C6F7CF+6B4F068694D37EE63699194C01AED97E59EFC4BD4D22213DD7C84F47A695F6C6+B5502F8451254E5D83A8A7475123ADE5EC99F7D40A5703BB15F4F8E436AB920B+F3E03F84F5F4FBC8F143920B4BC1213390E55EDA127A661C14FBA3D5EE8F87B5+838D8BF63862470918FFE848B62E85C666128F5DC07BA5CA30383B07BCBF4CF8+7D6EDDC36DF148B2CDA2DCB8A73D485629912199D7C042973610143A1CF363A1+175A950332BF60BAFB40428D0C7255C8B6D52516794891DFC3CF93F8394519A0+6BFC591AD971C14508EAE99F77A9510B3E790ECB32382785188AE4597CB47835+1FF1460F7B266114DD412657F1415637C3EE0EFD76D9AD3355E14B8CE2D4B37C+642D3D58A8A2F2714D4368D36A576DAD823D0DD2C435B3373DDC556CF204D726+28E770BB3A73CAD12F72A9CBC37A8815E1615B754E3B01F93CC33A81470DD239+9F9804E1193645B1CC0A03BBAC09FB1902B160CE611ED61649D19FBEB62CD451+60535B4C60B1BE34213ECF89E47640954791415BE706498836A7D663D2729CFA+E52FD90C74E416874B402976DEA0CDDE27333126D916A6F4C4C4DB7595FF8AD2+0055DB161387622D8F6BD4A3FAD5EE610095E66AA9B392CAA3276E4494412B67+9D494A206C072E981120FC5AE7A33CE3EEED3A77C0EA6594F48061AC7A4A4A48+303DFF266EFA820268614FF485A40608E37CE48518FB9643A696207A51A28E51+EE9111031076E0002C49B549CF6C6599DF6B9E6263B1BCA88E6B266FE55C6A72+9BC5217F899EFFE211141CA2D1DFD1DB7205FC1687E1B72C4B4D981ADA5B0F69+0028DF9A059E4F27C9B1B8D40ED4C12A840BF1A5BB9C446B1DECD229A49ADBE3+4E327E8B1F363718D1D8F9BAEBBB03B631A7C3FBC6854F79FBE840906C506C8D+2B7BFA430A6EC43F45ABC49A68A13DC0AED7869F11827D160FAE1A408578ACEB+EFB222F182A5BDBE49FCE9B68CD0B586DE01152BEB6193BBDFF82F885E21D447+867701B1EC364B3612106EF1A53BFE448FD70C8420F1900B519EE3CDB3988305+407D829D638D8E206989056EDD079438A82C5303620631D51141F9607BF3F194+71E7576677437263240BB71EA85D4511925D0A63CC07A7A4E4DCE4BC4381CDD7+6CBACA65DCD18E93BE84DAD66A0689EC79494463D256B1DE8EA58E89FF87F2C9+70320D4806636D1A8B25013515033F9DEB081F69978E132D9061C46F659B937B+D487BF0B30693B3EA3A4A9DE7057391E527BB0EF795742461CBFFDE493A2DACB+FADBD14834BB8103E74A7586BE9BA10ABB76F4C4D2123F4BC0BCA95C5BF211C0+35747D29AC9CBC9945F6704190B2CA274708A2BBDFE625E635F17B55DF1663C3+85928D88CF5742E456A33141CE4DA0C8396E300CF0CE3A84F450BA203B130D70+844B00BE1526425951B27AA2AFF48A1D4D1D5D0AF598B8F5E83DE0C320FF1548+AB2E4481BA8AA2E878BE84EA5479608AD544DF8E96DB229E76CAC63E66186BC0+39B48AFD5EFFAE777E3DA595CC99508810073BFD5ABEC38A45674442CC2EBAD9+028A17E8740E856E7E40D3118A8FE294B85DA01821890F2E2D6261877E686E5C+62D113D007FB7E457E641323E567294F8AA405FE1281C454531FABEA6F80D6AE+C4392A2AF51C9B3CCA1A51A057B13FA66DD1045864075A4DF1BD6404C75D5261+55E3FE632236DC6C5B47EA040F7D083FC69189AB111EF4B193ABD2D10133C3CF+89D130465EA221C0D776D9DD7858CAFB1CE945CD7D8304686AE7CDA7229B5A9E+E701654A6DE8AF6F4868D478F409224D5F1C1E4D6B180991C3EF1CE927E0D21F+779E173B4A259451F0CD184C608723E1523D1911C2DFEF1C56DB811FE59B60D0+584E304F6BCCEAD1CEE62507301BE113D3C737D3D8A26EAA4C9FEB9F32BBC03C+7EAD26BB9D78EC42A8FEB11741E727F2D8263741C576B59445C4AF95A03541FA+E8339620712A998927AA0CF6B7F72484290E888D5F35BEB0D24340AF8816BB2C+1D01932B6FC470B4E6B9552CD9F28BA25FF7986D009698132C1F52F2E9FA5DF6+481A320623DB9BC66DCDF8192F00BFA34D1099436E92BF505E8472B13261B62A+24E223617BF270FD946B59A62AE46A30826EA080CC967A4ED0EE405A8314A62D+C12A288CDECE5DC22126A214EA4B763EEDFF91D2C440ACE817BA116927E5E9B6+527ACFF6F50EB79C0A283751FCED7175A837F70003CAB95CB3FD2970FF26CADC+D815699C8815FBECBBFA90B28B68150EF57E4D41B0A21205A8B736054DEB34E0+9283DE0F488184EF47C7237D5E7798C0261039DA9F12B3583B4ACF988CAFA599+87ECE62D725F31AEFB85F35C30C87D764442EAD0AFF5F60D020F1A3818FAD6AE+DAA15AB5A9A90CD713056180042F58812A2FD097EBDCAA1BDF7F6AC864B1F2D8+1D2509B845F3CE95A792EBCB7A97B819F61AD96717E9D48AF8FB4E8FC71BC9B1+A3FFFDC9F0145E57C9E2C0C505F8F8A79DA7C650856A79825B0F2067ECD8B776+44E30A90CBA2D421BAFCF6DA39F11DCB62E364EA2CED2EC6CFEBDF63C2C6BD3A+24BB163449782EEEAEC8C73264E9287F915F0C3B87309D352307D6EA222CD891+C0EF1A58101F92672A5B1DAEABF17935C6D13BF158A93B1449A4430CCCAD848A+2D136BB3ABC61625573A4781D22F5EF7797AC9DB5C44745CE470C5DFB38E9B25+EAC1EC8B06C2D16AEBBCCE728149E5793467A60BEF35EA76391814D390553BF7+6C7FC7A31FA7EB5225BCEAFAF918171FC9B7ED58A5889E7AD1BFBDCA84A7C3C4+EEC2DF4F42E8CE77BA0F54C1DE7AF927FFF8BDE0551B7BC60D802D8F9561AA2A+CB60802E1136708656140BE968A7C097367A2ABC569D636B6482E289E3126087+E73F2EEFFDBD65C5ECD547227819DE993A1D070BC25128531AD857DDE5C3E171+50D43424075D7BD94B1CA74494D6421682171E16A44DE13CC8D7CDA2AC233225+21E7F1FB1D40C5D355C6CFB133D0411BC2E06B75F2CA6C2B025CD77F915E2C4E+944DEE3627D40841BD76E5F54C1A18A7D25D611D361940FD33F67A7446F62735+AD43BCF4B20E02E002F7F27AB363DD6C664A89C490D903D46C34154DD861D650+AC87A0B7B6847E16F20EF948F8721A83B2E635A71D2B85131EDF3EAA6265C909+B7042BF76CCD3DE852F766EEEABBCF12FBFD6FE3E1B86E0C7DF91AEDA21CF24E+CCD91D65CA69779FC0EA75892A6E8F6C73489E1144D5C74533E0D59DD9A3366F+02694A7431C0D1AFF847AAB94AB25814F78B7DE228B027F55B11B1FA59115135+0927B4AF7311C6C7724808581CFAB39F6C1C357D6701FD1230042310E2A428B4+4ECB74DD531E8456B0B7375A1671694F0F66BE4AC0F19BB796E4A75E06436BE4+982C7CD295E92A4A3A369046F08A0731F7831B543855A1ACDFA524B41DDF3985+402C982D54B5DBB360CA1B013A93EE309B9A49DC739A64EF64CE97FC8FF365D7+B45B70CF1239C33B654079F421F244CD1671D03E321CF0B8DD712EB2B2A4A58F+755126CCA5AD752E366AF9B94874AD5E0EE049E60EBF64554D19D794C9C249F6+55F8AFB6C47A3259407D233873EE7ADCE62BCA5EBA247105905FFEDDFB9F9372+A5E92541C5E2FE3D3724D641DC59913B47C86F95C5D6C38A4FDBFCFA2B61AAB8+7BD8C223CA01B76DEC853FAB28610978CFD2DCB703B3B1593CF7DFFDAB1D82EE+68D4C4E854BCB7E2DF23FA307D93E34C9438F104C0C729B7287DF63C1348145B+241E451C7182326244E9CB1C1405E0A5BC3EC104256C859154509352E671C057+B06599DBF5486162AB7DECBBEE2B81B88E9AD921E8E4082E516350718BDEB0A9+5B9A43656513A3984984EC059647B1B6A35A9BE9E8705CA4DAB24EF037485D6B+A815B9807C7F088822CB1ACFD5C412967D9B405F72F0CC6D8257D9D57DBD867C+314FC025D607D8EBDA94446A2D7B7CEBFDD8E6645930BD84A0B461DB7A54DC3C+3B7AC3DC417C276BFE7F05CBCFB23BEAABD65BC399C0355C2DE61975F9E1CBED+ADFD244129ADEE78AC271E6E7E33CCC6E1C7279EFAA27CE6407CE4222E1AC0E9+434C46EAA8F0F1E113E6942D94E0E78F257858EFB0E31133E53627A041CFFF53+3EB314D4FC052BCA2F5D910A8FE67DCEB877914896F73A3EEC057B6E1E32B6CE+7B94812541236382E720D5F08B7EFB1755D455146D77B37AB3DBFA9870D5C15B+098BD69843E03B04484BA87640BF9C11876BC819E894CEB8762612806287C7AC+E17958E9992C3F5D616330603E0669BE7A32242148A33FCB577FDB0061549077+A0377AE77F220D668DDB52D8786A24683923B96C022867BB959CF148C1D70CC3+A6D1724D9DB9A25BF9A726BD762EA02FC49205CF8AEBBC23E33D3DF0F5B24FCD+3E3A5CE1F9A1FDD837E25A3A8960CE09D608A8FBB9C7347355BB25BAEE30FDF7+B66C5426F7DD55E9ADD777E4403662C0553252FBEDFB2CC5C076444FD777E021+32FB6E00A393AB4915411970BC3D91BA93F5B9EF417D3FAE3209034D8ACBE3DD+B8EB27225F2A30D694FFACE480B0A4C47ACF477954EDE3899EB9DB603447D372+A50179C4F5B0A99D65B8AECD0624D8A7B91474875C873281FCC8F229470AC090+1E8EE3F403F8EBC8749E2F48F8A8177959EA496129F68D31839D1A17AEA1B1F4+0FB5CC569688521E0C4A90D2FCADC7616F167256E110E0B5F57CC0E096E1045D+200BCB92AAC097C1AF30FEF00E94B4D17E3B9F587AA24365170E495712E03158+4F3B00658979018108AB73BF946749AD4C27D6A8F1359E6B9C0C89750D5AD535+1B9185F0164501EF2B8DE5CDDD597DA91188E42973357C04F3C4591BC9A304C3+79FB10B0DC1672012E922884199CA7055EF632364B7686B1088DA372C62491F9+9D4B374A212C09A63D19F34D397FF8880A8CDF4E0E2F28EBD2D6DA4AEC0BA2A1+4C8E53698B7EF2850B5CCC7E34A194AECCA07BCF639B4BD95C17DB1CDC644D16+0680502ED3FC816555DBBCC261DEABF7BCB9A43292EDD82A188F930C291A4EF7+D6C53516B072F7E2E1F2612F0CDD1E4E804CEF80BC1F31C469B6959A63DAE604+8F578F4B6D192674FF5E6E3A049F33C5505BDCD199E4E0946DAA612C49A2963A+3966DE386DEEC9D5B0BDA0E6C672C4A0C8F8CF59A26E4561397D9F801243ABB9+D2D42D705849E2FF85685EDC5D3E92491A328E22E15E3F2DD0FB3C903A8C5A2F+94E1D57017094D741D71EF06B9AE0D45D9A7EC384402E0AF8D6B7034EA9D2418+7918D0674401AB5746B8246DD6CE0DF1136AACA9FAAB053485CF977088A6B236+5C6D91E2BABF76A062368078F595BE97E6DCE3750F936F512247151ED3FDAAFC+B1DBD20365756AE55FE37F9D2AD3D916AAA0F2778EBB41E95BEF832B99751F7B+6A48EF5C3E480102CB467513FE625FF004BF47B8FBCE4A34E9DEC5E4AF3CCB17+A1E3796EC7E2FB8137B4587EAD92CC1B1B5348E2C9B00DF66E5B6C9109C108DB+1BB8F4FAC399EAAA90D466B67F76B2F06842EA358B49DFB5637A6D7F29393188+F92CCA4255B7737580A156162A54368D1249C1138B63C072AD78EDC466CDBC0A+F1688440E9E90C620C9871391CFB3F8CAAC6E86A7AC5059533FFCA37CE02D70E+4314C3FAE6BA9A95A7C8ECC357E6050317CFB629C6162E972A3ADD8C7AB444DE+07C4216D4C6B061CF8D50882FD2AFCDCD3EE3422A19E5580B761A13C96E9BC37+5E7D31A7B2549B198396D7CC613DEC4224E62EAABA0A7E988491A11CD3E63371+92A6237979B68991ACD7E876B1A6C44A59182E11CDD327F9D504C3CD23D351BB+3862C29DCAC55960C37E5266C7DB3289163CE8BC6AD8A6FD1A400955B3D35ACF+6A573B6CF71D0CCF43A551539D642F5BF7033682307ECBE25B77AB8D10CF4B04+3FF268DB07DFC9DCDC35379E67FCBBF92578265885FB091E4DAED630BA004AE0+5F44EAF69BB7B95EBACC252D959C937569780CB51071162C1716AFAB30BEBDF7+07DA93082A7A99F452222805497BD686D62D8624D584AAA52DE48DE0B924C7A5+A41637759E4965B524C199CCC2B2D4890B66643FF1C1C07CCBB9A184B2706CA4+629E5D7EF4541E69CEC82B97FE857FA4BEF6C0A57F1D953BEF2E4B59CE850B87+C62EC50891AB4FF89B0F879753853A9775EE1719ACDE6364D7E92AFA1B5311D7+12CFD057FECC5E5C9246F24F547598C9668869F4B2E19CCEC767966DA0560FE2+6B6F539950E1A3C47C67DB4D8E1B92CFF2E051A016B8F532D96BA7A6763794BA+D97585CF3659096AA36EEAD9F26F2AF7561ABDA9147E600B58D6113B664D41F4+21C8459D5FC4354ABF52B01ADC04C041C3CA4670598A76ECDCF1D3355EB96853+854941A3D536BCBFA1B684E92E399B6035E98E59B56851D575E79EE3817B004B+E9154AFEFCBFD7BA06C6401767873DCCE83E73633AD340DC74BF2903FD635B64+7C8ED161ADCA933CB07718AC31F3B0A0BFB289881BF9D56BC51C5A413F9BD19A+60E7E70C135658DE0C4E9085C3444B8324A8861F543A241A2161C7E6F5D74685+FCF3BAADBA67B04C83EE7168D3FF7F93F857DB52BEC645244C65EFED7EE1D21F+E14A06B2DB9952F562DD53ACFD24F25785BD9FFC8368BF19FBC09645597373C6+76B86CC1E8CDE1B20F7BB8EF7BAA4C364D0E9231990678E178CA4F336DEB0CAA+8DE656F079BF940350A88B078A8F3BDB6926FE790DC8E283D569889D21932223+48F7A87129ECF0F9C7963A787FC909EB0F5C3BDC142066B67A122C5E219F9DA2+18B3484F9F3713D041FC21A6301C3CBD9155B3C6A1A0FF1E0C0D256CF5FC5DAF+D25608E4089959A51EE3F53DE74E7C1B41CE20F27BB6A3A8198554896B8A15B3+CCD3F98E685C5C860777E33E6A4EB3DDD53F24BBAACB14FBA1DC674C7BD31180+EEAF67B06F771D7D42460B2AAB7B9B24ECC8D436D3398878EBB3F15DF1DA576A+7D908E59C00BCCC02432F64928A9C6AD396F7A605D26D38A8D2FF736DE4CB5C6+10026482371F76A128D484347CAB37C0AEDC3037BBBCEA14A2232BE054979387+604DDA7044818BBA9733C940BE2ACDCCF61F28C478536AD024C464461F04AA19+C256814AEF21E1F3308381DCFF15375E8F0CD993E992DB3E01F176752CE50974+F0A5B809C4674B500FEA1E0E211873C9F2E1361F2E2F8BD74782600538F8F08C+2EA8F3590451F51810A108007236DC8D2E0ACB81B57B0A8B98DD54293404D4C9+83F8C3685A1EDF02419EF6417CAAA19AAE853D64C7268C4085AD1A1C3F20B81B+54C973F74B157EADEDA4C14E57D31C5BEEBC4EECF9304E39E7E6FC68263DE6B5+0C87DD6BFAF3C07E0785135B21F3843B75CC29AC27ADF563AD40114A909A62C7+99190B6DD605990464C5FDF03F7A488E5D78BDB02ACAAB736B61CED43E186982+1640FC4BFFB7CD48EFEAE7AB951001381410936BD20779281BF21E8D3C840438+6A0104A20375757225C8F23347C185775EFD7D370F0C498C6FFB472C5BCEB99A+8E1F8B95329DFAB7F04BF4D6C7F81A487D1D7F3DA0D8076B8A92D2FD75A3C205+70BF57A38D1B0E33DA185C91E49BDA7D264F01CDFB5A26C6156A8095E608D79B+9CC97C57E063B588B1B60D2C593E50175E3CC279768B47AD25B9EE5B21622506+BE930E1C04D16CA4575B8063D459211D2E71539C9CEB5CD83C375866DCD414B0+139B17B9CBE1CCDF305E02B6922AE6214C19D6EED369F2AF21BE0FE1B2951BAF+FCAABA075E432EB2484F6D9BA446C5DF437F7BBF1F35B5C6FE6C957228A0FD02+5562EA0D34C347375FEA0EDAB5B4D7C02691D227B5FA70CD24D40ABF98FF2019+90B5B1658EDC7848F7DD385185A7F084DCF500CC2C2C74B766857A755B7029C6+DEC394AEC59FB9F9ED96229070994ECACEA2C783CD0AE9583DA9154A330BE03B+888A985EA8771329D5389784C5FC3BB390D3885DD8F754C2355387DDEA44A024+73AC18E8EBC2A332A1945AD781A59A813ADAF6C9FC8602AA8A05247FE7EE4A76+DAA2604CAEAD31DF4ADB9DC6B935763D208F4E0011E79A858DE20F7BD257E34B+B04DB5DAEA0C8F761193D3A15CD113021337E2395DA7815402AE18F5065270A9+66FEC977BBACC12916A8582C779AB1415C6AD3EA056B9CF84247AFC6DD2839CF+B27F55FFA056537707D1A6E2EC167D053F338C84A95D625A7F17B455B6F1E61E+819443D7EBB9CF0784E0549F80B0746F0384BDBCFF97DDC2E6A58A902A78C7AF+C01C0312CA9AA810990A6AEB53CC48512B0E4ED88F77DDA07ED1F0BD8DB5D794+981593944B0647F0FEAE6AE673445D6BD5565EA5896E65558AA9435F9723065F+AA5B0595A0930CA8FFB23F28389EC2263365E1EBA12C23211C3EEC006F3ED211+D4C1869572905E58A6AA77C55DFC5213914A7474316B1D354A7AB6A430E06920+E0E48EB4D5C0F56EC23864A0EBDB1F82BB204BF9D2F8550E9924848FF309F41B+1B626C94726905A02D786D6C8892B9DD527739612CA5DF4F5173D48CADE0F60A+1B40D1B3AD41E6957063165E87215210FE0B903C519C3C6469EB156FA1304A28+355D940B0355F9BE4ECA58EA908CE2ECD9B79A06611F133D718CFC969A111539+E4DD5040E6C3386C8E92910CCDBF9D8465BA46B8F5C1D628D8F92717AD8803BB+7B0A3212B08EBA0639788693678E0A029505FB2083F2297300F32349C7E62CC2+EB892B6A56741317C7175853CB6F3384C3B6787AE50C6A6EBAC2D7E4FDAF2D71+E8A17EDC598C903AA8B0833F5BEBFE81D6253530EF0EC5932FD46685F96352F2+A29B8236E579128E1631C1865E8B504E5A269878DF8717FFDDC797C3ED564941+B52F4F59D386A8A985FB07499D074327FF5845768DB56E6B6938AACAC716397B+23886CD2B67B23FD6D3521065EAADC4DD8BC86A6217D4B7F2C33BC5609F01773+C1DAD241AE0C4586885887269D17BD8DA942B02A1EBE5911878BBAA5E2E44432+75A11EFFB75DA22F5ACEDC4B4DAA0674ACD3E30CF9F5E0BDE4C43D2637513045+79F50813ED0CE832839F1F3065561463055EB0B6D282CFB6547C92129FC1AD42+F35619EE54082F6577568AD4041B1C654F4F51FBD5CDFA885E537A86C14F45B0+CF5C8BB49CD3374B265B41FA7797F93856EAB3266D9D7F952FB990025C4F3EC8+D06DD33BCBB2B5034945FCF9CC53C1C30C74B7672C2DCF8B5493E0A1605A42F7+431815117C8CA56D34A8E0F676559C6F0EDBF9C75B9C67508A04FAA4ACB11B4E+7CB8492D2A9D3F18027ACA5D540538C5FFB7F90553335C77B3CF2A77C7CBA809+27FE4F6820B5AA48355C7A0E049D9CB4B1D131C5F9F2BD9F3F4F22FA41BA3F2C+BCE2751EDE24986060CACC05E5495C90A28A305B71BC2A8D59C1101896E58727+5C840C4B3477A82A3A07D882E586A866B92DC5987074CA9E368D09799974B329+592A5C0DCA35D7BADA44FB7AB5DEF39F8DBAC156954CB6800F69DD2E791B61BB+3CB3C223F25590470C7EA39C6B5225520C3A4DBB23CD2F158167C69393B5E47C+8F3EB0DFAA2827CF47E86CA6A34CA12D2A36092F883DAAE0D700A7EB5B3D51D3+961E776A24E996CFC9CA954768A087B5B5E77DE17AB0389544095DD6279F5CC1+BD0E25579B313319605D55629437D35F13B1FBF9DE9A0AC4AC9B57AA96E1FB85+FEFBA0C19AB447257CA7E6FC3FD13612673789EB8483B718B2F8AD863567AE3D+660FD8F0C0689DEA10100C18E6BF583FBBEB0EA52097F8F10DA4E644D7335A3C+B0904F071013617052B1C5D8FDCBF2C18E3C0A87AF418041E038F2F9BEBF0B99+C1A8C638D6DCB15A0B24ABAE4BCA71F2DA4C69BD65FA0AB7A197884D2FBA030B+2BED21D5F9ECD551A2B9801C4006019D221DEDC9E063F793927E2069BE07DD7A+E90C7B68930F06BADF14A7820414B282914D2847EF3717C9FA42E3B65D867B6C+1E2E591B3ACFCA9513FE5040B0DBAF4907C4AAB47FA97F56872D3244441B9E09+C0DAB719F38F0C9FCF4097F1C943849348C73FE4565EFA47C4322C8E0362727D+9779147F4AE544FBF1AF05CAF9B16F3C2149865CA09028640DC2149561EB6415+DBB5AEF305F3CF7EA5307DB555176D0673973428970CE53F004D5C1CA4962522+075E5607749381A941DAE22EE81AB12133871C435AC0FD724AD1C0CD6044CE0D+66A94F5869283E4D8E759B40311560A4F890B82591F86A8B53C2C04B76236139+CDF31B90EE3BCD21C6418BB1E05632ECEC339E5867F3CBD78A561B7D4886A543+7AC97BB6A13A334915A672DCD2A846B65D3CC7E78391F9EA5192F65874F16D45+CBC4C0C2A2F8156A31A2C65F6938DD0BB776EA29DA49D2B45793361E5D0106A2+393286531CC69AD7315A51AED92E61019335C3AF8BF875A0F35ADAC89BADB534+12336B10762055DCBF8156A5EBC422D502DA6F5F3E5F93D0EAA1E57B15E9894B+AE35D892A23DD080F0CC7842C1B0A15A6849E9F0BB2E391A8A86CF6B67222AF4+02BC08A45FE256B434D99013B214952CB08DEA17088B1AC3AD4E0BDB5438906A+C94B21329104E18233D792299FA50FF0E630C39A9374B977FAE799DB66F0FDD0+6F9BCEEF610C9F5DA60493619E2243E994E2E154E368D9F4520BE71ABC7821BB+16A434E51412221BEDCAA99EC6E776F4B1118601F01B31E1FEBE9230C7096CD3+65A812D9730F8B6C1E79185C2C9053EF51DD4E86E52628D1A8FD274BAA70E555+A032DE81406AB89EB1E85580ED623CEACCDDEB4C783B4AE4812FB022A0A4EB23+F0BFBB7267939F79D8F9BBC8C941EB14881B63036EF57F1A47B6D7C12FDAA6D3+C49FE48A79C8CB8D6A74A3A838A36A68AB9CA92F5F066BA61A7F78568AEBB4B4+1817FA079D34DF823935A79BEB5112462524771E07A170AA246C40ADFFD15EAD+62C95E799BC5D8ACDFAC88119E582016394B0407D0843DE3B5016B67B6188C52+ADEBA0E14E8AE0BAE069E47F2F10A8D904EF582706F791C087D038F7A9888A59+2972F533D77503002C3DDF851955281D06FFA7DE33BB67FC1DC48A04FCD452F1+F999849920AC8451E9E5078EDA420B6259AED114DD89E1E8A692355C3B7BC51D+9202CCF5C56A978D216C011B764E2BB76E6ED9F37DE52714AA7D2310C9053B12+F65FB8D6A3FE459A2097C6E24C9E64EA6882D0B05F379611A4B73E64BFF64ED0+73B22F4BDBCCAB4F4E0C4D7AD8A9204EBCA1D0F7A7E76B3A4F21E8BE4281CA72+301BB2106AC5CE9E24D4C20ADF9CBE5AB44FB8A411FA77261BCE5B544968D9A4+547F997B52AAE64F9FE4F4728C2CEAAC53AE25534F25EAF19B3D9EC292DB8506+74BA8E9120DEA9FBC2702369DFAC9F91DED2760506ED56CF66460CB72D217A06+DBA7CBB6FD50F4DA0153F35802D9FB2EA06432AE779BB0420DB82599E8B70CDD+CB048513FE85FBB6735192AE1B0630B6857B070B43A8E602DA6127EDCDD3550A+17FBC52BC26229399DBDFA557C94ABD7409495921931C68D1372BB0AF7F5F141+4735+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMR10+%!PS-AdobeFont-1.1: CMR10 1.00B+%%CreationDate: 1992 Feb 19 19:54:52+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.00B) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMR10) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMR10 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 11 /ff put+dup 12 /fi put+dup 13 /fl put+dup 14 /ffi put+dup 33 /exclam put+dup 34 /quotedblright put+dup 39 /quoteright put+dup 40 /parenleft put+dup 41 /parenright put+dup 42 /asterisk put+dup 43 /plus put+dup 44 /comma put+dup 45 /hyphen put+dup 46 /period put+dup 47 /slash put+dup 48 /zero put+dup 49 /one put+dup 50 /two put+dup 51 /three put+dup 52 /four put+dup 53 /five put+dup 54 /six put+dup 55 /seven put+dup 56 /eight put+dup 57 /nine put+dup 58 /colon put+dup 59 /semicolon put+dup 61 /equal put+dup 63 /question put+dup 64 /at put+dup 65 /A put+dup 66 /B put+dup 67 /C put+dup 68 /D put+dup 69 /E put+dup 70 /F put+dup 71 /G put+dup 72 /H put+dup 73 /I put+dup 74 /J put+dup 75 /K put+dup 76 /L put+dup 77 /M put+dup 78 /N put+dup 79 /O put+dup 80 /P put+dup 82 /R put+dup 83 /S put+dup 84 /T put+dup 85 /U put+dup 86 /V put+dup 87 /W put+dup 88 /X put+dup 89 /Y put+dup 90 /Z put+dup 91 /bracketleft put+dup 92 /quotedblleft put+dup 93 /bracketright put+dup 96 /quoteleft put+dup 97 /a put+dup 98 /b put+dup 99 /c put+dup 100 /d put+dup 101 /e put+dup 102 /f put+dup 103 /g put+dup 104 /h put+dup 105 /i put+dup 106 /j put+dup 107 /k put+dup 108 /l put+dup 109 /m put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 113 /q put+dup 114 /r put+dup 115 /s put+dup 116 /t put+dup 117 /u put+dup 118 /v put+dup 119 /w put+dup 120 /x put+dup 121 /y put+dup 122 /z put+dup 123 /endash put+dup 124 /emdash put+readonly def+/FontBBox{-251 -250 1009 969}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5CF7158F1163BC1F3352E22A1452E73FECA8A4+87100FB1FFC4C8AF409B2067537220E605DA0852CA49839E1386AF9D7A1A455F+D1F017CE45884D76EF2CB9BC5821FD25365DDEA6E45F332B5F68A44AD8A530F0+92A36FAC8D27F9087AFEEA2096F839A2BC4B937F24E080EF7C0F9374A18D565C+295A05210DB96A23175AC59A9BD0147A310EF49C551A417E0A22703F94FF7B75+409A5D417DA6730A69E310FA6A4229FC7E4F620B0FC4C63C50E99E179EB51E4C+4BC45217722F1E8E40F1E1428E792EAFE05C5A50D38C52114DFCD24D54027CBF+2512DD116F0463DE4052A7AD53B641A27E81E481947884CE35661B49153FA19E+0A2A860C7B61558671303DE6AE06A80E4E450E17067676E6BBB42A9A24ACBC3E+B0CA7B7A3BFEA84FED39CCFB6D545BB2BCC49E5E16976407AB9D94556CD4F008+24EF579B6800B6DC3AAF840B3FC6822872368E3B4274DD06CA36AF8F6346C11B+43C772CC242F3B212C4BD7018D71A1A74C9A94ED0093A5FB6557F4E0751047AF+D72098ECA301B8AE68110F983796E581F106144951DF5B750432A230FDA3B575+5A38B5E7972AABC12306A01A99FCF8189D71B8DBF49550BAEA9CF1B97CBFC7CC+96498ECC938B1A1710B670657DE923A659DB8757147B140A48067328E7E3F9C3+7D1888B284904301450CE0BC15EEEA00E48CCD6388F3FC3BEFD8D9C400015B65+0F2F536D035626B1FF0A69D732C7A1836D635C30C06BED4327737029E5BA5830+B9E88A4024C3326AD2F34F47B54739B48825AD6699F7D117EA4C4AEC4440BF6D+AA0099DEFD326235965C63647921828BF269ECC87A2B1C8CAD6C78B6E561B007+97BE2BC7CA32B4534075F6491BE959D1F635463E71679E527F4F456F774B2AF8+FEF3D8C63B2F8B99FE0F73BA44B3CF15A613471EA3C7A1CD783D3EB41F4ACEE5+20759B6A4C4466E2D80EF7C7866BAD06E5DF0434D2C607FC82C9EBD4D8902EE4+0A7617C3AEACCB7CCE00319D0677AA6DB7E0250B51908F966977BD8C8D07FDBD+F4D058444E7D7D91788DEA997CBE0545902E67194B7BA3CD0BF454FCA60B9A20+3E6BB526D2D5B5321EE18DD2A0B15E53BCB8E3E01067B30ED2DD2CB9B06D3122+A737435305D42DE9C6B614926BFD44DF10D14402EBEDFF0B144B1C9BD22D7379+5262FEEAFE31C8A721C2D46AA00C10681BA9970D09F1EA4FA1566B96E221864A+45A24ADAEC63F61C9FD18376D3984449A1F998C318A8FE36D0D5020E18A49625+0F3BB603BA1F3E66FF412F6A32433FF8BD2968D79CE4273AD0E0CDDA5153C2BF+F8A46A2244F9394A49D339F763F5A7411A3C29336B21CCB01723705AF589B078+3763035411FE36AB5D744E81379106890688CB5BC41184548B7FEBA08DE7288E+E6570FEA20C51FACE8E8F824BB61A4A038AB817C47B87391611B77928B2565A9+3B27A573C05D36ED01D8F27CB2C793370FA9B90021B5696280A55F2CB6117B64+293EAE0EA5A243F56FD007773CA35DF71B3D28643C25210CCE25F37A5095D6E5+9CAFD99DD1DB0D7EAD454C13464DF6FF5DD42339797AE5AE467084550FC00139+6EE818C6365007B2FD6E26285B832CFE6EA7E99665A224C9813C036CED262639+3FB39C1F05FF8F31D2DEF37BB9B883334F51EA124581B786A3D5FE6424B19872+AE7CB657C8D9528934B990B94FA4A6D61BC9D2CA9B4E95A22CBAA066043F44D1+AF32F545B9E123536914A7FD7FE96F12039EC25128C810BFF546AABC609DF57F+E19D511F324E32956177C4376D191C691B9F0B21FA84BAF3DCBBA536CD710A80+1DCD4C83C02E69A140E1A4CFFA3B012398F21DDD96ED8060DB98EE133F430022+41BA1DA473F1C99F0D6CDBD35188DAF712AC83E0EDE08EFC3CA2B4A21EE55692+CF22799274A5CFAE84C89C937AEECF9CC71A328015B63C1730FA68A18871E174+D035568A73346EBE4EBCAE410A4F2505370A0ECB487FB40FD823065AC56CE66A+9D8440C5B3F74B855EDAECE69835137D4D76FC0FEBA53998F57EEF25C7E3D9A9+21BFDBD66C84D8AF7D8A3B79FAA9DA2963FD47689E519FBB2B7793CE6DE04A5C+203539BF94A5A700E65B5A5DD37B051EA4348BDC4CA39909ABDF8C4102A58FD6+661206115F7EF6C29E12408BADB83AD40071F53B501C15601338467BED90B659+2708D01CD77E109ABA63C19FE12606511639C5D9D5522C80692D1CA874E17B9C+753AEEF13718DD36A008B2D39D618F4F766174423AE972CB619634766A5DA025+F9682D9E2A3C752D0F6F18B0D58319FCA606BD6DBC4F83D19DCAC84A6165B460+AC1A0057B12E2023F175E6A51FC12A4852043F6F2F2625ECFF6E866293531437+1C060C9383278C81B8DF68BEED88C49F86B7617C5B938457D19FA336C616D2AB+0A430B489EAE7998EAB74FC8C037550E12EF9AC540FD37473DB1A44B1747A4C7+4687624D806FAC32A53BD65A333DA3732ADA2774D6621BB59BDAECA5637F1F41+CD2AAEA8DB9774C2730DBDE3A2F9499C719A0E9D59FF37C4F4E6E54D5EC402C8+6599488AE21DD119CA2BF54EDB306B26351D0CC4C82040835580087C60327110+9F8A1277DDBBD25823AD30F0E960604BFF9CE454C5C841119F73535F3093FBD6+8E47B1357BA56E3D906EC70D68E85465479539187B56EC67A64DE38FC444950E+A82B014254689B676BD02A3068ED7ED5D4C9CA1839ACD730A1796A6FEE8905DC+73D95625C5F6B4364B1507A313B56BDB2A1DBEBD436AD80F31439C84BD00248C+F900452374CBDC6ECBC496178471EDA30464C1C4BF38936EC7E7767FF4637CD0+34D3C202285C0B3ACA5515977C253F00DEDD878F6AD84BA9A1041553A3626EE9+A5B4C881E77FF893293253F9507A3B8F955BF288562B67E2A99DF65D86D14B48+DC7587B628505B75A6DFA4CC8DB2CFCAC62ECA302FF5FCAB51FCE19FD7BB7675+D747A66872C49954B0C1547A8759E42FD7219E7D9C87F62451C47B13B46D9619+D0CBCBF138ED5CB03C8793626FBF6B4ADEEC391FC7AB65269CD899FAFEC8A9D9+DD838E4AC1249C33E3CD4539F09989D0407AD5A9A3C99BA7A24F62D428406A61+862D66DAA7EDCF0D8EE84B4399BB7FD1E117F90046F53CB268327B3333C0D82E+6BCBD0A6BBF76130D08527593DCADDF3B1D76A9154C5919562D5BA8767A899D4+DF546740D7EE9908EAFD91CE8F707A74696ED0DE86F6BE6C1E7DF1534E1A645F+D2315D77E06A87CF2093119D5CC415783F73F3561E7D336E3774570D50569DDB+F5DC496B875A91F2A2074DB8A7E44F86698BE3701727D63F644FF0DF38ED505E+ACB70239F0287885F27B6D1487A9CDF5817F92866613ACD932B6347F5857B242+95C3C47EE9AA298763F9BA372E0215161696CCA5C5EC4CA9088AF24D18AE43BA+1D0F9C25C23645D97AA5E9C05C59FD2E7B5CF123048FEF61080F6E16AB0D852A+0A0F0DC41D08B6DF137200563D61539C3B5DFB979889AC756B8A42A81D422DA1+9DB2215B060FDEDE2AD01D4AF60ECB81C94B66E1B8036B71CDDC8721E3D270FD+CD92252E2F73EB2CFA581A0AB5B196EEF05E926E3A8C45936FB43F7E726350B6+FF5C9D68CC477F4C4541E37210CC0DC917B9458699100283BBED7DE5634B08E1+E8A1275815A358B4C0D3787313C850999DF7330A5165A70BB5B5104415A5F973+3160B501075FC60DAF1C8C6DA3A674331DDE8854DE916DDD0491906F4EBB7F6A+C56C4A9D6132320E2E021CFEA843F7C56203E943D3A9B12D8321EAABAE3580BD+58D81B6C551BB86D2FB83A3E6B4924EE0D07E961E5235E7D473647322CC62C69+EB8DDEA11AAED833A80339E58330BD4AC7BC67B692ABA6A34D4D2D7A1A279A45+91974DF964E64592E3856B6D72B26D6E16241437159F3A09A5F30A4360083530+C76CD71780CC61C31DDE51A144E6E656F62A579D808F5FA729F1A66382EABA98+B6E376765D96FF4015BF46B3314B72C007A8DAE08A2E29F3461FA56B4BA6DBAF+6AC06F4C94FE3F2D692913E13F99B6AFABF801C0119625C51F8015E35BA453E5+8AD266F5BE4EA6E839C605AFCA7F11B673E51FF62A17D6BC824119A89599F86E+04D3DF374382132A2F1FB1F9E307DB10AB21E627C4356DBEB97C0A6205AADC11+22176F33DEA813908601A242263A845256234C6A3C9242AA2811F9E43BAB934A+024BDEDA3CB1E7DBE07BD210EA3341582B6D2A1577185C01E6F38CBE50E63DC5+0C27D22533C60F2FA74E15A9098F5B0AB07B31A098A88C9629F2BFE3E51379F4+43E54F4AC11B6134C39EA3F16B0AD01160792AEE382FA08C171DE8FE8D78B8BF+AF4B630DCC09B8C548ABF9AC0ECE250D4F18F481EFD5AF1F00B23DF090B57BC5+7825A72FB1E529CAC192DC16ACD2D77E8FC158921B4E9073108E69D69E191B7E+8E1840F83F758C840A0DA59252EA309DF1828E5C01FB9528AF8EED2A5DBCE0B9+8CFAEED4BE7BB81293E49C382F8662548F7CB5579C809007E665BA1899F6807C+3E866941D7373CF2C2F487AF294CAEF6CF9B5C1B9A6E9CD65F0DDDBDE957D66B+F24237FAE7EEA33E43E490301027B9CD1E6FEC252840205E189AEC434459F366+1BC556669446C0B9E669B25BCBBFF22B784B4CC714EB95609FED61E42E01EE45+A838557391DBA3951A3973A245BB8A4B9E88376805D0D8C477D3C5C70612DBEE+6A8AF5446815F55876C73AD91A5EBAA2285AF07BCB69F885753FC33F83BD1580+CA7AC604D06FD47C6E8A07634A19A72D7688310A784FD89DF166763C6D4AAC71+C003DB5D6BC52D8A7FD05CF12C53FDBDA604B584D0FF803A8D7BF183CF0E22FC+F9011A5329FE5D2F095FEC195444A764BA9CD36A077185F166C7FAA9859D553E+691E7BCECB5D43A323C5ADF846B1A1B0EE270CF96425E1CBB4FEBB3E81BB875E+D967F4F572FECD33A30FB4E9F05015933E97F0D2DEF1125FB5087946F7926AA8+06496F0111FFFE2928BB1582B0E02881531056467D2D94FA9F006DB22A40111D+B6777129303B181642F51DA4CA249C1E65AA9AA6E2F0C79D7209C35FD900945A+F2C7C71B32DC0F89AF0AC59573F904C3859DB7A2C8AE8C164BBC978BA802046A+85AB09238724BD79C2BFF5DCDFF0782A78C3CB21D902264830DE68D56B7BD342+DF8A600DA584B90B2D709EE65AABDB77DD38098FEFADB215C364757FA59823F4+ECA195DD6B19C803247274891D1CA67DDB96EC916EFF714AC8F318F84FA2A463+5A5E61A2C97BAFAC99F809B7A3E814DAB76C58F6175757A00D4540F3A776A31F+9A73EBA040CACE648C2E29AD238A138589086749477BEEFEBB3C0C733B41FA57+5B1E8CAC11EAB1DD6333D1CCE3A18B00FAD758397D85145196E24C50EE493D55+F65362262E253BB4B6D2B8A1482B1BFCE4EA6D04D6E31D9426FF698F4AFA272B+137950114BBFA18DEED6A7E7BADE564ADC4CAE468601CC0ED8B150EC0677DE4A+AA832D773709C36EF5FDF41783B9A176EAFD013D427DA388403B1B1669C8C4EA+73B897AB32B49BAD6D12B490C9CD7B7DB6C30F4DA9CDE2B27A84332BA8911CC1+F4E320EFF068A91B2DC000FED5D7673784A811D25FA865B5220E6860037BFEFB+E8EF7B4F49AC104F09E5E5D074B6B25BE7CBDE81D45A45488D0B702134F9C623+7A0E716FB6BB1DAB32CFCD8B668D85D6E4E8199182A459A42C762F2147C0917F+67EDB0AE06259AAA5B16E0E9DB89F6C0D4E4DA8ACF922DEF359DBB70A7AE1981+D04421A23B1574D763592D3BE450F8B882D4BDB3D6210A52F3F55C406288BE8F+2DCC6823D276EEBE11068396E5EB84540150871B770FA5E7056887390FF51933+8352B1578E447D3218008EFE22A90A4FC003812BC023E8B700A40934750E4748+DBD1F945B732E04CC7BB5368A9962F82917C57A318C77C612E720F7348AA5A11+9F22C3351773CDCFA6FFF6C9F229CD30C4DA8CAA0488DB8647E2F2DBC9FF835A+C6AA9516EA7661581059E5715D4DE468918A69F519ABDCD123666276ACB12855+4EA4F0F51336C3FFD960004471B7626E7048BF459E943F090759FD4FEDE44FC9+CFC72801663891B8DD3C11D136ACF46DBCD3C52B182B6ACABAA4267F9207481D+2E8CDE266DFAA6569FB4B210C14765982C463EB0434FC806DC2CE5760BE8802F+1E624A52AD82E9EAF0AC95535D3ECE393BE615AFFAF4EA0A3E0B98626BBE9958+9A78F1B8C44A82B0A8F58B6D2885775CD85D9AE5B8F38341ABF13568D3F92207+C21E8A093A69764A6EEF47A46E7A3C09859E21FAE2D3DECC33D0AEEEFD7A7FAB+0E26848195D253E06213C9399BC70AC8E775E6ADAAE247ECC881D15DA7E0FEB5+728A576D3138BC8818F6BE96154528A0FAB090DAA7B112DE1DE06DDCA4DE34DB+19EB2D645A16EA6DEEB2418E39D8407E8E894F05EA56836BD1646ECEFB16A04A+0B8C661C7EECB7489670361F780730562B9E2A94D56C6D5FD3B105AAA246B36C+740579450AEED6C50EEB8361A79F6FCAFCEDBD74A2428C245FDE7F0A1BF78D24+B4AB3D20DB10BAF267D908BB96981C483F9B00D428BDC5CB6177B70D0878FB28+D8BB7E63B77E83E645ECA268FC80F8462376CA79497D27B4C54D584A8B6878E3+FBD127F4496ED9889DAD465B0603831F9D27B02FA90141BE12C435F11B1749AD+05EC335BC2537C5259C073E051DDBA18C0CFCDE872C87D777EC0F750AC10C8A2+B66772A27B6F6A02896AC90737596D7E714F135CD36EDFE41C4713CA42E15DD3+47FC9621DB409F58DB6801719E1F3B8A497F39AE37FBBADB5A16287DBF5EDE27+EF18EAB44A4FC5218A78BF16AEF60CA50EA6950360DBAEBA30CB92CEB9D65649+143DAD6BC1E47BEC4948E8B5A3B55C3F4145853BF781B6E10A2C57D208C8EFDB+95EF5B0596691BE4CF8FA535793E60B576BDF201AEF6AFF2EBC90F6F60FDC6EC+F16ACA3480D659B2469DA3624F9A4427E6592FB855971A63793E136B88A7C0A7+61E422752C1B0D6848D788BD5B0ECED3D553A50AFE28F64902FAF3C3F14CE110+B10906187804F11BF718B0580E0C091677B344E30015ADD79958DD1988E1A365+B7635C74AB86A80FFE24166349455EFB1BB54786E66E2B742BE2633A07C65F52+53CB11B8ED7F117E06F48B74BC2AD714BA8B273DE4136C68B74C70BCD611B89F+4A87BDC47BE6D9193016421D0E627E2C5817DA87370B8EF164AE9AC8D0C77760+38A6607C1995875E88C3EC2D9CCF348FA9925A30962D926F7ED78E4178E32C3D+E24CF7319D8B30FBB394218DFAEDB4E4F07A90BF4867E63CC04D4068A98CE037+43BC44151E542EE04ED958F89E3B3B08D008BE9578889DB7D5DD59D04E980599+DA7EB889EFA58DF557657981576DC38B6EB20AB2525D49AF316CF5566A09B7D3+26EA42FB286E842DFF58ED787C4E18E027950BD6DC9004045BD28D7A1C8C202D+C7F524B47F5442D5C68FECF0611CB1876F9613EA43AA511F105A25B1D3224F68+F465092204E11E00747141AFB1969E44F70E322D0C9393F3B512ACA59ED5D4F7+73C28F9E9E44A9924A12BDD82182BF3686D1B39763D6D214B7CA31AA58E6C139+4ADB44647ED643AF8235817AEDC7D2B6825493F51CEE95888A92E408F072236F+93F20D7553F636CC434542CA6AF1CF88D425B7EA9FD8288D798CB65348A3F9A0+C8CC0B07AA753802BB8B0FA1B946DED31A6531C9E994A19EFF5450CE23D155EF+3B7F2B915A7A5C376EE60D38ED81C2EA3985F53B487979A107E3B7BB6B80F479+22702BECCBEC982C53B4919C4F8E665A007B9BF7BB60210CDB09CB882F02841B+9E372736443FFA80A6342BCA0CC65A60042B1D1C229C753731D3E943CFAE2083+8F1396AA962547A92A9837550F727F41319D2794CB5E48006B5DB5881366B674+E514819C5490B9EC921A578E64C40B77D67A9C83EB67E44224940BBCDA993E21+FCDF0084544557C2375500B3C5A672BC1ED9E2B190E01187EFC7D143134138B8+249AD80D393FDD3FE6A41772326023CB48718E126E6FC0BDE6725C9B6F890E21+1825A796CD2693D18FDC3833258D7AC2770A02F1060A102BBE7CA751F84BF46E+B2A863756B25B7E9F7A046625479FA59B64EA86569925EEEE5A649DD56A83AA3+2B6A1A8378984DD1DD71399DFC62F0B7980A3A189EA3D5C2AB2418302D646307+21B414015A20CDB349242CD6A6ED393601DC2BBF3167699AFCF77C4ADDDB96C0+196BD585ED0AD6F46514B243CC808B3CA33D0D7E07AA1DBE1B34D09FE3BA3737+F4D688839E4DCC9BE558962682B7402819562B58E5F8710FC836F4501909D422+79D49C5595AD439405E6C6DFC12F88BADBE469218F6D8F72414AF91CA6E2A0BA+52B290657EDAB35C6DFDE615AFF02A81ED7D27D6B582D05FA73A492C7D77A990+179F32E0080C739B8AE88799489427E7F75F3DFABD303F760AB8DECA9C3F2C7F+D8DECF68B73C42D6640AA577F60C0E83E3770891ABCC713DAD235B56EF660EF1+5C59A195DB97556048B1CA8BA620C9727DB558B910F9BE2C2074CA2492194812+F9864FE4CE083387091EC1BC25DDB07133E1259A4C583FC5403FA678B0CA2FC7+005A1D87A899C99DBDA85A07D712EAE9979DC0C67969AFE715EDEAB2062B86D7+343C451F8AC27B33A9058A1384D834DF70AB83B3B613FE65DCDCADA7476986EF+273551F2484175504A1EA987E1A6A4A12CAEA9A4D5D5879BAB3D06E6E3F2C279+DB66B68AB473AE715C300BA2F11BA59491262B696E230EF84C44733D12862F60+705645236F296000C1361CA13EF8CA0930ADB5FCF3FBD376A9585C9C2A7AF1C6+2AC4257EC49754CCE9ACDE734CC25DA34EEE44B77C2FBB480C3058DD22653293+431E5651613F5F62D692A9FC7D3EAC3D78F14CA85B52B13BC7000A1393E71E4E+E97C71DF6017651FF529BA8EEDB337AADD49BFF20CE6411892471998B5A6BD9C+442E45881F40B5F4F218769B81655450F99545B5C11F199BE3C842D0F306DAE6+443DA3ABF69C45B9862DA6FB49F55AF463C5A7E0D3712C507E0AC25187240299+2F912CDFD84B034434B519C8A2435673E7F98625D2BF3736ECAD292101EB6697+15B4E6BD122327E2D341F21689CF15E222AC0ED5DE05D11033CD5B9241004C2E+623A91FA234D16AFA14F4AA4B9F7B703A0CB32ADEF90A9C4F460B275880A7B6C+FC27CEB4365F0A4265DC9C6DD1ADB52392F48910A52E5801D9CC57145E5E7B52+8D61DFFB0167C8B37CB364F5E6A34157323B771D204A67DF64178FA9E9BA609D+6FB84E479A6650B4BFC54487330B796511F392EE276AEAE82C85898CC342ABF5+E0BD402684F6394D912E5E187D9F7E54463521B2BDF915AE8A0464B06D0AE9F5+C2E7D925C77325576457F45ABD2615F0CC52FB65915C10E40422B0C5A88C6062+0BD25FCF7CF788E24F970698B24F8E879A9399AF6EB393184FFC202B9019D8A9+934C369D8457BBB8ED49829DAA481B6B88582E3DE6441F3218937ACB9732E303+F073D667620F2ED856410809FC05C52CB2C03A923C183F92730E449336F59BEF+305C9C43B0F756EFE6BD31DA5C7F6876C0515FD9C6C2696E955B441D4E30F702+F5C42C1967E61CF84AAC95395CB7C7BF5C65688E0B58E8452B75CA632D80AD10+E6B336404DC44E9B86E39D2C417CB1C5B518262135E41A7E1A77424B76471145+1B51FA2722E80CF288D5E121A7235AA7B40BD9A998B26A4B3E825F9C980E70DD+847603CBCC7850002831A535DEFD9F22D326888233F5F1B4898AABBE42D63DE3+FF068EE4B1B00176AC2A80271C1E53564A4A341D989084F8940561DC129F0003+171E1398E5B1A7A1075E302564734762D205761FA50632E1E99C36CE7A977A9A+6044DD686A3868A39DA911E725216D6FCF78CD32AF292AC09ED49CB2D820679C+2FCAF6C03B4B8352E4B235EC39275708A69380FD2478FF35D528FCA5F19F7309+33E1F541BB50F994ED14E6195ABB0F0A2CE56EE466D9531799C0466B69AC6A74+368690FDA54590F7C6858C7F3EF06C19857D61C18A1E78DA8135F560115D601C+AC8F6E0498C48EFC064FC77DB53B7D0A9A6B9C1A2D0A464A29EA66B1A90934CF+68974650EEA3A9AFAC67421DDA9B36AFE6E8FD42A73B1FA18DBCEDC7B6BA6494+A1A4A9CE8188944E99A723DBFB95FA451BBA0429890AAA4967496E6BD14CE43D+FACAD10D5513CB3DE917F2810265DE631341CC906949F5DA681B3A3BD528F8AC+DE987ED551F20E50C98684CA1AE73CD28060405503751A596E4A16399BC29DAA+5C04C569F01E989AAC6FE3B8B2FC26ADCE8F44D141BE85AEA5BD43184851576B+1D4AAB0B30EB76CC3AF94E819D0A9E914DCE77AA8C5A087A100915446856CE00+46D0DBCA56B26B56BD7B161079E165A2F04B21428F25A76D4C45846F8671DB6B+CD129AB36636FBC9DB3BC644FE9F03942AF05FD877811254401754A651C42037+F7B898921BB39DA0E4B5EAC18BF1FA8B13C717EABBA19D40EAF5EF55F186CD57+B1C8D1B612BB50D9B8F502B9ABD3BD28D2AEA375CED8F6F51DF908BD84989508+6C50003CB5AEDE1FFCF6E3028BD41FAEFDF634F66CC577E1107388233AEC4A68+0EA8AA596D28A336011A1772FDF1E9CDCE282B26A71CD9CA7A25354731E00233+9D7065D21E8B4AB078A9ACDF019252F4A23AFED416DEA7B2748DE969C227E66B+5832B1852C5DDAA5F65F547D892D66EC4576238C602D92CE68E311A709C30911+632AA0DC9D85988DCBD62F81013F9547495092665879FA54AFA8CF58F96BA62A+184F12F60C82C2C863777E43B9A7BCCF0AC12BC366D6B126B89EBA13259720C6+1A58CC0969EC7D32AABF9B30E9FD03E3835261C3A387EB323A093E865D035604+CB85AE5A94FCE4CAD9DCA5AB0FA8352934DA4F6E60B760C94807A7A6BDC4FE7A+BA6B8622CDB4E05EA17CD32A8E0965E2B4A6D033A7598AA85D7552422FB52D6A+985475CD45A157B55EF3EA49E62B505E874CF69EEA90676C295E3F11874C7210+BA5B49ECC856334E8FF7C7A4FFD2A0171972881591A8ED3C00497D6D4A48D6B2+51D3E973F8483AED2D8D09F241E15C1FEC508B5EECDF4DBCE06BE5457D29EF58+BAE1CAF0D0313EB2C44E678DE97E25086084944A860C6998E87E472B0D1E9D6D+71F2D7E01D95AAA64C78A236658CF5A0258EBB8251D3C7952EBEE49E72580E58+03FB0F95900772D55ADF48031544C4F666A010E739E927F6D0C18B0338D30065+F9C39F161C0806DEFE24886B7C5E842823E61606DB17AA83CC8F1216465ACF38+E3B5E576B23DF1B9B2B970B8B1D331D86F19E55862DA0C19028422BC38B2F0FB+CEA60D339D804430A2BDBE2BAFA6CE9404A788E79A1721C1DF968A7712C68F39+9F45D8C194B31A28C9742D4AC7CF72EAEE1367AB1DAFF9C6F0B2EC9EBE3F8E09+5EBB4D4ADF4714437F169450D36CF192380EC6AF05EEFA3ED08F71AE10217C3D+5E5092CDCA2D6A0A516B2A20C7829B760913A5E5621495DD956CA9416E79F737+F327A174EA2EE976432BDAE193E53BF1AB61C3B19C5E1572BFBDEFF7931B385D+E7B06AF7FDB3E96B77A144E4BC3884AFF286CEE883E3F8106F520E1549679E96+CCA2DD7D6C7CC147439FB8ECE7727851CE1FE2051233ADBEA7DA5915D8D158E8+0B4ED21DE74E2895FEFB78AA2A93853BE25B5D702F4E56CEB101D67EFAE6541F+715EF9D1C9A2EAA6A616789DBF2DCC2D1F2BF0B95EE8BB8FFC483B13DB0CECAA+0F9D241FFCE9EAB04CE46CB9C9626CF69CA17026739CA739FF0264AAD124D8A0+CB923303075DC6129913F618AA702A9CD5050DF609C75F760089A3488768C378+FEEEA13A0F15E73591CC3FBA51A3366991B4E9737E2FE8AC93786B0597322FAA+41B786555DD6C338D98DCD7D5EE320A76E4840C6126777CD80463C813A62178D+6C4069697C223F4D946A9CBD0BFAED117F155863C1C6F18EA21C484CF2A8670E+A1AD9C382566BD5500CCCEF503FC5113E4F820728A65FBA17232766732E2F8DF+5FA4295B932C2EF50D6241CCD7684D1D8B5E9C2B48A90CEC500AD6C58D000C1F+00C8A9E07AFB476B7C6416B703C9CF606F29B4B8AFB5DCDF0749523531CF7808+3543F788A75561DA3F6E658CA30F14CCBB362D50DD4C054249C448A9B52ABDCD+CF434458B38F937B638E72CE686B134119390E2EB4B31CD3CE8D1B2AD9F61416+7C12D13812A40192F8F76D035D568267AA15D62A3759B02A4E21D6003E1FF1BE+28B518DFAE561B1970EEA6C127090C37D09280D0CCA928BCC43B6515C82D7461+620781FE009A26A52F2FF5AB2270B9A003D835FAE5D8B8CD7848CB0601900DD5+32AB022CDDC1B6EDEF8D262E1E08B4C0850E689625254E515030550866576AAB+EA468997F360A023659B0502EF9482B0E44E6BE9FDD89F1AE69784AF6289D579+B66C6735C89E541EEB7E998BCDB5BCDD910B4891C9D63C6489FDEC228141600C+1ADB63C161FDE77BABC5E2C0350F71AAB4F39D410A3BE6E6A9F70BE130D2B311+A7DB035EBC02ED4D8F60FE6F44F39D2DD040E5F17A4ECBFDADD36FA9C4884B42+0C8D044B6C524D2B3CF04B284E24BEEED611CF0B7FD0EAC35A7D079504009914+6666BF699750DDD65E889B92BCE2512EE6A7DA4456AEB5880AECD8D64EDA8E39+A9660D8B51EACAA81324F0F19ABBB6F080978D5D0E0C94CC1256142293A54F54+49AB2CC0B8C4381902ECCC6980E81407A9DBB8397127309B3B023B3703E35FB9+1077731A56247F8AF749F179A33AE655B5DC39146439FCC2648C20FF25B25853+4ACC62436A976EFB1CCDD5070AE038F3EBFCC4BBAB8F370A74936A8010C406E5+38F87EECA9A2337AE60AD928138A4D960DAEAD6863B8AC07112CA3AF8B8C7C37+3AD5E111CF540CC5D994EDD8B044260942171E312DF8E08F8423B3045C8527FB+4ECFAD8F88129EA494CC166019D2708ED630F2665F6894AB84DDA1B2F8DB1D72+EDBCAD09A4015D1CC31AF83F862FC04E1282F5D8B78EEA319330B10F6359E2E7+838AB72E87F486717700841BA06DE4A5F2826976B36D952C2FEBCE683F1B8222+31A47531DC9BE004FACBE6A0C0774B609CE54E7BA4989874091DA12FA107259B+F95C0B5DBA1BA9A1AABE7F366666A800635FF18D073358FA04EBCA735038C6F7+61BD36B4BAC5BE20DFD7DE044E8B5587BD763F55BC4EE29F4CFB2B9EAA8E4AC6+26A7CA2184A7FBA69E9B978463B5B048D8E95E2221FA1793EF11AFEF9DF0CA3F+565987ECD4A3FE1630E7AAD568FBB7FED942BDB71B5A4207D9957152CCC8EEDD+CC294EF761640089F1DD369A2A5A7830FB114E8F6766ECCF6AEFB134083C7E29+3283571F2CAC83BBE96022AA8F387C95150AD8A78FD227C48BB192843FBAA5E4+8719BD87A90F1C2E08CF248709370BF1B1E766849199CE6C0ED2000FA9FE43F5+8CB86019164BF5FEE2C84BBFD8CAEE91BC975FC50A09F8342BB39A083C46809F+8CB01FE6B3BA62ECC518F1F859E86E446F95AF0518046018198DA567314006EB+D718710F77E3430BDEC036E495DDD09610A364094505C0556D0F75924E344264+9C4D53B8EFF93167F017A1E6B617F41E8B950CACC82F0CD92E95290A12A5E85D+2B609EA36EBD1BA8CF842660BD933C760C4AFD44C6809686B6D6C4BF4BC9BEF2+763477C80D0F7A0DF4E63807381701E168798F123DED5CFD8EF12D8F58C976B7+87F06344C65D83EB381C66B67755C86117A6C40C62CBF4CB8AFAF4D6F403481D+A294BE7A3C4D5B3F616C7951C6A60B3726CD03AC7851A1C1C3BBFED0EACF4F74+3E112FB6252430C00133328D590818263190D9818496FF59308521BDCEF4F354+96BC53C25E10DDCEC7C91A47DCA4503237624354CB6E7ED7551682D824FB56B2+E943F59480F6EBC0360B27AB0E6D8295FE709D65E6E3BA8F8CBC2C0B7EE60787+6B4646383580F24C892DC5D96DFB274FE8CC69178A7764B4499AF2B68364DEDC+B48D86643D83F936979A17A757DC1234735376674CD5B81D4614C23EB583E6DA+4562EB4A47AE4419E4F96A743A758BC3F68B758AEDBCA9E7FC745023EBD88756+741C0F6BD976FCE4E37614F5EEA10AF97BE72D1E7A19B0C3761A151B0D6D0FB4+045536192D99DAAFB082C18CE05F632A65115D837F8153A55786502B1A41C82D+686E11B71B696A6B2787BE6F807076F505331AD513DD46E4B0EBB120D5C7E2DF+E19DFD8893E5DC5BD2AC46D51C136603918E2970710261CBB4DE70E36144E69A+B89A6B4F06874B84E6845DAADD85683E79D1635CE6F28E1F032BD0F227445911+F96110741A63BFA71043159CB69A8AE9201CD5FE17239E56AD0AF9B99D9F938B+BFA7A3177D58E085FEC49AEA2EA110B66599EFA84C15A6483EED80C49C00A104+BDE4651A671FB1F7A9BE89A10924C5CEFA8173188ADDE69294357405A261C3DF+B42C9C604F6124F53AFCA3E4EE1A0182A10679A176CB6E5EC5DDF99AB1809BD2+A1B5D34617190562A4BAB380F651911B5607CC258FDB3A8C136B21C4D1481091+023E797D1D210BEEA598035AA9784E107ED7DC14F6BEB82E306F353977D7CF52+C8AD8FA1BCEA4DA9FFEDFB5C07836C2427E86F97324FED39E433EA598C9C118B+F83783F70D57BE80A780270185F87B5AD77FEB9085521FA32539E2CD41DC864F+455AFE814E050E2D58AA8AF9647A750CD835F889FCE0E69AB3A005ACB9D438AE+9554FCE50D3BBD289BD1C267130EFB46268C84B82291811871CE8318F6B39BD5+3AB58C18186FA15A9C6284A749D3CE10FD643C57312A4C13F5B2B081562EB796+D44E3394EEB78CF6A68C6448AE394A4074D77893D2EC5C2EF73E9124863A7D98+DC26C7D30022A0E4B4A19237E0EC21F7FA6FB7AF9F53D1EF716A1C39E3DB6614+161C10C0A61381DB13E012868DB95CA1190659548F72F04EEBC4DE61D8C4AB6F+A36AD588DB61B486233833FF442DB4392FD2B9C2A6506F606B565DFC7425B74D+5214D920EF74D6A640A59F15BA0DC55D2510DB5C9F8A2773AFEEE00B6F69821C+57FF103825A6B9813E7CF9C14C745E8076E22C83365BF7F9C0C3F538E24D3FE2+EA959206677F46E7F1CB54C74D7219366B8906E6FB0665DDC70F0C98A7E997AC+7920B53510F34B306213A6390BD866343A18F79CFB4D0B5003BA799062A4DBFA+7F1AEA077DA5B577E8DE7D8F1BA1EDAD1DEE8D8DC484375032218022925F50F2+347987096CF1A346599D72EDE355027F283695D2DD0FCCDD62AF2A391393C68F+C5F12A1690952E135C4DC146C9357E153C33068E5E3B1E4A0E619EA3BF252B12+54F6680775F29C7873895B0544351BD8067487926C98D64FBA33263806CD64FC+311ADDB09FCF7368C84CC651A8E8B4D78AA090A7C2630CF7BFC49F70CD9A0EAA+200C7E996DCDE4390A6D7340A0E0354AFF41F4CDFF41D15D844F6D3ECF92B42E+9839732F51DECFC3FD268B4A014D94FA3D2C87C68C95D96C03658692AC00FE1E+89C93392D1D2875D916A0593E1E9A370B102EBB28974F2B1DCBC8DF08BA5637A+F87692625832644642B7EAF9D676A766A929CC50BB5C97070D56B996A988CA1A+8172251CFC95054F0EAE6EE1A5478E05FB5999AF5B78AAE31B1ACA9408C88BAE+6C22F7D1DC0E87B864CF9E8DB0A675F86CD53EE3B9CE57D7D5437F939DCEC93C+FB1EFE4DAADF042E721DA7B73655875B9D255ABADB1137452CF3B63117BAF9FF+09BA3323126E8325A6A933F0C6E3C7F055DB52BD316D2D24995E42895E346ACB+5F37E7CE38B702C39177D703BDE8FFA7FF36EAC92630D70E2826EC863B8A3C5A+A7CA9895C7B2E37F5F2D125C96EB5EB207C48E9F31CBAD0239C9955224D0D387+BB050B82342817DC7565175475A3E6C45FBCC4133AE306B51E7FB52DCB1D4D8A+059856DAAAF798002A171E207373E42D44855ECA8FBC58D2D55CC5C76BD0A146+10C6C6F4F4781793D201E0DC9C401FEF2A8AF498CF13BF7EB86A861DB4F761A9+8FBDC70B968BD887ABCB3F42DB92BBA8873C659836E07C4E183F7864D0BFFD08+125AD59E294880BB28F98381805C216A2A96A4DDE963135E507AC85D03F1559E+5B5E628DE01725C711E64598F7138F7EBC3B17B58318E235C02FF2C65E1E3C1F+FF4D03D174F03C6A75F88C39A1ED2B550B799F29509205FE0979E310C064F93C+9CD28D2B594E99F54ADB64C357F8E74F114C9E4F5D0DD227C1B59D8F230B616C+DCB5F9D63A4019E1393C5219B991D6A3A848DCF344CD0DE54873E513C9C17783+6D9002CB07864FB85A91907409FBEA954C168D91C7474E293E14839D707A80B4+514B9F376EBCFD64839F3AA9FC74346B63A9FF8A4D251BD79FFDEAC8626BC59A+200684014E499E9388D5AA912097891EB8793F0A231478F9759B69C58F64E133+8C00D12A58BD7DC5A5164A287AE82301E96EC471F69EE38593C6D8D10107DB36+728DEB2D15E7D16DB331890DFB63A7328A14E5583C303F4AEF34A0FC41E0388E+09126ABDC9E2C2A7E1770EE0F894B8BBF22B4AEFE3E35B86AE9F7A75169EAA24+FB17CFD1C14ECFC0302AED2198ACDD642FF224DB45F96CB869C856FB51D6F273+9F6C6D155740E9E4515DA13460C6330710E62BF93E65E4730BFA48BD01C55D78+C616484FD200AFAA5F1BEB2BD962E1D00FC806DFD6CE3304CF661B139BF9FA18+B2222CA305F26D43C3469A8856D4FCA1CE3D400FABA0B6EFEF31E077F1C08022+388E17C3B82FF34A1EB9D25F9A7D930310A6DB534564CF7EDA5CF9032752A3E3+262438C7B16508E739F02EFB5A5651975A08C494E53872B6CD97AD868259EF95+F3A4054F9DA61DFAC94722F68A242B0E1278FEFBCD43F21087A82FD0CD09CAEC+C7FB4F3CFE441938379EFB10D45E41C6E63DB2C2876810097200A1D9057F8615+61CCEEEB0604AFF0DB4EA4869EA9FF6E7CD8F930A8DDBF82C800BE2626F46FD9+3F361D7F9A3D3C138AC8B12CFC4734851697CE8F1673D8D43DFDD3AB2DFEA03B+2C06B56572FD751653A3DC6DDA4048760A1A4443903F3B039C2268220F2B5805+70A302D6751FA82C884669AE49AE2A6D1EE377B96D125B47EE3E7DF66C33542A+70ECE4DD67F35081E2CEF1D28EED41A53EA61013B5C433B39532135352F2A94D+59313328FBE57D6FE410E64B1E846B03FE0A30422F4E5D5C8146128BB4AA8C2C+630B9499C910C05D206610438F4FA65DAD327282E3C58C3957101B20AFDBD864+581875C9DE2C3AC55C343137BC4D1B909629A2EF9135EC4BAC0BF29018A82A0C+841424571F71A2A27E2D9484AA47784EB92EAC52573900E14F6925721406FDB8+F9A2FD68ADD352B5FA039D2390DFF4E0F72A078931A750411E9E035053B457E6+00314660B50320B70934D4E94E4D3B308D7DBC2388A77FF084DD83F8884F309A+DCF4EB8766A7CAEE25C6E20824BF2C76068850C2B5FCBD07BC7CB7B4B7BC0E46+A4092E082867CCC3184B02C3F04D18121275F250FD3E075C7A3810734B7D9ACB+D4AD0D1CDFEBF5037B035F0B74378B25F367DBF7C26E489B06E024EC80B47321+7B54C24BD0F998E21732CB608D2477EE18CE7CE18FB417C0790B16BFB9F89203+3B97EC54BD85AB9344F1BAB2A9BFA8DA80E33D589256F43A4257FD46F37C2F05+92A488313DE6049C649ED4FA4E83A8CCD93B2247146F20D01018924FA8D188B0+3A5D3B44413DB76A508EEA254DA3CEF3B03C0E624264A9E9D572ED479C3FA76F+EDA23D0D9887AD60469474764EEA04DD4B5DAAD669C14186D9678424A091D0FE+AD822699718F7D23B05076DED3C883404712226EB7E52ABB3DFF9FD907B4B5B7+665A98651FD41E0F66E70B5CFA97DB81151B96FEB4B33A09720199082B46BF9C+6E715C2BD6345B45AB3F553D3F20E7D19CDE669F858ED0489DA8A09A3A95AF70+4F6051763163DDDAF1D31B22DF8A5BFB4C0EBD69A6BB12C2DC74940E1BAEA5D9+54479566029ECDAB26EC6D15DACCF75DCCECC4386DB0D86D2802726822FC04E6+C676B7F43589EB5E53B57AFAD12C29B777266E0714FB0FB476CCA6FFA25F713C+C5E27BC8786B114EE2327D16DE9C0E0D42D018388D2F7B940279726ACA3ACCEC+31F0852E9EFE3419CB37660562658CF54E7843B8D70D62A7AF1C812017E7C826+E58F3EFEAFA779379127642BE0A60705400EDB133CCC8BA30965D09938D22C26+7D06429685DE334C38DFAB31BC4F0CC33D8F3D93EBF3BFDCB0C43F77007B9C1E+666C6713DF254F5E19F655F8EFEA367E10BE74A282F909989D865C8B6D52D39B+114A729CA7F11D538920E61DF08EB89A48D59FDBCF4AEA67CF8CE990E1BAF5AF+145CA80B81C16BDDD9B2BD1A6B153137930D69ED680EA892ADD867B393F6501E+E5A67316DB3665BA3036321743415AB1A784A9D1464E245AAB0F9EC455254FB0+DF049DC9B83D67D7947A3FCA600745E4696190800752BCF657B656C19AFDE528+940B059C56B09D9A5D692576A746DF0214F0F8045A649351BBE92695C93866C0+600313509A85807EE23FAA86CABAC8C35EE8F8F87430298A9B2890DBFE87E520+120F3D9F25F4076B09619B7CAC6E1DA280637862B87DA391DAE17A768B82798B+FB40FE8272D6F288B8BC577CDB1D0E907729312C7F412FA1A6B568840B04B7F0+ED55DEA371551E02D3451ADD0F0D46D697C7CF1CD8A6C4A372D11B4CB39A435C+C350FD01434914C1F9EF60E2296B5557EFCBC15AF21E4C82D9A52B0763128A6A+9CF83D5CF7C5F36B001C5E77C00ACED958E35AF237C055E27F26ED00FDACC250+E8716574D50B9DC810293430695F4D9270B981081E49C47A915B42039DCB36D3+CE5555FC26FCE46B2D996CEE6AB80454CBBB35F9F53A4E939C82BCF2477BA0AF+6F88E574D83B92F7081B0E1F5B0CCBF6BF9675AE7B9DBBD107120481737D28E2+FFB6AAB6DA6601EDFAD88E2BE75C12569E4B8551D4869DC5A36BB6E2AE00E1E1+41DB4A43A6B4A90A334BCBACB678FCC647D25BEE140449033160EC5C363F9E57+5618C223ECE6A79C1EB76FECA1578E151984914439AEDA51C3E86167E3D63552+168B9B8DE77901E3291E2C4DD5376F051EABC76D9127EE146B8BAC22857914B7+1D77475F209F54B80B5F55A9D23913B5002394A1526B9492FEC352B05CE461F7+1C8CE49047D9796810CC96290FDD9BE5D4350637F6F8C8870FEFECEED33C129F+C5CD0602BEE07534E254D181C89AEF245AC1D1BED915F4CDBB0B9B745B82049F+E6762D6D1E4CCE1886C823947623FD46E39E957B3CB503E93596921E75F4E818+1B799D6A277B64201D325B280564BDAA7CB7132F16F48EDC386E5285C1A5E308+8EA7647B92E39EDCDDEA3D554E3406C6E411C22313033C7AEAB9E4DB2A1A1A4B+03F75D0DC8F1B5B2E09B2C22FF062BB1F017BB7E383D444F6530B487BAD96C59+4CCB9685C3C905398225E045A40F86717AE3B78234B3774D4B445EFBD95C26F2+CBD98EA1C95A2A88D21B4415A0DF1A724385AAD2115CEEC3EA9AEA9203ABDD30+4388EA0B7C3B76DA1382D38AF01325D88FF9168028DA9353BAB23F67E960A542+8F3107B55CF7221175F1810BF0D07343BE59584B6D06F9D9B5D171F1D6BB167B+020C5039C36EC1CB1AAC41773065BC7991D712ACEA5D7F627B02611FCDCE2171+1EC7EC74AB0BFC57B1CCED1884BB9B18868A2053AF58F621016AE639ED6D58EA+BC42FF0FA5F76685634C85F3BAC77EAB39C23707518CAAFC7DCBC9F9D27B8BE4+9E85D3354A74F0A8D93CB7C2EC5A9982804BF24ED1832C549EC8B2AB2B1A212B+14E04F26BFBF1811C51029CF134633B62E08C3F88C615157DBCC5D3360575487+11630253C97F950490F0A2479405C6D88896D9715A139D0D365EEF1F65254616+DE309AAC8C708FD30001B3AB61A07630C8A5ED420D286442FFB6729DF0BFA47B+E2C8748062BA997499C1CA63131F3AEA492C2292E8F1B87011932640FA023A1C+022D98B92397BF2C01709CB33B012E69B928ED9E78B5157CC3A5E6F504267421+EEA08A95A5B3062D0AA95CA6411F51C3ABD548B82F47D3A759B3B1C5D8F8A227+BA4A23C777B7C36721C2DAF57426DD1A5538DEAF00B432D8E839C15C33B27623+20295E2DCDF4F1277FA2319433F4249B246D4BEBAA57DB6378C96576881B8557+17AD5BE0949882C4BCE64C7E037FD8161CFBF8E7212C23BAF8C9CDD6E1944834+36B69C59CBE7AF01B041FA9507CF9EEA2272A8E90F4E8EE8D0EE8BE355369BAB+C289855A10A2E0C23A146E9394BAAD955E6F55E44127003E6976DD267BCFC1BC+14130D1B5841165507F65D0599FA44E81329A04EC5B71BA7D4050071CA65421C+0457D6BFF4E361666041C197E2594BF098E6AD3212A1075DBB2815903464E207+0A54ED33C29B0B92254C9ABF5AD9A8B92F050D2B02244B09DBE3AE43920A0714+CCFD525CC5E5594E3E1B6C58AE380F3E680B96127F48C00A5CD25D09A4768FC2+5E0FA2135662DDEA45A533F68B0B77E7938E03C304927D597C9925A925BEF576+2DBE69512FB9C0D5E9D85704B2762D3A8E49DE2920E533A2A2B3A6B5910D0210+D51B77F1D4A7CCCC264DCB4D138E4157F9931A376785A4963EC4754BEE642C6A+9953711F9235407EAC877A53491706029B42562370A3776CD6E00664291BA825+3644B0318C1A997FB81F7D88B33D51939C7AA6833BE8B9E22BFE9960897299C3+57CA4244A0F42A92156CBFC0C46E9F76C9210239D9B116BC8F0D1E024FCF8793+49137D8610AAB7DF3EBAB12F3B087076146D0B4E0800ABE190175F877E67037E+1C4D5DD2B1F53957CFF1C51C349248F68FE367E451E7685F104482D3B9DD4D79+30E63CABE8A97DE032E9B4ECCB6744C2FF3A796530603D9B1645A144EF9B78F8+32EF35D95F04CA48482BC44B56626F80195C2E34D5ABB6EC46B5CDD1051B1121+C06BD2AE633FA5F7EBBF4C54C9FDF19ED3165B0E176E3DFD22B2CD6B9376CCC6+C862A13E3A7316D6CDE2B598F22D3D3935A888146BA654907EFD4EBB93E16C16+91127ADF44D0D01061E29E58D102A537C84A694341595DE48E29D2928F067B70+91C0E71168EED7D9FE14B3F495CE41BF7BC7CCDBFABF97D8C9FA5FD21604698A+1C8700D6692774BF8A0A723B868BF8E80F82468FD097639C571C3A0EE0C154DE+9FB11B7E89979087BED793DE89F2B4B3C6A267E4FE3C8A02EA38847E2A4CB03E+2B73AACE332836D739D1C4B14C71E5E5E110DE20DBDCA5916E4E33D1B5037B55+F991FD0F12B91E669A6DBA12DC98B4CF9E160BAA103BBA643E25275BC32BFBA1+9AD5401BEAF813FAC17F67B0B9F222D03A080813DC68EFF4CF745E42A0423A3A+76A639A13C1217D84E62AEB0495FF3D9F9557D3EEADB4CF622232B6AE4FE2DC7+A95AE1796788BCEE6421FDF76448F0462B79F1612E83774EF10D5F62A5A27542+0F2E85903EF5ECFB398574DDED563876110507B87067F349E123010D781F9ED5+EDAD8F07443E8F84ADDA31121DB3D1414B540ECF9897476FD351A6EBDD5490ED+DE2703120234293E6B8293830F57F1B8AB65EAD8FF7EA3F0A3E02C38F927318F+C492105EF2AD9DB49BD49922F6F54B21DD1E5B8885C19424927CE4DF58754DD3+87A29CF611E2CC20B3B726B22A0D46C709FFEA147ED78FA7F874119B11D63CF7+8C54F6C0E77AEB656B5F3318531CEF393C1860E69AE5EEB179C2C8E01E10D2A5+94FB29EBB9F897CC3A7F0C3D9022D80197166552F2BEDEAE8459EB15821A9CE4+CC97C7F13E588FA18BE5FE27953BE6E6C754E0C25BA394A62888B49B636661C6+9B5848F85E6F9C5516928D6C2BFE046A8E6E9DC127CBA203391D1DE19BFEF942+A07AE4D25A6AADE9DED198F55D0E2BCC220C64DADDEDFAFF96CFC4A4BA1AE986+05E81E6696DF11D0DCB551701A4B76C64A7601D3B1B2C0A558F04FE5289C5EE0+52EED2DED72459CA00DD31AFA2AFAFFE05165E51D29F93C27891AA3829286C5E+DE807583D1F6B621B7BFC9A0158F6EEC63BD5FB85215891A22B8ABCFE02A1412+F34A4B506C85476ACEE743051AD048FA3733791A0BBA0CC7A980E04C6845E8F7+71A07F0C81BB3D93EE17F0DAADB692BCAB67D36EB3AE466B465689359A48A041+674ABE5EC84438C599F00C98C41FACA12ABA4D09018E8797559CA60CCA0A2B6C+173894E846E19E440F45C8318718A969A5878174725458753B3383A464720ACB+996B30491310AFE3AF22239F1CCF8386FF12EAF178E7B7DDA38619663C94867E+18178B12E0EC9B47BFBAF6BB841A42252D748A31936F0438A105F61D33334B94+2C14408AC7AAF6B18014ECB670E7B70518E72D5C69E2DF45BA48+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMR12+%!PS-AdobeFont-1.1: CMR12 1.0+%%CreationDate: 1991 Aug 20 16:38:05+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMR12) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMR12 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 44 /comma put+dup 48 /zero put+dup 50 /two put+dup 51 /three put+dup 56 /eight put+dup 65 /A put+dup 68 /D put+dup 82 /R put+dup 97 /a put+dup 100 /d put+dup 105 /i put+dup 108 /l put+dup 110 /n put+dup 111 /o put+dup 112 /p put+dup 114 /r put+dup 117 /u put+dup 118 /v put+dup 121 /y put+readonly def+/FontBBox{-34 -251 988 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5CF4E9D2405B169CD5365D6ECED5D768D66D6C+68618B8C482B341F8CA38E9BB9BAFCFAAD9C2F3FD033B62690986ED43D9C9361+3645B82392D5CAE11A7CB49D7E2E82DCD485CBA04C77322EB2E6A79D73DC194E+59C120A2DABB9BF72E2CF256DD6EB54EECBA588101ABD933B57CE8A3A0D16B28+51D7494F73096DF53BDC66BBF896B587DF9643317D5F610CD9088F9849126F23+DDE030F7B277DD99055C8B119CAE9C99158AC4E150CDFC2C66ED92EBB4CC092A+AA078CE16247A1335AD332DAA950D20395A7384C33FF72EAA31A5B89766E635F+45C4C068AD7EE867398F0381B07CB94D29FF097D59FF9961D195A948E3D87C31+821E9295A56D21875B41988F7A16A1587050C3C71B4E4355BB37F255D6B237CE+96F25467F70FA19E0F85785FF49068949CCC79F2F8AE57D5F79BB9C5CF5EED5D+9857B9967D9B96CDCF73D5D65FF75AFABB66734018BAE264597220C89FD17379+26764A9302D078B4EB0E29178C878FD61007EEA2DDB119AE88C57ECFEF4B71E4+140A34951DDC3568A84CC92371A789021A103A1A347050FDA6ECF7903F67D213+1D0C7C474A9053866E9C88E65E6932BA87A73686EAB0019389F84D159809C498+1E7A30ED942EB211B00DBFF5BCC720F4E276C3339B31B6EABBB078430E6A09BB+377D3061A20B1EB98796B8607EECBC699445EAA866C38E03ED7D4F3EDBCA1926+2AF6A41F67AFCFBF3630C943FA111E4CCD988A7363F7C2B75EAF5830B049460E+0D2B337988F150B9182E989E7750C51BA83DF37685483F86D1F47478883F3F6A+4B7F768DA5AA89E8F163029ADD4A9209DE8A4F285766C06EA859639B92CCCDCA+F59B1C2BB8D588CA754D1257BFF76B53984DF4937093AAEF79009D32A29A4C16+FB610C7D6713482C48D7F9E8410C0F00AD6E67021056B6035534E79F05D14EF2+4E87EDDEC33BE4856B885EC0B969DD2E7C8F2F9BF4DB0CD7E57BF8B4050C1434+4031EBB95A69072D59DE7B4C42AFD5D88841EFCD1CCDB6A258E2A5D80C594B96+D6AECC3AB046504F5C88D55CBC667ADFB2F1F15F45E35765F19DAF1F24EBD3F8+866F1A46ECF961B9C9090ACAFF56898A343980FD407515151D934A1382C748C9+75527F50FFFBB8F5966142CB57A8AEE7A1B59C397EC17B8C96FD1C60A37780F6+B384BE280BDE753394C427E45CA9E0DD32314C28F6E2CDD56FE4C7E8443BFE47+EF23E3C05915D9327C554CF3A66AE541C0E78027D5129483989C47B330E59079+1FB06F07FA02F309E4DB7B1902B0B2AD32C25D41069B20A02F90A04E70B1AA63+77AD56E9B90EA1BA5CFB1CCEBEE303DBC38ACD5CCEFBB4E8D111C410D3D421D8+0DBA1694D2247962F328EAD58CF9F70B1676E1A3CC5435CC40AB246E999DA792+033479BBF97040700292341E4A23C63F59482A847D24C6BF32695EB03747B510+8DBE3886BF599C70FCE44BF5D938B1FEB1FB220518AB7A5642E0036051D93B67+BF989E92540A768C854F36842C04FB63459B923FBF3E5856349FD3F424FAB552+84729C4148EBDEDF7BA893D6E36AFEEE824958CEB6C332C94133CBA5041C642F+B907AF9505FC8FCF7E73FA84C5AC598AA85D105597B6D1A75A3181258697B1F4+5778C0E2E43029FCB4107490783D183569D2AA6A3F61F0D03B789316F0768FE2+97C0FDFB9C44CB00A7FA103CBB21E5CD7E493EAF95259BCE98F8A3CF566EFF2A+888CC88D9B6DB7D00E488F7C4C29C5752FDED24D6F44AAC3C26D07E7BABBC43A+5D24125289A31591E2EEAA9C506FFC7181A26C1DE3BA9FB2F109A10DC2C651A8+970180B236D40CD936F8C08BEA82E514AC1AD16D55C42ACA7FB1AB3DF5425AA1+717B12A92E2999AF28FBA1093B630737B9E1D96FF84F3C3DB731248A704B2C96+BAC94CE0D0117B7094B62DB87200A1427005C3FE78A7594C0DF6F4D97A7441A6+16CAF9CD075E8E8809DE7DF80E4641529F7C443593AC02FA021F0578208BBB81+3FC7175FAED6F99655D0C26BBF3CAA5C36F6F35AAF2965F5A11F356555CFFD3F+A3295016A762281D04E1BA67E13474CC56F2CFCA5D940720DE6BD01241B3BFD2+FF26637BF35EDF1542383937BF4BA3835B38ACD9CE8E0DB187A55BB84434464C+24E9F98E0A98AC93ED6086660197FC59C44C8AA4E3D7C08E4E12BD1F7A7CD3D7+2B63A764761FFE7093AF663F04377B94D7CE5D0C8C0A88428983F24FCC4484CD+63C7D5CCAE3A50B1591011FDE7162D97829B5329C097BD547E28D47DDAE0646F+350DC376C2CE22B187610E328312AC7A6CE5A2399EBCFE3B8654FFDFA9184B5E+8E118BF5DAC01E308BD2B7AF9B2024059E220B07EC3F2E2404CBC47638403A6C+41624E06E3C436B28079F557DDEBBCEEE25A38414E0AB8D5F681148AE6D24C04+E4ACF32D7627CD1E3E7E0633F5D8AEA737721BE677D22BB020DED1A6E16F11A8+BD061761C1C60A0058B2E98F43276511F9B4D418EAD47E19369943B7DFE7F14F+4165E8D5ED209507DDD8502DD376BB4AC3A265B4399196801575036B59F45B7E+83E2F86BF252A4D569AAB46D1FBCE00439E7AAB71DE3ED8E722DDF0FED634311+8D2644F0ED00C374024B166236EDAC17DBC566D0A12AF0566E22A642F7CB16B9+4E43BC115F23EFC6E28CCE230C527AD63453AE244C52C52AAC1F5DEDC217B3D5+273E9578D26BD4F32BD69AF4DA38DF5BA2A43A5904441CD6A69D1B4B7F471FFB+6511C8D6FF12236C479F1C6E0C566B5108CBB048203D731FF0E552AC099A55C4+8747B12DB22CD44F8D3A148B38B7EB95E963C40D3A7075CB56122D6E97DFD04F+67F18A506F44F4E12CC5042CA33830CD6CEBBC6224AF8B7D102164EEE35836AE+D4D691EB9DC1A67592CD50B593D6B5B10F03E1B0D69A515CD035A3A2004895BC+617D5F8197731C0513D06FB1302DC04BAFB912475810F76C5866249F0ED51E5D+C9E67E0AEFC5FB1B6A6B1F5DACB1F98CCB683BDDA753366F3FE632A9CAAF56D1+673348C83E0A1909DCBA459051E64E9B6C555E79CD6CBFFF6071E94030D53DD6+B197CC84997A7BDDE5A10BA8D10E17A36FF894C963FAC88B36B613D727A5F667+AE9C19A540D7A536F6EB1D03123A0EE5308A1F50B99BACDA2B5748DAE121F696+99A8660031929502F55DE6577FB2892E2C0DBC1B89AB6D8A08A127E851E5DA4F+D00D262EA4B895B0ED62AB2F5EE377589B6746DCC69A53B2C4A96862AFD17203+FD1412FDF12BD5204AC7922ED0DDF12D04A37D980A33D5B0C326EFD33606661D+E07C633F7CBA169BE6D9CE50518CE771A04BDC182F91545833B69EFB9378F359+4E8C6381C6613E916214AA4182669C99A840AD40024E7549934C93CEA222FCAC+D2242C5229DA62F5D9B850EB9DFF69F0918E9C8024D03B6EC65C5ADDF0827F05+6A3AD6880AAA5C105A17E17146A28D303D974E1ACED7B7AED833FD409F966B8A+8B4AFC6C4FC43E27ADF558D6F5863CC01DB7D8CF23F8E087F41DF2475C99A668+9CAA84DA539A38DD03626AA3397CF14FA1F446EC258D69C283F34A36C1F3010A+46E5BB20B03A1E10DAB5E1401AE631C7472DFEF277F319F7EBA84E8E84707ED7+AD062E31658CB8DDC9728284C2FBA230E128900599CA1CAB8817E561DFFB8D4B+677A29D40C44336141DDD76B49C2F25AF3E8A5C5E87F8343A4C8D3D6CF959569+CCD52EC1C44269FD607F7364310A23D0A427BDBE38BA109CFC1C9AA979E7BD52+B7E6874C94DD1031D8F29A6B6A0BA9A4607203A11EE01D8B3461732F06DA8064+E4B2BF40853D266FF34C2073B0389565B592D4D9CE6579E0B9554AE95D4D61B3+F768613ED7BF7AD682E8921D582960B122F9A6BD86BF43FB5AAF1039484A0B6B+571A30DAC56BB16BF3A211E33A8EE062955CF7E555FA05212D921F33DAF8883D+B845565B36E5EE4ADF4803B7E73BEF80C715B39E2206723A2FB76F2004472B23+BB16FC7E5671163EA999C89E6BDDBEFD07658E893FDA8BC5D5E1DBC0CDF374DE+3C5591141C8205A9A7B0104EF38149E134EEE486E2696A2C6F35E99207674231+A63097C7BF4DFFABC7C6FA3066D7ECE7AFAF3B9BDBB34FF96250A98F561110A4+0255B5B5FF8D3F5BE0D0C23D76FDC82FE5526A4274F028DB5F273FF2A8A0895D+ADBF5A78FF4FCDCDEDFC8F9DE71827DDC27E6654458E663F3A40FC3F9C53D4A7+66A43FD47D8308A57452E6E057E46292F129C5A6B957EDD028DADDA99E269921+0269CEFE4615E013FC94CE24437431B2779AA53737470E5776EA77F20877B792+DB41DF268C03A71ABC5442C65E7C0D60DC7655C75788E0D905DF2BC217153713+01CE8B27AD61F663D844635A3F53B56F5F2805DF62ADD62540D8E34201CB1E5F+466492F572A761616338933D2D96E2F960DB477C0FBA6592A4FEB70A1EA9FE2F+704462A4E89832F928FADC6A796AF51A7D79D0961C2044A9B904D40AE74E1A01+244B48CBAE1ADD57376BB4E538A89D4F9C463950880845875A686ABD4169EB15+9B8399916BDC375C6CD46A91268B8471F36B75EFC61E247E25D826155D29FEA7+F359B1F6039E751FB6A5F14E69C66777453345796923906BD4C5BD2F7DD6EFF9+339730B922D12DD52EA113FB5B58131B1E2FEEE8A1526C45EA58AC372D959221+E5C40C08FBB39C58459C6A5B2D4FFC9046AB5E1944372743A63C2C1B11BCE465+8D7EBAC6E96318B41E1F60EB16DE91047CEC7D1E0D06A3D8199F6CAECDAB2949+10E3494B86463B77DCBFEE21F86FD61A2E3E31317F16BF9F09947DEA6C32196B+D12C0600CA3D469D8349913705C23DEEA95601F92EE2D52C1F712F805A0CE588+3E131A5DA721ADDF1A6997B2FB861A381846A10342056A08FA0FE7BD51F8D2D9+E87CABBA5A70E08D0C9A5B0E7E808DD8456EDB6440F90ED10865C25D2C56ED82+7B154B4ADB7E8A9A924097266CD1A0E48985F5DB1841ECF0F69948210A302E68+3207E4CCD964FC9CC5D352CC869983DB43AA20FC95FB83509EC00B50E5F31467+791FE28CCDEC17D878B3309025F4F11AE77EA165BF9E07A7868FC5730D234673+991ECE6878FDA62EF24531AC3697FC634A27C19678E487F5668C9BB177B0A995+43002096125BC2B3D2F34BDEA9A1266C62F69520236800FB241F479362BFDF04+4AD438B4A14572445BE8E57273FA3A061EF9F9DFC554E1DE0F4C598B44723F4E+AAEEEA65821FBF3F7B1CAD5B12ABF859C4F8605B6A50A42628318A55D107B57A+0804A824CED814834DB0C0348D53914E04448F6EED003E8A55DF2B42C8C006AD+23C79D28A608B5E1F37EEC937E3193ED63D7B83413C449A0640C30D25E67C577+5D6C76760C837FAD2EE3D280758924A4DB471B4F8CC2ED69D484177EA012493A+BEDC628D103CCA428B4E9571CDCAE804A05553B347AF80+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMTI12+%!PS-AdobeFont-1.1: CMTI12 1.0+%%CreationDate: 1991 Aug 18 21:06:53+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMTI12) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle -14.04 def+/isFixedPitch false def+end readonly def+/FontName /CMTI12 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 68 /D put+dup 97 /a put+dup 99 /c put+dup 114 /r put+dup 115 /s put+readonly def+/FontBBox{-36 -251 1103 750}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE+D919C2DDD26BDC0D99398B9F4D03D6A8F05B47AF95EF28A9C561DBDC98C47CF5+525003F3DBE5BF07B2E83E66B7F97DDD7CE0EEB75A78BD9227BF359D002B6ADB+8AC57A33FED4EF021A7085B1E2B933DE602F0FF71467ECD501744AE338AF29A0+26F7D368AC6F25CCB882DB7B7343566192BD687E1349225982823027D3B66703+3B0DB7A7E680A682B98023D39C7FAE81A5D5B867A0A66C8AA0DBC83B1596A84F+0436AC6A7900B767BDCCE0060A4811003C79FDCC71D73F7F2D0A6675E93AD21A+56B4CD8EF75EED3DE8C0A18BEBF7B9D1BE72504872D56EDB272F1E97FC726CB6+68C85C713059DA19F6C2E0F3E12710A59B6FC4699AE883DE8C8615B7292AC25C+D5714B6CFB14EF0EF11EB13009BEBA4F345A5D3D6D9926ABC2BAD7DB1328651E+437BFB3C46DA7B62219660FC368CF3D3704DAD3AB461C28F711665BF484BF61C+052093D231CA65618EA463D63E406ECE858D180A6C0589B2FEDC321371C28E77+DE974D655DF5FF7D41ED01FE717D928A885F6FA6CFE4D2C0807F8E7F937916E0+96EDD1A3BA67802B1F4A49100E75613BA0356D9DCBBAD4DAB3C59E70A47058F5+2163D1730F0EE4D1F87C3A4AE723A23CFD7986FC4FBD399347E9F5946354E013+D860FC446AFF0B0744F5DA27CC777C96ADB388D1E835DDCBE123FB517679B9B7+EF696E091A9D51510BE264701A41C04FA8125A48F306ACA7A83E35D5BA0C296A+BC594ECA2CB27E92FED95B595C21E5BF0DA724D40761CB377BDE5FB98C9D152D+6C0DC98C4083E9656321BFC445CD6FCC142DEF16E27DD6FAD0B3185223B1A7D6+779F39C70793184F2C3B721FD0AE6D8E063BD47804785DAEA74AF8C75483B713+650616572C73A5DFDAFC7F9DA4FF42E3106C3CC276C323D919C20441451E6C20+E062B492B8654836F3ECF0B289EEA09BA9E14E38D36894ABBC9501CACF492453+DFDE5A36A945E91459C01414133E411E2ADD83F6F0C22581BBCB2D99CA81869E+9A58BD550CFA5C24A06C32E1D9C85211E6EE6FD97AA5E8B931AF9EBB1AA4133F+C4E8D73D916E32BB4F23C9F5495F005E1584389D9222F59CDC57008C52BEADA1+5A2EFEDC8F96978B74FEC0BAA9B0E5407B0E55D9AEDF93626DA0AA29E0A946EF+AB0FFE7E28028BD3FD295097938D2F53119469B94D3B54D3044C5FA31018DCDE+50F8C9C0C75AE7C856F5E624B6888FD07F039B9BA67278D92C5C4D339DF938F0+89EFB96933C621C38AAF497FC40B88FB456C3FBBBF9452E23D9442D173F81A48+303FC6DBB4F53D4894BA8AF8F0C620BACA4FC756258DC8D207955B0FF848BC9F+4146BB9E53ADDD7A8C4347960CBC17A508CD60975932EB884040E51FA62EE899+A9F61E60AA27DD29952CE3833C84AF0C9B8B11CD0E9FA5B9BF78BDBFC03713E4+48CC2CDF9F63BDE4BDBC97B14D12D7FEB940D8B5BE870B805660BA3CA5C68E7C+7EEC19D30B299D8E1CFDAB149C2B0E8D84EAC3160F60BDB8A4984F92F4C58F05+3250EDA9D74921DCD857E539A1BFF4416385E6F3BBD10C00484E7B0AE93207E8+63EB127F071B76BE0181663DC82B37AD27DC9542900293605EF6286644D41092+AAC998F981DC016CF13198D941E42540A8A93784BCE54E0E5587CD8D3A239113+F5860C0D1D641D13B9EF714E60AD4374A960DE181151F207A60A3473224CCFF4+E9AEB264439ADE9302D00DE9E1A2A13BBBF1C09D2D3B6C2C14F53312CA9D8664+50234E3BFF7C840ABCDEF45626CD61E8A8C49D9D687E4AA0C1E8F32AFB193D38+5785ADF588FE00EE62A8D4A33432F4DE581A6D668C10762B38F80E27F707F10F+86851E70CAC5C568B9708EFD434E0E6D6CB3DA801E10C2094610353BF2EC62C4+A317E39135B944217A69A0A5B5120D713C5EE9C65BB6EE08174F7BA947CD4D08+13829ED67FDF5ACA66FCED0DF84CD246B02646EBBC7EABBD7B034294BB29BB05+78C92593A5BFF4E645285401C503D399DC3F6E71C294289EA7CEE22F87800717+EAF96299709217C6E1436FAA49BE0FC5427CC5E2FDA48238C6B76FAFF42BC74F+A1BF6F333AA3F0C899EB5D0FF0654698F518F0728A2CE7DAC2142ECDBFA48E92+53138E6D37D4675A1E5FC9D13F5348CB948F396E27519483826C63DCEAD5E506+E00C27D7ABBDAB7FF35CCA06EE5AD611A0AE56EAFB48071A5E2195992E830D82+F610819BAA91311D638CAE11C44A1F484269C7D6F2C7F2BF16EEED+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +%%BeginFont: CMR17+%!PS-AdobeFont-1.1: CMR17 1.0+%%CreationDate: 1991 Aug 20 16:38:24+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.+11 dict begin+/FontInfo 7 dict dup begin+/version (1.0) readonly def+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def+/FullName (CMR17) readonly def+/FamilyName (Computer Modern) readonly def+/Weight (Medium) readonly def+/ItalicAngle 0 def+/isFixedPitch false def+end readonly def+/FontName /CMR17 def+/PaintType 0 def+/FontType 1 def+/FontMatrix [0.001 0 0 0.001 0 0] readonly def+/Encoding 256 array+0 1 255 {1 index exch /.notdef put} for+dup 40 /parenleft put+dup 41 /parenright put+dup 43 /plus put+dup 46 /period put+dup 48 /zero put+dup 50 /two put+dup 53 /five put+dup 55 /seven put+dup 68 /D put+dup 97 /a put+dup 99 /c put+dup 101 /e put+dup 104 /h put+dup 112 /p put+dup 114 /r put+dup 115 /s put+dup 116 /t put+readonly def+/FontBBox{-33 -250 945 749}readonly def+currentdict end+currentfile eexec+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8+2BDBF16FBC7512FAA308A093FE5F075EA0A10A15B0ED05D5039DA41B32B16E95+A3CE9725A429B35BAD796912FC328E3A28F96FCADA20A598E247755E7E7FF801+BDB00E9B9B086BDBE6EDCF841A3EAFC6F5284FED3C634085BA4EE0FC6A026E96+96D55575481B007BF93CA452EE3F71D83FAAB3D9DEDD2A8F96C5840EAE5BE5DC+9322E81DFF5E250DEB386E12A49FC9FBF9B4C25C3283F3CEA74B8278A1B09DA7+E9AE4FBAAF23EDF5A3E07D39385D521547C3AAAB8EB70549756EBA8EF445AF4A+497CA924ACCC3DD5456F8E2C7E36946A5BF14E2E959895F7C94F49137256BE46+4A238684D52792234869EAE1A6D8ADF4E138B79472D2A90A6CA99E2394CC20CD+3841733046175B20CEBE372327BF13428EED6A3E2FDF84C2DBA4B0AD584EE9DF+B51828D3B8F385846158C29C9AC3496CB9692DD10219697B2ED4D425C3957FD8+C4600D76E045C561216EF05D38177243C314877A69A1C22E3BEC611A2EE5A216+9B7C264CF6D1839DBBD78A40610F2C0D7C2FE09FFA9822FF55035AD52546970F+83EED2D30EABB1F303091EBC11A5379B12BB3F405E371519A53EA9D66174ED25+A2E55463EC71A97BE4C04B39E68112956117C8252DB6FB14AB64534B4BCD568B+246DB833982B38CDE7268BBF74B6B0C18091E1B1F87D32D66F4DD023D1F10D2A+7736A960F72AC01F733A11023832CD68FB6288A5977743F781214D8FA9C0C3F7+80001321D4397771F728FD9EE57CFE7D9192B887EC883EB1505068261DC40089+7B7D2820F06515CD74513521F6397FEAB3AD3572D9A8269430E407E357422461+1785FC2782047F4C0339D79B16862D939F3A37F78E4E2174E4FBF132539CB760+207999FF86F6A3EBE48EB0A1CA635450FDEEF79EB16D853F3BF4B4156F735FAF+A48459456EC1B4D72FF323BEC9E64C713F57C7A941619478F394383309DE02E6+AAC9F6D85A368D60200559C67CB0906125446DC9B555CCCC6505804143152F0B+870DD118024B54CDAFCA79EAEEB6A1D87839EF33163954AC270DBC6A7CE7016A+39CFFB67DED9B04017053C855487217B4731C9F54865D394599605A801C7C52B+8084CC1E959412A0FB888EF013D16104889D2FEE8C41CF141B7DAC4E58C872FA+FA8658E1F1E5DF9755291DE4F22ABC7A3A5CDEB21631862E6F05FD5AB9B6EF6F+1659BCD48FBE78084167755A3E122B8D2A6537B37031B8E8ADF50A47044F7DB6+55D9FF12C020C0B4FE5301C84AE7B666C9F00E282EA025D2C8CA0F00A9517F06+3707B879D9E58C94811A11B442E2E89E878F0CB4EAF112294C150EF936C17030+8FB9C4FEB43759A395FAEC75087CB27EAA29999F30733D87CBC36A098807723C+F7AAD5A0054F1C49211C90F05B0AD11863E49F4BDD4AB2B317D4400250CBDC88+F0A4E2C40D2D280C093D4FABA195262E9B2D9FD711C2405777A6C83FABF0F7D5+8FC5187B153C390D51332E89C8142E221E387816F7F0AA79CB7D8F5F4CD2E996+E1395A6B2FEFDB5F854E049C91ED8A47FC96EAA8F7BB022C3BF52D6A3A9112A6+F5F58E2830A93F5503C0E06B118C28BD3BB74208C780D8B8B0984FB8278E4557+359AFBA7A1B96B768327DB92C80CF6B05F8B90FA1D6C392E986C9FEBF478EDBE+9EC1C4BCB953B5D399C6D14B00C8980D409C3E829E15F8A475F5BBDED5688048+426E623AB4FB0CB86E6282B96B943DE37C73CF4F349F4AF6F268E350A75DADA6+94794E4A8F2D50ADB4FB55888624CDB06747C215856CC2861A2D17F4CA4991C7+50D4E4DAC279604C83A4D204EF52194C146E4C1CBCF1D516B0800101FE8FA1F9+905D94CB5FAE74500A5D65293BBC4361FE5A0B5FA673835F418B541FB8D440E9+0DFF121C092521DFC1665EB5ADD2A63E263390670A6184EEB43B2D7FAA5A597E+08B445E163C1132EBB94FFDF0BD2117BF64B18D97EDB948551AA9028AD88FC2D+4176F4889FD5E0DF8BE7D27DAABA4706A6EC125EC3CFD4BD525E8C00AE94CE4A+1A3A97646FD995AE3E0E33A5DDF86809587C4C6FFC8113900B80C5BE4948933B+D6A679BD01EDBCD59B0D667F2D1A0155DCCB41AE6E09F45457C21075C67EAB10+9577CA47AF1F83123BBC0113BA5265D02971CC6A7455FCFBA47A79E96F27EBAE+C65FAF7532FCD7736EA44DE5746488175ECCABB686EAC4C8981BBFD7A87CF790+CA2CF4AA70202112C141755187C989C0CF8975CC1284D3A0A4DA50F24900C8EB+4D7330FEDC86300A6A88CBF1B0AF22A24D6BB40EB87963783C167BB67FE0E4F3+8FF5A0E57A7B73E3A9B39E4969302725859A8671012CE6D7C80B09BDEB44DA33+7DF9BF54EDE64D0A65FB06F0F6388C7775C771560A462474A16FA016AEF742C3+87224F8388871BDE1E72F3AA3D7841BEBC9F37B9033E2EEC8BF0282CDAB1C375+C53A44A2BA7D5DE1E9BA359DF88C148EE2143B40B8396EAEF4E0EA9B2ACEF3EF+64D3E5484828ADC7C246BE7271B7199A99453A8C3356F66F3E23F4B8D98042C3+0A58DD8A4BCDAC1D1EC284CCAA5904D686549D286E6EA5C1D7D0C31B6B635A81+EE0B79991C99BBF83D2A30B249506447DBEE38FBA27F4F8CD397648072FD80BB+326394CF8BDA92FF16D75AACCD68335954871E51916AEA4AF9C4777041E1CEC8+1A04F444B604CD2FD52547A5E4840414DC495258DF89D59DF84710C40D82A0E0+A3CCE1CD0C427CDA33DDE02F1EFD7577AB03141D6A8A2AF819FC9BB867B46E77+999280560112E389E7B1E8FDD9808837362D159412BB50D02BD306B4D2640A10+2E719B68C528335CF9A663382A5EE7A4310C48BF79310C05DD853E221918568E+327F37F6347CF7987A5B5CCA15DF23114B7745414706B90466E484ECE9295A58+72FA289F4CF732EA92B936970A022B2754A1B62AE429485061BB7395AE139F56+DB66AFCAF89A504A372FBCD8535BE5027F7FDF52FDA9EEA79342E0DBC8084234+5E458933A5B5C553A21C16C7C27DB8DC20AB84545AF63C689647516D831F06F5+7012B482B04C6C72C91AB4BDDF8D7991D28E2837A910C6F33E4A332759DEC746+BD0D06AEB804D21DD47E9C207B9D81BD8BD8AE887CDFDCD07A36CD4A377B19A2+D9F683DC0F5E0938DE8C51223FAE4155D304C217B7AE79B76868946EC45FE55C+60C899E8B634E08C3458B6B6770C1D4C9D691E5201DE35B66C843C9E6C1E75BC+E4694E4CB15981B1D478B722094E0958674A24B8F7C0F89C585CA87B91A5DEC5+70979756DD101540762EC859677FDF0B16814734883A6D289483016E56401156+83412D5FC9B386E0665035678B00F5CE107E46A43928E153A81509C5CE6F779B+87B02B618FFCF5BC4DF5CD70B8F190A371EED8BD162F5B10D7FEE9A83B30FA50+D1D52EF60F2FB92DE5652220B9FE428489A234D139CA767FF647A7A0DDEEA81A+0AC73068442F871BE613103818B333E7C6D2052425C44456D6131209B3B75F30+2145DD9B9823453395A68B3220F7AE3CEADB0FF148983BCDCDF331EF8BE79BED+F756E86CFD435888451A0BAD1FB0FE8C206CC69923D65FFA43FAA359C92EE606+E9DCDD8592B10722AC9D2FA2872B90950D8AD7C28311FAA07C2C465099E45514+778B7195489EA9E172E11D2D41F9DD761F5F3916E1647DA6A9E17F440A1B95EC+93201ECA7A9CBEAB987E6D73173CB792FA4060109106E451812DF9CEC3E2FDD9+4358916BD1A8AE710A2C7455FA526E15D6B6C9A71FDD1CF5BF5399B5F24374F3+17B15284355842F018464CF07CA851B213AEE3EDE3E6DEF7915637280FEC9BAF+E27E7D797648CF8E6DDBED398D529F5A81EA62A7E1CAD22A53ECE6E37FE63935+922DD0EF6FD310A999BD8B33BC88062E6774857C0ADD699066B0C71E153C09F6+6B81C0289A40D849558DB5506E080490035DD7EDB923F749579F41701A85CA0D+1B3C50864BB482C11988AE852186DE32D355AC0D18F555A3BECB6F07A7ABE271+9A10E89386AF2506E108DCC61B3D490AEF866DC6FC3DF6682F76B43CCA96948C+6A5F51E8C569B899AEEEA72AC89F6A67C28FCED02A9EC9807D9C341FB93A110D+17FF4E04394D9F3FA25C5B0720A65BAD215578C92C0BDB9448E746CB29F8CFB0+40BF2C8B72E732E1EA238538613F7AF05E718D5196662F8F2ED46783B012B079+2D137F8394A50EDB52C6FEA3DF16E0F3A47F9D409D48B3FA0DCF8384BE880745+42D7708569F7DA72937EBB3D491B2BDB3D38DC6D6BD7FF7E7C87E5BA675EB4B9+B257586BF868FE3912E7FCF3B0764D2B4D83CABD865A2487C640A00FC4A00AC5+435EAD575C6F1208BB10756073507383F2125EB3D8191CEA1A5DE1ECE08B4158+7BF69FF7FEB4D42B1D756FE2F0884B38626AD7511016BDA2080A498230614CD8+900D1048EB8487EBCB5EEC50F193322FADC24B30DB6ACA317D97D96B53F13C4C+DD17B32841C13E411D6321C804D22755357247752E193CD8ECAF8955FBC6F66E+0094B19893FB6C9E29C1D3F4236A21BE81B90E0905E188A975E7F57533DE45A6+309F531818328CD4EA7A52E5215FBE7C20BDE0CA20D59D63FE4817FE3696B9FE+D4EFADECEB514B8D35AAC803259B79017A27960553E3E2F7077D6F6270AFFF64+3247F7F26E16D4538E6F588E7ECCBEF751A46D+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+0000000000000000000000000000000000000000000000000000000000000000+cleartomark+%%EndFont +TeXDict begin 40258431 52099146 1000 600 600 (src/darcs_print.dvi)+@start /Fa 134[51 51 69 51 51 49 38 50 53 46 53 51 62+43 53 1[25 51 53 44 46 52 49 48 51 4[46 7[65 51 9[34+3[62 2[64 18[46 27 31 27 2[36 36 5[46 34[{}37 83.022+/CMCSC10 rf /Fb 134[73 3[73 71 55 72 1[67 76 73 89 61+2[36 1[77 64 67 75 71 69 73 9[132 1[97 94 3[89 1[97 118+82 4[102 85 89 99 94 22[38 44[{}31 119.552 /CMCSC10 rf+/Fc 145[40 10[33 1[36 97[{}3 66.4176 /CMTI8 rf /Fd 207[19+47[52{}2 58.1154 /CMSY7 rf /Fe 145[35 50[35 25[71 33[{}3+66.4176 /CMSY8 rf /Ff 160[71 11[43 83[{}2 66.4176 /CMMI8+rf /Fg 171[69 69 83[{}2 83.022 /CMEX10 rf /Fh 143[34+3[21 8[30 99[{}3 58.1154 /CMMI7 rf /Fi 153[41 19[63 1[53+12[59 1[62 2[65 1[65 1[23 58[{}8 83.022 /CMMI10 rf /Fj+134[39 3[39 39 39 39 1[39 39 39 1[39 2[39 39 2[39 39+39 39 39 9[39 3[39 2[39 39 39 1[39 7[39 2[39 3[39 2[39+10[39 1[39 2[39 39 39 40[{}31 74.7198 /CMTT9 rf /Fk 131[112+1[50 59 1[81 59 62 44 44 46 1[62 56 62 93 31 59 34 31+62 56 34 51 62 50 62 54 11[86 78 62 84 1[77 2[106 67+88 2[88 3[86 81 80 85 6[31 56 56 56 56 56 56 56 56 56+56 1[31 37 31[62 1[65 11[{}53 99.6264 /CMBX12 rf /Fl+128[35 2[71 1[31 37 37 51 37 39 27 28 28 37 39 35 39+59 20 37 1[20 39 35 22 31 39 31 39 35 4[35 4[72 2[51+39 52 2[55 53 4[25 53 1[46 2[51 50 53 1[33 3[20 20 11[20+24 20 2[27 27 20 4[35 20 20[39 41 11[{}53 66.4176 /CMR8+rf /Fm 200[33 33 33 33 33 33 33 49[{}7 58.1154 /CMR7+rf /Fn 145[42 2[42 65[83 7[83 83 16[42 1[83 13[{}7 83.022+/CMSY10 rf /Fo 133[35 35 35 35 35 35 35 35 35 1[35 35+35 35 35 35 1[35 35 35 35 35 35 35 35 35 9[35 2[35 1[35+2[35 35 7[35 35 35 35 1[35 5[35 35 6[35 35 35 1[35 35+35 45[{}42 66.4176 /CMTT8 rf /Fp 200[30 30 30 30 30 30+30 30 48[{}8 49.8132 /CMR6 rf /Fq 134[71 71 97 71 75+52 53 55 71 75 67 75 112 37 71 1[37 75 67 41 61 75 60+75 65 7[102 102 139 102 103 94 75 100 1[92 101 105 128+2[69 50 105 106 85 88 103 97 96 102 6[37 67 67 67 67+67 67 67 67 67 67 1[37 45 37 4[37 24[112 75 13[{}63 119.552+/CMBX12 rf /Fr 129[44 44 44 44 44 44 44 44 44 44 44 44+44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44+44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 1[44 44+44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44+44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44+44 44 44 44 44 44 44 44 44 44 33[{}93 83.022 /CMTT10+rf /Fs 134[40 39 55 38 45 28 34 35 38 42 42 47 68 21+38 1[25 42 38 25 38 42 38 38 42 4[43 4[83 2[59 1[61 1[56+1[62 4[32 62 64 5[62 6[25 10[42 25 1[25 4[25 4[43 25+20[47 51 11[{}43 83.022 /CMTI10 rf /Ft 135[102 3[75 1[79+1[108 1[108 4[54 108 2[88 108 2[94 29[140 138 146 10[97+97 97 97 97 97 49[{}19 172.188 /CMBX12 rf /Fu 166[62+62 85 62 62 60 46 61 1[57 65 62 76 52 65 1[30 62 65 54+57 63 60 59 62 6[23 42 42 42 42 42 42 42 42 42 42 1[23+28 23 4[23 39[{}38 83.022 /CMSL10 rf /Fv 134[50 50 69+50 53 37 38 39 1[53 48 53 80 27 50 1[27 53 48 29 44 53+42 53 46 7[72 72 99 72 73 66 53 72 1[65 72 75 91 57 75+1[36 75 75 60 63 73 69 68 72 6[27 48 1[48 48 48 48 48+48 48 48 2[32 27 30[53 53 12[{}60 83.022 /CMBX10 rf /Fw+134[123 3[129 90 92 95 1[129 116 129 194 65 2[65 129+116 71 106 129 103 129 113 11[179 162 1[173 1[159 1[182+1[140 2[87 1[183 2[178 168 165 53[129 12[{}31 206.559+/CMBX12 rf /Fx 131[83 42 37 44 44 60 44 46 32 33 33 44+46 42 46 69 23 44 25 23 46 42 25 37 46 37 46 42 23 2[23+42 23 51 62 62 85 62 62 60 46 61 1[57 65 62 76 52 65+43 30 62 65 54 57 63 60 59 62 65 39 1[65 1[23 23 42 42+42 42 42 42 42 42 42 42 42 23 28 23 65 42 32 32 23 4[42+23 18[69 46 46 48 11[{}87 83.022 /CMR10 rf /Fy 134[51+2[51 54 2[38 1[54 49 54 1[27 2[27 4[54 2[49 14[72 13[75+2[73 8[49 4[49 49 1[49 3[27 44[{}19 99.6264 /CMR12 rf+/Fz 140[48 49 14[54 1[60 28[88 68[{}5 119.552 /CMTI12+rf /FA 139[51 52 51 1[73 7[73 2[58 1[58 1[66 28[101 12[66+1[66 2[66 1[66 1[36 2[103 1[51 51 40[{}17 143.462 /CMR17+rf end+%%EndProlog+%%BeginSetup+%%Feature: *Resolution 600dpi+TeXDict begin+%%BeginPaperSize: Letter+letter+%%EndPaperSize+ end+%%EndSetup+%%Page: 1 1+TeXDict begin 1 0 bop 749 2140 a FA(Darcs)43 b(2.0.0)f(\(2.0.0)g(\(+)i+(75)f(patc)l(hes\)\))1576 2322 y Fz(Dar)-6 b(cs)1412+2688 y Fy(Da)m(vid)33 b(Roundy)1421 2928 y(April)g(23,)f(2008)p+eop end+%%Page: 2 2+TeXDict begin 2 1 bop 739 282 a Fx(2)p eop end+%%Page: 3 3+TeXDict begin 3 2 bop 291 1181 a Fw(Con)-6 b(ten)g(ts)291+1699 y Fv(1)76 b(In)m(tro)s(duction)2166 b(5)415 1801+y Fx(1.1)84 b(F)-7 b(eatures)44 b(.)e(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)+f(.)h(.)g(.)f(.)h(.)131 b(7)415 1902 y(1.2)84 b(Switc)n(hing)28+b(from)f(CVS)58 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)131 b(9)415+2004 y(1.3)84 b(Switc)n(hing)28 b(from)f(arc)n(h)70 b(.)42+b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(10)291 2190 y Fv(2)76+b(Building)30 b(darcs)2040 b(13)415 2291 y Fx(2.1)84+b(Prerequisites)77 b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(13)415 2393 y(2.2)84 b(Building)28 b(on)f(Mac)g(OS)g(X)35+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)+f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(14)415 2494 y(2.3)84+b(Building)28 b(on)f(Microsoft)g(Windo)n(ws)36 b(.)42+b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h+(.)90 b(14)415 2596 y(2.4)84 b(Building)28 b(from)f(tarball)j(.)42+b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(14)415 2697 y(2.5)84+b(Building)28 b(darcs)e(from)h(the)h(rep)r(ository)61+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)+90 b(15)415 2799 y(2.6)84 b(Building)28 b(darcs)e(with)i(git)h(.)41+b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h+(.)f(.)h(.)g(.)f(.)h(.)90 b(16)415 2900 y(2.7)84 b(Submitting)29+b(patc)n(hes)e(to)g(darcs)37 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(16)291+3086 y Fv(3)76 b(Getting)31 b(started)1998 b(17)415 3188+y Fx(3.1)84 b(Creating)27 b(y)n(our)f(rep)r(ository)34+b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)+h(.)f(.)h(.)g(.)f(.)h(.)90 b(17)415 3289 y(3.2)84 b(Making)27+b(c)n(hanges)h(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(18)415 3391 y(3.3)84 b(Making)27 b(y)n(our)f(rep)r(ository)g(visible)+i(to)f(others)50 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)90 b(18)415 3492 y(3.4)84 b(Getting)28 b(c)n(hanges)e(made)i(to)+f(another)g(rep)r(ository)35 b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)90 b(19)415 3594 y(3.5)84 b(Mo)n(ving)27 b(patc)n(hes)g+(from)g(one)g(rep)r(ository)f(to)h(another)56 b(.)41+b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(19)606 3696+y(3.5.1)k(All)28 b(pulls)36 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h+(.)90 b(19)606 3797 y(3.5.2)k(Send)28 b(and)f(apply)g(man)n(ually)64+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)+h(.)90 b(19)606 3899 y(3.5.3)k(Push)32 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)+f(.)h(.)g(.)f(.)h(.)90 b(20)606 4000 y(3.5.4)k(Push)27+b(|apply-as)70 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(20)606 4102+y(3.5.5)k(Sending)27 b(signed)h(patc)n(hes)e(b)n(y)i(email)72+b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(21)415 4203 y(3.6)84 b(Reducing)28 b(disk)f(space)g(usage)36+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)+f(.)h(.)g(.)f(.)h(.)90 b(24)606 4305 y(3.6.1)k(Linking)27+b(b)r(et)n(w)n(een)h(rep)r(ositories)78 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(24)606 4406+y(3.6.2)k(Alternate)27 b(formats)g(for)g(the)h(pristine)g(tree)57+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(24)291+4592 y Fv(4)76 b(Con\014guring)31 b(darcs)1904 b(27)415+4694 y Fx(4.1)84 b(prefs)48 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(27)415 4795 y(4.2)84+b(En)n(vironmen)n(t)26 b(v)-5 b(ariables)53 b(.)41 b(.)h(.)f(.)h(.)f(.)+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h+(.)90 b(30)415 4897 y(4.3)84 b(General-purp)r(ose)26+b(v)-5 b(ariables)57 b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(31)415+4998 y(4.4)84 b(Remote)28 b(rep)r(ositories)81 b(.)42+b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(32)1702 5208 y(3)p eop+end+%%Page: 4 4+TeXDict begin 4 3 bop 739 282 a Fx(4)2351 b Fu(CONTENTS)863+515 y Fx(4.5)84 b(Highligh)n(ted)28 b(output)47 b(.)41+b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(34)863 616 y(4.6)84+b(Character)26 b(escaping)h(and)g(non-ASCI)r(I)h(c)n(haracter)e(enco)r+(dings)76 b(.)41 b(.)h(.)g(.)f(.)90 b(34)739 800 y Fv(5)76+b(Best)32 b(practices)2058 b(37)863 900 y Fx(5.1)84 b(In)n(tro)r+(duction)26 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(37)863 1000 y(5.2)84 b(Creating)27 b(patc)n(hes)61+b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(37)1054+1101 y(5.2.1)k(Changes)38 b(.)j(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(38)1054 1201 y(5.2.2)k(Keeping)27 b(or)g(discarding)f(c)n(hanges)80+b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(38)1054 1301 y(5.2.3)k(Unrecording)26 b(c)n(hanges)42+b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f+(.)h(.)g(.)f(.)90 b(38)1054 1402 y(5.2.4)k(Sp)r(ecial)28+b(patc)n(hes)f(and)g(p)r(ending)c(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(39)863 1502 y(5.3)84+b(Using)28 b(patc)n(hes)40 b(.)i(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)90 b(40)1054 1603 y(5.3.1)k(Dep)r(endencies)47 b(.)42+b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h+(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(40)1054 1703 y(5.3.2)k(Branc)n(hes:)35+b(just)29 b(normal)d(rep)r(ositories)61 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)+f(.)h(.)f(.)h(.)g(.)f(.)90 b(40)1054 1803 y(5.3.3)k(Mo)n(ving)27+b(patc)n(hes)g(around|no)f(v)n(ersions)40 b(.)h(.)h(.)g(.)f(.)h(.)f(.)h+(.)f(.)h(.)g(.)f(.)90 b(41)1054 1904 y(5.3.4)k(T)-7 b(ags|v)n(ersions)+60 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(41)1054 2004 y(5.3.5)k(Con\015icts)+25 b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(42)1054+2104 y(5.3.6)k(Resolving)27 b(con\015icts)57 b(.)42 b(.)f(.)h(.)f(.)h+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(43)863 2205 y(5.4)84 b(Distributed)29 b(dev)n(elopmen)n(t)e(with)h+(one)f(primary)f(dev)n(elop)r(er)39 b(.)i(.)h(.)f(.)h(.)g(.)f(.)90+b(43)863 2305 y(5.5)84 b(Dev)n(elopmen)n(t)28 b(b)n(y)f(a)g(small)g+(group)g(of)g(dev)n(elop)r(ers)g(in)h(one)f(o\016ce)e(.)41+b(.)h(.)g(.)f(.)90 b(44)863 2406 y(5.6)84 b(P)n(ersonal)26+b(dev)n(elopmen)n(t)76 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(44)1054 2506 y(5.6.1)k(Priv)-5 b(ate)27 b(patc)n(hes)41+b(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h+(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(45)739 2690 y Fv(6)76+b(Darcs)33 b(commands)1934 b(47)863 2790 y Fx(6.1)84+b(Common)28 b(options)f(to)g(darcs)g(commands)35 b(.)41+b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(48)863 2891 y(6.2)84 b(Options)27 b(apart)g(from)g(darcs)g(commands)+51 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)+90 b(56)863 2991 y(6.3)84 b(Getting)28 b(help)c(.)41+b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(57)1054+3091 y(6.3.1)k(darcs)27 b(help)38 b(.)k(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)+90 b(57)863 3192 y(6.4)84 b(Creating)27 b(rep)r(ositories)45+b(.)d(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(57)1054 3292 y(6.4.1)k(darcs)27+b(initialize)75 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(57)1054+3392 y(6.4.2)k(darcs)27 b(get)79 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)+f(.)90 b(59)1054 3493 y(6.4.3)k(darcs)27 b(put)66 b(.)42+b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(60)863 3593 y(6.5)84+b(Mo)r(difying)28 b(the)g(con)n(ten)n(ts)f(of)h(a)f(rep)r(ository)50+b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(61)1054 3694 y(6.5.1)k(darcs)27 b(add)56 b(.)42 b(.)f(.)h(.)g(.)f(.)h+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)+h(.)g(.)f(.)90 b(61)1054 3794 y(6.5.2)k(darcs)27 b(remo)n(v)n(e)61+b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(62)1054 3894 y(6.5.3)k(darcs)27+b(m)n(v)79 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(62)1054 3995 y(6.5.4)k(darcs)27 b(replace)64 b(.)42+b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h+(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(63)863 4095 y(6.6)84+b(W)-7 b(orking)27 b(with)h(c)n(hanges)63 b(.)42 b(.)f(.)h(.)f(.)h(.)f+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)+90 b(64)1054 4195 y(6.6.1)k(darcs)27 b(record)g(.)41+b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(64)1054 4296 y(6.6.2)k(darcs)27+b(pull)52 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(67)1054 4396 y(6.6.3)k(darcs)27 b(push)84 b(.)41 b(.)h(.)g(.)f(.)h(.)+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h+(.)g(.)f(.)90 b(69)1054 4497 y(6.6.4)k(darcs)27 b(send)h(.)42+b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(71)1054 4597+y(6.6.5)k(darcs)27 b(apply)54 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(74)863 4697 y(6.7)84 b(Seeing)28 b(what)f(y)n(ou'v)n(e)g(done)37+b(.)k(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)90 b(78)1054 4798 y(6.7.1)k(darcs)27+b(whatsnew)h(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(78)1054 4898+y(6.7.2)k(darcs)27 b(c)n(hanges)38 b(.)k(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90+b(78)1054 4998 y(6.7.3)k(darcs)27 b(sho)n(w)76 b(.)41+b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)90 b(80)p eop end+%%Page: 5 5+TeXDict begin 5 4 bop 291 282 a Fu(CONTENTS)2350 b Fx(5)415+515 y(6.8)84 b(More)27 b(adv)-5 b(anced)27 b(commands)36+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)+f(.)h(.)g(.)f(.)h(.)90 b(82)606 615 y(6.8.1)k(darcs)26+b(tag)75 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(82)606 715 y(6.8.2)k(darcs)26 b(setpref)77 b(.)42 b(.)f(.)h(.)f(.)h+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)+f(.)h(.)90 b(83)606 814 y(6.8.3)k(darcs)26 b(c)n(hec)n(k)58+b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(84)606 914 y(6.8.4)k(darcs)26+b(optimize)76 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(85)415+1013 y(6.9)84 b(Undoing,)28 b(redoing)e(and)h(running)h(in)f(circles)70+b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(87)606 1113 y(6.9.1)k(darcs)26 b(amend-record)82 b(.)42+b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)90 b(87)606 1213 y(6.9.2)k(darcs)26 b(rollbac)n(k)32+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(88)606 1312 y(6.9.3)k(darcs)26+b(unrecord)65 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(89)606+1412 y(6.9.4)k(darcs)26 b(obliterate)38 b(.)j(.)h(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(90)606 1512 y(6.9.5)k(darcs)26 b(rev)n(ert)41 b(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)+g(.)f(.)h(.)90 b(91)606 1611 y(6.9.6)k(darcs)26 b(unrev)n(ert)79+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)+f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(92)415 1711 y(6.10)42+b(Adv)-5 b(anced)28 b(examination)f(of)g(the)h(rep)r(ository)53+b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(92)606 1810 y(6.10.1)52 b(darcs)26 b(di\013)74 b(.)41+b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(92)606 1910 y(6.10.2)52+b(darcs)26 b(annotate)66 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(94)606 2010 y(6.10.3)52 b(darcs)26 b(sho)n(w)76 b(.)42+b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(95)415 2109 y(6.11)42+b(Rarely)27 b(needed)g(and)h(obscure)e(commands)60 b(.)41+b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(97)606 2209 y(6.11.1)52 b(darcs)26 b(con)n(v)n(ert)53+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(97)606 2309 y(6.11.2)52+b(darcs)26 b(mark-con\015icts)66 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(98)606 2408 y(6.11.3)52 b(darcs)26 b(dist)57 b(.)41+b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90 b(98)606 2508 y(6.11.4)52+b(darcs)26 b(trac)n(kdo)n(wn)71 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)90+b(98)606 2607 y(6.11.5)52 b(darcs)26 b(repair)41 b(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)+g(.)f(.)h(.)48 b(100)291 2790 y Fv(A)k(Theory)33 b(of)e(patc)m(hes)1846+b(101)415 2890 y Fx(A.1)64 b(Bac)n(kground)45 b(.)d(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)+h(.)f(.)h(.)g(.)f(.)h(.)48 b(101)415 2989 y(A.2)64 b(In)n(tro)r+(duction)25 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)48+b(101)415 3089 y(A.3)64 b(Applying)28 b(patc)n(hes)43+b(.)e(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)48 b(102)606 3189+y(A.3.1)74 b(Hunk)28 b(patc)n(hes)40 b(.)i(.)f(.)h(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)48+b(102)606 3288 y(A.3.2)74 b(T)-7 b(ok)n(en)26 b(replace)h(patc)n(hes)61+b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)+g(.)f(.)h(.)48 b(102)415 3388 y(A.4)64 b(P)n(atc)n(h)26+b(relationships)43 b(.)f(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)48+b(103)415 3487 y(A.5)64 b(Comm)n(uting)27 b(patc)n(hes)78+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)48 b(103)606 3587 y(A.5.1)74+b(Comp)r(osite)27 b(patc)n(hes)47 b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)48+b(103)606 3687 y(A.5.2)74 b(Ho)n(w)27 b(merges)f(are)h(actually)g(p)r+(erformed)21 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)48+b(105)415 3786 y(A.6)64 b(Con\015icts)32 b(.)42 b(.)f(.)h(.)f(.)h(.)f+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)48 b(107)415 3886 y(A.7)64+b(P)n(atc)n(h)26 b(string)h(formatting)74 b(.)42 b(.)f(.)h(.)f(.)h(.)g+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)48+b(108)291 4069 y Fv(B)56 b(DarcsRep)s(o)32 b(format)1828+b(109)291 4251 y(C)55 b(The)32 b(GNU)g(General)g(Public)g(License)1183+b(111)415 4351 y Fx(C.1)66 b(App)r(endix:)38 b(Ho)n(w)27+b(to)g(Apply)i(These)e(T)-7 b(erms)27 b(to)g(Y)-7 b(our)28+b(New)f(Programs)66 b(.)48 b(117)p eop end+%%Page: 6 6+TeXDict begin 6 5 bop 739 282 a Fx(6)2351 b Fu(CONTENTS)p+eop end+%%Page: 7 7+TeXDict begin 7 6 bop 291 1145 a Ft(Chapter)64 b(1)291+1567 y Fw(In)-6 b(tro)6 b(duction)291 2005 y Fx(Darcs)26+b(is)h(a)g(revision)f(con)n(trol)g(system,)i(along)e(the)i(lines)f(of)g+(CVS)h(or)e(arc)n(h.)36 b(That)27 b(means)291 2105 y(that)38+b(it)h(k)n(eeps)f(trac)n(k)f(of)h(v)-5 b(arious)37 b(revisions)g(and)h+(branc)n(hes)f(of)i(y)n(our)e(pro)5 b(ject,)40 b(allo)n(ws)291+2204 y(for)29 b(c)n(hanges)g(to)g(propagate)f(from)i(one)g(branc)n(h)f+(to)g(another.)43 b(Darcs)29 b(is)h(in)n(tended)h(to)f(b)r(e)291+2304 y(an)h(\\adv)-5 b(anced")30 b(revision)h(con)n(trol)f(system.)49+b(Darcs)31 b(has)g(t)n(w)n(o)g(particularly)g(distinctiv)n(e)291+2403 y(features)h(whic)n(h)h(di\013er)f(from)h(other)f(revision)g(con)n+(trol)f(systems:)47 b(1\))33 b(eac)n(h)f(cop)n(y)g(of)h(the)291+2503 y(source)27 b(is)i(a)f(fully)h(functional)g(branc)n(h,)f(and)h+(2\))f(underlying)g(darcs)g(is)h(a)f(consisten)n(t)g(and)291+2603 y(p)r(o)n(w)n(erful)f(theory)f(of)i(patc)n(hes.)291+2854 y Fv(Ev)m(ery)45 b(source)f(tree)g(a)g(branc)m(h)85+b Fx(The)38 b(primary)f(simplifying)i(notion)f(of)g(darcs)f(is)291+2954 y(that)d Fs(every)42 b Fx(cop)n(y)33 b(of)g(y)n(our)g(source)f(co)+r(de)i(is)f(a)h(full)g(rep)r(ository)-7 b(.)54 b(This)34+b(is)f(dramatically)291 3053 y(di\013eren)n(t)h(from)h(CVS,)g(in)g+(whic)n(h)f(the)h(normal)f(usage)g(is)g(for)g(there)h(to)f(b)r(e)i(one)+e(cen)n(tral)291 3153 y(rep)r(ository)22 b(from)i(whic)n(h)h(source)e+(co)r(de)h(will)h(b)r(e)g(c)n(hec)n(k)n(ed)e(out.)36+b(It)25 b(is)f(closer)f(to)h(the)h(notion)291 3253 y(of)32+b(arc)n(h,)h(since)g(the)g(`normal')f(use)h(of)g(arc)n(h)e(is)i(for)f+(eac)n(h)g(dev)n(elop)r(er)g(to)h(create)f(his)h(o)n(wn)291+3352 y(rep)r(ository)-7 b(.)41 b(Ho)n(w)n(ev)n(er,)29+b(darcs)f(mak)n(es)h(it)h(ev)n(en)f(easier,)g(since)h(simply)f(c)n(hec)+n(king)g(out)h(the)291 3452 y(co)r(de)37 b(is)g(all)f(it)i(tak)n(es)e+(to)h(create)g(a)f(new)h(rep)r(ository)-7 b(.)65 b(This)37+b(has)f(sev)n(eral)g(adv)-5 b(an)n(tages,)291 3552 y(since)28+b(y)n(ou)f(can)h(harness)f(the)i(full)g(p)r(o)n(w)n(er)e(of)h(darcs)f+(in)i(an)n(y)e(scratc)n(h)g(cop)n(y)h(of)g(y)n(our)f(co)r(de,)291+3651 y(without)f(committing)h(y)n(our)e(p)r(ossibly)h(destabilizing)g+(c)n(hanges)f(to)i(a)f(cen)n(tral)f(rep)r(ository)-7+b(.)291 3903 y Fv(Theory)47 b(of)f(patc)m(hes)84 b Fx(The)40+b(dev)n(elopmen)n(t)f(of)i(a)e(simpli\014ed)i(theory)e(of)h(patc)n(hes)+g(is)291 4002 y(what)23 b(originally)f(motiv)-5 b(ated)24+b(me)g(to)g(create)f(darcs.)34 b(This)24 b(patc)n(h)f(formalism)g+(means)h(that)291 4102 y(darcs)h(patc)n(hes)h(ha)n(v)n(e)g(a)g(set)h+(of)g(prop)r(erties,)f(whic)n(h)h(mak)n(e)f(p)r(ossible)g+(manipulations)h(that)291 4201 y(couldn't)g(b)r(e)g(done)g(in)h(other)e+(revision)g(con)n(trol)g(systems.)36 b(First,)27 b(ev)n(ery)f(patc)n(h)+h(is)g(in)n(v)n(ert-)291 4301 y(ible.)65 b(Secondly)-7+b(,)39 b(sequen)n(tial)d(patc)n(hes)h(\(i.e.)g(patc)n(hes)g(that)g(are)+f(created)g(in)h(sequence,)291 4401 y(one)30 b(after)g(the)g(other\))g+(can)g(b)r(e)h(reordered,)e(although)h(this)h(reordering)d(can)i(fail,)+h(whic)n(h)291 4500 y(means)g(the)h(second)f(patc)n(h)h(is)f(dep)r+(enden)n(t)i(on)e(the)h(\014rst.)49 b(Thirdly)-7 b(,)33+b(patc)n(hes)e(whic)n(h)h(are)291 4600 y(in)d(parallel)f(\(i.e.)i(b)r+(oth)g(patc)n(hes)f(w)n(ere)f(created)h(b)n(y)g(mo)r(difying)g(iden)n+(tical)g(trees\))h(can)f(b)r(e)291 4700 y(merged,)g(and)h(the)g(result)+g(of)f(a)h(set)g(of)f(merges)g(is)h(indep)r(enden)n(t)g(of)g(the)g+(order)f(in)h(whic)n(h)291 4799 y(the)c(merges)f(are)f(p)r(erformed.)36+b(This)26 b(last)g(prop)r(ert)n(y)f(is)g(critical)h(to)f(darcs')g+(philosoph)n(y)-7 b(,)26 b(as)291 4899 y(it)i(means)f(that)i(a)e+(particular)g(v)n(ersion)f(of)i(a)g(source)e(tree)i(is)g(fully)g+(de\014ned)h(b)n(y)e(the)i(list)f(of)291 4998 y(patc)n(hes)e(that)h+(are)e(in)i(it,)h(i.e.)f(there)f(is)h(no)f(issue)g(regarding)f(the)i+(order)e(in)i(whic)n(h)g(merges)1702 5208 y(7)p eop end+%%Page: 8 8+TeXDict begin 8 7 bop 739 282 a Fx(8)1569 b Fu(CHAPTER)27+b(1.)64 b(INTR)n(ODUCTION)739 515 y Fx(are)27 b(p)r(erformed.)38+b(F)-7 b(or)28 b(a)f(more)h(thorough)f(discussion)g(of)h(darcs')f+(theory)h(of)g(patc)n(hes,)g(see)739 615 y(App)r(endix)g(A.)739+855 y Fv(A)23 b(simple)e(adv)-5 b(anced)23 b(to)s(ol)82+b Fx(Besides)19 b(b)r(eing)h(\\adv)-5 b(anced")18 b(as)h(discussed)g+(ab)r(o)n(v)n(e,)h(darcs)739 955 y(is)32 b(actually)f(also)f(quite)j+(simple.)49 b(V)-7 b(ersioning)31 b(to)r(ols)g(can)h(b)r(e)g(seen)g(as)+f(three)g(la)n(y)n(ers.)48 b(A)n(t)739 1054 y(the)34+b(foundation)g(is)f(the)i(abilit)n(y)e(to)h(manipulate)g(c)n(hanges.)54+b(On)33 b(top)h(of)g(that)g(m)n(ust)g(b)r(e)739 1154+y(placed)c(some)g(kind)g(of)h(database)e(system)h(to)g(k)n(eep)g(trac)n+(k)f(of)i(the)f(c)n(hanges.)44 b(Finally)-7 b(,)31 b(at)739+1253 y(the)j(v)n(ery)e(top)h(is)g(some)g(sort)f(of)i(distribution)f+(system)g(for)g(getting)g(c)n(hanges)f(from)h(one)739+1353 y(place)27 b(to)h(another.)863 1457 y(Really)-7+b(,)30 b(only)f(the)g(\014rst)g(of)h(these)f(three)g(la)n(y)n(ers)e(is)+j(of)f(particular)f(in)n(terest)h(to)g(me,)h(so)739 1557+y(the)e(other)g(t)n(w)n(o)f(are)h(done)f(as)h(simply)g(as)g(p)r+(ossible.)38 b(A)n(t)28 b(the)h(database)e(la)n(y)n(er,)g(darcs)g(just)+739 1656 y(has)33 b(an)g(ordered)f(list)h(of)g(patc)n(hes)g(along)f+(with)i(the)g(patc)n(hes)e(themselv)n(es,)j(eac)n(h)d(stored)739+1756 y(as)k(an)g(individual)h(\014le.)65 b(Darcs')36+b(distribution)h(system)f(is)h(strongly)e(inspired)i(b)n(y)f(that)739+1856 y(of)d(arc)n(h.)52 b(Lik)n(e)33 b(arc)n(h,)h(darcs)e(uses)g(a)h+(dum)n(b)h(serv)n(er,)e(t)n(ypically)h(apac)n(he)f(or)g(just)i(a)f(lo)r+(cal)739 1955 y(or)38 b(net)n(w)n(ork)f(\014le)i(system)g(when)g+(pulling)g(patc)n(hes.)70 b(darcs)37 b(has)i(built-in)g(supp)r(ort)g+(for)739 2055 y(using)28 b Fr(ssh)g Fx(to)h(write)f(to)h(a)f(remote)h+(\014le)g(system.)40 b(A)29 b(darcs)f(executable)g(is)h(called)f(on)h+(the)739 2155 y(remote)34 b(system)g(to)g(apply)g(the)h(patc)n(hes.)56+b(Arbitrary)33 b(other)h(transp)r(ort)f(proto)r(cols)g(are)739+2254 y(supp)r(orted,)22 b(through)e(an)g(en)n(vironmen)n(t)f(v)-5+b(ariable)20 b(describing)g(a)g(command)g(that)h(will)f(run)739+2354 y(darcs)27 b(on)h(the)h(remote)e(system.)39 b(See)28+b(the)h(do)r(cumen)n(tation)f(for)g(D)n(AR)n(CS)p 3085+2354 25 4 v 30 w(APPL)-7 b(Y)p 3398 2354 V 29 w(F)n(OO)739+2453 y(in)28 b(Chapter)f(4)g(for)g(details.)863 2558+y(The)d(recommended)e(metho)r(d)i(is)f(to)g(send)g(patc)n(hes)g+(through)f(gpg-signed)g(email)h(mes-)739 2657 y(sages,)j(whic)n(h)i+(has)f(the)h(adv)-5 b(an)n(tage)26 b(of)h(b)r(eing)h(mostly)f(async)n+(hronous.)739 2897 y Fv(Keeping)j(trac)m(k)k(of)e(c)m(hanges)g(rather)h+(than)g(v)m(ersions)82 b Fx(In)28 b(the)g(last)f(paragraph,)e(I)739+2997 y(explained)31 b(revision)f(con)n(trol)g(systems)h(in)g(terms)g+(of)g(three)g(la)n(y)n(ers.)46 b(One)31 b(can)g(also)f(lo)r(ok)739+3096 y(at)k(them)i(as)e(ha)n(ving)f(t)n(w)n(o)h(distinct)i(uses.)57+b(One)35 b(is)f(to)h(pro)n(vide)f(a)g(history)g(of)g(previous)739+3196 y(v)n(ersions.)g(The)26 b(other)f(is)h(to)g(k)n(eep)f(trac)n(k)f+(of)i(c)n(hanges)f(that)h(are)e(made)i(to)g(the)g(rep)r(ository)-7+b(,)739 3296 y(and)37 b(to)g(allo)n(w)f(these)h(c)n(hanges)f(to)h(b)r+(e)h(merged)e(and)h(mo)n(v)n(ed)f(from)h(one)g(rep)r(ository)e(to)739+3395 y(another.)40 b(These)28 b(t)n(w)n(o)h(uses)f(are)g(distinct,)i+(and)f(almost)f(orthogonal,)f(in)i(the)h(sense)e(that)739+3495 y(a)d(to)r(ol)f(can)h(supp)r(ort)g(one)g(of)g(the)g(t)n(w)n(o)g+(uses)f(optimally)h(while)g(pro)n(viding)f(no)h(supp)r(ort)g(for)739+3595 y(the)f(other.)35 b(Darcs)23 b(is)h(not)g(in)n(tended)g(to)g(main)+n(tain)g(a)f(history)g(of)h(v)n(ersions,)f(although)g(it)h(is)739+3694 y(p)r(ossible)29 b(to)h(kludge)f(together)g(suc)n(h)g(a)g+(revision)f(history)-7 b(,)30 b(either)f(b)n(y)g(making)g(eac)n(h)g+(new)739 3794 y(patc)n(h)24 b(dep)r(end)g(on)g(all)f(previous)g(patc)n+(hes,)h(or)f(b)n(y)h(tagging)e(regularly)-7 b(.)34 b(In)24+b(a)g(sense,)g(this)g(is)739 3893 y(what)g(the)g(tag)f(feature)g(is)h+(for,)g(but)g(the)g(in)n(ten)n(tion)g(is)f(that)h(tagging)e(will)i(b)r+(e)g(used)g(only)f(to)739 3993 y(mark)32 b(particularly)g(notable)h(v)n+(ersions)e(\(e.g.)i(released)f(v)n(ersions,)h(or)f(p)r(erhaps)h(v)n+(ersions)739 4093 y(that)28 b(pass)f(a)g(time)h(consuming)f(test)h+(suite\).)863 4197 y(Other)d(revision)f(con)n(trol)f(systems)i(are)f+(cen)n(tered)g(up)r(on)i(the)f(job)g(of)g(k)n(eeping)f(trac)n(k)g(of)+739 4297 y(a)31 b(history)f(of)i(v)n(ersions,)e(with)i(the)g(abilit)n+(y)f(to)g(merge)g(c)n(hanges)f(b)r(eing)h(added)h(as)e(it)i(w)n(as)739+4396 y(seen)i(that)i(this)f(w)n(ould)f(b)r(e)h(desirable.)58+b(But)35 b(the)g(fundamen)n(tal)g(ob)5 b(ject)35 b(remained)f(the)739+4496 y(v)n(ersions)26 b(themselv)n(es.)863 4600 y(In)k(suc)n(h)f(a)g+(system,)h(a)f(patc)n(h)g(\(I)g(am)g(using)g(patc)n(h)h(here)e(to)i+(mean)f(an)g(encapsulated)739 4700 y(set)g(of)g(c)n(hanges\))f(is)h+(uniquely)g(determined)g(b)n(y)g(t)n(w)n(o)f(trees.)41+b(Merging)27 b(c)n(hanges)h(that)h(are)739 4799 y(in)34+b(t)n(w)n(o)f(trees)h(consists)f(of)h(\014nding)g(a)g(common)f(paren)n+(t)g(tree,)j(computing)d(the)i(di\013s)f(of)739 4899+y(eac)n(h)h(tree)h(with)g(their)g(paren)n(t,)h(and)f(then)g(clev)n+(erly)f(com)n(bining)g(those)h(t)n(w)n(o)f(di\013s)h(and)739+4998 y(applying)f(the)i(com)n(bined)f(di\013)h(to)f(the)g(paren)n(t)g+(tree,)i(p)r(ossibly)d(at)i(some)e(p)r(oin)n(t)h(in)h(the)p+eop end+%%Page: 9 9+TeXDict begin 9 8 bop 291 282 a Fu(1.1.)63 b(FEA)-7 b(TURES)2177+b Fx(9)291 515 y(pro)r(cess)38 b(allo)n(wing)g(h)n(uman)h(in)n(terv)n+(en)n(tion,)i(to)e(allo)n(w)f(for)h(\014xing)g(up)g(problems)g(in)h+(the)291 615 y(merge)26 b(suc)n(h)i(as)e(con\015icts.)415+728 y(In)36 b(the)g(w)n(orld)e(of)i(darcs,)h(the)f(source)e(tree)h(is)h+Fs(not)43 b Fx(the)36 b(fundamen)n(tal)g(ob)5 b(ject,)37+b(but)291 828 y(rather)26 b(the)i(patc)n(h)g(is)g(the)g(fundamen)n(tal)+g(ob)5 b(ject.)37 b(Rather)27 b(than)h(a)f(patc)n(h)h(b)r(eing)g+(de\014ned)291 928 y(in)40 b(terms)f(of)h(the)g(di\013erence)g(b)r(et)n+(w)n(een)g(t)n(w)n(o)f(trees,)j(a)d(tree)h(is)g(de\014ned)g(as)f(the)h+(result)291 1027 y(of)33 b(applying)f(a)h(giv)n(en)f(set)h(of)g(patc)n+(hes)f(to)h(an)g(empt)n(y)g(tree.)53 b(Moreo)n(v)n(er,)31+b(these)j(patc)n(hes)291 1127 y(ma)n(y)25 b(b)r(e)h(reordered)d+(\(unless)j(there)g(are)e(dep)r(endencies)i(b)r(et)n(w)n(een)g(the)g+(patc)n(hes)f(in)n(v)n(olv)n(ed\))291 1227 y(without)c(c)n(hanging)f+(the)i(tree.)35 b(As)21 b(a)g(result,)i(there)e(is)g(no)g(need)h(to)f+(\014nd)h(a)f(common)g(paren)n(t)291 1326 y(when)h(p)r(erforming)f(a)h+(merge.)34 b(Or,)22 b(if)h(y)n(ou)e(lik)n(e,)i(their)f(common)g(paren)n+(t)f(is)h(de\014ned)h(b)n(y)f(the)291 1426 y(set)30 b(of)h(common)f+(patc)n(hes,)h(and)f(ma)n(y)g(not)h(corresp)r(ond)e(to)i(an)n(y)e(v)n+(ersion)g(in)i(the)g(v)n(ersion)291 1525 y(history)-7+b(.)415 1639 y(One)32 b(useful)h(consequence)f(of)g(darcs')g(patc)n+(h-orien)n(ted)f(philosoph)n(y)h(is)g(that)h(since)f(a)291+1739 y(patc)n(h)21 b(need)i(not)f(b)r(e)g(uniquely)h(de\014ned)f(b)n(y)+g(a)g(pair)f(of)h(trees)g(\(old)g(and)g(new\),)i(w)n(e)d(can)h(ha)n(v)n+(e)291 1838 y(sev)n(eral)d(w)n(a)n(ys)g(of)h(represen)n(ting)g(the)h+(same)f(c)n(hange,)h(whic)n(h)f(di\013er)h(only)g(in)g(ho)n(w)f(they)h+(com-)291 1938 y(m)n(ute)27 b(and)h(what)f(the)h(result)g(of)f(merging)+g(them)h(is.)36 b(Of)28 b(course,)e(creating)h(suc)n(h)g(a)g(patc)n(h)+291 2038 y(will)19 b(require)g(some)g(sort)g(of)g(user)g(input.)35+b(This)20 b(is)f(a)h(Go)r(o)r(d)f(Thing,)i(since)f(the)g(user)f+Fs(cr)l(e)l(ating)291 2137 y Fx(the)f(patc)n(h)h(should)f(b)r(e)h(the)f+(one)g(forced)g(to)h(think)g(ab)r(out)f(what)g(he)h(really)e(w)n(an)n+(ts)h(to)g(c)n(hange,)291 2237 y(rather)i(than)i(the)h(users)d(merging)+h(the)h(patc)n(h.)35 b(An)22 b(example)g(of)g(this)g(is)f(the)i(tok)n+(en)e(replace)291 2336 y(patc)n(h)27 b(\(See)h(Section)g(A.3.2\).)37+b(This)28 b(feature)f(mak)n(es)g(it)h(p)r(ossible)f(to)h(create)f(a)g+(patc)n(h,)g(for)291 2436 y(example,)f(whic)n(h)g(c)n(hanges)f(ev)n+(ery)g(instance)h(of)g(the)h(v)-5 b(ariable)25 b(\\stupidly)p+2605 2436 25 4 v 30 w(named)p 2875 2436 V 30 w(v)-5 b(ar")25+b(to)291 2536 y(\\b)r(etter)p 557 2536 V 29 w(v)-5 b(ar)p+700 2536 V 29 w(name",)20 b(while)f(lea)n(ving)e(\\other)p+1720 2536 V 29 w(stupidly)p 2042 2536 V 30 w(named)p+2312 2536 V 30 w(v)-5 b(ar")17 b(un)n(touc)n(hed.)33+b(When)291 2635 y(this)27 b(patc)n(h)g(is)h(merged)e(with)i(an)n(y)f+(other)g(patc)n(h)g(in)n(v)n(olving)f(the)i(\\stupidly)p+2683 2635 V 29 w(named)p 2952 2635 V 30 w(v)-5 b(ar",)291+2735 y(that)27 b(instance)f(will)h(also)f(b)r(e)h(mo)r(di\014ed)g(to)g+(\\b)r(etter)p 1931 2735 V 29 w(v)-5 b(ar)p 2074 2735+V 29 w(name".)36 b(This)27 b(is)g(in)g(con)n(trast)e(to)291+2835 y(a)j(more)h(con)n(v)n(en)n(tional)e(merging)h(metho)r(d)h(whic)n+(h)g(w)n(ould)g(not)g(only)g(fail)g(to)g(c)n(hange)f(new)291+2934 y(instances)33 b(of)i(the)f(v)-5 b(ariable,)36 b(but)f(w)n(ould)e+(also)h(in)n(v)n(olv)n(e)f(con\015icts)h(when)g(merging)f(with)291+3034 y(an)n(y)24 b(patc)n(h)h(that)g(mo)r(di\014es)g(lines)g(con)n+(taining)f(the)i(v)-5 b(ariable.)35 b(By)24 b(more)h(using)f+(additional)291 3133 y(information)g(ab)r(out)i(the)g(programmer's)d+(in)n(ten)n(t,)j(darcs)f(is)g(th)n(us)h(able)f(to)g(mak)n(e)g(the)h+(pro-)291 3233 y(cess)e(of)h(c)n(hanging)f(a)h(v)-5 b(ariable)24+b(name)h(the)h(trivial)e(task)h(that)g(it)h(really)e(is,)i(whic)n(h)f+(is)g(really)291 3333 y(just)j(a)f(trivial)g(searc)n(h)f(and)h+(replace,)g(mo)r(dulo)h(tok)n(enizing)e(the)i(co)r(de)g(appropriately)+-7 b(.)415 3446 y(The)20 b(patc)n(h)g(formalism)f(discussed)g(in)h(App)+r(endix)h(A)g(is)e(what)h(mak)n(es)f(darcs')g(approac)n(h)291+3546 y(p)r(ossible.)66 b(In)37 b(order)f(for)h(a)g(tree)h(to)f(consist)+g(of)g(a)g(set)h(of)f(patc)n(hes,)j(there)d(m)n(ust)g(b)r(e)h(a)291+3645 y(deterministic)27 b(merge)f(of)h(an)n(y)f(set)h(of)g(patc)n(hes,)+f(regardless)f(of)i(the)g(order)f(in)h(whic)n(h)g(they)291+3745 y(m)n(ust)19 b(b)r(e)g(merged.)34 b(This)19 b(requires)f(that)h+(one)g(b)r(e)g(able)g(to)g(reorder)e(patc)n(hes.)34 b(While)20+b(I)f(don't)291 3845 y(kno)n(w)25 b(that)i(the)f(patc)n(hes)g(are)f+(required)g(to)i(b)r(e)f(in)n(v)n(ertible)g(as)f(w)n(ell,)i(m)n(y)f+(implemen)n(tation)291 3944 y(certainly)33 b(requires)g(in)n(v)n+(ertibilit)n(y)-7 b(.)55 b(In)35 b(particular,)f(in)n(v)n(ertibilit)n+(y)g(is)g(required)f(to)h(mak)n(e)291 4044 y(use)27 b(of)h(Theorem)e+(2,)i(whic)n(h)f(is)h(used)f(extensiv)n(ely)g(in)h(the)g(manipulation)f+(of)h(merges.)291 4392 y Fq(1.1)135 b(F)-11 b(eatures)291+4600 y Fv(Record)28 b(c)m(hanges)h(lo)s(cally)82 b Fx(In)25+b(darcs,)g(the)g(equiv)-5 b(alen)n(t)24 b(of)h(a)f(cvs)h(\\commit")f+(is)g(called)291 4700 y(record,)g(b)r(ecause)h(it)h(do)r(esn't)f(put)h+(the)g(c)n(hange)e(in)n(to)i(an)n(y)e(remote)h(or)g(cen)n(tralized)f+(rep)r(osi-)291 4799 y(tory)-7 b(.)36 b(Changes)26 b(are)g(alw)n(a)n+(ys)f(recorded)g(lo)r(cally)-7 b(,)27 b(meaning)g(no)f(net)i(access)e+(is)h(required)f(in)291 4899 y(order)c(to)h(w)n(ork)g(on)g(y)n(our)f+(pro)5 b(ject)23 b(and)h(record)e(c)n(hanges)g(as)h(y)n(ou)g(mak)n(e)f+(them.)37 b(Moreo)n(v)n(er,)291 4998 y(this)25 b(means)h(that)f(there)h+(is)f(no)h(need)f(for)g(a)h(separate)e(\\disconnected)h(op)r(eration")f+(mo)r(de.)p eop end+%%Page: 10 10+TeXDict begin 10 9 bop 739 282 a Fx(10)1527 b Fu(CHAPTER)27+b(1.)64 b(INTR)n(ODUCTION)739 515 y Fv(In)m(teractiv)m(e)49+b(records)83 b Fx(Y)-7 b(ou)41 b(can)f(c)n(ho)r(ose)g(to)g(p)r(erform)g+(an)h(in)n(teractiv)n(e)e(record,)k(in)739 615 y(whic)n(h)24+b(case)g(darcs)f(will)i(prompt)g(y)n(ou)e(for)h(eac)n(h)g(c)n(hange)f+(y)n(ou)h(ha)n(v)n(e)g(made)g(and)g(ask)g(if)h(y)n(ou)739+715 y(wish)32 b(to)g(record)e(it.)51 b(Of)32 b(course,)f(y)n(ou)h(can)f+(tell)i(darcs)d(to)i(record)f(all)h(the)g(c)n(hanges)e(in)j(a)739+814 y(giv)n(en)h(\014le,)j(or)d(to)h(skip)g(all)g(the)g(c)n(hanges)f+(in)h(a)f(giv)n(en)h(\014le,)i(or)d(go)g(bac)n(k)g(to)h(a)f(previous)+739 914 y(c)n(hange,)d(or)f(whatev)n(er.)47 b(There)31+b(is)g(also)f(an)h(exp)r(erimen)n(tal)g(graphical)f(in)n(terface,)h+(whic)n(h)739 1013 y(allo)n(ws)23 b(y)n(ou)h(to)g(view)g(and)h(c)n(ho)r+(ose)e(c)n(hanges)g(ev)n(en)h(more)g(easily)-7 b(,)24+b(and)h(in)f(whic)n(hev)n(er)g(order)739 1113 y(y)n(ou)j(lik)n(e.)739+1329 y Fv(Unrecord)35 b(lo)s(cal)f(c)m(hanges)84 b Fx(As)29+b(a)h(corollary)d(to)j(the)g(\\lo)r(cal")e(nature)i(of)f(the)i(record)+739 1429 y(op)r(eration,)20 b(if)g(a)f(c)n(hange)f(hasn't)i(y)n(et)f(b)+r(een)h(published)g(to)f(the)h(w)n(orld|that)f(is,)i(if)f(the)g(lo)r+(cal)739 1528 y(rep)r(ository)25 b(isn't)i(accessible)f(b)n(y)h+(others|y)n(ou)e(can)h(safely)g(unrecord)g(a)g(c)n(hange)g(\(ev)n(en)h+(if)739 1628 y(it)32 b(w)n(asn't)g(the)g(most)g(recen)n(tly)f(recorded)+g(c)n(hange\))g(and)h(then)g(re-record)e(it)i(di\013eren)n(tly)-7+b(,)739 1727 y(for)29 b(example)h(if)g(y)n(ou)f(forgot)g(to)h(add)g(a)f+(\014le,)i(in)n(tro)r(duced)f(a)f(bug)h(or)f(realized)g(that)h(what)739+1827 y(y)n(ou)d(recorded)f(as)h(a)g(single)g(c)n(hange)g(w)n(as)f+(really)h(t)n(w)n(o)f(separate)h(c)n(hanges.)739 2043+y Fv(In)m(teractiv)m(e)38 b(ev)m(erything)f(else)82 b+Fx(Most)32 b(darcs)e(commands)h(supp)r(ort)h(an)f(in)n(teractiv)n(e)739+2143 y(in)n(terface.)i(The)18 b(\\rev)n(ert")f(command,)i(for)f+(example,)i(whic)n(h)e(undo)r(es)h(unrecorded)e(c)n(hanges)739+2242 y(has)29 b(the)i(same)e(in)n(terface)h(as)f(record,)g(so)h(y)n(ou)+f(can)h(easily)f(rev)n(ert)g(just)h(a)g(single)f(c)n(hange.)739+2342 y(Pull,)f(push,)h(send)g(and)f(apply)g(all)g(allo)n(w)f(y)n(ou)h+(to)g(view)h(and)f(in)n(teractiv)n(ely)f(select)h(whic)n(h)739+2441 y(c)n(hanges)e(y)n(ou)h(wish)g(to)h(pull,)g(push,)g(send)f(or)g+(apply)-7 b(.)739 2657 y Fv(T)f(est)35 b(suites)81 b+Fx(Darcs)30 b(has)f(supp)r(ort)h(for)g(in)n(tegrating)e(a)i(test)g+(suite)g(with)h(a)f(rep)r(ository)-7 b(.)739 2757 y(If)32+b(y)n(ou)f(c)n(ho)r(ose)g(to)h(use)f(this,)i(y)n(ou)f(can)f(de\014ne)h+(a)f(test)i(command)e(\(e.g.)h(\\mak)n(e)e(c)n(hec)n(k"\))739+2857 y(and)i(ha)n(v)n(e)e(darcs)h(run)h(that)g(command)g(on)f(a)h+(clean)f(cop)n(y)g(of)h(the)g(pro)5 b(ject)32 b(either)f(prior)739+2956 y(to)c(recording)e(a)i(c)n(hange)f(or)h(prior)f(to)h(applying)f(c)+n(hanges|and)g(to)h(reject)g(c)n(hanges)f(that)739 3056+y(cause)h(the)h(test)g(to)f(fail.)739 3272 y Fv(An)m(y)32+b(old)e(serv)m(er)83 b Fx(Darcs)26 b(do)r(es)g(not)h(require)f(a)g(sp)r+(ecialized)g(serv)n(er)f(in)i(order)e(to)i(mak)n(e)739+3371 y(a)c(rep)r(ository)f(a)n(v)-5 b(ailable)22 b(for)h(read)f+(access.)34 b(Y)-7 b(ou)24 b(can)f(use)g(h)n(ttp,)i(ftp,)g(or)d(ev)n+(en)h(just)h(a)f(plain)739 3471 y(old)k(ssh)h(serv)n(er)d(to)j(access)e+(y)n(our)h(darcs)f(rep)r(ository)-7 b(.)739 3687 y Fv(Y)f(ou)36+b(decide)g(write)h(p)s(ermissions)80 b Fx(Darcs)31 b(do)r(esn't)g(try)h+(to)f(manage)g(write)g(access.)739 3786 y(That's)38 b(y)n(our)f+(business.)70 b(Supp)r(orted)38 b(push)h(metho)r(ds)g(include)g(direct)+f(ssh)g(access)f(\(if)739 3886 y(y)n(ou're)d(willing)i(to)f+Fs(give)43 b Fx(direct)35 b(ssh)h(access)e(a)n(w)n(a)n(y\),)i(using)f+(sudo)g(to)g(allo)n(w)g(users)g(who)739 3986 y(already)23+b(ha)n(v)n(e)h(shell)h(access)f(to)h(only)f(apply)h(c)n(hanges)e(to)i+(the)h(rep)r(ository)-7 b(,)24 b(or)g(v)n(eri\014cation)739+4085 y(of)k(gpg-signed)f(c)n(hanges)h(sen)n(t)g(b)n(y)h(email)f+(against)f(a)i(list)g(of)f(allo)n(w)n(ed)f(k)n(eys.)39+b(In)29 b(addition,)739 4185 y(there)d(is)g(go)r(o)r(d)g(supp)r(ort)g+(for)f(submission)h(of)g(patc)n(hes)g(b)n(y)g(email)g(that)h(are)e(not)+h(automat-)739 4284 y(ically)i(applied,)g(but)h(can)f(easily)f(b)r(e)i+(applied)f(with)h(a)f(shell)g(escap)r(e)g(from)g(a)g(mail)g(reader)739+4384 y(\(this)g(is)g(ho)n(w)f(I)g(deal)g(with)i(con)n(tributions)d(to)i+(darcs\).)739 4600 y Fv(Symmetric)i(rep)s(ositories)80+b Fx(Ev)n(ery)25 b(darcs)g(rep)r(ository)f(is)i(created)f(equal)g(\(w)n+(ell,)i(with)739 4700 y(the)f(exception)e(of)i(a)f(\\partial")e(rep)r+(ository)-7 b(,)24 b(whic)n(h)h(do)r(esn't)h(con)n(tain)e(a)h(full)h+(history.)13 b(.)h(.)g(\),)739 4799 y(and)29 b(ev)n(ery)f(w)n(orking)g+(directory)g(has)h(an)g(asso)r(ciated)f(rep)r(ository)-7+b(.)40 b(As)30 b(a)f(result,)g(there)g(is)739 4899 y(a)23+b(symmetry)g(b)r(et)n(w)n(een)h(\\uploading")e(and)h(\\do)n(wnloading")+e(c)n(hanges|y)n(ou)g(can)i(use)h(the)739 4998 y(same)j(commands)g+(\(push)h(or)f(pull\))h(for)f(either)h(purp)r(ose.)p+eop end+%%Page: 11 11+TeXDict begin 11 10 bop 291 282 a Fu(1.2.)63 b(SWITCHING)29+b(FR)n(OM)e(CVS)1610 b Fx(11)291 515 y Fv(CGI)32 b(script)83+b Fx(Darcs)27 b(has)g(a)g(CGI)h(script)f(that)h(allo)n(ws)e(bro)n+(wsing)g(of)h(the)h(rep)r(ositories.)291 729 y Fv(P)m(ortable)83+b Fx(Darcs)18 b(runs)g(on)g(UNIX)h(\(or)f(UNIX-lik)n(e\))g(systems)g+(\(whic)n(h)h(includes)f(Mac)g(OS)g(X\))291 829 y(as)27+b(w)n(ell)g(as)g(on)g(Microsoft)g(Windo)n(ws.)291 1043+y Fv(File)44 b(and)i(directory)g(mo)m(v)m(es)83 b Fx(Renames)39+b(or)g(mo)n(v)n(es)f(of)h(\014les)h(and)f(directories,)i(of)291+1142 y(course)24 b(are)g(handled)i(prop)r(erly)-7 b(,)25+b(so)g(when)h(y)n(ou)f(rename)f(a)h(\014le)h(or)f(mo)n(v)n(e)f(it)i(to)+g(a)f(di\013eren)n(t)291 1242 y(directory)-7 b(,)26 b(its)i(history)f+(is)g(un)n(brok)n(en,)f(and)i(merges)e(with)j(rep)r(ositories)c(that)j+(don't)g(ha)n(v)n(e)291 1342 y(the)g(\014le)f(renamed)g(will)h(w)n(ork)+e(as)h(exp)r(ected.)291 1556 y Fv(T)-8 b(ok)m(en)35 b(replace)83+b Fx(Y)-7 b(ou)31 b(can)f(use)g(the)g(\\darcs)f(replace")g(command)h+(to)g(mo)r(dify)g(all)g(o)r(c-)291 1655 y(currences)25+b(of)h(a)g(particular)f(tok)n(en)h(\(de\014ned)h(b)n(y)f(a)g+(con\014gurable)f(set)h(of)h(c)n(haracters)d(that)291+1755 y(are)35 b(allo)n(w)n(ed)h(in)g(\\tok)n(ens"\))g(in)g(a)h(\014le.)+64 b(This)37 b(has)f(the)h(adv)-5 b(an)n(tage)35 b(that)i(merges)e+(with)291 1854 y(c)n(hanges)22 b(that)i(in)n(tro)r(duce)g(new)g(copies)+f(of)h(the)g(old)g(tok)n(en)f(will)h(ha)n(v)n(e)f(the)h(e\013ect)g(of)g+(c)n(hang-)291 1954 y(ing)34 b(it)i(to)f(the)g(new)g(tok)n(en|whic)n(h)+f(comes)h(in)g(handy)g(when)g(c)n(hanging)e(a)i(v)-5+b(ariable)34 b(or)291 2054 y(function)28 b(name)f(that)h(is)g(used)f+(throughout)g(a)g(pro)5 b(ject.)291 2268 y Fv(Con\014gurable)35+b(defaults)83 b Fx(Y)-7 b(ou)31 b(can)g(easily)g(con\014gure)f(the)i+(default)f(\015ags)g(passed)f(to)291 2367 y(an)n(y)h(command)h(on)h+(either)f(a)g(p)r(er-rep)r(ository)e(or)i(a)g(p)r(er-user)f(basis)h(or)+g(a)g(com)n(bination)291 2467 y(thereof.)291 2740 y Fq(1.2)135+b(Switc)l(hing)45 b(from)h(CVS)291 2921 y Fx(Darcs)26+b(is)i(refreshingly)e(di\013eren)n(t)i(from)f(CVS.)415+3021 y(CVS)g(k)n(eeps)f(v)n(ersion)f(con)n(trolled)h(data)g(in)h(a)f+(cen)n(tral)g(rep)r(ository)-7 b(,)25 b(and)h(requires)g(that)291+3121 y(users)j(c)n(hec)n(k)h(out)g(a)g(w)n(orking)f(directory)g(whenev)+n(er)h(they)h(wish)f(to)h(access)e(the)i(v)n(ersion-)291+3220 y(con)n(trolled)h(sources.)53 b(In)34 b(order)e(to)i(mo)r(dify)g+(the)g(cen)n(tral)f(rep)r(ository)-7 b(,)33 b(a)h(user)f(needs)g(to)291+3320 y(ha)n(v)n(e)27 b(write)h(access)g(to)g(the)h(cen)n(tral)f(rep)r+(ository;)f(if)i(he)g(do)r(esn't,)g(CVS)g(merely)f(b)r(ecomes)291+3420 y(a)f(to)r(ol)g(to)h(get)f(the)h(latest)f(sources.)415+3519 y(In)d(darcs)f(there)g(is)h(no)f(distinction)h(b)r(et)n(w)n(een)g+(w)n(orking)e(directories)g(and)i(rep)r(ositories.)291+3619 y(In)32 b(order)f(to)i(w)n(ork)e(on)h(a)g(pro)5+b(ject,)33 b(a)f(user)g(mak)n(es)g(a)g(lo)r(cal)g(cop)n(y)g(of)g(the)h+(rep)r(ository)e(he)291 3718 y(w)n(an)n(ts)26 b(to)g(w)n(ork)g(in;)h+(he)g(ma)n(y)f(then)i(harness)d(the)j(full)f(p)r(o)n(w)n(er)f(of)h(v)n+(ersion)e(con)n(trol)g(lo)r(cally)-7 b(.)291 3818 y(In)30+b(order)g(to)g(distribute)h(his)g(c)n(hanges,)f(a)g(user)g(who)g(has)g+(write)g(access)g(can)g Fs(push)37 b Fx(them)291 3918+y(to)26 b(the)h(remote)f(rep)r(ository;)g(one)g(who)h(do)r(esn't)g(can)+f(simply)h(send)f(them)i(b)n(y)e(e-mail)g(in)h(a)291+4017 y(format)g(that)h(mak)n(es)e(them)i(easy)f(to)g(apply)h(on)f(the)h+(remote)f(system.)291 4231 y Fv(Darcs)34 b(commands)f(for)g(CVS)h+(users)82 b Fx(Because)28 b(of)h(the)g(di\013eren)n(t)g(mo)r(dels)g+(used)g(b)n(y)291 4331 y(cvs)e(and)g(darcs,)g(it)h(is)f(di\016cult)i+(to)e(pro)n(vide)f(a)i(complete)f(equiv)-5 b(alence)27+b(b)r(et)n(w)n(een)h(cvs)f(and)291 4430 y(darcs.)35 b(A)28+b(rough)f(corresp)r(ondence)f(for)h(the)h(ev)n(eryda)n(y)d(commands)i+(follo)n(ws:)291 4687 y Fr(cvs)42 b(checkout)498 4787+y(darcs)g(get)291 4899 y(cvs)g(update)498 4998 y(darcs)g(pull)p+eop end+%%Page: 12 12+TeXDict begin 12 11 bop 739 282 a Fx(12)1527 b Fu(CHAPTER)27+b(1.)64 b(INTR)n(ODUCTION)739 515 y Fr(cvs)42 b(-n)h(update)946+615 y(darcs)f(pull)g(--dry-run)24 b Fx(\(summarize)j(remote)g(c)n+(hanges\))739 736 y Fr(cvs)42 b(-n)h(update)946 835 y(darcs)f(whatsnew)+e(--summary)24 b Fx(\(summarize)j(lo)r(cal)g(c)n(hanges\))739+956 y Fr(cvs)42 b(-n)h(update)e(|)i(grep)f('?')946 1056+y(darcs)g(whatsnew)e(-ls)j(|)g(grep)f(^a)70 b Fx(\(list)28+b(p)r(oten)n(tial)g(\014les)f(to)h(add\))739 1177 y Fr(rm)43+b(foo.txt;)d(cvs)i(update)f(foo.txt)946 1276 y(darcs)h(revert)f+(foo.txt)25 b Fx(\(rev)n(ert)h(to)i(fo)r(o.txt)g(from)f(rep)r(o\))739+1397 y Fr(cvs)42 b(diff)946 1497 y(darcs)g(whatsnew)24+b Fx(\(if)29 b(c)n(hec)n(king)d(lo)r(cal)h(c)n(hanges\))739+1618 y Fr(cvs)42 b(diff)946 1717 y(darcs)g(diff)26 b+Fx(\(if)i(c)n(hec)n(king)f(recorded)f(c)n(hanges\))739+1838 y Fr(cvs)42 b(commit)946 1938 y(darcs)g(record)25+b Fx(\(if)k(committing)e(lo)r(cally\))739 2059 y Fr(cvs)42+b(commit)946 2158 y(darcs)g(tag)26 b Fx(\(if)j(marking)d(a)h(v)n+(ersion)f(for)h(later)g(use\))739 2279 y Fr(cvs)42 b(commit)946+2379 y(darcs)g(push)26 b Fx(or)h Fr(darcs)41 b(send)26+b Fx(\(if)j(committing)e(remotely\))739 2500 y Fr(cvs)42+b(diff)g(|)h(mail)946 2599 y(darcs)f(send)739 2720 y(cvs)g(add)946+2820 y(darcs)g(add)739 2941 y(cvs)g(tag)h(-b)946 3040+y(darcs)f(get)739 3161 y(cvs)g(tag)946 3261 y(darcs)g(tag)739+3483 y Fv(Migrating)34 b(CVS)i(rep)s(ositories)d(to)i(darcs)84+b Fx(T)-7 b(o)r(ols)30 b(and)h(instructions)f(for)g(migrat-)739+3582 y(ing)36 b(CVS)g(rep)r(ositories)f(to)g(darcs)g(are)h(pro)n(vided)+f(on)g(the)i(darcs)e(comm)n(unit)n(y)g(w)n(ebsite:)739+3682 y(h)n(ttp://darcs.net/DarcsWiki/Con)n(v)n(ertingF)-7+b(romCvs)739 3963 y Fq(1.3)135 b(Switc)l(hing)46 b(from)f(arc)l(h)739+4147 y Fx(Although)35 b(arc)n(h,)g(lik)n(e)f(darcs,)i(is)e(a)g+(distributed)i(system,)g(and)e(the)h(t)n(w)n(o)f(systems)g(ha)n(v)n(e)+739 4246 y(man)n(y)e(similarities)f(\(b)r(oth)j(require)d(no)h(sp)r+(ecial)g(serv)n(er,)g(for)g(example\),)i(their)e(essen)n(tial)739+4346 y(organization)25 b(is)j(v)n(ery)e(di\013eren)n(t.)863+4447 y(Lik)n(e)40 b(CVS,)h(arc)n(h)e(k)n(eeps)h(data)g(in)h(t)n(w)n(o)e+(t)n(yp)r(es)i(of)f(data)g(structures:)62 b(rep)r(ositories)739+4546 y(\(called)36 b(\\arc)n(hiv)n(es"\))d(and)k(w)n(orking)d+(directories.)61 b(In)36 b(order)f(to)h(mo)r(dify)h(a)f(rep)r(ository)+-7 b(,)739 4646 y(one)28 b(m)n(ust)h(\014rst)f(c)n(hec)n(k)g(out)h(a)f+(corresp)r(onding)f(w)n(orking)g(directory)-7 b(.)39+b(This)29 b(requires)e(that)739 4746 y(users)e(remem)n(b)r(er)g(a)g(n)n+(um)n(b)r(er)g(of)h(di\013eren)n(t)g(w)n(a)n(ys)e(of)i(pushing)f(data)g+(around)g(|)h Fr(tla)e(get)p Fx(,)739 4845 y Fr(update)p+Fx(,)h Fr(commit)p Fx(,)g Fr(archive-mirror)d Fx(and)28+b(so)f(on.)p 739 4921 1146 4 v 831 4975 a Fp(0)866 4998+y Fo(http://darcs.net/DarcsWi)q(ki/)q(Conv)q(ert)q(ingF)q(rom)q(Cvs)p+eop end+%%Page: 13 13+TeXDict begin 13 12 bop 291 282 a Fu(1.3.)63 b(SWITCHING)29+b(FR)n(OM)e(AR)n(CH)1535 b Fx(13)415 515 y(In)24 b(darcs,)g(on)f(the)h+(other)f(hand,)i(there)f(is)f(no)h(distinction)g(b)r(et)n(w)n(een)g(w)n+(orking)e(directo-)291 615 y(ries)k(and)i(rep)r(ositories,)d(and)j+(just)g(c)n(hec)n(king)e(out)h(y)n(our)f(sources)g(creates)h(a)g(lo)r+(cal)f(cop)n(y)h(of)291 715 y(a)e(rep)r(ository)-7 b(.)34+b(This)26 b(allo)n(ws)e(y)n(ou)h(to)g(harness)g(the)h(full)g(p)r(o)n(w)+n(er)e(of)i(v)n(ersion)e(con)n(trol)g(in)i(an)n(y)291+814 y(scratc)n(h)32 b(cop)n(y)g(of)i(y)n(our)e(sources,)h(and)h(also)e+(means)h(that)h(there)f(are)f(just)i(t)n(w)n(o)f(w)n(a)n(ys)f(to)291+914 y(push)27 b(data)g(around:)36 b Fr(darcs)25 b(record)p+Fx(,)g(whic)n(h)i(stores)f(edits)i(in)n(to)f(y)n(our)f(lo)r(cal)g(rep)r+(ository)-7 b(,)291 1013 y(and)32 b Fr(pull)p Fx(,)f(whic)n(h)h(mo)n(v)+n(es)f(data)h(b)r(et)n(w)n(een)g(rep)r(ositories.)49+b(\()p Fr(darcs)30 b(push)h Fx(is)h(merely)g(the)291+1113 y(opp)r(osite)27 b(of)g Fr(pull)p Fx(;)f Fr(send)g+Fx(and)i Fr(apply)e Fx(are)g(just)i(the)g(t)n(w)n(o)f(halv)n(es)g(of)g+Fr(push)p Fx(\).)291 1334 y Fv(Darcs)36 b(commands)e(for)h(arc)m(h)i+(users)83 b Fx(Because)29 b(of)h(the)h(di\013eren)n(t)g(mo)r(dels)f+(used)g(b)n(y)291 1434 y(arc)n(h)i(and)i(darcs,)h(it)f(is)g(di\016cult)+h(to)f(pro)n(vide)f(a)h(complete)f(equiv)-5 b(alence)34+b(b)r(et)n(w)n(een)g(arc)n(h)291 1533 y(and)27 b(darcs.)36+b(A)28 b(rough)e(corresp)r(ondence)g(for)h(the)h(ev)n(eryda)n(y)d+(commands)i(follo)n(ws:)291 1802 y Fr(tla)42 b(init-tree)498+1901 y(darcs)g(initialize)291 2022 y(tla)g(get)498 2121+y(darcs)g(get)291 2241 y(tla)g(update)498 2341 y(darcs)g(pull)291+2461 y(tla)g(file-diffs)d(f)44 b(|)f(patch)e(-R)498 2561+y(darcs)h(revert)291 2681 y(tla)g(changes)f(--diffs)498+2780 y(darcs)h(whatsnew)291 2900 y(tla)g(logs)498 3000+y(darcs)g(changes)291 3120 y(tla)g(file-diffs)498 3220+y(darcs)g(diff)g(-u)291 3340 y(tla)g(add)498 3440 y(darcs)g(add)291+3560 y(tla)g(mv)498 3659 y(darcs)g(mv)26 b Fx(\(not)i+Fr(tla)43 b(move)p Fx(\))291 3779 y Fr(tla)f(commit)498+3879 y(darcs)g(record)25 b Fx(\(if)j(committing)g(lo)r(cally\))291+3999 y Fr(tla)42 b(commit)498 4099 y(darcs)g(tag)26 b+Fx(\(if)i(marking)f(a)g(v)n(ersion)f(for)h(later)g(use\))291+4219 y Fr(tla)42 b(commit)498 4319 y(darcs)g(push)26+b Fx(or)g Fr(darcs)42 b(send)26 b Fx(\(if)i(committing)g(remotely\))291+4439 y Fr(tla)42 b(archive-mirror)498 4538 y(darcs)g(pull)26+b Fx(or)g Fr(darcs)42 b(push)291 4658 y(tla)g(tag)498+4758 y(darcs)g(get)26 b Fx(\(if)i(creating)f(a)g(branc)n(h\))291+4878 y Fr(tla)42 b(tag)498 4978 y(darcs)g(tag)26 b Fx(\(if)i(creating)f+(a)g(tag\).)p eop end+%%Page: 14 14+TeXDict begin 14 13 bop 739 282 a Fx(14)1527 b Fu(CHAPTER)27+b(1.)64 b(INTR)n(ODUCTION)739 515 y Fv(Migrating)36 b(arc)m(h)k(rep)s+(ositories)35 b(to)i(darcs)84 b Fx(T)-7 b(o)r(ols)32+b(and)g(instructions)g(for)g(migrat-)739 615 y(ing)37+b(arc)n(h)f(rep)r(ositories)g(to)h(darcs)f(are)g(pro)n(vided)h(on)g+(the)g(darcs)f(comm)n(unit)n(y)h(w)n(ebsite:)739 715+y(h)n(ttp://darcs.net/DarcsWiki/Con)n(v)n(ertingF)-7+b(romArc)n(h)p 739 4921 1146 4 v 831 4975 a Fp(0)866+4998 y Fo(http://darcs.net/DarcsWi)q(ki/)q(Conv)q(ert)q(ingF)q(rom)q+(Arch)p eop end+%%Page: 15 15+TeXDict begin 15 14 bop 291 1164 a Ft(Chapter)64 b(2)291+1605 y Fw(Building)76 b(darcs)291 2062 y Fx(This)35 b(c)n(hapter)g+(should)h(w)n(alk)f(y)n(ou)g(through)g(the)i(steps)e(necessary)f(to)i+(build)h(darcs)d(for)291 2162 y(y)n(ourself.)64 b(There)36+b(are)g(in)h(general)f(t)n(w)n(o)g(w)n(a)n(ys)g(to)h(build)g(darcs.)64+b(One)37 b(is)g(for)g(building)291 2261 y(released)24+b(v)n(ersions)g(from)i(tarballs,)f(and)h(the)h(other)e(is)h(to)g(build)+g(the)h(latest)e(and)h(greatest)291 2361 y(darcs,)g(from)h(the)h(darcs)+f(rep)r(o)g(itself.)415 2486 y(Please)i(let)h(me)g(kno)n(w)f(if)i(y)n+(ou)e(ha)n(v)n(e)g(an)n(y)g(problems)g(building)h(darcs,)g(or)f(don't)h+(ha)n(v)n(e)291 2586 y(problems)h(describ)r(ed)h(in)g(this)g(c)n+(hapter)g(and)f(think)i(there's)f(something)f(obsolete)g(here,)291+2686 y(so)c(I)g(can)g(k)n(eep)g(this)h(page)f(up-to-date.)291+3097 y Fq(2.1)135 b(Prerequisites)291 3327 y Fx(T)-7+b(o)30 b(build)g(darcs)g(y)n(ou)f(will)i(need)f(to)h(ha)n(v)n(e)e+Fr(ghc)p Fx(,)h(the)g(Glorious)f(Glasgo)n(w)g(Hask)n(ell)h(Com-)291+3427 y(piler.)36 b(Y)-7 b(ou)28 b(should)f(ha)n(v)n(e)g(at)g(the)h(v)n+(ery)f(minim)n(um)h(v)n(ersion)e(6.4.)415 3552 y(It)k(is)g(a)g(go)r(o)r+(d)f(idea)g(\(but)i(not)f(required\))f(to)h(ha)n(v)n(e)f(soft)n(w)n+(are)f(installed)i(that)g(pro)n(vide)291 3652 y(darcs)d(net)n(w)n(ork)g+(access.)38 b(The)29 b Fr(libwww-dev)p Fx(,)c Fr(libwww-ssl-dev)d+Fx(or)28 b Fr(libcurl)e Fx(pac)n(k)-5 b(ages)291 3751+y(new)n(er)27 b(than)i(than)f(7.18.0)f(are)g(recommended)h(b)r(ecause)g+(they)g(pro)n(vide)f(pip)r(elining)i(sup-)291 3851 y(p)r(ort)18+b(sp)r(eed)g(up)h(HTTP)f(access.)33 b(They)18 b(ha)n(v)n(e)f(to)h+(explicitly)h(c)n(hosen)e(with)i Fr(--with-libwww)291+3951 y Fx(or)26 b Fr(--with-curl-pipe)o(lin)o(in)o(g)p+Fx(.)31 b(Otherwise,)c(darcs)f(will)h(automatically)g(lo)r(ok)f(for)h+(one)291 4050 y(of)f(lib)r(curl,)h Fr(curl)e Fx(or)h+Fr(wget)p Fx(.)34 b(Y)-7 b(ou)27 b(also)e(migh)n(t)i(w)n(an)n(t)f(to)g+(ha)n(v)n(e)f(scp)i(a)n(v)-5 b(ailable)25 b(if)i(y)n(ou)f(w)n(an)n(t)+291 4150 y(to)h(grab)f(y)n(our)h(rep)r(os)f(o)n(v)n(er)g(ssh.)14+b(.)g(.)415 4275 y(T)-7 b(o)29 b(use)f(the)i Fr(diff)d+Fx(command)h(of)h(darcs,)f(a)h Fr(diff)e Fx(program)g(supp)r(orting)h+(options)h Fr(-r)291 4375 y Fx(\(recursiv)n(e)i(di\013)6+b(\))34 b(and)e Fr(-N)g Fx(\(sho)n(w)g(new)h(\014les)g(as)f+(di\013erences)g(against)g(an)g(empt)n(y)h(\014le\))g(is)291+4475 y(required.)41 b(The)29 b Fr(configure)d Fx(script)j(will)g(lo)r+(ok)g(for)g Fr(gdiff)p Fx(,)f Fr(gnudiff)e Fx(and)j Fr(diff)f+Fx(in)i(this)291 4574 y(order.)i(Y)-7 b(ou)19 b(can)f(force)g(the)h+(use)g(of)f(another)g(program)f(b)n(y)h(setting)h(the)g+Fr(DIFF)e Fx(en)n(vironmen)n(t)291 4674 y(v)-5 b(ariable)26+b(b)r(efore)h(running)h Fr(configure)p Fx(.)415 4799+y(T)-7 b(o)38 b(rebuild)h(the)g(do)r(cumen)n(tation)f(\(whic)n(h)h+(should)g(not)f(b)r(e)i(necessary)c(since)j(it)g(is)291+4899 y(included)29 b(in)h(h)n(tml)f(form)g(with)h(the)g(tarballs\),)f+(y)n(ou)f(will)i(need)f(to)g(ha)n(v)n(e)f(latex)h(installed,)291+4998 y(as)e(w)n(ell)g(as)g(latex2h)n(tml)g(if)h(y)n(ou)f(w)n(an)n(t)g+(to)g(build)h(it)g(in)g(h)n(tml)g(form.)1681 5208 y(15)p+eop end+%%Page: 16 16+TeXDict begin 16 15 bop 739 282 a Fx(16)1465 b Fu(CHAPTER)27+b(2.)64 b(BUILDING)29 b(D)n(AR)n(CS)739 515 y Fq(2.2)135+b(Building)45 b(on)g(Mac)g(OS)f(X)739 705 y Fx(T)-7 b(o)30+b(build)i(on)e(Mac)h(OS)f(X,)i(y)n(ou)e(will)h(need)g(the)g(Apple)g+(Dev)n(elop)r(er)g(T)-7 b(o)r(ols)30 b(and)g(the)i(ghc)739+805 y(6.4)27 b(pac)n(k)-5 b(age)26 b(installed.)739 1102+y Fq(2.3)135 b(Building)45 b(on)g(Microsoft)g(Windo)l(ws)739+1292 y Fx(T)-7 b(o)27 b(build)h(on)g(Microsoft)e(Windo)n(ws,)i(y)n(ou)e+(will)i(need:)863 1491 y Fn(\017)41 b Fx(MinGW)29 b(whic)n(h)e(pro)n+(vides)g(the)h(GCC)f(to)r(olc)n(hain)g(for)g(win32.)863+1675 y Fn(\017)41 b Fx(MSYS)d(whic)n(h)e(pro)n(vides)f(a)h(unix)h+(build)f(en)n(vironmen)n(t)g(for)g(win32.)62 b(Be)37+b(sure)e(to)946 1774 y(do)n(wnload)27 b(the)h(separate)e(msysDTK,)h+(auto)r(conf)g(and)h(automak)n(e.)863 1957 y Fn(\017)41+b Fx(zlib-1.2.1+)26 b(library)g(and)i(headers.)863 2141+y Fn(\017)41 b Fx(curl-7.12.2+)25 b(library)h(and)i(headers.)863+2324 y Fn(\017)41 b Fx(If)26 b(building)g(with)f(an)g(SSL)h(enabled)f+(curl)f(y)n(ou)h(will)g(need)h(the)f(Op)r(enSSL)h(libraries,)946+2423 y(uno\016cial)i(builds)g(are)e(a)n(v)-5 b(ailable)26+b(at)946 2523 y(h)n(ttp://www.slpro)n(w)n(eb.com/pro)r(ducts/Win32Op)r+(enSSL.h)n(tml.)863 2723 y(Cop)n(y)20 b(the)h(zlib)f(and)h(curl)f+(libraries)f(and)h(headers)f(to)i(b)r(oth)f(GHC)h(and)f(MinGW.)i(GHC)+739 2822 y(stores)17 b(C)h(headers)g(in)g Fr(<ghc-dir>/gcc-lib)o(/i)o+(ncl)o(ud)o(e)12 b Fx(and)19 b(libraries)e(in)h Fr(<ghc-dir>/gcc-lib)o+Fx(.)739 2922 y(MinGW)h(stores)e(headers)h(in)g Fr(<mingw-dir>/inclu)o+(de)12 b Fx(and)18 b(libraries)f(in)i Fr(<mingw-dir>/lib)o+Fx(.)863 3026 y(Set)26 b(P)-7 b(A)g(TH)26 b(to)g(include)g(the)g+Fr(<msys-dir>/bin)p Fx(,)20 b Fr(<mingw-dir>/bin)p Fx(,)g+Fr(<curl-dir>)p Fx(,)739 3125 y(and)32 b(a)h(directory)e(con)n(taining)+h(a)g(pre-built)g(darcs.exe)g(if)h(y)n(ou)f(w)n(an)n(t)f(the)j(build's)+f(patc)n(h)739 3225 y(con)n(text)27 b(stored)g(for)g(`)p+Fr(darcs)41 b(--exact-version)p Fx('.)739 3429 y Fr(C:\\darcs>)f(cd)j+(<darcs-source-d)o(ir)o(>)739 3529 y(C:\\darcs>)d(sh)739+3728 y($)j(export)e(GHC=/c/<ghc-dir>/)o(bi)o(n/)o(ghc)o(.e)o(xe)739+3828 y($)i(autoconf)739 3927 y($)g(./configure)c(--target=mingw)739+4027 y($)k(make)739 4324 y Fq(2.4)135 b(Building)45 b(from)g(tarball)+739 4514 y Fx(If)23 b(y)n(ou)f(get)g(darcs)f(from)i(a)f(tarball,)h(the)+g(pro)r(cedure)e(\(after)i(unpac)n(king)e(the)i(tarball)f(itself)6+b(\))739 4614 y(is)27 b(as)g(follo)n(ws:)p 739 4684 1146+4 v 831 4737 a Fp(0)866 4761 y Fo(http://www.mingw.org/)831+4817 y Fp(0)866 4840 y Fo(http://www.mingw.org/msy)q(s.s)q(html)831+4896 y Fp(0)866 4919 y Fo(http://www.gzip.org/zlib)q(/)831+4975 y Fp(0)866 4998 y Fo(http://curl.haxx.se/)p eop+end+%%Page: 17 17+TeXDict begin 17 16 bop 291 282 a Fu(2.5.)63 b(BUILDING)29+b(D)n(AR)n(CS)f(FR)n(OM)f(THE)g(REPOSITOR)-7 b(Y)776+b Fx(17)291 515 y Fr(\045)43 b(./configure)291 615 y(\045)g(make)291+715 y(#)g(Optional,)d(but)i(recommended)291 814 y(\045)h(make)f(test)+291 914 y(\045)h(make)f(install)415 1105 y Fx(There)27+b(are)g(options)g(to)g(con\014gure)g(that)h(y)n(ou)e(ma)n(y)h(w)n(an)n+(t)g(to)h(c)n(hec)n(k)e(out)i(with)291 1304 y Fr(\045)43+b(./configure)c(--help)415 1495 y Fx(If)32 b(y)n(our)e(header)h+(\014les)g(are)f(installed)h(in)h(a)f(non-standard)f(lo)r(cation,)i(y)n+(ou)e(ma)n(y)h(need)291 1594 y(to)f(de\014ne)h(the)g+Fr(CFLAGS)e Fx(and)h Fr(CPPFLAGS)e Fx(en)n(vironmen)n(t)h(v)-5+b(ariables)30 b(to)h(include)g(the)g(path)291 1694 y(to)c(the)h+(headers.)36 b(e.g.)g(on)28 b(NetBSD,)g(y)n(ou)f(ma)n(y)g(need)h(to)f+(run)291 1893 y Fr(\045)43 b(CFLAGS=-I/usr/pk)o(g/)o(in)o(clu)o(de)37+b(CPPFLAGS=-I/usr/)o(pkg)o(/i)o(nc)o(lud)o(e)g(./configure)291+2212 y Fq(2.5)135 b(Building)45 b(darcs)g(from)g(the)g(rep)t(ository)+291 2409 y Fx(T)-7 b(o)26 b(build)i(the)g(latest)f(darcs)f(from)h(its)g+(rep)r(ository)-7 b(,)26 b(y)n(ou)g(will)h(\014rst)g(need)h(a)e(w)n+(orking)g(cop)n(y)291 2508 y(of)h(Darcs)g(2.)36 b(Y)-7+b(ou)28 b(can)f(get)h(darcs)e(using:)291 2708 y Fr(\045)43+b(darcs)e(get)i(-v)f(http://darcs.net/)291 2898 y Fx(and)27+b(once)g(y)n(ou)g(ha)n(v)n(e)f(the)i(darcs)f(rep)r(ository)f(y)n(ou)h+(can)g(bring)g(it)h(up)g(to)f(date)h(with)g(a)291 3098+y Fr(\045)43 b(darcs)e(pull)415 3288 y Fx(The)25 b(rep)r(ository)d(do)r+(esn't)j(hold)f(automatically)g(generated)f(\014les,)i(whic)n(h)g+(include)g(the)291 3388 y(con\014gure)30 b(script)i(and)g(the)g(HTML)h+(do)r(cumen)n(tation,)g(so)e(y)n(ou)g(need)h(to)g(run)g+Fr(autoconf)291 3488 y Fx(\014rst.)415 3596 y(Y)-7 b(ou'll)37+b(need)g Fr(autoconf)d Fx(2.50)h(or)h(higher.)64 b(Some)36+b(systems)h(ha)n(v)n(e)e(more)h(than)h(one)291 3695 y(v)n(ersion)e(of)j+Fr(autoconf)c Fx(installed.)66 b(F)-7 b(or)37 b(example,)j+Fr(autoconf)34 b Fx(ma)n(y)j(p)r(oin)n(t)g(to)g(v)n(ersion)291+3795 y(2.13,)26 b(while)i Fr(autoconf259)23 b Fx(runs)k(v)n(ersion)f+(2.59.)415 3903 y(Also)k(note)g(that)h Fr(make)e Fx(is)h(really)g("GNU)+g(mak)n(e".)44 b(On)30 b(some)g(systems,)h(suc)n(h)f(as)g(the)291+4002 y(*BSDs,)d(y)n(ou)g(ma)n(y)g(need)g(to)h(t)n(yp)r(e)g+Fr(gmake)d Fx(instead)j(of)f(mak)n(e)g(for)g(this)h(to)f(w)n(ork.)415+4110 y(If)k(y)n(ou)f(w)n(an)n(t)g(to)h(create)e(readable)h(do)r(cumen)n+(tation)g(y)n(ou'll)g(need)h(to)f(ha)n(v)n(e)g(latex)g(in-)291+4210 y(stalled.)291 4409 y Fr(\045)43 b(autoconf)291+4509 y(\045)g(./configure)291 4608 y(\045)g(make)291+4708 y(\045)g(make)f(install)415 4899 y Fx(If)27 b(y)n(ou)g(w)n(an)n(t)+f(to)h(t)n(w)n(eak)f(the)h(con\014gure)f(options,)g(y)n(ou'll)h(need)g+(to)g(run)f Fr(./configure)291 4998 y Fx(y)n(ourself)g(after)h(the)h+(mak)n(e,)f(and)h(then)g(run)f(mak)n(e)g(again.)p eop+end+%%Page: 18 18+TeXDict begin 18 17 bop 739 282 a Fx(18)1465 b Fu(CHAPTER)27+b(2.)64 b(BUILDING)29 b(D)n(AR)n(CS)739 515 y Fq(2.6)135+b(Building)45 b(darcs)g(with)g(git)739 697 y Fx(T)-7+b(o)37 b(enable)g(git)g(supp)r(ort,)j(y)n(ou)d(\014rst)g(need)h(to)f+(grab)f(a)h(cop)n(y)g(of)g(the)h(git)f(source)f(co)r(de;)739+797 y(since)28 b(darcs)g(do)r(esn't)g(y)n(et)g(ha)n(v)n(e)g(the)h+(capabilit)n(y)e(of)i(accessing)e(remote)g(git)i(rep)r(ositories,)739+896 y(y)n(ou'll)23 b(ha)n(v)n(e)g(to)g(either)h(do)n(wnload)e(a)i+(tarball)e(or)h(use)h(git)g(itself)g(to)f(clone)h(a)f(git)h(rep)r+(ository)-7 b(.)739 996 y(Compile)20 b(git)g(\(no)g(need)h(to)f+(install\);)j(this)d(will)g(create)g(a)f(\014le)i(\\)p+Fr(libgit.a)p Fx(".)30 b(Then)20 b(create)g(a)739 1096+y(symlink)25 b(to)g(the)g(git)g(source)f(directory)g(named)h(\\)p+Fr(git)p Fx(")e(in)i(y)n(our)f(darcs)g(source)f(directory)-7+b(,)739 1195 y(con\014gure)26 b(darcs)h(using)g(the)h(\\)p+Fr(--enable-git)p Fx(")22 b(option,)27 b(and)g(build)i(darcs)d(as)h+(usual.)739 1470 y Fq(2.7)135 b(Submitting)46 b(patc)l(hes)f(to)g+(darcs)739 1652 y Fx(I)26 b(kno)n(w,)g(this)h(do)r(esn't)g(really)e(b)r+(elong)h(in)h(this)g(c)n(hapter,)f(but)h(if)g(y)n(ou're)e(using)h(the)h+(rep)r(os-)739 1751 y(itory)k(v)n(ersion)f(of)h(darcs)g(it's)h(really)e+(easy)h(to)g(submit)i(patc)n(hes)e(to)g(me)h(using)f(darcs.)48+b(In)739 1851 y(fact,)35 b(ev)n(en)e(if)g(y)n(ou)g(don't)g(kno)n(w)g+(an)n(y)f(Hask)n(ell,)i(y)n(ou)e(could)h(submit)h(\014xes)f(or)g+(additions)739 1951 y(to)e(this)h(do)r(cumen)n(t)g(\(b)n(y)f(editing)h+Fr(building_darcs.t)o(ex)o Fx(\))26 b(based)31 b(on)g(y)n(our)g(exp)r+(erience)739 2050 y(building)d(darcs.)12 b(.)i(.)863+2150 y(T)-7 b(o)24 b(do)h(so,)f(just)h(record)e(y)n(our)g(c)n(hanges)g+(\(whic)n(h)i(y)n(ou)f(made)g(in)g(the)h(darcs)f(rep)r(ository\))739+2316 y Fr(\045)43 b(darcs)f(record)f(--no-test)739 2482+y Fx(making)c(sure)f(to)i(giv)n(e)e(the)i(patc)n(h)f(a)g(nice)g+(descriptiv)n(e)g(name.)66 b(The)37 b Fr(--no-test)d+Fx(op-)739 2582 y(tions)d(k)n(eeps)f(darcs)g(from)g(trying)g(to)h(run)g+(the)g(unit)h(tests,)g(whic)n(h)e(can)h(b)r(e)g(rather)f(time-)739+2681 y(consuming.)66 b(Then)38 b(y)n(ou)e(can)h(send)h(the)g(patc)n(h)f+(to)g(the)h(darcs-dev)n(el)e(mailing)h(list)h(b)n(y)739+2781 y(email)27 b(b)n(y)739 2947 y Fr(\045)43 b(darcs)f(send)g(-u)739+3113 y Fx(The)30 b(darcs)f(rep)r(ository)f(stores)g(the)j(email)e+(address)g(to)h(whic)n(h)f(patc)n(hes)h(should)f(b)r(e)h(sen)n(t)739+3212 y(b)n(y)38 b(default.)70 b(The)38 b(email)h(address)e(y)n(ou)h+(see)g(is)g(actually)g(m)n(y)g(o)n(wn,)j(but)e(when)f(darcs)739+3312 y(notices)24 b(that)i(y)n(ou)e(ha)n(v)n(en't)g(signed)h(the)g+(patc)n(h)g(with)g(m)n(y)g(GPG)g(k)n(ey)-7 b(,)25 b(it)g(will)h(forw)n+(ard)d(the)739 3412 y(message)j(to)i(darcs-dev)n(el.)p+eop end+%%Page: 19 19+TeXDict begin 19 18 bop 291 1139 a Ft(Chapter)64 b(3)291+1555 y Fw(Getting)77 b(started)291 1988 y Fx(This)34+b(c)n(hapter)f(will)i(lead)f(y)n(ou)g(through)f(an)i(example)e(use)i+(of)f(darcs,)h(whic)n(h)f(hop)r(efully)291 2088 y(will)27+b(allo)n(w)g(y)n(ou)g(to)g(get)h(started)f(using)g(darcs)f(with)i(y)n+(our)f(pro)5 b(ject.)291 2369 y Fq(3.1)135 b(Creating)46+b(y)l(our)f(rep)t(ository)291 2553 y Fx(Creating)30 b(y)n(our)h(rep)r+(ository)f(in)i(the)h(\014rst)e(place)h(just)g(in)n(v)n(olv)n(es)e+(telling)i(darcs)f(to)h(create)291 2652 y(the)h(sp)r(ecial)g(directory)+f(\(called)p 1352 2652 27 4 v 64 w Fr(darcs)p Fx(\))f(in)j(y)n(our)e+(pro)5 b(ject)32 b(tree,)i(whic)n(h)f(will)h(hold)f(the)291+2752 y(revision)28 b(information.)41 b(This)29 b(is)g(done)g(b)n(y)g+(simply)g(calling)f(from)h(the)h(ro)r(ot)e(directory)g(of)291+2851 y(y)n(our)e(pro)5 b(ject:)291 3022 y Fr(\045)43+b(cd)g(my_project/)291 3122 y(\045)g(darcs)e(initialize)291+3291 y Fx(This)f(creates)g(the)h Fr(_darcs)e Fx(directory)h(and)g(p)r+(opulates)h(it)g(with)h(whatev)n(er)d(\014les)i(and)291+3391 y(directories)23 b(are)h(needed)h(to)g(describ)r(e)g(an)f(empt)n+(y)h(pro)5 b(ject.)36 b(Y)-7 b(ou)25 b(no)n(w)f(need)h(to)g(tell)g+(darcs)291 3490 y(what)h(\014les)g(and)f(directories)g(in)h(y)n(our)f+(pro)5 b(ject)26 b(should)g(b)r(e)g(under)g(revision)f(con)n(trol.)35+b(Y)-7 b(ou)291 3590 y(do)27 b(this)h(using)f(the)h(command)f+Fr(darcs)42 b(add)1700 3560 y Fm(1)1736 3590 y Fx(:)291+3761 y Fr(\045)h(darcs)e(add)i(*.c)f(Makefile.am)d(configure.ac)291+3930 y Fx(When)27 b(y)n(ou)g(ha)n(v)n(e)f(added)h(all)g(y)n(our)f+(\014les)h(\(or)f(at)h(least,)g(think)h(y)n(ou)e(ha)n(v)n(e\),)h(y)n+(ou)f(will)i(w)n(an)n(t)291 4030 y(to)i(record)f(y)n(our)h(c)n(hanges.)+44 b(\\Recording")29 b(alw)n(a)n(ys)f(includes)j(adding)f(a)g(note)h+(as)f(to)g(wh)n(y)291 4130 y(the)f(c)n(hange)f(w)n(as)g(made,)i(or)e+(what)h(it)h(do)r(es.)41 b(In)29 b(this)h(case,)e(w)n(e'll)h(just)h+(note)f(that)h(this)f(is)291 4229 y(the)f(initial)f(v)n(ersion.)291+4400 y Fr(\045)43 b(darcs)e(record)g(--all)291 4499 y(What)h(is)g(the)h+(patch)e(name?)h(Initial)e(revision.)291 4669 y Fx(Note)30+b(that)h(since)f(w)n(e)g(didn't)i(sp)r(ecify)e(a)g(patc)n(h)h(name)f+(on)g(the)h(command)f(line)h(w)n(e)f(w)n(ere)291 4769+y(prompted)e(for)h(one.)40 b(If)29 b(the)h(en)n(vironmen)n(t)e(v)-5+b(ariable)27 b(`EMAIL')i(isn't)g(set,)h(y)n(ou)e(will)h(also)p+291 4842 1146 4 v 383 4896 a Fp(1)418 4920 y Fl(Note)e(that)h(darcs)e+(do)r(es)h(not)h(do)e(wildcard)h(expansion,)h(instead)f(relying)f(on)h+(the)g(command)h(shell.)291 4998 y(The)c(Windo)n(ws)g(p)r(ort)g(of)f+(darcs)h(has)g(a)f(limited)h(form)e(of)i(expansion)g(pro)n(vided)h(b)n+(y)f(the)g(C)g(run)n(time)1681 5208 y Fx(19)p eop end+%%Page: 20 20+TeXDict begin 20 19 bop 739 282 a Fx(20)1383 b Fu(CHAPTER)27+b(3.)64 b(GETTING)28 b(ST)-7 b(AR)g(TED)739 515 y Fx(b)r(e)37+b(prompted)f(for)f(y)n(our)g(email)h(address.)62 b(Eac)n(h)35+b(patc)n(h)h(that)g(is)g(recorded)f(is)h(giv)n(en)g(a)739+615 y(unique)30 b(iden)n(ti\014er)f(consisting)g(of)h(the)g(patc)n(h)f+(name,)h(its)g(creator's)e(email)h(address,)g(and)739+715 y(the)f(date)f(when)h(it)g(w)n(as)f(created.)739+985 y Fq(3.2)135 b(Making)45 b(c)l(hanges)739 1167 y+Fx(No)n(w)24 b(that)h(w)n(e)f(ha)n(v)n(e)f(created)h(our)g(rep)r+(ository)-7 b(,)23 b(mak)n(e)h(a)g(c)n(hange)f(to)i(one)f(or)f(more)h+(of)g(y)n(our)739 1267 y(\014les.)37 b(After)28 b(making)f(the)h(mo)r+(di\014cation)f(run:)739 1415 y Fr(\045)43 b(darcs)f(whatsnew)739+1563 y Fx(This)27 b(should)g(sho)n(w)f(y)n(ou)g(the)h(mo)r+(di\014cations)g(that)g(y)n(ou)f(just)i(made,)f(in)g(the)h(darcs)e+(patc)n(h)739 1662 y(format.)34 b(If)20 b(y)n(ou)f(prefer)g(to)g(see)h+(y)n(our)e(c)n(hanges)g(in)i(a)f(di\013eren)n(t)h(format,)h(read)e+(Section)g(6.7.1,)739 1762 y(whic)n(h)27 b(describ)r(es)g(the)h+(whatsnew)g(command)f(in)h(detail.)863 1862 y(Let's)j(sa)n(y)f(y)n(ou)g+(ha)n(v)n(e)f(no)n(w)h(made)h(a)f(c)n(hange)g(to)h(y)n(our)e(pro)5+b(ject.)46 b(The)30 b(next)h(thing)g(to)739 1961 y(do)24+b(is)g(to)g(record)e(a)i(patc)n(h.)35 b(Recording)23+b(a)h(patc)n(h)g(consists)f(of)h(grouping)e(together)i(a)f(set)h(of)739+2061 y(related)k(c)n(hanges,)g(and)h(giving)f(them)h(a)g(name.)41+b(It)29 b(also)f(tags)g(the)h(patc)n(h)g(with)g(the)g(date)739+2161 y(it)f(w)n(as)f(recorded)f(and)h(y)n(our)f(email)i(address.)863+2260 y(T)-7 b(o)28 b(record)e(a)h(patc)n(h)g(simply)h(t)n(yp)r(e:)739+2408 y Fr(\045)43 b(darcs)f(record)739 2556 y Fx(darcs)26+b(will)i(then)g(prompt)g(y)n(ou)f(with)h(all)f(the)h(c)n(hanges)f(that)+h(y)n(ou)f(ha)n(v)n(e)f(made)h(that)h(ha)n(v)n(e)739+2656 y(not)j(y)n(et)h(b)r(een)g(recorded,)f(asking)f(y)n(ou)h(whic)n(h)+h(ones)e(y)n(ou)h(w)n(an)n(t)g(to)h(include)f(in)h(the)g(new)739+2755 y(patc)n(h.)k(Finally)-7 b(,)28 b(darcs)f(will)g(ask)g(y)n(ou)g+(for)g(a)g(name)h(for)f(the)h(patc)n(h.)863 2855 y(Y)-7+b(ou)37 b(can)f(no)n(w)f(rerun)h(whatsnew,)i(and)e(see)g(that)h(indeed)+f(the)h(c)n(hanges)e(y)n(ou)g(ha)n(v)n(e)739 2955 y(recorded)26+b(are)h(no)g(longer)f(mark)n(ed)h(as)g(new.)739 3225+y Fq(3.3)135 b(Making)45 b(y)l(our)g(rep)t(ository)h(visible)g(to)f+(others)739 3407 y Fx(Ho)n(w)37 b(do)g(y)n(ou)g(let)g(the)h(w)n(orld)e+(kno)n(w)h(ab)r(out)g(these)h(w)n(onderful)e(c)n(hanges?)65+b(Ob)n(viously)-7 b(,)739 3507 y(they)24 b(m)n(ust)h(b)r(e)f(able)g(to)+g(see)g(y)n(our)f(rep)r(ository)-7 b(.)34 b(Curren)n(tly)24+b(the)g(easiest)g(w)n(a)n(y)f(to)h(do)g(this)g(is)739+3607 y(t)n(ypically)f(b)n(y)g(h)n(ttp)g(using)g(an)n(y)g(w)n(eb)g(serv)+n(er.)34 b(The)23 b(recommended)g(w)n(a)n(y)f(to)h(do)g(this)g(\(using)+739 3706 y(apac)n(he)f(in)h(a)f(UNIX)i(en)n(vironmen)n(t\))e(is)h(to)g+(create)f(a)h(directory)e(called)i Fr(/var/www/repos)p+Fx(,)739 3806 y(and)k(then)h(put)h(a)e(symlink)g(to)h(y)n(our)e(rep)r+(ository)g(there:)739 3954 y Fr(\045)43 b(cd)g(/var/www/repos)739+4053 y(\045)g(ln)g(-s)g(/home/username/)o(myp)o(ro)o(je)o(ct)37+b(.)863 4201 y Fx(As)d(long)e(as)h(y)n(ou're)f(running)h(a)g(w)n(eb)g+(serv)n(er)e(and)i(making)g(y)n(our)f(rep)r(ository)f(a)n(v)-5+b(ail-)739 4301 y(able)27 b(to)g(the)g(w)n(orld,)g(y)n(ou)f(ma)n(y)g+(as)h(w)n(ell)g(mak)n(e)f(it)i(easy)e(for)h(p)r(eople)g(to)g(see)g+(what)g(c)n(hanges)739 4401 y(y)n(ou'v)n(e)f(made.)37+b(Y)-7 b(ou)28 b(can)f(do)g(this)h(b)n(y)f(running)h+Fr(make)42 b(installserver)p Fx(,)22 b(whic)n(h)28 b(installs)739+4500 y(the)36 b(program)d Fr(darcs_cgi)f Fx(at)j Fr(/usr/lib/cgi-bin/)o+(dar)o(cs)o Fx(.)55 b(Y)-7 b(ou)36 b(also)e(will)i(need)f(to)739+4600 y(create)k(a)g(cac)n(he)g(directory)g(named)h Fr(/var/cache/darcs)+o(_c)o(gi)p Fx(,)d(and)i(mak)n(e)h(sure)f(the)739 4700+y(o)n(wner)i(of)h(that)g(directory)f(is)h(the)g(same)g(user)f(that)i(y)+n(our)e(w)n(eb)g(serv)n(er)g(runs)g(its)i(cgi)739 4799+y(scripts)35 b(as.)60 b(F)-7 b(or)35 b(me,)j(this)e(is)f(www-data.)60+b(No)n(w)36 b(y)n(our)e(friends)i(and)f(enemies)g(should)739+4899 y(b)r(e)j(able)e(to)i(easily)e(bro)n(wse)g(y)n(our)g(rep)r+(ositories)f(b)n(y)i(p)r(oin)n(ting)g(their)g(w)n(eb)g(bro)n(wsers)e+(at)739 4998 y Fr(http://your.serv)o(er)o(.or)o(g/)o(cgi)o(-b)o(in)o+(/da)o(rc)o(s)p Fx(.)p eop end+%%Page: 21 21+TeXDict begin 21 20 bop 291 282 a Fu(3.4.)63 b(GETTING)28+b(CHANGES)g(MADE)g(TO)f(ANOTHER)h(REPOSITOR)-7 b(Y)267+b Fx(21)291 515 y Fq(3.4)135 b(Getting)35 b(c)l(hanges)h(made)f(to)g+(another)g(rep)t(ository)291 697 y Fx(Ok,)h(so)f(I)g(can)f(no)n(w)h+(bro)n(wse)f(y)n(our)f(rep)r(ository)h(using)h(m)n(y)g(w)n(eb)f(bro)n+(wser.)12 b(.)i(.)49 b(so)35 b(what?)291 797 y(Ho)n(w)29+b(do)g(I)h(get)f(y)n(our)g(c)n(hanges)f(in)n(to)h Fs(my)38+b Fx(rep)r(ository)-7 b(,)29 b(where)g(they)h(can)f(do)g(some)g(go)r(o)+r(d?)291 896 y(It)f(couldn't)f(b)r(e)h(easier.)36 b(I)28+b(just)g Fr(cd)f Fx(in)n(to)g(m)n(y)g(rep)r(ository)-7+b(,)27 b(and)g(there)g(t)n(yp)r(e:)291 1056 y Fr(\045)43+b(darcs)e(pull)h(http://your.serve)o(r.)o(org)o(/r)o(ep)o(os/)o(yo)o+(urp)o(ro)o(je)o(ct)291 1215 y Fx(Darcs)c(will)h(c)n(hec)n(k)f(to)h+(see)g(if)g(y)n(ou)g(ha)n(v)n(e)e(recorded)h(an)n(y)g(c)n(hanges)g+(that)h(aren't)g(in)g(m)n(y)291 1315 y(curren)n(t)25+b(rep)r(ository)-7 b(.)35 b(If)28 b(so,)e(it'll)h(prompt)g(me)g(for)f+(eac)n(h)g(one,)g(to)h(see)f(whic)n(h)h(ones)f(I)h(w)n(an)n(t)291+1414 y(to)32 b(add)g(to)g(m)n(y)h(rep)r(ository)-7 b(.)49+b(Note)33 b(that)g(y)n(ou)e(ma)n(y)h(see)g(a)g(di\013eren)n(t)h(series)+e(of)h(prompts)291 1514 y(dep)r(ending)c(on)g(y)n(our)f(answ)n(ers,)f+(since)i(sometimes)g(one)f(patc)n(h)h(dep)r(ends)h(on)e(another,)h(so)+291 1613 y(if)h(y)n(ou)f(answ)n(er)f(y)n(es)h(to)h(the)g(\014rst)g+(one,)g(y)n(ou)f(w)n(on't)g(b)r(e)i(prompted)e(for)h(the)g(second)f(if)+i(the)291 1713 y(\014rst)d(dep)r(ends)h(on)f(it.)415+1813 y(Of)i(course,)g(ma)n(yb)r(e)g(I)g(don't)h(ev)n(en)f(ha)n(v)n(e)f+(a)h(cop)n(y)f(of)h(y)n(our)f(rep)r(ository)-7 b(.)41+b(In)29 b(that)h(case)291 1912 y(I'd)d(w)n(an)n(t)g(to)h(do)f(a)291+2072 y Fr(\045)43 b(darcs)e(get)i(http://your.ser)o(ver)o(.o)o(rg/)o+(re)o(po)o(s/y)o(ou)o(rpr)o(oj)o(ec)o(t)291 2231 y Fx(whic)n(h)27+b(gets)g(the)h(whole)f(rep)r(ository)-7 b(.)415 2331+y(I)24 b(could)f(instead)g(create)f(an)h(empt)n(y)h(rep)r(ository)d+(and)j(fetc)n(h)f(all)g(of)h(y)n(our)e(patc)n(hes)g(with)291+2430 y(pull.)37 b(Get)28 b(is)f(just)i(a)e(more)g(e\016cien)n(t)g(w)n+(a)n(y)g(to)g(clone)g(a)g(whole)h(rep)r(ository)-7 b(.)415+2530 y(Get,)43 b(pull)c(and)g(push)h(also)e(w)n(ork)g(o)n(v)n(er)f+(ssh.)72 b(Ssh-paths)39 b(are)f(of)h(the)h(same)e(form)291+2629 y(accepted)27 b(b)n(y)g(scp,)h(namely)f Fr([username@]host:)o(/pa)+o(th)o(/t)o(o/r)o(ep)o(osi)o(to)o(ry)o Fx(.)291 2903+y Fq(3.5)135 b(Mo)l(ving)50 b(patc)l(hes)g(from)g(one)g(rep)t(ository)h+(to)f(an-)597 3052 y(other)291 3234 y Fx(Darcs)32 b(is)h(\015exible)h+(as)e(to)h(ho)n(w)g(y)n(ou)f(mo)n(v)n(e)h(patc)n(hes)f(from)h(one)g+(rep)r(ository)f(to)h(another.)291 3333 y(This)c(section)h(will)g(in)n+(tro)r(duce)g(all)f(the)i(w)n(a)n(ys)d(y)n(ou)h(can)h(get)f(patc)n(hes)+g(from)h(one)g(place)f(to)291 3433 y(another,)d(starting)h(with)h(the)g+(simplest)g(and)f(mo)n(ving)g(to)g(the)h(most)g(complicated.)291+3664 y Fk(3.5.1)112 b(All)37 b(pulls)291 3817 y Fx(The)43+b(simplest)h(metho)r(d)f(is)h(the)f(\\all-pull")g(metho)r(d.)84+b(This)44 b(in)n(v)n(olv)n(es)d(making)i(eac)n(h)291+3917 y(rep)r(ository)35 b(readable)h(\(b)n(y)h(h)n(ttp,)k(ftp,)f+(nfs-moun)n(ted)d(disk,)j(whatev)n(er\),)f(and)e(y)n(ou)f(run)291+4017 y Fr(darcs)41 b(pull)24 b Fx(in)h(the)g(rep)r(ository)e(y)n(ou)i+(w)n(an)n(t)f(to)h(mo)n(v)n(e)f(the)h(patc)n(h)g(to.)36+b(This)25 b(is)g(nice,)g(as)f(it)291 4116 y(do)r(esn't)e(require)g(y)n+(ou)g(to)g(giv)n(e)g(write)g(access)f(to)i(an)n(y)n(one)e(else,)i(and)g+(is)f(reasonably)f(simple.)291 4347 y Fk(3.5.2)112 b(Send)38+b(and)h(apply)f(man)m(ually)291 4500 y Fx(Sometimes)32+b(y)n(ou)f(ha)n(v)n(e)g(a)h(mac)n(hine)f(on)h(whic)n(h)g(it)h(is)f(not)+g(con)n(v)n(enien)n(t)f(to)h(set)g(up)g(a)g(w)n(eb)291+4600 y(serv)n(er,)23 b(p)r(erhaps)i(b)r(ecause)g(it's)g(b)r(ehind)h(a)f+(\014rew)n(all)f(or)g(p)r(erhaps)g(for)h(securit)n(y)f(reasons,)g(or)+291 4700 y(b)r(ecause)30 b(it)i(is)f(often)g(turned)h(o\013.)47+b(In)32 b(this)f(case)f(y)n(ou)h(can)g(use)g Fr(darcs)41+b(send)30 b Fx(from)h(that)291 4799 y(computer)d(to)h(generate)f(a)g+(patc)n(h)h(bundle)h(destined)f(for)g(another)f(rep)r(ository)-7+b(.)39 b(Y)-7 b(ou)29 b(can)291 4899 y(either)j(let)h(darcs)e(email)h+(the)h(patc)n(h)f(for)g(y)n(ou,)h(or)f(sa)n(v)n(e)f(it)i(as)f(a)g+(\014le)g(and)h(transfer)e(it)i(b)n(y)291 4998 y(hand.)j(Then)28+b(in)f(the)h(destination)f(rep)r(ository)f(y)n(ou)h(\(or)f(the)i(o)n+(wner)e(of)i(that)f(rep)r(ository\))p eop end+%%Page: 22 22+TeXDict begin 22 21 bop 739 282 a Fx(22)1383 b Fu(CHAPTER)27+b(3.)64 b(GETTING)28 b(ST)-7 b(AR)g(TED)739 515 y Fx(run)35+b Fr(darcs)41 b(apply)33 b Fx(to)i(apply)f(the)i(patc)n(hes)e(con)n+(tained)g(in)h(the)g(bundle.)60 b(This)35 b(is)f(also)739+615 y(quite)h(a)g(simple)g(metho)r(d)g(since,)i(lik)n(e)e(the)g+(all-pull)g(metho)r(d,)i(it)f(do)r(esn't)f(require)f(that)739+715 y(y)n(ou)28 b(giv)n(e)h(an)n(y)n(one)f(write)h(access)f(to)h(y)n+(our)f(rep)r(ository)-7 b(.)41 b(But)29 b(it's)h(less)f(con)n(v)n+(enien)n(t,)f(since)739 814 y(y)n(ou)f(ha)n(v)n(e)f(to)i(k)n(eep)f+(trac)n(k)f(of)i(the)g(patc)n(h)f(bundle)h(\(in)g(the)g(email,)g(or)e+(whatev)n(er\).)863 914 y(If)32 b(y)n(ou)e(use)h(the)h(send)f(and)g+(apply)g(metho)r(d)h(with)f(email,)h(y)n(ou'll)f(probably)f(w)n(an)n(t)+g(to)739 1013 y(create)39 b(a)g Fr(_darcs/prefs/em)o(ail)33+b Fx(\014le)39 b(con)n(taining)g(y)n(our)f(email)i(address.)71+b(This)39 b(w)n(a)n(y)739 1113 y(an)n(y)n(one)28 b(who)h(sends)f(to)i+(y)n(our)e(rep)r(ository)f(will)j(automatically)e(send)h(the)h(patc)n+(h)f(bundle)739 1213 y(to)e(y)n(our)g(email)g(address.)863+1312 y(If)40 b(y)n(ou)e(receiv)n(e)g(man)n(y)g(patc)n(hes)h(b)n(y)f+(email,)k(y)n(ou)c(probably)g(will)h(b)r(ene\014t)h(b)n(y)f(run-)739+1412 y(ning)32 b(darcs)e(apply)i(directly)g(from)f(y)n(our)g(mail)h+(program.)47 b(I)32 b(ha)n(v)n(e)f(in)h(m)n(y)g Fr(.muttrc)d+Fx(the)739 1512 y(follo)n(wing:)739 1653 y Fr(auto_view)40+b(text/x-patch)e(text/x-darcs-patc)o(h)739 1753 y(macro)j(pager)h(A)h+("<pipe-entry>dar)o(cs)37 b(apply)42 b(--verbose)e(--mark-conflict)o(s)+e(\\)1088 1853 y(--reply)i(droundy@abridgega)o(me)o(.or)o(g)d+(--repodir)j(~/darcs")739 1995 y Fx(whic)n(h)30 b(allo)n(ws)f(me)h(to)g+(view)h(a)e(sen)n(t)h(patc)n(h,)h(and)f(then)h(apply)f(the)h(patc)n(h)f+(directly)g(from)739 2094 y Fr(mutt)p Fx(,)e(sending)h(a)g+(con\014rmation)f(email)h(to)g(the)g(p)r(erson)g(who)g(sen)n(t)g(me)g+(the)h(patc)n(h.)41 b(The)739 2194 y(auto)n(view)36 b(line)i(relies)f+(on)g(on)h(the)g(follo)n(wing)e(lines,)k(or)d(something)g(lik)n(e)g+(them,)k(b)r(eing)739 2293 y(presen)n(t)27 b(in)h(one's)f+Fr(.mailcap)p Fx(:)739 2435 y Fr(text/x-patch;)1171 b(cat;)42+b(copiousoutput)739 2535 y(text/x-darcs-pat)o(ch)o(;)909+b(cat;)42 b(copiousoutput)739 2762 y Fk(3.5.3)112 b(Push)739+2915 y Fx(If)23 b(y)n(ou)f(use)h(ssh)f(\(and)h(preferably)f(also)g+(ssh-agen)n(t,)g(so)g(y)n(ou)g(w)n(on't)h(ha)n(v)n(e)e(to)i(k)n(eep)f+(ret)n(yping)739 3015 y(y)n(our)33 b(passw)n(ord\),)i(y)n(ou)e(can)h+(use)g(the)h(push)g(metho)r(d)g(to)f(transfer)g(c)n(hanges)f(\(using)h+(the)739 3115 y(scp)d(proto)r(col)f(for)g(comm)n(unication\).)47+b(This)31 b(metho)r(d)h(is)f(again)f(not)h(v)n(ery)f(complicated,)739+3214 y(since)i(y)n(ou)f(presumably)g(already)g(ha)n(v)n(e)g(the)h(ssh)g+(p)r(ermissions)f(set)h(up.)51 b(Push)32 b(can)f(also)739+3314 y(b)r(e)d(used)g(when)h(the)f(target)f(rep)r(ository)g(is)h(lo)r+(cal,)f(in)i(whic)n(h)f(case)f(ssh)h(isn't)g(needed.)38+b(On)739 3413 y(the)33 b(other)f(hand,)i(in)f(this)f(situation)h(y)n+(ou)f(could)g(as)g(easily)g(run)g(a)g(pull,)j(so)c(there)i(isn't)739+3513 y(m)n(uc)n(h)27 b(b)r(ene\014t.)863 3613 y(Note)33+b(that)g(y)n(ou)e(can)i(use)f(push)h(to)f(administer)g(a)g(m)n+(ultiple-user)g(rep)r(ository)-7 b(.)50 b(Y)-7 b(ou)739+3712 y(just)26 b(need)g(to)f(create)g(a)g(user)g(for)g(the)h(rep)r+(ository)e(\(or)h(rep)r(ositories\),)g(and)h(giv)n(e)e(ev)n(ery)n(one)+739 3812 y(with)h(write)f(access)f(ssh)h(access,)f(p)r(erhaps)h(using)g+Fr(.ssh/authorized_)o(key)o(s)p Fx(.)30 b(Then)24 b(they)739+3912 y(run)739 4053 y Fr(\045)43 b(darcs)f(push)g(repouser@repo.s)o(er)+o(ver)o(:r)o(epo)o(/d)o(ire)o(ct)o(or)o(y)739 4281 y+Fk(3.5.4)112 b(Push)38 b(|apply-as)739 4434 y Fx(No)n(w)30+b(w)n(e)f(get)h(more)g(subtle.)45 b(If)31 b(y)n(ou)e(lik)n(e)h(the)g+(idea)g(in)h(the)f(previous)g(paragraph)d(ab)r(out)739+4534 y(creating)d(a)i(rep)r(ository)e(user)h(to)g(o)n(wn)g(a)h(rep)r+(ository)e(whic)n(h)h(is)h(writable)f(b)n(y)h(a)f(n)n(um)n(b)r(er)g(of)+739 4633 y(users,)i(y)n(ou)f(ha)n(v)n(e)h(one)g(other)g(option.)863+4725 y(Push)h Fr(--apply-as)d Fx(can)j(run)g(on)g(either)g(a)g(lo)r+(cal)g(rep)r(ository)f(or)h(one)g(accessed)f(with)739+4816 y(ssh,)21 b(but)f(uses)g Fr(sudo)e Fx(to)i(run)f(a)g(darcs)g+(apply)h(command)f(\(ha)n(ving)g(created)g(a)g(patc)n(h)h(bundle)739+4907 y(as)25 b(in)g(send\))h(as)f(another)f(user.)36+b(Y)-7 b(ou)25 b(can)g(add)h(the)g(follo)n(wing)e(line)i(in)f(y)n(our)f+Fr(sudoers)f Fx(\014le)739 4998 y(to)k(allo)n(w)g(the)h(users)f(to)g+(apply)g(their)h(patc)n(hes)f(to)g(a)g(cen)n(tralized)g(rep)r(ository:)+p eop end+%%Page: 23 23+TeXDict begin 23 22 bop 291 282 a Fu(3.5.)63 b(MO)n(VING)28+b(P)-7 b(A)g(TCHES)27 b(FR)n(OM)h(ONE)f(REPOSITOR)-7+b(Y)26 b(TO)h(ANOTHER)128 b Fx(23)291 515 y Fj(ALL)118+b(ALL)40 b(=)f(\(repo-user\))j(NOPASSWD:)f(/usr/bin/darcs)i(apply)d+(--all)g(--repodir)i(/repo/path*)415 708 y Fx(This)37+b(metho)r(d)g(is)g(ideal)g(for)f(a)h(cen)n(tralized)f(rep)r(ository)f+(when)i(all)g(the)g(users)f(ha)n(v)n(e)291 808 y(accoun)n(ts)26+b(on)h(the)h(same)f(computer,)g(if)i(y)n(ou)d(don't)i(w)n(an)n(t)f(y)n+(our)f(users)h(to)g(b)r(e)h(able)g(to)f(run)291 907 y(arbitrary)e+(commands)i(as)g(rep)r(o-user.)291 1187 y Fk(3.5.5)112+b(Sending)39 b(signed)f(patc)m(hes)g(b)m(y)g(email)291+1357 y Fx(Most)30 b(of)h(the)h(previous)d(metho)r(ds)j(are)e(a)g(bit)i+(clumsy)f(if)g(y)n(ou)f(don't)h(w)n(an)n(t)g(to)g(giv)n(e)f(eac)n(h)291+1457 y(p)r(erson)c(with)h(write)g(access)f(to)g(a)h(rep)r(ository)e(an)+i(accoun)n(t)f(on)g(y)n(our)g(serv)n(er.)35 b(Darcs)26+b(send)291 1556 y(can)j(b)r(e)h(con\014gured)f(to)h(send)f(a)h+(cryptographically)d(signed)i(patc)n(h)h(b)n(y)f(email.)43+b(Y)-7 b(ou)30 b(can)291 1656 y(then)f(set)h(up)f(y)n(our)f(mail)i+(system)f(to)g(ha)n(v)n(e)f(darcs)g(v)n(erify)h(that)g(patc)n(hes)g(w)n+(ere)f(signed)h(b)n(y)291 1755 y(an)36 b(authorized)f(user)h(and)g+(apply)g(them)h(when)g(a)f(patc)n(h)g(is)g(receiv)n(ed)g(b)n(y)g+(email.)63 b(The)291 1855 y(results)34 b(of)h(the)g(apply)g(can)f(b)r+(e)i(returned)e(to)h(the)g(user)f(b)n(y)h(email.)59 b(Unsigned)35+b(patc)n(hes)291 1955 y(\(or)c(patc)n(hes)h(signed)g(b)n(y)g+(unauthorized)f(users\))h(will)g(b)r(e)h(forw)n(arded)e(to)h(the)h(rep)+r(ository)291 2054 y(o)n(wner)26 b(\(or)h(who)r(ev)n(er)f(y)n(ou)h+(con\014gure)g(them)h(to)f(b)r(e)h(forw)n(arded)e(to.)14+b(.)g(.)g(\).)415 2163 y(This)35 b(metho)r(d)h(is)g(esp)r(ecially)e+(nice)i(when)f(com)n(bined)g(with)h(the)g Fr(--test)d+Fx(option)i(of)291 2263 y(darcs)30 b(apply)-7 b(,)32+b(since)g(it)g(allo)n(ws)e(y)n(ou)h(to)g(run)g(the)h(test)g(suite)g+(\(assuming)f(y)n(ou)g(ha)n(v)n(e)f(one\))291 2362 y(and)c(reject)g+(patc)n(hes)g(that)h(fail|and)f(it's)h(all)f(done)g(on)g(the)h(serv)n+(er,)e(so)g(y)n(ou)h(can)g(happily)291 2462 y(go)c(on)i(w)n(orking)e+(on)h(y)n(our)f(dev)n(elopmen)n(t)h(mac)n(hine)h(without)g(slo)n(wdo)n+(wn)e(while)i(the)g(serv)n(er)291 2561 y(runs)j(the)h(tests.)415+2670 y(Setting)c(up)f(darcs)f(to)i(run)f(automatically)f(in)h(resp)r+(onse)f(to)i(email)f(is)g(b)n(y)g(far)f(the)i(most)291+2770 y(complicated)30 b(w)n(a)n(y)f(to)h(get)g(patc)n(hes)f(from)h(one)+g(rep)r(ository)f(to)h(another.)13 b(.)h(.)44 b(so)30+b(it'll)h(tak)n(e)291 2869 y(a)c(few)h(sections)f(to)g(explain)g(ho)n+(w)g(to)h(go)e(ab)r(out)i(it.)291 3132 y Fv(Securit)m(y)46+b(considerations)83 b Fx(When)40 b(y)n(ou)f(set)h(up)g(darcs)f(to)h+(run)f(apply)h(on)f(signed)291 3232 y(patc)n(hes,)23+b(y)n(ou)f(should)h(assume)g(that)g(a)g(user)f(with)i(write)f(access)f+(can)g(write)h(to)g(an)n(y)g(\014le)g(or)291 3332 y(directory)18+b(that)i(is)g(writable)g(b)n(y)f(the)i(user)e(under)h(whic)n(h)f(the)i+(apply)e(pro)r(cess)g(runs.)34 b(Unless)291 3431 y(y)n(ou)24+b(sp)r(ecify)i(the)f Fr(--no-test)d Fx(\015ag)i(to)h(darcs)g(apply)g+(\(and)g(this)g(is)h Fs(not)33 b Fx(the)25 b(default\),)i(y)n(ou)291+3531 y(are)k(also)g(allo)n(wing)f(an)n(y)n(one)h(with)h(write)g(access)+f(to)h(that)h(rep)r(ository)d(to)i(run)g(arbitrary)291+3631 y(co)r(de)27 b(on)h(y)n(our)e(mac)n(hine)i(\(since)g(they)g(can)f+(run)h(a)f(test)h(suite|whic)n(h)g(they)g(can)f(mo)r(dify)291+3730 y(ho)n(w)n(ev)n(er)e(they)j(lik)n(e\).)37 b(This)27+b(is)h(quite)g(a)f(p)r(oten)n(tial)g(securit)n(y)g(hole.)415+3839 y(F)-7 b(or)23 b(these)h(reasons,)e(if)i(y)n(ou)f(don't)h+(implicitly)g(trust)f(y)n(our)g(users,)g(it)h(is)f(recommended)291+3938 y(that)29 b(y)n(ou)g(create)f(a)h(user)f(for)h(eac)n(h)g(rep)r+(ository)e(to)i(limit)h(the)g(damage)e(an)h(attac)n(k)n(er)e(can)291+4038 y(do)c(with)i(access)d(to)i(y)n(our)f(rep)r(ository)-7+b(.)34 b(When)24 b(considering)f(who)g(to)h(trust,)h(k)n(eep)e(in)h+(mind)291 4138 y(that)h(a)g(securit)n(y)f(breac)n(h)g(on)g(an)n(y)h+(dev)n(elop)r(er's)f(mac)n(hine)g(could)h(giv)n(e)f(an)h(attac)n(k)n+(er)e(access)291 4237 y(to)k(their)h(priv)-5 b(ate)27+b(k)n(ey)g(and)g(passphrase,)f(and)h(th)n(us)h(to)g(y)n(our)e(rep)r+(ository)-7 b(.)291 4500 y Fv(Installing)45 b(necessary)i(programs)83+b Fx(Y)-7 b(ou)41 b(also)e(m)n(ust)i(install)g(the)f(follo)n(wing)g+(pro-)291 4600 y(grams:)35 b(gn)n(upg,)26 b(a)h(mailer)f(con\014gured)h+(to)g(receiv)n(e)f(mail)h(\(e.g.)g(exim,)g(sendmail)g(or)f(p)r(ost-)291+4700 y(\014x\),)j(and)g(a)g(w)n(eb)g(serv)n(er)e(\(usually)i(apac)n+(he\).)40 b(If)30 b(y)n(ou)e(w)n(an)n(t)g(to)h(b)r(e)h(able)f(to)g(bro)+n(wse)e(y)n(our)291 4799 y(rep)r(ository)21 b(on)j(the)f(w)n(eb)h(y)n+(ou)e(m)n(ust)i(also)e(con\014gure)h(y)n(our)f(w)n(eb)h(serv)n(er)f(to)+h(run)g(cgi)g(scripts)291 4899 y(and)34 b(mak)n(e)g(sure)h(the)g(darcs)+f(cgi)g(script)h(w)n(as)f(prop)r(erly)f(installed)i(\(b)n(y)g(either)g+(a)f(darcs-)291 4998 y(serv)n(er)25 b(pac)n(k)-5 b(age,)26+b(or)h(`mak)n(e)g(install-serv)n(er'\).)p eop end+%%Page: 24 24+TeXDict begin 24 23 bop 739 282 a Fx(24)1383 b Fu(CHAPTER)27+b(3.)64 b(GETTING)28 b(ST)-7 b(AR)g(TED)739 515 y Fv(Gran)m(ting)35+b(access)g(to)g(a)g(rep)s(ository)82 b Fx(Y)-7 b(ou)30+b(create)g(y)n(our)e(gpg)i(k)n(ey)f(b)n(y)h(running)g(\(as)739+615 y(y)n(our)c(normal)h(user\):)739 788 y Fr(\045)43+b(gpg)f(--gen-key)739 959 y Fx(Y)-7 b(ou)30 b(will)h(b)r(e)g(prompted)f+(for)g(y)n(our)f(name)h(and)g(email)h(address,)f(among)f(other)h+(options.)739 1058 y(Of)c(course,)f(y)n(ou)g(can)g(skip)h(this)g(step)g+(if)g(y)n(ou)f(already)f(ha)n(v)n(e)h(a)g(gpg)g(k)n(ey)g(y)n(ou)g(wish)+h(to)f(use.)863 1159 y(Y)-7 b(ou)29 b(no)n(w)g(need)g(to)g(exp)r(ort)f+(the)h(public)h(k)n(ey)e(so)g(w)n(e)h(can)f(tell)i(the)f(patc)n(her)f+(ab)r(out)h(it.)739 1259 y(Y)-7 b(ou)28 b(can)f(do)g(this)h(with)g(the)+g(follo)n(wing)f(command)g(\(again)f(as)h(y)n(our)g(normal)f(user\):)+739 1432 y Fr(\045)43 b(gpg)f(--export)f("email@address")c(>)43+b(/tmp/exported_key)739 1603 y Fx(And)28 b(no)n(w)f(w)n(e)g(can)g(add)h+(y)n(our)e(k)n(ey)h(to)h(the)g Fr(allowed_keys)p Fx(:)739+1775 y Fr(\(as)42 b(root\)>)f(gpg)i(--keyring)d(/var/lib/darcs/)o(rep)o+(os)o(/m)o(ypr)o(oj)o(ect)o(/a)o(ll)o(owe)o(d_)o(key)o(s)d(\\)1393+1875 y(--no-default-ke)o(yri)o(ng)g(--import)j(/tmp/exported_key)739+2046 y Fx(Y)-7 b(ou)26 b(can)g(rep)r(eat)g(this)h(pro)r(cess)e(an)n(y)h+(n)n(um)n(b)r(er)g(of)g(times)h(to)f(authorize)g(m)n(ultiple)h(users)e+(to)739 2146 y(send)i(patc)n(hes)g(to)h(the)g(rep)r(ository)-7+b(.)863 2247 y(Y)g(ou)23 b(should)g(no)n(w)f(b)r(e)i(able)e(to)h(send)g+(a)g(patc)n(h)f(to)h(the)h(rep)r(ository)d(b)n(y)i(running)f(as)g(y)n+(our)739 2347 y(normal)k(user,)i(in)f(a)h(w)n(orking)d(cop)n(y)i(of)h+(the)g(rep)r(ository:)739 2519 y Fr(\045)43 b(darcs)f(send)g(--sign)f+(http://your.com)o(put)o(er)o(/re)o(po)o(s/)o(myp)o(ro)o(jec)o(t)739+2690 y Fx(Y)-7 b(ou)30 b(ma)n(y)f(w)n(an)n(t)h(to)f(add)h(\\send)g+(sign")f(to)h(the)g(\014le)g Fr(_darcs/prefs/defa)o(ul)o(ts)24+b Fx(so)29 b(that)739 2790 y(y)n(ou)e(w)n(on't)g(need)h(to)f(t)n(yp)r+(e)h Fr(--sign)d Fx(ev)n(ery)i(time)h(y)n(ou)e(w)n(an)n(t)h(to)h(send.)+14 b(.)g(.)863 2891 y(If)30 b(y)n(our)d(gpg)h(k)n(ey)h(is)f(protected)h+(b)n(y)f(a)h(passphrase,)e(then)j(executing)e Fr(send)f+Fx(with)j(the)739 2991 y Fr(--sign)25 b Fx(option)i(migh)n(t)h(giv)n(e)+f(y)n(ou)f(the)i(follo)n(wing)f(error:)739 3163 y Fr(darcs)41+b(failed:)85 b(Error)41 b(running)g(external)f(program)h('gpg')739+3334 y Fx(The)20 b(most)g(lik)n(ely)g(cause)f(of)h(this)g(error)f(is)h+(that)g(y)n(ou)f(ha)n(v)n(e)g(a)h(miscon\014gured)f(gpg)g(that)i(tries)+739 3434 y(to)28 b(automatically)g(use)g(a)g(non-existen)n(t)g+(gpg-agen)n(t)f(program.)38 b(Gn)n(uPG)28 b(will)h(still)g(w)n(ork)739+3534 y(without)c(gpg-agen)n(t)e(when)i(y)n(ou)e(try)i(to)f(sign)h(or)e+(encrypt)i(y)n(our)e(data)i(with)g(a)f(passphrase)739+3633 y(protected)39 b(k)n(ey)-7 b(.)72 b(Ho)n(w)n(ev)n(er,)40+b(it)g(will)f(exit)h(with)g(an)f(error)e(co)r(de)j(2)f(\()p+Fr(ENOENT)p Fx(\))e(causing)739 3733 y Fr(darcs)31 b+Fx(to)i(fail.)52 b(T)-7 b(o)33 b(\014x)g(this,)h(y)n(ou)e(will)h(need)g+(to)g(edit)h(y)n(our)d Fr(~/.gnupg/gpg.conf)26 b Fx(\014le)739+3833 y(and)h(commen)n(t)h(out)f(or)g(remo)n(v)n(e)f(the)i(line)g(that)g+(sa)n(ys:)739 4005 y Fr(use-agent)739 4176 y Fx(If)37+b(after)f(commen)n(ting)g(out)g(or)f(remo)n(ving)g(the)i+Fr(use-agent)c Fx(line)j(in)h(y)n(our)e(gpg)g(con\014g-)739+4276 y(uration)i(\014le)h(y)n(ou)g(still)g(get)g(the)g(same)g(error,)h+(then)f(y)n(ou)f(probably)g(ha)n(v)n(e)g(a)h(mo)r(di\014ed)739+4375 y(Gn)n(uPG)24 b(with)g(use-agen)n(t)f(as)g(a)h(hard-co)r(ded)f+(option.)36 b(In)24 b(that)g(case,)g(y)n(ou)g(should)f(c)n(hange)739+4475 y Fr(use-agent)h Fx(to)j Fr(no-use-agent)c Fx(to)k(disable)h(it)g+(explicitly)-7 b(.)739 4700 y Fv(Setting)29 b(up)g(a)h(sendable)e(rep)s+(ository)h(using)f(pro)s(cmail)83 b Fx(If)25 b(y)n(ou)g(don't)h(ha)n(v)+n(e)e(ro)r(ot)739 4799 y(access)38 b(on)g(y)n(our)g(mac)n(hine,)k(or)c+(p)r(erhaps)g(simply)h(don't)h(w)n(an)n(t)e(to)h(b)r(other)g(creating)f+(a)739 4899 y(separate)32 b(user,)i(y)n(ou)f(can)g(set)g(up)h(a)e+(darcs)h(rep)r(ository)e(using)i(pro)r(cmail)g(to)g(\014lter)g(y)n(our)+739 4998 y(mail.)47 b(I)31 b(will)g(assume)f(that)h(y)n(ou)f(already)g+(use)h(pro)r(cmail)f(to)h(\014lter)f(y)n(our)g(email.)47+b(If)31 b(not,)p eop end+%%Page: 25 25+TeXDict begin 25 24 bop 291 282 a Fu(3.5.)63 b(MO)n(VING)28+b(P)-7 b(A)g(TCHES)27 b(FR)n(OM)h(ONE)f(REPOSITOR)-7+b(Y)26 b(TO)h(ANOTHER)128 b Fx(25)291 515 y(y)n(ou)34+b(will)h(need)g(to)f(read)g(up)i(on)e(it,)j(or)d(p)r(erhaps)g(should)h+(use)g(a)f(di\013eren)n(t)h(metho)r(d)g(for)291 615 y(routing)26+b(the)i(email)g(to)f(darcs.)415 715 y(T)-7 b(o)40 b(b)r(egin)g(with,)j+(y)n(ou)c(m)n(ust)h(con\014gure)f(y)n(our)g(rep)r(ository)f(so)h(that)i+(a)e(darcs)g(send)291 814 y(to)34 b(y)n(our)f(rep)r(ository)g(will)i+(kno)n(w)e(where)h(to)g(send)h(the)g(email.)57 b(Do)34+b(this)h(b)n(y)f(creating)f(a)291 914 y(\014le)26 b(in)g+Fr(/path/to/your/r)o(epo)o(/_)o(da)o(rcs)o(/p)o(ref)o(s)20+b Fx(called)25 b Fr(email)f Fx(con)n(taining)h(y)n(our)f(email)291+1013 y(address.)52 b(As)33 b(a)g(tric)n(k)f(\(to)i(b)r(e)f(explained)g+(b)r(elo)n(w\),)h(w)n(e)f(will)h(create)e(the)h(email)g(address)291+1113 y(with)22 b(\\darcs)e(rep)r(o")h(as)g(y)n(our)f(name,)j(in)f(an)f+(email)h(address)e(of)i(the)g(form)f(\\Da)n(vid)g(Roundy)291+1213 y Fi(<)p Fx(droundy@abridgegame.org)p Fi(>)p Fx(.")291+1361 y Fr(\045)43 b(echo)f('my)g(darcs)g(repo)f(<user@host.com>')c(\\)+552 1460 y(>)43 b(/path/to/your/rep)o(o/)o(_da)o(rc)o(s/p)o(re)o(fs)o+(/em)o(ai)o(l)415 1608 y Fx(The)36 b(next)g(step)h(is)e(to)h(set)g(up)h+(a)e(gn)n(upg)g(k)n(eyring)g(con)n(taining)g(the)h(public)h(k)n(eys)e+(of)291 1708 y(p)r(eople)h(authorized)f(to)h(send)g(to)g(y)n(our)e(rep)+r(ository)-7 b(.)61 b(Here)36 b(I'll)g(giv)n(e)f(a)h(second)f(w)n(a)n+(y)g(of)291 1807 y(going)22 b(ab)r(out)h(this)h(\(see)f(ab)r(o)n(v)n(e)+f(for)h(the)g(\014rst\).)36 b(This)23 b(time)h(I'll)g(assume)e(y)n(ou)h+(w)n(an)n(t)g(to)g(giv)n(e)291 1907 y(me)k(write)h(access)e(to)i(y)n+(our)e(rep)r(ository)-7 b(.)35 b(Y)-7 b(ou)28 b(can)f(do)g(this)h(b)n+(y:)291 2055 y Fr(gpg)42 b(--no-default-key)o(ri)o(ng)37+b(\\)465 2154 y(--keyring)j(/path/to/the/all)o(ow)o(ed_)o(ke)o(ys)d+(--recv-keys)i(D3D5BCEC)291 2302 y Fx(This)22 b(w)n(orks)g(b)r(ecause)g+(\\D3D5BCEC")f(is)i(the)g(ID)g(of)g(m)n(y)g(gpg)f(k)n(ey)-7+b(,)23 b(and)g(I)g(ha)n(v)n(e)e(uploaded)291 2402 y(m)n(y)26+b(k)n(ey)f(to)i(the)f(gpg)g(k)n(eyserv)n(ers.)34 b(Actually)-7+b(,)27 b(this)f(also)f(requires)h(that)g(y)n(ou)g(ha)n(v)n(e)f+(con\014g-)291 2502 y(ured)j(gpg)g(to)h(access)f(a)g(v)-5+b(alid)29 b(k)n(eyserv)n(er.)38 b(Y)-7 b(ou)29 b(can,)g(of)g(course,)f+(rep)r(eat)g(this)h(command)291 2601 y(for)e(all)g(k)n(eys)g(y)n(ou)f+(w)n(an)n(t)h(to)h(allo)n(w)e(access)h(to.)415 2701 y(Finally)-7+b(,)28 b(w)n(e)f(add)g(a)h(few)g(lines)f(to)h(y)n(our)e+Fr(.procmailrc)p Fx(:)291 2849 y Fr(:0)291 2948 y(*)43+b(^TOmy)e(darcs)h(repo)291 3048 y(|\(umask)e(022;)i(darcs)g(apply)f+(--reply)g(user@host.com)d(\\)465 3148 y(--repodir)i(/path/to/your/re)o+(po)d(--verify)j(/path/to/the/allo)o(we)o(d_k)o(ey)o(s\))291+3295 y Fx(The)f(purp)r(ose)g(for)g(the)h(\\m)n(y)f(darcs)f(rep)r(o")h+(tric)n(k)g(is)g(partially)g(to)g(mak)n(e)g(it)h(easier)e(to)291+3395 y(recognize)23 b(patc)n(hes)h(sen)n(t)h(to)f(the)h(rep)r(ository)+-7 b(,)24 b(but)i(is)e(ev)n(en)h(more)f(crucial)g(to)g(a)n(v)n(oid)g+(nast)n(y)291 3495 y(b)r(ounce)29 b(lo)r(ops)f(b)n(y)h(making)g(the)g+Fr(--reply)d Fx(option)j(ha)n(v)n(e)f(an)h(email)g(address)f(that)h(w)n+(on't)291 3594 y(go)i(bac)n(k)f(to)i(the)g(rep)r(ository)-7+b(.)48 b(This)32 b(means)g(that)g(unsigned)f(patc)n(hes)g(that)i(are)d+(sen)n(t)i(to)291 3694 y(y)n(our)26 b(rep)r(ository)g(will)i(b)r(e)g+(forw)n(arded)e(to)h(y)n(our)f(ordinary)g(email.)415+3793 y(Lik)n(e)c(most)f(mail-pro)r(cessing)f(programs,)h(Pro)r(cmail)g+(b)n(y)h(default)g(sets)g(a)f(tigh)n(t)h(umask.)291 3893+y(Ho)n(w)n(ev)n(er,)k(this)j(will)g(prev)n(en)n(t)e(the)i(rep)r+(ository)e(from)h(remaining)g(w)n(orld-readable;)e(th)n(us,)291+3993 y(the)k(\\umask)g(022")e(is)j(required)e(to)i(relax)e(the)i+(umask.)45 b(\(Alternativ)n(ely)-7 b(,)31 b(y)n(ou)f(could)g(set)291+4092 y(Pro)r(cmail's)c(global)g Fr(UMASK)g Fx(v)-5 b(ariable)26+b(to)i(a)f(more)g(suitable)g(v)-5 b(alue.\))291 4304+y Fv(Chec)m(king)37 b(if)g(y)m(our)h(e-mail)e(patc)m(h)i(w)m(as)g+(applied)82 b Fx(After)33 b(sending)f(a)f(patc)n(h)h(with)291+4404 y Fr(darcs)41 b(send)p Fx(,)21 b(y)n(ou)e(ma)n(y)h(not)h(receiv)n+(e)e(an)n(y)h(feedbac)n(k,)h(ev)n(en)g(if)g(the)g(patc)n(h)f(is)g+(applied.)35 b(Y)-7 b(ou)291 4504 y(can)25 b(con\014rm)g(whether)g(or)g+(not)h(y)n(our)e(patc)n(h)h(w)n(as)g(applied)h(to)f(the)h(remote)f(rep)+r(ository)f(b)n(y)291 4603 y(p)r(oin)n(ting)j Fr(darcs)42+b(changes)24 b Fx(at)k(a)f(remote)g(rep)r(ository:)291+4751 y Fr(darcs)41 b(changes)g(--last=10)f(--repo=http://d)o(arc)o(s.)o+(net)o(/)415 4899 y Fx(That)23 b(sho)n(ws)e(y)n(ou)h(the)g(last)g(10)g+(c)n(hanges)f(in)i(the)g(remote)e(rep)r(ository)-7 b(.)34+b(Y)-7 b(ou)23 b(can)f(adjust)291 4998 y(the)28 b(options)f(giv)n(en)f+(to)i Fr(changes)d Fx(if)j(a)f(more)g(adv)-5 b(anced)27+b(query)g(is)g(needed.)p eop end+%%Page: 26 26+TeXDict begin 26 25 bop 739 282 a Fx(26)1383 b Fu(CHAPTER)27+b(3.)64 b(GETTING)28 b(ST)-7 b(AR)g(TED)739 515 y Fq(3.6)135+b(Reducing)45 b(disk)g(space)g(usage)739 698 y Fx(A)34+b(Darcs)e(rep)r(ository)g(con)n(tains)h(the)h(patc)n(hes)f(that)h+(Darcs)e(uses)i(to)f(store)g(history)-7 b(,)34 b(the)739+797 y(w)n(orking)22 b(directory)-7 b(,)24 b(and)f(a)h+Fs(pristine)j(tr)l(e)l(e)j Fx(\(a)24 b(cop)n(y)f(of)h(the)g(w)n(orking)+e(directory)h(\014les)h(with)739 897 y(no)h(lo)r(cal)f(mo)r+(di\014cations\).)36 b(F)-7 b(or)25 b(large)f(rep)r(ositories,)g(this)h+(can)g(add)g(up)g(to)g(a)g(fair)g(amoun)n(t)739 997 y(of)i(disk)h+(usage.)863 1097 y(There)k(are)g(t)n(w)n(o)g(tec)n(hniques)g(that)h+(can)f(b)r(e)h(used)g(to)f(reduce)g(the)h(amoun)n(t)f(of)h(space)739+1196 y(used)c(b)n(y)g(Darcs)f(rep)r(ositories:)38 b(linking)29+b(and)g(using)g(no)f(pristine)h(tree.)41 b(The)29 b(former)g(can)739+1296 y(b)r(e)i(used)f(on)g(an)n(y)g(rep)r(ository;)g(the)h(latter)f(is)+g(only)g(suitable)g(in)h(sp)r(ecial)f(circumstances,)739+1396 y(as)d(it)h(mak)n(es)e(some)h(op)r(erations)g(m)n(uc)n(h)g(slo)n+(w)n(er.)739 1630 y Fk(3.6.1)112 b(Linking)39 b(b)s(et)m(w)m(een)f(rep)+s(ositories)739 1784 y Fx(A)26 b(n)n(um)n(b)r(er)g(of)g(\014lesystems)g+(supp)r(ort)g Fs(linking)34 b Fx(\014les,)26 b(sharing)f(a)h(single)f+(\014le)i(data)e(b)r(et)n(w)n(een)739 1883 y(di\013eren)n(t)41+b(directories.)75 b(Under)41 b(some)f(circumstances,)j(when)e(rep)r+(ositories)f(are)f(v)n(ery)739 1983 y(similar)25 b(\(t)n(ypically)g(b)r+(ecause)g(they)g(represen)n(t)f(di\013eren)n(t)i(branc)n(hes)e(of)h+(the)h(same)f(piece)g(of)739 2083 y(soft)n(w)n(are\),)h(Darcs)h(will)h+(use)f(linking)h(to)f(a)n(v)n(oid)f(storing)h(the)h(same)f(\014le)g(m)n+(ultiple)h(times.)863 2183 y(Whenev)n(er)22 b(y)n(ou)g(in)n(v)n(ok)n(e)+f Fr(darcs)42 b(get)21 b Fx(to)h(cop)n(y)g(a)g(rep)r(ository)f(from)h+(a)g(lo)r(cal)g(\014lesystem)739 2282 y(on)n(to)27 b(the)h(same)f+(\014lesystem,)g(Darcs)g(will)h(link)g(patc)n(hes)e(whenev)n(er)h(p)r+(ossible.)863 2382 y(In)39 b(order)e(to)h(sa)n(v)n(e)f(time,)k+Fr(darcs)h(get)37 b Fx(do)r(es)h(not)g(link)g(pristine)h(trees)e(ev)n+(en)h(when)739 2482 y(individual)20 b(\014les)g(are)f(iden)n(tical.)34+b(Additionally)-7 b(,)21 b(as)f(y)n(ou)f(pull)h(patc)n(hes)f(in)n(to)h+(trees,)h(patc)n(hes)739 2581 y(will)i(b)r(ecome)f(unlink)n(ed.)36+b(This)22 b(will)h(result)g(in)g(a)f(lot)g(of)h(w)n(asted)f(space)g(if)+h(t)n(w)n(o)f(rep)r(ositories)739 2681 y(ha)n(v)n(e)e(b)r(een)i(living)+f(for)g(a)g(long)g(time)h(but)g(are)f(similar.)34 b(In)22+b(suc)n(h)f(a)g(case,)h(y)n(ou)e(should)i Fs(r)l(elink)739+2781 y Fx(\014les)27 b(b)r(et)n(w)n(een)h(the)g(t)n(w)n(o)f(rep)r+(ositories.)863 2881 y(Relinking)32 b(is)f(an)g(asymmetric)f(op)r+(eration:)43 b(y)n(ou)31 b(relink)f(one)h(rep)r(ository)f(\(to)h(whic)n+(h)739 2980 y(y)n(ou)i(m)n(ust)h(ha)n(v)n(e)f(write)h(access\))f(to)h+(another)f(rep)r(ository)-7 b(,)35 b(called)e(the)i Fs(sibling)p+Fx(.)57 b(This)34 b(is)739 3080 y(done)24 b(with)g Fr(darcs)42+b(optimize)e(--relink)p Fx(,)22 b(with)i({the)g Fr(--sibling)d+Fx(\015ag)i(sp)r(ecifying)h(the)739 3180 y(sibling.)826+3347 y Fr($)43 b(cd)g(/var/repos/darcs)o(.ne)o(t)826+3447 y($)g(darcs)f(optimize)e(--relink)g(--sibling)g(/var/repos/darcs)+739 3614 y Fx(The)33 b Fr(--sibling)d Fx(\015ag)i(can)h(b)r(e)g(rep)r+(eated)g(m)n(ultiple)h(times,)h(in)e(whic)n(h)g(case)g(Darcs)f(will)739+3713 y(try)23 b(to)g(\014nd)g(a)g(\014le)h(to)f(link)g(to)g(in)h(all)e+(of)i(the)f(siblings.)35 b(If)24 b(a)f(default)g(rep)r(ository)f(is)h+(de\014ned,)739 3813 y(Darcs)k(will)g(try)-7 b(,)28 b(as)f(a)g(last)g+(resort,)g(to)g(link)h(against)e(the)i(default)g(rep)r(ository)-7+b(.)863 3913 y(Additional)36 b(space)e(sa)n(vings)f(can)h(b)r(e)i(ac)n+(hiev)n(ed)d(b)n(y)i(relinking)f(\014les)h(in)g(the)g(pristine)739+4013 y(tree)h(\(see)h(b)r(elo)n(w\))g(b)n(y)f(using)h(the)g+Fr(--relink-pristin)o(e)31 b Fx(\015ag.)64 b(Ho)n(w)n(ev)n(er,)37+b(doing)f(this)739 4112 y(prev)n(en)n(ts)26 b(Darcs)g(from)h(ha)n(ving)+f(precise)g(timestamps)h(on)g(the)g(pristine)g(\014les,)h(whic)n(h)f+(car-)739 4212 y(ries)g(a)g(mo)r(derate)g(p)r(erformance)f(p)r(enalt)n+(y)-7 b(.)739 4446 y Fk(3.6.2)112 b(Alternate)37 b(formats)i(for)e(the)+g(pristine)h(tree)739 4600 y Fx(By)23 b(default,)i(ev)n(ery)d(Darcs)g+(rep)r(ository)g(con)n(tains)g(a)h(complete)h(cop)n(y)e(of)h(the)h+Fs(pristine)j(tr)l(e)l(e)p Fx(,)739 4700 y(the)34 b(w)n(orking)e(tree)h+(as)g(it)h(w)n(ould)g(b)r(e)g(if)g(there)f(w)n(ere)g(no)g(lo)r(cal)g+(edits.)56 b(By)33 b(a)n(v)n(oiding)f(the)739 4799 y(need)39+b(to)f(consult)h(a)f(p)r(ossibly)g(large)f(n)n(um)n(b)r(er)i(of)f(patc)+n(hes)g(just)h(to)g(\014nd)g(out)g(if)g(a)f(\014le)739+4899 y(is)32 b(mo)r(di\014ed,)i(the)f(pristine)f(tree)g(mak)n(es)g(a)g+(lot)g(of)g(op)r(erations)g(m)n(uc)n(h)g(faster)g(than)g(they)739+4998 y(w)n(ould)27 b(otherwise)g(b)r(e.)p eop end+%%Page: 27 27+TeXDict begin 27 26 bop 291 282 a Fu(3.6.)63 b(REDUCING)29+b(DISK)e(SP)-7 b(A)n(CE)27 b(USA)n(GE)1278 b Fx(27)415+515 y(Under)36 b(some)f(circumstances,)h(k)n(eeping)f(a)g(whole)g+(pristine)h(tree)f(is)g(not)h(desirable.)291 615 y(This)g(is)h(the)g+(case)f(when)h(preparing)e(a)h(rep)r(ository)g(to)g(bac)n(k)g(up,)k+(when)c(publishing)h(a)291 715 y(rep)r(ository)16 b(on)j(a)f(public)g+(w)n(eb)h(serv)n(er)d(with)j(limited)g(space,)h(or)e(when)g(storing)g+(a)g(rep)r(ository)291 814 y(on)29 b(\015oppies)h(or)f(small)g(USB)h(k)+n(eys.)43 b(In)30 b(suc)n(h)g(cases,)f(it)h(is)g(p)r(ossible)g(to)f+(use)h(a)g(rep)r(ository)291 914 y(with)e(no)f(pristine)g(tree.)415+1013 y(Darcs)20 b(automatically)f(recognizes)g(a)i(rep)r(ository)e+(with)i(no)f(pristine)h(tree.)34 b(In)21 b(order)e(to)291+1113 y(create)25 b(suc)n(h)h(a)g(tree,)g(sp)r(ecify)g(the)h+Fr(--no-pristine-tr)o(ee)20 b Fx(\015ag)25 b(to)h Fr(darcs)42+b(initialize)291 1213 y Fx(or)23 b Fr(darcs)41 b(get)p+Fx(.)35 b(There)23 b(is)h(curren)n(tly)g(no)f(w)n(a)n(y)g(to)h(switc)n+(h)g(an)g(existing)g(rep)r(ository)e(to)i(use)291 1312+y(no)j(pristine)g(tree.)415 1412 y(The)c(supp)r(ort)g(for)g+Fr(--no-pristine-tr)o(ee)17 b Fx(rep)r(ositories)k(is)i(fairly)g(new,)h+(and)f(has)g(not)291 1512 y(b)r(een)j(extensiv)n(ely)f(optimized)g(y)n+(et.)36 b(Please)25 b(let)h(us)f(kno)n(w)g(if)h(y)n(ou)f(use)h(this)g+(functionalit)n(y)-7 b(,)291 1611 y(and)27 b(whic)n(h)h(op)r(erations)e+(y)n(ou)h(\014nd)h(are)e(to)r(o)i(slo)n(w.)p eop end+%%Page: 28 28+TeXDict begin 28 27 bop 739 282 a Fx(28)1383 b Fu(CHAPTER)27+b(3.)64 b(GETTING)28 b(ST)-7 b(AR)g(TED)p eop end+%%Page: 29 29+TeXDict begin 29 28 bop 291 1139 a Ft(Chapter)64 b(4)291+1555 y Fw(Con\014guring)77 b(darcs)291 1987 y Fx(There)28+b(are)f(sev)n(eral)g(w)n(a)n(ys)h(y)n(ou)g(can)g(adjust)h(darcs')e(b)r+(eha)n(vior)h(to)g(suit)h(y)n(our)f(needs.)40 b(The)291+2087 y(\014rst)30 b(is)h(to)g(edit)h(\014les)f(in)h(the)f+Fr(_darcs/prefs/)26 b Fx(directory)k(of)h(a)g(rep)r(ository)-7+b(.)45 b(Suc)n(h)32 b(con-)291 2186 y(\014guration)d(only)i(applies)g+(when)g(w)n(orking)e(with)j(that)f(rep)r(ository)-7 b(.)46+b(T)-7 b(o)30 b(con\014gure)g(darcs)291 2286 y(on)k(a)g(p)r(er-user)g+(rather)g(than)g(p)r(er-rep)r(ository)f(basis)h(\(but)i(with)f(essen)n+(tially)e(the)i(same)291 2385 y(metho)r(ds\),)j(y)n(ou)e(can)f(edit)i+(\(or)e(create\))h(\014les)g(in)g(the)g Fr(~/.darcs/)d+Fx(directory)-7 b(.)61 b(Finally)-7 b(,)291 2485 y(the)31+b(b)r(eha)n(vior)f(of)h(some)f(darcs)g(commands)h(can)g(b)r(e)g(mo)r+(di\014ed)h(b)n(y)f(setting)g(appropriate)291 2585 y(en)n(vironmen)n(t)+26 b(v)-5 b(ariables.)291 2863 y Fq(4.1)135 b(prefs)291+3046 y Fx(The)29 b Fr(_darcs)e Fx(directory)h(con)n(tains)h(a)g+Fr(prefs)e Fx(directory)-7 b(.)41 b(This)30 b(directory)e(exists)h+(simply)291 3146 y(to)j(hold)f(user)h(con\014guration)e(settings)i(sp)r+(eci\014c)g(to)g(this)h(rep)r(ository)-7 b(.)48 b(The)33+b(con)n(ten)n(ts)e(of)291 3246 y(this)25 b(directory)e(are)h(in)n+(tended)h(to)g(b)r(e)g(mo)r(di\014able)g(b)n(y)g(the)g(user,)g+(although)f(in)h(some)f(cases)291 3345 y(a)j(mistak)n(e)g(in)g(suc)n(h)+h(a)f(mo)r(di\014cation)g(ma)n(y)g(cause)g(darcs)g(to)g(b)r(eha)n(v)n+(e)g(strangely)-7 b(.)291 3565 y Fv(defaults)82 b Fx(Default)45+b(v)-5 b(alues)43 b(for)g(darcs)f(commands)h(can)g(b)r(e)h+(con\014gured)e(on)h(a)g(p)r(er-)291 3664 y(rep)r(ository)20+b(basis)h(b)n(y)g(editing)h(\(and)g(p)r(ossibly)f(creating\))g(the)i+Fr(_darcs/prefs/de)o(fa)o(ult)o(s)291 3764 y Fx(\014le.)37+b(Eac)n(h)26 b(line)i(of)f(this)h(\014le)g(has)f(the)h(follo)n(wing)f+(form:)291 3933 y Fr(COMMAND)40 b(FLAG)i(VALUE)291 4101+y Fx(where)23 b Fr(COMMAND)f Fx(is)i(either)h(the)f(name)h(of)f(the)h+(command)f(to)g(whic)n(h)h(the)f(default)h(applies,)291+4201 y(or)g Fr(ALL)g Fx(to)h(indicate)g(that)g(the)h(default)g(applies)+e(to)h(all)g(commands)g(accepting)f(that)i(\015ag.)291+4300 y(The)i Fr(FLAG)e Fx(term)i(is)g(the)g(name)g(of)g(the)g(long)f+(argumen)n(t)g(option)g(without)i(the)f(\\)p Fr(--)p+Fx(",)f(i.e.)291 4400 y Fr(verbose)h Fx(rather)j(than)h+Fr(--verbose)p Fx(.)49 b(Finally)-7 b(,)34 b(the)f Fr(VALUE)d+Fx(option)j(can)f(b)r(e)h(omitted)g(if)291 4500 y(the)f(\015ag)g(is)g+(one)g(suc)n(h)h(as)e Fr(verbose)f Fx(that)j(do)r(esn't)f(in)n(v)n(olv)+n(e)f(a)h(v)-5 b(alue.)51 b(If)33 b(the)g(v)-5 b(alue)32+b(has)291 4599 y(spaces)j(in)i(it,)j(use)d(single)f(quotes,)j(not)d+(double)h(quotes,)i(to)d(surround)g(it.)65 b(Eac)n(h)36+b(line)291 4699 y(only)26 b(tak)n(es)g(one)h(\015ag.)36+b(T)-7 b(o)26 b(set)h(m)n(ultiple)h(defaults)f(for)f(the)h(same)g+(command)f(\(or)h(for)f Fr(ALL)291 4799 y Fx(commands\),)h(use)g(m)n+(ultiple)h(lines.)415 4899 y(Note)20 b(that)h(the)f(use)g(of)g+Fr(ALL)f Fx(easily)h(can)g(ha)n(v)n(e)f(unpredicted)h(consequences,)g+(esp)r(ecially)291 4998 y(if)i(commands)f(in)h(new)n(er)f(v)n(ersions)f+(of)i(darcs)e(accepts)i(\015ags)e(that)i(they)g(didn't)h(in)f(previous)+1681 5208 y(29)p eop end+%%Page: 30 30+TeXDict begin 30 29 bop 739 282 a Fx(30)1272 b Fu(CHAPTER)27+b(4.)64 b(CONFIGURING)29 b(D)n(AR)n(CS)739 515 y Fx(v)n(ersions.)40+b(A)30 b(command)f(lik)n(e)g Fr(obliterate)c Fx(could)k(b)r(e)h(dev)-5+b(astating)29 b(with)h(the)g(\\wrong")739 615 y(\015ags)c(\(for)i+(example)f({all\).)36 b(Only)28 b(use)f(safe)g(\015ags)g(with)h+Fr(ALL)p Fx(.)913 714 y Fr(~/.darcs/defaults)485 b Fx(pro)n(vides)26+b(defaults)i(for)f(this)h(user)f(accoun)n(t)913 813 y+Fr(repo/_darcs/prefs)o(/d)o(efa)o(ul)o(ts)93 b Fx(pro)n(vides)26+b(defaults)i(for)f(one)g(pro)5 b(ject,)2146 913 y(o)n(v)n(errules)25+b(c)n(hanges)h(p)r(er)i(user)863 1009 y(F)-7 b(or)38+b(example,)i(if)e(y)n(our)f(system)h(clo)r(c)n(k)f(is)h(bizarre,)h(y)n+(ou)e(could)h(instruct)g(darcs)e(to)739 1108 y(alw)n(a)n(ys)c(ignore)g+(the)i(\014le)g(mo)r(di\014cation)f(times)h(b)n(y)f(adding)h(the)g+(follo)n(wing)e(line)i(to)f(y)n(our)739 1208 y Fr(_darcs/prefs/def)o+(au)o(lts)25 b Fx(\014le.)48 b(\(Note)31 b(that)h(this)f(w)n(ould)g(ha)+n(v)n(e)f(to)i(b)r(e)f(done)g(for)g(eac)n(h)739 1308+y(rep)r(ository!\))739 1444 y Fr(ALL)42 b(ignore-times)863+1581 y Fx(If)35 b(y)n(ou)f(nev)n(er)g(w)n(an)n(t)f(to)i(run)f(a)g(test)+h(when)g(recording)d(to)j(a)f(particular)f(rep)r(ository)739+1681 y(\(but)i(still)f(w)n(an)n(t)g(to)g(do)g(so)f(when)i(running)f+Fr(check)e Fx(on)i(that)g(rep)r(ository\),)h(and)f(lik)n(e)f(to)739+1780 y(name)27 b(all)h(y)n(our)e(patc)n(hes)h(\\Stupid)h(patc)n(h",)f+(y)n(ou)g(could)g(use)g(the)h(follo)n(wing:)739 1917+y Fr(record)41 b(no-test)739 2016 y(record)g(patch-name)e(Stupid)j+(patch)863 2153 y Fx(If)31 b(y)n(ou)f(w)n(ould)g(lik)n(e)g(a)g(command)+g(to)g(b)r(e)h(run)g(ev)n(ery)e(time)i(patc)n(hes)f(are)f(recorded)g+(in)739 2253 y(a)f(particular)e(rep)r(ository)h(\(for)h(example)f(if)i+(y)n(ou)e(ha)n(v)n(e)g(one)h(cen)n(tral)f(rep)r(ository)-7+b(,)27 b(that)i(all)739 2352 y(dev)n(elop)r(ers)35 b(con)n(tribute)h+(to\),)j(then)e(y)n(ou)f(can)g(set)g(apply)g(to)h(alw)n(a)n(ys)d(run)j+(a)f(command)739 2452 y(when)24 b(apply)g(is)g(successful.)35+b(F)-7 b(or)24 b(example,)g(if)g(y)n(ou)g(need)g(to)g(mak)n(e)f(sure)g+(that)i(the)f(\014les)g(in)739 2552 y(the)h(rep)r(ository)d(ha)n(v)n(e)+h(the)i(correct)e(access)g(righ)n(ts)g(y)n(ou)g(migh)n(t)h(use)g(the)h+(follo)n(wing.)35 b(There)739 2651 y(are)26 b(t)n(w)n(o)h(things)h(to)f+(note)h(ab)r(out)f(using)h(darcs)e(this)i(w)n(a)n(y:)863+2788 y Fn(\017)41 b Fx(Without)29 b(the)f(second)e(line)i(y)n(ou)f+(will)h(get)f(errors,)e(b)r(ecause)i(the)h(sub)g(pro)r(cess)e(that)946+2887 y(runs)i(apply)f(cannot)g(prompt)g(in)n(teractiv)n(ely)-7+b(.)863 3039 y Fn(\017)41 b Fx(Whatev)n(er)20 b(script)g(is)h(run)f(b)n+(y)g(the)h(p)r(ost)g(apply)f(command)g(should)g(not)h(b)r(e)f(b)r(e)h+(added)946 3138 y(to)27 b(the)g(rep)r(ository)e(with)i+Fr(darcs)41 b(add)p Fx(;)26 b(doing)g(so)g(w)n(ould)g(allo)n(w)g(p)r+(eople)g(to)h(mo)r(dify)946 3238 y(that)i(\014le)g(and)f(then)h(run)f+(arbitrary)f(scripts)h(on)g(y)n(our)f(main)h(rep)r(ository)-7+b(,)28 b(p)r(ossibly)946 3338 y(damaging)f(or)f(violating)h(securit)n+(y)-7 b(.)739 3483 y Fr(apply)41 b(posthook)g(chmod)g(-R)i(a+r)f(*)739+3583 y(apply)f(run-posthook)863 3729 y Fx(Similarly)-7+b(,)40 b(if)d(y)n(ou)f(need)i(a)e(command)h(to)g(run)g(automatically)f+(b)r(efore)h(darcs)f(p)r(er-)739 3829 y(forms)28 b(an)g(action)f(y)n+(ou)h(can)g(use)g(a)f(preho)r(ok.)38 b(Using)28 b(preho)r(oks)f(it)i+(could)f(b)r(e)g(p)r(ossible)g(to)739 3928 y(canonicalize)e(line)i+(endings)f(b)r(efore)h(recording)d(patc)n(hes.)863 4028+y(There)18 b(are)g(some)f(options)h(whic)n(h)h(are)e(mean)n(t)h(sp)r+(eci\014cally)g(for)g(use)g(in)h Fr(_darcs/prefs/def)o(au)o(lt)o(s)p+Fx(.)739 4127 y(One)24 b(of)h(them)h(is)e Fr(--disable)p+Fx(.)33 b(As)24 b(the)i(name)e(suggests,)g(this)i(option)e(will)h+(disable)g(ev)n(ery)739 4227 y(command)h(that)i(got)e(it)i(as)e+(argumen)n(t.)35 b(So,)27 b(if)h(y)n(ou)e(are)g(afraid)g(that)h(y)n(ou)+g(could)f(damage)739 4327 y(y)n(our)i(rep)r(ositories)f(b)n(y)i(inadv)n+(erten)n(t)g(use)g(of)g(a)f(command)h(lik)n(e)g(amend-record,)f(add)h+(the)739 4426 y(follo)n(wing)d(line)i(to)g Fr(_darcs/prefs/def)o(au)o+(lt)o(s)p Fx(:)739 4563 y Fr(amend-record)39 b(disable)863+4700 y Fx(Also,)20 b(a)e(global)g(preferences)f(\014le)h(can)g(b)r(e)h+(created)f(with)h(the)f(name)h Fr(.darcs/defaults)739+4799 y Fx(in)29 b(y)n(our)e(home)h(directory)-7 b(.)38+b(Options)28 b(presen)n(t)f(there)i(will)f(b)r(e)h(added)f(to)g(the)h+(rep)r(ository-)739 4899 y(sp)r(eci\014c)18 b(preferences.)33+b(If)19 b(they)g(con\015ict)f(with)h(rep)r(ository-sp)r(eci\014c)d+(options,)k(the)f(rep)r(ository-)739 4998 y(sp)r(eci\014c)28+b(ones)f(will)g(tak)n(e)g(precedence.)p eop end+%%Page: 31 31+TeXDict begin 31 30 bop 291 282 a Fu(4.1.)63 b(PREFS)2313+b Fx(31)291 515 y Fv(rep)s(os)82 b Fx(The)33 b Fr(_darcs/prefs/rep)o+(os)27 b Fx(\014le)33 b(con)n(tains)f(a)h(list)g(of)g(rep)r(ositories)f+(y)n(ou)g(ha)n(v)n(e)291 615 y(pulled)40 b(from)g(or)g(pushed)g(to,)k+(and)c(is)g(used)g(for)g(auto)r(completion)g(of)g(pull)h(and)f(push)291+715 y(commands)26 b(in)h(bash.)36 b(F)-7 b(eel)27 b(free)g(to)f(delete)+i(an)n(y)e(lines)g(from)h(this)g(list)g(that)g(migh)n(t)g(get)g(in)291+814 y(there,)g(or)g(to)g(delete)h(the)g(\014le)g(as)f(a)g(whole.)291+1023 y Fv(author)83 b Fx(The)28 b Fr(_darcs/prefs/au)o(tho)o(r)21+b Fx(\014le)28 b(con)n(tains)e(the)i(email)f(address)f(\(or)h(name\))+291 1123 y(to)39 b(b)r(e)i(used)f(as)f(the)i(author)e(when)h(patc)n+(hes)f(are)g(recorded)g(in)h(this)h(rep)r(ository)-7+b(,)41 b(e.g.)291 1222 y Fr(David)g(Roundy)g(<droundy@abridgeg)o(am)o+(e.o)o(rg)o(>)p Fx(.)k(This)32 b(\014le)g(o)n(v)n(errides)e(the)j(con)n+(ten)n(ts)291 1322 y(of)27 b(the)h(en)n(vironmen)n(t)f(v)-5+b(ariables)26 b Fr($DARCS_EMAIL)d Fx(and)k Fr($EMAIL)p+Fx(.)291 1531 y Fv(b)s(oring)82 b Fx(The)31 b Fr(_darcs/prefs/bori)o+(ng)25 b Fx(\014le)32 b(ma)n(y)f(con)n(tain)g(a)h(list)g(of)f(regular)f+(expres-)291 1631 y(sions)24 b(describing)g(\014les,)h(suc)n(h)f(as)h+(ob)5 b(ject)24 b(\014les,)i(that)f(y)n(ou)f(do)g(not)h(exp)r(ect)g(to)+g(add)f(to)h(y)n(our)291 1730 y(pro)5 b(ject.)36 b(As)27+b(an)h(example,)f(the)h(b)r(oring)f(\014le)h(that)f(I)h(use)g(with)g(m)+n(y)f(darcs)f(rep)r(ository)g(is:)291 1865 y Fr(\\.hi$)291+1965 y(\\.o$)291 2064 y(^\\.[^/])291 2164 y(^_)291 2264+y(~$)291 2363 y(\(^|/\)CVS\($|/\))291 2498 y Fx(A)e(newly)h(created)f+(rep)r(ository)e(has)i(a)h(longer)e(b)r(oring)g(\014le)i(that)g+(includes)g(man)n(y)e(common)291 2598 y(source)j(con)n(trol,)g(bac)n+(kup,)h(temp)r(orary)-7 b(,)27 b(and)g(compiled)h(\014les.)415+2697 y(Y)-7 b(ou)28 b(ma)n(y)e(w)n(an)n(t)h(to)h(ha)n(v)n(e)e(the)i(b)r+(oring)e(\014le)i(under)f(v)n(ersion)f(con)n(trol.)36+b(T)-7 b(o)27 b(do)g(this)h(y)n(ou)291 2797 y(can)i(use)g(darcs)f+(setpref)h(to)g(set)h(the)f(v)-5 b(alue)30 b(\\b)r(oring\014le")f(to)h+(the)h(name)f(of)g(y)n(our)f(desired)291 2897 y(b)r(oring)36+b(\014le)h(\(e.g.)g Fr(darcs)k(setpref)g(boringfile)e(.boring)p+Fx(,)e(where)f Fr(.boring)f Fx(is)i(the)291 2996 y(rep)r(ository)32+b(path)j(of)f(a)g(\014le)h(that)g(has)f(b)r(een)h(darcs)e(added)h(to)h+(y)n(our)e(rep)r(ository\).)56 b(The)291 3096 y(b)r(oring\014le)30+b(preference)h(o)n(v)n(errides)e Fr(_darcs/prefs/bori)o(ng)o+Fx(,)e(so)k(b)r(e)h(sure)f(to)g(cop)n(y)g(that)291 3195+y(\014le)c(to)h(the)g(b)r(oring\014le.)415 3295 y(Y)-7+b(ou)31 b(can)f(also)f(set)i(up)g(a)f(\\b)r(oring")f(regexps)g(\014le)h+(in)h(y)n(our)f(home)g(directory)-7 b(,)30 b(named)291+3395 y Fr(~/.darcs/boring)o Fx(,)22 b(whic)n(h)28 b(will)f(b)r(e)h+(used)g(with)g(all)f(of)h(y)n(our)e(darcs)h(rep)r(ositories.)415+3494 y(An)n(y)i(\014le)g(not)g(already)f(managed)g(b)n(y)h(darcs)f(and)+h(whose)f(rep)r(ository)f(path)j(\(suc)n(h)f(as)291 3594+y Fr(manual/index.ht)o(ml)p Fx(\))c(matc)n(hes)31 b(an)n(y)g(of)g(the)h+(b)r(oring)f(regular)f(expressions)f(is)j(consid-)291+3694 y(ered)c(b)r(oring.)40 b(The)30 b(b)r(oring)e(\014le)h(is)g(used)g+(to)g(\014lter)g(the)g(\014les)g(pro)n(vided)f(to)h(darcs)f(add,)h(to)+291 3793 y(allo)n(w)34 b(y)n(ou)h(to)h(use)f(a)g(simple)h+Fr(darcs)42 b(add)g(newdir)f(newdir/*)33 b Fx(without)j(acciden)n+(tally)291 3893 y(adding)29 b(a)g(bunc)n(h)h(of)g(ob)5+b(ject)29 b(\014les.)43 b(It)30 b(is)g(also)e(used)i(when)g(the)g+Fr(--look-for-adds)24 b Fx(\015ag)291 3992 y(is)k(giv)n(en)g(to)g+(whatsnew)g(or)g(record.)38 b(Note)29 b(that)f(once)g(a)h(\014le)f(has)+g(b)r(een)h(added)g(to)f(darcs,)291 4092 y(it)g(is)f(not)h(considered)e+(b)r(oring,)h(ev)n(en)g(if)h(it)g(matc)n(hes)f(the)h(b)r(oring)f+(\014le)h(\014lter.)291 4301 y Fv(binaries)82 b Fx(The)32+b Fr(_darcs/prefs/bina)o(ri)o(es)26 b Fx(\014le)32 b(ma)n(y)g(con)n+(tain)f(a)h(list)h(of)f(regular)e(ex-)291 4401 y(pressions)25+b(describing)h(\014les)h(that)g(should)g(b)r(e)h(treated)e(as)g(binary)+h(\014les)g(rather)e(than)j(text)291 4500 y(\014les.)58+b(Darcs)34 b(automatically)g(treats)g(\014les)g(con)n(taining)g+Fr(^Z\\)g Fx(or)g Fr('\\0')f Fx(as)h(binary)-7 b(.)58+b(Y)-7 b(ou)291 4600 y(probably)31 b(will)i(w)n(an)n(t)f(to)h(ha)n(v)n+(e)e(the)i(binaries)f(\014le)h(under)f(v)n(ersion)f(con)n(trol.)51+b(T)-7 b(o)32 b(do)h(this)291 4700 y(y)n(ou)i(can)g(use)h(darcs)e+(setpref)i(to)g(set)f(the)h(v)-5 b(alue)36 b(\\binaries\014le")e(to)i+(the)g(name)f(of)h(y)n(our)291 4799 y(desired)d(binaries)h(\014le)g+(\(e.g.)g Fr(darcs)42 b(setpref)e(binariesfile)f(./.binaries)p+Fx(,)31 b(where)291 4899 y Fr(.binaries)23 b Fx(is)k(a)g(\014le)h(that)+g(has)e(b)r(een)i(darcs)e(added)i(to)f(y)n(our)f(rep)r(ository\).)35+b(As)28 b(with)g(the)291 4998 y(b)r(oring)e(\014le,)i(y)n(ou)f(can)g+(also)g(set)g(up)h(a)f Fr(~/.darcs/binaries)21 b Fx(\014le)28+b(if)g(y)n(ou)f(lik)n(e.)p eop end+%%Page: 32 32+TeXDict begin 32 31 bop 739 282 a Fx(32)1272 b Fu(CHAPTER)27+b(4.)64 b(CONFIGURING)29 b(D)n(AR)n(CS)739 515 y Fv(email)82+b Fx(The)26 b Fr(_darcs/prefs/ema)o(il)19 b Fx(\014le)27+b(is)e(used)h(to)g(pro)n(vide)f(the)i(e-mail)e(address)g(for)739+615 y(y)n(our)d(rep)r(ository)f(that)i(others)f(will)i(use)e(when)i+(they)f Fr(darcs)41 b(send)22 b Fx(a)g(patc)n(h)h(bac)n(k)f(to)h(y)n+(ou.)739 715 y(The)28 b(con)n(ten)n(ts)e(of)i(the)g(\014le)g(should)f+(simply)h(b)r(e)g(an)f(e-mail)g(address.)739 986 y Fv(sources)83+b Fx(The)27 b Fr(_darcs/prefs/sou)o(rce)o(s)21 b Fx(\014le)28+b(is)f(used)h(to)f(indicate)h(alternativ)n(e)e(lo)r(ca-)739+1085 y(tions)i(from)h(whic)n(h)f(to)g(do)n(wnload)g(patc)n(hes)g(when)g+(using)h(a)f(\\hashed")f(rep)r(ository)-7 b(.)38 b(This)739+1185 y(\014le)28 b(con)n(tains)e(lines)i(suc)n(h)f(as:)739+1392 y Fr(cache:/home/drou)o(nd)o(y/.)o(da)o(rcs)o(/c)o(ac)o(he)739+1492 y(readonly:/home/o)o(th)o(eru)o(se)o(r/.)o(da)o(rc)o(s/c)o(ac)o+(he)739 1592 y(repo:http://darc)o(s.)o(net)739 1789 y+Fx(This)18 b(w)n(ould)g(indicate)h(that)f(darcs)f(should)i(\014rst)f+(lo)r(ok)f(in)i Fr(/home/droundy/.d)o(arc)o(s/)o(cac)o(he)739+1888 y Fx(for)27 b(patc)n(hes)f(that)i(migh)n(t)f(b)r(e)g(missing,)g+(and)g(if)h(the)g(patc)n(h)f(isn't)g(there,)g(it)h(should)f(sa)n(v)n(e)+f(a)739 1988 y(cop)n(y)17 b(there)i(for)e(future)i(use.)34+b(In)18 b(that)h(case,)g(darcs)f(will)g(lo)r(ok)g(in)h+Fr(/home/otheruser)o(/.d)o(ar)o(cs)o(/ca)o(ch)o(e)739+2088 y Fx(to)28 b(see)f(if)h(that)g(user)f(migh)n(t)h(ha)n(v)n(e)f(do)n+(wnloaded)f(a)i(cop)n(y)-7 b(,)27 b(but)h(w)n(on't)f(try)h(to)g(sa)n(v)+n(e)e(a)h(cop)n(y)739 2187 y(there,)42 b(of)d(course.)70+b(Finally)-7 b(,)42 b(it)e(will)f(lo)r(ok)g(in)g Fr(http://darcs.net)p+Fx(.)65 b(Note)39 b(that)h(the)739 2287 y Fr(sources)23+b Fx(\014le)i(can)g(also)g(exist)g(in)h Fr(~/.darcs/)p+Fx(.)32 b(Also)25 b(note)h(that)f(the)h(sources)e(men)n(tioned)739+2387 y(in)35 b(y)n(our)g Fr(sources)d Fx(\014le)k(will)f(b)r(e)h(tried)+f Fs(b)l(efor)l(e)43 b Fx(the)35 b(rep)r(ository)f(y)n(ou)h(are)f+(pulling)i(from.)739 2486 y(This)e(can)g(b)r(e)g(useful)h(in)f(a)n(v)n+(oiding)f(do)n(wnloading)f(patc)n(hes)i(m)n(ultiple)g(times)h(when)f(y)+n(ou)739 2586 y(pull)28 b(from)f(a)g(remote)g(rep)r(ository)f(to)i+(more)f(than)g(one)h(lo)r(cal)f(rep)r(ository)-7 b(.)863+2696 y(W)g(e)23 b(strongly)f(advise)f(that)i(y)n(ou)f(enable)g(a)h+(global)e(cac)n(he)h(directory)-7 b(,)22 b(whic)n(h)h(will)f(allo)n(w)+739 2796 y(darcs)i(to)h(a)n(v)n(oid)e(re-do)n(wnloading)g(patc)n(hes)h+(\(for)h(example,)g(when)g(doing)f(a)h(second)f(darcs)739+2895 y(get)32 b(of)g(the)h(same)f(rep)r(ository\),)g(and)g(also)f(allo)+n(ws)g(darcs)g(to)i(use)f(hard)f(links)i(to)f(reduce)739+2995 y(disk)27 b(usage.)36 b(T)-7 b(o)27 b(do)h(this,)g(simply)739+3202 y Fr(mkdir)41 b(-p)i($HOME/.darcs/cach)o(e)739 3302+y(echo)f(cache:$HOME/.dar)o(cs)o(/ca)o(ch)o(e)37 b(>)44+b($HOME/.darcs/so)o(urc)o(es)739 3499 y Fx(Note)c(that)h(the)g(cac)n+(he)e(directory)g(should)h(reside)g(on)g(the)h(same)f(\014lesystem)g+(as)f(y)n(our)739 3599 y(rep)r(ositories,)e(so)e(y)n(ou)h(ma)n(y)f+(need)i(to)f(v)-5 b(ary)35 b(this.)64 b(Y)-7 b(ou)36+b(can)g(also)f(use)h(m)n(ultiple)h(cac)n(he)739 3699+y(directories)25 b(on)h(di\013eren)n(t)h(\014lesystems,)f(if)h(y)n(ou)f+(ha)n(v)n(e)f(sev)n(eral)g(\014lesystems)h(on)h(whic)n(h)f(y)n(ou)739+3798 y(use)h(darcs.)739 4069 y Fv(motd)82 b Fx(The)22+b Fr(_darcs/prefs/motd)15 b Fx(\014le)22 b(ma)n(y)f(con)n(tain)g(a)h+(\\message)e(of)i(the)g(da)n(y")e(whic)n(h)739 4169 y(will)42+b(b)r(e)g(displa)n(y)n(ed)f(to)g(users)g(who)h(get)f(or)g(pull)h(from)f+(the)i(rep)r(ository)d(without)i(the)739 4268 y Fr(--quiet)25+b Fx(option.)739 4598 y Fq(4.2)135 b(En)l(vironmen)l(t)46+b(v)-7 b(ariables)739 4799 y Fx(There)34 b(are)g(a)h(few)g(en)n+(vironmen)n(t)f(v)-5 b(ariables)33 b(whose)h(con)n(ten)n(ts)h(a\013ect)+g(darcs')f(b)r(eha)n(vior.)739 4899 y(Here)d(is)h(a)g(quic)n(k)f(list)h+(of)g(all)g(the)g(v)-5 b(ariables)30 b(and)i(their)g(do)r(cumen)n+(tation)f(in)i(the)f(rest)f(of)739 4998 y(the)d(man)n(ual:)p+eop end+%%Page: 33 33+TeXDict begin 33 32 bop 291 282 a Fu(4.3.)63 b(GENERAL-PURPOSE)26+b(V)-9 b(ARIABLES)1231 b Fx(33)p 415 436 2240 4 v 413+535 4 100 v 465 505 a Fv(V)-8 b(ariable)p 2250 535 V+1490 w(Section)p 2653 535 V 415 539 2240 4 v 413 638+4 100 v 465 608 a Fx(D)n(AR)n(CS)p 758 608 25 4 v 30+w(EDITOR,)27 b(EDITOR,)h(VISUAL)p 2250 638 4 100 v 629+w(4.3)p 2653 638 V 413 738 V 465 708 a(D)n(AR)n(CS)p+758 708 25 4 v 30 w(P)-7 b(A)n(GER,)27 b(P)-7 b(A)n(GER)p+2250 738 4 100 v 1080 w(4.3)p 2653 738 V 413 837 V 465+808 a(HOME)p 2250 837 V 1774 w(4.3)p 2653 837 V 413 937+V 465 907 a(TERM)p 2250 937 V 1780 w(4.3)p 2653 937 V+415 940 2240 4 v 413 1040 4 100 v 465 1010 a(D)n(AR)n(CS)p+758 1010 25 4 v 30 w(EMAIL,)28 b(EMAIL)p 2250 1040 4+100 v 1111 w(6.1)p 2653 1040 V 415 1043 2240 4 v 413+1143 4 100 v 465 1113 a(D)n(AR)n(CS)p 758 1113 25 4 v+30 w(APPL)-7 b(Y)p 1071 1113 V 29 w(F)n(OO)p 2250 1143+4 100 v 1222 w(4.4)p 2653 1143 V 413 1243 V 465 1213+a(D)n(AR)n(CS)p 758 1213 25 4 v 30 w(GET)p 970 1213 V+30 w(F)n(OO)p 2250 1243 4 100 v 1322 w(4.4)p 2653 1243+V 413 1342 V 465 1312 a(D)n(AR)n(CS)p 758 1312 25 4 v+30 w(MGET)p 1046 1312 V 30 w(F)n(OO)p 2250 1342 4 100+v 1246 w(4.4)p 2653 1342 V 413 1442 V 465 1412 a(D)n(AR)n(CS)p+758 1412 25 4 v 30 w(MGETMAX)p 2250 1442 4 100 v 1258+w(4.4)p 2653 1442 V 413 1541 V 465 1512 a(D)n(AR)n(CS)p+758 1512 25 4 v 30 w(PR)n(O)n(XYUSERPWD)p 2250 1541 4+100 v 982 w(4.4)p 2653 1541 V 413 1641 V 465 1611 a(D)n(AR)n(CS)p+758 1611 25 4 v 30 w(W)n(GET)p 2250 1641 4 100 v 1451+w(4.4)p 2653 1641 V 413 1741 V 465 1711 a(D)n(AR)n(CS)p+758 1711 25 4 v 30 w(SSH)p 2250 1741 4 100 v 1562 w(4.4)p+2653 1741 V 413 1840 V 465 1810 a(D)n(AR)n(CS)p 758 1810+25 4 v 30 w(SCP)p 2250 1840 4 100 v 1553 w(4.4)p 2653+1840 V 413 1940 V 465 1910 a(D)n(AR)n(CS)p 758 1910 25+4 v 30 w(SFTP)p 2250 1940 4 100 v 1499 w(4.4)p 2653 1940+V 413 2040 V 465 2010 a(SSH)p 624 2010 25 4 v 30 w(POR)g(T)p+2250 2040 4 100 v 1614 w(4.4)p 2653 2040 V 415 2043 2240+4 v 413 2143 4 100 v 465 2113 a(D)n(AR)n(CS)p 758 2113+25 4 v 30 w(AL)g(TERNA)g(TIVE)p 1399 2113 V 30 w(COLOR)p+2250 2143 4 100 v 772 w(4.5)p 2653 2143 V 413 2242 V+465 2212 a(D)n(AR)n(CS)p 758 2212 25 4 v 30 w(AL)e(W)g(A)i(YS)p+1132 2212 V 31 w(COLOR)p 2250 2242 4 100 v 1038 w(4.5)p+2653 2242 V 413 2342 V 465 2312 a(D)n(AR)n(CS)p 758 2312+25 4 v 30 w(DO)p 916 2312 V 30 w(COLOR)p 1249 2312 V+29 w(LINES)p 2250 2342 4 100 v 979 w(4.5)p 2653 2342+V 413 2441 V 465 2412 a(D)n(AR)n(CS)p 758 2412 25 4 v+30 w(DONT)p 1038 2412 V 30 w(COLOR)p 2250 2441 4 100+v 1133 w(4.5)p 2653 2441 V 413 2541 V 465 2511 a(D)n(AR)n(CS)p+758 2511 25 4 v 30 w(DONT)p 1038 2511 V 30 w(ESCAPE)p+1407 2511 V 29 w(TRAILING)p 1858 2511 V 30 w(CR)p 2250+2541 4 100 v 495 w(4.5)p 2653 2541 V 413 2641 V 465 2611+a(D)n(AR)n(CS)p 758 2611 25 4 v 30 w(DONT)p 1038 2611+V 30 w(ESCAPE)p 1407 2611 V 29 w(TRAILING)p 1858 2611+V 30 w(SP)g(A)n(CES)p 2250 2641 4 100 v 297 w(4.5)p 2653+2641 V 413 2740 V 465 2710 a(D)n(AR)n(CS)p 758 2710 25+4 v 30 w(DONT)p 1038 2710 V 30 w(ESCAPE)p 1407 2710 V+29 w(8BIT)p 2250 2740 4 100 v 877 w(4.6)p 2653 2740 V+413 2840 V 465 2810 a(D)n(AR)n(CS)p 758 2810 25 4 v 30+w(DONT)p 1038 2810 V 30 w(ESCAPE)p 1407 2810 V 29 w(ANYTHING)p+2250 2840 4 100 v 603 w(4.6)p 2653 2840 V 413 2940 V+465 2910 a(D)n(AR)n(CS)p 758 2910 25 4 v 30 w(DONT)p+1038 2910 V 30 w(ESCAPE)p 1407 2910 V 29 w(ISPRINT)p+2250 2940 4 100 v 722 w(4.6)p 2653 2940 V 413 3039 V+465 3009 a(D)n(AR)n(CS)p 758 3009 25 4 v 30 w(ESCAPE)p+1127 3009 V 29 w(EXTRA)p 2250 3039 4 100 v 1046 w(4.6)p+2653 3039 V 413 3139 V 465 3109 a(D)n(AR)n(CS)p 758 3109+25 4 v 30 w(DONT)p 1038 3109 V 30 w(ESCAPE)p 1407 3109+V 29 w(EXTRA)p 2250 3139 4 100 v 766 w(4.6)p 2653 3139+V 415 3142 2240 4 v 291 3397 a Fq(4.3)135 b(General-purp)t(ose)45+b(v)-7 b(ariables)291 3593 y Fv(D)m(AR)m(CS)p 630 3593+29 4 v 35 w(EDITOR)83 b Fx(When)28 b(pulling)f(up)h(an)f(editor)g+(\(for)g(example,)h(when)f(adding)g(a)291 3692 y(long)32+b(commen)n(t)h(in)g(record\),)g(darcs)f(uses)g(the)h(con)n(ten)n(ts)g+(of)g(D)n(AR)n(CS)p 2536 3692 25 4 v 30 w(EDITOR)f(if)i(it)f(is)291+3792 y(de\014ned.)55 b(If)34 b(not,)h(it)f(tries)g(the)g(con)n(ten)n+(ts)f(of)g(VISUAL,)i(and)e(if)i(that)e(isn't)h(de\014ned)h(\(or)291+3892 y(fails)26 b(for)g(some)g(reason\),)g(it)h(tries)g(EDITOR.)36+b(If)27 b(none)f(of)h(those)f(en)n(vironmen)n(t)g(v)-5+b(ariables)291 3991 y(are)26 b(de\014ned,)i(darcs)f(tries)g+Fr(vi)p Fx(,)g Fr(emacs)p Fx(,)e Fr(emacs)42 b(-nw)26+b Fx(and)i Fr(nano)e Fx(in)i(that)g(order.)291 4246 y+Fv(D)m(AR)m(CS)p 630 4246 29 4 v 35 w(P)-8 b(A)m(GER)83+b Fx(When)25 b(using)g(a)f(pager)g(for)g(displa)n(ying)g(a)g(patc)n(h,)+h(darcs)f(uses)h(the)291 4345 y(con)n(ten)n(ts)39 b(of)g(D)n(AR)n(CS)p+1030 4345 25 4 v 30 w(P)-7 b(A)n(GER)39 b(if)h(it)g(is)g(de\014ned.)73+b(If)40 b(not,)j(it)d(tries)f(the)h(con)n(ten)n(ts)f(of)291+4445 y(P)-7 b(A)n(GER)27 b(and)g(then)h Fr(more)p Fx(.)291+4700 y Fv(D)m(AR)m(CS)p 630 4700 29 4 v 35 w(TMPDIR)83+b Fx(If)19 b(the)g(en)n(vironmen)n(t)e(v)-5 b(ariable)17+b(D)n(AR)n(CS)p 2416 4700 25 4 v 30 w(TMPDIR)i(is)f(de\014ned,)291+4799 y(darcs)i(will)j(use)f(that)g(directory)f(for)g(its)h(temp)r+(oraries.)34 b(Otherwise)21 b(it)i(will)f(use)g(TMPDIR,)291+4899 y(if)30 b(that)g(is)f(de\014ned,)i(and)f(if)g(not)g(that)g(then)g+Fr(/tmp)e Fx(and)i(if)g Fr(/tmp)e Fx(do)r(esn't)i(exist,)g(it'll)g(put)+291 4998 y(the)e(temp)r(oraries)e(in)i Fr(_darcs)p Fx(.)p+eop end+%%Page: 34 34+TeXDict begin 34 33 bop 739 282 a Fx(34)1272 b Fu(CHAPTER)27+b(4.)64 b(CONFIGURING)29 b(D)n(AR)n(CS)863 515 y Fx(This)e(is)f(v)n+(ery)f(helpful,)i(for)f(example,)g(when)g(recording)f(with)h(a)g(test)h+(suite)f(that)h(uses)739 615 y(MPI,)j(in)h(whic)n(h)g(case)f(using)g+Fr(/tmp)f Fx(to)i(hold)g(the)g(test)g(cop)n(y)f(is)g(no)h(go)r(o)r(d,)g+(as)f Fr(/tmp)f Fx(isn't)739 715 y(shared)21 b(o)n(v)n(er)g(NFS)i(and)g+(th)n(us)f(the)h Fr(mpirun)d Fx(call)j(will)f(fail,)i(since)e(the)h+(binary)f(isn't)h(presen)n(t)739 814 y(on)k(the)h(compute)g(no)r(des.)+739 1036 y Fv(HOME)82 b Fx(HOME)30 b(is)h(used)g(to)f(\014nd)i(the)f(p)+r(er-user)f(prefs)g(directory)-7 b(,)31 b(whic)n(h)g(is)g(lo)r(cated)+739 1135 y(at)c Fr($HOME/.darcs)p Fx(.)739 1357 y Fv(TERM)82+b Fx(If)26 b(darcs)e(is)h(compiled)g(with)g(lib)r(curses)g(supp)r(ort)g+(and)g(supp)r(ort)f(for)h(color)f(out-)739 1456 y(put,)31+b(it)g(uses)f(the)g(en)n(vironmen)n(t)g(v)-5 b(ariable)29+b(TERM)h(to)g(decide)g(whether)g(or)f(not)i(color)d(is)739+1556 y(supp)r(orted)f(on)h(the)g(output)g(terminal.)739+1836 y Fq(4.4)135 b(Remote)47 b(rep)t(ositories)739 2020+y Fv(SSH)p 926 2020 29 4 v 34 w(POR)-8 b(T)83 b Fx(When)31+b(using)f(ssh,)i(if)f(the)g(SSH)p 2320 2020 25 4 v 30+w(POR)-7 b(T)30 b(en)n(vironmen)n(t)f(v)-5 b(ariable)30+b(is)g(de-)739 2120 y(\014ned,)e(darcs)e(will)i(use)g(that)g(p)r(ort)f+(rather)f(than)i(the)g(default)g(ssh)g(p)r(ort)f(\(whic)n(h)h(is)f+(22\).)739 2341 y Fv(D)m(AR)m(CS)p 1078 2341 29 4 v 35+w(SSH)83 b Fx(The)28 b(D)n(AR)n(CS)p 1835 2341 25 4 v+31 w(SSH)h(en)n(vironmen)n(t)e(v)-5 b(ariable)28 b(de\014nes)h(the)g+(command)739 2441 y(that)34 b(darcs)f(will)h(use)g(when)g(ask)n(ed)f+(to)h(run)f(ssh.)56 b(This)34 b(command)f(is)h Fs(not)42+b Fx(in)n(terpreted)739 2541 y(b)n(y)35 b(a)g(shell,)i(so)e(y)n(ou)f+(cannot)h(use)g(shell)g(metac)n(haracters,)g(and)g(the)h(\014rst)f(w)n+(ord)f(in)i(the)739 2640 y(command)27 b(m)n(ust)h(b)r(e)g(the)g(name)f+(of)h(an)f(executable)g(lo)r(cated)h(in)f(y)n(our)g(path.)739+2862 y Fv(D)m(AR)m(CS)p 1078 2862 29 4 v 35 w(SCP)37+b(and)g(D)m(AR)m(CS)p 1859 2862 V 35 w(SFTP)84 b Fx(The)31+b(D)n(AR)n(CS)p 2683 2862 25 4 v 30 w(SCP)h(and)f(D)n(AR)n(CS)p+3361 2862 V 30 w(SFTP)739 2961 y(en)n(vironmen)n(t)f(v)-5+b(ariables)29 b(de\014ne)i(the)g(commands)f(that)h(darcs)f(will)g(use)h+(when)g(ask)n(ed)e(to)739 3061 y(run)k(scp)g(or)g(sftp.)55+b(Darcs)33 b(uses)g(scp)g(and)g(sftp)h(to)g(access)e(rep)r(ositories)g+(whose)g(address)739 3161 y(is)e(of)g(the)g(form)g Fr(user@foo.org:foo)+24 b Fx(or)29 b Fr(foo.org:foo)p Fx(.)40 b(Darcs)29 b(will)h(use)g(scp)+g(to)g(cop)n(y)739 3260 y(single)c(\014les)h(\(e.g.)g(rep)r(ository)f+(meta-information\),)g(and)h(sftp)h(to)f(cop)n(y)f(m)n(ultiple)i+(\014les)f(in)739 3360 y(batc)n(hes)h(\(e.g.)h(patc)n(hes\).)42+b(These)28 b(commands)h(are)f Fs(not)37 b Fx(in)n(terpreted)28+b(b)n(y)h(a)g(shell,)h(so)e(y)n(ou)739 3460 y(cannot)21+b(use)h(shell)g(metac)n(haracters,)f(and)h(the)g(\014rst)g(w)n(ord)e+(in)j(the)f(command)f(m)n(ust)i(b)r(e)f(the)739 3559+y(name)h(of)h(an)f(executable)g(lo)r(cated)g(in)h(y)n(our)e(path.)36+b(By)23 b(default,)i Fr(scp)d Fx(and)i Fr(sftp)e Fx(are)g(used.)739+3659 y(When)31 b(y)n(ou)g(can)f(use)h(sftp,)h(but)g(not)f(scp)f(\(e.g.)+h(some)g(ISP)f(w)n(eb)h(sites\),)h(it)f(w)n(orks)e(to)i(set)739+3758 y(D)n(AR)n(CS)p 1032 3758 V 30 w(SCP)26 b(to)h(`sftp'.)37+b(The)27 b(other)f(w)n(a)n(y)f(around)h(do)r(es)g(not)h(w)n(ork,)f+(i.e.)g(D)n(AR)n(CS)p 3407 3758 V 30 w(FTP)739 3858 y(m)n(ust)i+(reference)e(an)i(sftp)g(program,)d(not)j(scp.)739 4080+y Fv(D)m(AR)m(CS)p 1078 4080 29 4 v 35 w(PR)m(O)m(XYUSERPWD)84+b Fx(This)41 b(en)n(vironmen)n(t)e(v)-5 b(ariable)40+b(allo)n(ws)g(D)n(AR)n(CS)739 4179 y(and)23 b(lib)r(curl)g(to)g(access)+f(remote)h(rep)r(ositories)e(via)i(a)f(passw)n(ord-protected)f(HTTP)i+(pro)n(xy)-7 b(.)739 4279 y(The)38 b(pro)n(xy)e(itself)i(is)g(sp)r+(eci\014ed)g(with)g(the)g(standard)f(en)n(vironmen)n(t)g(v)-5+b(ariable)37 b(for)g(this)739 4378 y(purp)r(ose,)e(namely)e('h)n(ttp)p+1558 4378 25 4 v 31 w(pro)n(xy'.)54 b(The)34 b(D)n(AR)n(CS)p+2361 4378 V 30 w(PR)n(O)n(XYUSERPWD)f(en)n(vironmen)n(t)739+4478 y(v)-5 b(ariable)33 b(sp)r(eci\014es)i(the)f(pro)n(xy)f(username)h+(and)g(passw)n(ord.)55 b(It)35 b(m)n(ust)g(b)r(e)g(giv)n(en)e(in)i(the)+739 4578 y(form)27 b Fs(username:p)l(asswor)l(d)p Fx(.)739+4799 y Fv(D)m(AR)m(CS)p 1078 4799 29 4 v 35 w(GET)p 1317+4799 V 35 w(F)m(OO,)20 b(D)m(AR)m(CS)p 1933 4799 V 35+w(MGET)p 2263 4799 V 34 w(F)m(OO)i(and)f(D)m(AR)m(CS)p+3026 4799 V 35 w(APPL)-8 b(Y)p 3384 4799 V 36 w(F)m(OO)739+4899 y Fx(When)27 b(trying)f(to)g(access)f(a)h(rep)r(ository)f(with)i+(a)f(URL)h(b)r(eginning)g(fo)r(o://,)e(darcs)h(will)g(in-)739+4998 y(v)n(ok)n(e)g(the)i(program)d(sp)r(eci\014ed)j(b)n(y)f(the)g(D)n+(AR)n(CS)p 2288 4998 25 4 v 31 w(GET)p 2501 4998 V 29+w(F)n(OO)g(en)n(vironmen)n(t)f(v)-5 b(ariable)26 b(\(if)p+eop end+%%Page: 35 35+TeXDict begin 35 34 bop 291 282 a Fu(4.4.)63 b(REMOTE)27+b(REPOSITORIES)1550 b Fx(35)291 515 y(de\014ned\))19+b(to)f(do)n(wnload)f(eac)n(h)g(\014le,)k(and)d(the)h(command)f(sp)r+(eci\014ed)h(b)n(y)f(the)g(D)n(AR)n(CS)p 2894 515 25+4 v 31 w(APPL)-7 b(Y)p 3208 515 V 29 w(F)n(OO)291 615+y(en)n(vironmen)n(t)26 b(v)-5 b(ariable)27 b(\(if)h(de\014ned\))g(when)+g(pushing)g(to)f(a)g(fo)r(o://)g(URL.)415 721 y(This)h(metho)r(d)g(o)n+(v)n(errides)d(all)i(other)g(w)n(a)n(ys)f(of)i(getting)f+Fr(foo://xxx)d Fx(URLs.)415 827 y(Note)29 b(that)h(eac)n(h)f(command)f+(should)i(b)r(e)f(constructed)g(so)g(that)g(it)h(sends)f(the)h(do)n+(wn-)291 927 y(loaded)f(con)n(ten)n(t)h(to)g(STDOUT,)g(and)g(the)h+(next)f(argumen)n(t)f(to)h(it)h(should)e(b)r(e)i(the)g(URL.)291+1027 y(Here)c(are)f(some)h(examples)g(that)h(should)g(w)n(ork)e(for)h+(D)n(AR)n(CS)p 2258 1027 V 30 w(GET)p 2470 1027 V 30+w(HTTP:)291 1242 y Fr(fetch)41 b(-q)i(-o)g(-)291 1342+y(curl)f(-s)g(-f)291 1442 y(lynx)g(-source)291 1541 y(wget)g(-q)g(-O)h+(-)415 1750 y Fx(If)33 b(set,)i(D)n(AR)n(CS)p 956 1750+V 30 w(MGET)p 1244 1750 V 29 w(F)n(OO)d(will)h(b)r(e)h(used)f(to)f+(fetc)n(h)h(man)n(y)g(\014les)f(from)h(a)f(single)291+1850 y(rep)r(ository)21 b(sim)n(ultaneously)-7 b(.)34+b(Replace)23 b(F)n(OO)f(and)g(fo)r(o)h(as)f(appropriate)f(to)i(handle)f+(other)291 1950 y(URL)31 b(sc)n(hemes.)45 b(These)30+b(commands)g(are)f Fs(not)39 b Fx(in)n(terpreted)30 b(b)n(y)g(a)g+(shell,)i(so)e(y)n(ou)f(cannot)291 2049 y(use)c(shell)h(metac)n+(haracters,)e(and)i(the)g(\014rst)g(w)n(ord)f(in)h(the)g(command)g(m)n+(ust)g(b)r(e)g(the)g(name)291 2149 y(of)j(an)f(executable)h(lo)r(cated)+g(in)g(y)n(our)f(path.)41 b(The)29 b(GET)g(command)f(will)h(b)r(e)h+(called)e(with)291 2249 y(a)k(URL)h(for)e(eac)n(h)h(\014le.)52+b(The)33 b(MGET)f(command)g(will)h(b)r(e)g(in)n(v)n(ok)n(ed)e(with)i(a)+f(n)n(um)n(b)r(er)g(of)291 2348 y(URLs)26 b(and)f(is)h(exp)r(ected)h+(to)e(do)n(wnload)g(the)h(\014les)g(to)g(the)g(curren)n(t)f(directory)+-7 b(,)26 b(preserving)291 2448 y(the)34 b(\014le)g(name)g(but)h(not)f+(the)g(path.)56 b(The)34 b(APPL)-7 b(Y)34 b(command)g(will)g(b)r(e)g+(called)g(with)g(a)291 2547 y(darcs)26 b(patc)n(h\014le)h(pip)r(ed)i+(in)n(to)e(its)h(standard)e(input.)38 b(Example:)291+2763 y Fr(wget)k(-q)291 3014 y Fv(D)m(AR)m(CS)p 630 3014+29 4 v 35 w(MGETMAX)83 b Fx(When)41 b(in)n(v)n(oking)e(a)h(D)n(AR)n(CS)+p 2247 3014 25 4 v 30 w(MGET)p 2535 3014 V 30 w(F)n(OO)f(command,)291+3114 y(darcs)26 b(will)h(limit)h(the)g(n)n(um)n(b)r(er)f(of)g(URLs)h+(presen)n(ted)e(to)h(the)h(command)f(to)g(the)h(v)-5+b(alue)27 b(of)291 3213 y(this)g(v)-5 b(ariable,)27 b(if)h(set,)g(or)f+(200.)291 3464 y Fv(D)m(AR)m(CS)p 630 3464 29 4 v 35+w(W)m(GET)83 b Fx(This)29 b(is)f(a)h(v)n(ery)f(old)g(option)h(that)g+(is)g(only)f(used)h(if)g(lib)r(curl)g(is)g(not)291 3564+y(compiled)e(in)i(and)e(one)h(of)g(the)g(D)n(AR)n(CS)p+1584 3564 25 4 v 30 w(GET)p 1796 3564 V 30 w(F)n(OO)f(is)g(not)h(used.)+38 b(Using)28 b(one)f(of)h(those)291 3664 y(is)f(recommended)g+(instead.)415 3770 y(The)i(D)n(AR)n(CS)p 880 3770 V 30+w(W)n(GET)f(en)n(vironmen)n(t)f(v)-5 b(ariable)27 b(de\014nes)i(the)f+(command)g(that)h(darcs)291 3870 y(will)19 b(use)h(to)f(fetc)n(h)h(all)+f(URLs)h(for)f(remote)g(rep)r(ositories.)32 b(The)20+b(\014rst)f(w)n(ord)g(in)g(the)h(command)291 3969 y(m)n(ust)27+b(b)r(e)h(the)g(name)g(of)f(an)g(executable)g(lo)r(cated)h(in)g(y)n+(our)e(path.)37 b(Extra)26 b(argumen)n(ts)g(can)291 4069+y(b)r(e)i(included)g(as)f(w)n(ell,)g(suc)n(h)g(as:)291+4285 y Fr(wget)42 b(-q)415 4494 y Fx(Darcs)26 b(will)i(app)r(end)f+Fr(-i)g Fx(to)g(the)g(argumen)n(t)g(list,)g(whic)n(h)g(it)h(uses)f(to)g+(pro)n(vide)f(a)h(list)g(of)291 4593 y(URLS)d(to)f(do)n(wnload.)34+b(This)24 b(allo)n(ws)e(wget)h(to)h(do)n(wnload)e(m)n(ultiple)i(patc)n+(hes)f(at)h(the)f(same)291 4693 y(time.)36 b(It's)25+b(p)r(ossible)f(to)h(use)f(another)g(command)g(b)r(esides)h+Fr(wget)e Fx(with)i(this)g(en)n(vironmen)n(t)291 4793+y(v)-5 b(ariable,)26 b(but)i(it)g(m)n(ust)g(supp)r(ort)g(the)g+Fr(-i)e Fx(option)i(in)g(the)g(same)f(w)n(a)n(y)-7 b(.)415+4899 y(These)39 b(commands)f(are)g Fs(not)46 b Fx(in)n(terpreted)38+b(b)n(y)h(a)f(shell,)k(so)c(y)n(ou)g(cannot)g(use)h(shell)291+4998 y(meta-c)n(haracters.)p eop end+%%Page: 36 36+TeXDict begin 36 35 bop 739 282 a Fx(36)1272 b Fu(CHAPTER)27+b(4.)64 b(CONFIGURING)29 b(D)n(AR)n(CS)739 515 y Fq(4.5)135+b(Highligh)l(ted)47 b(output)739 712 y Fx(If)33 b(the)g(terminal)f+(understands)g(ANSI)i(color)d(escap)r(e)h(sequences,)h(darcs)f(will)h+(highligh)n(t)739 811 y(certain)27 b(k)n(eyw)n(ords)f(and)i(delimiters)+g(when)g(prin)n(ting)g(patc)n(hes.)38 b(This)28 b(can)g(b)r(e)g(turned)+g(o\013)739 911 y(b)n(y)k(setting)g(the)h(en)n(vironmen)n(t)f(v)-5+b(ariable)31 b(D)n(AR)n(CS)p 2376 911 25 4 v 30 w(DONT)p+2656 911 V 30 w(COLOR)h(to)g(1.)51 b(If)33 b(y)n(ou)e(use)739+1010 y(a)i(pager)g(that)h(happ)r(ens)g(to)g(understand)f(ANSI)i+(colors,)f(lik)n(e)f Fr(less)42 b(-R)p Fx(,)34 b(darcs)e(can)i(b)r(e)+739 1110 y(forced)27 b(alw)n(a)n(ys)f(to)i(highligh)n(t)f(the)i(output)+f(b)n(y)g(setting)f(D)n(AR)n(CS)p 2799 1110 V 31 w(AL)-9+b(W)g(A)i(YS)p 3174 1110 V 30 w(COLOR)27 b(to)739 1210+y(1.)48 b(If)32 b(y)n(ou)f(can't)h(see)f(colors)f(y)n(ou)g(can)i(set)f+(D)n(AR)n(CS)p 2433 1210 V 30 w(AL)-7 b(TERNA)g(TIVE)p+3074 1210 V 30 w(COLOR)31 b(to)h(1,)739 1309 y(and)e(darcs)e(will)i+(use)g(ANSI)g(co)r(des)g(for)f(b)r(old)h(and)g(rev)n(erse)e(video)h+(instead)g(of)h(colors.)42 b(In)739 1409 y(addition,)23+b(there)g(is)f(an)h(extra-colorful)d(mo)r(de,)k(whic)n(h)e(is)h(not)f+(enabled)h(b)n(y)f(default,)i(whic)n(h)739 1509 y(can)j(b)r(e)h(activ)+-5 b(ated)28 b(with)g(D)n(AR)n(CS)p 1844 1509 V 30 w(DO)p+2002 1509 V 30 w(COLOR)p 2335 1509 V 29 w(LINES.)863+1616 y(By)20 b(default)h(darcs)d(will)j(escap)r(e)e(\(b)n(y)h(highligh)+n(ting)f(if)i(p)r(ossible\))f(an)n(y)f(kind)h(of)g(spaces)f(at)739+1716 y(the)g(end)g(of)f(lines)h(when)g(sho)n(wing)e(patc)n(h)h(con)n+(ten)n(ts.)34 b(If)19 b(y)n(ou)e(don't)i(w)n(an)n(t)f(this)h(y)n(ou)f+(can)g(turn)739 1815 y(it)25 b(o\013)f(b)n(y)g(setting)g(D)n(AR)n(CS)p+1607 1815 V 30 w(DONT)p 1887 1815 V 31 w(ESCAPE)p 2257+1815 V 28 w(TRAILING)p 2707 1815 V 31 w(SP)-7 b(A)n(CES)23+b(to)i(1.)35 b(A)25 b(sp)r(ecial)739 1915 y(case)18 b(exists)h(for)g+(only)g(carriage)e(returns:)32 b(D)n(AR)n(CS)p 2334 1915+V 30 w(DONT)p 2614 1915 V 30 w(ESCAPE)p 2983 1915 V 29+w(TRAILING)p 3434 1915 V 30 w(CR.)739 2231 y Fq(4.6)135+b(Character)52 b(escaping)g(and)e(non-ASCI)t(I)g(c)l(harac-)1045+2380 y(ter)c(enco)t(dings)739 2576 y Fx(Darcs)39 b(needs)h(to)g(escap)r+(e)f(certain)g(c)n(haracters)f(when)i(prin)n(ting)g(patc)n(h)f(con)n+(ten)n(ts)h(to)g(a)739 2676 y(terminal.)h(Characters)27+b(lik)n(e)h Fs(b)l(acksp)l(ac)l(e)37 b Fx(can)29 b(otherwise)f(hide)h+(patc)n(h)g(con)n(ten)n(t)f(from)h(the)739 2776 y(user,)e(and)h(other)g+(c)n(haracter)e(sequences)h(can)g(ev)n(en)h(in)g(some)g(cases)f+(redirect)g(commands)739 2875 y(to)g(the)h(shell)g(if)g(the)g(terminal)+f(allo)n(ws)g(it.)863 2983 y(By)g(default)g(darcs)e(will)i(only)f(allo)+n(w)g(prin)n(table)g(7-bit)g(ASCI)r(I)h(c)n(haracters)e(\(including)739+3082 y(space\),)f(and)h(the)f(t)n(w)n(o)g(con)n(trol)f(c)n(haracters)f+Fs(tab)30 b Fx(and)24 b Fs(new)t(line)p Fx(.)36 b(\(See)25+b(the)g(last)f(paragraph)739 3182 y(in)j(this)f(section)g(for)g(a)g(w)n+(a)n(y)f(to)i(tailor)e(this)i(b)r(eha)n(vior.\))35 b(All)27+b(other)f(o)r(ctets)g(are)g(prin)n(ted)g(in)739 3282+y(quoted)h(form)h(\(as)f Fr(^<control)40 b(letter>)24+b Fx(or)j Fr(\\<hex)42 b(code>)p Fx(\).)863 3389 y(Darcs)24+b(has)g(some)g(limited)h(supp)r(ort)f(for)g(lo)r(cales.)35+b(If)25 b(the)g(system's)f(lo)r(cale)g(is)g(a)g(single-)739+3489 y(b)n(yte)j(c)n(haracter)e(enco)r(ding,)h(lik)n(e)h(the)g(Latin)g+(enco)r(dings,)f(y)n(ou)h(can)f(set)h(the)g(en)n(vironmen)n(t)739+3588 y(v)-5 b(ariable)26 b(D)n(AR)n(CS)p 1343 3588 V+30 w(DONT)p 1623 3588 V 30 w(ESCAPE)p 1992 3588 V 29+w(ISPRINT)h(to)g(1)f(and)h(darcs)f(will)h(displa)n(y)f(all)h(the)739+3688 y(prin)n(tables)h(in)g(the)h(curren)n(t)f(system)g(lo)r(cale)g+(instead)g(of)g(just)h(the)g(ASCI)r(I)g(ones.)39 b(NOTE:)739+3787 y(This)e(curen)n(tly)f(do)r(es)g(not)h(w)n(ork)e(on)h(some)h(arc)n+(hitectures)e(if)i(darcs)f(is)g(compiled)h(with)739 3887+y(GHC)21 b(6.4.)33 b(Some)20 b(non-ASCI)r(I)g(con)n(trol)f(c)n+(haracters)f(migh)n(t)i(b)r(e)h(prin)n(ted)f(and)g(can)g(p)r(ossibly)+739 3987 y(sp)r(o)r(of)27 b(the)h(terminal.)863 4094+y(F)-7 b(or)24 b(m)n(ulti-b)n(yte)h(c)n(haracter)d(enco)r(dings)i+(things)h(are)e(less)h(smo)r(oth.)36 b(UTF-8)24 b(will)h(w)n(ork)739+4194 y(if)30 b(y)n(ou)g(set)g(D)n(AR)n(CS)p 1402 4194+V 30 w(DONT)p 1682 4194 V 30 w(ESCAPE)p 2051 4194 V 29+w(8BIT)f(to)h(1,)h(but)f(non-prin)n(tables)f(outside)h(the)739+4293 y(7-bit)22 b(ASCI)r(I)h(range)e(are)h(no)g(longer)f(escap)r(ed.)35+b(E.g.,)23 b(the)g(extra)e(con)n(trol)g(c)n(haracters)g(from)739+4393 y(Latin-1)33 b(migh)n(t)g(lea)n(v)n(e)f(y)n(our)g(terminal)i(at)f+(the)h(mercy)f(of)g(the)h(patc)n(h)g(con)n(ten)n(ts.)54+b(Space)739 4493 y(c)n(haracters)26 b(outside)i(the)h(7-bit)f(ASCI)r(I)+h(range)e(are)g(no)h(longer)g(recognized)e(and)j(will)f(not)739+4592 y(b)r(e)g(prop)r(erly)e(escap)r(ed)i(at)f(line)h(endings.)863+4700 y(As)38 b(a)f(last)g(resort)g(y)n(ou)f(can)i(set)f(D)n(AR)n(CS)p+2250 4700 V 30 w(DONT)p 2530 4700 V 30 w(ESCAPE)p 2899+4700 V 29 w(ANYTHING)i(to)f(1.)739 4799 y(Then)23 b(ev)n(erything)g+(that)g(do)r(esn't)h(\015ip)f(co)r(de)h(sets)f(should)g(w)n(ork,)g(and)+g(so)g(will)g(all)g(the)h(b)r(ells)739 4899 y(and)29+b(whistles)h(in)g(y)n(our)e(terminal.)42 b(This)30 b(en)n(vironmen)n(t)+e(v)-5 b(ariable)29 b(can)g(also)f(b)r(e)i(handy)g(if)739+4998 y(y)n(ou)f(pip)r(e)i(the)f(output)g(to)g(a)g(pager)e(or)h+(external)g(\014lter)h(that)g(kno)n(ws)f(b)r(etter)h(than)g(darcs)p+eop end+%%Page: 37 37+TeXDict begin 37 36 bop 291 282 a Fu(4.6.)51 b(CHARA)n(CTER)19+b(ESCAPING)f(AND)h(NON-ASCI)r(I)g(CHARA)n(CTER)g(ENCODINGS)p+Fx(37)291 515 y(ho)n(w)38 b(to)g(handle)g(y)n(our)g(enco)r(ding.)69+b(Note)39 b(that)g Fs(al)t(l)48 b Fx(escaping,)41 b(including)d(the)h+(sp)r(ecial)291 615 y(escaping)26 b(of)i(an)n(y)e(line)i(ending)g+(spaces,)e(will)i(b)r(e)g(turned)g(o\013)g(b)n(y)f(this)h(setting.)415+715 y(There)j(are)g(t)n(w)n(o)g(en)n(vironmen)n(t)f(v)-5+b(ariables)31 b(y)n(ou)f(can)i(set)f(to)h(explicitly)g(tell)g(darcs)e+(to)291 814 y(not)h(escap)r(e)f(or)h(escap)r(e)f(o)r(ctets.)48+b(They)31 b(are)f(D)n(AR)n(CS)p 2015 814 25 4 v 30 w(DONT)p+2295 814 V 30 w(ESCAPE)p 2664 814 V 29 w(EXTRA)h(and)291+914 y(D)n(AR)n(CS)p 584 914 V 30 w(ESCAPE)p 953 914 V+28 w(EXTRA.)22 b(Their)g(v)-5 b(alues)21 b(should)h(b)r(e)g(strings)f+(consisting)f(of)i(the)g(v)n(er-)291 1013 y(batim)f(o)r(ctets)g(in)h+(question.)34 b(The)22 b(do-escap)r(es)e(tak)n(e)g(precedence)h(o)n(v)n+(er)f(the)h(don)n(t-escap)r(es.)291 1113 y(Space)28 b(c)n(haracters)f+(are)h(still)h(escap)r(ed)f(at)h(line)g(endings)g(though.)41+b(The)29 b(sp)r(ecial)f(en)n(viron-)291 1213 y(men)n(t)34+b(v)-5 b(ariable)34 b(D)n(AR)n(CS)p 1119 1213 V 30 w(DONT)p+1399 1213 V 30 w(ESCAPE)p 1768 1213 V 29 w(TRAILING)p+2219 1213 V 30 w(CR)h(turns)f(o\013)h(escaping)e(of)291+1312 y(carriage)25 b(return)i(last)g(on)g(the)h(line)g(\(DOS)g(st)n+(yle\).)p eop end+%%Page: 38 38+TeXDict begin 38 37 bop 739 282 a Fx(38)1272 b Fu(CHAPTER)27+b(4.)64 b(CONFIGURING)29 b(D)n(AR)n(CS)p eop end+%%Page: 39 39+TeXDict begin 39 38 bop 291 1158 a Ft(Chapter)64 b(5)291+1594 y Fw(Best)77 b(practices)291 2096 y Fq(5.1)135 b(In)l(tro)t+(duction)291 2316 y Fx(This)31 b(c)n(hapter)f(is)h(in)n(tended)g(to)g+(review)g(v)-5 b(arious)29 b(scenarios)h(and)g(describ)r(e)h(in)h(eac)n+(h)e(case)291 2416 y(e\013ectiv)n(e)j(w)n(a)n(ys)e(of)i(using)g(darcs.)+52 b(There)32 b(is)h(no)g(one)f(\\b)r(est)h(practice",)h(and)f(darcs)e+(is)i(a)291 2515 y(su\016cien)n(tly)h(lo)n(w-lev)n(el)f(to)r(ol)h(that)+h(there)g(are)e(man)n(y)h(high-lev)n(el)g(w)n(a)n(ys)f(one)h(can)g(use)+g(it,)291 2615 y(whic)n(h)25 b(can)g(b)r(e)h(confusing)f(to)g(new)g+(users.)36 b(The)25 b(plan)g(\(and)h(hop)r(e\))g(is)f(that)h(v)-5+b(arious)24 b(users)291 2714 y(will)36 b(con)n(tribute)f(here)h+(describing)f(ho)n(w)h(they)g(use)g(darcs)f(in)h(di\013eren)n(t)g(en)n+(vironmen)n(ts.)291 2814 y(Ho)n(w)n(ev)n(er,)30 b(this)i(is)g(not)g(a)f+(wiki,)i(and)e(con)n(tributions)g(will)h(b)r(e)g(edited)g(and)g(review)+n(ed)e(for)291 2914 y(consistency)c(and)i(wisdom.)291+3297 y Fq(5.2)135 b(Creating)46 b(patc)l(hes)291 3517+y Fx(This)31 b(section)g(will)h(la)n(y)e(do)n(wn)h(the)h(concepts)f+(around)f(patc)n(h)i(creation.)47 b(The)31 b(aim)h(is)f(to)291+3616 y(dev)n(elop)i(a)h(w)n(a)n(y)f(of)h(thinking)h(that)f(corresp)r+(onds)f(w)n(ell)h(to)g(ho)n(w)g(darcs)f(is)h(b)r(eha)n(ving)g(|)291+3716 y(ev)n(en)27 b(in)h(complicated)f(situations.)415+3836 y(In)34 b(a)g(single)f(darcs)g(rep)r(ository)g(y)n(ou)g(can)h+(think)g(of)g(t)n(w)n(o)f(\\v)n(ersions")f(of)i(the)g(source)291+3936 y(tree.)45 b(They)30 b(are)g(called)g(the)h Fs(working)39+b Fx(and)30 b Fs(pristine)38 b Fx(trees.)45 b Fs(Working)38+b Fx(is)31 b(y)n(our)e(normal)291 4035 y(source)37 b(tree,)k(with)e(or)+f(without)h(darcs)e(alongside.)69 b(The)38 b(only)g(thing)h(that)g(mak)+n(es)e(it)291 4135 y(part)c(of)g(a)h(darcs)e(rep)r(ository)g(is)i(the)g+Fr(_darcs)d Fx(directory)h(in)i(its)g(ro)r(ot.)54 b Fs(Pristine)41+b Fx(is)34 b(the)291 4235 y(recorded)28 b(state)h(of)h(the)g(source)e+(tree.)42 b(The)30 b(pristine)f(tree)h(is)f(constructed)g(from)g+(groups)291 4334 y(of)38 b(c)n(hanges,)i(called)f Fs(p)l(atches)46+b Fx(\(some)39 b(other)f(v)n(ersion)f(con)n(trol)g(systems)h(use)h(the)+g(term)291 4434 y Fs(changeset)i Fx(instead)32 b(of)g+Fs(p)l(atch)6 b Fx(\).)1316 4404 y Fm(1)1406 4434 y Fx(Darcs)32+b(will)g(create)g(and)g(store)f(these)i(patc)n(hes)e(based)291+4534 y(on)c(the)h(c)n(hanges)e(y)n(ou)h(mak)n(e)g(in)h+Fs(working)p Fx(.)p 291 4685 1146 4 v 383 4738 a Fp(1)418+4762 y Fl(If)20 b(y)n(ou)g(lo)r(ok)h(inside)p 965 4762+22 4 v 45 w(darcs)f(y)n(ou)h(will)d(\014nd)j(\014les)f(or)g+(directories)g(named)h Fo(patches)g Fl(and)g Fo(inventories)p+Fl(,)291 4841 y(whic)n(h)k(store)g(all)f(the)i(patc)n(hes)g(ev)n(er)f+(recorded.)35 b(If)25 b(the)h(rep)r(ository)f(holds)g(a)f(cac)n(hed)j+(pristine)d(tree,)i(it)e(is)291 4920 y(stored)g(in)f(a)h(directory)g+(called)g Fo(pristine)i Fl(or)d Fo(current)p Fl(;)i(otherwise,)f(the)h+(fact)f(that)h(there)f(is)f(no)h(pristine)291 4998 y(tree)g(is)f(mark)n+(ed)h(b)n(y)g(the)g(presence)h(of)e(a)h(\014le)g(called)g+Fo(pristine.none)j Fl(or)c Fo(current.none)p Fl(.)1681+5208 y Fx(39)p eop end+%%Page: 40 40+TeXDict begin 40 39 bop 739 282 a Fx(40)1466 b Fu(CHAPTER)27+b(5.)64 b(BEST)27 b(PRA)n(CTICES)739 515 y Fk(5.2.1)112+b(Changes)739 679 y Fx(If)28 b Fs(working)37 b Fx(and)28+b Fs(pristine)35 b Fx(are)26 b(the)j(same,)e(there)h(are)f(\\no)g(c)n+(hanges")f(in)i(the)h(rep)r(ository)-7 b(.)739 778 y(Changes)28+b(can)i(b)r(e)g(in)n(tro)r(duced)f(\(or)g(remo)n(v)n(ed\))g(b)n(y)g+(editing)h(the)g(\014les)f(in)h Fs(working)p Fx(.)44+b(They)739 878 y(can)35 b(also)g(b)r(e)h(caused)f(b)n(y)g(darcs)g+(commands,)i(whic)n(h)e(can)h(mo)r(dify)g Fs(b)l(oth)42+b(working)i Fx(and)739 978 y Fs(pristine)p Fx(.)37 b(It)24+b(is)h(imp)r(ortan)n(t)f(to)g(understand)g(for)g(eac)n(h)g(darcs)f+(command)h(ho)n(w)g(it)h(mo)r(di\014es)739 1077 y Fs(working)p+Fx(,)k Fs(pristine)34 b Fx(or)27 b(b)r(oth)h(of)g(them.)863+1183 y Fr(whatsnew)k Fx(\(as)j(w)n(ell)g(as)f Fr(diff)p+Fx(\))g(can)g(sho)n(w)g(the)i(di\013erence)f(b)r(et)n(w)n(een)g+Fs(working)43 b Fx(and)739 1282 y Fs(pristine)36 b Fx(to)29+b(y)n(ou.)40 b(It)30 b(will)f(b)r(e)h(sho)n(wn)e(as)g(a)h(di\013erence)+g(in)g Fs(working)p Fx(.)43 b(In)29 b(adv)-5 b(anced)28+b(cases)739 1382 y(it)f(need)f Fs(not)34 b Fx(b)r(e)26+b Fs(working)35 b Fx(that)27 b(has)e(c)n(hanged;)h(it)h(can)e(just)i+(as)f(w)n(ell)g(ha)n(v)n(e)f(b)r(een)h Fs(pristine)p+Fx(,)739 1481 y(or)h(b)r(oth.)37 b(The)28 b(imp)r(ortan)n(t)f(thing)h+(is)f(the)h(di\013erence)g(and)f(what)h(darcs)e(can)h(do)h(with)g(it.)+739 1743 y Fk(5.2.2)112 b(Keeping)38 b(or)g(discarding)g(c)m(hanges)739+1907 y Fx(If)24 b(y)n(ou)g(ha)n(v)n(e)e(a)i(di\013erence)g(in)g+Fs(working)p Fx(,)i(y)n(ou)e(do)f(t)n(w)n(o)h(things)g(with)g(it:)36+b Fr(record)21 b Fx(it)k(to)f(k)n(eep)739 2006 y(it,)k(or)f+Fr(revert)e Fx(it)j(to)f(lose)g(the)h(c)n(hanges.)2029+1976 y Fm(2)863 2112 y Fx(If)37 b(y)n(ou)e(ha)n(v)n(e)g(a)h+(di\013erence)g(b)r(et)n(w)n(een)g Fs(working)44 b Fx(and)36+b Fs(pristine)6 b Fx(|for)37 b(example)f(after)739 2211+y(editing)26 b(some)f(\014les)g(in)h Fs(working)7 b Fx(|)p+Fr(whatsnew)24 b Fx(will)i(sho)n(w)f(some)g(\\unrecorded)f(c)n+(hanges".)739 2311 y(T)-7 b(o)29 b(sa)n(v)n(e)f(these)h(c)n(hanges,)g+(use)g Fr(record)p Fx(.)40 b(It)30 b(will)f(create)g(a)g(new)g(patc)n+(h)h(in)f Fs(pristine)37 b Fx(with)739 2411 y(the)31+b(same)g(c)n(hanges,)g(so)f Fs(working)40 b Fx(and)31+b Fs(pristine)38 b Fx(are)30 b(no)h(longer)f(di\013eren)n(t.)48+b(T)-7 b(o)30 b(instead)739 2510 y(undo)d(the)g(c)n(hanges)f(in)h+Fs(working)p Fx(,)h(use)f Fr(revert)p Fx(.)34 b(It)27+b(will)g(mo)r(dify)h(the)f(\014les)g(in)g Fs(working)35+b Fx(to)739 2610 y(b)r(e)28 b(the)g(same)f(as)g(in)h+Fs(pristine)34 b Fx(\(where)28 b(the)g(c)n(hanges)e(do)h(not)h+(exist\).)739 2872 y Fk(5.2.3)112 b(Unrecording)38 b(c)m(hanges)739+3035 y Fr(unrecord)30 b Fx(is)j(a)g(command)g(mean)n(t)g(to)h(b)r(e)f+(run)h(only)f(in)g(priv)-5 b(ate)33 b(rep)r(ositories.)53+b(Its)33 b(in-)739 3135 y(tended)21 b(purp)r(ose)f(is)g(to)h(allo)n(w)e+(dev)n(elop)r(ers)g(the)i(\015exibilit)n(y)g(to)f(undo)g(patc)n(hes)g+(that)h(ha)n(v)n(en't)739 3234 y(b)r(een)28 b(distributed)g(y)n(et.)863+3340 y(Ho)n(w)n(ev)n(er,)21 b(darcs)g(do)r(es)g(not)g(prev)n(en)n(t)g+(y)n(ou)g(from)g(unrecording)f(a)h(patc)n(h)g(that)h(has)f(b)r(een)739+3439 y(copied)27 b(to)h(another)e(rep)r(ository)-7 b(.)36+b(Be)27 b(a)n(w)n(are)e(of)j(this)g(danger!)863 3544+y(If)39 b(y)n(ou)e Fr(unrecord)d Fx(a)k(patc)n(h,)i(that)e(patc)n(h)g+(will)g(b)r(e)g(deleted)g(from)g Fs(pristine)p Fx(.)68+b(This)739 3644 y(will)35 b(cause)g Fs(working)44 b Fx(to)35+b(b)r(e)h(di\013eren)n(t)f(from)g Fs(pristine)p Fx(,)j(and)d+Fr(whatsnew)e Fx(to)i(rep)r(ort)f(un-)739 3744 y(recorded)h(c)n+(hanges.)63 b(The)37 b(di\013erence)g(will)g(b)r(e)g(the)g(same)f(as)h+(just)g(b)r(efore)f(that)i(patc)n(h)739 3843 y(w)n(as)26+b Fr(record)p Fx(ed.)34 b(Think)27 b(ab)r(out)f(it.)37+b Fr(record)25 b Fx(examines)h(what's)g(di\013eren)n(t)h(with)g+Fs(working)739 3943 y Fx(and)g(constructs)f(a)g(patc)n(h)h(with)g(the)h+(same)e(c)n(hanges)f(in)j Fs(pristine)34 b Fx(so)26 b(they)h(are)f(no)h+(longer)739 4043 y(di\013eren)n(t.)55 b Fr(unrecord)31+b Fx(deletes)i(this)h(patc)n(h;)j(the)d(c)n(hanges)e(in)i+Fs(pristine)41 b Fx(disapp)r(ear)32 b(and)739 4142 y(the)c+(di\013erence)f(is)h(bac)n(k.)863 4247 y(If)g(the)f(recorded)e(c)n+(hanges)h(included)h(an)f(error,)g(the)h(resulting)f(\015a)n(w)n(ed)g+(patc)n(h)g(can)h(b)r(e)739 4347 y(unrecorded.)39 b(When)29+b(the)g(c)n(hanges)e(ha)n(v)n(e)g(b)r(een)i(\014xed,)g(they)g(can)f(b)r+(e)h(recorded)f(again)f(as)739 4447 y(a)g(new|hop)r(efully)h(\015a)n+(wless|patc)n(h.)863 4552 y(If)j(the)g(whole)f(c)n(hange)f(w)n(as)g+(wrong)g(it)i(can)e(b)r(e)i(discarded)e(from)h Fs(working)39+b Fx(to)r(o,)31 b(with)739 4651 y Fr(revert)p Fx(.)73+b Fr(revert)38 b Fx(will)j(up)r(date)g Fs(working)49+b Fx(to)40 b(the)h(state)g(of)f Fs(pristine)p Fx(,)45+b(in)40 b(whic)n(h)h(the)739 4751 y(c)n(hanges)26 b(do)h(no)h(longer)e+(exist)h(after)h(the)g(patc)n(h)f(w)n(as)g(deleted.)p+739 4842 1146 4 v 831 4896 a Fp(2)866 4920 y Fl(Rev)n(ert)d(can)f(undo)+h(precious)f(w)n(ork)g(in)g(a)g(blink.)31 b(T)-6 b(o)23+b(protect)h(y)n(ou)g(from)e(great)i(grief,)e(the)i(discarded)739+4998 y(c)n(hanges)h(are)f(sa)n(v)n(ed)g(temp)r(orarily)g(so)f(the)i+(latest)f(rev)n(ert)g(can)h(b)r(e)f(undone)h(with)e(unrev)n(ert.)p+eop end+%%Page: 41 41+TeXDict begin 41 40 bop 291 282 a Fu(5.2.)63 b(CREA)-7+b(TING)28 b(P)-7 b(A)g(TCHES)1720 b Fx(41)415 515 y(Keep)42+b(in)h(mind)h(that)f(the)g(patc)n(hes)f(are)f(y)n(our)h(history)-7+b(,)45 b(so)d(deleting)h(them)g(with)291 615 y Fr(unrecord)36+b Fx(mak)n(es)j(it)h(imp)r(ossible)f(to)h(trac)n(k)e(what)i(c)n(hanges)+e(y)n(ou)h Fs(r)l(e)l(al)t(ly)48 b Fx(made.)73 b(Re-)291+715 y(doing)28 b(the)g(patc)n(hes)g(is)h(ho)n(w)f(y)n(ou)f(\\co)n(v)n+(er)g(the)i(trac)n(ks".)37 b(On)29 b(the)g(other)f(hand,)g(it)h(can)g+(b)r(e)291 814 y(a)d(v)n(ery)g(con)n(v)n(enien)n(t)f(w)n(a)n(y)h(to)h+(manage)e(and)i(organize)e(c)n(hanges)g(while)i(y)n(ou)f(try)h(them)g+(out)291 914 y(in)j(y)n(our)f(priv)-5 b(ate)30 b(rep)r(ository)-7+b(.)43 b(When)31 b(all)f(is)g(ready)f(for)h(shipping,)h(the)g(c)n+(hanges)e(can)h(b)r(e)291 1013 y(reorganized)25 b(in)j(what)f(seems)g+(as)g(useful)h(and)g(impressiv)n(e)e(patc)n(hes.)36 b(Use)28+b(it)g(with)g(care.)415 1136 y(All)38 b(patc)n(hes)f(are)g(global,)i+(so)e(don't)h Fs(ever)48 b Fx(replace)36 b(an)i(already)e(\\shipp)r+(ed")h(patc)n(h)291 1235 y(in)c(this)h(w)n(a)n(y!)53+b(If)34 b(an)f(erroneous)e(patc)n(h)i(is)g(deleted)h(and)f(replaced)g+(with)h(a)e(b)r(etter)i(one,)291 1335 y(y)n(ou)29 b(ha)n(v)n(e)h(to)g+(replace)g(it)g(in)h Fs(al)t(l)41 b Fx(rep)r(ositories)28+b(that)j(ha)n(v)n(e)e(a)h(cop)n(y)g(of)h(it.)46 b(This)30+b(ma)n(y)g(not)291 1434 y(b)r(e)f(feasible,)h(unless)e(it's)i(all)f+(priv)-5 b(ate)29 b(rep)r(ositories.)39 b(If)30 b(other)f(dev)n(elop)r+(ers)e(ha)n(v)n(e)h(already)291 1534 y(made)e(patc)n(hes)h(or)f(tags)g+(in)h(their)g(rep)r(ositories)e(that)j(dep)r(end)f(on)g(the)g(old)g+(patc)n(h,)g(things)291 1634 y(will)g(get)h(complicated.)291+1986 y Fk(5.2.4)112 b(Sp)s(ecial)39 b(patc)m(hes)f(and)g(p)s(ending)291+2181 y Fx(The)h(patc)n(hes)g(describ)r(ed)g(in)h(the)g(previous)f+(sections)g(ha)n(v)n(e)f(mostly)h(b)r(een)h(h)n(unks.)73+b(A)291 2281 y Fs(hunk)40 b Fx(is)31 b(one)g(of)g(darcs')f(primitiv)n+(e)h(patc)n(h)g(t)n(yp)r(es,)h(and)f(it)h(is)f(used)g(to)g(remo)n(v)n+(e)f(old)h(lines)291 2380 y(and/or)j(insert)h(new)h(lines.)61+b(There)35 b(are)g(other)g(t)n(yp)r(es)h(of)g(primitiv)n(e)f(patc)n+(hes,)i(suc)n(h)f(as)291 2480 y Fs(adddir)j Fx(and)28+b Fs(add\014le)36 b Fx(whic)n(h)28 b(add)g(new)g(directories)f(and)g+(\014les,)i(and)f Fs(r)l(eplac)l(e)35 b Fx(whic)n(h)28+b(do)r(es)291 2580 y(a)f(searc)n(h-and-replace)d(on)j(tok)n(ens)g(in)h+(\014les.)415 2702 y(Hunks)19 b(are)e(alw)n(a)n(ys)f(calculated)i(in)h+(place)f(with)h(a)f(di\013)h(algorithm)e(just)i(b)r(efore)f+Fr(whatsnew)291 2801 y Fx(or)31 b Fr(record)p Fx(.)47+b(But)32 b(other)g(t)n(yp)r(es)g(of)f(primitiv)n(e)h(patc)n(hes)f(need)+h(to)g(b)r(e)h(explicitly)f(created)291 2901 y(with)22+b(a)f(darcs)g(command.)35 b(They)21 b(are)g(k)n(ept)h(in)g+Fs(p)l(ending)2051 2871 y Fm(3)2111 2901 y Fx(un)n(til)h(they)f(are)f+(either)g(recorded)291 3001 y(or)26 b(rev)n(erted.)415+3123 y Fs(Pending)45 b Fx(can)36 b(b)r(e)h(though)n(t)f(of)h(as)e(a)h+(sp)r(ecial)h(extension)f(of)g Fs(working)p Fx(.)65 b(When)37+b(y)n(ou)291 3222 y(issue,)k(e.g.,)g(a)e(darcs)f Fr(replace)e+Fx(command,)41 b(the)e(replace)f(is)h(p)r(erformed)f(on)h(the)g+(\014les)291 3322 y(in)c Fs(working)44 b Fx(and)35 b(at)g(the)h(same)e+(time)i(a)f(replace)f(patc)n(h)h(is)g(put)h(in)g Fs(p)l(ending)p+Fx(.)60 b(P)n(atc)n(hes)291 3422 y(in)33 b Fs(p)l(ending)42+b Fx(describ)r(e)33 b(sp)r(ecial)g(c)n(hanges)f(made)h(in)h+Fs(working)p Fx(.)55 b(The)33 b(di\013)h(algorithm)f(will)291+3521 y(\014ctiv)n(ely)26 b(apply)h(these)g(c)n(hanges)e(to)i+Fs(pristine)34 b Fx(b)r(efore)27 b(it)g(compares)e(it)j(to)f+Fs(working)p Fx(,)h(so)e(all)291 3621 y(lines)h(in)h+Fs(working)36 b Fx(that)27 b(are)g(c)n(hanged)f(b)n(y)h(a)g+Fr(replace)e Fx(command)i(will)h(also)e(b)r(e)i(c)n(hanged)291+3721 y(in)f Fs(p)l(ending)7 b Fx(+)p Fs(pristine)34 b+Fx(when)27 b(the)h(h)n(unks)e(are)g(calculated.)36 b(That's)27+b(wh)n(y)f(no)h(h)n(unks)f(with)291 3820 y(the)k(replaced)g(lines)g+(will)h(b)r(e)g(sho)n(wn)f(b)n(y)g Fr(whatsnew)p Fx(;)f(it)i(only)f+(sho)n(ws)f(the)i(replace)e(patc)n(h)291 3920 y(in)e+Fs(p)l(ending)36 b Fx(resp)r(onsible)27 b(for)g(the)h(c)n(hange.)415+4042 y(If)34 b(a)g(sp)r(ecial)f(patc)n(h)h(is)g(recorded,)g(it)g(will)g+(simply)g(b)r(e)g(mo)n(v)n(ed)f(to)h Fs(pristine)p Fx(.)56+b(If)35 b(it)f(is)291 4142 y(instead)27 b(rev)n(erted,)f(it)h(will)g(b)+r(e)h(deleted)f(from)g Fs(p)l(ending)35 b Fx(and)27 b(the)h(accompan)n+(ying)d(c)n(hange)291 4241 y(will)i(b)r(e)h(remo)n(v)n(ed)e(from)i+Fs(working)p Fx(.)415 4363 y(Note)h(that)f(rev)n(erting)f(a)h(patc)n(h)+g(in)h(p)r(ending)g(is)f Fs(not)36 b Fx(the)29 b(same)f(as)g(simply)h+(remo)n(ving)291 4463 y(it)e(from)h(p)r(ending.)37 b(It)28+b(actually)e(applies)h(the)h(in)n(v)n(erse)e(of)i(the)g(c)n(hange)e(to)+h Fs(working)p Fx(.)38 b(Most)291 4563 y(notable)d(is)h(that)g(rev)n+(erting)f(an)h(add\014le)g(patc)n(h)f(will)i(delete)f(the)g(\014le)g+(in)h Fs(working)44 b Fx(\(the)291 4662 y(in)n(v)n(erse)32+b(of)h(adding)g(it\).)55 b(So)33 b(if)h(y)n(ou)f(add)g(the)h(wrong)e+(\014le)i(to)f(darcs)f(b)n(y)h(mistak)n(e,)i Fs(don)-8+b('t)291 4762 y Fr(revert)16 b Fx(the)i(add\014le.)34+b(Instead)18 b(use)g Fr(remove)p Fx(,)g(whic)n(h)h(cancels)e(out)i(the)+g(add\014le)f(in)h(p)r(ending.)p 291 4921 1146 4 v 383+4975 a Fp(3)418 4998 y Fl(In)24 b(the)g(\014le)p 745+4998 22 4 v 49 w Fo(darcs/patches/pending)p Fl(.)p eop+end+%%Page: 42 42+TeXDict begin 42 41 bop 739 282 a Fx(42)1466 b Fu(CHAPTER)27+b(5.)64 b(BEST)27 b(PRA)n(CTICES)739 515 y Fq(5.3)135+b(Using)46 b(patc)l(hes)739 698 y Fx(This)22 b(section)g(will)h(la)n(y)+f(do)n(wn)g(the)h(concepts)f(around)f(patc)n(h)i(distribution)f(and)g+(branc)n(hes.)739 798 y(The)30 b(aim)g(is)f(to)h(dev)n(elop)f(a)g(w)n+(a)n(y)g(of)h(thinking)g(that)g(corresp)r(onds)e(w)n(ell)i(to)f(ho)n(w)+h(darcs)e(is)739 898 y(b)r(eha)n(ving)f(|)g(ev)n(en)h(in)f(complicated)+h(situations.)863 998 y(A)k(rep)r(ository)d(is)i(a)f(collection)g(of)h+(patc)n(hes.)46 b(P)n(atc)n(hes)30 b(ha)n(v)n(e)f(no)i(de\014ned)g+(order,)g(but)739 1098 y(patc)n(hes)j(can)g(ha)n(v)n(e)g(dep)r+(endencies)h(on)g(other)f(patc)n(hes.)58 b(P)n(atc)n(hes)33+b(can)h(b)r(e)h(added)g(to)g(a)739 1197 y(rep)r(ository)23+b(in)h(an)n(y)g(order)f(as)h(long)f(as)h(all)g(patc)n(hes)g(dep)r+(ended)h(up)r(on)g(are)e(there.)36 b(P)n(atc)n(hes)739+1297 y(can)24 b(b)r(e)h(remo)n(v)n(ed)e(from)i(a)f(rep)r(ository)f(in)i+(an)n(y)f(order,)g(as)g(long)g(as)g(no)g(remaining)g(patc)n(hes)739+1396 y(dep)r(end)k(on)f(them.)863 1497 y(Rep)r(ositories)i(can)h(b)r(e)+g(cloned)g(to)g(create)f(branc)n(hes.)43 b(P)n(atc)n(hes)29+b(created)g(in)h(di\013eren)n(t)739 1596 y(branc)n(hes)35+b(ma)n(y)g(con\015ict.)63 b(A)36 b(con\015ict)g(is)g(a)g(v)-5+b(alid)36 b(state)g(of)g(a)g(rep)r(ository)-7 b(.)61+b(A)36 b(con\015ict)739 1696 y(mak)n(es)26 b(the)i(w)n(orking)e(tree)i+(am)n(biguous)e(un)n(til)i(the)g(con\015ict)f(is)h(resolv)n(ed.)739+1932 y Fk(5.3.1)112 b(Dep)s(endencies)739 2087 y Fx(There)25+b(are)f(t)n(w)n(o)h(kinds)g(of)h(dep)r(endencies:)36+b(implicit)26 b(dep)r(endencies)g(and)f(explicit)h(dep)r(en-)739+2186 y(dencies.)863 2286 y(Implicit)35 b(dep)r(endencies)f(is)g(the)g+(far)g(most)g(common)f(kind.)56 b(These)34 b(are)f(calculated)739+2386 y(automatically)28 b(b)n(y)i(darcs.)41 b(If)30 b(a)f(patc)n(h)g+(remo)n(v)n(es)f(a)h(\014le)h(or)e(a)i(line)f(of)h(co)r(de,)g(it)g+(will)f(ha)n(v)n(e)739 2486 y(to)f(dep)r(end)i(on)e(the)h(patc)n(h)f+(that)h(added)g(that)g(\014le)g(or)e(line)i(of)g(co)r(de.)2906+2456 y Fm(4)2983 2486 y Fx(If)g(a)f(patc)n(h)g(adds)h(a)739+2585 y(line)f(of)h(co)r(de,)f(it)h(will)f(usually)g(ha)n(v)n(e)f(to)h+(dep)r(end)h(on)f(the)h(patc)n(h)f(or)f(patc)n(hes)h(that)g(added)739+2685 y(the)g(adjacen)n(t)f(lines.)863 2785 y(Explicit)41+b(dep)r(endencies)g(can)f(b)r(e)h(created)f(if)h(y)n(ou)e(giv)n(e)h+(the)h Fr(--ask-deps)c Fx(option)739 2885 y(to)j Fr(darcs)i(record)p+Fx(.)74 b(This)40 b(is)h(go)r(o)r(d)f(for)g(assuring)f(that)i(logical)e+(dep)r(endencies)i(hold)739 2985 y(b)r(et)n(w)n(een)32+b(patc)n(hes.)49 b(It)32 b(can)g(also)e(b)r(e)j(used)f(to)f(group)g+(patc)n(hes|a)g(patc)n(h)h(with)g(explicit)739 3084 y(dep)r(endencies)+23 b(do)r(esn't)h(need)f(to)g(c)n(hange)f(an)n(ything|and)h(pulling)g+(the)h(patc)n(h)f(also)f(pulls)739 3184 y(all)27 b(patc)n(hes)g(it)h(w)+n(as)f(made)g(to)h(dep)r(end)g(on.)739 3420 y Fk(5.3.2)112+b(Branc)m(hes:)51 b(just)37 b(normal)i(rep)s(ositories)739+3574 y Fx(Darcs)22 b(do)r(es)g(not)h(ha)n(v)n(e)f(branc)n(hes|it)f(do)r+(esn't)i(need)g(to.)35 b(Ev)n(ery)22 b(rep)r(ository)f(can)h(b)r(e)h+(used)739 3674 y(as)i(a)h(branc)n(h.)35 b(This)26 b(means)f(that)h(an)n+(y)g(t)n(w)n(o)f(rep)r(ositories)f(are)h(\\branc)n(hes")e(in)j(darcs,)g+(but)739 3774 y(it)34 b(is)f(not)g(of)g(m)n(uc)n(h)g(use)g(unless)g+(they)h(ha)n(v)n(e)e(a)h(large)f(p)r(ortion)g(of)i(patc)n(hes)e(in)i+(common.)739 3873 y(If)28 b(they)f(are)g(di\013eren)n(t)g(pro)5+b(jects)27 b(they)h(will)f(ha)n(v)n(e)g(nothing)g(in)h(common,)f(but)h+(darcs)e(ma)n(y)739 3973 y(still)h(v)n(ery)e(w)n(ell)i(b)r(e)g(able)f+(to)g(merge)g(them,)i(although)e(the)h(result)f(probably)f(is)i+(nonsense.)739 4072 y(Therefore)j(the)j(w)n(ord)d(\\branc)n(h")g(isn't)+i(a)g(tec)n(hnical)f(term)h(in)g(darcs;)h(it's)f(just)g(the)g(w)n(a)n+(y)739 4172 y(w)n(e)27 b(think)h(of)g(one)f(rep)r(ository)f(in)i+(relation)e(to)i(another.)863 4272 y(Branc)n(hes)d(are)f+Fs(very)34 b Fx(useful)27 b(in)f(darcs.)35 b(They)25+b(are)g(in)h(fact)g Fs(ne)l(c)l(essary)34 b Fx(if)26+b(y)n(ou)f(w)n(an)n(t)g(to)739 4372 y(do)k(more)f(than)h(only)g(simple)+g(w)n(ork.)40 b(When)30 b(y)n(ou)e Fr(get)g Fx(someone's)g(rep)r+(ository)f(from)i(the)739 4472 y(In)n(ternet,)i(y)n(ou)f(are)g+(actually)g(creating)f(a)h(branc)n(h)g(of)h(it.)46 b(It)31+b(ma)n(y)f(\014rst)g(seem)h(ine\016cien)n(t)739 4571+y(\(or)e(if)h(y)n(ou)e(come)h(from)h(CVS|frigh)n(tening\),)g(not)f(to)g+(sa)n(y)g(plain)g(a)n(wkw)n(ard.)41 b(But)29 b(darcs)739+4671 y(is)c(designed)g(this)g(w)n(a)n(y)-7 b(,)24 b(and)h(it)h(has)e+(means)h(to)g(mak)n(e)f(it)i(e\016cien)n(t.)36 b(The)25+b(answ)n(er)f(to)h(man)n(y)739 4770 y(questions)h(ab)r(out)h(ho)n(w)f+(to)h(do)g(a)f(thing)h(with)h(darcs)d(is:)37 b(\\use)26+b(a)g(branc)n(h".)36 b(It)27 b(is)g(a)f(simple)p 739+4842 1146 4 v 831 4896 a Fp(4)866 4920 y Fl(Actually)18+b(it)g(do)r(esn't)h(ha)n(v)n(e)g(to|in)f(theory|,)i(but)f(in)e+(practice)i(it's)f(hard)g(to)h(create)g(\\negativ)n(e")h(\014les)739+4998 y(or)j(lines)g(in)h(the)g(w)n(orking)g(tree.)32+b(See)24 b(the)g(c)n(hapter)h(ab)r(out)g(Theory)f(of)g(patc)n(hes)h+(for)e(other)h(constrain)n(ts.)p eop end+%%Page: 43 43+TeXDict begin 43 42 bop 291 282 a Fu(5.3.)63 b(USING)29+b(P)-7 b(A)g(TCHES)1904 b Fx(43)291 515 y(and)21 b(elegan)n(t)f+(solution)h(with)h(great)e(p)r(o)n(w)n(er)g(and)i(\015exibilit)n(y)-7+b(,)23 b(whic)n(h)e(con)n(tributes)g(to)g(darcs')291+615 y(uncomplicated)27 b(user)g(in)n(terface.)415 716+y(Y)-7 b(ou)41 b(create)f(new)h(branc)n(hes)f(\(i.e.,)45+b(clone)c(rep)r(ositories\))e(with)j(the)f Fr(get)f Fx(and)h+Fr(put)291 816 y Fx(commands.)291 1057 y Fk(5.3.3)112+b(Mo)m(ving)38 b(patc)m(hes)g(around|no)h(v)m(ersions)291+1213 y Fx(P)n(atc)n(hes)23 b(are)h(global,)h(and)g(a)g(cop)n(y)f(of)h+(a)g(patc)n(h)g(either)g(is)g(or)f(is)h(not)g(presen)n(t)g(in)g(a)g+(branc)n(h.)291 1313 y(This)f(w)n(a)n(y)e(y)n(ou)h(can)h(rig)f(a)h+(branc)n(h)f(almost)g(an)n(y)g(w)n(a)n(y)g(y)n(ou)g(lik)n(e,)i(as)e+(long)g(as)h(dep)r(endencies)291 1412 y(are)29 b(ful\014lled|darcs)i+Fs(won)-8 b('t)38 b Fx(let)31 b(y)n(ou)f(break)g(dep)r(endencies.)46+b(If)31 b(y)n(ou)f(susp)r(ect)h(a)g(certain)291 1512+y(feature)20 b(from)h(some)f(time)i(ago)d(in)n(tro)r(duced)i(a)g(bug,)h+(y)n(ou)e(can)h(remo)n(v)n(e)e(the)i(patc)n(h/patc)n(hes)291+1612 y(that)27 b(adds)h(the)g(feature,)f(and)g(try)h(without)g(it.)1795+1581 y Fm(5)415 1713 y Fx(P)n(atc)n(hes)g(are)g(added)i(to)f(a)g(rep)r+(ository)f(with)i Fr(pull)e Fx(and)h(remo)n(v)n(ed)f(from)h(the)h(rep)r+(osi-)291 1812 y(tories)f(with)i Fr(obliterate)p Fx(.)41+b(Don't)31 b(confuse)f(these)g(t)n(w)n(o)g(commands)f(with)i+Fr(record)d Fx(and)291 1912 y Fr(unrecord)p Fx(,)c(whic)n(h)k+(constructs)e(and)i(deconstructs)f(patc)n(hes.)415 2013+y(It)19 b(is)f(imp)r(ortan)n(t)h(not)f(to)g(lose)g(patc)n(hes)g(when)h+(\(re\)mo)n(ving)e(them)i(around.)33 b Fr(pull)17 b Fx(needs)291+2113 y(a)24 b(source)f(rep)r(ository)g(to)h(cop)n(y)g(the)h(patc)n(h)f+(from,)h(whereas)e Fr(obliterate)e Fx(just)k(erases)e(the)291+2212 y(patc)n(h.)35 b(Bew)n(are)24 b(that)h(if)h(y)n(ou)e(obliterate)g+Fs(al)t(l)35 b Fx(copies)24 b(of)h(a)g(patc)n(h)g(it)g(is)g(completely)+g(lost|)291 2312 y(forev)n(er.)34 b(Therefore)25 b(y)n(ou)g(should)g(w)+n(ork)g(with)h(branc)n(hes)e(when)i(y)n(ou)f(obliterate)g(patc)n(hes.)+291 2412 y(The)18 b Fr(obliterate)d Fx(command)k(can)f(wisely)h(b)r(e)g+(disabled)f(in)h(a)g(dedicated)g(main)g(rep)r(ository)291+2511 y(b)n(y)27 b(adding)g Fr(obliterate)39 b(disable)25+b Fx(to)j(the)g(rep)r(ository's)d(defaults)j(\014le.)415+2613 y(F)-7 b(or)33 b(con)n(v)n(enience,)h(there)f(is)h(a)f+Fr(push)f Fx(command.)54 b(It)34 b(w)n(orks)e(lik)n(e)h+Fr(pull)f Fx(but)j(in)f(the)291 2712 y(other)22 b(direction.)35+b(It)23 b(also)e(di\013ers)i(from)f Fr(pull)f Fx(in)i(an)g(imp)r(ortan)+n(t)f(w)n(a)n(y:)33 b(it)23 b(starts)f(a)h(second)291+2812 y(instance)k(of)g(darcs)g(to)g(apply)h(the)g(patc)n(h)f(in)h(the)g+(target)e(rep)r(ository)-7 b(,)26 b(ev)n(en)h(if)h(it's)g(on)g(the)291+2911 y(same)36 b(computer.)66 b(It)38 b(can)f(cause)f(surprises)g(if)i+(y)n(ou)e(ha)n(v)n(e)g(a)h(\\wrong")e(darcs)i(in)g(y)n(our)291+3011 y(P)-7 b(A)g(TH.)291 3252 y Fk(5.3.4)112 b(T)-9+b(ags|v)m(ersions)291 3408 y Fx(While)35 b Fr(pull)e+Fx(and)i Fr(obliterate)30 b Fx(can)35 b(b)r(e)g(used)g(to)f(construct)h+(di\013eren)n(t)g(\\v)n(ersions")d(in)291 3508 y(a)f(rep)r(ository)-7+b(,)31 b(it)h(is)f(often)h(desirable)f(to)g(name)h(sp)r(eci\014c)f+(con\014gurations)f(of)i(patc)n(hes)f(so)291 3608 y(they)d(can)g(b)r(e)+h(iden)n(ti\014ed)g(and)f(retriev)n(ed)f(easily)h(later.)38+b(This)28 b(is)h(ho)n(w)e(darcs)h(implemen)n(ts)291 3707+y(what)d(is)g(usually)g(kno)n(wn)g(as)f(v)n(ersions.)35+b(The)25 b(command)g(for)g(this)h(is)f Fr(tag)p Fx(,)g(and)g(it)h+(records)291 3807 y(a)h(tag)g(in)h(the)g(curren)n(t)e(rep)r(ository)-7+b(.)415 3908 y(A)38 b(tag)f(is)g(just)h(a)f(patc)n(h,)j(but)e(it)g+(only)f(con)n(tains)f(explicit)i(dep)r(endencies.)67+b(It)38 b(will)291 4008 y(dep)r(end)32 b(on)f(all)g(the)g(patc)n(hes)g+(in)h(the)f(curren)n(t)g(rep)r(ository)-7 b(.)2192 3978+y Fm(6)2275 4008 y Fx(Darcs)31 b(can)g(recognize)f(if)h(a)291+4107 y(patc)n(h)c(is)g(as)g(a)g(tag;)h(tags)e(are)h(sometimes)g+(treated)g(sp)r(ecially)g(b)n(y)h(darcs)e(commands.)415+4209 y(While)k(traditional)e(revision)h(con)n(trol)f(systems)g(tag)h(v)+n(ersions)f(in)h(the)h(time)g(line)f(his-)291 4308 y(tory)-7+b(,)28 b(darcs)g(lets)h(y)n(ou)f(tag)h(an)n(y)f(con\014guration)f(of)i+(patc)n(hes)g(at)f(an)n(y)h(time,)h(and)e(pass)h(the)291+4408 y(tags)d(around)h(b)r(et)n(w)n(een)g(branc)n(hes.)415+4509 y(With)37 b(the)e(option)h Fr(--tag)d Fx(to)j Fr(get)e+Fx(y)n(ou)h(can)g(easily)g(get)g(a)g(named)h(v)n(ersion)e(in)i(the)291+4609 y(rep)r(ository)26 b(as)g(a)i(new)f(branc)n(h.)p+291 4684 1146 4 v 383 4738 a Fp(5)418 4762 y Fl(darcs)f(ev)n(en)i(has)e+(a)h(sp)r(ecial)g(command,)g Fo(trackdown)i Fl(that)f(automatically)g+(remo)n(v)n(es)f(patc)n(hes)h(un)n(til)291 4840 y(a)23+b(sp)r(eci\014ed)i(test)g(no)f(longer)f(fails.)383 4896+y Fp(6)418 4920 y Fl(It)e(will)e(omit)i(patc)n(hes)h(already)f(dep)r+(ended)i(up)r(on)e(b)n(y)g(other)g(patc)n(hes,)i(since)e(they)g(will)f+(b)r(e)h(indirectly)291 4998 y(dep)r(ended)k(up)r(on)g(an)n(yw)n(a)n(y)+-6 b(.)p eop end+%%Page: 44 44+TeXDict begin 44 43 bop 739 282 a Fx(44)1466 b Fu(CHAPTER)27+b(5.)64 b(BEST)27 b(PRA)n(CTICES)739 515 y Fk(5.3.5)112+b(Con\015icts)739 669 y Fx(This)26 b(part)h(of)f(darcs)g(b)r(ecomes)g+(a)g(bit)h(complicated,)g(and)f(the)h(description)f(giv)n(en)g(here)g+(is)739 768 y(sligh)n(tly)h(simpli\014ed.)863 868 y(Con\015icting)f+(patc)n(hes)e(are)h(created)g(when)g(y)n(ou)g(record)f(c)n(hanges)g(to)+h(the)h(same)f(line)h(in)739 967 y(t)n(w)n(o)i(di\013eren)n(t)i(rep)r+(ositories.)40 b(Same)29 b(line)g(do)r(es)g Fs(not)37+b Fx(mean)29 b(the)g(same)g(line)g(n)n(um)n(b)r(er)g(and)739+1067 y(\014le)f(name,)f(but)h(the)g(same)f(line)h(added)g(b)n(y)f(a)g+(common)g(dep)r(ended-up)r(on)h(patc)n(h.)863 1167 y(Con)n(trary)34+b(to)i(man)n(y)g(other)f(merging)g(to)r(ols,)j(darcs)d(considers)f(t)n+(w)n(o)i(patc)n(hes)f(mak-)739 1266 y(ing)42 b(the)i+Fs(same)49 b Fx(c)n(hange)42 b(to)g(b)r(e)h(a)g(con\015ict.)82+b(In)43 b(fact,)k(darcs)41 b(do)r(esn't)i(ev)n(en)f(lo)r(ok)g(at)739+1366 y(the)36 b(con)n(ten)n(ts)f(of)h(the)h(con\015icting)e(lines.)62+b(If)36 b(y)n(ou)g(think)g(this)g(is)g(wrong,)h(think)f(ab)r(out)739+1466 y(t)n(w)n(o)g(di\013eren)n(t)g(patc)n(hes)g(eac)n(h)g(adding)g(a)g+(new)h(k)n(eyw)n(ord)d(and)j(also)e(c)n(hanging)g(the)i(line)739+1565 y(\\)p Fr(#define)j(NUM_OF_KEYWORDS)d(17)p Fx(")27+b(to)g(\\)p Fr(#define)41 b(NUM_OF_KEYWORDS)c(18)p Fx(".)863+1665 y(A)22 b(con\015ict)g Fs(happ)l(ens)30 b Fx(when)22+b(t)n(w)n(o)f(con\015icting)g(patc)n(hes)g(meet)h(in)g(the)h(same)e+(rep)r(ository)-7 b(.)739 1764 y(This)25 b(is)g(no)g(problem)g(for)g+(darcs;)g(it)h(can)f(happily)g(pull)h(together)e(just)i(an)n(y)e(patc)n+(hes.)36 b(But)739 1864 y(it)k(is)f(a)g(problem)g(for)g(the)h(\014les)f+(in)h Fs(working)48 b Fx(\(and)40 b Fs(pristine)6 b Fx(\).)74+b(The)39 b(con\015ict)h(can)f(b)r(e)739 1964 y(though)n(t)25+b(of)g(as)g(t)n(w)n(o)f(patc)n(hes)h(telling)g(darcs)f(di\013eren)n(t)i+(things)f(ab)r(out)g(what)g(a)g(\014le)g(should)739 2063+y(lo)r(ok)i(lik)n(e.)863 2163 y(Darcs)39 b(escap)r(es)g(this)h(problem)+f(b)n(y)h(ignoring)e(those)h(parts)2803 2133 y Fm(7)2879+2163 y Fx(of)h(the)g(patc)n(hes)f(that)739 2263 y(con\015ict.)34+b(They)21 b(are)e(ignored)g(in)i Fs(b)l(oth)27 b Fx(patc)n(hes.)34+b(If)20 b(patc)n(h)g(A)h(c)n(hanges)e(the)i(line)f(\\FIXME")739+2362 y(to)29 b(\\FIXED",)f(and)h(patc)n(h)g(B)g(c)n(hanges)f(the)h+(same)g(line)g(to)g(\\DONE",)f(the)i(t)n(w)n(o)e(patc)n(hes)739+2462 y(together)39 b(will)h(pro)r(duce)f(the)h(line)g(\\FIXME".)f+(Darcs)g(do)r(esn't)g(care)g(whic)n(h)h(one)f(y)n(ou)739+2561 y(pulled)24 b(in)n(to)f(the)g(rep)r(ository)f(\014rst,)i(y)n(ou)e+(still)h(get)g(the)h(same)f(result)g(when)g(the)h(con\015icting)739+2661 y(patc)n(hes)j(meet.)37 b(All)28 b(other)f(c)n(hanges)f(made)i(b)n+(y)f(A)h(and)f(B)h(are)e(p)r(erformed)i(as)f(normal.)863+2761 y(Darcs)18 b(can)g(mark)f(a)h(con\015ict)h(for)f(y)n(ou)f(in)i+Fs(working)p Fx(.)35 b(This)18 b(is)g(done)h(with)f Fr(mark-conflicts)p+Fx(.)739 2860 y(Con\015icts)j(are)f(mark)n(ed)g(suc)n(h)g(that)i(b)r+(oth)f(con\015icting)g(c)n(hanges)e(are)h(inserted)h(with)h(sp)r(ecial)+739 2960 y(delimiter)h(lines)f(around)g(them.)36 b(Then)23+b(y)n(ou)f(can)g(merge)g(the)h(t)n(w)n(o)f(c)n(hanges)f(b)n(y)i(hand,)g+(and)739 3060 y(remo)n(v)n(e)j(the)i(delimiters.)863+3159 y(When)39 b(y)n(ou)e(pull)i(patc)n(hes,)h(darcs)d(automatically)g+(p)r(erforms)g(a)h Fr(mark-conflicts)739 3259 y Fx(for)c(y)n(ou)f(if)i+(a)f(con\015ict)g(happ)r(ens.)58 b(Y)-7 b(ou)34 b(can)g(remo)n(v)n(e)f+(the)h(markup)g(with)h Fr(revert)p Fx(,)e(Re-)739 3358+y(mem)n(b)r(er)38 b(that)h(the)h(result)e(will)h(b)r(e)g(the)g(lines)g+(from)f(the)h(previous)f(v)n(ersion)f(common)739 3458+y(to)h(b)r(oth)g(con\015icting)f(patc)n(hes.)67 b(The)38+b(con\015ict)g(marking)f(can)g(b)r(e)h(redone)f(again)g(with)739+3558 y Fr(mark-conflicts)p Fx(.)863 3657 y(A)32 b(sp)r(ecial)e(case)g+(is)h(when)g(a)f(pulled)h(patc)n(h)g(con\015icts)g(with)g(unrecorded)f+(c)n(hanges)f(in)739 3757 y(the)22 b(rep)r(ository)-7+b(.)34 b(The)22 b(con\015ict)g(will)h(b)r(e)f(automatically)g(mark)n+(ed)f(as)g(usual,)i(but)g(since)f(the)739 3857 y(markup)h(is)i+Fs(also)30 b Fx(an)24 b(unrecorded)f(c)n(hange,)h(it)g(will)h(get)f+(mixed)g(in)h(with)f(y)n(our)f(unrecorded)739 3956 y(c)n(hanges.)36+b(There)28 b(is)g(no)f(guaran)n(tee)f(y)n(ou)i(can)f(rev)n(ert)g+Fs(only)36 b Fx(the)28 b(markup)f(after)h(this,)g(and)739+4056 y Fr(resolve)d Fx(will)j(not)h(b)r(e)f(able)g(to)g(redo)f(this)h+(markup)g(later)f(if)i(y)n(ou)e(remo)n(v)n(e)g(it.)38+b(It)29 b(is)f(go)r(o)r(d)739 4155 y(practice)f(to)g(record)f(imp)r+(ortan)n(t)i(c)n(hanges)e(b)r(efore)h(pulling.)863 4255+y Fr(mark-conflicts)d Fx(can't)k(mark)g(complicated)h(con\015icts.)40+b(In)29 b(that)g(case)f(y)n(ou'll)g(ha)n(v)n(e)739 4355+y(to)h(use)g Fr(darcs)41 b(diff)28 b Fx(and)h(other)f(commands)h(to)g+(understand)g(what)g(the)g(con\015ict)g(is)h(all)739+4454 y(ab)r(out.)k(If)18 b(for)g(example)g(t)n(w)n(o)g(con\015icting)g+(patc)n(hes)g(create)f(the)i(same)f(\014le,)i Fr(mark-conflicts)739+4554 y Fx(will)26 b(pic)n(k)f(just)h(one)f(of)h(them,)h(and)e(no)g+(delimiters)h(are)f(inserted.)35 b(So)26 b(w)n(atc)n(h)f(out)g(if)h+(darcs)739 4654 y(tells)i(y)n(ou)e(ab)r(out)i(a)f(con\015ict.)863+4753 y Fr(mark-conflicts)22 b Fx(can)k(also)g(b)r(e)i(used)f(to)f(c)n+(hec)n(k)h(for)f(unresolv)n(ed)g(con\015icts.)36 b(If)27+b(there)739 4853 y(are)33 b(none,)j(darcs)d(replies)h(\\No)g+(con\015icts)g(to)g(resolv)n(e".)55 b(While)35 b Fr(pull)e+Fx(rep)r(orts)g(when)i(a)p 739 4921 1146 4 v 831 4975+a Fp(7)866 4998 y Fl(The)24 b(primitiv)n(e)f(patc)n(hes)i(making)f(up)g+(the)h(total)f(patc)n(h.)p eop end+%%Page: 45 45+TeXDict begin 45 44 bop 291 282 a Fu(5.4.)51 b(DISTRIBUTED)19+b(DEVELOPMENT)e(WITH)i(ONE)f(PRIMAR)-7 b(Y)19 b(DEVELOPER)p+Fx(45)291 515 y(con\015ict)27 b(happ)r(ens,)h Fr(obliterate)23+b Fx(and)28 b Fr(get)e Fx(don't.)291 754 y Fk(5.3.6)112+b(Resolving)38 b(con\015icts)291 909 y Fx(A)30 b(con\015ict)g(is)g+(resolv)n(ed)e(\(not)i(mark)n(ed,)f(as)h(with)g(the)h(command)e+Fr(mark-conflicts)p Fx(\))c(as)291 1009 y(so)r(on)30+b(as)g(some)h(new)g(patc)n(h)g(dep)r(ends)h(on)f(the)g(con\015icting)g+(patc)n(hes.)47 b(This)31 b(will)g(usually)291 1109 y(b)r(e)25+b(the)g(resolv)n(e)e(patc)n(h)h(y)n(ou)g(record)f(after)i(man)n(ually)f+(putting)h(together)f(the)h(pieces)f(from)291 1208 y(the)33+b(con\015ict)g(markup)f(pro)r(duced)h(b)n(y)g Fr(mark-conflicts)27+b Fx(\(or)33 b Fr(pull)p Fx(\).)52 b(But)33 b(it)h(can)e(just)291+1308 y(as)26 b(w)n(ell)i(b)r(e)f(a)g(tag.)37 b(So)27+b(don't)g(forget)g(to)g(\014x)h(con\015icts)f(b)r(efore)g(y)n(ou)g+(acciden)n(tly)g(\\resolv)n(e")291 1407 y(them)h(b)n(y)f(recording)f+(other)h(patc)n(hes.)415 1508 y(If)e(the)g(con\015ict)f(is)g(with)h+(one)f(of)g(y)n(our)f(not-y)n(et-published)h(patc)n(hes,)g(y)n(ou)g(ma)+n(y)f(c)n(ho)r(ose)291 1608 y(to)k(amend)h(that)f(patc)n(h)h(rather)e+(than)i(creating)e(a)i(resolv)n(e)d(patc)n(h.)415 1709+y(If)h(y)n(ou)g(w)n(an)n(t)f(to)h(bac)n(k)f(out)h(and)f(w)n(ait)h(with)+g(the)h(con\015ict,)f(y)n(ou)f(can)h Fr(obliterate)c+Fx(the)291 1808 y(con\015icting)31 b(patc)n(h)g(y)n(ou)f(just)i+(pulled.)49 b(Before)31 b(y)n(ou)f(can)h(do)g(that)h(y)n(ou)f(ha)n(v)n+(e)f(to)h Fr(revert)291 1908 y Fx(the)d(con\015ict)f(markups)g(that)h+Fr(pull)e Fx(inserted)h(when)h(the)g(con\015ict)f(happ)r(ened.)291+2189 y Fq(5.4)135 b(Distributed)52 b(dev)l(elopmen)l(t)i(with)e(one)f+(primary)597 2338 y(dev)l(elop)t(er)291 2522 y Fx(This)24+b(is)g(ho)n(w)f(darcs)g(itself)i(is)f(dev)n(elop)r(ed.)35+b(There)24 b(are)f(man)n(y)h(con)n(tributors)e(to)j(darcs,)e(but)291+2622 y(ev)n(ery)i(con)n(tribution)h(is)g(review)n(ed)f(and)h(man)n+(ually)g(applied)g(b)n(y)h(m)n(yself.)36 b(F)-7 b(or)26+b(this)g(sort)g(of)291 2721 y(a)g(situation,)h Fr(darcs)42+b(send)25 b Fx(is)i(ideal,)g(since)g(the)h(barrier)d(for)h(con)n+(tributions)h(is)g(v)n(ery)f(lo)n(w,)291 2821 y(whic)n(h)h(helps)h+(encourage)d(con)n(tributors.)415 2922 y(One)h(could)f(simply)h(set)g+(the)g Fr(_darcs/prefs/emai)o(l)20 b Fx(v)-5 b(alue)25+b(to)h(the)g(pro)5 b(ject)25 b(mailing)291 3022 y(list,)h(but)f(I)h+(also)e(use)h(darcs)f(send)h(to)g(send)g(m)n(y)g(c)n(hanges)f(to)h(the)+h(main)f(serv)n(er,)f(so)g(instead)291 3121 y(the)18+b(email)h(address)e(is)h(set)g(to)h(\\)p Fr(Davids)40+b(Darcs)i(Repo)g(<droundy@abridg)o(ega)o(me)o(.o)o(rg>)o+Fx(".)291 3221 y(My)27 b Fr(.procmailrc)c Fx(\014le)28+b(on)f(the)h(serv)n(er)e(has)h(the)h(follo)n(wing)f(rule:)291+3392 y Fr(:0)291 3491 y(*)43 b(^TODavids)d(Darcs)h(Repo)291+3591 y(|\(umask)f(022;)i(darcs)g(apply)f(--reply)g(darcs-devel@abri)o+(dg)o(ega)o(me)o(.or)o(g)c(\\)857 3690 y(--repodir)j(/path/to/repo)e+(--verify)j(/path/to/allowe)o(d_k)o(ey)o(s\))291 3860+y Fx(This)30 b(causes)f(darcs)g(apply)g(to)h(b)r(e)h(run)f(on)f(an)n(y)+h(email)f(sen)n(t)h(to)g(\\Da)n(vids)f(Darcs)g(Rep)r(o".)291+3960 y Fr(apply)c Fx(actually)h(applies)h(them)g(only)g(if)g(they)g+(are)f(signed)h(b)n(y)g(an)f(authorized)g(k)n(ey)-7 b(.)37+b(Cur-)291 4059 y(ren)n(tly)-7 b(,)35 b(the)g(only)f(authorized)f(k)n+(ey)h(is)g(mine,)i(but)f(of)f(course)f(this)i(could)f(b)r(e)h(extended)+291 4159 y(easily)26 b(enough.)415 4260 y(The)19 b(cen)n(tral)e(darcs)g+(rep)r(ository)g(con)n(tains)g(the)i(follo)n(wing)e(v)-5+b(alues)18 b(in)h(its)g Fr(_darcs/prefs/de)o(fau)o(lt)o(s)p+Fx(:)291 4430 y Fr(apply)41 b(test)291 4530 y(apply)g(verbose)291+4630 y(apply)g(happy-forwarding)291 4799 y Fx(The)22+b(\014rst)g(line)h(tells)f(apply)g(to)h(alw)n(a)n(ys)d(run)i(the)h+(test)g(suite.)35 b(The)23 b(test)f(suite)h(is)f(in)h(fact)g(the)291+4899 y(main)30 b(reason)f(I)h(use)g(send)h(rather)e(than)i(push,)g+(since)f(it)h(allo)n(ws)e(me)i(to)f(easily)f(con)n(tin)n(ue)291+4998 y(w)n(orking)34 b(\(or)i(put)g(m)n(y)g(computer)g(to)g(sleep\))g+(while)h(the)f(tests)g(are)f(b)r(eing)i(run)f(on)g(the)p+eop end+%%Page: 46 46+TeXDict begin 46 45 bop 739 282 a Fx(46)1466 b Fu(CHAPTER)27+b(5.)64 b(BEST)27 b(PRA)n(CTICES)739 515 y Fx(main)k(serv)n(er.)47+b(The)32 b(second)e(line)i(is)g(just)g(there)f(to)g(impro)n(v)n(e)f+(the)i(email)g(resp)r(onse)e(that)739 615 y(I)i(get)g(when)h(a)f(patc)n+(h)g(has)g(either)g(b)r(een)h(applied)f(or)g(failed)g(the)h(tests.)51+b(The)32 b(third)h(line)739 715 y(mak)n(es)25 b(darcs)g(not)h(complain)+f(ab)r(out)h(unsigned)g(patc)n(hes,)g(but)g(just)h(to)f(forw)n(ard)e+(them)i(to)739 814 y Fr(darcs-devel)p Fx(.)863 914 y(On)36+b(m)n(y)g(dev)n(elopmen)n(t)f(computer,)j(I)e(ha)n(v)n(e)e(in)i(m)n(y)g+Fr(.muttrc)d Fx(the)j(follo)n(wing)f(alias,)739 1013+y(whic)n(h)j(allo)n(ws)e(me)i(to)f(easily)g(apply)h(patc)n(hes)f(that)h+(I)f(get)h(via)f(email)g(directly)h(to)f(m)n(y)739 1113+y(darcs)26 b(w)n(orking)g(directory:)739 1256 y Fr(macro)41+b(pager)h(A)h("<pipe-entry>\(um)o(ask)37 b(022;)42 b(darcs)f(apply)h+(--no-test)e(-v)i(\\)1088 1356 y(--repodir)d(~/darcs\)")739+1625 y Fq(5.5)135 b(Dev)l(elopmen)l(t)38 b(b)l(y)d(a)h(small)g(group)f+(of)h(dev)l(elop)t(ers)1045 1775 y(in)45 b(one)g(o\016ce)739+1957 y Fx(This)28 b(section)g(describ)r(es)g(the)h(dev)n(elopmen)n(t)f+(metho)r(d)h(used)f(for)g(the)h(densit)n(y)f(functional)739+2056 y(theory)17 b(co)r(de)i(DFT++,)h(whic)n(h)e(is)g(a)n(v)-5+b(ailable)17 b(at)i Fr(http://dft.phys)o(ics)o(.c)o(orn)o(el)o(l.)o+(edu)o(/d)o(ft)p Fx(.)863 2156 y(W)-7 b(e)40 b(ha)n(v)n(e)d(a)i(n)n(um)+n(b)r(er)f(of)h(w)n(orkstations)e(whic)n(h)i(all)f(moun)n(t)h(the)h+(same)e Fr(/home)f Fx(via)739 2256 y(NFS.)27 b(W)-7 b(e)27+b(created)f(a)g(sp)r(ecial)g(\\dft")h(user,)f(with)h(the)g(cen)n(tral)f+(rep)r(ository)f(living)h(in)h(that)739 2355 y(user's)i(home)g+(directory)-7 b(.)42 b(The)30 b(ssh)g(public)g(k)n(eys)f(of)g+(authorized)g(p)r(ersons)g(are)g(added)g(to)739 2455+y(the)c(\\dft")g(user's)f Fr(.ssh/allowed_key)o(s)p Fx(,)19+b(and)25 b(w)n(e)g(commit)g(patc)n(hes)f(to)h(this)g(rep)r(ository)739+2554 y(using)i Fr(darcs)42 b(push)p Fx(.)36 b(As)28 b(in)g(Section)g+(5.4,)f(w)n(e)h(ha)n(v)n(e)e(the)j(cen)n(tral)e(rep)r(ository)f(set)i+(to)f(run)739 2654 y(the)h(test)g(suite)g(b)r(efore)f(the)h(push)g(go)r+(es)e(through.)863 2754 y(Note)i(that)g(no)f(one)g(ev)n(er)g(runs)g(as)+g(the)h(dft)h(user.)863 2853 y(A)40 b(subtlet)n(y)f(that)h(w)n(e)f(ran)+f(in)n(to)i(sho)n(w)n(ed)e(up)h(in)h(the)g(running)e(of)i(the)f(test)h+(suite.)739 2953 y(Since)33 b(our)f(test)g(suite)h(includes)g(the)g+(running)f(of)h(MPI)f(programs,)g(it)h(m)n(ust)f(b)r(e)i(run)e(in)739+3053 y(a)39 b(directory)f(that)h(is)h(moun)n(ted)f(across)e(our)i+(cluster.)71 b(T)-7 b(o)39 b(ac)n(hiev)n(e)f(this,)43+b(w)n(e)c(set)g(the)739 3152 y Fr($DARCS_TMPDIR)22 b+Fx(en)n(vironmen)n(t)27 b(v)-5 b(ariable)26 b(to)i Fr(~/tmp)p+Fx(.)863 3252 y(Note)e(that)g(ev)n(en)g(though)f(there)h(are)e(only)i+(four)f(activ)n(e)g(dev)n(elop)r(ers)f(at)i(the)g(momen)n(t,)739+3352 y(the)g(distributed)g(nature)g(of)g(darcs)e(still)j(pla)n(ys)e(a)g+(large)f(role.)36 b(Eac)n(h)25 b(dev)n(elop)r(er)f(w)n(orks)h(on)739+3451 y(a)30 b(feature)g(un)n(til)h(it)g(is)f(stable,)h(a)g(pro)r(cess)e+(that)i(often)f(tak)n(es)g(quite)h(a)f(few)h(patc)n(hes,)f(and)739+3551 y(only)d(once)g(it)h(is)g(stable)f(do)r(es)g(he)h+Fr(push)e Fx(to)h(the)h(cen)n(tral)f(rep)r(ository)-7+b(.)739 3820 y Fq(5.6)135 b(P)l(ersonal)46 b(dev)l(elopmen)l(t)739+4002 y Fx(It's)39 b(easy)e(to)h(ha)n(v)n(e)g(sev)n(eral)f(p)r(ersonal)g+(dev)n(elopmen)n(t)h(trees)g(using)g(darcs,)i(ev)n(en)e(when)739+4102 y(w)n(orking)24 b(on)h(a)g(team)h(or)e(with)i(shared)f(co)r(de.)36+b(The)26 b(n)n(um)n(b)r(er)f(and)g(metho)r(d)h(of)g(using)f(eac)n(h)739+4201 y(p)r(ersonal)e(tree)i(is)f(limited)i(only)e(b)n(y)g(suc)n(h)g+(grand)g(limitations)g(as:)35 b(y)n(our)24 b(disk)g(space,)g(y)n(our)+739 4301 y(imagination,)j(a)n(v)-5 b(ailable)26 b(time,)i(etc.)863+4401 y(F)-7 b(or)34 b(example,)i(if)f(the)g(cen)n(tral)e(darcs)g(rep)r+(ository)g(for)h(y)n(our)f(dev)n(elopmen)n(t)h(team)g(is)739+4500 y Fi(R)802 4512 y Fh(c)836 4500 y Fx(,)29 b(y)n(ou)e(can)i(create)+e(a)h(lo)r(cal)g(w)n(orking)f(directory)g(for)i(feature)f+Fi(f)2830 4512 y Fm(1)2867 4500 y Fx(.)39 b(This)29 b(lo)r(cal)f(w)n+(orking)739 4600 y(directory)23 b(con)n(tains)f(a)i(full)h(cop)n(y)e+(of)g Fi(R)1961 4612 y Fh(c)2019 4600 y Fx(\(as)h(of)g(the)g(time)g(of)+g(the)h(\\darcs)d(get")h(op)r(eration\))739 4700 y(and)32+b(can)g(b)r(e)h(denoted)g Fi(R)1562 4712 y Fm(1)1599+4700 y Fx(.)51 b(In)33 b(the)g(midst)g(of)f(w)n(orking)f(on)h(feature)g+Fi(f)3029 4712 y Fm(1)3066 4700 y Fx(,)i(y)n(ou)d(realize)h(it)739+4799 y(requires)22 b(the)i(dev)n(elopmen)n(t)f(of)h(a)f(separate)f+(feature)h Fi(f)2460 4811 y Fm(2)2497 4799 y Fx(.)36+b(Rather)23 b(than)g(in)n(termingling)g Fi(f)3566 4811+y Fm(1)739 4899 y Fx(and)i Fi(f)939 4911 y Fm(2)1000+4899 y Fx(in)g(the)h(same)e(w)n(orking)f(tree,)i(y)n(ou)f(can)h(create)+f(a)g(new)h(w)n(orking)e(tree)i(for)f(w)n(orking)739+4998 y(on)j Fi(f)895 5010 y Fm(2)932 4998 y Fx(,)h(where)f(that)h(w)n+(orking)e(tree)h(con)n(tains)g(the)h(rep)r(ository)e+Fi(R)2808 5010 y Fm(2)2845 4998 y Fx(.)p eop end+%%Page: 47 47+TeXDict begin 47 46 bop 291 282 a Fu(5.6.)63 b(PERSONAL)27+b(DEVELOPMENT)1431 b Fx(47)415 515 y(While)28 b(w)n(orking)d(on)i+Fi(f)1126 527 y Fm(2)1162 515 y Fx(,)h(other)e(dev)n(elop)r(ers)g(ma)n+(y)g(ha)n(v)n(e)g(made)h(other)f(c)n(hanges;)g(these)291+615 y(c)n(hanges)e(can)h(b)r(e)g(retriev)n(ed)g(on)g(a)g(p)r(er-patc)n+(h)f(selection)h(basis)g(b)n(y)g(p)r(erio)r(dic)g(\\darcs)f(pull")291+715 y(op)r(erations.)415 816 y(When)k(y)n(our)f(w)n(ork)f(on)h+Fi(f)1206 828 y Fm(2)1271 816 y Fx(is)g(completed,)h(y)n(ou)f(can)g+(publish)h(it)g(for)f(the)h(use)g(of)f(other)291 915+y(dev)n(elop)r(ers)g(b)n(y)i(a)g(\\darcs)e(push")i(\(or)g(\\darcs)e+(send"\))i(from)g Fi(R)2308 927 y Fm(2)2374 915 y Fx(to)g+Fi(R)2540 927 y Fh(c)2574 915 y Fx(.)41 b(Indep)r(enden)n(tly)291+1015 y(of)29 b(the)i(publishing)f(of)f Fi(f)1074 1027+y Fm(2)1111 1015 y Fx(,)i(y)n(ou)e(can)g(merge)g(y)n(our)g+Fi(f)1958 1027 y Fm(2)2025 1015 y Fx(w)n(ork)f(in)n(to)i(y)n(our)e+Fi(f)2633 1027 y Fm(1)2700 1015 y Fx(w)n(orking)g(tree)291+1115 y(b)n(y)h(a)h(\\darcs)f(pull)h Fi(R)973 1127 y Fm(2)1010+1115 y Fx(")g(in)h(the)f Fi(R)1390 1127 y Fm(1)1458 1115+y Fx(dev)n(elopmen)n(t)f(tree)h(\(or)f(\\darcs)g(push")h(from)g+Fi(R)3014 1127 y Fm(2)3081 1115 y Fx(to)291 1214 y Fi(R)354+1226 y Fm(1)391 1214 y Fx(\).)415 1315 y(When)23 b(y)n(our)e(w)n(ork)g+(on)h Fi(f)1185 1327 y Fm(1)1245 1315 y Fx(is)g(completed,)i(y)n(ou)d+(publish)i(it)g(as)f(w)n(ell)g(b)n(y)g(a)g(\\darcs)f(push")291+1415 y(from)27 b Fi(R)550 1427 y Fm(1)615 1415 y Fx(to)g+Fi(R)779 1427 y Fh(c)813 1415 y Fx(.)415 1516 y(Y)-7+b(our)18 b(lo)r(cal)g(feature)h(dev)n(elopmen)n(t)f(e\013orts)g(for)g+Fi(f)1942 1528 y Fm(1)1997 1516 y Fx(or)g Fi(f)2131 1528+y Fm(2)2187 1516 y Fx(can)g(eac)n(h)g(consist)g(of)g(m)n(ultiple)291+1616 y(patc)n(hes.)52 b(When)34 b(pushing)f(or)f(pulling)h(to)g(other)f+(trees,)i(these)f(patc)n(hes)g(can)f(either)h(all)291+1715 y(b)r(e)d(selected)h(or)e(sp)r(eci\014c)i(patc)n(hes)e(can)h(b)r+(e)h(selected.)45 b(Th)n(us,)31 b(if)g(y)n(ou)f(in)n(tro)r(duce)g(a)g+(set)g(of)291 1815 y(debugging)23 b(calls)h(in)n(to)g(the)g(co)r(de,)h+(y)n(ou)f(can)f(commit)i(the)g(debugging)e(co)r(de)h(in)h(a)e+(distictly)291 1915 y(separate)j(patc)n(h)h(\(or)g(patc)n(hes\))g(that)+h(y)n(ou)f(will)h(not)f(push)h(to)g Fi(R)2316 1927 y+Fh(c)2350 1915 y Fx(.)291 2155 y Fk(5.6.1)112 b(Priv)-6+b(ate)37 b(patc)m(hes)291 2311 y Fx(As)22 b(discussed)f(in)i(the)f+(section)g(ab)r(o)n(v)n(e,)g(a)f(dev)n(elop)r(er)g(ma)n(y)h(ha)n(v)n(e)+f(v)-5 b(arious)20 b(c)n(hanges)h(to)h(their)291 2411+y(lo)r(cal)j(dev)n(elopmen)n(t)g(rep)r(ositories)g(that)h(they)g(do)g+(not)g(ev)n(er)e(wish)i(to)g(publish)h(to)e(a)h(group)291+2511 y(rep)r(ository)d(\(e.g.)36 b(p)r(ersonal)24 b(debugging)g(co)r+(de\),)i(but)g(whic)n(h)f(they)g(w)n(ould)g(lik)n(e)g(to)g(k)n(eep)g+(in)291 2610 y(their)i(lo)r(cal)g(rep)r(ository)-7 b(,)26+b(and)i(p)r(erhaps)f(ev)n(en)g(share)f(amongst)h(their)g(lo)r(cal)g+(rep)r(ositories.)415 2711 y(This)h(is)g(easily)f(done)g(via)h(darcs,)f+(since)g(those)h(priv)-5 b(ate)27 b(c)n(hanges)g(can)g(b)r(e)h+(committed)291 2811 y(in)35 b(patc)n(hes)g(that)h(are)f(separate)f+(from)h(other)g(patc)n(hes;)k(during)c(the)h(pro)r(cess)f(of)g(push-)+291 2911 y(ing)28 b(patc)n(hes)h(to)g(the)g(common)g(rep)r(ository)e+(\()p Fi(R)1800 2923 y Fh(c)1834 2911 y Fx(\),)j(the)g(dev)n(elop)r(er)+e(is)h(queried)f(for)h(whic)n(h)291 3010 y(patc)n(hes)e(should)g(b)r(e)+h(mo)n(v)n(ed)e(to)i(\()p Fi(R)1422 3022 y Fh(c)1456+3010 y Fx(\))g(on)f(a)h(patc)n(h-b)n(y-patc)n(h)d(basis.)415+3111 y(The)31 b Fr(--complement)c Fx(\015ag)j(for)g(the)i(\\darcs)e+(pull")h(op)r(eration)f(can)g(further)h(simplify)291+3211 y(this)25 b(e\013ort.)36 b(If)26 b(the)g(dev)n(elop)r(er)e(copies)+h(\(via)g(\\darcs)f(push")h(or)g(\\darcs)e(pull"\))j(all)f(priv)-5+b(ate)291 3311 y(patc)n(hes)40 b(in)n(to)h(a)g(sp)r(ecial)g(rep)r+(ository/w)n(orking)c(tree)k(\()p Fi(R)2160 3323 y Fh(p)2199+3311 y Fx(\),)k(then)c(those)g(patc)n(hes)g(are)291 3410+y(easily)27 b(disregarded)g(for)h(pulling)g(b)n(y)h(adding)f+Fr(--complement)23 b Fx(to)29 b(the)f(\\darcs)f(pull")i(line)291+3510 y(and)e(listing)h Fi(R)765 3522 y Fh(p)831 3510+y Fx(after)f(the)h(primary)e(source)h(rep)r(ository)-7+b(.)415 3611 y(The)36 b Fr(--complement)c Fx(\015ag)j(is)h(only)g(a)n+(v)-5 b(ailable)35 b(for)h(\\darcs)f(pull",)j(and)e(not)h(\\darcs)291+3711 y(push")j(or)f(\\darcs)g(send",)44 b(requiring)39+b(the)i(user)f(to)g(ha)n(v)n(e)f(pull)i(access)f(to)g(the)h(target)291+3810 y(rep)r(ository)-7 b(.)32 b(While)21 b(the)f(actual)f(public)h+(rep)r(ository)e(is)i(often)g(not)g(shared)e(in)i(this)g(manner,)291+3910 y(it's)k(simple)h(to)f(create)f(a)h(lo)r(cal)g(v)n(ersion)e(of)j+(the)f(public)h(rep)r(ository)e(to)h(act)g(as)f(the)i(staging)291+4010 y(area)h(for)h(that)h(public)g(rep)r(ository)-7+b(.)415 4111 y(The)26 b(follo)n(wing)e(example)h(extends)g(the)h(t)n(w)+n(o)f(feature)g(addition)g(example)g(in)h(the)g(pre-)291+4210 y(vious)18 b(section)i(using)f(a)g(lo)r(cal)g(staging)f(rep)r+(ository)g(\()p Fi(R)1983 4222 y Fh(l)2009 4210 y Fx(\))i(and)f(a)g+(priv)-5 b(ate)19 b(patc)n(h)g(rep)r(ository:)291 4401+y Fr($)43 b(cd)g(working-dir)291 4500 y($)g(darcs)e(get)i+(http://server/r)o(epo)o(s/)o(Rc)37 b(Rl)291 4700 y($)43+b(darcs)e(get)i(Rl)f(R1)291 4799 y($)h(cd)g(R1)291 4899+y(...development)37 b(of)43 b(f1)291 4998 y($)g(darcs)e(record)g+(-m'p1:)g(f1)i(initial)e(work')p eop end+%%Page: 48 48+TeXDict begin 48 47 bop 739 282 a Fx(48)1466 b Fu(CHAPTER)27+b(5.)64 b(BEST)27 b(PRA)n(CTICES)739 515 y Fr(...)739+615 y($)43 b(darcs)f(record)f(-m'p2:)g(my)i(debugging)c(tracepoints')+739 715 y(...)739 914 y($)k(cd)g(..)739 1013 y($)g(darcs)f(get)g+(http://server/re)o(po)o(s/R)o(c)37 b(R2)739 1113 y($)43+b(cd)g(R2)739 1213 y($)g(darcs)f(pull)g(-p)g(p2)h(../R1)739+1312 y(...)f(development)d(of)k(f2)739 1412 y($)g(darcs)f(record)f+(-m'p3:)g(f2)i(finished')739 1611 y($)g(cd)g(..)739 1711+y($)g(darcs)f(get)g(Rl)h(Rp)739 1810 y($)g(cd)g(Rp)739+1910 y($)g(darcs)f(pull)g(-p)g(p2)h(../R2)739 2109 y($)g(cd)g(../Rl)739+2209 y($)g(darcs)f(pull)g(--complement)c(../R2)k(../Rp)739+2309 y($)h(darcs)f(send)739 2408 y(...)g(for)h(publishing)c(f2)k+(patches)d(to)j(Rc)739 2607 y($)g(cd)g(../R1)739 2707+y($)g(darcs)f(pull)g(../R2)739 2807 y(...)g(updates)f(R1)i(with)f(f2)g+(changes)f(from)h(R2)739 2906 y(...)g(more)g(development)d(of)k(f1)739+3006 y($)g(darcs)f(record)f(-m'p4:)g(f1)i(feature)d(finished.')739+3205 y($)j(cd)g(../Rl)739 3305 y($)g(darcs)f(pull)g(--complement)c+(../R1)k(../Rp)739 3404 y($)h(darcs)f(send)p eop end+%%Page: 49 49+TeXDict begin 49 48 bop 291 1165 a Ft(Chapter)64 b(6)291+1607 y Fw(Darcs)77 b(commands)291 2065 y Fx(The)27 b(general)f(format)h+(of)h(a)f(darcs)g(command)g(is)291 2339 y Fr(\045)43+b(darcs)e(COMMAND)g(OPTIONS)g(ARGUMENTS)f(...)291 2585+y Fx(Here)28 b Fr(COMMAND)d Fx(is)k(a)f(command)g(suc)n(h)g(as)g+Fr(add)f Fx(or)h Fr(record)p Fx(,)e(whic)n(h)j(of)f(course)f(ma)n(y)h+(ha)n(v)n(e)291 2685 y(one)19 b(or)g(more)g(argumen)n(ts.)32+b(Options)20 b(ha)n(v)n(e)e(the)i(form)g Fr(--option)c+Fx(or)j Fr(-o)p Fx(,)h(while)g(argumen)n(ts)291 2784+y(v)-5 b(ary)28 b(from)g(command)h(to)f(command.)41 b(There)28+b(are)g(man)n(y)g(options)h(whic)n(h)g(are)e(common)291+2884 y(to)g(a)g(n)n(um)n(b)r(er)h(of)f(di\013eren)n(t)h(commands,)f+(whic)n(h)g(will)h(b)r(e)g(summarized)f(here.)415 3011+y(If)22 b(y)n(ou)f(wish,)j(y)n(ou)d(ma)n(y)g(use)g(an)n(y)h(unam)n+(biguous)e(b)r(eginning)i(of)g(a)f(command)h(name)g(as)291+3110 y(a)k(shortcut:)36 b(for)26 b Fr(darcs)42 b(record)p+Fx(,)24 b(y)n(ou)i(could)h(t)n(yp)r(e)g Fr(darcs)41 b(recor)25+b Fx(or)h Fr(darcs)41 b(rec)p Fx(,)26 b(but)291 3210+y(not)c Fr(darcs)41 b(re)22 b Fx(since)g(that)h(could)f(b)r(e)h+(confused)f(with)h Fr(darcs)41 b(replace)p Fx(,)21 b+Fr(darcs)41 b(revert)291 3309 y Fx(and)27 b Fr(darcs)42+b(remove)p Fx(.)415 3436 y(In)36 b(some)f(cases,)i Fr(COMMAND)c+Fx(actually)i(consists)g(of)g(t)n(w)n(o)g(w)n(ords,)i(a)e(sup)r+(er-command)291 3535 y(and)24 b(a)h(sub)r(command.)35+b(F)-7 b(or)25 b(example,)g(the)g(\\displa)n(y)e(the)i(manifest")g+(command)f(has)h(the)291 3635 y(form)i Fr(darcs)41 b(query)h(manifest)p+Fx(.)291 3993 y Fv(Command)26 b(o)m(v)m(erview)83 b Fx(Not)23+b(all)g(commands)g(mo)r(dify)g(the)h(\\patc)n(hes")d(of)i(y)n(our)f+(rep)r(os-)291 4093 y(itory)27 b(\(that)i(is,)f(the)h(named)f(patc)n+(hes)g(whic)n(h)g(other)f(users)h(can)g(pull\);)h(some)f(commands)291+4192 y(only)f(a\013ect)h(the)h(cop)n(y)e(of)h(the)g(source)f(tree)g(y)n+(ou're)g(w)n(orking)f(on)i(\(y)n(our)f(\\w)n(orking)f(direc-)291+4292 y(tory"\),)32 b(and)g(some)f(a\013ect)h(b)r(oth.)51+b(This)32 b(table)g(summarizes)f(what)h(y)n(ou)g(should)g(exp)r(ect)291+4392 y(from)19 b(eac)n(h)g(one)h(and)g(will)g(hop)r(efully)g(serv)n(e)f+(as)g(guide)h(when)g(y)n(ou're)f(ha)n(ving)g(doubts)h(ab)r(out)291+4491 y(whic)n(h)27 b(command)g(to)h(use.)p 291 4842 1146+4 v 383 4896 a Fp(1)418 4919 y Fl(But)c(it)f(a\013ects)i(the)g(rep)r+(ository)f(and)g(w)n(orking)f(directory)h(targeted)i(b)n(y)e(the)g+(push)383 4975 y Fp(2)418 4998 y Fl(As)f(for)g(the)h(other)h(end,)e+(see)i(apply)1681 5208 y Fx(49)p eop end+%%Page: 50 50+TeXDict begin 50 49 bop 739 282 a Fx(50)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)p 1394 436 1555 4+v 1392 535 4 100 v 1502 505 a Fx(a\013ects)p 1838 535+V 158 w(patc)n(hes)p 2208 535 V 99 w(w)n(orking)e(directory)p+2947 535 V 1394 539 1555 4 v 1392 638 4 100 v 1503 608+a(record)p 1838 638 V 238 w(y)n(es)p 2208 638 V 454 w(no)p+2947 638 V 1394 641 1555 4 v 1392 741 4 100 v 1457 711+a(unrecord)p 1838 741 V 192 w(y)n(es)p 2208 741 V 454+w(no)p 2947 741 V 1394 744 1555 4 v 1392 844 4 100 v+1473 814 a(rollbac)n(k)p 1838 844 V 208 w(y)n(es)p 2208+844 V 442 w(y)n(es)p 2947 844 V 1394 847 1555 4 v 1392+947 4 100 v 1510 917 a(rev)n(ert)p 1838 947 V 257 w(no)p+2208 947 V 454 w(y)n(es)p 2947 947 V 1394 950 1555 4+v 1392 1050 4 100 v 1464 1020 a(unrev)n(ert)p 1838 1050+V 211 w(no)p 2208 1050 V 454 w(y)n(es)p 2947 1050 V 1394+1053 1555 4 v 1392 1153 4 100 v 1547 1123 a(pull)p 1838+1153 V 284 w(y)n(es)p 2208 1153 V 442 w(y)n(es)p 2947+1153 V 1394 1156 1555 4 v 1392 1256 4 100 v 1443 1226+a(obliterate)p 1838 1256 V 179 w(y)n(es)p 2208 1256 V+442 w(y)n(es)p 2947 1256 V 1394 1259 1555 4 v 1392 1359+4 100 v 1516 1329 a(apply)p 1838 1359 V 252 w(y)n(es)p+2208 1359 V 442 w(y)n(es)p 2947 1359 V 1394 1362 1555+4 v 1392 1462 4 100 v 1512 1432 a(push)1683 1402 y Fm(1)p+1838 1462 V 1981 1432 a Fx(no)p 2208 1462 V 466 w(no)p+2947 1462 V 1394 1465 1555 4 v 1392 1565 4 100 v 1517+1535 a(send)1679 1505 y Fm(2)p 1838 1565 V 1981 1535+a Fx(no)p 2208 1565 V 466 w(no)p 2947 1565 V 1394 1568+1555 4 v 1392 1668 4 100 v 1536 1638 a(put)1660 1608+y Fm(3)p 1838 1668 V 1981 1638 a Fx(no)p 2208 1668 V+466 w(no)p 2947 1668 V 1394 1671 1555 4 v 739 1898 a+Fq(6.1)135 b(Common)46 b(options)f(to)g(darcs)g(commands)p+975 2084 2392 4 v 975 2158 a Fr(--help)p 975 2213 V 739+2404 a Fx(Ev)n(ery)29 b Fr(COMMAND)e Fx(accepts)j Fr(--help)e+Fx(as)i(an)g(argumen)n(t,)g(whic)n(h)g(tells)h(it)f(to)h(pro)n(vide)e+(a)h(bit)739 2504 y(of)j(help.)54 b(Among)33 b(other)g(things,)h(this)g+(help)f(alw)n(a)n(ys)e(pro)n(vides)h(an)h(accurate)f(listing)h(of)739+2603 y(the)28 b(options)e(a)n(v)-5 b(ailable)26 b(with)i(that)g+(command,)f(and)g(is)g(guaran)n(teed)f(nev)n(er)g(to)h(b)r(e)h(out)f+(of)739 2703 y(sync)i(with)i(the)f(v)n(ersion)e(of)i(darcs)f(y)n(ou)g+(actually)g(ha)n(v)n(e)g(installed)h(\(unlik)n(e)g(this)g(man)n(ual,)+739 2803 y(whic)n(h)d(could)h(b)r(e)g(for)f(an)g(en)n(tirely)g+(di\013eren)n(t)h(v)n(ersion)e(of)i(darcs\).)739 2977+y Fr(\045)43 b(darcs)f(COMMAND)e(--help)p 975 3168 V+975 3242 a(--disable)p 975 3279 V 739 3470 a Fx(Ev)n(ery)17+b Fr(COMMAND)e Fx(accepts)j(the)h Fr(--disable)14 b Fx(option,)20+b(whic)n(h)f(can)f(b)r(e)g(used)h(in)f Fr(_darcs/prefs/defa)o(ult)o(s)+739 3569 y Fx(to)25 b(disable)g(some)g(commands)f(in)i(the)g(rep)r+(ository)-7 b(.)34 b(This)26 b(can)e(b)r(e)i(helpful)g(if)g(y)n(ou)f(w)+n(an)n(t)f(to)739 3669 y(protect)19 b(the)i(rep)r(ository)d(from)i+(acciden)n(tal)f(use)h(of)g(adv)-5 b(anced)19 b(commands)g(lik)n(e)h+(obliterate,)739 3768 y(unpull,)28 b(unrecord)f(or)f(amend-record.)p+975 3959 V 975 4034 a Fr(--verbose,)40 b(--quiet,)g(--normal-verbosi)o+(ty)p 975 4089 V 739 4280 a Fx(Most)25 b(commands)f(also)g(accept)h+(the)h Fr(--verbose)21 b Fx(option,)26 b(whic)n(h)f(tells)g(darcs)f(to)+h(pro)n(vide)739 4379 y(additional)e(output.)36 b(The)23+b(amoun)n(t)g(of)g(v)n(erb)r(osit)n(y)e(v)-5 b(aries)23+b(from)g(command)f(to)i(command.)739 4479 y(Commands)g(that)h(accept)g+Fr(--verbose\\verb)19 b Fx(also)24 b(accept)h Fr(--quiet\\verb)p+Fx(,)20 b(whic)n(h)25 b(sur-)739 4578 y(presses)e(non-error)e(output,)k+(and)f Fr(--normal-verbosi)o(ty\\)o(ve)o(rb)18 b Fx(whic)n(h)24+b(can)f(b)r(e)h(used)g(to)739 4678 y(restore)i(the)i(default)g(v)n(erb)+r(osit)n(y)e(if)i Fr(--verbose)c Fx(or)j Fr(--quiet)e+Fx(is)i(in)h(the)g(defaults)g(\014le.)p 975 4869 V 975+4944 a Fr(--debug)p 975 4998 V eop end+%%Page: 51 51+TeXDict begin 51 50 bop 291 282 a Fu(6.1.)63 b(COMMON)28+b(OPTIONS)e(TO)h(D)n(AR)n(CS)h(COMMANDS)767 b Fx(51)291+515 y(Man)n(y)19 b(commands)h(also)g(accept)g(the)g Fr(--debug)e+Fx(option,)k(whic)n(h)e(causes)g(darcs)f(to)h(generate)291+615 y(additional)38 b(output)h(that)g(ma)n(y)f(b)r(e)h(useful)g(for)g+(debugging)e(its)i(b)r(eha)n(vior,)i(but)e(whic)n(h)291+715 y(otherwise)26 b(w)n(ould)h(not)h(b)r(e)g(in)n(teresting.)p+527 895 2392 4 v 527 969 a Fr(--repodir)p 527 1024 V+291 1205 a Fx(Another)i(common)f(option)h(is)h(the)f+Fr(--repodir)d Fx(option,)k(whic)n(h)f(allo)n(ws)f(y)n(ou)g(to)i(sp)r+(ecify)291 1304 y(the)e(directory)e(of)h(the)h(rep)r(ository)e(in)i+(whic)n(h)g(to)f(p)r(erform)g(the)h(command.)40 b(This)28+b(option)291 1404 y(is)e(used)g(with)h(commands,)f(suc)n(h)g(as)g+(whatsnew,)g(that)h(ordinarily)e(w)n(ould)h(b)r(e)g(p)r(erformed)291+1503 y(within)33 b(a)f(rep)r(ository)f(directory)-7 b(,)32+b(and)g(allo)n(ws)f(y)n(ou)h(to)g(use)h(those)f(commands)f(without)291+1603 y(actually)g(b)r(eing)h(in)h(the)g(rep)r(ository)d(directory)h+(when)h(calling)g(the)h(command.)50 b(This)32 b(is)291+1703 y(useful)27 b(when)h(running)f(darcs)f(in)i(a)f(pip)r(e,)h(as)e+(migh)n(t)h(b)r(e)h(the)g(case)e(when)i(running)f Fr(apply)291+1802 y Fx(from)g(a)g(mailer.)p 527 1983 V 527 2057 a+Fr(--remote-repo)p 527 2112 V 415 2292 a Fx(Some)j(commands,)g(suc)n(h)+g(as)g Fr(pull)f Fx(require)g(a)h(remote)f(rep)r(ository)g(to)h(b)r(e)h+(sp)r(eci\014ed,)291 2392 y(either)k(from)g(the)h(command)g(line)g(or)e+(as)h(a)h(default.)61 b(The)36 b Fr(--remote-repo)30+b Fx(pro)n(vides)291 2492 y(an)38 b(alternativ)n(e)g(w)n(a)n(y)f(to)i+(supply)g(this)g(remote)f(rep)r(ository)f(path.)70 b(This)39+b(\015ag)f(can)h(b)r(e)291 2591 y(seen)d(as)g(temp)r(orarily)g+(\\replacing")f(the)i(default)h(rep)r(ository)-7 b(.)63+b(Setting)37 b(it)h(causes)e(the)291 2691 y(command)25+b(to)g(ignore)g(the)h(default)g(rep)r(ository)e(\(it)j(also)d(do)r(es)i+(not)f(a\013ect,)i(i.e.)36 b(o)n(v)n(erwrite)291 2791+y(the)21 b(default)g(rep)r(ository\).)33 b(On)21 b(the)g(other)g(hand,)+h(if)f(an)n(y)f(other)h(rep)r(ositories)e(are)h(supplied)291+2890 y(as)h(command)h(line)g(argumen)n(ts,)g(this)g(\015ag)g(will)g(b)r+(e)g(ignored)f(\(and)i(the)f(default)h(rep)r(ository)291+2990 y(ma)n(y)j(b)r(e)i(o)n(v)n(erwritten\).)291 3205+y Fv(Selecting)f(patc)m(hes)83 b Fx(Man)n(y)24 b(commands)g(op)r(erate)+f(on)h(a)g(patc)n(h)g(or)g(patc)n(hes)f(that)i(ha)n(v)n(e)291+3305 y(already)18 b(b)r(een)h(recorded.)33 b(There)19+b(are)f(a)h(n)n(um)n(b)r(er)h(of)f(options)g(that)g(sp)r(ecify)h(whic)n+(h)g(patc)n(hes)291 3404 y(are)34 b(selected)i(for)f(these)h(op)r+(erations:)52 b Fr(--patch)p Fx(,)35 b Fr(--match)p Fx(,)g+Fr(--tag)p Fx(,)h(and)g(v)-5 b(arian)n(ts)34 b(on)291+3504 y(these,)25 b(whic)n(h)f(for)g Fr(--patch)e Fx(are)h+Fr(--patches)p Fx(,)f Fr(--from-patch)p Fx(,)e(and)k+Fr(--to-patch)p Fx(.)32 b(The)291 3604 y Fr(--patch)f+Fx(and)k Fr(--tag)e Fx(forms)h(simply)h(tak)n(e)e(\(POSIX)i(extended,)i+(ak)-5 b(a)34 b Fr(egrep)p Fx(\))f(regular)291 3703 y(expressions)26+b(and)i(matc)n(h)g(them)g(against)f(tag)g(and)h(patc)n(h)g(names.)38+b Fr(--match)p Fx(,)25 b(describ)r(ed)291 3803 y(b)r(elo)n(w,)i(allo)n+(ws)f(more)h(p)r(o)n(w)n(erful)g(patterns.)415 3903 y(The)i(plural)e+(forms)h(of)h(these)f(options)g(select)g(all)g(matc)n(hing)g(patc)n+(hes.)39 b(The)28 b(singular)291 4002 y(forms)36 b(select)i(the)f(last)+h(matc)n(hing)e(patc)n(h.)67 b(The)37 b(range)f(\(from)h(and)h(to\))f+(forms)g(select)291 4102 y(patc)n(hes)27 b(after)g(or)f(up)i(to)g(\(b)r+(oth)g(inclusiv)n(e\))g(the)g(last)f(matc)n(hing)g(patc)n(h.)415+4201 y(These)g(options)g(use)g(the)g(curren)n(t)g(order)f(of)h(patc)n+(hes)f(in)i(the)f(rep)r(ository)-7 b(.)36 b(darcs)26+b(ma)n(y)291 4301 y(reorder)i(patc)n(hes,)j(so)f(this)h(is)g(not)f+(necessarily)f(the)i(order)e(of)i(creation)f(or)f(the)i(order)f(in)291+4401 y(whic)n(h)25 b(patc)n(hes)g(w)n(ere)g(applied.)36+b(Ho)n(w)n(ev)n(er,)24 b(as)h(long)g(as)g(y)n(ou)g(are)f(just)j+(recording)d(patc)n(hes)291 4500 y(in)j(y)n(our)g(o)n(wn)g(rep)r+(ository)-7 b(,)26 b(they)i(will)f(remain)g(in)h(order.)415+4600 y(When)h(a)f(patc)n(h)g(or)f(a)h(group)f(of)h(patc)n(hes)g(is)g+(selected,)g(all)g(patc)n(hes)g(they)g(dep)r(end)h(on)291+4700 y(get)f(silen)n(tly)h(selected)g(to)r(o.)41 b(F)-7+b(or)29 b(example:)39 b Fr(darcs)j(pull)g(--patches)e(bugfix)26+b Fx(means)291 4799 y(\\pull)31 b(all)g(the)h(patc)n(hes)e(with)i+(`bug\014x')f(in)h(their)f(name,)h(along)f(with)g(an)n(y)g(patc)n(hes)g+(they)291 4899 y(require.")i(If)23 b(y)n(ou)f(really)g(only)g(w)n(an)n+(t)g(patc)n(hes)g(with)h(`bug\014x')g(in)g(their)g(name,)g(y)n(ou)f+(should)291 4998 y(use)38 b(the)h Fr(--no-deps)c Fx(option,)41+b(whic)n(h)e(mak)n(es)e(darcs)h(exclude)g(an)n(y)g(matc)n(hed)h(patc)n+(hes)p eop end+%%Page: 52 52+TeXDict begin 52 51 bop 739 282 a Fx(52)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)739 515 y Fx(from)k(the)g+(selection)f(whic)n(h)h(ha)n(v)n(e)f(dep)r(endencies)h(that)h(are)e+(themselv)n(es)g(not)h(explicitly)739 615 y(matc)n(hed)27+b(b)n(y)h(the)g(selection.)863 715 y(F)-7 b(or)22 b Fr(unrecord)p+Fx(,)e Fr(unpull)g Fx(and)i Fr(obliterate)p Fx(,)d(patc)n(hes)j(that)g+(dep)r(end)h(on)f(the)g(selected)739 814 y(patc)n(hes)40+b(are)f(silen)n(tly)i(included,)j(or)c(if)h Fr(--no-deps)c+Fx(is)k(used)f(selected)h(patc)n(hes)f(with)739 914 y(dep)r(endencies)+28 b(on)f(not)h(selected)f(patc)n(hes)g(are)g(excluded)g(from)h(the)g+(selection.)739 1128 y Fv(Matc)m(h)84 b Fx(Curren)n(tly)24+b Fr(--match)e Fx(accepts)j(\014v)n(e)f(primitiv)n(e)h(matc)n(h)g(t)n+(yp)r(es,)g(although)f(there)739 1228 y(are)31 b(plans)h(to)g(expand)g+(it)h(to)f(matc)n(h)g(more)f(patterns.)51 b(Also,)33+b(note)f(that)g(the)h(syn)n(tax)e(is)739 1328 y(still)d(preliminary)e+(and)i(sub)5 b(ject)28 b(to)f(c)n(hange.)863 1427 y(The)36+b(\014rst)f(matc)n(h)h(t)n(yp)r(e)g(accepts)f(a)g(literal)g(string)g+(whic)n(h)g(is)h(c)n(hec)n(k)n(ed)e(against)h(the)739+1527 y(patc)n(h)27 b(name.)37 b(The)28 b(syn)n(tax)e(is)739+1687 y Fr(darcs)41 b(annotate)g(--summary)f(--match)g('exact)h+(foo+bar')739 1847 y Fx(This)27 b(is)g(useful)g(for)g(situations)f+(where)h(a)g(patc)n(h)f(name)h(con)n(tains)f(c)n(haracters)f(that)i+(could)739 1946 y(b)r(e)h(considered)e(sp)r(ecial)i(for)f(regular)f+(expressions.)863 2046 y(In)f(this)g(and)f(the)h(other)f(matc)n(h)h(t)n+(yp)r(es,)g(the)g(argumen)n(t)e(m)n(ust)i(b)r(e)g(enclosed)f(in)g+(double)739 2146 y(quotes)39 b(if)h(it)g(con)n(tains)e(spaces.)71+b(Y)-7 b(ou)40 b(can)f(escap)r(e)g(a)g(quote)g(in)h(the)f(argumen)n(t)g+(with)739 2245 y(a)31 b(bac)n(kslash;)g(bac)n(kslash)e(escap)r(es)i+(itself,)h(but)g(it)g(is)f(treated)g(literally)f(if)i(follo)n(w)n(ed)e+(b)n(y)h(a)739 2345 y(c)n(haracter)20 b(other)i(than)h(a)f(double)h+(quote)f(or)g(bac)n(kslash,)g(so)g(it)h(is)f(t)n(ypically)g(not)h+(necessary)739 2445 y(to)35 b(escap)r(e)g(a)h(bac)n(kslash.)59+b(No)35 b(suc)n(h)h(escaping)e(is)i(necessary)d(unless)j(the)g(argumen)+n(t)e(is)739 2544 y(enclosed)27 b(in)h(double)f(quotes.)863+2644 y(The)22 b(second)g(matc)n(h)f(t)n(yp)r(e)h(accepts)f(a)h(regular)+e(expression)g(whic)n(h)i(is)g(c)n(hec)n(k)n(ed)e(against)739+2743 y(the)28 b(patc)n(h)f(name.)37 b(The)28 b(syn)n(tax)e(is)739+2903 y Fr(darcs)41 b(annotate)g(--summary)f(--match)g('name)i(foo')739+3063 y Fx(Note)34 b(that)g(to)g(matc)n(h)g(regexp)f(metac)n(haracters,)+h(suc)n(h)f(as)h Fr(\()p Fx(,)h(literally)-7 b(,)35 b(they)g(m)n(ust)f+(b)r(e)739 3163 y(escap)r(ed)e(with)h(bac)n(kslash)e(along)g(with)i(an)+n(y)e(em)n(b)r(edded)i(double)g(quotes.)50 b(T)-7 b(o)32+b(matc)n(h)h(a)739 3263 y(literal)j(bac)n(kslash)f(it)h(m)n(ust)h(b)r+(e)g(written)g(quadrupled)e(in)i(general,)g(but)h(often)e(it)h(need)739+3362 y(not)i(b)r(e)h(escap)r(ed,)i(since)d(bac)n(kslash)f(is)h(only)g+(sp)r(ecial)g(in)h(regexps)e(when)h(follo)n(w)n(ed)g(b)n(y)739+3462 y(a)e(metac)n(haracter.)63 b(In)37 b(the)h(follo)n(wing)e(example)+h(pairs,)h(the)g(\014rst)f(literal)f(is)h(matc)n(hed)739+3562 y(b)n(y)30 b(the)h(second)f(sequence)g(in)h(the)g(matc)n(h)f+(name:)43 b(\\)p Fr(")p Fx(":\\)p Fr(\\")p Fx(",)28 b(\\)p+Fr(\\)p Fx(":\\)p Fr(\\\\\\\\)p Fx(",)g(\\)p Fr(\\x)p+Fx(":\\)p Fr(\\x)p Fx(",)739 3661 y(\\)p Fr(\()p Fx(":\\)p+Fr(\\\()p Fx(".)863 3761 y(The)g(third)g(matc)n(h)f(t)n(yp)r(e)h(matc)n+(hes)f(the)h(darcs)f(hash)g(for)g(eac)n(h)g(patc)n(h:)739+3921 y Fr(darcs)41 b(annotate)g(--summary)f(--match)g(\\)826+4020 y('hash)i(20040403105958-)o(53a)o(90)o(-c)o(719)o(56)o(7e9)o(2c)o+(3b0)o(ab)o(9e)o(ddd)o(52)o(90b)o(70)o(57)o(12b)o(8b)o(918)o(ef)o(')739+4180 y Fx(Note)36 b(y)n(ou)g(need)h(to)f(pro)n(vide)f(the)i(full)h+(hash)e(string)g(as)f(ab)r(o)n(v)n(e.)63 b(This)36 b(is)g(in)n(tended)h+(to)739 4280 y(b)r(e)27 b(used,)g(for)g(example,)f(b)n(y)h(programs)d+(allo)n(wing)i(y)n(ou)g(to)h(view)f(darcs)g(rep)r(ositories)f(\(e.g.)+739 4380 y(CGI)j(scripts)f(lik)n(e)g(viewCVS\).)863 4479+y(The)d(fourth)f(matc)n(h)g(t)n(yp)r(e)h(accepts)f(a)f(regular)g+(expression)g(whic)n(h)h(is)g(c)n(hec)n(k)n(ed)f(against)739+4579 y(the)28 b(patc)n(h)f(author.)36 b(The)28 b(syn)n(tax)f(is)739+4739 y Fr(darcs)41 b(annotate)g(--summary)f(--match)g('author)h(foo')+863 4899 y Fx(There)31 b(is)g(also)f(supp)r(ort)h(for)g(matc)n(hing)f+(b)n(y)h(date.)47 b(This)31 b(is)g(done)g(using)g(commands)739+4998 y(suc)n(h)c(as)p eop end+%%Page: 53 53+TeXDict begin 53 52 bop 291 282 a Fu(6.1.)63 b(COMMON)28+b(OPTIONS)e(TO)h(D)n(AR)n(CS)h(COMMANDS)767 b Fx(53)291+515 y Fr(darcs)41 b(annotate)f(--summary)g(--match)h('date)g("last)h+(week"')291 615 y(darcs)f(annotate)f(--summary)g(--match)h('date)g+(yesterday')291 715 y(darcs)g(annotate)f(--summary)g(--match)h('date)g+("today)h(14:00"')291 814 y(darcs)f(annotate)f(--summary)g(--match)h+('date)g("tea)h(time)g(yesterday"')291 914 y(darcs)f(annotate)f+(--summary)g(--match)h('date)g("3)i(days)f(before)f(last)h(year)g(at)h+(17:00"')291 1013 y(darcs)e(changes)g(--from-match)d('date)k("Sat)g+(Jun)86 b(30)43 b(11:31:30)d(EDT)i(2004"')415 1195 y+Fx(Notes:)57 b(when)37 b(matc)n(hing)g(on)g(the)h(ISO)f(format,)j(a)d+(partial)g(date)g(is)g(treated)h(as)e(a)291 1295 y(range.)60+b(English)36 b(dates)f(can)h(either)g(refer)f(to)h(a)g(sp)r(eci\014c)g+(da)n(y)f(\(\\6)h(mon)n(ths)g(ago',\\da)n(y)291 1395+y(b)r(efore)25 b(y)n(esterda)n(y"\),)f(or)h(to)h(an)g(in)n(terv)-5+b(al)25 b(from)h(some)f(past)h(date)g(\(\\last)f(mon)n(th"\))h(to)g+(the)291 1494 y(presen)n(t.)50 b(Putting)33 b(this)f(all)h(together,)f+(if)h(to)r(da)n(y)f(is)g(\\2004-07-24")27 b(then)33 b(the)g(follo)n+(wing)291 1594 y(matc)n(hes)27 b(should)g(w)n(ork:)p+415 1611 2706 4 v 413 1710 4 100 v 465 1680 a Fv(date)412+b(patc)m(hes)32 b(selected)p 3119 1710 V 415 1714 2706+4 v 413 1813 4 100 v 465 1783 a Fx(2004)424 b(from)27+b(2004-01-01)c(up)28 b(to)f(and)h(including)g(2004-12-31)p+3119 1813 V 413 1913 V 465 1883 a(2004-01)312 b(from)27+b(2004-01-01)c(up)28 b(to)f(and)h(including)g(2004-01-31)p+3119 1913 V 413 2013 V 465 1983 a(2004-01-01)200 b(during)27+b(2004-01-01)p 3119 2013 V 415 2016 2706 4 v 413 2116+4 100 v 465 2086 a(to)r(da)n(y)386 b(during)27 b(2004-07-24)c+(\(starting)k(midnigh)n(t)h(in)g(y)n(our)e(timezone\))p+3119 2116 V 413 2215 V 465 2185 a(y)n(esterda)n(y)248+b(during)27 b(2004-07-23)p 3119 2215 V 413 2315 V 465+2285 a(6)g(mon)n(ths)g(ago)104 b(during)27 b(2004-01-23)p+3119 2315 V 415 2318 2706 4 v 413 2418 4 100 v 465 2388+a(last)g(6)g(mon)n(ths)100 b(since)27 b(2004-01-23)p+3119 2418 V 413 2517 V 465 2487 a(last)g(mon)n(th)202+b(since)27 b(2004-06-23)c(\(not)28 b(2004-06-01!\))p+3119 2517 V 413 2617 V 465 2587 a(last)f(w)n(eek)259+b(since)27 b(2004-07-16)p 3119 2617 V 415 2620 2706 4+v 415 2692 a(F)-7 b(or)40 b(more)h(precise)f(con)n(trol,)j(y)n(ou)d(ma)+n(y)g(sp)r(ecify)h(an)g(in)n(terv)-5 b(al,)44 b(either)d(in)g(a)f+(small)291 2791 y(subset)31 b(of)h(English)f(or)f(of)i(the)g(ISO)g+(8601)d(format.)49 b(If)32 b(y)n(ou)f(use)g(the)h(ISO)g(format,)g(note)+291 2891 y(that)k(durations,)h(when)f(sp)r(eci\014ed)h(alone,)g(are)e+(in)n(terpreted)g(as)h(b)r(eing)g(relativ)n(e)f(to)h(the)291+2990 y(curren)n(t)26 b(date)i(and)f(time.)291 3178 y+Fr(darcs)41 b(annotate)f(--summary)g(--match)h('date)g("between)g+(2004-03-12)e(and)k(last)e(week"')291 3277 y(darcs)g(annotate)f+(--summary)g(--match)h('date)g("after)h(2005"')291 3377+y(darcs)f(annotate)f(--summary)g(--match)h('date)g("in)i(the)f(last)g+(3)h(weeks"')291 3476 y(darcs)e(annotate)f(--summary)g(--match)h('date)+g("P3M/2006-03-17"')291 3576 y(darcs)g(annotate)f(--summary)g(--match)h+('date)g("2004-01-02/2006-)o(03-)o(17)o("')291 3676 y(darcs)g(annotate)+f(--summary)g(--match)h('date)g("P2M6D"')415 3858 y Fx(Y)-7+b(ou)25 b(ma)n(y)f(also)g(prefer)g(to)g(com)n(bine)h(date)f(matc)n+(hing)h(with)g(a)f(more)g(sp)r(eci\014c)h(pattern.)291+4045 y Fr(darcs)41 b(annotate)f(--summary)g(--match)h('date)g("last)h+(week")f(&&)i(name)f(foo')415 4227 y Fx(The)33 b Fr(--match)d+Fx(pattern)i(can)h(include)g(the)g(logical)e(op)r(erators)g+Fr(&&)p Fx(,)i Fr(||)f Fx(and)h Fr(not)p Fx(,)g(as)291+4326 y(w)n(ell)27 b(as)g(grouping)f(of)i(patterns)f(with)h(paren)n+(theses.)35 b(F)-7 b(or)27 b(example)291 4514 y Fr(darcs)41+b(annotate)f(--summary)g(--match)h('name)g(record)h(&&)g(not)h(name)f+(overrode')p 527 4717 2392 4 v 527 4792 a(--ignore-times)p+527 4847 V 291 4921 1146 4 v 383 4975 a Fp(3)418 4998+y Fo(http://www.w3.org/TR/NOTE)q(-da)q(teti)q(me)p eop+end+%%Page: 54 54+TeXDict begin 54 53 bop 739 282 a Fx(54)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)739 515 y Fx(Darcs)20+b(optimizes)h(its)g(op)r(erations)e(b)n(y)i(k)n(eeping)f(trac)n(k)g(of)+h(the)g(mo)r(di\014cation)g(times)g(of)f(y)n(our)739+615 y(\014les.)65 b(This)37 b(dramatically)e(sp)r(eeds)i(up)h(commands)+e(suc)n(h)h(as)f Fr(whatsnew)e Fx(and)j Fr(record)739+715 y Fx(whic)n(h)27 b(w)n(ould)g(otherwise)g(require)f(reading)g(ev)n+(ery)g(\014le)h(in)h(the)g(rep)r(ository)e(and)h(compar-)739+814 y(ing)32 b(it)g(with)g(a)g(reference)f(v)n(ersion.)48+b(Ho)n(w)n(ev)n(er,)31 b(there)h(are)f(times)h(when)g(this)g(can)g+(cause)739 914 y(problems,)h(suc)n(h)f(as)g(when)h(running)f(a)g+(series)f(of)i(darcs)e(commands)h(from)g(a)g(script,)i(in)739+1013 y(whic)n(h)h(case)g(often)h(a)f(\014le)h(will)g(b)r(e)g(mo)r+(di\014ed)g(t)n(wice)f(in)h(the)g(same)f(second,)i(whic)n(h)f(can)739+1113 y(lead)27 b(to)g(the)h(second)f(mo)r(di\014cation)g(going)f+(unnoticed.)37 b(The)28 b(solution)f(to)g(suc)n(h)g(predica-)739+1213 y(men)n(ts)f(is)f(the)h Fr(--ignore-times)20 b Fx(option,)26+b(whic)n(h)f(instructs)h(darcs)e(not)i(to)f(trust)h(the)g(\014le)739+1312 y(mo)r(di\014cation)h(times,)h(but)g(instead)g(to)f(c)n(hec)n(k)g+(eac)n(h)g(\014le's)g(con)n(ten)n(ts)g(explicitly)-7+b(.)p 975 1511 2392 4 v 975 1586 a Fr(--author)p 975+1622 V 739 1821 a Fx(Sev)n(eral)24 b(commands)h(need)h(to)g(b)r(e)g+(able)f(to)h(iden)n(tify)g(y)n(ou.)35 b(Con)n(v)n(en)n(tionally)-7+b(,)25 b(y)n(ou)f(pro)n(vide)739 1920 y(an)18 b(email)g(address)f(for)h+(this)h(purp)r(ose,)g(whic)n(h)g(can)f(include)h(commen)n(ts,)g(e.g.)f+Fr(David)42 b(Roundy)f(<droundy@abridge)o(gam)o(e.)o(or)o(g>)p+Fx(.)739 2020 y(The)18 b(easiest)g(w)n(a)n(y)f(to)h(do)g(this)h(is)f+(to)h(de\014ne)f(an)g(en)n(vironmen)n(t)g(v)-5 b(ariable)17+b Fr(EMAIL)f Fx(or)i Fr(DARCS_EMAIL)739 2119 y Fx(\(with)36+b(the)g(latter)f(o)n(v)n(erriding)e(the)j(former\).)60+b(Y)-7 b(ou)35 b(can)g(also)g(o)n(v)n(erride)e(this)j(using)f(the)739+2219 y Fr(--author)20 b Fx(\015ag)i(to)i(an)n(y)e(command.)35+b(Alternativ)n(ely)-7 b(,)24 b(y)n(ou)e(could)h(set)g(y)n(our)f(email)h+(address)739 2319 y(on)f(a)f(p)r(er-rep)r(ository)f(basis)i(using)g+(the)g(\\defaults")f(mec)n(hanism)h(for)g(\\ALL")f(commands,)739+2418 y(as)d(describ)r(ed)g(in)h(App)r(endix)h(B.)34 b(Or,)19+b(y)n(ou)f(could)h(sp)r(ecify)g(the)g(author)f(on)g(a)g(p)r(er-rep)r+(ository)739 2518 y(basis)27 b(using)g(the)h Fr(_darcs/prefs/aut)o(hor)+21 b Fx(\014le)28 b(as)e(describ)r(ed)i(in)g(section)f(4.1.)863+2621 y(Also,)37 b(a)d(global)f(author)h(\014le)h(can)f(b)r(e)h(created)+f(in)h(y)n(our)e(home)h(directory)g(with)h(the)739 2721+y(name)27 b Fr(.darcs/author)p Fx(.)k(This)c(\014le)g(o)n(v)n(errides)d+(the)k(con)n(ten)n(ts)e(of)h(the)g(en)n(vironmen)n(t)f(v)-5+b(ari-)739 2821 y(ables,)27 b(but)h(a)f(rep)r(ository-sp)r(eci\014c)f+(author)h(\014le)h(o)n(v)n(errides)d(the)j(global)e(author)h(\014le.)p+975 3019 V 975 3094 a Fr(--dont-compress,)37 b(--compress)p+975 3149 V 739 3347 a Fx(By)26 b(default,)g(darcs)f(commands)h(that)g+(write)g(patc)n(hes)f(to)h(disk)g(will)g(compress)f(the)i(patc)n(h)739+3447 y(\014les.)35 b(If)22 b(y)n(ou)e(don't)i(w)n(an)n(t)f(this,)i(y)n+(ou)d(can)h(c)n(ho)r(ose)g(the)h Fr(--dont-compress)15+b Fx(option,)22 b(whic)n(h)739 3547 y(causes)k(darcs)h(not)h(to)f+(compress)f(the)i(patc)n(h)g(\014le.)p 975 3745 V 975+3820 a Fr(--dry-run)p 975 3875 V 739 4073 a Fx(The)c+Fr(--dry-run)c Fx(option)j(will)h(cause)e(darcs)h(not)h(to)f(actually)g+(tak)n(e)g(the)h(sp)r(eci\014ed)g(action,)739 4173 y(but)c(only)e(prin)+n(t)h(what)g(w)n(ould)g(ha)n(v)n(e)e(happ)r(ened.)35+b(Not)19 b(all)g(commands)f(accept)h Fr(--dry-run)p Fx(,)739+4273 y(but)28 b(those)f(that)h(do)g(should)f(accept)g(the)h+Fr(--summary)c Fx(option.)p 975 4471 V 975 4546 a Fr(--summary,)40+b(--no-summary)p 975 4601 V 739 4799 a Fx(The)30 b Fr(--summary)c+Fx(option)k(sho)n(ws)e(a)i(summary)f(of)h(the)g(patc)n(hes)f(that)i(w)n+(ould)e(ha)n(v)n(e)g(b)r(een)739 4899 y(pulled/pushed/whatev)n(er.)j+(The)18 b(format)g(is)h(similar)e(to)h(the)h(output)g(format)f(of)g+Fr(cvs)43 b(update)739 4998 y Fx(and)27 b(lo)r(oks)g(lik)n(e)g(this:)p+eop end+%%Page: 55 55+TeXDict begin 55 54 bop 291 282 a Fu(6.1.)63 b(COMMON)28+b(OPTIONS)e(TO)h(D)n(AR)n(CS)h(COMMANDS)767 b Fx(55)291+515 y Fr(A)86 b(./added_but_not_r)o(ec)o(ord)o(ed)o(.c)291+615 y(A!)42 b(./added_but_not_r)o(ec)o(ord)o(ed)o(_co)o(nf)o(lic)o(ts)o+(.c)291 715 y(a)86 b(./would_be_added_)o(if)o(_lo)o(ok)o(_fo)o(r_)o+(add)o(s_)o(op)o(tio)o(n_)o(was)o(_u)o(se)o(d.h)291 914+y(M)g(./modified.t)39 b(-1)k(+1)291 1013 y(M!)f(./modified_confli)o(ct)+o(s.t)37 b(-1)43 b(+1)291 1213 y(R)86 b(./removed_but_not)o(_r)o(eco)o+(rd)o(ed.)o(c)291 1312 y(R!)42 b(./removed_but_not)o(_r)o(eco)o(rd)o+(ed_)o(co)o(nfl)o(ic)o(ts)o(.c)415 1588 y Fx(Y)-7 b(ou)28+b(can)f(probably)f(guess)h(what)h(the)g(\015ags)e(mean)i(from)f(the)h+(clev)n(er)e(\014le)i(names.)332 1749 y Fr(A)f Fx(is)h(for)f(\014les)g+(that)h(ha)n(v)n(e)f(b)r(een)h(added)f(but)h(not)g(recorded)e(y)n(et.)+332 1913 y Fr(a)k Fx(is)f(for)h(\014les)f(found)h(using)g(the)g+Fr(--look-for-adds)24 b Fx(option)29 b(a)n(v)-5 b(ailable)29+b(for)g Fr(whatsnew)498 2012 y Fx(and)k Fr(record)p Fx(.)51+b(They)33 b(ha)n(v)n(e)f(not)h(b)r(een)g(added)g(y)n(et,)h(but)g(w)n+(ould)e(b)r(e)i(added)f(auto-)498 2112 y(matically)24+b(if)i Fr(--look-for-adds)18 b Fx(w)n(ere)24 b(used)h(with)g(the)g+(next)g Fr(record)d Fx(command.)332 2275 y Fr(M)i Fx(is)g(for)g+(\014les)g(that)g(ha)n(v)n(e)f(b)r(een)i(mo)r(di\014ed)f(in)h(the)f(w)n+(orking)f(directory)f(but)j(not)f(recorded)498 2375 y(y)n(et.)37+b(The)27 b(n)n(um)n(b)r(er)h(of)f(added)h(and)f(subtracted)g(lines)h+(is)f(also)g(sho)n(wn.)332 2538 y Fr(R)g Fx(is)h(for)f(\014les)g(that)h+(ha)n(v)n(e)f(b)r(een)h(remo)n(v)n(ed,)e(but)i(the)g(remo)n(v)-5+b(al)26 b(is)i(not)f(recorded)f(y)n(et.)291 2699 y(An)i(exclamation)e+(mark)h(app)r(ears)f(next)i(to)g(an)n(y)e(option)i(that)g(has)f(a)g+(con\015ict.)291 2914 y Fv(Resolution)f(of)i(con\015icts)83+b Fx(T)-7 b(o)24 b(resolv)n(e)f(con\015icts)i(using)f(an)g(external)g+(to)r(ol,)h(y)n(ou)f(need)291 3014 y(to)j(sp)r(ecify)h(a)f(command)g+(to)h(use,)f(e.g.)291 3175 y Fr(--external-merg)o(e)38+b('opendiff)h(\0451)k(\0452)g(-ancestor)d(\045a)j(-merge)e(\045o')291+3336 y Fx(The)28 b Fr(\0451)f Fx(and)h Fr(\0452)f Fx(are)g(replaced)g+(with)h(the)h(t)n(w)n(o)e(v)n(ersions)f(to)i(b)r(e)g(merged,)g+Fr(\045a)f Fx(is)h(replaced)291 3435 y(with)23 b(the)g(common)f+(ancestor)g(of)g(the)i(t)n(w)n(o)e(v)n(ersions.)33 b(Most)23+b(imp)r(ortan)n(tly)-7 b(,)23 b Fr(\045o)f Fx(is)h(replaced)291+3535 y(with)32 b(the)g(name)g(of)g(the)g(output)h(\014le)f(that)g+(darcs)f(will)h(require)f(to)h(b)r(e)g(created)f(holding)291+3634 y(the)23 b(merged)f(v)n(ersion.)34 b(The)23 b(ab)r(o)n(v)n(e)e+(example)h(w)n(orks)g(with)h(the)g(FileMerge.app)f(to)r(ol)h(that)291+3734 y(comes)j(with)j(Apple's)f(dev)n(elop)r(er)e(to)r(ols.)36+b(T)-7 b(o)28 b(use)f(xxdi\013,)h(y)n(ou)f(w)n(ould)g(use)291+3895 y Fr(--external-merg)o(e)38 b('xxdiff)i(-m)j(-O)g(-M)g(\045o)f+(\0451)h(\045a)g(\0452')291 4056 y Fx(T)-7 b(o)27 b(use)g+Fr(kdiff3)p Fx(,)f(y)n(ou)g(can)i(use)291 4217 y Fr(--external-merg)o+(e)38 b('kdiff3)i(--output)h(\045o)h(\045a)h(\0451)g(\0452')291+4378 y Fx(T)-7 b(o)27 b(use)g Fr(tortoiseMerge)p Fx(,)c(y)n(ou)j(can)i+(use)291 4539 y Fr(--external-merg)o(e)38 b('tortoiseMerge)f+(/base:"\045a")j(/mine:"\0451")f(/theirs:"\0452")g(/merged:"\045o"')291+4700 y Fx(\()p Fr(tortoiseMerge)25 b Fx(is)k(a)h(nice)g(merge)f(to)r+(ol)h(that)g(comes)f(with)i(T)-7 b(ortoiseSVN)29 b(and)h(w)n(orks)291+4799 y(w)n(ell)d(on)g(Windo)n(ws.\))415 4899 y(Note)e(that)g(the)g+(command)g(is)f(split)i(in)n(to)e(space-separated)e(w)n(ords)i(and)h+(the)g(\014rst)f(one)291 4998 y(is)h Fr(exec)p Fx(ed)f(with)i(the)g+(rest)f(as)g(argumen)n(ts|it)f(is)i(not)f(a)g(shell)h(command.)35+b(In)26 b(particular,)p eop end+%%Page: 56 56+TeXDict begin 56 55 bop 739 282 a Fx(56)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)739 515 y Fx(on)d(Windo)n(ws)g+(this)h(means)f(that)h(the)g(\014rst)g(command)f(path)g(should)h(not)f+(con)n(tain)g(spaces)739 615 y(and)i(y)n(ou)g(should)h(mak)n(e)e(sure)h+(the)h(command)f(is)h(in)g(y)n(our)e Fr(PATH)p Fx(.)863+715 y(The)e(substitution)h(of)e(the)i Fr(\045)e Fx(escap)r(es)g(is)h+(done)f(ev)n(erywhere.)34 b(If)24 b(y)n(ou)f(need)h(to)g(prev)n(en)n(t)+739 814 y(substitution)30 b(y)n(ou)e(can)h(use)g(a)g(double)g(p)r+(ercen)n(tage)f(sign,)h(i.e.)42 b Fr(\045\045a)28 b Fx(is)h+(substituted)h(with)739 914 y Fr(\045a)p Fx(.)36 b(Here)27+b(is)h(an)f(example)g(script)h(to)f(use)g(the)h(Emacs')f(Edi\013)h(pac)+n(k)-5 b(age)26 b(for)h(merging.)782 1064 y Fr(#!)43+b(/bin/sh)782 1164 y(#)h(External)c(merge)h(command)g(for)h(darcs,)g+(using)f(Emacs)h(Ediff,)f(via)h(server)f(if)i(possible.)782+1263 y(#)h(It)e(needs)g(args)g(\0451)h(\0452)f(\045a)h(\045o,)f(i.e.)g+(the)h(external)d(merge)i(command)e(is,)j(say,)782 1363+y(#)h(`emerge3)c(\0451)j(\0452)f(\045a)h(\045o'.)782+1463 y(test)f($#)h(-eq)g(4)g(||)f(exit)g(1)782 1562 y+(form="\(ediff-merg)o(e-f)o(il)o(es-)o(wi)o(th)o(-an)o(ce)o(sto)o(r")+782 1662 y(while)g(test)g($#)h(-gt)f(0;)h(do)957 1761+y(count=$count.)957 1861 y(if)g([)g($count)e(=)i(....)f(];)h(then)1131+1961 y(form=$form\\)c(nil)391 b(#)43 b(Lisp)f(STARTUP-HOOKS)d(arg)957+2060 y(fi)957 2160 y(case)j($1)h(in)783 b(#)43 b(Worry)f(about)f+(quoting)g(--)i(escape)e(")i(and)g(\\)1131 2260 y(*[\\"\\\\]*)d(\))k+(form=$form\\)39 b(\\"$\(echo)h($1)j(|)g(sed)f(-e's/["\\\\]/\\\\\\0/g)o+('\))o(\\")37 b(;;)1131 2359 y(*\))43 b(form=$form\\)c(\\"$1\\")i(;;)+957 2459 y(esac)957 2558 y(shift)782 2658 y(done)782+2758 y(form=$form'\)')782 2857 y(\()j(emacsclient)39+b(--eval)i("$form")f(||)j(#)g(Emacs)f(22)h(server)870+2957 y(gnudoit)d("$form")h(||)522 b(#)43 b(XEmacs/Emacs)c(21)k(server)+870 3057 y(emacs)e(--eval)g("$form")g(||)304 b(#)43 b(Relatively)d+(slow)i(to)h(start)e(up)870 3156 y(xemacs)g(-eval)g("$form")433+b(#)43 b(Horribly)e(slow)h(to)g(start)g(up)782 3256 y(\))i(2>/dev/null)+739 3406 y Fx(It)28 b(w)n(ould)f(b)r(e)h(in)n(v)n(ok)n(ed)e(lik)n(e:)+739 3556 y Fr(--external-merge)37 b('emerge3)j(\0451)j(\0452)g(\045a)f+(\045o')863 3706 y Fx(If)34 b(y)n(ou)f(\014gure)g(out)h(ho)n(w)f(to)g+(use)h(darcs)e(with)i(another)f(merge)f(to)r(ol,)j(please)e(let)h(me)+739 3806 y(kno)n(w)27 b(what)g(\015ags)g(y)n(ou)g(used)g(so)g(I)h(can)f+(men)n(tion)h(it)g(here.)863 3906 y(Note)34 b(that)g(if)g(y)n(ou)e(do)i+(use)f(an)g(external)g(merge)f(to)r(ol,)j(most)e(lik)n(ely)g(y)n(ou)g+(will)h(w)n(an)n(t)739 4005 y(to)c(add)f(to)h(y)n(our)e(defaults)j+(\014le)e(\()p Fr(_darcs/prefs/defau)o(lt)o(s)24 b Fx(or)29+b Fr(~/.darcs/prefs)p Fx(,)c(see)739 4105 y(4.1\))i(a)g(line)h(suc)n(h)+f(as)739 4255 y Fr(ALL)42 b(external-merge)c(kdiff3)j(--output)f(\045o)+j(\045a)g(\0451)g(\0452)739 4405 y Fx(or)739 4556 y Fr(ALL)f+(external-merge)c(tortoiseMerge)g(/base:"\045a")i(/mine:"\0451")f+(/theirs:"\0452")g(/merged:"\045o")863 4706 y Fx(Note)28+b(that)g(the)g(defaults)g(\014le)f(do)r(es)h(not)f(w)n(an)n(t)g(quotes)+g(around)g(the)h(command.)p 975 4869 2392 4 v 975 4944+a Fr(--posthook=COMMA)o(ND,)37 b(--no-posthook)p 975+4998 V eop end+%%Page: 57 57+TeXDict begin 57 56 bop 291 282 a Fu(6.1.)63 b(COMMON)28+b(OPTIONS)e(TO)h(D)n(AR)n(CS)h(COMMANDS)767 b Fx(57)291+515 y(T)-7 b(o)34 b(pro)n(vide)g(a)g(command)g(that)h(should)g(b)r(e)g+(run)f(whenev)n(er)g(a)h(darcs)e(command)i(com-)291 615+y(pletes)29 b(successfully)-7 b(,)29 b(use)g Fr(--posthook)c+Fx(to)k(sp)r(ecify)h(the)f(command.)42 b(This)29 b(is)g(useful)g(for)+291 715 y(p)r(eople)i(who)g(w)n(an)n(t)g(to)g(ha)n(v)n(e)g(a)g(command)+g(run)g(whenev)n(er)g(a)g(patc)n(h)g(is)h(applied.)48+b(Using)291 814 y Fr(--no-posthook)22 b Fx(will)28 b(disable)f(running)+g(the)h(command.)p 527 979 2392 4 v 527 1053 a Fr(--prompt-posthoo)o+(k,)37 b(--run-posthook)p 527 1108 V 291 1273 a Fx(These)18+b(options)f(con)n(trol)h(prompting)f(b)r(efore)h(running)h(the)f(p)r+(ostho)r(ok.)33 b(Use)19 b Fr(--prompt-posthoo)o(k)291+1373 y Fx(to)i(force)f(prompting)h(b)r(efore)g(running)f(the)i(p)r+(ostho)r(ok)f(command.)34 b(F)-7 b(or)20 b(securit)n(y)h(reasons,)291+1472 y(this)33 b(is)f(the)i(default.)53 b(When)33 b(de\014ning)g(a)g(p)+r(ostho)r(ok)f(for)g(apply)-7 b(,)34 b(y)n(ou)e(will)h(need)g(to)g(use)+291 1572 y Fr(--run-posthook)d Fx(or)36 b(else)g(y)n(ou)f(will)i(get)f+(an)g(error,)h(b)r(ecause)f(the)h(subpro)r(cess)e(whic)n(h)291+1671 y(runs)27 b(the)h(apply)f(command)g(cannot)g(prompt)h(the)g(user.)+415 1771 y(Some)e(darcs)f(commands)g(exp)r(ort)h(to)g(the)g(p)r(ostho)r+(ok)g(command)g(information)f(ab)r(out)291 1871 y(the)g(c)n(hanges)e(b)+r(eing)h(made.)36 b(In)25 b(particular,)f(three)g(en)n(vironmen)n(t)g+(v)-5 b(ariables)23 b(are)g(de\014ned.)291 1970 y Fr(DARCS_PATCHES)17+b Fx(con)n(tains)k(a)h(h)n(uman-readable)e(summary)i(of)g(the)h(patc)n+(hes)f(b)r(eing)g(acted)291 2070 y(up)r(on.)50 b(The)32+b(format)f(is)h(the)g(same)g(as)f("darcs)f(c)n(hanges".)49+b Fr(DARCS_PATCHES_X)o(ML)26 b Fx(Con-)291 2170 y(tains)32+b(the)h(same)g(details,)h(in)f(the)g(same)f(XML)h(format)g(as)f("darcs)+f(c)n(hanges".)51 b(Finally)-7 b(,)291 2269 y Fr(DARCS_FILES)21+b Fx(con)n(tains)k(a)g(list)h(of)g(the)g(\014les)g(a\013ected,)g(one)g+(\014le)g(p)r(er)g(line.)36 b(If)26 b(y)n(our)f(rep)r(os-)291+2369 y(itory)h(has)h(\014lenames)f(including)i(newlines,)f(y)n(ou'll)f+(just)i(ha)n(v)n(e)e(to)h(cop)r(e.)37 b(Note,)27 b(ho)n(w)n(ev)n(er,)+291 2468 y(that)h Fs(none)34 b Fx(of)28 b(these)g(en)n(vironmen)n(t)f+(v)-5 b(ariables)27 b(are)g(de\014ned)h(when)g(running)g(under)g(win-)+291 2568 y(do)n(ws.)58 b(Note)36 b(also)e(that)h(w)n(e)g(refuse)g(to)g+(pass)f(en)n(vironmen)n(t)g(v)-5 b(ariables)34 b(greater)g(in)h(size)+291 2668 y(than)27 b(10k,)g(in)h(order)e(to)h(a)n(v)n(oid)g(triggering)+e Fr(E2BIG)h Fx(errors.)p 527 2848 V 527 2923 a Fr(--prehook=COMMAN)o+(D,)37 b(--no-prehook)p 527 2978 V 291 3159 a Fx(T)-7+b(o)23 b(pro)n(vide)g(a)h(command)f(that)i(should)f(b)r(e)g(run)g(b)r+(efore)g(a)f(darcs)g(command)h(is)g(executed,)291 3258+y(use)f Fr(--prehook)c Fx(to)k(sp)r(ecify)g(the)h(command.)35+b(An)23 b(example)g(use)g(is)g(for)g(p)r(eople)g(who)g(w)n(an)n(t)291+3358 y(to)i(ha)n(v)n(e)f(a)h(command)g(run)g(whenev)n(er)g(a)g(patc)n+(h)g(is)g(to)g(b)r(e)h(recorded,)e(suc)n(h)h(as)g(translating)291+3458 y(line)e(endings)g(b)r(efore)g(recording)e(patc)n(hes.)35+b(Using)23 b Fr(--no-prehook)18 b Fx(will)23 b(disable)g(running)291+3557 y(the)28 b(command.)p 527 3722 V 527 3797 a Fr(--prompt-prehook)o+(,)37 b(--run-prehook)p 527 3852 V 291 4016 a Fx(These)18+b(options)f(con)n(trol)h(prompting)f(b)r(efore)h(running)h(the)f(preho)+r(ok.)33 b(Use)18 b Fr(--prompt-prehook)291 4116 y Fx(to)25+b(force)g(prompting)f(b)r(efore)i(running)f(the)g(preho)r(ok)g+(command.)35 b(F)-7 b(or)25 b(securit)n(y)g(reasons,)291+4215 y(this)i(is)h(the)g(default.)p 527 4396 V 527 4471+a Fr(--ssh-cm,)40 b(--no-ssh-cm)p 527 4519 V 415 4700+a Fx(F)-7 b(or)28 b(commands)h(whic)n(h)g(in)n(v)n(ok)n(e)e(ssh,)i+(darcs)f(will)h(normally)f(m)n(ultiplex)i(ssh)e(sessions)291+4799 y(o)n(v)n(er)i(a)i(single)g(connection)h(as)e(long)h(as)g(y)n(our)+f(v)n(ersion)g(of)i(ssh)f(has)g(the)h(Con)n(trolMaster)291+4899 y(feature)j(from)g(Op)r(enSSH)i(v)n(ersions)d(3.9)h(and)g(ab)r(o)n+(v)n(e.)64 b(This)36 b(option)h(will)g(a)n(v)n(oid)e(darcs)291+4998 y(trying)27 b(to)g(use)g(this)h(feature)g(ev)n(en)f(if)h(y)n(our)e+(ssh)h(supp)r(orts)h(it.)p eop end+%%Page: 58 58+TeXDict begin 58 57 bop 739 282 a Fx(58)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)p 975 515 2392 4+v 975 590 a Fr(--umask)p 975 627 V 739 797 a Fx(By)g(default,)h(Darcs)f+(will)h(use)f(y)n(our)f(curren)n(t)h(umask.)39 b(The)28+b(option)h Fr(--umask)c Fx(will)k(cause)739 896 y(Darcs)e(to)g(switc)n+(h)h(to)f(a)g(di\013eren)n(t)h(umask)f(b)r(efore)g(writing)g(to)h(the)g+(rep)r(ository)-7 b(.)p 975 1085 V 975 1160 a Fr(--dont-restrict-)o+(pat)o(hs)o(,)38 b(--restrict-path)o(s)p 975 1215 V 739+1403 a Fx(By)23 b(default)h(darcs)f(is)g(only)g(allo)n(w)n(ed)g(to)g+(manage)f(and)i(mo)r(dify)g(\014les)f(and)h(directories)e(con-)739+1502 y(tained)h(inside)h(the)f(curren)n(t)f(rep)r(ository)g(and)h(not)g+(b)r(eing)h(part)e(of)i(an)n(y)e(darcs)g(rep)r(ository's)739+1602 y(meta)32 b(data)g(\(including)h(the)f(curren)n(t)g(one\).)51+b(This)32 b(is)g(mainly)g(for)g(securit)n(y)-7 b(,)32+b(to)h(protect)739 1702 y(y)n(ou)27 b(from)h(sp)r(o)r(ofed)g(patc)n+(hes)g(mo)r(difying)g(arbitrary)e(\014les)i(with)h(sensitiv)n(e)e+(data|sa)n(y)-7 b(,)27 b(in)739 1801 y(y)n(our)i(home)h(directory|or)e+(temp)r(ering)i(with)h(an)n(y)f(rep)r(ository's)e(meta)i(data)g(to)g+(switc)n(h)739 1901 y(o\013)e(this)f(safet)n(y)g(guard.)863+2002 y(But)e(sometimes)f(y)n(ou)f(ma)n(y)g(w)n(an)n(t)h(to)g(manage)f+(a)h(group)f(of)h(\\sub")f(rep)r(ositories')g(pref-)739+2102 y(erence)29 b(\014les)h(with)g(a)f(global)g(rep)r(ository)-7+b(,)29 b(or)g(use)g(darcs)g(in)h(some)f(other)g(adv)-5+b(anced)29 b(w)n(a)n(y)-7 b(.)739 2201 y(The)18 b(b)r(est)h(w)n(a)n(y)e+(is)i(probably)e(to)h(put)h Fr(ALL)42 b(dont-restrict-pat)o(hs)12+b Fx(in)19 b Fr(_darcs/prefs/de)o(fau)o(lt)o(s)p Fx(.)739+2301 y(This)27 b(turns)h(o\013)g(all)f(sanit)n(y)g(c)n(hec)n(king)f+(for)h(\014le)h(paths)f(in)h(patc)n(hes.)863 2402 y(P)n(ath)23+b(c)n(hec)n(king)f(can)h(b)r(e)h(temp)r(orarily)e(turned)i(on)f(with)h+Fr(--restrict-paths)17 b Fx(on)23 b(the)739 2502 y(command)k(line,)h+(when)g(pulling)g(or)e(applying)h(unkno)n(wn)g(patc)n(hes.)739+2784 y Fq(6.2)135 b(Options)45 b(apart)h(from)f(darcs)g(commands)p+975 2968 V 975 3043 a Fr(--help,)c(--extended-help)p+975 3098 V 739 3286 a Fx(Calling)29 b(darcs)g(with)h(just)g+Fr(--help)e Fx(as)h(an)g(argumen)n(t)g(giv)n(es)f(a)i(brief)g(summary)f+(of)g(what)739 3386 y(commands)h(are)f(a)n(v)-5 b(ailable.)44+b(The)30 b Fr(--extended-help)24 b Fx(option)30 b(giv)n(es)f(a)h(more)g+(tec)n(hnical)739 3485 y(summary)d(of)g(what)h(the)g(commands)f+(actually)g Fs(do)p Fx(.)p 975 3656 V 975 3730 a Fr(--version,)40+b(--exact-version)p 975 3779 V 739 3949 a Fx(Calling)c(darcs)f(with)i+(the)g(\015ag)e Fr(--version)e Fx(tells)k(y)n(ou)e(the)i(v)n(ersion)e+(of)h(darcs)g(y)n(ou)f(are)739 4048 y(using.)53 b(Calling)33+b(darcs)f(with)i(the)f(\015ag)g Fr(--exact-version)27+b Fx(giv)n(es)32 b(the)h(precise)g(v)n(ersion)739 4148+y(of)d(darcs,)f(ev)n(en)g(if)h(that)g(v)n(ersion)e(do)r(esn't)i+(corresp)r(ond)e(to)i(a)f(released)f(v)n(ersion)g(n)n(um)n(b)r(er.)739+4248 y(This)22 b(is)g(helpful)h(with)g(bug)f(rep)r(orts,)g(esp)r+(ecially)g(when)g(running)g(with)h(a)f(\\latest")f(v)n(ersion)739+4347 y(of)27 b(darcs.)p 975 4518 V 975 4592 a Fr(--commands)p+975 4629 V 739 4799 a Fx(Similarly)20 b(calling)g(darcs)f(with)i(only)f+Fr(--commands)d Fx(giv)n(es)i(a)h(simple)h(list)f(of)h(a)n(v)-5+b(ailable)19 b(com-)739 4899 y(mands.)37 b(This)27 b(latter)g+(arrangemen)n(t)f(is)h(primarily)f(in)n(tended)i(for)f(the)h(use)f(of)h+(command-)739 4998 y(line)g(auto)r(completion)f(facilities,)g(as)g(are)+g(a)n(v)-5 b(ailable)26 b(in)i(bash.)p eop end+%%Page: 59 59+TeXDict begin 59 58 bop 291 282 a Fu(6.3.)63 b(GETTING)28+b(HELP)1933 b Fx(59)291 515 y Fq(6.3)135 b(Getting)46+b(help)291 723 y Fk(6.3.1)112 b(darcs)38 b(help)291 886+y Fx(Y)-7 b(ou)20 b(could)g(also)f(call)h Fr(help)f Fx(as)h(a)g+(command.)34 b(This)20 b(is)h(equiv)-5 b(alen)n(t)20+b(to)g(calling)g(darcs)f({help.)291 986 y(The)30 b Fr(--verbose)d+Fx(argumen)n(t)j(is)g(equiv)-5 b(alen)n(t)31 b(to)f(the)h(darcs)f+(option)g Fr(--extended-help)p Fx(.)291 1086 y(If)24+b(y)n(ou)g(pass)f(it)i(another)e(command)h(as)f(an)h(argumen)n(t,)g(it)+h(will)f(b)r(e)h(equiv)-5 b(alen)n(t)24 b(to)g(passing)291+1185 y(the)34 b Fr(--help)e Fx(to)j(that)f(command.)57+b(F)-7 b(or)34 b(example,)i Fr(darcs)41 b(help)h(query)g(manifest)31+b Fx(is)291 1285 y(equiv)-5 b(alen)n(t)27 b(to)g Fr(darcs)42+b(query)f(manifest)g(--help)p Fx(.)415 1390 y Fr(Usage:)g(darcs)h(help)+g([OPTION]...)d([<DARCS_COMMAND)o(>)f([DARCS_SUBCOMMA)o(ND])o(])415+1495 y Fx(Options:)565 1632 y Fr(--match)969 1582 y Fx(sho)n(ws)27+b(a)g(summary)g(of)g(ho)n(w)g(to)h(use)f(patc)n(h)969+1682 y(matc)n(hing)g(rules)415 1769 y(Displa)n(y)c(help)h(for)g(darcs)e+(or)h(a)h(single)f(command.)35 b(help)24 b(displa)n(ys)f(usage)g+(information)291 1869 y(for)36 b(darcs)f(in)i(general)f(or)g(for)g(a)g+(single)g(command)h(\(for)f(example,)j(darcs)d(help)h(query)291+1968 y(manifest\).)415 2073 y(Note)31 b(that)f({v)n(erb)r(ose)f(prin)n+(ts)h(extra)f(help)i(for)f(darcs)f(as)h(a)g(whole,)h(but)g(it)g(mak)n+(es)e(no)291 2173 y(di\013erence)e(when)h(getting)f(help)h(for)f(a)g+(single)g(command.)291 2475 y Fq(6.4)135 b(Creating)46+b(rep)t(ositories)291 2683 y Fk(6.4.1)112 b(darcs)38+b(initialize)291 2846 y Fr(Usage:)j(darcs)g(initialize)f([OPTION]...)+415 2951 y Fx(Options:)565 3050 y Fr(--plain-pristin)o(e-t)o(re)o(e)268+b Fx(use)27 b(a)g(plain)h(pristine)g(tree)f([DEF)-9 b(A)n(UL)i(T])565+3150 y Fr(--no-pristine-t)o(ree)1754 3149 y Fx(use)27+b(no)h(pristine)f(tree)565 3287 y Fr(--hashed)1754 3237+y Fx(Some)g(new)h(features.)36 b(Compatible)28 b(with)g(older)1754+3337 y(rep)r(os)565 3463 y Fr(--darcs-2)1754 3411 y Fx(All)g(features.)+36 b(Related)28 b(rep)r(os)f(m)n(ust)g(use)h(same)1754+3510 y(format)f([EXPERIMENT)-7 b(AL])565 3641 y Fr(--old-fashioned)o+(-in)o(ve)o(nt)o(ory)1754 3589 y Fx(Minimal)28 b(features.)36+b(What)28 b(older)f(rep)r(os)f(use.)1754 3688 y([DEF)-9+b(A)n(UL)i(T])565 3809 y Fr(--repodir)39 b(DIRECTORY)1754+3767 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e(directory)g(in)i(whic)n+(h)f(to)1754 3867 y(run)415 3938 y(Initialize)h(a)f(new)h(source)e+(tree)h(as)g(a)g(darcs)g(rep)r(ository)-7 b(.)415 4043+y(Call)33 b Fr(initialize)c Fx(once)k(for)f(eac)n(h)h(pro)5+b(ject)32 b(y)n(ou)g(w)n(ork)g(on.)53 b(Run)34 b(it)g(from)e(the)i(top)+291 4142 y(lev)n(el)28 b(directory)g(of)h(the)h(pro)5+b(ject,)29 b(with)h(the)f(pro)5 b(ject)29 b(\014les)g(already)e(there.)+42 b Fr(initialize)291 4242 y Fx(will)22 b(set)h(up)g(all)g(the)g+(directories)e(and)i(\014les)f(darcs)g(needs)g(in)h(order)f(to)g(start)+g(k)n(eeping)g(trac)n(k)291 4341 y(of)27 b(revisions)f(for)h(y)n(our)g+(pro)5 b(ject.)415 4446 y Fr(initialize)26 b Fx(creates)j(a)g(single)h+(directory)f(named)g Fr(_darcs)p Fx(,)g(with)h(con)n(ten)n(ts)g(for)f+(in-)291 4546 y(ternal)38 b(use.)69 b(The)39 b(one)f(sub)r(dictory)g+(of)g(in)n(terest)g(to)h(users)e(is)i Fr(_darcs/prefs)p+Fx(,)d(whic)n(h)291 4646 y(will)27 b(include)g(an)g(empt)n(y)g(\014le)g+Fr(_darcs/prefs/mot)o(d)21 b Fx(\(see)27 b(Section)g(4.1\),)g(as)f(w)n+(ell)h(as)f(\014les)291 4745 y(named)40 b Fr(boring)d+Fx(and)j Fr(binaries)p Fx(,)g(whic)n(h)g(con)n(tain)g(useful)g+(defaults)g(as)g(describ)r(ed)g(in)291 4845 y(Sections)27+b(4.1)g Fs(et)i(se)l(q.)p 527 5048 2392 4 v eop end+%%Page: 60 60+TeXDict begin 60 59 bop 739 282 a Fx(60)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)975 515 y Fr(--old-fashioned-)o+(inv)o(en)o(tor)o(y)975 615 y(--hashed)975 715 y(--darcs-2)p+975 751 2392 4 v 863 951 a Fx(These)g(options)f(describ)r(e)g(p)r+(ossible)g(rep)r(ository)f(formats)h(to)h(use.)863 1055+y Fr(old-fashioned-inv)o(ent)o(or)o(y)20 b Fx(is)25 b(the)i(default.)36+b(While)27 b(it)f(has)f(minimal)h(features,)g(it)739+1155 y(is)h(the)h(b)r(est)g(tested)g(and)g(the)g(limitations)f(it)h(do)+r(es)g(ha)n(v)n(e)e(are)h(w)n(ell)g(kno)n(wn.)863 1258+y Fr(hashed)18 b Fx(O\013ers)h(sev)n(eral)f(features)h(while)h(still)g+(b)r(eing)g(compatible)f(with)h(old-fashioned)739 1358+y(rep)r(ositories.)35 b(The)28 b(sp)r(eci\014c)f(features)g(are:)863+1558 y Fn(\017)41 b Fx(The)25 b(hashed)f(format)g(allo)n(ws)f(for)h+(greater)f(atomicit)n(y)h(of)g(op)r(erations.)35 b(This)24+b(mak)n(es)946 1658 y(for)35 b(greater)f(safet)n(y)h(and)g(sim)n+(ultaneously)f(greater)g(e\016ciency)-7 b(.)60 b(These)35+b(b)r(ene\014ts,)946 1757 y(ho)n(w)n(ev)n(er,)26 b(ha)n(v)n(e)h(not)g+(b)r(een)h(fully)h(realized)d(in)i(this)g(release.)36+b(F)-7 b(or)27 b(instance,)g(with)i(a)946 1857 y(hashed)f(rep)r+(ository)-7 b(,)27 b(there)h(is)g(no)g(need)g(for)g(darcs)f(push)h(to)g+(require)f(a)h(rep)r(ository)946 1956 y(lo)r(c)n(k,)34+b(so)e(y)n(ou)g(could)h(record)e(patc)n(hes)h(while)h(w)n(aiting)f(for)+g(a)h(push)g(to)f(\014nish)h(\(for)946 2056 y(instance,)28+b(if)g(it's)g(w)n(aiting)f(on)g(the)h(test)g(suite\).)863+2239 y Fn(\017)41 b Fx(The)29 b Fr(_darcs/pristine)22+b Fx(directory)27 b(no)h(longer)f(holds)h(the)h(pristine)f(cac)n(he.)38+b(This)946 2339 y(disallo)n(ws)i(certain)h(hac)n(kish)f(short-cuts,)j+(but)f(also)e(dramatically)f(reduces)i(the)946 2439 y(danger)36+b(of)h(third-part)n(y)f(programs)e(\(e.g.)65 b(DreamW)-7+b(ea)n(v)n(er\))35 b(recursing)g(in)n(to)i(the)946 2538+y(pristine)28 b(cac)n(he)f(and)g(corrupting)f(darcs)h(rep)r(ositories.)+863 2722 y Fn(\017)41 b Fx(Darcs)24 b(get)f(can)h(optionally)f(op)r+(erate)g(in)h(a)f(m)n(uc)n(h)h(faster)f(\\lazy")g(fashion,)h(meaning)+946 2821 y(that)35 b(patc)n(hes)e(are)g(do)n(wnloaded)f(only)h(when)h+(they)g(are)f(needed.)56 b(This)34 b(giv)n(es)e(us)946+2921 y(m)n(uc)n(h)c(of)f(the)h(b)r(ene\014ts)g(of)g({partial)e(rep)r+(ositories,)g(without)i(most)f(of)g(their)h(disad-)946+3020 y(v)-5 b(an)n(tages.)40 b(This)29 b(approac)n(h,)e(ho)n(w)n(ev)n+(er,)g(do)r(es)i(ha)n(v)n(e)f(sev)n(eral)f(new)i(dangers.)39+b(First,)946 3120 y(some)d(op)r(erations)g(ma)n(y)g(unexp)r(ectedly)h+(require)e(the)i(do)n(wnload)f(of)g(large)f(n)n(um-)946+3220 y(b)r(ers)25 b(of)f(patc)n(hes,)h(whic)n(h)g(could)f(b)r(e)h(slo)n+(w)f(\(but)h(y)n(ou)f(could)h(alw)n(a)n(ys)d(in)n(terrupt)j(with)946+3319 y Fr(^C)p Fx(\).)39 b(Secondly)-7 b(,)41 b(if)e(the)f(source)g+(rep)r(ository)f(disapp)r(ears,)j(or)d(y)n(ou)h(lose)g(net)n(w)n(ork)+946 3419 y(connectivit)n(y)-7 b(,)28 b(some)f(op)r(erations)f(ma)n(y)h+(fail.)863 3602 y Fn(\017)41 b Fx(Darcs)29 b(no)n(w)g(supp)r(orts)h+(cac)n(hing)e(of)i(patc)n(hes)f(and)h(\014le)g(con)n(ten)n(ts)f(to)g+(reduce)h(band-)946 3702 y(width)h(and)g(sa)n(v)n(e)d(disk)i(space.)45+b(It)30 b(greatly)f(sp)r(eeds)i(up)f(a)g(n)n(um)n(b)r(er)g(of)g(op)r+(erations,)946 3802 y(and)f(is)g(essen)n(tially)f(transparen)n(t.)39+b(The)29 b(only)f(reason)f(w)n(e)i(don't)g(enable)g(it)g(b)n(y)f(de-)+946 3901 y(fault)i(is)f(b)r(ecause)f(it)h(creates)f(a)h(large)e+(directory)h(in)58 b(/.darcs/cac)n(he)26 b(without)j(the)946+4001 y(user's)e(explicit)h(consen)n(t.)863 4201 y Fr(darcs-2)35+b Fx(Enables)h(all)h(a)n(v)-5 b(ailable)35 b(features,)k(and)e+(requiring)f(that)h(all)g(rep)r(os)f(for)h(a)739 4300+y(pro)5 b(ject)29 b(use)g(the)h(same)e(format.)42 b(In)30+b(addition)f(to)g(the)h(features)f(of)g(the)h Fr(hashed)d+Fx(format)739 4400 y(describ)r(ed)g(ab)r(o)n(v)n(e,)g(the)h+Fr(darcs-2)c Fx(format)j(also)g(enables)g(the)h(follo)n(wing:)863+4600 y Fn(\017)41 b Fx(It)26 b(should)e(no)h(longer)e(b)r(e)j(p)r+(ossible)e(to)h(confuse)g(darcs)e(or)h(freeze)h(it)g(inde\014nitely)h+(b)n(y)946 4699 y(merging)h(con\015icting)g(c)n(hanges.)863+4883 y Fn(\017)41 b Fx(Iden)n(tical)c(primitiv)n(e)f(c)n(hanges)f(no)i+(longer)e(con\015ict.)64 b(This)36 b(is)h(a)f(long-requested)946+4982 y(feature,)28 b(and)f(has)g(far-reac)n(hing)e(implications.)p+eop end+%%Page: 61 61+TeXDict begin 61 60 bop 291 282 a Fu(6.4.)63 b(CREA)-7+b(TING)28 b(REPOSITORIES)1475 b Fx(61)p 527 515 2392+4 v 527 590 a Fr(--no-pristine-tr)o(ee)p 527 645 V 291+835 a Fx(In)18 b(order)f(to)h(sa)n(v)n(e)f(disk)h(space,)i(y)n(ou)e+(can)g(use)g Fr(initialize)c Fx(with)19 b(the)g Fr(--no-pristine-t)o+(ree)291 934 y Fx(\015ag)24 b(to)i(create)f(a)g(rep)r(ository)f(with)i+(no)g(pristine)f(tree.)36 b(Please)25 b(see)g(Section)h(3.6)f(for)g+(more)291 1034 y(information.)291 1276 y Fk(6.4.2)112+b(darcs)38 b(get)291 1433 y Fr(Usage:)j(darcs)g(get)i([OPTION]...)c+(<REPOSITORY>)f([<DIRECTORY>])415 1534 y Fx(Options:)652+1630 y Fr(--repo-name)h(DIRECTORY)444 b Fx(path)28 b(of)g(output)g+(directory)652 1770 y Fr(--partial)2015 1717 y Fx(get)g(partial)e(rep)r+(ository)g(using)i(c)n(hec)n(kp)r(oin)n(t)2015 1817 y(\(old-fashioned)f+(format)g(only\))652 1908 y Fr(--lazy)1099 b Fx(get)28+b(patc)n(h)f(\014les)h(only)f(as)g(needed)652 2007 y+Fr(--ephemeral)879 b Fx(don't)28 b(sa)n(v)n(e)e(patc)n(h)h(\014les)h+(in)g(the)g(rep)r(ository)652 2107 y Fr(--complete)923+b Fx(get)28 b(a)f(complete)g(cop)n(y)g(of)h(the)g(rep)r(ository)652+2236 y Fr(--to-match)39 b(PATTERN)2015 2194 y Fx(select)28+b(c)n(hanges)e(up)i(to)f(a)h(patc)n(h)f(matc)n(hing)2015+2294 y(P)-7 b(A)g(TTERN)652 2393 y Fr(--to-patch)39 b(REGEXP)2015+2352 y Fx(select)28 b(c)n(hanges)e(up)i(to)f(a)h(patc)n(h)f(matc)n+(hing)2015 2451 y(REGEXP)465 2521 y Fr(-t)99 b(--tag)41+b(REGEXP)838 b Fx(select)28 b(tag)f(matc)n(hing)g(REGEXP)652+2650 y Fr(--context)40 b(FILENAME)2015 2609 y Fx(v)n(ersion)26+b(sp)r(eci\014ed)i(b)n(y)g(the)g(con)n(text)f(in)2015+2708 y(FILENAME)652 2778 y Fr(--set-default)791 b Fx(set)28+b(default)g(rep)r(ository)e([DEF)-9 b(A)n(UL)i(T])652+2878 y Fr(--no-set-default)659 b Fx(don't)28 b(set)g(default)g(rep)r+(ository)652 2977 y Fr(--set-scripts-ex)o(ec)o(ut)o(abl)o(e)311+b Fx(mak)n(e)27 b(scripts)g(executable)652 3077 y Fr(--dont-set-scrip)o+(ts)o(-e)o(xec)o(ut)o(abl)o(e)93 b Fx(don't)28 b(mak)n(e)f(scripts)g+(executable)652 3176 y Fr(--nolinks)967 b Fx(do)28 b(not)f(link)h(rep)r+(ository)e(or)h(pristine)g(to)h(sibling)652 3276 y Fr(--plain-pristine)+o(-t)o(re)o(e)442 b Fx(use)28 b(a)f(plain)h(pristine)f(tree)g([DEF)-9+b(A)n(UL)i(T])652 3376 y Fr(--no-pristine-tr)o(ee)2015+3375 y Fx(use)28 b(no)f(pristine)h(tree)652 3475 y Fr(--hashed)2015+3483 y Fx(Con)n(v)n(ert)f(darcs-1)e(format)i(to)h(hashed)f(format)652+3575 y Fr(--old-fashioned-)o(in)o(ve)o(nto)o(ry)2015+3583 y Fx(Con)n(v)n(ert)g(from)g(hashed)g(to)g(darcs-1)f(format)652+3704 y Fr(--repodir)40 b(DIRECTORY)2015 3662 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)h(in)g(whic)n(h)h(to)2015+3762 y(run)415 3830 y(Adv)-5 b(anced)28 b(options:)565+3966 y Fr(--no-ssh-cm)1144 3914 y Fx(don't)f(use)h(SSH)g(Con)n+(trolMaster)d(feature)1144 4013 y([DEF)-9 b(A)n(UL)i(T])565+4104 y Fr(--ssh-cm)1144 4112 y Fx(use)27 b(SSH)h(Con)n(trolMaster)e+(feature)415 4201 y(If)f(the)f(remote)f(rep)r(ository)g(and)h(the)g+(curren)n(t)f(directory)g(are)g(in)h(the)h(same)e(\014lesystem)291+4301 y(and)j(that)h(\014lesystem)f(supp)r(orts)g(hard)g(links,)h(get)f+(will)h(create)f(hard)g(links)g(for)g(the)h(patc)n(h)291+4401 y(\014les,)38 b(whic)n(h)e(means)f(that)i(the)f(additional)f+(storage)f(space)i(needed)g(will)g(b)r(e)h(minimal.)291+4500 y(This)30 b(is)g Fs(very)39 b Fx(go)r(o)r(d)29 b(for)h(y)n(our)f+(disk)h(usage)g(\(and)g(for)g(the)h(sp)r(eed)f(of)h(running)f(get\),)h+(so)e(if)291 4600 y(y)n(ou)34 b(w)n(an)n(t)h(m)n(ultiple)h(copies)e(of)+i(a)e(rep)r(ository)-7 b(,)36 b(I)g(strongly)d(recommend)i(\014rst)g+(running)291 4700 y Fr(darcs)41 b(get)26 b Fx(to)h(get)g(y)n(ourself)f+(one)g(cop)n(y)-7 b(,)27 b(and)g(then)g(running)g Fr(darcs)42+b(get)26 b Fx(on)g(that)i(cop)n(y)291 4799 y(to)40 b(mak)n(e)g(an)n(y)f+(more)h(y)n(ou)g(lik)n(e.)75 b(The)41 b(only)f(catc)n(h)g(is)g(that)h+(the)g(\014rst)f(time)h(y)n(ou)f(run)291 4899 y Fr(darcs)h(push)34+b Fx(or)g Fr(darcs)42 b(pull)33 b Fx(from)i(an)n(y)g(of)g(these)g+(second)g(copies,)h(b)n(y)f(default)h(they)291 4998 y(will)27+b(access)g(y)n(our)f(\014rst)h(cop)n(y|whic)n(h)g(ma)n(y)g(not)h(b)r(e)+g(what)f(y)n(ou)g(w)n(an)n(t.)p eop end+%%Page: 62 62+TeXDict begin 62 61 bop 739 282 a Fx(62)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(Y)-7+b(ou)31 b(ma)n(y)f(sp)r(ecify)h(the)f(name)h(of)f(the)h(rep)r(ository)e+(created)g(b)n(y)i(pro)n(viding)e(a)h(second)739 615+y(argumen)n(t)c(to)i(get,)f(whic)n(h)h(is)f(a)h(directory)e(name.)p+975 805 2392 4 v 975 880 a Fr(--context,)40 b(--tag,)h(--to-patch,)e+(--to-match)p 975 935 V 739 1126 a Fx(If)c(y)n(ou)g(w)n(an)n(t)f(to)h+(get)g(a)g(sp)r(eci\014c)g(v)n(ersion)f(of)h(a)g(rep)r(ository)-7+b(,)35 b(y)n(ou)g(ha)n(v)n(e)f(a)g(few)i(options.)739+1225 y(Y)-7 b(ou)30 b(can)f(either)g(use)h(the)g Fr(--tag)p+Fx(,)e Fr(--to-patch)d Fx(or)k Fr(--to-match)d Fx(options,)j(or)g(y)n+(ou)g(can)739 1325 y(use)d(the)g Fr(--context=FILEN)o(AME)19+b Fx(option,)26 b(whic)n(h)g(sp)r(eci\014es)f(a)h(\014le)g(con)n+(taining)e(a)i(con)n(text)739 1425 y(generated)31 b(with)i+Fr(darcs)42 b(changes)f(--context)p Fx(.)48 b(This)32+b(allo)n(ws)g(y)n(ou)g(\(for)g(example\))g(to)739 1524+y(include)24 b(in)h(y)n(our)d(compiled)i(program)e(an)i(option)g(to)g+(output)h(the)f(precise)f(v)n(ersion)g(of)h(the)739 1624+y(rep)r(ository)j(from)i(whic)n(h)g(it)g(w)n(as)f(generated,)g(and)h+(then)g(p)r(erhaps)g(ask)f(users)g(to)h(include)739 1723+y(this)f(information)f(in)h(bug)f(rep)r(orts.)863 1825+y(Note)j(that)g(when)g(sp)r(ecifying)f Fr(--to-patch)d+Fx(or)i Fr(--to-match)p Fx(,)e(y)n(ou)j(ma)n(y)g(get)g(a)h(v)n(er-)739+1925 y(sion)j(of)g(y)n(our)f(co)r(de)h(that)g(has)g(nev)n(er)f(b)r+(efore)h(b)r(een)h(seen,)g(if)g(the)g(patc)n(hes)e(ha)n(v)n(e)h(gotten)+739 2024 y(themselv)n(es)23 b(reordered.)34 b(If)24 b(y)n(ou)f(ev)n(er)+g(w)n(an)n(t)g(to)h(b)r(e)g(able)f(to)h(precisely)f(repro)r(duce)g(a)g+(giv)n(en)739 2124 y(v)n(ersion,)j(y)n(ou)h(need)h(either)f(to)g(tag)g+(it)h(or)f(create)g(a)g(con)n(text)g(\014le.)739 2367+y Fk(6.4.3)112 b(darcs)38 b(put)739 2524 y Fr(Usage:)j(darcs)h(put)g+([OPTION]...)d(<NEW)j(REPOSITORY>)863 2625 y Fx(Options:)1100+2751 y Fr(--to-match)d(PATTERN)2464 2709 y Fx(select)27+b(c)n(hanges)f(up)i(to)g(a)f(patc)n(h)g(matc)n(hing)2464+2809 y(P)-7 b(A)g(TTERN)1100 2908 y Fr(--to-patch)39+b(REGEXP)2464 2867 y Fx(select)27 b(c)n(hanges)f(up)i(to)g(a)f(patc)n+(h)g(matc)n(hing)2464 2966 y(REGEXP)913 3036 y Fr(-t)99+b(--tag)42 b(REGEXP)838 b Fx(select)27 b(tag)g(matc)n(hing)g(REGEXP)+1100 3165 y Fr(--context)40 b(FILENAME)2464 3123 y Fx(v)n(ersion)26+b(sp)r(eci\014ed)i(b)n(y)f(the)h(con)n(text)f(in)2464+3223 y(FILENAME)1100 3293 y Fr(--set-scripts-ex)o(ecu)o(ta)o(ble)311+b Fx(mak)n(e)26 b(scripts)i(executable)1100 3392 y Fr(--dont-set-scrip)+o(ts-)o(ex)o(ecu)o(ta)o(bl)o(e)94 b Fx(don't)27 b(mak)n(e)g(scripts)g+(executable)1100 3492 y Fr(--hashed)2464 3500 y Fx(Con)n(v)n(ert)f+(darcs-1)f(format)j(to)f(hashed)g(format)1100 3592 y+Fr(--old-fashioned-)o(inv)o(en)o(tor)o(y)2464 3600 y+Fx(Con)n(v)n(ert)f(from)h(hashed)g(to)h(darcs-1)d(format)1100+3721 y Fr(--repodir)40 b(DIRECTORY)2464 3679 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)f(to)2464+3779 y(run)863 3847 y(Adv)-5 b(anced)28 b(options:)1013+3943 y Fr(--apply-as)39 b(USERNAME)97 b Fx(apply)27 b(patc)n(h)g(as)g+(another)g(user)g(using)g(sudo)1013 4083 y Fr(--apply-as-mysel)o(f)1941+4030 y Fx(don't)g(use)h(sudo)f(to)h(apply)f(as)g(another)f(user)1941+4130 y([DEF)-9 b(A)n(UL)i(T])1013 4261 y Fr(--no-ssh-cm)1941+4208 y Fx(don't)27 b(use)h(SSH)g(Con)n(trolMaster)d(feature)1941+4308 y([DEF)-9 b(A)n(UL)i(T])1013 4399 y Fr(--ssh-cm)1941+4407 y Fx(use)27 b(SSH)h(Con)n(trolMaster)e(feature)863+4496 y(Put)j(is)g(the)g(opp)r(osite)g(of)f(get.)41 b(Put)28+b(copies)g(the)i(con)n(ten)n(t)e(of)h(the)g(curren)n(t)f(rep)r(ository)+739 4596 y(and)f(puts)h(it)g(in)g(a)f(newly)h(created)f(rep)r(ository)+-7 b(.)863 4698 y Fs(W)h(ARNING:)31 b Fx(Put)26 b(is)g(far)g(less)f+(optimized)i(than)f(get,)g(esp)r(ecially)g(for)g(lo)r(cal)g(rep)r+(osito-)739 4797 y(ries.)36 b(W)-7 b(e)28 b(recommend)f(a)n(v)n(oiding)+f(use)h(of)h(put)g(except)g(for)f(small)g(rep)r(ositories.)863+4899 y(Put)f(is)g(used)f(when)h(y)n(ou)f(already)f(ha)n(v)n(e)h(a)g+(rep)r(ository)f(and)i(w)n(an)n(t)f(to)g(mak)n(e)g(a)g(cop)n(y)g(of)739+4998 y(it.)37 b(A)28 b(t)n(ypical)f(use-case)f(is)i(when)g(y)n(ou)f(w)n+(an)n(t)f(to)i(branc)n(h)f(y)n(our)f(pro)5 b(ject.)p+eop end+%%Page: 63 63+TeXDict begin 63 62 bop 291 282 a Fu(6.5.)63 b(MODIFYING)29+b(THE)e(CONTENTS)h(OF)f(A)h(REPOSITOR)-7 b(Y)553 b Fx(63)415+515 y(Put)21 b(w)n(orks)d(b)n(y)j(\014rst)f(initializing)g(a)g(rep)r+(ository)-7 b(.)33 b(If)21 b(the)g(new)g(rep)r(ository)d(is)j(not)f(on)+h(the)291 615 y(lo)r(cal)30 b(\014le)h(system)f(then)i(darcs)d(will)i+(login)f(to)h(the)g(remote)f(host)h(and)f(run)h Fr(darcs)41+b(init)291 715 y Fx(there.)52 b(After)34 b(the)f(new)g(rep)r(ository)e+(is)i(created)f(all)h(selected)g(patc)n(hes)f(will)h(b)r(e)h(pushed)291+814 y(just)28 b(as)f(with)h(the)g(command)f Fr(push)p+Fx(.)p 527 990 2392 4 v 527 1065 a Fr(--apply-as)p 527+1120 V 415 1296 a Fx(If)f(y)n(ou)g(giv)n(e)f(the)h Fr(--apply-as)c+Fx(\015ag,)j(darcs)g(will)h(use)g(sudo)f(to)h(apply)g(the)g(c)n(hanges)+f(as)291 1395 y(a)e(di\013eren)n(t)i(user.)35 b(This)24+b(can)g(b)r(e)h(useful)g(if)g(y)n(ou)e(w)n(an)n(t)h(to)g(set)g(up)h(a)f+(system)g(where)g(sev)n(eral)291 1495 y(users)33 b(can)h(mo)r(dify)h+(the)g(same)e(rep)r(ository)-7 b(,)35 b(but)g(y)n(ou)f(don't)g(w)n(an)n+(t)g(to)g(allo)n(w)f(them)i(full)291 1595 y(write)30+b(access.)46 b(This)31 b(isn't)h(secure)e(against)g(skilled)h+(malicious)f(attac)n(k)n(ers,)g(but)h(at)g(least)291+1694 y(can)c(protect)g(y)n(our)f(rep)r(ository)g(from)i(clumsy)-7+b(,)27 b(inept)h(or)f(lazy)g(users.)p 527 1870 V 527+1945 a Fr(--context,)39 b(--tag,)i(--to-patch,)e(--to-match)p+527 2000 V 291 2176 a Fx(If)34 b(y)n(ou)g(w)n(an)n(t)f(to)h(put)h(a)f+(sp)r(eci\014c)g(v)n(ersion)f(of)h(a)g(rep)r(ository)-7+b(,)35 b(y)n(ou)e(ha)n(v)n(e)g(a)h(few)g(options.)291+2275 y(Y)-7 b(ou)29 b(can)g(either)h(use)f(the)h Fr(--tag)p+Fx(,)e Fr(--to-patch)e Fx(or)j Fr(--to-match)c Fx(options,)30+b(or)e(y)n(ou)h(can)291 2375 y(use)c(the)h Fr(--context=FILENAM)o(E)20+b Fx(option,)26 b(whic)n(h)f(sp)r(eci\014es)h(a)f(\014le)h(con)n+(taining)f(a)g(con)n(text)291 2475 y(generated)31 b(with)i+Fr(darcs)42 b(changes)e(--context)p Fx(.)49 b(This)32+b(allo)n(ws)f(y)n(ou)h(\(for)h(example\))f(to)291 2574+y(include)24 b(in)g(y)n(our)f(compiled)h(program)e(an)i(option)g(to)g+(output)g(the)h(precise)e(v)n(ersion)g(of)h(the)291 2674+y(rep)r(ository)j(from)i(whic)n(h)f(it)i(w)n(as)e(generated,)g(and)h+(then)g(p)r(erhaps)g(ask)f(users)g(to)h(include)291 2773+y(this)e(information)g(in)h(bug)g(rep)r(orts.)415 2873+y(Note)i(that)g(when)f(sp)r(ecifying)h Fr(--to-patch)25+b Fx(or)k Fr(--to-match)p Fx(,)d(y)n(ou)j(ma)n(y)g(get)g(a)g(v)n(er-)+291 2973 y(sion)j(of)i(y)n(our)e(co)r(de)h(that)g(has)g(nev)n(er)f(b)r+(efore)h(b)r(een)h(seen,)g(if)g(the)g(patc)n(hes)e(ha)n(v)n(e)g(gotten)+291 3072 y(themselv)n(es)23 b(reordered.)34 b(If)24 b(y)n(ou)f(ev)n(er)+f(w)n(an)n(t)i(to)f(b)r(e)h(able)g(to)g(precisely)f(repro)r(duce)f(a)i+(giv)n(en)291 3172 y(v)n(ersion,)i(y)n(ou)h(need)g(either)h(to)f(tag)g+(it)h(or)f(create)g(a)g(con)n(text)g(\014le.)291 3445+y Fq(6.5)135 b(Mo)t(difying)45 b(the)g(con)l(ten)l(ts)h(of)f(a)g(rep)t+(ository)291 3644 y Fk(6.5.1)112 b(darcs)38 b(add)291+3797 y Fr(Usage:)j(darcs)g(add)i([OPTION]...)c(<FILE)i(or)i(DIRECTORY>)+c(...)415 3897 y Fx(Options:)652 3991 y Fr(--boring)575+b Fx(don't)28 b(skip)g(b)r(oring)f(\014les)652 4090 y+Fr(--case-ok)531 b Fx(don't)28 b(refuse)f(to)h(add)f(\014les)h+(di\013ering)f(only)g(in)h(case)465 4190 y Fr(-r)99 b(--recursive)1579+4198 y Fx(add)28 b(con)n(ten)n(ts)f(of)g(sub)r(directories)652+4290 y Fr(--not-recursive)1579 4298 y Fx(don't)h(add)g(con)n(ten)n(ts)f+(of)g(sub)r(directories)652 4429 y Fr(--date-trick)1579+4377 y Fx(add)g(\014les)f(with)h(date)g(app)r(ended)g(to)f(a)n(v)n(oid)+f(con\015ict)1579 4477 y([EXPERIMENT)-7 b(AL])652 4607+y Fr(--no-date-trick)1579 4555 y Fx(don't)28 b(use)g(exp)r(erimen)n+(tal)f(date)g(app)r(ending)h(tric)n(k)1579 4655 y([DEF)-9+b(A)n(UL)i(T])652 4775 y Fr(--repodir)40 b(DIRECTORY)1579+4733 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e(directory)h(in)h(whic)n+(h)f(to)1579 4833 y(run)652 4903 y Fr(--dry-run)531 b+Fx(don't)28 b(actually)f(tak)n(e)g(the)h(action)415 4998+y(Adv)-5 b(anced)28 b(options:)p eop end+%%Page: 64 64+TeXDict begin 64 63 bop 739 282 a Fx(64)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)1013 514 y Fr(--umask)41+b(UMASK)97 b Fx(sp)r(ecify)28 b(umask)f(to)h(use)f(when)h(writing)863+616 y(Add)36 b(needs)f(to)g(b)r(e)h(called)f(whenev)n(er)f(y)n(ou)h+(add)g(a)f(new)i(\014le)f(or)f(directory)g(to)h(y)n(our)739+716 y(pro)5 b(ject.)39 b(Of)28 b(course,)g(it)h(also)f(needs)g(to)g(b)r+(e)h(called)g(when)f(y)n(ou)g(\014rst)g(create)g(the)h(pro)5+b(ject,)739 815 y(to)27 b(let)h(darcs)f(kno)n(w)g(whic)n(h)g(\014les)h+(should)f(b)r(e)h(k)n(ept)f(trac)n(k)g(of.)863 916 y(Darcs)i(will)g+(refuse)f(to)h(add)g(a)f(\014le)h(or)f(directory)g(that)h(di\013ers)g+(from)f(an)h(existing)g(one)739 1016 y(only)e(in)g(case.)36+b(This)28 b(is)f(b)r(ecause)g(the)h(HFS+)f(\014le)h(system)f(used)g(on)+g(MacOS)g(treats)g(suc)n(h)739 1116 y(\014les)g(as)g(b)r(eing)h(one)f+(and)h(the)g(same.)863 1217 y(Y)-7 b(ou)32 b(can)g(not)g(add)f(sym)n(b)+r(olic)h(links)f(to)h(darcs.)49 b(If)32 b(y)n(ou)f(try)h(to)f(do)h+(that,)h(darcs)e(will)739 1316 y(refuse)26 b(and)g(prin)n(t)g(an)g+(error)e(message.)35 b(P)n(erhaps)24 b(y)n(ou)i(w)n(an)n(t)f(to)h(mak)n+(e)f(sym)n(b)r(olic)h(links)g Fs(to)739 1416 y Fx(the)i(\014les)f(in)h+(darcs)f(instead?)p 975 1604 2392 4 v 975 1678 a Fr(--boring)p+975 1733 V 863 1921 a Fx(By)i(default)g(darcs)f(will)h(ignore)e(all)i+(\014les)f(that)h(matc)n(h)g(an)n(y)f(of)g(the)i(b)r(oring)e(patterns.)+739 2021 y(If)g(y)n(ou)f(w)n(an)n(t)g(to)g(add)h(suc)n(h)f(a)g(\014le)h+(an)n(yw)n(a)n(y)d(y)n(ou)i(m)n(ust)h(use)f(the)h Fr(--boring)d+Fx(option.)p 975 2209 V 975 2283 a Fr(--date-trick)p+975 2320 V 863 2508 a Fx(The)40 b Fr(--date-trick)34+b Fx(option)39 b(allo)n(ws)f(y)n(ou)h(to)g(enable)g(an)g(exp)r(erimen)n+(tal)g(tric)n(k)f(to)739 2607 y(mak)n(e)e(add)g(con\015icts,)j(in)e+(whic)n(h)f(t)n(w)n(o)g(users)g(eac)n(h)g(add)g(a)h(\014le)g(or)e+(directory)h(with)h(the)739 2707 y(same)27 b(name,)g(less)g+(problematic.)36 b(While)28 b(this)g(tric)n(k)f(is)g(completely)g+(safe,)h(it)f(is)h(not)f(clear)739 2806 y(to)g(what)h(exten)n(t)g(it)g+(is)f(b)r(ene\014cial.)739 3046 y Fk(6.5.2)112 b(darcs)38+b(remo)m(v)m(e)739 3201 y Fr(Usage:)j(darcs)h(remove)f([OPTION]...)e+(<FILE)i(or)i(DIRECTORY>)c(...)863 3302 y Fx(Options:)1013+3427 y Fr(--repodir)h(DIRECTORY)1941 3386 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)d(directory)i(in)h(whic)n(h)f(to)1941+3485 y(run)863 3552 y(Adv)-5 b(anced)28 b(options:)1013+3652 y Fr(--umask)41 b(UMASK)97 b Fx(sp)r(ecify)28 b(umask)f(to)h(use)f+(when)h(writing)863 3754 y(Remo)n(v)n(e)e(should)g(b)r(e)h(called)f+(when)h(y)n(ou)f(w)n(an)n(t)f(to)i(remo)n(v)n(e)e(a)h(\014le)g(from)h+(y)n(our)e(pro)5 b(ject,)739 3854 y(but)40 b(don't)g(actually)f(w)n(an)+n(t)f(to)i(delete)f(the)h(\014le.)73 b(Otherwise)39 b(just)h(delete)g+(the)f(\014le)h(or)739 3954 y(directory)-7 b(,)34 b(and)f(darcs)g(will)+h(notice)f(that)h(it)g(has)f(b)r(een)h(remo)n(v)n(ed.)53+b(Be)34 b(a)n(w)n(are)d(that)j(the)739 4053 y(\014le)c(WILL)f(b)r(e)h+(deleted)g(from)g(an)n(y)f(other)g(cop)n(y)f(of)i(the)g(rep)r(ository)e+(to)h(whic)n(h)h(y)n(ou)f(later)739 4153 y(apply)e(the)h(patc)n(h.)739+4392 y Fk(6.5.3)112 b(darcs)38 b(m)m(v)739 4548 y Fr(Usage:)j(darcs)h+(mv)g([OPTION]...)d([FILE)j(or)h(DIRECTORY]...)863 4649+y Fx(Options:)1013 4744 y Fr(--case-ok)532 b Fx(don't)27+b(refuse)h(to)f(add)h(\014les)f(di\013ering)g(only)h(in)f(case)1013+4873 y Fr(--repodir)40 b(DIRECTORY)1941 4832 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)d(directory)i(in)h(whic)n(h)f(to)1941+4931 y(run)863 4998 y(Adv)-5 b(anced)28 b(options:)p+eop end+%%Page: 65 65+TeXDict begin 65 64 bop 291 282 a Fu(6.5.)63 b(MODIFYING)29+b(THE)e(CONTENTS)h(OF)f(A)h(REPOSITOR)-7 b(Y)553 b Fx(65)565+514 y Fr(--umask)40 b(UMASK)98 b Fx(sp)r(ecify)28 b(umask)f(to)g(use)h+(when)f(writing)415 615 y(Darcs)f(m)n(v)g(needs)g(to)g(b)r(e)h(called)f+(whenev)n(er)g(y)n(ou)f(w)n(an)n(t)h(to)g(mo)n(v)n(e)f(\014les)i(or)e+(directories.)291 715 y(Unlik)n(e)e(remo)n(v)n(e,)g(m)n(v)g(actually)g+(p)r(erforms)g(the)h(mo)n(v)n(e)f(itself)h(in)g(y)n(our)e(w)n(orking)g+(cop)n(y)-7 b(.)35 b(This)291 814 y(is)26 b(wh)n(y)f(\\m)n(v")g(isn't)i+(called)e(\\mo)n(v)n(e",)g(since)h(it)g(is)g(really)f(almost)g(equiv)-5+b(alen)n(t)26 b(to)g(the)h(unix)291 914 y(command)g(\\m)n(v".)p+527 1083 2392 4 v 527 1158 a Fr(--case-ok)p 527 1194+V 415 1363 a Fx(Darcs)g(m)n(v)g(will)g(b)n(y)g(default)h(refuse)f(to)g+(rename)g(a)g(\014le)g(if)h(there)f(already)f(exists)h(a)g(\014le)291+1463 y(ha)n(ving)e(the)h(same)g(name)g(apart)g(from)g(case.)35+b(This)26 b(is)h(b)r(ecause)f(doing)f(so)h(could)g(create)f(a)291+1562 y(rep)r(ository)f(that)h(could)h(not)g(b)r(e)g(used)f(on)h(\014le)+f(systems)g(that)h(are)f(case)g(insensitiv)n(e)g(\(suc)n(h)291+1662 y(as)i(Apple's)g(HFS+\).)38 b(Y)-7 b(ou)28 b(can)f(o)n(v)n(erride)+e(this)j(b)n(y)f(with)h(the)g(\015ag)f Fr(--case-ok)p+Fx(.)291 1892 y Fk(6.5.4)112 b(darcs)38 b(replace)291+2045 y Fr(Usage:)j(darcs)g(replace)g([OPTION]...)e(<OLD>)i(<NEW>)h+(<FILE>)f(...)415 2145 y Fx(Options:)652 2239 y Fr(--token-chars)d+("[CHARS]")1754 2247 y Fx(de\014ne)28 b(tok)n(en)f(to)g(con)n(tain)g+(these)h(c)n(haracters)465 2376 y Fr(-f)99 b(--force)1754+2327 y Fx(pro)r(ceed)27 b(with)h(replace)e(ev)n(en)i(if)g('new')f(tok)n+(en)1754 2426 y(already)f(exists)652 2512 y Fr(--no-force)662+b Fx(don't)28 b(force)e(the)i(replace)f(if)h(it)g(lo)r(oks)f(scary)652+2641 y Fr(--repodir)40 b(DIRECTORY)1754 2600 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)f(to)1754+2699 y(run)415 2765 y(Adv)-5 b(anced)28 b(options:)565+2859 y Fr(--ignore-times)1274 2867 y Fx(don't)g(trust)g(the)g(\014le)g+(mo)r(di\014cation)f(times)565 2959 y Fr(--umask)40 b(UMASK)141+b Fx(sp)r(ecify)28 b(umask)f(to)h(use)f(when)h(writing)415+3055 y(Replace)37 b(allo)n(ws)f(y)n(ou)h(to)g(c)n(hange)f(a)h(sp)r+(eci\014ed)g(tok)n(en)g(wherev)n(er)f(it)i(o)r(ccurs)e(in)i(the)291+3154 y(sp)r(eci\014ed)h(\014les.)71 b(The)39 b(replace)f(is)h(enco)r+(ded)h(in)f(a)g(sp)r(ecial)f(patc)n(h)h(and)g(will)g(merge)g(as)291+3254 y(exp)r(ected)23 b(with)g(other)g(patc)n(hes.)34+b(T)-7 b(ok)n(ens)22 b(here)h(are)e(de\014ned)j(b)n(y)e(a)h(regexp)f+(sp)r(ecifying)h(the)291 3354 y(c)n(haracters)i(whic)n(h)i(are)g(allo)n+(w)n(ed.)35 b(By)28 b(default)g(a)f(tok)n(en)g(corresp)r(onds)f(to)h(a)+g(C)h(iden)n(ti\014er.)415 3453 y(The)37 b(default)g(regexp)f(is)h+Fr([A-Za-z_0-9])p Fx(\),)e(and)h(if)i(one)e(of)h(y)n(our)f(tok)n(ens)g+(con)n(tains)291 3553 y(a)41 b(`)p Fr(-)p Fx(')g(or)f(`)p+Fr(.)p Fx(',)45 b(y)n(ou)c(will)g(then)h(\(b)n(y)g(default\))g(get)f+(the)h(\\\014lename")e(regexp,)k(whic)n(h)d(is)291 3653+y Fr([A-Za-z_0-9\\-\\.)o(])p Fx(.)p 527 3822 V 527 3896+a Fr(--token-chars)p 527 3933 V 415 4102 a Fx(If)f(y)n(ou)e(prefer)h+(to)g(c)n(ho)r(ose)f(a)h(di\013eren)n(t)g(set)h(of)f(c)n(haracters)e+(to)i(de\014ne)g(y)n(our)g(tok)n(en)291 4201 y(\(p)r(erhaps)44+b(b)r(ecause)g(y)n(ou)f(are)h(programming)e(in)j(some)f(other)g+(language\),)j(y)n(ou)d(ma)n(y)291 4301 y(do)39 b(so)g(with)i(the)f+Fr(--token-chars)35 b Fx(option.)73 b(Y)-7 b(ou)40 b(ma)n(y)f(prefer)h+(to)f(de\014ne)i(tok)n(ens)e(in)291 4401 y(terms)25 b(of)g(delimiting)h+(c)n(haracters)d(instead)j(of)f(allo)n(w)n(ed)f(c)n(haracters)f(using)j+(a)f(\015ag)f(suc)n(h)i(as)291 4500 y Fr(--token-chars)38+b('[^)k(\\n\\t]')p Fx(,)26 b(whic)n(h)j(w)n(ould)f(de\014ne)g(a)g(tok)n+(en)g(as)g(b)r(eing)h(white-space)291 4600 y(delimited.)415+4700 y(If)19 b(y)n(ou)f(do)g(c)n(ho)r(ose)f(a)h(non-default)g(tok)n(en)+g(de\014nition,)i(I)f(recommend)f(using)g Fr(_darcs/prefs/de)o(fau)o+(lt)o(s)291 4799 y Fx(to)31 b(alw)n(a)n(ys)e(sp)r(ecify)i(the)h(same)e+Fr(--token-chars)p Fx(,)d(since)k(y)n(our)f(replace)g(patc)n(hes)g+(will)i(b)r(e)291 4899 y(b)r(etter)f(b)r(eha)n(v)n(ed)f(\(in)h(terms)g+(of)g(comm)n(utation)f(and)h(merges\))f(if)h(they)g(ha)n(v)n(e)f(tok)n+(ens)g(de-)291 4998 y(\014ned)e(in)f(the)h(same)f(w)n(a)n(y)-7+b(.)p eop end+%%Page: 66 66+TeXDict begin 66 65 bop 739 282 a Fx(66)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(When)j(using)e(darcs)g+(replace,)h(the)g(\\new")f(tok)n(en)g(ma)n(y)g(not)h(already)f(app)r+(ear)g(in)h(the)739 615 y(\014le|if)h(that)f(is)g(the)g(case,)g(the)h+(replace)e(c)n(hange)f(w)n(ould)i(not)g(b)r(e)h(in)n(v)n(ertible.)43+b(This)30 b(limi-)739 715 y(tation)d(holds)h(only)f(on)g(the)h+(already-recorded)c(v)n(ersion)i(of)i(the)g(\014le.)863+814 y(There)h(is)f(a)h(p)r(oten)n(tially)f(confusing)h(di\013erence,)g+(ho)n(w)n(ev)n(er,)e(when)i(a)f(replace)g(is)g(used)739+914 y(to)f(mak)n(e)g(another)g(replace)f(p)r(ossible:)739+1062 y Fr(\045)43 b(darcs)f(replace)e(newtoken)h(aaack)g(./foo.c)739+1161 y(\045)i(darcs)f(replace)e(oldtoken)h(newtoken)f(./foo.c)739+1261 y(\045)j(darcs)f(record)739 1409 y Fx(will)29 b(b)r(e)h(v)-5+b(alid,)29 b(ev)n(en)f(if)i Fr(newtoken)c Fx(and)j Fr(oldtoken)c+Fx(are)j(b)r(oth)i(presen)n(t)e(in)h(the)h(recorded)739+1508 y(v)n(ersion)c(of)h(fo)r(o.c,)h(while)g(the)g(sequence)739+1656 y Fr(\045)43 b([manually)d(edit)i(foo.c)f(replacing)f(newtoken)h+(with)g(aaack])739 1756 y(\045)i(darcs)f(replace)e(oldtoken)h(newtoken)+f(./foo.c)739 1904 y Fx(will)31 b(fail)f(b)r(ecause)h(\\newtok)n(en")e+(still)h(exists)h(in)g(the)g(recorded)e(v)n(ersion)g(of)h+Fr(foo.c)p Fx(.)44 b(The)739 2003 y(reason)35 b(for)h(the)h+(di\013erence)g(is)g(that)g(when)g(recording,)g(a)f(\\replace")f(patc)n+(h)i(alw)n(a)n(ys)d(is)739 2103 y(recorded)k Fs(b)l(efor)l(e)46+b Fx(an)n(y)38 b(man)n(ual)h(c)n(hanges,)i(whic)n(h)e(is)g(usually)f+(what)i(y)n(ou)e(w)n(an)n(t,)j(since)739 2202 y(often)d(y)n(ou)f(will)h+(in)n(tro)r(duce)g(new)g(o)r(ccurrences)e(of)i(the)h(\\newtok)n(en")d+(in)i(y)n(our)f(man)n(ual)739 2302 y(c)n(hanges.)53 b(In)34+b(con)n(trast,)f(m)n(ultiple)h(\\replace")e(c)n(hanges)g(are)g+(recorded)g(in)i(the)g(order)e(in)739 2402 y(whic)n(h)27+b(they)h(w)n(ere)f(made.)739 2672 y Fq(6.6)135 b(W)-11+b(orking)45 b(with)h(c)l(hanges)739 2871 y Fk(6.6.1)112+b(darcs)38 b(record)739 3024 y Fr(Usage:)j(darcs)h(record)f+([OPTION]...)e([FILE)i(or)i(DIRECTORY]...)863 3124 y+Fx(Options:)913 3218 y Fr(-m)99 b(--patch-name)39 b(PATCHNAME)139+b Fx(name)28 b(of)f(patc)n(h)913 3317 y Fr(-A)99 b(--author)40+b(EMAIL)490 b Fx(sp)r(ecify)28 b(author)f(id)1100 3417+y Fr(--no-test)706 b Fx(don't)28 b(run)f(the)h(test)g(script)1100+3517 y Fr(--test)838 b Fx(run)28 b(the)g(test)f(script)1100+3616 y Fr(--leave-test-dir)o(ect)o(or)o(y)137 b Fx(don't)28+b(remo)n(v)n(e)e(the)i(test)g(directory)1100 3716 y Fr+(--remove-test-di)o(rec)o(to)o(ry)93 b Fx(remo)n(v)n(e)26+b(the)i(test)g(directory)913 3816 y Fr(-a)99 b(--all)882+b Fx(answ)n(er)26 b(y)n(es)h(to)h(all)f(patc)n(hes)1100+3915 y Fr(--pipe)838 b Fx(exp)r(ect)28 b(to)g(receiv)n(e)e(input)i+(from)g(a)f(pip)r(e)913 4015 y Fr(-i)99 b(--interactive)530+b Fx(prompt)28 b(user)f(in)n(teractiv)n(ely)1100 4114+y Fr(--ask-deps)662 b Fx(ask)27 b(for)g(extra)g(dep)r(endencies)1100+4214 y Fr(--no-ask-deps)530 b Fx(don't)28 b(ask)f(for)g(extra)f(dep)r+(endencies)1100 4314 y Fr(--edit-long-comm)o(ent)267+b Fx(edit)28 b(the)g(long)f(commen)n(t)h(b)n(y)f(default)1100+4413 y Fr(--skip-long-comm)o(ent)267 b Fx(don't)28 b(giv)n(e)f(a)g+(long)g(commen)n(t)1100 4513 y Fr(--prompt-long-co)o(mme)o(nt)180+b Fx(prompt)26 b(for)g(whether)h(to)f(edit)h(the)g(long)f(commen)n(t)+913 4644 y Fr(-l)99 b(--look-for-adds)2202 4605 y Fx(lo)r(ok)27+b(for)g(\(non-b)r(oring\))g(\014les)g(that)h(could)g(b)r(e)2202+4705 y(added)1100 4814 y Fr(--dont-look-for-)o(add)o(s)2202+4762 y Fx(don't)g(lo)r(ok)f(for)g(an)n(y)g(\014les)g(that)h(could)f(b)r+(e)h(added)2202 4862 y([DEF)-9 b(A)n(UL)i(T])1100 4982+y Fr(--repodir)40 b(DIRECTORY)2202 4940 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)g(to)2202+5040 y(run)p eop end+%%Page: 67 67+TeXDict begin 67 66 bop 291 282 a Fu(6.6.)63 b(W)n(ORKING)28+b(WITH)g(CHANGES)1450 b Fx(67)415 515 y(Adv)-5 b(anced)28+b(options:)565 610 y Fr(--logfile)39 b(FILE)186 b Fx(giv)n(e)26+b(patc)n(h)i(name)f(and)g(commen)n(t)h(in)g(\014le)565+710 y Fr(--delete-logfil)o(e)94 b Fx(delete)27 b(the)h(log\014le)f+(when)h(done)565 810 y Fr(--compress)357 b Fx(create)26+b(compressed)h(patc)n(hes)565 909 y Fr(--dont-compress)137+b Fx(don't)27 b(create)g(compressed)f(patc)n(hes)565+1009 y Fr(--ignore-times)1362 1017 y Fx(don't)h(trust)h(the)g(\014le)g+(mo)r(di\014cation)f(times)565 1108 y Fr(--umask)40 b(UMASK)229+b Fx(sp)r(ecify)27 b(umask)h(to)f(use)g(when)h(writing)415+1205 y(If)36 b(y)n(ou)g(pro)n(vide)e(one)i(or)f(more)g(\014les)h(or)f+(directories)g(as)g(additional)g(argumen)n(ts)g(to)291+1305 y(record,)25 b(y)n(ou)i(will)g(only)g(b)r(e)h(prompted)f(to)g(c)n+(hanges)f(in)h(those)g(\014les)g(or)g(directories.)35+b(Eac)n(h)291 1404 y(patc)n(h)e(is)h(giv)n(en)f(a)g(name,)j(whic)n(h)d+(t)n(ypically)h(w)n(ould)f(consist)g(of)h(a)g(brief)g(description)f(of)+291 1504 y(the)28 b(c)n(hanges.)35 b(This)28 b(name)f(is)h(later)f+(used)h(to)f(describ)r(e)h(the)g(patc)n(h.)36 b(The)28+b(name)g(m)n(ust)f(\014t)291 1604 y(on)f(one)h(line)g(\(i.e.)h(cannot)e+(ha)n(v)n(e)g(an)n(y)g(em)n(b)r(edded)i(newlines\).)36+b(If)28 b(y)n(ou)e(ha)n(v)n(e)g(more)g(to)h(sa)n(y)-7+b(,)291 1703 y(stic)n(k)27 b(it)h(in)g(the)g(log.)415+1804 y(The)34 b(patc)n(h)f(is)h(also)f(\015agged)f(with)j(the)f(author)+f(of)g(the)i(c)n(hange,)f(tak)n(en)f(b)n(y)g(default)291+1903 y(from)k(the)i Fr(DARCS_EMAIL)34 b Fx(en)n(vironmen)n(t)j(v)-5+b(ariable,)40 b(and)e(if)h(that)f(do)r(esn't)g(exist,)j(from)291+2003 y(the)36 b Fr(EMAIL)d Fx(en)n(vironmen)n(t)i(v)-5+b(ariable.)60 b(The)36 b(date)g(on)f(whic)n(h)h(the)g(patc)n(h)g(w)n+(as)e(recorded)291 2102 y(is)h(also)f(included.)59 b(Curren)n(tly)34+b(there)h(is)g(no)g(pro)n(vision)e(for)i(k)n(eeping)f(trac)n(k)g(of)h+(when)g(a)291 2202 y(patc)n(h)c(en)n(ters)f(a)h(giv)n(en)f(rep)r+(ository)-7 b(.)46 b(Finally)-7 b(,)33 b(eac)n(h)d(c)n(hangeset)g+(should)h(ha)n(v)n(e)f(a)h(full)h(log)291 2302 y(\(whic)n(h)k(ma)n(y)g+(b)r(e)g(empt)n(y\).)63 b(This)37 b(log)e(is)h(for)g(detailed)g(notes)g+(whic)n(h)g(are)f(to)r(o)h(length)n(y)291 2401 y(to)c(\014t)h(in)g(the)+g(name.)52 b(If)33 b(y)n(ou)f(answ)n(er)f(that)i(y)n(ou)f(do)h(w)n(an)n+(t)f(to)g(create)g(a)g(commen)n(t)h(\014le,)291 2501+y(darcs)27 b(will)i(op)r(en)g(an)f(editor)h(so)f(that)h(y)n(ou)f(can)g+(en)n(ter)g(the)h(commen)n(t)g(in.)40 b(The)29 b(c)n(hoice)f(of)291+2601 y(editor)i(pro)r(ceeds)h(as)f(follo)n(ws.)47 b(If)32+b(one)f(of)g(the)h Fr($DARCS_EDITOR)p Fx(,)26 b Fr($VISUAL)i+Fx(or)j Fr($EDITOR)291 2700 y Fx(en)n(vironmen)n(t)d(v)-5+b(ariables)27 b(is)i(de\014ned,)h(its)g(v)-5 b(alue)29+b(is)f(used)i(\(with)f(precedence)g(pro)r(ceeding)291+2800 y(in)c(the)h(order)f(listed\).)36 b(If)26 b(not,)h(\\vi",)e+(\\emacs",)f(\\emacs)g(-n)n(w")h(and)h(\\nano")d(are)i(tried)h(in)291+2899 y(that)h(order.)p 527 3085 2392 4 v 527 3160 a Fr(--logfile)p+527 3215 V 415 3401 a Fx(If)k(y)n(ou)e(wish,)i(y)n(ou)f(ma)n(y)f(sp)r+(ecify)i(the)f(patc)n(h)g(name)g(and)h(log)e(using)h(the)h+Fr(--logfile)291 3500 y Fx(\015ag.)66 b(If)38 b(y)n(ou)e(do)i(so,)h+(the)f(\014rst)f(line)h(of)g(the)g(sp)r(eci\014ed)g(\014le)f(will)h(b)r+(e)g(tak)n(en)f(to)h(b)r(e)g(the)291 3600 y(patc)n(h)29+b(name,)i(and)f(the)g(remainder)f(will)i(b)r(e)f(the)h(\\long)e(commen)+n(t".)43 b(This)31 b(feature)e(can)291 3700 y(b)r(e)22+b(esp)r(ecially)g(handy)h(if)g(y)n(ou)e(ha)n(v)n(e)g(a)h(test)h(that)g+(fails)f(sev)n(eral)f(times)i(on)f(the)h(record)e(\(th)n(us)291+3799 y(ab)r(orting)30 b(the)h(record\),)g(so)g(y)n(ou)f(don't)i(ha)n(v)+n(e)d(to)j(t)n(yp)r(e)f(in)g(the)h(long)e(commen)n(t)h(m)n(ultiple)291+3899 y(times.)37 b(The)27 b(\014le's)h(con)n(ten)n(ts)f(will)h(o)n(v)n+(erride)d(the)j Fr(--patch-name)23 b Fx(option.)p 527+4085 V 527 4159 a Fr(--ask-deps)p 527 4214 V 415 4400+a Fx(Eac)n(h)29 b(patc)n(h)g(ma)n(y)g(dep)r(end)i(on)f(an)n(y)f(n)n(um)+n(b)r(er)g(of)h(previous)f(patc)n(hes.)43 b(If)30 b(y)n(ou)f(c)n(ho)r+(ose)291 4500 y(to)j(mak)n(e)g(y)n(our)f(patc)n(h)h(dep)r(end)h(on)f(a)+g(previous)g(patc)n(h,)h(that)g(patc)n(h)f(is)h(required)e(to)i(b)r(e)+291 4599 y(applied)27 b(b)r(efore)g(y)n(our)f(patc)n(h)h(can)f(b)r(e)i+(applied)f(to)g(a)g(rep)r(ository)-7 b(.)35 b(This)28+b(can)e(b)r(e)i(used,)f(for)291 4699 y(example,)f(if)i(a)e(piece)h(of)g+(co)r(de)g(requires)f(a)g(function)i(to)f(b)r(e)g(de\014ned,)h(whic)n+(h)f(w)n(as)f(de\014ned)291 4798 y(in)h(an)h(earlier)e(patc)n(h.)415+4899 y(If)e(y)n(ou)e(w)n(an)n(t)h(to)g(man)n(ually)g(de\014ne)g(an)n(y)+g(dep)r(endencies)h(for)e(y)n(our)h(patc)n(h,)h(y)n(ou)e(can)h(use)291+4998 y(the)28 b Fr(--ask-deps)23 b Fx(\015ag,)k(and)g(darcs)g(will)h+(ask)e(y)n(ou)h(for)g(the)h(patc)n(h's)f(dep)r(endencies.)p+eop end+%%Page: 68 68+TeXDict begin 68 67 bop 739 282 a Fx(68)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(It)42+b(is)g(p)r(ossible)f(to)g(record)g(a)g(patc)n(h)g(whic)n(h)h(has)f(no)g+(actual)g(c)n(hanges)f(but)i(whic)n(h)739 615 y(has)32+b(sp)r(eci\014c)g(dep)r(endencies.)52 b(This)32 b(t)n(yp)r(e)g(of)h+(patc)n(h)f(can)g(b)r(e)h(though)n(t)f(of)g(as)g(a)g(\\partial)739+715 y(tag".)67 b(The)39 b Fr(darcs)i(tag)c Fx(command)h(will)g(record)f+(a)h(patc)n(h)g(with)g(no)g(actual)g(c)n(hanges)739 814+y(but)44 b(whic)n(h)g(dep)r(ends)g(on)f(the)h(en)n(tire)f(curren)n(t)g+(in)n(v)n(en)n(tory)e(of)j(the)g(rep)r(ository)-7 b(.)83+b(The)739 914 y Fr(darcs)41 b(record)h(--ask-deps)29+b Fx(with)34 b(no)f(selected)g(c)n(hanges)f(will)i(record)e(a)h(patc)n+(h)g(that)739 1013 y(dep)r(ends)25 b(on)f(only)g(those)g(patc)n(hes)g+(selected)g(via)g(the)h Fr(--ask-deps)c Fx(op)r(eration,)j(resulting)+739 1113 y(in)29 b(a)f(patc)n(h)g(whic)n(h)h(describ)r(es)f(a)g(set)h+(of)f(patc)n(hes;)h(the)g(presence)f(of)g(this)h(primary)f(patc)n(h)739+1213 y(in)g(a)f(rep)r(ository)f(implies)i(the)g(presence)e(of)i(\(at)g+(least\))f(the)h(dep)r(ended-up)r(on)g(patc)n(hes.)p+975 1388 2392 4 v 975 1463 a Fr(--no-test,)83 b(--test)p+975 1511 V 863 1687 a Fx(If)38 b(y)n(ou)e(con\014gure)f(darcs)h(to)g+(run)h(a)f(test)h(suite,)i(darcs)d(will)h(run)f(this)h(test)g(on)g(the)+739 1787 y(recorded)27 b(rep)r(ository)h(to)h(mak)n(e)f(sure)g(it)i(is)+f(v)-5 b(alid.)41 b(Darcs)28 b(\014rst)h(creates)f(a)g(pristine)h(cop)n+(y)739 1886 y(of)34 b(the)i(source)d(tree)h(\(in)h(a)g(temp)r(orary)e+(directory\),)j(then)f(it)g(runs)f(the)h(test,)i(using)d(its)739+1986 y(return)26 b(v)-5 b(alue)27 b(to)g(decide)g(if)h(the)f(record)f+(is)h(v)-5 b(alid.)37 b(If)27 b(it)g(is)g(not)g(v)-5+b(alid,)28 b(the)f(record)f(will)h(b)r(e)739 2085 y(ab)r(orted.)47+b(This)32 b(is)f(a)g(handy)g(w)n(a)n(y)f(to)h(a)n(v)n(oid)f(making)h+(stupid)h(mistak)n(es)e(lik)n(e)h(forgetting)739 2185+y(to)i(`darcs)g(add')g(a)g(new)h(\014le.)54 b(It)34 b(also)f(can)g(b)r+(e)h(tediously)f(slo)n(w,)h(so)f(there)g(is)g(an)h(option)739+2285 y(\()p Fr(--no-test)p Fx(\))24 b(to)k(skip)f(the)h(test.)p+975 2460 V 975 2535 a Fr(--pipe)p 975 2590 V 863 2766+a Fx(If)22 b(y)n(ou)f(run)g(record)f(with)i(the)g Fr(--pipe)d+Fx(option,)j(y)n(ou)f(will)h(b)r(e)g(prompted)f(for)g(the)h(patc)n(h)+739 2866 y(date,)32 b(the)f(author,)h(the)f(patc)n(h)g(name,)h(and)f+(the)h(long)e(commen)n(t.)48 b(The)31 b(long)f(commen)n(t)739+2965 y(will)21 b(extend)h(un)n(til)f(the)g(end)h(of)f(\014le)g(of)g+(stdin)h(is)f(reac)n(hed)e(\(ctrl-D)j(on)f(Unixy)g(systems,)h(ctrl-)739+3065 y(Z)30 b(on)g(systems)f(running)h(a)g(Microsoft)f(OS\).)h(This)g+(in)n(terface)g(is)g(in)n(tended)g(for)g(scripting)739+3164 y(darcs,)f(in)h(particular)f(for)g(writing)g(rep)r(ository)g(con)n+(v)n(ersion)e(scripts.)43 b(The)30 b(prompts)f(are)739+3264 y(in)n(tended)h(mostly)f(as)g(a)g(useful)h(guide)f(\(since)g+(scripts)g(w)n(on't)h(need)f(them\),)i(to)e(help)h(y)n(ou)739+3364 y(understand)d(the)h(format)f(in)h(whic)n(h)g(to)f(pro)n(vide)f+(the)i(input.)p 975 3539 V 975 3614 a Fr(--interactive)p+975 3651 V 863 3826 a Fx(By)k(default,)i Fr(record)c+Fx(w)n(orks)h(in)n(teractiv)n(ely)-7 b(.)50 b(Probably)30+b(the)j(only)f(thing)h(y)n(ou)e(need)739 3926 y(to)e(kno)n(w)g(ab)r+(out)g(using)g(this)g(is)h(that)f(y)n(ou)g(can)g(press)f+Fr(?)h Fx(at)g(the)h(prompt)f(to)g(b)r(e)h(sho)n(wn)f(a)739+4026 y(list)g(of)f(the)h(rest)f(of)h(the)g(options)f(and)g(what)h(they)+f(do.)40 b(The)29 b(rest)f(should)g(b)r(e)h(clear)f(from)739+4125 y(there.)37 b(Here's)27 b(a)g(\\screenshot")e(to)j(demonstrate:)+739 4301 y Fr(hunk)42 b(./hello.pl)d(+2)739 4401 y(+#!/usr/bin/perl)739+4500 y(+print)i("Hello)g(World!\\n";)739 4600 y(Shall)g(I)j(record)d+(this)h(patch?)f(\(2/2\))g([ynWsfqadjk],)d(or)43 b(?)g(for)g(help:)e(?)+739 4700 y(How)h(to)h(use)f(record...)739 4799 y(y:)h(record)e(this)h+(patch)739 4899 y(n:)h(don't)e(record)g(it)739 4998 y(w:)i(wait)f(and)g+(decide)f(later,)g(defaulting)f(to)i(no)p eop end+%%Page: 69 69+TeXDict begin 69 68 bop 291 282 a Fu(6.6.)63 b(W)n(ORKING)28+b(WITH)g(CHANGES)1450 b Fx(69)291 615 y Fr(s:)42 b(don't)g(record)f+(the)h(rest)g(of)h(the)f(changes)f(to)i(this)f(file)291+715 y(f:)g(record)f(the)i(rest)f(of)g(the)h(changes)e(to)h(this)g(file)+291 914 y(d:)g(record)f(selected)g(patches)291 1013 y(a:)h(record)f+(all)i(the)f(remaining)e(patches)291 1113 y(q:)i(cancel)f(record)291+1312 y(j:)h(skip)g(to)h(next)f(patch)291 1412 y(k:)g(back)g(up)h(to)g+(previous)d(patch)291 1512 y(h)j(or)g(?:)f(show)g(this)g(help)291+1711 y(<Space>:)e(accept)h(the)h(current)f(default)g(\(which)g(is)i+(capitalized\))291 2128 y Fx(What)26 b(y)n(ou)g(can't)g(see)g(in)h+(that)f(\\screenshot")f(is)h(that)h Fr(darcs)d Fx(will)j(also)e(try)h+(to)g(use)g(color)291 2228 y(in)h(y)n(our)g(terminal)g(to)h(mak)n(e)e+(the)i(output)g(ev)n(en)g(easier)e(to)h(read.)291 2640+y Fk(6.6.2)112 b(darcs)38 b(pull)291 2856 y Fr(Usage:)j(darcs)g(pull)h+([OPTION]...)d([REPOSITORY]...)415 2990 y Fx(Options:)652+3118 y Fr(--matches)h(PATTERN)401 b Fx(select)28 b(patc)n(hes)f(matc)n+(hing)g(P)-7 b(A)g(TTERN)465 3217 y Fr(-p)99 b(--patches)40+b(REGEXP)445 b Fx(select)28 b(patc)n(hes)f(matc)n(hing)g(REGEXP)465+3317 y Fr(-t)99 b(--tags)41 b(REGEXP)576 b Fx(select)28+b(tags)f(matc)n(hing)g(REGEXP)465 3416 y Fr(-a)99 b(--all)925+b Fx(answ)n(er)27 b(y)n(es)f(to)i(all)f(patc)n(hes)465+3516 y Fr(-i)99 b(--interactive)573 b Fx(prompt)28 b(user)f(in)n+(teractiv)n(ely)652 3616 y Fr(--mark-conflicts)441 b+Fx(mark)27 b(con\015icts)g([DEF)-9 b(A)n(UL)i(T])652+3715 y Fr(--allow-conflict)o(s)398 b Fx(allo)n(w)27 b(con\015icts,)g+(but)h(don't)g(mark)f(them)652 3815 y Fr(--dont-allow-con)o(fl)o(ic)o+(ts)180 b Fx(fail)28 b(on)f(patc)n(hes)g(that)h(create)f(con\015icts)+652 3915 y Fr(--external-merge)37 b(COMMAND)96 b Fx(use)28+b(external)f(to)r(ol)g(to)g(merge)g(con\015icts)652 4014+y Fr(--test)881 b Fx(run)28 b(the)g(test)g(script)652+4114 y Fr(--no-test)749 b Fx(don't)28 b(run)g(the)g(test)g(script)652+4213 y Fr(--dry-run)749 b Fx(don't)28 b(actually)f(tak)n(e)g(the)h+(action)465 4313 y Fr(-s)99 b(--summary)749 b Fx(summarize)27+b(c)n(hanges)652 4413 y Fr(--no-summary)617 b Fx(don't)28+b(summarize)f(c)n(hanges)652 4512 y Fr(--no-deps)749+b Fx(don't)28 b(automatically)f(ful\014ll)h(dep)r(endencies)652+4612 y Fr(--set-default)573 b Fx(set)28 b(default)g(rep)r(ository)e+([DEF)-9 b(A)n(UL)i(T])652 4712 y Fr(--no-set-default)441+b Fx(don't)28 b(set)g(default)g(rep)r(ository)652 4841+y Fr(--repodir)40 b(DIRECTORY)1797 4799 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)h(in)g(whic)n(h)h(to)1797+4899 y(run)415 4998 y(Adv)-5 b(anced)28 b(options:)p+eop end+%%Page: 70 70+TeXDict begin 70 69 bop 739 282 a Fx(70)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)1013 502 y Fr(--intersection)747+b Fx(tak)n(e)27 b(in)n(tersection)g(of)h(all)f(rep)r(ositories)1013+602 y Fr(--union)1055 b Fx(tak)n(e)27 b(union)h(of)g(all)f(rep)r+(ositories)f([DEF)-9 b(A)n(UL)i(T])1013 744 y Fr(--complement)2376+694 y Fx(tak)n(e)27 b(complemen)n(t)h(of)f(rep)r(ositories)f(\(in)i+(order)2376 793 y(listed\))1013 884 y Fr(--compress)923+b Fx(create)27 b(compressed)g(patc)n(hes)1013 984 y Fr(--dont-compress)+703 b Fx(don't)28 b(create)f(compressed)f(patc)n(hes)1013+1083 y Fr(--nolinks)967 b Fx(do)28 b(not)f(link)h(rep)r(ository)e(or)h+(pristine)g(to)h(sibling)1013 1183 y Fr(--ignore-times)2376+1191 y Fx(don't)g(trust)g(the)g(\014le)g(mo)r(di\014cation)f(times)1013+1312 y Fr(--remote-repo)38 b(URL)2376 1270 y Fx(sp)r(ecify)28+b(the)g(remote)f(rep)r(ository)f(URL)i(to)g(w)n(ork)2376+1370 y(with)1013 1480 y Fr(--no-ssh-cm)2376 1428 y Fx(don't)g(use)g+(SSH)g(Con)n(trolMaster)d(feature)2376 1527 y([DEF)-9+b(A)n(UL)i(T])1013 1618 y Fr(--ssh-cm)2376 1626 y Fx(use)28+b(SSH)g(Con)n(trolMaster)e(feature)1013 1717 y Fr(--set-scripts-ex)o+(ec)o(uta)o(bl)o(e)311 b Fx(mak)n(e)27 b(scripts)g(executable)1013+1817 y Fr(--dont-set-scrip)o(ts)o(-ex)o(ec)o(uta)o(bl)o(e)93+b Fx(don't)28 b(mak)n(e)f(scripts)g(executable)1013 1917+y Fr(--umask)41 b(UMASK)794 b Fx(sp)r(ecify)28 b(umask)f(to)h(use)f+(when)h(writing)863 2012 y(Pull)34 b(is)g(used)g(to)g(bring)f(c)n+(hanges)g(made)g(in)i(another)e(rep)r(ository)f(in)n(to)i(the)g(curren)+n(t)739 2112 y(rep)r(ository)27 b(\(that)j(is,)f(either)g(the)h(one)e+(in)i(the)f(curren)n(t)f(directory)-7 b(,)29 b(or)f(the)h(one)g(sp)r+(eci\014ed)739 2212 y(with)38 b(the)h({rep)r(o)r(dir)d(option\).)68+b(Pull)38 b(allo)n(ws)f(y)n(ou)g(to)h(bring)f(o)n(v)n(er)f(all)i(or)f+(some)g(of)h(the)739 2311 y(patc)n(hes)24 b(that)i(are)e(in)h(that)g+(rep)r(ository)e(but)j(not)f(in)g(this)h(one.)35 b(Pull)25+b(accepts)f(argumen)n(ts,)739 2411 y(whic)n(h)38 b(are)e(URLs)i(from)f+(whic)n(h)h(to)f(pull,)k(and)d(when)f(called)h(without)g(an)f(argumen)n+(t,)739 2511 y(pull)26 b(will)f(use)h(the)f(rep)r(ository)f(from)h+(whic)n(h)h(y)n(ou)e(ha)n(v)n(e)g(most)i(recen)n(tly)e(either)i(pushed)+f(or)739 2610 y(pulled.)p 975 2782 2392 4 v 975 2857+a Fr(--intersection,)37 b(--union)k([DEFAULT],)f(--complement)p+975 2912 V 863 3084 a Fx(If)i(y)n(ou)e(pro)n(vide)g(more)h(than)g(one)g+(rep)r(ository)e(as)h(an)h(argumen)n(t)f(to)h(pull,)k(darcs')739+3183 y(b)r(eha)n(vior)23 b(is)h(determined)h(b)n(y)f(the)h(presence)e+(of)i(the)g Fr(--complement)p Fx(,)20 b Fr(--intersection)p+Fx(,)739 3283 y(and)27 b Fr(--union)e Fx(\015ags.)863+3455 y Fn(\017)41 b Fx(The)30 b(default)g(\()p Fr(--union)p+Fx(\))d(b)r(eha)n(vior)i(is)g(to)h(pull)g(an)n(y)e(patc)n(hes)h(that)h+(are)f(in)g(an)n(y)g(of)946 3554 y(the)f(sp)r(eci\014ed)g(rep)r+(ositories)e(\()p Fi(R)1961 3566 y Fm(1)2013 3492 y Fg(S)2096+3554 y Fi(R)2159 3566 y Fm(2)2210 3492 y Fg(S)2293 3554+y Fi(R)2356 3566 y Fm(3)2407 3554 y Fi(:)14 b(:)g(:)p+Fx(\).)863 3716 y Fn(\017)41 b Fx(If)27 b(y)n(ou)e(instead)h(sp)r+(ecify)g(the)h Fr(--intersection)20 b Fx(\015ag,)25 b(darcs)g(will)i+(only)e(pull)i(those)946 3816 y(patc)n(hes)g(whic)n(h)h(are)f(presen)n+(t)g(in)g(all)h(source)e(rep)r(ositories)g(\()p Fi(R)2913+3828 y Fm(1)2964 3753 y Fg(T)3047 3816 y Fi(R)3110 3828+y Fm(2)3161 3753 y Fg(T)3244 3816 y Fi(R)3307 3828 y+Fm(3)3359 3816 y Fi(:)14 b(:)g(:)o Fx(\).)863 3977 y+Fn(\017)41 b Fx(If)28 b(y)n(ou)e(sp)r(ecify)i(the)f Fr(--complement)22+b Fx(\015ag,)27 b(darcs)f(will)h(only)g(pull)g(elemen)n(ts)g(in)h(the)+946 4077 y(\014rst)39 b(rep)r(ository)e(that)i(do)g(not)f(exist)h(in)g+(an)n(y)f(of)h(the)g(remaining)f(rep)r(ositories)3568+4047 y Fm(4)946 4177 y Fx(\()p Fi(R)1041 4189 y Fm(1)1079+4177 y Fn(n)p Fx(\()p Fi(R)1216 4189 y Fm(2)1267 4114+y Fg(S)1350 4177 y Fi(R)1413 4189 y Fm(3)1464 4114 y+Fg(S)1547 4177 y Fi(:)14 b(:)g(:)p Fx(\)\).)p 975 4348+V 975 4423 a Fr(--external-merge)p 975 4478 V 739 4527+1146 4 v 831 4581 a Fp(4)866 4604 y Fl(The)32 b(\014rst)f(thing)i+(darcs)e(will)g(do)h(is)f(remo)n(v)n(e)h(duplicates,)i(k)n(eeping)f+(only)f(the)g(\014rst)g(sp)r(eci\014cation.)739 4683+y(This)26 b(is)f(noticeable)j(for)e(the)h(complemen)n(t)g(op)r+(eration,)h(since)f(mathematically)g Ff(S)t Fe(n)p Ff(S)h+Fe(!)23 b(;)p Fl(,)k(one)g(w)n(ould)739 4762 y(exp)r(ect)i(that)f(\\)p+Fo(darcs)37 b(pull)f(--complement)j(repo1)e(repo1)p Fl(")29+b(w)n(ould)e(result)g(in)f(no)i(pulls,)f(but)g(the)h(du-)739+4841 y(plicate)e(elimination)f(remo)n(v)n(es)h(the)g(second)h+Fo(repo1)p Fl(,)f(reducing)g(the)g(ab)r(o)n(v)n(e)h(to)f(e\013ectiv)n+(ely)h(\\)p Fo(darcs)37 b(pull)739 4920 y(repo1)p Fl(".)53+b(The)30 b(exp)r(ected)j(functionalit)n(y)e(could)g(b)r(e)g(seen)g(via)+f(\\)p Fo(darcs)37 b(get)f(-a)g(repo1)h(repo2;)g(darcs)739+4998 y(pull)f(--complement)j(repo1)e(repo2)p Fl(",)25+b(but)f(there)g(are)g(easier)f(w)n(a)n(ys)h(of)g(doing)g(nothing!)p+eop end+%%Page: 71 71+TeXDict begin 71 70 bop 291 282 a Fu(6.6.)63 b(W)n(ORKING)28+b(WITH)g(CHANGES)1450 b Fx(71)415 515 y(Y)-7 b(ou)29+b(can)f(use)h(an)f(external)g(in)n(teractiv)n(e)g(merge)g(to)r(ol)g(to)+h(resolv)n(e)e(con\015icts)h(with)i(the)291 615 y(\015ag)c+Fr(--external-merge)p Fx(.)31 b(F)-7 b(or)27 b(more)g(details)g(see)g+(subsection)g(6.1.)p 527 791 2392 4 v 527 865 a Fr(--matches,)39+b(--patches,)h(--tags,)g(--no-deps)p 527 920 V 415 1096+a Fx(The)25 b Fr(--patches)p Fx(,)c Fr(--matches)p Fx(,)g+Fr(--tags)p Fx(,)i(and)h Fr(--no-deps)d Fx(options)j(can)g(b)r(e)h+(used)f(to)291 1196 y(select)j(whic)n(h)h(patc)n(hes)f(to)g(pull,)h(as)+f(describ)r(ed)g(in)h(subsection)f(6.1.)p 527 1371 V+527 1446 a Fr(--no-test,)39 b(--test)p 527 1494 V 415+1670 a Fx(If)26 b(y)n(ou)g(sp)r(ecify)g(the)g Fr(--test)e+Fx(option,)i(pull)g(will)g(run)g(the)g(test)g(\(if)h(a)f(test)g+(exists\))g(on)f(a)291 1769 y(scratc)n(h)g(cop)n(y)g(of)h(the)h(rep)r+(ository)e(con)n(ten)n(ts)g(prior)h(to)g(actually)f(p)r(erforming)h+(the)h(pull.)36 b(If)291 1869 y(the)28 b(test)f(fails,)h(the)g(pull)g+(will)g(b)r(e)g(ab)r(orted.)p 527 2045 V 527 2119 a Fr(--verbose)p+527 2156 V 415 2331 a Fx(Adding)i(the)h Fr(--verbose)26+b Fx(option)k(causes)e(another)h(section)h(to)g(app)r(ear)f(in)h(the)g+(out-)291 2431 y(put)k(whic)n(h)h(also)e(displa)n(ys)g(a)h(summary)g+(of)g(patc)n(hes)f(that)i(y)n(ou)f(ha)n(v)n(e)f(and)h(the)h(remote)291+2531 y(rep)r(ository)d(lac)n(ks.)54 b(Th)n(us,)35 b(the)f(follo)n(wing)+f(syn)n(tax)f(can)i(b)r(e)g(used)g(to)f(sho)n(w)g(y)n(ou)g(all)h(the)+291 2630 y(patc)n(h)27 b(di\013erences)g(b)r(et)n(w)n(een)h(t)n(w)n(o)f+(rep)r(ositories:)291 2806 y Fr(darcs)41 b(pull)h(--dry-run)e+(--verbose)291 3037 y Fk(6.6.3)112 b(darcs)38 b(push)291+3190 y Fr(Usage:)j(darcs)g(push)h([OPTION]...)d([REPOSITORY])415+3290 y Fx(Options:)652 3384 y Fr(--matches)h(PATTERN)183+b Fx(select)28 b(patc)n(hes)f(matc)n(hing)g(P)-7 b(A)g(TTERN)465+3484 y Fr(-p)99 b(--patches)40 b(REGEXP)227 b Fx(select)28+b(patc)n(hes)f(matc)n(hing)g(REGEXP)465 3584 y Fr(-t)99+b(--tags)41 b(REGEXP)358 b Fx(select)28 b(tags)f(matc)n(hing)g(REGEXP)+652 3683 y Fr(--no-deps)531 b Fx(don't)28 b(automatically)f(ful\014ll)h+(dep)r(endencies)465 3783 y Fr(-a)99 b(--all)707 b Fx(answ)n(er)27+b(y)n(es)f(to)i(all)f(patc)n(hes)465 3882 y Fr(-i)99+b(--interactive)355 b Fx(prompt)28 b(user)f(in)n(teractiv)n(ely)652+3982 y Fr(--sign)663 b Fx(sign)28 b(the)g(patc)n(h)f(with)h(y)n(our)e+(gpg)h(k)n(ey)652 4082 y Fr(--sign-as)40 b(KEYID)271+b Fx(sign)28 b(the)g(patc)n(h)f(with)h(a)f(giv)n(en)g(k)n(eyid)652+4219 y Fr(--sign-ssl)39 b(IDFILE)1579 4169 y Fx(sign)28+b(the)g(patc)n(h)f(using)g(op)r(enssl)g(with)h(a)g(giv)n(en)1579+4269 y(priv)-5 b(ate)28 b(k)n(ey)652 4355 y Fr(--dont-sign)443+b Fx(don't)28 b(sign)f(the)h(patc)n(h)652 4454 y Fr(--dry-run)531+b Fx(don't)28 b(actually)f(tak)n(e)g(the)h(action)465+4554 y Fr(-s)99 b(--summary)531 b Fx(summarize)27 b(c)n(hanges)652+4654 y Fr(--no-summary)399 b Fx(don't)28 b(summarize)f(c)n(hanges)652+4783 y Fr(--repodir)40 b(DIRECTORY)1579 4741 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)h(in)h(whic)n(h)f(to)1579+4841 y(run)652 4910 y Fr(--set-default)355 b Fx(set)28+b(default)g(rep)r(ository)e([DEF)-9 b(A)n(UL)i(T])652+5010 y Fr(--no-set-default)223 b Fx(don't)28 b(set)g(default)g(rep)r+(ository)p eop end+%%Page: 72 72+TeXDict begin 72 71 bop 739 282 a Fx(72)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(Adv)-5+b(anced)28 b(options:)1013 609 y Fr(--apply-as)39 b(USERNAME)97+b Fx(apply)27 b(patc)n(h)g(as)g(another)g(user)g(using)g(sudo)1013+749 y Fr(--apply-as-mysel)o(f)1941 697 y Fx(don't)g(use)h(sudo)f(to)h+(apply)f(as)g(another)f(user)1941 797 y([DEF)-9 b(A)n(UL)i(T])1013+887 y Fr(--nolinks)532 b Fx(do)27 b(not)h(link)f(rep)r(ository)f(or)h+(pristine)g(to)h(sibling)1013 1016 y Fr(--remote-repo)38+b(URL)1941 975 y Fx(sp)r(ecify)28 b(the)g(remote)e(rep)r(ository)g(URL)+i(to)g(w)n(ork)1941 1074 y(with)1013 1184 y Fr(--no-ssh-cm)1941+1132 y Fx(don't)f(use)h(SSH)g(Con)n(trolMaster)d(feature)1941+1232 y([DEF)-9 b(A)n(UL)i(T])1013 1322 y Fr(--ssh-cm)1941+1330 y Fx(use)27 b(SSH)h(Con)n(trolMaster)e(feature)863+1418 y(Push)38 b(is)g(the)g(opp)r(osite)f(of)h(pull.)68+b(Push)38 b(allo)n(ws)e(y)n(ou)h(to)h(cop)n(y)f(c)n(hanges)f(from)i+(the)739 1518 y(curren)n(t)27 b(rep)r(ository)f(in)n(to)h(another)g+(rep)r(ository)-7 b(.)863 1617 y(F)g(or)34 b(ob)n(vious)f(reasons,)h(y)+n(ou)g(can)g(only)g(push)g(to)h(rep)r(ositories)d(to)j(whic)n(h)f(y)n+(ou)f(ha)n(v)n(e)739 1717 y(write)28 b(access.)36 b(In)28+b(addition,)g(y)n(ou)f(can)g(only)g(push)h(to)g(rep)r(os)f(that)h(y)n+(ou)f(access)g(either)h(on)739 1816 y(the)33 b(lo)r(cal)f(\014le)h+(system)g(or)f(with)h(ssh.)52 b(In)33 b(order)e(to)i(apply)g(with)g+(ssh,)h(darcs)d(m)n(ust)i(also)739 1916 y(b)r(e)h(installed)g(on)f(the)+h(remote)f(computer.)55 b(The)34 b(command)f(in)n(v)n(ok)n(ed)f(to)i+(run)g(ssh)f(ma)n(y)739 2016 y(b)r(e)25 b(con\014gured)e(b)n(y)i(the)g+Fr(DARCS_SSH)c Fx(en)n(vironmen)n(t)i(v)-5 b(ariable)24+b(\(see)h(subsection)f(4.4\).)35 b(The)739 2115 y(command)27+b(in)n(v)n(ok)n(ed)f(via)h(ssh)h(is)f(alw)n(a)n(ys)f+Fr(darcs)p Fx(,)g(i.e.)h(the)h(darcs)f(executable)g(m)n(ust)h(b)r(e)g+(in)739 2215 y(the)g(default)g(path)g(on)f(the)h(remote)f(mac)n(hine.)+863 2315 y(Push)d(w)n(orks)e(b)n(y)h(creating)g(a)g(patc)n(h)h(bundle,)+h(and)e(then)h(running)g(darcs)e(apply)i(in)g(the)739+2414 y(target)h(rep)r(ository)g(using)h(that)h(patc)n(h)f(bundle.)37+b(This)26 b(means)g(that)h(the)g(default)g(options)739+2514 y(for)g Fs(apply)37 b Fx(in)28 b(the)h Fs(tar)l(get)35+b Fx(rep)r(ository)26 b(\(suc)n(h)i(as,)f(for)h(example,)f+Fr(--test)p Fx(\))f(will)i(a\013ect)g(the)739 2613 y(b)r(eha)n(vior)34+b(of)i(push.)61 b(This)36 b(also)e(means)i(that)g(push)g(is)f(somewhat)+g(less)g(e\016cien)n(t)h(than)739 2713 y(pull.)863 2813+y(When)29 b(y)n(ou)d(receiv)n(e)h(an)g(error)f(message)g(suc)n(h)h(as)+739 2978 y Fr(bash:)41 b(darcs:)h(command)e(not)j(found)739+3144 y Fx(then)36 b(this)f(means)g(that)g(the)h(darcs)e(on)h(the)h+(remote)e(mac)n(hine)h(could)g(not)g(b)r(e)h(started.)739+3244 y(Mak)n(e)25 b(sure)h(that)h(the)f(darcs)g(executable)g(is)g+(called)g Fr(darcs)e Fx(and)i(is)h(found)f(in)h(the)g(default)739+3343 y(path.)59 b(The)35 b(default)h(path)f(can)f(b)r(e)i(di\013eren)n+(t)f(in)g(in)n(teractiv)n(e)f(and)h(in)g(non-in)n(teractiv)n(e)739+3443 y(shells.)h(Sa)n(y)739 3609 y Fr(ssh)42 b(login@remote.mach)o(in)o+(e)c(darcs)739 3774 y Fx(to)27 b(try)h(whether)f(the)h(remote)f(darcs)g+(can)g(b)r(e)h(found,)g(or)739 3940 y Fr(ssh)42 b(login@remote.mach)o+(in)o(e)c('echo)j($PATH')739 4106 y Fx(\(note)28 b(the)g(single)f+(quotes\))g(to)h(c)n(hec)n(k)e(the)i(default)g(path.)p+975 4288 2392 4 v 975 4363 a Fr(--apply-as)p 975 4418+V 863 4600 a Fx(If)f(y)n(ou)e(giv)n(e)g(the)h Fr(--apply-as)c+Fx(\015ag,)k(darcs)e(will)i(use)g(sudo)g(to)f(apply)h(the)g(c)n(hanges)+f(as)739 4700 y(a)f(di\013eren)n(t)g(user.)35 b(This)25+b(can)f(b)r(e)g(useful)h(if)g(y)n(ou)e(w)n(an)n(t)h(to)g(set)h(up)f(a)g+(system)g(where)g(sev)n(eral)739 4799 y(users)33 b(can)h(mo)r(dify)h+(the)g(same)f(rep)r(ository)-7 b(,)34 b(but)h(y)n(ou)f(don't)g(w)n(an)n+(t)g(to)g(allo)n(w)g(them)h(full)739 4899 y(write)c(access.)46+b(This)31 b(isn't)g(secure)f(against)g(skilled)h(malicious)f(attac)n(k)+n(ers,)g(but)i(at)f(least)739 4998 y(can)c(protect)g(y)n(our)g(rep)r+(ository)f(from)h(clumsy)-7 b(,)28 b(inept)g(or)e(lazy)h(users.)p+eop end+%%Page: 73 73+TeXDict begin 73 72 bop 291 282 a Fu(6.6.)63 b(W)n(ORKING)28+b(WITH)g(CHANGES)1450 b Fx(73)p 527 515 2392 4 v 527+590 a Fr(--matches,)39 b(--patches,)h(--tags,)g(--no-deps)p+527 645 V 415 1271 a Fx(The)25 b Fr(--patches)p Fx(,)c+Fr(--matches)p Fx(,)g Fr(--tags)p Fx(,)i(and)h Fr(--no-deps)d+Fx(options)j(can)g(b)r(e)h(used)f(to)291 1371 y(select)j(whic)n(h)h+(patc)n(hes)f(to)g(push,)h(as)f(describ)r(ed)g(in)h(subsection)f(6.1.)+415 1581 y(When)h(there)f(are)g(con\015icts,)g(the)h(b)r(eha)n(vior)e+(of)h(push)h(is)f(determined)h(b)n(y)f(the)g(default)291+1681 y(\015ags)d(to)h Fr(apply)e Fx(in)j(the)g Fs(tar)l(get)33+b Fx(rep)r(ository)-7 b(.)34 b(Most)25 b(commonly)-7+b(,)25 b(for)g(pushed-to)g(rep)r(osito-)291 1781 y(ries,)k(y)n(ou'd)g+(lik)n(e)g(to)g(ha)n(v)n(e)f Fr(--dont-allow-con)o(fli)o(ct)o(s)23+b Fx(as)29 b(a)g(default)h(option)f(to)g(apply)291 1880+y(\(b)n(y)36 b(default,)j(it)e(is)g(already)e(the)i(default.)14+b(.)g(.)g(\).)64 b(If)37 b(this)g(is)f(the)h(case,)h(when)f(there)f+(are)291 1980 y(con\015icts)c(on)g(push,)h(darcs)f(will)g(fail)h(with)f+(an)g(error)f(message.)50 b(Y)-7 b(ou)32 b(can)g(then)h(resolv)n(e)291+2079 y(b)n(y)h(pulling)i(the)f(con\015icting)g(patc)n(h,)h(recording)e+(a)g(resolution)g(and)h(then)h(pushing)f(the)291 2179+y(resolution)26 b(together)h(with)h(the)g(con\015icting)f(patc)n(h.)415+2390 y(Darcs)f(do)r(es)g(not)g(ha)n(v)n(e)f(an)h(explicit)h(w)n(a)n(y)e+(to)h(tell)h(y)n(ou)e(whic)n(h)i(patc)n(h)f(con\015icted,)g(only)291+2489 y(the)g(\014le)g(name.)36 b(Y)-7 b(ou)25 b(ma)n(y)g(w)n(an)n(t)h+(to)f(pull)h(all)g(the)g(patc)n(hes)f(from)g(the)h(remote)g(rep)r+(ository)291 2589 y(just)h(to)g(b)r(e)g(sure.)36 b(If)27+b(y)n(ou)f(don't)h(w)n(an)n(t)f(to)h(do)g(this)g(in)g(y)n(our)e(w)n+(orking)g(directory)-7 b(,)26 b(y)n(ou)g(can)291 2688+y(create)g(another)h(darcs)f(w)n(orking)g(directory)h(for)g(this)h+(purp)r(ose.)415 2899 y(If)e(y)n(ou)f(w)n(an)n(t,)g(y)n(ou)g(could)g+(set)g(the)h(target)e(rep)r(ository)g(to)i(use)f Fr(--allow-conflict)o+(s)p Fx(.)291 2999 y(In)37 b(this)h(case)f(con\015icting)g(patc)n(hes)g+(will)h(b)r(e)g(applied,)i(but)e(the)g(con\015icts)f(will)h(not)g(b)r+(e)291 3098 y(mark)n(ed)26 b(in)i(the)g(w)n(orking)e(directory)-7+b(.)415 3309 y(If,)24 b(on)e(the)h(other)f(hand,)h(y)n(ou)f(ha)n(v)n(e)+f Fr(--mark-conflicts)16 b Fx(sp)r(eci\014ed)23 b(as)f(a)g(default)h+(\015ag)291 3408 y(for)k(apply)g(in)h(the)g(target)f(rep)r(ository)-7+b(,)27 b(when)g(there)h(is)g(a)f(con\015ict,)h(it)g(will)g(b)r(e)g+(mark)n(ed)f(in)291 3508 y(the)i(w)n(orking)f(directory)g(of)h(the)h+(target)e(rep)r(ository)-7 b(.)40 b(In)30 b(this)f(case,)g(y)n(ou)g+(should)g(resolv)n(e)291 3608 y(the)f(con\015ict)f(in)h(the)g(target)f+(rep)r(ository)f(itself.)291 4428 y Fk(6.6.4)112 b(darcs)38+b(send)291 4788 y Fr(Usage:)j(darcs)g(send)h([OPTION]...)d+([REPOSITORY])415 4998 y Fx(Options:)p eop end+%%Page: 74 74+TeXDict begin 74 73 bop 739 282 a Fx(74)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)1100 502 y Fr(--matches)40+b(PATTERN)489 b Fx(select)27 b(patc)n(hes)g(matc)n(hing)g(P)-7+b(A)g(TTERN)913 602 y Fr(-p)99 b(--patches)40 b(REGEXP)533+b Fx(select)27 b(patc)n(hes)g(matc)n(hing)g(REGEXP)913+701 y Fr(-t)99 b(--tags)41 b(REGEXP)664 b Fx(select)27+b(tags)g(matc)n(hing)g(REGEXP)1100 801 y Fr(--no-deps)837+b Fx(don't)28 b(automatically)e(ful\014ll)j(dep)r(endencies)913+901 y Fr(-a)99 b(--all)1013 b Fx(answ)n(er)26 b(y)n(es)h(to)g(all)h+(patc)n(hes)913 1000 y Fr(-i)99 b(--interactive)661 b+Fx(prompt)27 b(user)g(in)n(teractiv)n(ely)1100 1100 y+Fr(--from)41 b(EMAIL)708 b Fx(sp)r(ecify)28 b(email)f(address)913+1199 y Fr(-A)99 b(--author)40 b(EMAIL)621 b Fx(sp)r(ecify)28+b(author)f(id)1100 1299 y Fr(--to)42 b(EMAIL)795 b Fx(sp)r(ecify)28+b(destination)f(email)1100 1439 y Fr(--cc)42 b(EMAIL)2333+1391 y Fx(mail)27 b(results)g(to)h(additional)f(EMAIL\(s\).)2333+1491 y(Requires)g({reply)1100 1577 y Fr(--subject)40+b(SUBJECT)489 b Fx(sp)r(ecify)28 b(mail)f(sub)5 b(ject)913+1676 y Fr(-o)99 b(--output)40 b(FILE)665 b Fx(sp)r(ecify)28+b(output)g(\014lename)913 1776 y Fr(-O)99 b(--output-auto-na)o(me)442+b Fx(output)28 b(to)g(automatically)e(named)i(\014le)1100+1876 y Fr(--sign)969 b Fx(sign)27 b(the)h(patc)n(h)f(with)h(y)n(our)f+(gpg)g(k)n(ey)1100 1975 y Fr(--sign-as)40 b(KEYID)577+b Fx(sign)27 b(the)h(patc)n(h)f(with)h(a)g(giv)n(en)e(k)n(eyid)1100+2113 y Fr(--sign-ssl)39 b(IDFILE)2333 2063 y Fx(sign)27+b(the)h(patc)n(h)f(using)h(op)r(enssl)f(with)h(a)f(giv)n(en)2333+2162 y(priv)-5 b(ate)27 b(k)n(ey)1100 2248 y Fr(--dont-sign)749+b Fx(don't)28 b(sign)f(the)h(patc)n(h)913 2378 y Fr(-u)99+b(--unified)2333 2336 y Fx(output)28 b(patc)n(h)f(in)h(a)f(darcs-sp)r+(eci\014c)g(format)2333 2435 y(similar)g(to)g(di\013)h(-u)1100+2505 y Fr(--dry-run)837 b Fx(don't)28 b(actually)f(tak)n(e)g(the)g+(action)913 2605 y Fr(-s)99 b(--summary)837 b Fx(summarize)27+b(c)n(hanges)1100 2704 y Fr(--no-summary)705 b Fx(don't)28+b(summarize)e(c)n(hanges)1100 2804 y Fr(--edit-descripti)o(on)442+b Fx(edit)28 b(the)g(patc)n(h)f(bundle)h(description)1100+2904 y Fr(--dont-edit-desc)o(rip)o(ti)o(on)224 b Fx(don't)28+b(edit)g(the)g(patc)n(h)f(bundle)h(description)1100 3003+y Fr(--set-default)661 b Fx(set)28 b(default)g(rep)r(ository)e([DEF)-9+b(A)n(UL)i(T])1100 3103 y Fr(--no-set-default)529 b Fx(don't)28+b(set)f(default)h(rep)r(ository)1100 3232 y Fr(--repodir)40+b(DIRECTORY)2333 3190 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e+(directory)g(in)i(whic)n(h)f(to)2333 3290 y(run)1100+3360 y Fr(--sendmail-comma)o(nd)37 b(COMMAND)97 b Fx(sp)r(ecify)28+b(sendmail)f(command)863 3460 y(Adv)-5 b(anced)28 b(options:)1013+3558 y Fr(--logfile)40 b(FILE)272 b Fx(giv)n(e)27 b(patc)n(h)g(name)g+(and)h(commen)n(t)f(in)h(\014le)1013 3658 y Fr(--delete-logfile)180+b Fx(delete)28 b(the)g(log\014le)f(when)g(done)1013 3787+y Fr(--remote-repo)38 b(URL)1897 3745 y Fx(sp)r(ecify)28+b(the)g(remote)f(rep)r(ository)f(URL)i(to)f(w)n(ork)1897+3845 y(with)1013 3915 y Fr(--context)40 b(FILENAME)1897+3923 y Fx(send)28 b(to)f(con)n(text)g(stored)g(in)h(FILENAME)1013+4055 y Fr(--no-ssh-cm)1897 4002 y Fx(don't)g(use)f(SSH)h(Con)n+(trolMaster)e(feature)1897 4102 y([DEF)-9 b(A)n(UL)i(T])1013+4193 y Fr(--ssh-cm)1897 4201 y Fx(use)27 b(SSH)i(Con)n(trolMaster)c+(feature)863 4293 y(Send)k(is)f(used)f(to)h(prepare)f(a)g(bundle)i(of)f+(patc)n(hes)f(that)h(can)g(b)r(e)g(applied)g(to)g(a)f(target)739+4392 y(rep)r(ository)-7 b(.)63 b(Send)38 b(accepts)e(the)h(URL)g(of)g+(the)h(rep)r(ository)d(as)h(an)h(argumen)n(t.)64 b(When)739+4492 y(called)29 b(without)h(an)f(argumen)n(t,)g(send)g(will)h(use)f+(the)h(most)f(recen)n(t)g(rep)r(ository)f(that)h(w)n(as)739+4591 y(either)i(pushed)h(to,)g(pulled)g(from)f(or)g(sen)n(t)g(to.)48+b(By)31 b(default,)i(the)f(patc)n(h)f(bundle)h(is)f(sen)n(t)739+4691 y(b)n(y)c(email,)h(although)f(y)n(ou)f(ma)n(y)h(sa)n(v)n(e)f(it)i+(to)g(a)f(\014le.)863 4795 y(Do)19 b(not)f(confuse)g(the)h+Fr(--author)c Fx(options)j(with)h(the)g(return)f(address)f(that)h+Fr(darcs)42 b(send)739 4895 y Fx(will)28 b(set)f(for)g(y)n(our)g(patc)n+(h)g(bundle.)863 4998 y(F)-7 b(or)27 b(example,)h(if)g(y)n(ou)f(ha)n(v)+n(e)f(t)n(w)n(o)h(email)g(addresses)f(A)i(and)g(B:)p+eop end+%%Page: 75 75+TeXDict begin 75 74 bop 291 282 a Fu(6.6.)63 b(W)n(ORKING)28+b(WITH)g(CHANGES)1450 b Fx(75)332 515 y(If)19 b(y)n(ou)f(use)h+Fr(--author)40 b(A)18 b Fx(but)h(y)n(our)f(mac)n(hine)g(is)h+(con\014gured)e(to)i(send)f(mail)h(from)f(address)498+615 y(B)28 b(b)n(y)f(default,)h(then)g(the)g(return)f(address)g(on)g(y)+n(our)f(message)g(will)i(b)r(e)g(B.)332 795 y(If)i(y)n(ou)f(use)h+Fr(--from)41 b(A)30 b Fx(and)f(y)n(our)g(mail)h(clien)n(t)g(supp)r+(orts)f(setting)h(the)g(F)-7 b(rom:)41 b(address)498+894 y(arbitrarily)30 b(\(some)i(non-Unix-lik)n(e)f(mail)h(clien)n(ts,)i+(esp)r(ecially)-7 b(,)33 b(ma)n(y)e(not)h(supp)r(ort)498+994 y(this\),)f(then)f(the)f(return)g(address)f(will)i(b)r(e)g(A;)g(if)+g(it)f(do)r(es)h(not)f(supp)r(ort)g(this,)h(then)498+1094 y(the)e(return)f(address)g(will)g(b)r(e)h(B.)332+1273 y(If)d(y)n(ou)f(supply)h(neither)g Fr(--from)e Fx(nor)h+Fr(--author)p Fx(,)e(then)j(the)h(return)e(address)g(will)h(b)r(e)g(B.)+415 1450 y(In)19 b(addition,)h(unless)e(y)n(ou)g(sp)r(ecify)g(the)h+(sendmail)f(command)g(with)h Fr(--sendmail-comma)o(nd)p+Fx(,)291 1549 y(darcs)33 b(sends)i(email)g(using)g(the)g(default)g+(email)g(command)g(on)g(y)n(our)e(computer.)59 b(This)291+1649 y(default)30 b(command)f(is)h(determined)g(b)n(y)g(the)g+Fr(configure)c Fx(script.)43 b(Th)n(us,)31 b(on)e(some)g(non-)291+1749 y(Unix-lik)n(e)e(OSes,)g Fr(--from)e Fx(is)i(lik)n(ely)h(to)f(not)+h(w)n(ork)e(at)h(all.)p 527 1945 2392 4 v 527 2020 a+Fr(--unified)p 527 2056 V 415 2253 a Fx(If)35 b(y)n(ou)e(w)n(an)n(t)g+(to)h(create)f(patc)n(hes)h(ha)n(ving)f(con)n(text,)i(y)n(ou)e(can)h+(use)g(the)h Fr(--unified)291 2352 y Fx(option,)g(whic)n(h)f(creates)f+(output)i(v)-5 b(aguely)33 b(reminiscen)n(t)h(of)g Fr(diff)42+b(-u)p Fx(.)55 b(This)34 b(format)g(is)291 2452 y(still)27+b(darcs-sp)r(eci\014c)g(and)g(should)g(not)h(b)r(e)g(exp)r(ected)g(to)f+(apply)h(cleanly)f(b)n(y)g Fr(patch)p Fx(.)p 527 2649+V 527 2723 a Fr(--output,)40 b(--to,)h(--cc)p 527 2778+V 415 2975 a Fx(The)27 b Fr(--output)p Fx(,)d Fr(--output-auto-nam)o(e)+p Fx(,)d(and)27 b Fr(--to)f Fx(\015ags)g(determine)h(what)g(darcs)291+3074 y(do)r(es)g(with)h(the)f(patc)n(h)h(bundle)g(after)f(creating)f+(it.)37 b(If)28 b(y)n(ou)f(pro)n(vide)f(an)h Fr(--output)d+Fx(argu-)291 3174 y(men)n(t,)d(the)f(patc)n(h)f(bundle)h(is)g(sa)n(v)n+(ed)e(to)h(that)h(\014le.)35 b(If)20 b(y)n(ou)e(sp)r(ecify)i+Fr(--output-auto-nam)o(e)p Fx(,)291 3274 y(the)34 b(patc)n(h)f(bundle)i+(is)e(sa)n(v)n(ed)g(to)g(a)h(\014le)g(with)g(an)g(automatically)e+(generated)h(name.)55 b(If)291 3373 y(y)n(ou)33 b(giv)n(e)g(one)g(or)g+(more)g Fr(--to)g Fx(argumen)n(ts,)h(the)g(bundle)h(of)f(patc)n(hes)f+(is)h(sen)n(t)f(to)h(those)291 3473 y(lo)r(cations.)49+b(The)32 b(lo)r(cations)f(ma)n(y)g(either)h(b)r(e)g(email)g(addresses)e+(or)h(urls)h(that)g(the)g(patc)n(h)291 3572 y(should)27+b(b)r(e)h(submitted)g(to)g(via)f(HTTP)-7 b(.)415 3675+y(If)36 b(y)n(ou)g(don't)g(pro)n(vide)f(an)n(y)g(of)h(these)g(options,)+h(darcs)e(will)h(lo)r(ok)f(at)h(the)h(con)n(ten)n(ts)291+3775 y(of)27 b(the)i Fr(_darcs/prefs/ema)o(il)21 b Fx(\014le)28+b(in)h(the)f(target)f(rep)r(ository)f(\(if)j(it)f(exists\),)g(and)g+(send)291 3875 y(the)h(patc)n(h)g(b)n(y)g(email)g(to)g(that)g(address.)+40 b(In)29 b(this)h(case,)f(y)n(ou)f(ma)n(y)g(use)h(the)h+Fr(--cc)d Fx(option)291 3974 y(to)i(sp)r(ecify)g(additional)g(recipien)+n(ts)g(without)h(o)n(v)n(erriding)d(the)j(default)f(rep)r(ository)f+(email)291 4074 y(address.)415 4177 y(If)c(there)f(is)g(no)g(email)g+(address)f(asso)r(ciated)g(with)i(the)g(rep)r(ository)-7+b(,)22 b(darcs)h(will)g(prompt)291 4277 y(y)n(ou)j(for)h(an)h(email)f+(address.)p 527 4473 V 527 4548 a Fr(--subject)p 527+4603 V 415 4799 a Fx(Use)32 b(the)h Fr(--subject)c Fx(\015ag)i(to)h+(set)g(the)h(sub)5 b(ject)32 b(of)g(the)h(e-mail)f(to)g(b)r(e)g(sen)n+(t.)51 b(If)33 b(y)n(ou)291 4899 y(don't)27 b(pro)n(vide)f(a)h(sub)5+b(ject)27 b(on)g(the)h(command)f(line,)h(darcs)e(will)h(mak)n(e)g(one)g+(up)g(based)g(on)291 4998 y(names)g(of)g(the)h(patc)n(hes)f(in)h(the)g+(patc)n(h)f(bundle.)p eop end+%%Page: 76 76+TeXDict begin 76 75 bop 739 282 a Fx(76)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)p 975 515 2392 4+v 975 590 a Fr(--matches,)40 b(--patches,)f(--tags,)i(--no-deps)p+975 645 V 863 977 a Fx(The)25 b Fr(--patches)p Fx(,)c+Fr(--matches)p Fx(,)h Fr(--tags)p Fx(,)g(and)j Fr(--no-deps)20+b Fx(options)k(can)g(b)r(e)h(used)f(to)739 1076 y(select)j(whic)n(h)h+(patc)n(hes)f(to)g(send,)h(as)f(describ)r(ed)g(in)h(subsection)f(6.1.)p+975 1408 V 975 1483 a Fr(--edit-descripti)o(on)p 975+1538 V 863 1870 a Fx(If)34 b(y)n(ou)e(w)n(an)n(t)h(to)g(include)g(a)g+(description)f(or)h(explanation)f(along)g(with)h(the)h(bundle)739+1969 y(of)27 b(patc)n(hes,)g(y)n(ou)g(need)g(to)h(sp)r(ecify)f(the)h+Fr(--edit-descriptio)o(n)21 b Fx(\015ag,)27 b(whic)n(h)g(will)h(cause)+739 2069 y(darcs)f(to)g(op)r(en)h(up)h(an)e(editor)h(with)g(whic)n(h)g+(y)n(ou)f(can)h(comp)r(ose)f(a)g(message)g(to)g(go)g(along)739+2168 y(with)h(y)n(our)e(patc)n(hes.)p 975 2500 V 975+2575 a Fr(--sendmail-comma)o(nd)p 975 2611 V 863 2943+a Fx(If)37 b(y)n(ou)e(w)n(an)n(t)g(to)h(use)f(a)h(command)f(di\013eren)+n(t)h(from)f(the)i(default)f(one)f(for)h(sending)739+3043 y(email,)31 b(y)n(ou)e(need)h(to)g(sp)r(ecify)h(a)f(command)f+(line)i(with)f(the)h Fr(--sendmail-comma)o(nd)24 b Fx(op-)739+3142 y(tion.)37 b(The)28 b(command)g(line)g(can)f(con)n(tain)g(some)g+(format)g(sp)r(eci\014ers)h(whic)n(h)f(are)g(replaced)739+3242 y(b)n(y)c(the)h(actual)f(v)-5 b(alues.)35 b(Accepted)24+b(format)e(sp)r(eci\014ers)h(are)f Fr(\045s)h Fx(for)g(sub)5+b(ject,)24 b Fr(\045t)f Fx(for)g(to,)h Fr(\045c)739 3342+y Fx(for)g(cc,)h Fr(\045b)f Fx(for)g(the)h(b)r(o)r(dy)g(of)g(the)g+(mail,)g Fr(\045f)f Fx(for)g(from,)h Fr(\045a)f Fx(for)h(the)g(patc)n+(h)f(bundle)h(and)g(the)739 3441 y(same)g(sp)r(eci\014ers)h(in)g(upp)r+(ercase)f(for)h(the)g(URL-enco)r(ded)g(v)-5 b(alues.)36+b(Additionally)26 b(y)n(ou)g(can)739 3541 y(add)31 b+Fr(\045<)g Fx(to)h(the)f(end)h(of)g(the)g(command)f(line)h(if)g(the)g+(command)f(exp)r(ects)g(the)h(complete)739 3641 y(email)j(message)g(on)+g(standard)g(input.)62 b(E.g.)34 b(the)i(command)g(lines)f(for)h(ev)n+(olution)e(and)739 3740 y(msm)n(tp)28 b(lo)r(ok)f(lik)n(e)g(this:)739+4109 y Fr(evolution)40 b("mailto:\045T?subje)o(ct)o(=\045)o(S&a)o(tt)o+(ach)o(=\045)o(A&c)o(c=)o(\045C)o(&bo)o(dy)o(=\045B)o(")739+4209 y(msmtp)h(\045t)i(\045<)739 4639 y Fk(6.6.5)112+b(darcs)38 b(apply)739 4862 y Fr(Usage:)j(darcs)h(apply)f([OPTION]...)e+(<PATCHFILE>)863 4998 y Fx(Options:)p eop end+%%Page: 77 77+TeXDict begin 77 76 bop 291 282 a Fu(6.6.)63 b(W)n(ORKING)28+b(WITH)g(CHANGES)1450 b Fx(77)652 532 y Fr(--verify)40+b(PUBRING)1797 490 y Fx(v)n(erify)27 b(that)h(the)g(patc)n(h)f(w)n(as)g+(signed)g(b)n(y)g(a)h(k)n(ey)f(in)1797 590 y(PUBRING)652+689 y Fr(--verify-ssl)38 b(KEYS)1797 647 y Fx(v)n(erify)27+b(using)h(op)r(enSSL)f(with)h(authorized)f(k)n(eys)1797+747 y(from)h(\014le)f(KEYS)652 817 y Fr(--no-verify)661+b Fx(don't)28 b(v)n(erify)f(patc)n(h)g(signature)465+916 y Fr(-a)99 b(--all)925 b Fx(answ)n(er)27 b(y)n(es)f(to)i(all)f+(patc)n(hes)465 1016 y Fr(-i)99 b(--interactive)573 b+Fx(prompt)28 b(user)f(in)n(teractiv)n(ely)652 1115 y+Fr(--dry-run)749 b Fx(don't)28 b(actually)f(tak)n(e)g(the)h(action)652+1215 y Fr(--mark-conflicts)1797 1223 y Fx(mark)f(con\015icts)652+1315 y Fr(--allow-conflict)o(s)398 b Fx(allo)n(w)27 b(con\015icts,)g+(but)h(don't)g(mark)f(them)652 1452 y Fr(--no-resolve-con)o(fl)o(ic)o+(ts)1797 1402 y Fx(equiv)-5 b(alen)n(t)28 b(to)f({don)n(t-allo)n+(w-con\015icts,)e(for)1797 1502 y(bac)n(kw)n(ards)h(compatibilit)n(y)+652 1628 y Fr(--dont-allow-con)o(fl)o(ic)o(ts)1797 1576+y Fx(fail)i(on)f(patc)n(hes)g(that)h(create)f(con\015icts)1797+1675 y([DEF)-9 b(A)n(UL)i(T])652 1766 y Fr(--external-merge)37+b(COMMAND)96 b Fx(use)28 b(external)f(to)r(ol)g(to)g(merge)g+(con\015icts)652 1865 y Fr(--no-test)749 b Fx(don't)28+b(run)g(the)g(test)g(script)652 1965 y Fr(--test)881+b Fx(run)28 b(the)g(test)g(script)652 2065 y Fr(--leave-test-dir)o(ec)o+(to)o(ry)180 b Fx(don't)28 b(remo)n(v)n(e)e(the)i(test)g(directory)652+2164 y Fr(--remove-test-di)o(re)o(ct)o(ory)136 b Fx(remo)n(v)n(e)26+b(the)i(test)g(directory)652 2294 y Fr(--repodir)40 b(DIRECTORY)1797+2252 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e(directory)h(in)g(whic)n+(h)h(to)1797 2351 y(run)415 2417 y(Adv)-5 b(anced)28+b(options:)565 2541 y Fr(--reply)40 b(FROM)1928 2500+y Fx(reply)27 b(to)h(email-based)e(patc)n(h)i(using)f(FR)n(OM)1928+2599 y(address)565 2709 y Fr(--cc)41 b(EMAIL)1928 2661+y Fx(mail)28 b(results)f(to)g(additional)g(EMAIL\(s\).)1928+2761 y(Requires)g({reply)565 2877 y Fr(--happy-forward)o(ing)1928+2835 y Fx(forw)n(ard)f(unsigned)h(messages)f(without)i(extra)1928+2934 y(header)565 3004 y Fr(--sendmail-comm)o(and)37+b(COMMAND)227 b Fx(sp)r(ecify)28 b(sendmail)f(command)565+3104 y Fr(--ignore-times)1928 3112 y Fx(don't)h(trust)g(the)g(\014le)f+(mo)r(di\014cation)h(times)565 3203 y Fr(--compress)923+b Fx(create)27 b(compressed)f(patc)n(hes)565 3303 y Fr(--dont-compress)+703 b Fx(don't)28 b(create)f(compressed)f(patc)n(hes)565+3403 y Fr(--set-scripts-e)o(xec)o(ut)o(ab)o(le)311 b+Fx(mak)n(e)27 b(scripts)g(executable)565 3502 y Fr(--dont-set-scri)o+(pts)o(-e)o(xe)o(cut)o(ab)o(le)93 b Fx(don't)28 b(mak)n(e)f(scripts)g+(executable)565 3602 y Fr(--umask)40 b(UMASK)795 b Fx(sp)r(ecify)28+b(umask)f(to)h(use)f(when)h(writing)415 3698 y(Apply)d(is)f(used)h(to)f+(apply)g(a)g(bundle)h(of)g(patc)n(hes)e(to)i(this)g(rep)r(ository)-7+b(.)34 b(Suc)n(h)24 b(a)g(bundle)291 3797 y(ma)n(y)i(b)r(e)i(created)f+(using)h(send.)415 3897 y(Darcs)22 b(apply)g(accepts)g(a)h(single)f+(argumen)n(t,)g(whic)n(h)h(is)g(the)g(name)f(of)h(the)g(patc)n(h)f+(\014le)h(to)291 3997 y(b)r(e)28 b(applied.)37 b(If)28+b(y)n(ou)f(omit)h(this)g(argumen)n(t,)f(the)h(patc)n(h)f(is)h(read)f+(from)g(standard)g(input.)3117 3967 y Fm(5)291 4096 y+Fx(This)c(allo)n(ws)g(y)n(ou)g(to)g(use)h(apply)f(with)h(a)g(pip)r(e)g+(from)g(y)n(our)e(email)i(program,)e(for)h(example.)p+527 4278 2392 4 v 527 4353 a Fr(--verify)p 527 4408 V+415 4590 a Fx(If)h(y)n(ou)e(sp)r(ecify)i(the)g Fr(--verify)40+b(PUBRING)21 b Fx(option,)j(darcs)e(will)h(c)n(hec)n(k)g(that)g(the)h+(patc)n(h)291 4690 y(w)n(as)d(GPG-signed)g(b)n(y)h(a)g(k)n(ey)g(whic)n+(h)g(is)g(in)h Fr(PUBRING)d Fx(and)i(will)g(refuse)g(to)g(apply)g(the)h+(patc)n(h)291 4790 y(otherwise.)p 291 4842 1146 4 v 383+4896 a Fp(5)418 4920 y Fl(One)h(ca)n(v)n(eat:)33 b(don't)25+b(name)f(y)n(our)g(patc)n(h)h(\014le)f(\\magic)h(darcs)f(standard)g+(input",)h(or)e(darcs)h(will)e(read)291 4998 y(from)g(standard)j(input)+f(instead!)p eop end+%%Page: 78 78+TeXDict begin 78 77 bop 739 282 a Fx(78)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)p 975 515 2392 4+v 975 590 a Fr(--cc,)42 b(--reply)p 975 645 V 863 822+a Fx(If)23 b(y)n(ou)f(giv)n(e)f(the)h Fr(--reply)41 b(FROM)21+b Fx(option)h(to)g Fr(darcs)41 b(apply)p Fx(,)22 b(it)g(will)h(send)f+(the)h(results)739 922 y(of)k(the)g(application)f(to)h(the)g(sender)f+(of)h(the)g(patc)n(h.)37 b(This)26 b(only)h(w)n(orks)e(if)i(the)h(patc)+n(h)e(is)h(in)739 1021 y(the)k(form)f(of)h(email)f(with)h(its)g+(headers)f(in)n(tact,)h(so)f(that)h(darcs)f(can)g(actually)g(kno)n(w)g+(the)739 1121 y(origin)25 b(of)i(the)g(patc)n(h.)36 b(The)27+b(reply)f(email)g(will)h(indicate)g(whether)g(or)e(not)i(the)g(patc)n+(h)f(w)n(as)739 1221 y(successfully)f(applied.)36 b(The)25+b Fr(FROM)e Fx(\015ag)i(is)g(the)g(email)g(address)f(that)h(will)h(b)r+(e)f(used)g(as)g(the)739 1320 y(\\from")j(address)h(when)h(replying.)43+b(If)30 b(the)h(darcs)d(apply)i(is)g(b)r(eing)g(done)f(automatically)-7+b(,)739 1420 y(it)32 b(is)f(imp)r(ortan)n(t)h(that)g(this)g(address)e+(not)h(b)r(e)h(the)g(same)g(as)e(the)i(address)f(at)g(whic)n(h)h(the)+739 1520 y(patc)n(h)27 b(w)n(as)g(receiv)n(ed,)f(in)i(order)e(to)i(a)n+(v)n(oid)e(automatic)h(email)g(lo)r(ops.)863 1619 y(If)f(y)n(ou)e(w)n+(an)n(t)g(to)h(also)f(send)h(the)g(apply)g(email)f(to)h(another)f+(address)g(\(for)g(example,)h(to)739 1719 y(create)f(something)g(lik)n+(e)h(a)g(\\commits")f(mailing)g(list\),)i(y)n(ou)e(can)h(use)g(the)g+Fr(--cc)f Fx(option)g(to)739 1818 y(sp)r(ecify)32 b(additional)f+(recipien)n(ts.)49 b(Note)32 b(that)g(the)h Fr(--cc)d+Fx(option)h Fs(r)l(e)l(quir)l(es)39 b Fx(the)32 b Fr(--reply)739+1918 y Fx(option,)27 b(whic)n(h)h(pro)n(vides)e(the)i(\\F)-7+b(rom")26 b(address.)863 2018 y(The)39 b Fr(--reply)d+Fx(feature)i(of)g(apply)h(is)f(in)n(tended)h(primarily)f(for)g(t)n(w)n+(o)f(uses.)70 b(When)739 2117 y(used)32 b(b)n(y)f(itself,)i(it)f(is)g+(handy)f(for)h(when)f(y)n(ou)g(w)n(an)n(t)g(to)h(apply)f(patc)n(hes)h+(sen)n(t)f(to)h(y)n(ou)f(b)n(y)739 2217 y(other)24 b(dev)n(elop)r(ers)g+(so)h(that)g(they)g(will)g(kno)n(w)g(when)g(their)g(patc)n(h)g(has)f(b)+r(een)i(applied.)36 b(F)-7 b(or)739 2317 y(example,)27+b(in)h(m)n(y)f Fr(.muttrc)e Fx(\(the)j(con\014g)f(\014le)h(for)f(m)n(y)+g(mailer\))h(I)f(ha)n(v)n(e:)739 2478 y Fr(macro)41 b(pager)h(A)h+("<pipe-entry>dar)o(cs)37 b(apply)42 b(--verbose)e(\\)1088+2578 y(--reply)g(droundy@abridgega)o(me)o(.or)o(g)d(--repodir)j+(~/darcs)739 2740 y Fx(whic)n(h)33 b(allo)n(ws)f(me)h(to)h(apply)f(a)g+(patc)n(h)g(to)g(darcs)f(directly)h(from)g(m)n(y)g(mailer,)h(with)g+(the)739 2839 y(originator)20 b(of)j(that)f(patc)n(h)h(b)r(eing)f(sen)n+(t)h(a)f(con\014rmation)f(when)i(the)g(patc)n(h)f(is)h(successfully)739+2939 y(applied.)46 b(NOTE:)30 b(In)h(an)f(attempt)h(to)g(mak)n(e)e+(sure)h(no)h(one)f(else)g(can)g(read)g(y)n(our)f(email,)739+3038 y(m)n(utt)i(seems)g(to)g(set)g(the)g(umask)f(suc)n(h)h(that)g+(patc)n(hes)f(created)g(with)i(the)f(ab)r(o)n(v)n(e)f(macro)739+3138 y(are)c(not)i(w)n(orld-readable,)d(so)i(use)g(it)h(with)h(care.)+863 3238 y(When)k(used)e(in)h(com)n(bination)f(with)h(the)h+Fr(--verify)28 b Fx(option,)33 b(the)f Fr(--reply)d Fx(option)739+3337 y(allo)n(ws)20 b(for)h(a)g(nice)h(pushable)f(rep)r(ository)-7+b(.)34 b(When)22 b(these)f(t)n(w)n(o)g(options)g(are)g(used)g+(together,)739 3437 y(an)n(y)33 b(patc)n(hes)h(that)g(don't)h(pass)e+(the)i(v)n(erify)e(will)h(b)r(e)h(forw)n(arded)d(to)i(the)h+Fr(FROM)d Fx(address)739 3537 y(of)f(the)h Fr(--reply)d+Fx(option.)49 b(This)31 b(allo)n(ws)f(y)n(ou)h(to)h(set)f(up)h(a)f(rep)+r(ository)f(so)h(that)h(an)n(y)n(one)739 3636 y(who)j(is)h(authorized)f+(can)g(push)h(to)g(it)g(and)g(ha)n(v)n(e)e(it)i(automatically)f+(applied,)j(but)e(if)h(a)739 3736 y(stranger)25 b(pushes)i(to)h(it,)f+(the)h(patc)n(h)f(will)h(b)r(e)f(forw)n(arded)f(to)h(y)n(ou.)36+b(Please)26 b(\(for)h(y)n(our)f(o)n(wn)739 3835 y(sak)n(e!\))h(b)r(e)h+(certain)g(that)g(the)g Fr(--reply)41 b(FROM)26 b Fx(address)h(is)h+(di\013eren)n(t)g(from)f(the)i(one)e(used)739 3935 y(to)d(send)g(patc)n+(hes)f(to)h(a)f(pushable)h(rep)r(ository)-7 b(,)23 b(since)h(otherwise)+f(an)h(unsigned)f(patc)n(h)h(will)739 4035 y(b)r(e)k(forw)n(arded)e(to)+h(the)h(rep)r(ository)e(in)i(an)f(in\014nite)i(lo)r(op.)863+4134 y(If)j(y)n(ou)f(use)g Fr(darcs)41 b(apply)h(--verify)e(PUBRING)h+(--reply)28 b Fx(to)j(create)g(a)f(pushable)739 4234+y(rep)r(ository)22 b(b)n(y)i(applying)f(patc)n(hes)h(automatically)e+(as)i(they)g(are)f(receiv)n(ed)g(b)n(y)g(email,)i(y)n(ou)739+4334 y(will)j(also)e(w)n(an)n(t)h(to)h(use)f(the)h Fr(--dont-allow-con)+o(fli)o(ct)o(s)22 b Fx(option.)p 975 4511 V 975 4586+a Fr(--dont-allow-con)o(fli)o(ct)o(s)p 975 4622 V 739+4799 a Fx(The)28 b Fr(--dont-allow-co)o(nf)o(lic)o(ts)21+b Fx(\015ag)27 b(causes)f(apply)i(to)f(fail)h(when)f(applying)g(a)h+(patc)n(h)739 4899 y(w)n(ould)j(cause)g(con\015icts.)48+b(This)32 b(\015ag)f(is)g(recommended)g(on)h(rep)r(ositories)d(whic)n+(h)j(will)g(b)r(e)739 4998 y(pushed)c(to)f(or)g(sen)n(t)g(to.)p+eop end+%%Page: 79 79+TeXDict begin 79 78 bop 291 282 a Fu(6.6.)63 b(W)n(ORKING)28+b(WITH)g(CHANGES)1450 b Fx(79)p 527 515 2392 4 v 527+590 a Fr(--allow-conflict)o(s)p 527 627 V 415 817 a(--allow-conflict)o+(s)16 b Fx(will)22 b(allo)n(w)f(con\015icts,)i(but)g(will)f(k)n(eep)g+(the)g(lo)r(cal)f(and)h(recorded)291 916 y(v)n(ersions)32+b(in)i(sync)f(on)h(the)g(rep)r(ository)-7 b(.)54 b(This)33+b(means)h(the)g(con\015ict)g(will)g(exist)f(in)h(b)r(oth)291+1016 y(lo)r(cations)26 b(un)n(til)i(it)g(is)g(resolv)n(ed.)p+527 1206 V 527 1280 a Fr(--mark-conflicts)p 527 1317+V 415 1507 a(--mark-conflicts)21 b Fx(will)28 b(add)f(con\015ict)h+(mark)n(ers)e(to)h(illustrate)g(the)h(the)g(con\015ict.)p+527 1697 V 527 1772 a Fr(--external-merge)p 527 1827+V 415 2017 a Fx(Y)-7 b(ou)29 b(can)f(use)h(an)f(external)g(in)n+(teractiv)n(e)g(merge)g(to)r(ol)g(to)h(resolv)n(e)e(con\015icts)h(with)+i(the)291 2116 y(\015ag)c Fr(--external-merge)p Fx(.)31+b(F)-7 b(or)27 b(more)g(details)g(see)g(subsection)g(6.1.)p+527 2306 V 527 2381 a Fr(--all,)41 b(--interactive)p+527 2429 V 415 2619 a Fx(If)24 b(y)n(ou)g(pro)n(vide)e(the)j+Fr(--interactive)18 b Fx(\015ag,)24 b(darcs)f(will)h(ask)f(y)n(ou)g+(for)h(eac)n(h)f(c)n(hange)g(in)291 2719 y(the)29 b(patc)n(h)f(bundle)h+(whether)g(or)f(not)h(y)n(ou)f(wish)g(to)h(apply)f(that)h(c)n(hange.)39+b(The)29 b(opp)r(osite)291 2818 y(is)g(the)i Fr(--all)d+Fx(\015ag,)i(whic)n(h)g(can)g(b)r(e)g(used)g(to)g(o)n(v)n(erride)e(an)h+Fr(interactive)d Fx(whic)n(h)k(migh)n(t)291 2918 y(b)r(e)e(set)f(in)h+(y)n(our)e(\\defaults")h(\014le.)p 527 3108 V 527 3183+a Fr(--sendmail-comma)o(nd)p 527 3219 V 415 3409 a Fx(If)21+b(y)n(ou)f(w)n(an)n(t)f(to)i(use)f(a)g(command)g(di\013eren)n(t)g(from)+g(the)h(default)g(one)f(for)g(sending)g(mail,)291 3509+y(y)n(ou)i(need)h(to)h(sp)r(ecify)f(a)g(command)g(line)g(with)h(the)g+Fr(--sendmail-comma)o(nd)17 b Fx(option.)35 b(The)291+3608 y(command)e(line)h(can)g(con)n(tain)f(the)h(format)f(sp)r+(eci\014er)h Fr(\045t)f Fx(for)g(to)h(and)f(y)n(ou)h(can)f(add)h+Fr(\045<)291 3708 y Fx(to)29 b(the)i(end)f(of)f(the)i(command)e(line)h+(if)h(the)f(command)f(exp)r(ects)h(the)h(complete)e(mail)h(on)291+3808 y(standard)c(input.)38 b(F)-7 b(or)27 b(example,)g(the)h(command)f+(line)h(for)f(msm)n(tp)h(lo)r(oks)f(lik)n(e)g(this:)291+3999 y Fr(msmtp)41 b(\045t)i(\045<)p 527 4188 V 527 4262+a(--no-test,)c(--test)p 527 4310 V 415 4500 a Fx(If)c(y)n(ou)e(sp)r+(ecify)i(the)g Fr(--test)d Fx(option,)j(apply)f(will)h(run)f(the)h+(test)f(\(if)h(a)f(test)h(exists\))291 4600 y(prior)30+b(to)h(applying)f(the)i(patc)n(h.)47 b(If)32 b(the)f(test)h(fails,)g+(the)f(patc)n(h)g(is)g(not)h(applied.)47 b(In)32 b(this)291+4700 y(case,)39 b(if)f(the)f Fr(--reply)e Fx(option)i(w)n(as)g(used,)i+(the)f(results)f(of)h(the)f(test)h(are)f(sen)n(t)g(in)h(the)291+4799 y(reply)d(email.)61 b(Y)-7 b(ou)36 b(can)g(also)e(sp)r(ecify)i+(the)h Fr(--no-test)32 b Fx(option,)37 b(whic)n(h)f(will)g(o)n(v)n+(erride)291 4899 y(the)31 b Fr(--test)d Fx(option,)j(and)f(prev)n(en)n+(t)g(the)h(test)g(from)f(b)r(eing)h(run.)45 b(This)31+b(is)f(helpful)i(when)291 4998 y(setting)27 b(up)h(a)f(pushable)h(rep)r+(ository)-7 b(,)26 b(to)h(k)n(eep)g(users)g(from)g(running)h(co)r(de.)p+eop end+%%Page: 80 80+TeXDict begin 80 79 bop 739 282 a Fx(80)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)739 515 y Fq(6.7)135+b(Seeing)46 b(what)f(y)l(ou'v)l(e)h(done)739 871 y Fk(6.7.1)112+b(darcs)38 b(whatsnew)739 1182 y Fr(Usage:)j(darcs)h(whatsnew)e+([OPTION]...)f([FILE)i(or)i(DIRECTORY]...)863 1367 y+Fx(Options:)913 1546 y Fr(-s)99 b(--summary)575 b Fx(summarize)27+b(c)n(hanges)1100 1645 y Fr(--no-summary)443 b Fx(don't)28+b(summarize)f(c)n(hanges)913 1775 y Fr(-u)99 b(--unified)2071+1733 y Fx(output)29 b(patc)n(h)e(in)h(a)f(darcs-sp)r(eci\014c)f(format)+2071 1832 y(similar)h(to)h(di\013)g(-u)913 1934 y Fr(-l)99+b(--look-for-adds)2071 1895 y Fx(lo)r(ok)27 b(for)g(\(non-b)r(oring\))g+(\014les)h(that)g(could)f(b)r(e)2071 1994 y(added)1100+2104 y Fr(--dont-look-for-)o(add)o(s)2071 2052 y Fx(don't)h(lo)r(ok)f+(for)g(an)n(y)g(\014les)g(that)h(could)g(b)r(e)g(added)2071+2152 y([DEF)-9 b(A)n(UL)i(T])1100 2272 y Fr(--repodir)40+b(DIRECTORY)2071 2230 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e+(directory)h(in)g(whic)n(h)h(to)2071 2330 y(run)863 2480+y(Adv)-5 b(anced)28 b(options:)1013 2659 y Fr(--ignore-times)1723+2667 y Fx(don't)f(trust)h(the)g(\014le)g(mo)r(di\014cation)f(times)1013+2759 y Fr(--boring)358 b Fx(don't)27 b(skip)h(b)r(oring)f(\014les)863+2939 y(Displa)n(y)40 b(unrecorded)e(c)n(hanges)h(in)h(the)g(w)n(orking)+e(cop)n(y)-7 b(.)73 b(whatsnew)39 b(giv)n(es)g(y)n(ou)g(a)739+3039 y(view)28 b(of)g(what)h(c)n(hanges)e(y)n(ou'v)n(e)g(made)h(in)h(y)+n(our)e(w)n(orking)g(cop)n(y)g(that)i(ha)n(v)n(en't)f(y)n(et)g(b)r(een)+739 3139 y(recorded.)49 b(The)32 b(c)n(hanges)f(are)g(displa)n(y)n(ed)g+(in)i(darcs)e(patc)n(h)h(format.)50 b(Note)32 b(that)h({lo)r(ok-)739+3238 y(for-adds)21 b(implies)h({summary)g(usage.)34 b+Fr(darcs)41 b(whatsnew)19 b Fx(will)k(return)f(a)g(non-zero)e(v)-5+b(alue)739 3338 y(if)31 b(there)f(are)f(no)h(c)n(hanges,)f(whic)n(h)i+(can)e(b)r(e)i(useful)g(if)f(y)n(ou)g(just)h(w)n(an)n(t)e(to)h(see)g+(in)h(a)f(script)739 3438 y(if)35 b(an)n(ything)f(has)f(b)r(een)i(mo)r+(di\014ed.)58 b(If)35 b(y)n(ou)e(w)n(an)n(t)h(to)g(see)g(some)g(con)n+(text)g(around)f(y)n(our)739 3537 y(c)n(hanges,)25 b(y)n(ou)h(can)h+(use)f(the)h Fr(-u)f Fx(option,)h(to)f(get)g(output)i(similar)e(to)g+(the)h(unidi\013)h(format.)863 3722 y(If)e(y)n(ou)e(giv)n(e)g(one)g(or)+g(more)h(\014le)g(or)f(directory)f(names)i(as)f(an)h(argumen)n(t)f(to)g+Fr(whatsnew)p Fx(,)739 3821 y(darcs)i(will)i(output)g(only)g(c)n+(hanges)e(to)h(those)g(\014les)h(or)f(to)g(\014les)h(in)f(those)h+(directories.)739 4503 y Fk(6.7.2)112 b(darcs)38 b(c)m(hanges)739+4814 y Fr(Usage:)j(darcs)h(changes)e([OPTION]...)f([FILE)j(or)h+(DIRECTORY]...)863 4998 y Fx(Options:)p eop end+%%Page: 81 81+TeXDict begin 81 80 bop 291 282 a Fu(6.7.)63 b(SEEING)27+b(WHA)-7 b(T)29 b(YOU'VE)f(DONE)1347 b Fx(81)652 532+y Fr(--to-match)39 b(PATTERN)1623 490 y Fx(select)28+b(c)n(hanges)e(up)i(to)f(a)g(patc)n(h)h(matc)n(hing)1623+590 y(P)-7 b(A)g(TTERN)652 689 y Fr(--to-patch)39 b(REGEXP)1623+647 y Fx(select)28 b(c)n(hanges)e(up)i(to)f(a)g(patc)n(h)h(matc)n(hing)+1623 747 y(REGEXP)652 846 y Fr(--to-tag)40 b(REGEXP)1623+804 y Fx(select)28 b(c)n(hanges)e(up)i(to)f(a)g(tag)g(matc)n(hing)1623+904 y(REGEXP)652 1012 y Fr(--from-match)38 b(PATTERN)1623+962 y Fx(select)28 b(c)n(hanges)e(starting)g(with)j(a)e(patc)n(h)1623+1061 y(matc)n(hing)g(P)-7 b(A)g(TTERN)652 1185 y Fr(--from-patch)38+b(REGEXP)1623 1135 y Fx(select)28 b(c)n(hanges)e(starting)g(with)j(a)e+(patc)n(h)1623 1235 y(matc)n(hing)g(REGEXP)652 1350 y+Fr(--from-tag)39 b(REGEXP)1623 1309 y Fx(select)28 b(c)n(hanges)e+(starting)g(with)j(a)e(tag)g(matc)n(hing)1623 1408 y(REGEXP)652+1478 y Fr(--last)41 b(NUMBER)402 b Fx(select)28 b(the)g(last)f(NUMBER)h+(patc)n(hes)652 1578 y Fr(--matches)40 b(PATTERN)227+b Fx(select)28 b(patc)n(hes)e(matc)n(hing)i(P)-7 b(A)g(TTERN)465+1677 y Fr(-p)99 b(--patches)40 b(REGEXP)271 b Fx(select)28+b(patc)n(hes)e(matc)n(hing)i(REGEXP)465 1777 y Fr(-t)99+b(--tags)41 b(REGEXP)402 b Fx(select)28 b(tags)e(matc)n(hing)h(REGEXP)+652 1876 y Fr(--only-to-files)311 b Fx(sho)n(w)27 b(only)g(c)n(hanges)f+(to)i(sp)r(eci\014ed)f(\014les)652 1976 y Fr(--context)575+b Fx(giv)n(e)27 b(output)h(suitable)f(for)g(get)h({con)n(text)652+2076 y Fr(--xml-output)443 b Fx(generate)26 b(XML)i(formatted)g(output)+652 2175 y Fr(--human-readable)267 b Fx(giv)n(e)27 b(h)n(uman-readable)+e(output)652 2275 y Fr(--count)663 b Fx(output)28 b(coun)n(t)g(of)f(c)n+(hanges)465 2375 y Fr(-s)99 b(--summary)575 b Fx(summarize)27+b(c)n(hanges)652 2474 y Fr(--no-summary)443 b Fx(don't)28+b(summarize)f(c)n(hanges)652 2574 y Fr(--reverse)575+b Fx(sho)n(w)27 b(c)n(hanges)f(in)i(rev)n(erse)d(order)652+2673 y Fr(--repo)41 b(URL)534 b Fx(sp)r(ecify)28 b(the)g(rep)r(ository)+e(URL)652 2803 y Fr(--repodir)40 b(DIRECTORY)1623 2761+y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)g+(to)1623 2861 y(run)465 2930 y Fr(-a)99 b(--all)751 b+Fx(answ)n(er)26 b(y)n(es)h(to)h(all)f(patc)n(hes)465+3030 y Fr(-i)99 b(--interactive)399 b Fx(prompt)27 b(user)g(in)n+(teractiv)n(ely)415 3126 y(Adv)-5 b(anced)28 b(options:)565+3260 y Fr(--no-ssh-cm)1144 3208 y Fx(don't)f(use)h(SSH)g(Con)n+(trolMaster)d(feature)1144 3308 y([DEF)-9 b(A)n(UL)i(T])565+3398 y Fr(--ssh-cm)1144 3406 y Fx(use)27 b(SSH)h(Con)n(trolMaster)e+(feature)415 3494 y(Changes)20 b(giv)n(es)f(a)h(c)n(hangelog-st)n(yle)e+(summary)i(of)g(the)h(rep)r(ository)e(history)-7 b(,)22+b(including)291 3594 y(options)27 b(for)g(altering)f(ho)n(w)h(the)h+(patc)n(hes)f(are)g(selected)g(and)h(displa)n(y)n(ed.)415+3693 y(When)35 b(giv)n(en)f(one)g(or)g(more)g(\014les)g(or)g+(directories)f(as)h(an)g(argumen)n(t,)i(c)n(hanges)d(lists)291+3793 y(only)f(those)g(patc)n(hes)h(whic)n(h)f(a\013ect)h(those)g+(\014les)g(or)f(the)h(con)n(ten)n(ts)f(of)h(those)f(directories)291+3892 y(or,)d(of)h(course,)g(the)g(directories)f(themselv)n(es.)44+b(This)30 b(includes)g(c)n(hanges)e(that)j(happ)r(ened)291+3992 y(to)c(\014les)h(b)r(efore)f(they)h(w)n(ere)e(mo)n(v)n(ed)h(or)g+(renamed.)p 527 4141 2392 4 v 527 4216 a Fr(--from-match,)38+b(--from-patch,)g(--from-tag)p 527 4271 V 415 4421 a+Fx(If)30 b(c)n(hanges)d(is)i(giv)n(en)f(a)h Fr(--from-patch)p+Fx(,)24 b Fr(--from-match)p Fx(,)h(or)j Fr(--from-tag)d+Fx(option,)291 4520 y(it)j(outputs)f(only)h(those)f(c)n(hanges)f(since)+h(that)h(tag)f(or)g(patc)n(h.)415 4620 y(Without)32 b(an)n(y)e(options)+g(to)h(limit)h(the)f(scop)r(e)f(of)h(the)g(c)n(hanges,)g(history)f+(will)h(b)r(e)g(dis-)291 4719 y(pla)n(y)n(ed)26 b(going)h(bac)n(k)f(as)+h(far)g(as)g(p)r(ossible.)p 527 4869 V 527 4944 a Fr(--context,)39+b(--human-readable,)e(--xml-output)p 527 4998 V eop end+%%Page: 82 82+TeXDict begin 82 81 bop 739 282 a Fx(82)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(When)21+b(giv)n(en)f(the)h Fr(--context)c Fx(\015ag,)k(darcs)e(c)n(hanges)h+(outputs)g(su\016cien)n(t)h(information)739 615 y(to)k(allo)n(w)f(the)h+(curren)n(t)g(state)g(of)g(the)g(rep)r(ository)f(to)h(b)r(e)g+(recreated)f(at)h(a)g(later)f(date.)36 b(This)739 715+y(information)31 b(should)h(generally)e(b)r(e)i(pip)r(ed)h(to)f(a)f+(\014le,)i(and)f(then)g(can)g(b)r(e)g(used)g(later)f(in)739+814 y(conjunction)g(with)h Fr(darcs)41 b(get)i(--context)27+b Fx(to)k(recreate)f(the)h(curren)n(t)f(v)n(ersion.)46+b(Note)739 914 y(that)28 b(while)h(the)f Fr(--context)d+Fx(\015ag)i(ma)n(y)h(b)r(e)g(used)h(in)f(conjunction)g(with)h+Fr(--xml-output)739 1013 y Fx(or)24 b Fr(--human-readabl)o(e)p+Fx(,)19 b(in)25 b(neither)g(case)f(will)h(darcs)e(get)i(b)r(e)g(able)f+(to)h(read)f(the)h(output.)739 1113 y(On)34 b(the)g(other)f(hand,)j+(su\016cien)n(t)d(information)h Fs(wil)t(l)44 b Fx(b)r(e)34+b(output)g(for)g(a)f(kno)n(wledgeable)739 1213 y(h)n(uman)27+b(to)h(recreate)e(the)i(curren)n(t)f(state)g(of)h(the)g(rep)r(ository)+-7 b(.)739 1564 y Fk(6.7.3)112 b(darcs)38 b(sho)m(w)739+1758 y Fx(The)24 b(sho)n(w)f(command)g(pro)n(vides)g(access)f(to)i(sev)+n(eral)e(sub)r(commands)i(whic)n(h)g(can)f(b)r(e)h(used)739+1858 y(to)j(in)n(v)n(estigate)g(the)h(state)f(of)h(a)f(rep)r(ository)-7+b(.)739 2192 y Fv(darcs)33 b(sho)m(w)e(authors)739 2387+y Fr(Usage:)41 b(darcs)h(show)f(authors)g([OPTION]...)863+2509 y Fx(Options:)1013 2655 y Fr(--repodir)f(DIRECTORY)1941+2614 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)d(directory)i(in)h(whic)n+(h)f(to)1941 2713 y(run)863 2802 y(The)g(authors)f(command)h(writes)f+(a)h(list)g(of)g(all)g(patc)n(h)g(authors)e(in)j(the)f(rep)r(ository)e+(to)739 2901 y(standard)i(output.)739 3235 y Fv(darcs)33+b(sho)m(w)e(con)m(ten)m(ts)739 3430 y Fr(Usage:)41 b(darcs)h(show)f+(contents)g([OPTION]...)e([FILE]...)863 3552 y Fx(Options:)1100+3669 y Fr(--match)i(PATTERN)271 b Fx(select)27 b(a)g(single)h(patc)n(h)+f(matc)n(hing)g(P)-7 b(A)g(TTERN)913 3768 y Fr(-p)99+b(--patch)41 b(REGEXP)315 b Fx(select)27 b(a)g(single)h(patc)n(h)f+(matc)n(hing)g(REGEXP)913 3868 y Fr(-t)99 b(--tag)42+b(REGEXP)402 b Fx(select)27 b(tag)g(matc)n(hing)g(REGEXP)1100+3997 y Fr(--repodir)40 b(DIRECTORY)2028 3956 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)f(to)2028+4055 y(run)863 4148 y(Sho)n(w)33 b(con)n(ten)n(ts)f(can)h(b)r(e)g(used)+h(to)e(displa)n(y)h(an)f(earlier)g(v)n(ersion)g(of)h(some)f+(\014le\(s\).)54 b(If)739 4248 y(y)n(ou)31 b(giv)n(e)g(sho)n(w)f(con)n+(ten)n(ts)h(no)h(v)n(ersion)e(argumen)n(ts,)i(it)g(displa)n(ys)e(the)j+(recorded)d(v)n(ersion)739 4347 y(of)d(the)h(\014le\(s\).)739+4682 y Fv(darcs)33 b(sho)m(w)e(\014les)739 4877 y Fr(Usage:)41+b(darcs)h(show)f(files)h([OPTION]...)863 4998 y Fx(Options:)p+eop end+%%Page: 83 83+TeXDict begin 83 82 bop 291 282 a Fu(6.7.)63 b(SEEING)27+b(WHA)-7 b(T)29 b(YOU'VE)f(DONE)1347 b Fx(83)652 502+y Fr(--files)619 b Fx(include)28 b(\014les)g(in)g(output)g([DEF)-9+b(A)n(UL)i(T])652 602 y Fr(--no-files)487 b Fx(don't)28+b(include)g(\014les)g(in)g(output)652 701 y Fr(--directories)355+b Fx(include)28 b(directories)f(in)h(output)g([DEF)-9+b(A)n(UL)i(T])652 801 y Fr(--no-directories)223 b Fx(don't)28+b(include)g(directories)e(in)i(output)652 941 y Fr(--pending)1579+888 y Fx(re\015ect)g(p)r(ending)g(patc)n(hes)f(in)h(output)1579+988 y([DEF)-9 b(A)n(UL)i(T])652 1079 y Fr(--no-pending)399+b Fx(only)28 b(included)g(recorded)e(patc)n(hes)h(in)h(output)465+1178 y Fr(-0)99 b(--null)663 b Fx(separate)27 b(\014le)g(names)h(b)n(y)+f(NUL)h(c)n(haracters)652 1307 y Fr(--repodir)40 b(DIRECTORY)1579+1266 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e(directory)h(in)h(whic)n+(h)f(to)1579 1365 y(run)415 1437 y(The)d(\014les)g(command)f(lists)h+(the)g(v)n(ersion-con)n(trolled)c(\014les)k(in)g(the)g(w)n(orking)e+(cop)n(y)-7 b(.)35 b(The)291 1537 y(similar)26 b(manifest)i(command,)g+(lists)f(the)h(same)f(\014les,)h(excluding)f(an)n(y)g(directories.)415+1642 y(By)i(default)h(\(and)f(if)h(the)g Fr(--pending)25+b Fx(option)k(is)h(sp)r(eci\014ed\),)g(the)g(e\013ect)f(of)h(p)r+(ending)291 1741 y(patc)n(hes)h(on)i(the)g(rep)r(ository)e(is)h(tak)n+(en)g(in)n(to)g(accoun)n(t.)51 b(In)33 b(other)f(w)n(ords,)g(if)h(y)n+(ou)f(add)g(a)291 1841 y(\014le)24 b(using)g Fr(darcs)41+b(add)p Fx(,)24 b(it)h(immediately)f(app)r(ears)f(in)i(the)g(output)f+(of)h Fr(query)41 b(manifest)p Fx(,)291 1941 y(ev)n(en)31+b(if)i(it)f(is)h(not)f(y)n(et)g(recorded.)49 b(If)32+b(y)n(ou)g(sp)r(ecify)g(the)h Fr(--no-pending)27 b Fx(option,)33+b Fr(query)291 2040 y(manifest)24 b Fx(will)k(only)f(list)h(recorded)e+(\014les)h(\(and)h(directories\).)415 2146 y(The)35 b+Fr(--files)c Fx(and)j Fr(--directories)29 b Fx(options)34+b(con)n(trol)f(whether)h(\014les)g(and)h(direc-)291 2245+y(tories)j(are)g(included)i(in)g(the)g(output.)72 b(The)40+b Fr(--no-files)35 b Fx(and)k Fr(--no-directories)291+2345 y Fx(options)28 b(ha)n(v)n(e)g(the)i(rev)n(erse)d(e\013ect.)42+b(The)29 b(default)g(is)g(to)g(include)h(\014les,)f(but)h(not)f+(directo-)291 2444 y(ries.)415 2550 y(If)39 b(y)n(ou)e(sp)r(ecify)i+(the)g Fr(--null)c Fx(option,)41 b(the)e(\014le)f(names)g(are)f+(written)i(to)f(standard)291 2649 y(output)28 b(in)f(unescap)r(ed)g+(form,)h(and)f(separated)f(b)n(y)h(ASCI)r(I)h(NUL)g(b)n(ytes.)37+b(This)27 b(format)g(is)291 2749 y(suitable)g(for)g(further)h+(automatic)f(pro)r(cessing)f(\(for)h(example,)g(using)h+Fr(xargs)41 b(-0)p Fx(\).)291 2994 y Fv(darcs)32 b(sho)m(w)g(tags)291+3158 y Fr(Usage:)41 b(darcs)g(show)h(tags)g([OPTION]...)415+3263 y Fx(Options:)565 3393 y Fr(--repodir)d(DIRECTORY)1492+3351 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e(directory)g(in)i(whic)n+(h)g(to)1492 3451 y(run)415 3522 y(The)37 b(tags)f(command)h(writes)g+(a)f(list)i(of)f(all)g(tags)f(in)h(the)h(rep)r(ository)d(to)i(standard)+291 3622 y(output.)415 3727 y(T)-7 b(ab)29 b(c)n(haracters)d(\(ASCI)r+(I)k(c)n(haracter)c(9\))j(in)g(tag)f(names)g(are)g(c)n(hanged)f(to)i+(spaces)e(for)291 3827 y(b)r(etter)h(in)n(terop)r(erabilit)n(y)e(with)i+(shell)f(to)r(ols.)37 b(A)28 b(w)n(arning)e(is)h(prin)n(ted)h(if)g+(this)g(happ)r(ens.)291 4072 y Fv(darcs)k(sho)m(w)g(rep)s(o)291+4236 y Fr(Usage:)41 b(darcs)g(show)h(repo)g([OPTION]...)415+4341 y Fx(Options:)565 4471 y Fr(--repodir)d(DIRECTORY)1492+4429 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e(directory)g(in)i(whic)n+(h)g(to)1492 4528 y(run)565 4598 y Fr(--files)619 b Fx(include)28+b(\014les)g(in)g(output)g([DEF)-9 b(A)n(UL)i(T])565 4698+y Fr(--no-files)487 b Fx(don't)28 b(include)g(\014les)g(in)f(output)565+4797 y Fr(--xml-output)399 b Fx(generate)27 b(XML)h(formatted)f(output)+415 4899 y(The)e Fr(show)42 b(repo)23 b Fx(displa)n(ys)g(information)h+(ab)r(out)h(the)f(curren)n(t)g(rep)r(ository:)34 b(the)25+b(lo)r(ca-)291 4998 y(tion,)i(the)h(t)n(yp)r(e,)g(etc.)p+eop end+%%Page: 84 84+TeXDict begin 84 83 bop 739 282 a Fx(84)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(This)23+b(is)f(pro)n(vided)g(as)g(informational)f(output)i(for)f(t)n(w)n(o)g+(purp)r(oses:)33 b(curious)22 b(users)f(and)739 615 y(scripts)f(in)n(v)+n(oking)e(darcs.)34 b(F)-7 b(or)20 b(the)g(latter,)i(this)e+(information)g(can)g(b)r(e)h(parsed)e(to)h(facilitate)739+715 y(the)34 b(script;)j(for)d(example,)h Fr(darcs)41+b(show)h(repo)g(|)h(grep)f(Root:)g(|)h(awk)f({print)f($2})739+814 y Fx(can)36 b(b)r(e)h(used)f(to)h(lo)r(cate)f(the)g(top-lev)n(el)g+Fr(_darcs)e Fx(directory)h(from)h(an)n(yplace)f(within)j(a)739+914 y(darcs)26 b(rep)r(ository)g(w)n(orking)g(directory)-7+b(.)p 975 1080 2392 4 v 975 1155 a Fr(--files,)40 b(--no-files)p+975 1203 V 863 1370 a Fx(If)30 b(the)f Fr(--files)d Fx(option)j(is)f+(sp)r(eci\014ed)h(\(the)h(default\),)g(then)f(the)g Fr(show)42+b(repo)28 b Fx(op)r(era-)739 1470 y(tion)e(will)h(read)f(patc)n(h)g+(information)g(from)g(the)h(rep)r(ository)d(and)j(displa)n(y)e(the)i(n)+n(um)n(b)r(er)f(of)739 1569 y(patc)n(hes)g(in)h(the)g(rep)r(ository)-7+b(.)36 b(The)26 b Fr(--no-files)d Fx(option)k(can)f(b)r(e)h(used)g(to)g+(suppress)f(this)739 1669 y(op)r(eration)g(\(and)i(impro)n(v)n(e)e(p)r+(erformance\).)p 975 1835 V 975 1910 a Fr(--human-readable)o(,)38+b(--xml-output)p 975 1965 V 863 2132 a Fx(By)25 b(default,)g(the)g+Fr(show)42 b(repo)23 b Fx(displa)n(ys)h(output)h(in)f(h)n(uman)h+(readable)e(form,)i(but)g(the)739 2231 y Fr(--xml-output)16+b Fx(option)22 b(can)f(b)r(e)g(used)h(to)f(obtain)g(XML-formatted)g(to)+h(facilitate)f(regular)739 2331 y(parsing)26 b(b)n(y)h(external)g(to)r+(ols.)739 2603 y Fq(6.8)135 b(More)45 b(adv)-7 b(anced)45+b(commands)739 2801 y Fk(6.8.1)112 b(darcs)38 b(tag)739+2955 y Fr(Usage:)j(darcs)h(tag)g([OPTION]...)d([TAGNAME])863+3054 y Fx(Options:)913 3148 y Fr(-m)99 b(--patch-name)39+b(PATCHNAME)96 b Fx(name)27 b(of)h(patc)n(h)913 3248+y Fr(-A)99 b(--author)40 b(EMAIL)447 b Fx(sp)r(ecify)27+b(author)g(id)1100 3348 y Fr(--checkpoint)531 b Fx(create)26+b(a)h(c)n(hec)n(kp)r(oin)n(t)g(\014le)h(\(see)g(get)f({partial\))1100+3447 y Fr(--pipe)795 b Fx(exp)r(ect)27 b(to)h(receiv)n(e)e(input)j+(from)e(a)g(pip)r(e)913 3547 y Fr(-i)99 b(--interactive)487+b Fx(prompt)27 b(user)g(in)n(teractiv)n(ely)1100 3676+y Fr(--repodir)40 b(DIRECTORY)2159 3634 y Fx(sp)r(ecify)27+b(the)h(rep)r(ository)e(directory)h(in)h(whic)n(h)f(to)2159+3734 y(run)863 3800 y(Adv)-5 b(anced)28 b(options:)1013+3894 y Fr(--compress)313 b Fx(create)27 b(compressed)f(patc)n(hes)1013+3994 y Fr(--dont-compress)93 b Fx(don't)28 b(create)f(compressed)f+(patc)n(hes)1013 4093 y Fr(--umask)41 b(UMASK)184 b Fx(sp)r(ecify)28+b(umask)f(to)h(use)f(when)h(writing)863 4194 y(T)-7 b(ag)21+b(is)f(used)h(to)g(name)g(a)f(v)n(ersion)g(of)h(this)g(rep)r(ository)e+(\(i.e.)35 b(the)22 b(whole)e(tree\).)35 b(T)-7 b(ag)20+b(dif-)739 4293 y(fers)f(from)h(record)f(in)h(that)g(it)h(do)r(esn't)f+(record)e(an)n(y)h(new)h(c)n(hanges,)h(and)e(it)i(alw)n(a)n(ys)d(dep)r+(ends)739 4393 y(on)24 b(all)h(patc)n(hes)f(residing)g(in)h(the)g(rep)r+(ository)e(when)i(it)g(is)g(tagged.)35 b(This)24 b(means)h(that)g(one)+739 4493 y(can)i(later)g(repro)r(duce)g(this)h(v)n(ersion)e(of)h(the)h+(rep)r(ository)e(b)n(y)h(calling,)g(for)g(example:)739+4646 y Fr(\045)43 b(darcs)f(get)g(--tag)f("darcs)h(3.14")f+(REPOLOCATION)863 4799 y Fx(Eac)n(h)22 b(tagged)g(v)n(ersion)f(has)i(a)+f(v)n(ersion)g(name.)35 b(The)23 b(v)n(ersion)e(is)i(also)f(\015agged)f+(with)j(the)739 4899 y(p)r(erson)i(who)g(tagged)f(it)i(\(tak)n(en)f(b)n+(y)g(default)h(from)f(the)h(`D)n(AR)n(CS)p 2828 4899+25 4 v 30 w(EMAIL')g(or)e(`EMAIL')739 4998 y(en)n(vironmen)n(t)i(v)-5+b(ariable\).)36 b(The)27 b(date)h(is)f(also)g(included)h(in)g(the)g(v)n+(ersion)e(information.)p eop end+%%Page: 85 85+TeXDict begin 85 84 bop 291 282 a Fu(6.8.)63 b(MORE)27+b(AD)n(V)-9 b(ANCED)29 b(COMMANDS)1283 b Fx(85)415 515+y(A)39 b(tagged)e(v)n(ersion)f(automatically)h(dep)r(ends)i(on)f(all)g+(patc)n(hes)f(in)i(the)f(rep)r(ository)-7 b(.)291 615+y(This)27 b(allo)n(ws)g(y)n(ou)g(to)h(later)f(repro)r(duce)g(precisely)+g(that)i(v)n(ersion.)36 b(The)28 b(tag)f(do)r(es)h(this)g(b)n(y)291+715 y(dep)r(ending)c(on)h(all)f(patc)n(hes)g(in)g(the)h(rep)r(ository)+-7 b(,)24 b(except)g(for)g(those)g(whic)n(h)h(are)e(dep)r(ended)291+814 y(up)r(on)e(b)n(y)g(other)g(tags)f(already)g(in)i(the)g(rep)r+(ository)-7 b(.)33 b(In)21 b(the)h(common)f(case)f(of)i(a)f(sequen)n+(tial)291 914 y(series)j(of)i(tags,)g(this)g(means)f(that)i(the)f(tag)f+(dep)r(ends)h(on)g(all)g(patc)n(hes)f(since)h(the)g(last)f(tag,)291+1013 y(plus)i(that)h(tag)f(itself.)p 527 1193 2392 4+v 527 1268 a Fr(--checkpoint)p 527 1323 V 291 1502 a+Fx(The)e Fr(--checkpoint)c Fx(option)k(allo)n(ws)f(the)h(tag)g(b)r(e)h+(used)f(later)g(with)h(the)g Fr(--partial)c Fx(\015ag)291+1602 y(to)27 b Fr(get)f Fx(or)h Fr(check)p Fx(.)415 1701+y(A)40 b(partial)e(rep)r(ository)g(only)h(con)n(tains)f(patc)n(hes)h+(from)g(after)g(the)g(c)n(hec)n(kp)r(oin)n(t.)72 b(A)291+1801 y(partial)31 b(rep)r(ository)g(w)n(orks)f(just)j(lik)n(e)f(a)f+(normal)h(rep)r(ository)-7 b(,)32 b(but)g(an)n(y)g(command)g(that)291+1900 y(needs)27 b(to)h(lo)r(ok)e(at)i(the)g(con)n(ten)n(ts)f(of)g(a)h+(missing)f(patc)n(h)g(will)h(complain)f(and)g(ab)r(ort.)p+527 2080 V 527 2155 a Fr(--pipe)p 527 2209 V 415 2389+a Fx(If)21 b(y)n(ou)e(run)h(tag)g(with)g(the)h Fr(--pipe)d+Fx(option,)j(y)n(ou)e(will)i(b)r(e)f(prompted)g(for)g(the)h(tag)e(name)+291 2488 y(and)24 b(date.)35 b(This)24 b(in)n(terface)g(is)g(in)n+(tended)g(for)g(scripting)g(darcs,)f(in)i(particular)e(for)g(writing)+291 2588 y(rep)r(ository)i(con)n(v)n(ersion)f(scripts.)36+b(The)26 b(prompts)g(are)g(in)n(tended)h(mostly)f(as)g(useful)h(guide)+291 2688 y(\(since)f(scripts)f(w)n(on't)h(need)h(them\),)g(to)f(help)g+(y)n(ou)g(understand)f(the)i(format)f(in)g(whic)n(h)g(to)291+2787 y(pro)n(vide)g(the)i(input.)38 b(Here's)27 b(an)g(example)g(of)h+(what)f(the)h Fr(--pipe)d Fx(prompts)j(lo)r(oks)e(lik)n(e:)334+2967 y Fr(What)42 b(is)h(the)f(date?)g(Mon)g(Nov)g(15)h(13:38:01)d(EST)+j(2004)334 3066 y(Who)g(is)f(the)h(author?)d(David)i(Roundy)334+3166 y(What)g(is)h(the)f(version)f(name?)g(3.0)334 3266+y(Finished)f(tagging)h(patch)h('TAG)g(3.0')415 3445 y+Fx(Using)25 b Fr(tag)f Fx(creates)g(an)g(en)n(try)h(in)g(the)h(rep)r+(ository)d(history)h(just)i(lik)n(e)f Fr(record)p Fx(.)33+b(It)26 b(will)291 3545 y(sho)n(w)g(up)i(with)g Fr(darcs)42+b(changes)25 b Fx(app)r(earing)h(in)i(the)g(format:)334+3724 y Fr(tagged)41 b(My)i(Tag)f(Name)415 3903 y Fx(T)-7+b(o)20 b(displa)n(y)f(all)h(tags)g(in)g(the)h(rep)r(ository)-7+b(,)20 b(use)g(the)h(\\)p Fr(darcs)41 b(query)g(tags)p+Fx(")18 b(command.)291 4135 y Fk(6.8.2)112 b(darcs)38+b(setpref)291 4288 y Fr(Usage:)j(darcs)g(setpref)g([OPTION]...)e+(<PREF>)i(<VALUE>)415 4388 y Fx(Options:)565 4512 y Fr(--repodir)e+(DIRECTORY)1492 4470 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e+(directory)g(in)i(whic)n(h)g(to)1492 4570 y(run)415 4636+y(Adv)-5 b(anced)28 b(options:)565 4734 y Fr(--umask)40+b(UMASK)98 b Fx(sp)r(ecify)28 b(umask)f(to)g(use)h(when)f(writing)415+4835 y(Usage)g(example:)291 4998 y Fr(\045)43 b(darcs)e(setpref)g(test)+h("echo)f(I)j(am)e(not)h(really)e(testing)f(anything.")p+eop end+%%Page: 86 86+TeXDict begin 86 85 bop 739 282 a Fx(86)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(Setpref)h(allo)n(ws)e+(y)n(ou)g(to)i(set)f(a)g(preference)f(v)-5 b(alue)28+b(in)h(a)f(w)n(a)n(y)f(that)h(will)h(propagate)d(to)739+615 y(other)h(rep)r(ositories.)863 715 y(V)-7 b(alid)27+b(preferences)f(are:)35 b(test)27 b(predist)f(b)r(oring\014le)g+(binaries\014le.)36 b(If)27 b(y)n(ou)e(just)i(w)n(an)n(t)f(to)739+815 y(set)18 b(the)h(pref)f(v)-5 b(alue)19 b(in)f(y)n(our)f(rep)r+(ository)g(only)-7 b(,)20 b(y)n(ou)e(can)g(just)h(edit)f(\\)p+Fr(_darcs/prefs/pre)o(fs)p Fx(")o(.)739 914 y(Changes)26+b(y)n(ou)h(mak)n(e)g(in)h(that)g(\014le)g(will)f(b)r(e)h(preserv)n(ed.)+863 1015 y(The)22 b(\\)p Fr(_darcs/prefs/p)o(ref)o(s)p+Fx(")15 b(holds)21 b(the)g(only)g(preferences)f(information)h(that)h+(can)739 1114 y(propagate)h(b)r(et)n(w)n(een)i(rep)r(ositories)e(b)n(y)+i(pushes)g(and)f(pulls,)i(and)f(the)g(only)g(w)n(a)n(y)e(this)j(hap-)+739 1214 y(p)r(ens)k(is)h(when)f(the)h(setprefs)e(command)h(is)g(used.)+45 b(Note)30 b(that)h(although)f(prefs)f(settings)739+1314 y(are)36 b(included)i(in)f(patc)n(hes,)i(they)f(are)e+Fs(not)44 b Fx(fully)38 b(v)n(ersion)e(con)n(trolled.)64+b(In)37 b(particular,)739 1413 y(dep)r(ending)29 b(on)g(the)h(order)e+(in)h(whic)n(h)g(a)g(series)f(of)h(merges)f(is)h(p)r(erformed,)g(y)n+(ou)g(ma)n(y)f(end)739 1513 y(up)j(with)g(a)f(di\013eren)n(t)h(\014nal)+g(prefs)f(con\014guration.)45 b(In)31 b(practice)f(I)g(don't)h(exp)r+(ect)g(this)g(to)739 1612 y(b)r(e)d(a)f(problem,)g(as)g(the)h(prefs)f+(usually)h(w)n(on't)f(b)r(e)h(c)n(hanged)e(v)n(ery)h(often.)863+1713 y(The)32 b(follo)n(wing)e(v)-5 b(alues)31 b(are)f(v)-5+b(alid)32 b(preferences)e(options)h(whic)n(h)g(can)g(b)r(e)g+(con\014gured)739 1812 y(using)c(setpref:)863 1980 y+Fn(\017)41 b Fx(\\test")27 b(|)h(the)g(command)f(to)h(run)f(as)g(a)g+(test)h(script.)863 2149 y Fn(\017)41 b Fx(\\predist")27+b(|)g(a)g(command)g(to)g(run)h(prior)e(to)h(tarring)f(up)i(a)f+(distribution)g(tarball.)946 2248 y(T)n(ypically)g(this)h(w)n(ould)f+(consist)g(of)h(auto)r(conf)f(and/or)f(automak)n(e.)863+2417 y Fn(\017)41 b Fx(\\b)r(oring\014le")23 b(|)h(the)g(name)g(of)g(a)+g(\014le)g(to)g(read)f(instead)h(of)g(the)g(\\b)r(oring")e(prefs)i+(\014le.)863 2585 y Fn(\017)41 b Fx(\\binaries\014le")27+b(|)h(the)h(name)f(of)g(a)g(\014le)h(to)f(read)f(instead)h(of)g(the)h+(\\binaries")e(prefs)946 2685 y(\014le.)739 2920 y Fk(6.8.3)112+b(darcs)38 b(c)m(hec)m(k)739 3075 y Fr(Usage:)j(darcs)h(check)f+([OPTION]...)863 3175 y Fx(Options:)1013 3270 y Fr(--complete)662+b Fx(get)27 b(a)h(complete)f(cop)n(y)g(of)g(the)h(rep)r(ository)1013+3410 y Fr(--partial)2115 3357 y Fx(get)f(partial)g(rep)r(ository)f+(using)h(c)n(hec)n(kp)r(oin)n(t)2115 3457 y(\(old-fashioned)g(format)g+(only\))1013 3548 y Fr(--verify-hashes)442 b Fx(v)n(erify)27+b(v)-5 b(alidit)n(y)27 b(of)h(patc)n(h)f(\014les)1013+3647 y Fr(--no-test)706 b Fx(don't)28 b(run)f(the)h(test)g(script)1013+3747 y Fr(--test)838 b Fx(run)27 b(the)h(test)g(script)1013+3846 y Fr(--leave-test-dir)o(ec)o(tor)o(y)137 b Fx(don't)28+b(remo)n(v)n(e)e(the)i(test)g(directory)1013 3946 y Fr+(--remove-test-di)o(re)o(cto)o(ry)93 b Fx(remo)n(v)n(e)26+b(the)i(test)g(directory)1013 4075 y Fr(--repodir)40+b(DIRECTORY)2115 4034 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e+(directory)g(in)i(whic)n(h)g(to)2115 4133 y(run)863 4200+y(Chec)n(k)f(the)h(rep)r(ository)d(for)i(consistency)-7+b(.)36 b(Chec)n(k)26 b(v)n(eri\014es)h(that)g(the)h(patc)n(hes)e+(stored)739 4299 y(in)g(the)g(rep)r(ository)-7 b(,)24+b(when)i(successiv)n(ely)e(applied)h(to)h(an)f(empt)n(y)h(tree,)f(prop)+r(erly)g(recreate)739 4399 y(the)j(stored)f(pristine)g(tree.)p+975 4584 2392 4 v 975 4659 a Fr(--complete,)39 b(--partial)p+975 4714 V 863 4899 a Fx(If)h(y)n(ou)e(ha)n(v)n(e)f(a)i(c)n(hec)n(kp)r+(oin)n(t)f(of)h(the)g(rep)r(ository)e(\(as)h(is)h(the)g(case)f(if)i(y)n+(ou)e(got)g(the)739 4998 y(rep)r(ository)18 b(originally)g(using)h+Fr(darcs)41 b(get)i(--partial)p Fx(\),)18 b(b)n(y)h(default)h+Fr(darcs)41 b(check)18 b Fx(will)p eop end+%%Page: 87 87+TeXDict begin 87 86 bop 291 282 a Fu(6.8.)63 b(MORE)27+b(AD)n(V)-9 b(ANCED)29 b(COMMANDS)1283 b Fx(87)291 515+y(only)27 b(v)n(erify)h(the)g(con)n(ten)n(ts)g(since)f(the)i(most)f+(recen)n(t)f(c)n(hec)n(kp)r(oin)n(t.)38 b(Y)-7 b(ou)28+b(can)g(c)n(hange)f(this)291 615 y(b)r(eha)n(vior)f(using)h(the)h+Fr(--complete)c Fx(\015ag.)415 716 y(If)30 b(y)n(ou)f(lik)n(e,)h(y)n+(ou)f(can)g(con\014gure)g(y)n(our)f(rep)r(ository)g(to)i(b)r(e)g(able)f+(to)h(run)f(a)h(test)g(suite)291 816 y(of)c(some)g(sort.)35+b(Y)-7 b(ou)27 b(can)f(do)g(this)h(b)n(y)f(using)g(\\setpref)6+b(")26 b(to)g(set)g(the)h(\\test")f(v)-5 b(alue)26 b(to)h(b)r(e)f(a)291+916 y(command)h(to)g(run,)h(e.g.)291 1089 y Fr(\045)43+b(darcs)e(setpref)g(test)h("sh)g(configure)e(&&)j(make)f(&&)h(make)e+(test")291 1260 y Fx(Or,)25 b(if)i(y)n(ou)e(w)n(an)n(t)g(to)h(de\014ne)+g(a)g(test)g(sp)r(eci\014c)g(to)g(one)g(cop)n(y)f(of)h(the)g(rep)r+(ository)-7 b(,)25 b(y)n(ou)g(could)291 1360 y(do)i(this)h(b)n(y)f+(editing)h(the)g(\014le)g Fr(_darcs/prefs/pr)o(efs)o+Fx(.)p 527 1550 2392 4 v 527 1624 a Fr(--leave-test-dir)o(ec)o(tor)o+(y,)37 b(--remove-test-di)o(re)o(cto)o(ry)p 527 1679+V 415 1869 a Fx(Normally)30 b(darcs)g(deletes)g(the)i(directory)d(in)i+(whic)n(h)g(the)g(test)g(w)n(as)f(run)h(afterw)n(ards.)291+1969 y(Sometimes)c(\(esp)r(ecially)g(when)h(the)g(test)f(fails\))h(y)n+(ou'd)f(prefer)g(to)g(b)r(e)h(able)f(to)g(b)r(e)h(able)f(to)291+2068 y(examine)19 b(the)i(test)g(directory)e(after)h(the)g(test)h(is)f+(run.)34 b(Y)-7 b(ou)21 b(can)f(do)g(this)g(b)n(y)g(sp)r(ecifying)h+(the)291 2168 y Fr(--leave-test-di)o(rec)o(to)o(ry)j+Fx(\015ag.)46 b(Alas,)31 b(there)g(is)g(no)f(w)n(a)n(y)g(to)g(mak)n(e)g+(darcs)g(lea)n(v)n(e)g(the)291 2268 y(test)22 b(directory)f(only)g(if)i+(the)f(test)g(fails.)35 b(The)22 b(opp)r(osite)g(of)g+Fr(--leave-test-dir)o(ect)o(or)o(y)16 b Fx(is)291 2367+y Fr(--remove-test-d)o(ire)o(ct)o(or)o(y)p Fx(,)22 b(whic)n(h)28+b(could)g(come)g(in)g(handy)g(if)h(y)n(ou)e(c)n(ho)r(ose)g(to)h(mak)n+(e)291 2467 y Fr(--leave-test-di)o(rec)o(to)o(ry)21 b+Fx(the)28 b(default)g(\(see)g(section)f(4.1\).)p 527+2657 V 527 2731 a Fr(--no-test)p 527 2768 V 415 2958+a Fx(If)e(y)n(ou)e(just)i(w)n(an)n(t)f(to)g(c)n(hec)n(k)f(the)i+(consistency)f(of)g(y)n(our)f(rep)r(ository)g(without)h(running)291+3057 y(the)k(test,)g(y)n(ou)e(can)i(call)f(darcs)f(c)n(hec)n(k)h(with)h+(the)g Fr(--no-test)c Fx(option.)291 3299 y Fk(6.8.4)112+b(darcs)38 b(optimize)291 3456 y Fr(Usage:)j(darcs)g(optimize)f+([OPTION]...)415 3557 y Fx(Options:)652 3653 y Fr(--checkpoint)399+b Fx(create)27 b(a)g(c)n(hec)n(kp)r(oin)n(t)g(\014le)h(\(see)f(get)h+({partial\))465 3753 y Fr(-t)99 b(--tag)41 b(TAGNAME)358+b Fx(name)28 b(of)f(v)n(ersion)f(to)i(c)n(hec)n(kp)r(oin)n(t)652+3882 y Fr(--repodir)40 b(DIRECTORY)1579 3840 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)h(in)h(whic)n(h)f(to)1579+3940 y(run)652 4010 y Fr(--reorder-patche)o(s)180 b Fx(reorder)26+b(the)i(patc)n(hes)f(in)h(the)g(rep)r(ository)652 4109+y Fr(--sibling)40 b(URL)359 b Fx(sp)r(ecify)28 b(a)g(sibling)f+(directory)652 4209 y Fr(--relink)575 b Fx(relink)28+b(random)e(in)n(ternal)h(data)g(to)h(a)f(sibling)652+4309 y Fr(--relink-pristin)o(e)180 b Fx(relink)28 b(pristine)f(tree)g+(\(not)h(recommended\))415 4406 y(Adv)-5 b(anced)28 b(options:)565+4502 y Fr(--compress)313 b Fx(create)27 b(compressed)f(patc)n(hes)565+4602 y Fr(--dont-compress)93 b Fx(don't)28 b(create)e(compressed)h+(patc)n(hes)565 4702 y Fr(--uncompress)225 b Fx(uncompress)27+b(patc)n(hes)565 4801 y Fr(--umask)40 b(UMASK)185 b Fx(sp)r(ecify)28+b(umask)f(to)g(use)h(when)g(writing)415 4899 y(Optimize)19+b(can)f(help)h(to)g(impro)n(v)n(e)f(the)h(p)r(erformance)e(of)i(y)n+(our)f(rep)r(ository)f(in)i(a)f(n)n(um)n(b)r(er)291 4998+y(of)27 b(cases.)p eop end+%%Page: 88 88+TeXDict begin 88 87 bop 739 282 a Fx(88)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(Optimize)38+b(alw)n(a)n(ys)e(writes)i(out)g(a)f(fresh)h(cop)n(y)f(of)g(the)i(in)n+(v)n(en)n(tory)d(that)i(minimizes)739 615 y(the)33 b(amoun)n(t)f(of)h+(in)n(v)n(en)n(tory)e(that)i(need)g(b)r(e)g(do)n(wnloaded)f(when)g(p)r+(eople)h(pull)g(from)g(the)739 715 y(rep)r(ository)-7+b(.)863 814 y(Sp)r(eci\014cally)g(,)29 b(it)g(breaks)d(up)j(the)f(in)n+(v)n(en)n(tory)f(on)h(the)g(most)g(recen)n(t)g(tag.)38+b(This)28 b(sp)r(eeds)739 914 y(up)f(most)g(commands)g(when)g(run)g+(remotely)-7 b(,)27 b(b)r(oth)h(b)r(ecause)e(a)h(smaller)f(\014le)i+(needs)f(to)g(b)r(e)739 1013 y(transfered)k(\(only)g(the)h(most)g+(recen)n(t)f(in)n(v)n(en)n(tory\).)47 b(It)32 b(also)f(giv)n(es)f(a)i+(guaran)n(tee)e(that)i(all)739 1113 y(the)f(patc)n(hes)f(prior)f(to)i+(a)f(giv)n(en)g(tag)g(are)g(included)h(in)g(that)g(tag,)g(so)f(less)g+(comm)n(utation)739 1213 y(and)c(history)f(tra)n(v)n(ersal)e(is)j+(needed.)37 b(This)26 b(latter)f(issue)h(can)g(b)r(ecome)f(v)n(ery)g+(imp)r(ortan)n(t)h(in)739 1312 y(large)g(rep)r(ositories.)p+975 1483 2392 4 v 975 1558 a Fr(--checkpoint,)38 b(--tag)p+975 1613 V 863 1783 a Fx(If)25 b(y)n(ou)d(use)i(the)g+Fr(--checkpoint)19 b Fx(option,)24 b(optimize)g(creates)e(a)i(c)n(hec)n+(kp)r(oin)n(t)e(patc)n(h)i(for)739 1883 y(a)29 b(tag.)43+b(Y)-7 b(ou)30 b(can)f(sp)r(ecify)i(the)f(tag)f(with)h(the)g+Fr(--tag)e Fx(option,)i(or)f(just)i(let)f(darcs)e(c)n(ho)r(ose)739+1983 y(the)i(most)g(recen)n(t)g(tag.)44 b(Note)30 b(that)h(optimize)f+Fr(--checkpoint)25 b Fx(will)31 b(fail)f(when)g(used)h(on)739+2082 y(a)k(\\partial")e(rep)r(ository)-7 b(.)59 b(Also,)37+b(the)e(tag)g(that)h(is)f(to)g(b)r(e)h(c)n(hec)n(kp)r(oin)n(ted)e(m)n+(ust)i(not)f(b)r(e)739 2182 y(preceded)29 b(b)n(y)h(an)n(y)f(patc)n+(hes)g(that)h(are)f(not)h(included)g(in)g(that)g(tag.)43+b(If)30 b(that)g(is)g(the)g(case,)739 2282 y(no)d(c)n(hec)n(kp)r(oin)n+(ting)g(is)g(done.)863 2381 y(The)36 b(created)f(c)n(hec)n(kp)r(oin)n+(t)f(is)i(used)f(b)n(y)h(the)f Fr(--partial)d Fx(\015ag)j(to)g+Fr(get)g Fx(and)g Fr(check)p Fx(.)739 2481 y(This)28+b(allo)n(ws)e(for)h(users)g(to)h(retriev)n(e)e(a)i(w)n(orking)e(rep)r+(ository)g(with)i(limited)h(history)e(with)739 2580 y(a)g(sa)n(vings)f+(of)i(disk)f(space)g(and)g(bandwidth.)p 975 2751 V 975+2826 a Fr(--compress,)39 b(--dont-compress,)e(--uncompress)p+975 2881 V 863 3051 a Fx(Some)19 b(compression)d(options)i(are)g(a)n(v)+-5 b(ailable,)19 b(and)f(are)f(indep)r(enden)n(t)i(of)g(the)f+Fr(--checkpoint)739 3151 y Fx(option.)863 3251 y(By)38+b(default)h(the)f(patc)n(hes)g(in)g(the)h(rep)r(ository)d(are)i+(compressed.)67 b(These)38 b(use)g(less)739 3350 y(disk)e(space,)h+(whic)n(h)g(translates)d(in)n(to)i(less)g(bandwidth)h(if)f(the)h(rep)r+(ository)d(is)i(accessed)739 3450 y(remotely)-7 b(.)863+3550 y(Note)28 b(that)f(in)h(the)g(darcs-1.0)d(\(also)h(kno)n(wn)h(as)f+(\\old)h(fashioned)g(in)n(v)n(en)n(tory"\))e(rep)r(os-)739+3649 y(itory)37 b(format,)k(patc)n(hes)c(will)i(alw)n(a)n(ys)d(ha)n(v)n+(e)h(the)i(\\.gz")e(extension)h(whether)g(they)g(are)739+3749 y(compressed)26 b(or)h(not.)863 3848 y(Y)-7 b(ou)22+b(ma)n(y)e(w)n(an)n(t)h(to)g(uncompress)f(the)i(patc)n(hes)e(when)i(y)n+(ou'v)n(e)e(got)g(enough)h(disk)g(space)739 3948 y(but)28+b(are)f(running)g(out)h(of)f(ph)n(ysical)g(memory)-7+b(.)863 4048 y(If)34 b(y)n(ou)e(giv)n(e)h(the)g Fr(--compress)c+Fx(option,)35 b(optimize)e(will)g(compress)f(all)h(the)h(patc)n(hes)739+4147 y(in)i(the)g(rep)r(ository)-7 b(.)61 b(Similarly)-7+b(,)37 b(if)g(y)n(ou)e(giv)n(e)g(the)h Fr(--uncompress)p+Fx(,)d(optimize)j(will)g(de-)739 4247 y(compress)i(all)h(the)g(patc)n+(hes)g(in)g(the)h(rep)r(ository)-7 b(.)70 b Fr(--dont-compress)33+b Fx(means)39 b(\\don't)739 4347 y(compress,)29 b(but)h(don't)g+(uncompress)f(either".)43 b(It)30 b(w)n(ould)g(b)r(e)g(useful)g(if)g+(one)g(of)g(the)g(com-)739 4446 y(pression)c(options)h(w)n(as)g(pro)n+(vided)f(as)h(a)h(default)g(and)f(y)n(ou)g(w)n(an)n(ted)g(to)g(o)n(v)n+(erride)f(it.)p 975 4617 V 975 4692 a Fr(--relink)p 975+4728 V 863 4899 a Fx(The)33 b Fr(--relink)c Fx(and)j+Fr(--relink-pristin)o(e)26 b Fx(options)32 b(cause)f(Darcs)g(to)i+(relink)e(\014les)739 4998 y(from)c(a)g(sibling.)37 b(See)28+b(Section)f(3.6.)p eop end+%%Page: 89 89+TeXDict begin 89 88 bop 291 282 a Fu(6.9.)63 b(UNDOING,)29+b(REDOING)f(AND)g(R)n(UNNING)h(IN)f(CIR)n(CLES)566 b+Fx(89)p 527 515 2392 4 v 527 590 a Fr(--reorder-patche)o(s)p+527 645 V 415 808 a Fx(The)36 b Fr(--reorder-patch)o(es)29+b Fx(option)35 b(causes)f(Darcs)h(to)g(create)f(an)h(optimal)h(order-)+291 908 y(ing)29 b(of)g(its)h(in)n(ternal)e(patc)n(h)i(in)n(v)n(en)n+(tory)-7 b(.)40 b(This)30 b(ma)n(y)e(help)i(to)f(pro)r(duce)g(shorter)f+(`con)n(text')291 1008 y(lists)k(when)h(sending)f(patc)n(hes,)h(and)f+(ma)n(y)g(impro)n(v)n(e)f(p)r(erformance)g(for)h(some)g(other)g(op-)291+1107 y(erations)26 b(as)h(w)n(ell.)36 b(Y)-7 b(ou)28+b(should)f(not)g(run)h Fr(--reorder-patch)o(es)21 b Fx(on)27+b(a)g(rep)r(ository)f(from)291 1207 y(whic)n(h)j(someone)f(ma)n(y)h(b)r+(e)g(sim)n(ultaneously)g(pulling)g(or)f(getting,)i(as)e(this)i(could)f+(lead)g(to)291 1307 y(rep)r(ository)d(corruption.)291+1578 y Fq(6.9)135 b(Undoing,)45 b(redoing)h(and)f(running)f(in)h+(circles)291 1776 y Fk(6.9.1)112 b(darcs)38 b(amend-record)291+1929 y Fr(Usage:)j(darcs)g(amend-record)e([OPTION]...)g([FILE)i(or)i+(DIRECTORY]...)415 2029 y Fx(Options:)652 2123 y Fr(--match)d(PATTERN)+446 b Fx(select)27 b(a)g(single)h(patc)n(h)f(matc)n(hing)g(P)-7+b(A)g(TTERN)465 2223 y Fr(-p)99 b(--patch)40 b(REGEXP)490+b Fx(select)27 b(a)g(single)h(patc)n(h)f(matc)n(hing)g(REGEXP)652+2323 y Fr(--no-test)706 b Fx(don't)28 b(run)f(the)h(test)g(script)652+2422 y Fr(--test)838 b Fx(run)27 b(the)h(test)g(script)652+2522 y Fr(--leave-test-dir)o(ec)o(to)o(ry)137 b Fx(don't)28+b(remo)n(v)n(e)e(the)h(test)h(directory)652 2621 y Fr(--remove-test-di)+o(re)o(ct)o(ory)93 b Fx(remo)n(v)n(e)26 b(the)i(test)g(directory)465+2721 y Fr(-a)99 b(--all)882 b Fx(answ)n(er)26 b(y)n(es)h(to)g(all)h+(patc)n(hes)465 2821 y Fr(-i)99 b(--interactive)530 b+Fx(prompt)27 b(user)g(in)n(teractiv)n(ely)465 2920 y+Fr(-A)99 b(--author)40 b(EMAIL)490 b Fx(sp)r(ecify)28+b(author)e(id)465 3020 y Fr(-m)99 b(--patch-name)38 b(PATCHNAME)140+b Fx(name)27 b(of)h(patc)n(h)652 3120 y Fr(--edit-long-comm)o(en)o(t)+268 b Fx(edit)28 b(the)g(long)f(commen)n(t)g(b)n(y)h(default)652+3219 y Fr(--skip-long-comm)o(en)o(t)268 b Fx(don't)28+b(giv)n(e)e(a)h(long)g(commen)n(t)652 3319 y Fr(--prompt-long-co)o(mm)o+(en)o(t)181 b Fx(prompt)26 b(for)g(whether)h(to)f(edit)h(the)g(long)f+(commen)n(t)465 3450 y Fr(-l)99 b(--look-for-adds)1754+3411 y Fx(lo)r(ok)27 b(for)g(\(non-b)r(oring\))g(\014les)g(that)h+(could)f(b)r(e)1754 3511 y(added)652 3620 y Fr(--dont-look-for-)o(ad)o+(ds)1754 3568 y Fx(don't)h(lo)r(ok)e(for)i(an)n(y)e(\014les)i(that)g+(could)f(b)r(e)h(added)1754 3668 y([DEF)-9 b(A)n(UL)i(T])652+3788 y Fr(--repodir)40 b(DIRECTORY)1754 3746 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)f(to)1754+3846 y(run)415 3912 y(Adv)-5 b(anced)28 b(options:)565+4006 y Fr(--compress)313 b Fx(create)27 b(compressed)f(patc)n(hes)565+4106 y Fr(--dont-compress)93 b Fx(don't)28 b(create)e(compressed)h+(patc)n(hes)565 4205 y Fr(--ignore-times)1318 4213 y+Fx(don't)h(trust)f(the)h(\014le)g(mo)r(di\014cation)g(times)565+4305 y Fr(--umask)40 b(UMASK)185 b Fx(sp)r(ecify)28 b(umask)f(to)g(use)+h(when)g(writing)415 4401 y(Amend-record)19 b(is)h(used)h(to)f(replace)+f(a)h(patc)n(h)g(with)h(a)f(new)n(er)f(v)n(ersion)g(with)h(additional)+291 4500 y(c)n(hanges.)415 4600 y(W)-9 b(ARNINGS:)36+b(Y)-7 b(ou)34 b(should)f(ONL)-7 b(Y)34 b(use)g(amend-record)e(on)i+(patc)n(hes)f(whic)n(h)h(only)291 4700 y(exist)d(in)h(a)f(single)g(rep)+r(ository!)46 b(Also,)32 b(running)g(amend-record)d(while)j(another)e+(user)h(is)291 4799 y(pulling)c(from)h(the)g(same)f(rep)r(ository)f(ma)+n(y)g(cause)h(rep)r(ository)f(corruption.)415 4899 y(If)36+b(y)n(ou)g(pro)n(vide)e(one)i(or)f(more)g(\014les)h(or)f(directories)g+(as)g(additional)g(argumen)n(ts)g(to)291 4998 y(amend-record,)21+b(y)n(ou)i(will)g(only)f(b)r(e)h(prompted)g(to)g(c)n(hanges)e(in)i+(those)g(\014les)f(or)g(directories.)p eop end+%%Page: 90 90+TeXDict begin 90 89 bop 739 282 a Fx(90)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(The)37+b(old)g(v)n(ersion)e(of)h(the)i(patc)n(h)e(is)h(lost)f(and)h(the)g(new)+f(patc)n(h)h(will)g(include)g(b)r(oth)739 615 y(the)32+b(old)f(and)g(the)h(new)f(c)n(hanges.)47 b(This)32 b(is)f(mostly)g(the)+h(same)f(as)g(unrecording)f(the)h(old)739 715 y(patc)n(h,)g(\014xing)g+(the)h(c)n(hanges)d(and)i(recording)e(a)i(new)g(patc)n(h)f(with)i(the)f+(same)g(name)f(and)739 814 y(description.)863 919 y Fr(amend-record)23+b Fx(will)28 b(mo)r(dify)g(the)g(date)f(of)h(the)g(recorded)e(patc)n+(h.)863 1023 y(If)38 b(y)n(ou)e(con\014gure)f(darcs)h(to)g(run)h(a)f+(test)h(suite,)i(darcs)d(will)h(run)f(this)h(test)g(on)g(the)739+1123 y(amended)28 b(rep)r(ository)e(to)i(mak)n(e)g(sure)f(it)i(is)f(v)+-5 b(alid.)38 b(Darcs)28 b(\014rst)f(creates)g(a)h(pristine)g(cop)n(y)+739 1222 y(of)34 b(the)i(source)d(tree)h(\(in)h(a)g(temp)r(orary)e+(directory\),)j(then)f(it)g(runs)f(the)h(test,)i(using)d(its)739+1322 y(return)27 b(v)-5 b(alue)28 b(to)f(decide)h(if)g(the)g(amended)f+(c)n(hange)g(is)g(v)-5 b(alid.)739 1579 y Fk(6.9.2)112+b(darcs)38 b(rollbac)m(k)739 1741 y Fr(Usage:)j(darcs)h(rollback)e+([OPTION]...)f([FILE)i(or)i(DIRECTORY]...)863 1846 y+Fx(Options:)1100 1983 y Fr(--from-match)c(PATTERN)2202+1933 y Fx(select)28 b(c)n(hanges)e(starting)h(with)h(a)f(patc)n(h)2202+2032 y(matc)n(hing)g(P)-7 b(A)g(TTERN)1100 2156 y Fr(--from-patch)39+b(REGEXP)2202 2106 y Fx(select)28 b(c)n(hanges)e(starting)h(with)h(a)f+(patc)n(h)2202 2206 y(matc)n(hing)g(REGEXP)1100 2321+y Fr(--from-tag)39 b(REGEXP)2202 2280 y Fx(select)28+b(c)n(hanges)e(starting)h(with)h(a)f(tag)g(matc)n(hing)2202+2379 y(REGEXP)1100 2449 y Fr(--last)41 b(NUMBER)533 b+Fx(select)28 b(the)g(last)f(NUMBER)h(patc)n(hes)1100+2549 y Fr(--matches)40 b(PATTERN)358 b Fx(select)28 b(patc)n(hes)f+(matc)n(hing)g(P)-7 b(A)g(TTERN)913 2648 y Fr(-p)99 b(--patches)40+b(REGEXP)402 b Fx(select)28 b(patc)n(hes)f(matc)n(hing)g(REGEXP)913+2748 y Fr(-t)99 b(--tags)41 b(REGEXP)533 b Fx(select)28+b(tags)e(matc)n(hing)h(REGEXP)913 2847 y Fr(-a)99 b(--all)882+b Fx(answ)n(er)26 b(y)n(es)h(to)h(all)f(patc)n(hes)913+2947 y Fr(-i)99 b(--interactive)530 b Fx(prompt)28 b(user)f(in)n+(teractiv)n(ely)913 3047 y Fr(-A)99 b(--author)40 b(EMAIL)490+b Fx(sp)r(ecify)28 b(author)f(id)913 3146 y Fr(-m)99+b(--patch-name)39 b(PATCHNAME)139 b Fx(name)28 b(of)f(patc)n(h)1100+3246 y Fr(--edit-long-comm)o(ent)267 b Fx(edit)28 b(the)g(long)f+(commen)n(t)h(b)n(y)f(default)1100 3346 y Fr(--skip-long-comm)o(ent)267+b Fx(don't)28 b(giv)n(e)f(a)g(long)g(commen)n(t)1100+3445 y Fr(--prompt-long-co)o(mme)o(nt)180 b Fx(prompt)26+b(for)g(whether)h(to)f(edit)h(the)g(long)f(commen)n(t)1100+3545 y Fr(--no-test)706 b Fx(don't)28 b(run)f(the)h(test)g(script)1100+3644 y Fr(--test)838 b Fx(run)28 b(the)g(test)f(script)1100+3744 y Fr(--leave-test-dir)o(ect)o(or)o(y)137 b Fx(don't)28+b(remo)n(v)n(e)e(the)i(test)g(directory)1100 3844 y Fr+(--remove-test-di)o(rec)o(to)o(ry)93 b Fx(remo)n(v)n(e)26+b(the)i(test)g(directory)1100 3973 y Fr(--repodir)40+b(DIRECTORY)2202 3931 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e+(directory)g(in)i(whic)n(h)g(to)2202 4031 y(run)863 4102+y(Adv)-5 b(anced)28 b(options:)1013 4201 y Fr(--compress)313+b Fx(create)27 b(compressed)f(patc)n(hes)1013 4300 y+Fr(--dont-compress)93 b Fx(don't)28 b(create)f(compressed)f(patc)n(hes)+1013 4400 y Fr(--umask)41 b(UMASK)184 b Fx(sp)r(ecify)28+b(umask)f(to)h(use)f(when)h(writing)863 4500 y(Rollbac)n(k)d(is)g(used)+g(to)g(undo)g(the)h(e\013ects)f(of)g(one)g(or)f(more)h(patc)n(hes)f+(without)i(actually)739 4600 y(deleting)32 b(them.)53+b(Instead,)33 b(it)g(creates)f(a)g(new)g(patc)n(h)h(rev)n(ersing)d+(selected)i(p)r(ortions.)51 b(of)739 4700 y(those)22+b(c)n(hanges.)33 b(Unlik)n(e)22 b(obliterate)g(and)g(unrecord)f(\(whic)+n(h)h(accomplish)f(a)h(similar)f(goal\))739 4799 y(rollbac)n(k)h(is)h+(p)r(erfectly)h(safe,)f(since)h(it)g(lea)n(v)n(es)d(in)j(the)g(rep)r+(ository)e(a)h(record)f(of)h(its)h(c)n(hanges.)739 4899+y(If)29 b(y)n(ou)f(decide)g(y)n(ou)g(didn't)i(w)n(an)n(t)e(to)g(roll)g+(bac)n(k)g(a)g(patc)n(h)g(after)h(all,)f(y)n(ou)g(can)g(rev)n(erse)f+(its)739 4998 y(e\013ect)h(b)n(y)f(obliterating)g(the)h(rolled-bac)n(k)+d(patc)n(h.)p eop end+%%Page: 91 91+TeXDict begin 91 90 bop 291 282 a Fu(6.9.)63 b(UNDOING,)29+b(REDOING)f(AND)g(R)n(UNNING)h(IN)f(CIR)n(CLES)566 b+Fx(91)415 515 y(Rollbac)n(k)22 b(can)h(actually)f(allo)n(w)g(y)n(ou)h+(to)g(roll)f(bac)n(k)g(a)h(subset)g(of)g(the)h(c)n(hanges)d(made)i(b)n+(y)291 615 y(the)k(selected)f(patc)n(h)g(or)g(patc)n(hes.)36+b(Man)n(y)26 b(of)h(the)g(options)f(a)n(v)-5 b(ailable)25+b(in)i(rollbac)n(k)e(b)r(eha)n(v)n(e)291 715 y(similarly)h(to)i(the)g+(options)f(for)g(unrecord)f(6.9.3)h(and)g(record)f(6.6.1.)291+958 y Fk(6.9.3)112 b(darcs)38 b(unrecord)291 1116 y Fr(Usage:)j(darcs)g+(unrecord)f([OPTION]...)415 1217 y Fx(Options:)652 1351+y Fr(--from-match)e(PATTERN)1623 1302 y Fx(select)28+b(c)n(hanges)e(starting)g(with)j(a)e(patc)n(h)1623 1401+y(matc)n(hing)g(P)-7 b(A)g(TTERN)652 1525 y Fr(--from-patch)38+b(REGEXP)1623 1475 y Fx(select)28 b(c)n(hanges)e(starting)g(with)j(a)e+(patc)n(h)1623 1575 y(matc)n(hing)g(REGEXP)652 1690 y+Fr(--from-tag)39 b(REGEXP)1623 1649 y Fx(select)28 b(c)n(hanges)e+(starting)g(with)j(a)e(tag)g(matc)n(hing)1623 1748 y(REGEXP)652+1818 y Fr(--last)41 b(NUMBER)402 b Fx(select)28 b(the)g(last)f(NUMBER)h+(patc)n(hes)652 1917 y Fr(--matches)40 b(PATTERN)227+b Fx(select)28 b(patc)n(hes)e(matc)n(hing)i(P)-7 b(A)g(TTERN)465+2017 y Fr(-p)99 b(--patches)40 b(REGEXP)271 b Fx(select)28+b(patc)n(hes)e(matc)n(hing)i(REGEXP)465 2117 y Fr(-t)99+b(--tags)41 b(REGEXP)402 b Fx(select)28 b(tags)e(matc)n(hing)h(REGEXP)+652 2216 y Fr(--no-deps)575 b Fx(don't)28 b(automatically)e(ful\014ll)j+(dep)r(endencies)465 2316 y Fr(-a)99 b(--all)751 b Fx(answ)n(er)26+b(y)n(es)h(to)h(all)f(patc)n(hes)465 2416 y Fr(-i)99+b(--interactive)399 b Fx(prompt)27 b(user)g(in)n(teractiv)n(ely)652+2545 y Fr(--repodir)40 b(DIRECTORY)1623 2503 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)g(to)1623+2603 y(run)415 2671 y(Adv)-5 b(anced)28 b(options:)565+2767 y Fr(--compress)313 b Fx(create)27 b(compressed)f(patc)n(hes)565+2867 y Fr(--dont-compress)93 b Fx(don't)28 b(create)e(compressed)h+(patc)n(hes)565 2966 y Fr(--umask)40 b(UMASK)185 b Fx(sp)r(ecify)28+b(umask)f(to)g(use)h(when)g(writing)415 3064 y(Unrecord)38+b(do)r(es)h(the)h(opp)r(osite)f(of)g(record)f(in)h(that)h(it)g(mak)n+(es)e(the)h(c)n(hanges)f(from)291 3164 y(patc)n(hes)22+b(activ)n(e)g(c)n(hanges)f(again)g(whic)n(h)i(y)n(ou)f(ma)n(y)g(record)+f(or)h(rev)n(ert)f(later.)35 b(The)23 b(w)n(orking)291+3264 y(cop)n(y)j(itself)i(will)g(not)g(c)n(hange.)415+3366 y(Unrecord)33 b(can)h(b)r(e)g(though)n(t)g(of)g(as)f(undo-record.)+55 b(If)34 b(a)g(record)e(is)i(follo)n(w)n(ed)f(b)n(y)h(an)291+3465 y(unrecord,)26 b(ev)n(erything)f(lo)r(oks)i(lik)n(e)f(b)r(efore)h+(the)g(record;)f(all)h(the)g(previously)f(unrecorded)291+3565 y(c)n(hanges)j(are)g(bac)n(k,)i(and)g(can)f(b)r(e)h(recorded)e+(again)h(in)h(a)f(new)h(patc)n(h.)45 b(The)31 b(unrecorded)291+3664 y(patc)n(h)f(ho)n(w)n(ev)n(er)e(is)i(actually)g(remo)n(v)n(ed)f+(from)h(y)n(our)g(rep)r(ository)-7 b(,)29 b(so)h(there)g(is)h(no)f(w)n+(a)n(y)f(to)291 3764 y(record)d(it)i(again)e(to)i(get)f(it)h(bac)n(k.)+1362 3734 y Fm(6)1398 3764 y Fx(.)415 3866 y(If)j(y)n(ou)f(w)n(an)n(t)g+(to)g(remo)n(v)n(e)f(the)i(c)n(hanges)e(from)h(the)h(w)n(orking)e(cop)n+(y)g(to)r(o)h(\(where)h(they)291 3965 y(otherwise)17+b(will)i(sho)n(w)e(up)i(as)f(unrecorded)f(c)n(hanges)g(again\),)i(y)n+(ou'll)f(also)f(need)i(to)f Fr(darcs)41 b(revert)p Fx(.)291+4065 y(T)-7 b(o)27 b(do)g(unrecord)f(and)i(rev)n(ert)e(in)i(one)f(go,)g+(y)n(ou)g(can)g(use)h Fr(darcs)41 b(obliterate)p Fx(.)415+4167 y(If)e(y)n(ou)e(don't)h(rev)n(ert)f(after)g(unrecording,)i(then)g+(the)f(c)n(hanges)f(made)h(b)n(y)g(the)g(un-)291 4266+y(recorded)d(patc)n(hes)h(are)f(left)j(in)e(y)n(our)g(w)n(orking)f+(tree.)63 b(If)37 b(these)g(patc)n(hes)f(are)g(actually)291+4366 y(from)c(another)g(rep)r(ository)-7 b(,)33 b(in)n(teraction)f+(\(either)i(pushes)e(or)h(pulls\))g(with)h(that)f(rep)r(osi-)291+4466 y(tory)e(ma)n(y)h(b)r(e)h(massiv)n(ely)e(slo)n(w)n(ed)h(do)n(wn,)h+(as)f(darcs)f(tries)h(to)h(cop)r(e)f(with)h(the)g(fact)g(that)291+4565 y(y)n(ou)h(app)r(ear)f(to)i(ha)n(v)n(e)f(made)g(a)g(large)g(n)n+(um)n(b)r(er)g(of)h(c)n(hanges)e(that)i(con\015ict)g(with)g(those)291+4665 y(presen)n(t)23 b(in)h(the)g(other)f(rep)r(ository)-7+b(.)34 b(So)23 b(if)h(y)n(ou)f(really)g(w)n(an)n(t)g(to)g(undo)h(the)g+(result)f(of)h(a)f Fs(pul)t(l)291 4765 y Fx(op)r(eration,)31+b(use)g(obliterate!)47 b(Unrecord)30 b(is)i(primarily)e(in)n(tended)i+(for)e(when)i(y)n(ou)e(record)p 291 4842 1146 4 v 383+4896 a Fp(6)418 4920 y Fl(The)22 b(patc)n(h)h(\014le)f(itself)f(is)g+(not)i(actually)f(deleted,)h(but)g(its)e(con)n(text)j(is)e(lost,)f(so)h+(it)g(cannot)h(b)r(e)f(reliably)291 4998 y(read|y)n(our)h(only)h(c)n+(hoice)h(w)n(ould)f(b)r(e)g(to)g(go)g(in)f(b)n(y)h(hand)h(and)f(read)g+(its)f(con)n(ten)n(ts.)p eop end+%%Page: 92 92+TeXDict begin 92 91 bop 739 282 a Fx(92)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)739 515 y Fx(a)36+b(patc)n(h,)j(realize)c(it)i(needs)f(just)i(one)e(more)f(c)n(hange,)j+(but)f(w)n(ould)f(rather)g(not)g(ha)n(v)n(e)g(a)739 615+y(separate)26 b(patc)n(h)h(for)g(just)i(that)f(one)f(c)n(hange.)863+715 y Fv(W)-11 b(ARNING:)29 b Fx(Unrecord)g(should)h(not)g(b)r(e)g(run)+g(when)g(there)f(is)h(a)f(p)r(ossibilit)n(y)h(that)739+814 y(another)k(user)h(ma)n(y)g(b)r(e)h(pulling)f(from)h(the)f(same)g+(rep)r(ository)-7 b(.)59 b(A)n(ttempting)36 b(to)g(do)f(so)739+914 y(ma)n(y)27 b(cause)g(rep)r(ository)f(corruption.)p+975 1090 2392 4 v 975 1165 a Fr(--from-match,)38 b(--from-patch,)h+(--from-tag,)g(--last)p 975 1220 V 863 1396 a Fx(Usually)g(y)n(ou)f+(only)g(w)n(an)n(t)h(to)f(unrecord)g(the)h(latest)g(c)n(hanges,)h(and)f+(almost)f(nev)n(er)739 1495 y(w)n(ould)g(y)n(ou)g(w)n(an)n(t)h(to)f+(unrecord)g(c)n(hanges)f(b)r(efore)i(a)f(tag|y)n(ou)g(w)n(ould)g(ha)n+(v)n(e)g(to)g(ha)n(v)n(e)739 1595 y(unrecorded)27 b(the)i(tag)f(as)g(w)+n(ell)h(to)f(do)h(that.)40 b(Therefore,)28 b(and)g(for)g(e\016ciency)-7+b(,)29 b(darcs)f(only)739 1695 y(prompts)f(y)n(ou)g(for)g(the)h(latest)+f(patc)n(hes,)g(after)h(some)f(optimal)g(tag.)863 1794+y(If)35 b(y)n(ou)e(do)g(w)n(an)n(t)h(to)f(unrecord)g(more)g(patc)n(hes)+g(in)i(one)e(go,)i(there)e(are)g(the)i Fr(--from)739+1894 y Fx(and)27 b Fr(--last)f Fx(options)h(to)g(set)h(the)g(earliest)e+(patc)n(h)i(selectable)f(to)g(unrecord.)p 975 2070 V+975 2145 a Fr(--matches,)40 b(--patches,)f(--tags,)i(--no-deps)p+975 2200 V 863 2376 a Fx(The)25 b Fr(--patches)p Fx(,)c+Fr(--matches)p Fx(,)h Fr(--tags)p Fx(,)g(and)j Fr(--no-deps)20+b Fx(options)k(can)g(b)r(e)h(used)f(to)739 2475 y(select)j(whic)n(h)h+(patc)n(hes)f(to)g(unrecord,)g(as)g(describ)r(ed)g(in)h(subsection)f+(6.1.)863 2575 y(With)22 b(these)f(options)f(y)n(ou)g(can)g(sp)r(ecify)+h(what)f(patc)n(h)h(or)f(patc)n(hes)g(to)g(b)r(e)h(prompted)g(for)739+2674 y(b)n(y)27 b(unrecord.)36 b(This)28 b(is)g(esp)r(ecially)f(useful)+h(when)g(y)n(ou)f(w)n(an)n(t)g(to)g(unrecord)g(patc)n(hes)g(with)739+2774 y(dep)r(endencies,)j(since)g(all)f(the)h(dep)r(enden)n(t)h(patc)n+(hes)e(\(but)h(no)g(others\))f(will)h(b)r(e)g(included)739+2874 y(in)c(the)h(c)n(hoices.)35 b(Or)25 b(if)i(y)n(ou)e(use)h+Fr(--no-deps)c Fx(y)n(ou)j(w)n(on't)h(b)r(e)h(ask)n(ed)e(ab)r(out)h+(patc)n(hes)f(that)739 2973 y(can't)i(b)r(e)h(unrecorded)f(due)h(to)f+(dep)r(ending)h(patc)n(hes.)863 3073 y(Selecting)e(patc)n(hes)f(can)g+(b)r(e)h(slo)n(w,)f(so)g(darcs)f(cuts)i(the)g(searc)n(h)e(at)h(the)h+(last)f(optimized)739 3173 y(tag.)36 b(Use)28 b(the)g+Fr(--from)d Fx(or)i Fr(--last)e Fx(options)i(to)g(searc)n(h)f(more)h+(or)g(few)n(er)g(patc)n(hes.)739 3404 y Fk(6.9.4)112+b(darcs)38 b(obliterate)739 3557 y Fr(Usage:)j(darcs)h(obliterate)d+([OPTION]...)863 3657 y Fx(Options:)1100 3789 y Fr(--from-match)g+(PATTERN)2071 3739 y Fx(select)28 b(c)n(hanges)e(starting)h(with)h(a)f+(patc)n(h)2071 3838 y(matc)n(hing)g(P)-7 b(A)g(TTERN)1100+3962 y Fr(--from-patch)39 b(REGEXP)2071 3912 y Fx(select)28+b(c)n(hanges)e(starting)h(with)h(a)f(patc)n(h)2071 4012+y(matc)n(hing)g(REGEXP)1100 4127 y Fr(--from-tag)39 b(REGEXP)2071+4086 y Fx(select)28 b(c)n(hanges)e(starting)h(with)h(a)f(tag)g(matc)n+(hing)2071 4185 y(REGEXP)1100 4255 y Fr(--last)41 b(NUMBER)402+b Fx(select)28 b(the)g(last)f(NUMBER)h(patc)n(hes)1100+4355 y Fr(--matches)40 b(PATTERN)227 b Fx(select)28 b(patc)n(hes)f+(matc)n(hing)g(P)-7 b(A)g(TTERN)913 4454 y Fr(-p)99 b(--patches)40+b(REGEXP)271 b Fx(select)28 b(patc)n(hes)f(matc)n(hing)g(REGEXP)913+4554 y Fr(-t)99 b(--tags)41 b(REGEXP)402 b Fx(select)28+b(tags)f(matc)n(hing)g(REGEXP)1100 4654 y Fr(--no-deps)575+b Fx(don't)28 b(automatically)f(ful\014ll)h(dep)r(endencies)913+4753 y Fr(-a)99 b(--all)751 b Fx(answ)n(er)27 b(y)n(es)f(to)i(all)f+(patc)n(hes)913 4853 y Fr(-i)99 b(--interactive)399 b+Fx(prompt)28 b(user)f(in)n(teractiv)n(ely)1100 4982 y+Fr(--repodir)40 b(DIRECTORY)2071 4940 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)h(in)g(whic)n(h)h(to)2071+5040 y(run)p eop end+%%Page: 93 93+TeXDict begin 93 92 bop 291 282 a Fu(6.9.)63 b(UNDOING,)29+b(REDOING)f(AND)g(R)n(UNNING)h(IN)f(CIR)n(CLES)566 b+Fx(93)415 515 y(Adv)-5 b(anced)28 b(options:)565 610+y Fr(--compress)313 b Fx(create)27 b(compressed)f(patc)n(hes)565+710 y Fr(--dont-compress)93 b Fx(don't)28 b(create)e(compressed)h(patc)+n(hes)565 810 y Fr(--ignore-times)1318 818 y Fx(don't)h(trust)f(the)h+(\014le)g(mo)r(di\014cation)g(times)565 909 y Fr(--umask)40+b(UMASK)185 b Fx(sp)r(ecify)28 b(umask)f(to)g(use)h(when)g(writing)415+1006 y(Obliterate)g(completely)h(remo)n(v)n(es)e(recorded)h(patc)n(hes)+g(from)g(y)n(our)g(lo)r(cal)g(rep)r(ository)-7 b(.)291+1106 y(The)30 b(c)n(hanges)f(will)i(b)r(e)g(undone)f(in)h(y)n(our)e(w)n+(orking)g(cop)n(y)g(and)i(the)g(patc)n(hes)e(will)i(not)g(b)r(e)291+1205 y(sho)n(wn)24 b(in)h(y)n(our)e(c)n(hanges)h(list)h(an)n(ymore.)34+b(Bew)n(are)23 b(that)i(y)n(ou)f(can)h(lose)f(precious)g(co)r(de)g(b)n+(y)291 1305 y(obliterating!)415 1405 y(Obliterate)33+b(deletes)g(a)h(patc)n(h)f(from)g(the)h(rep)r(ository)e+Fs(and)43 b Fx(remo)n(v)n(es)31 b(those)i(c)n(hanges)291+1505 y(from)d(the)g(w)n(orking)f(directory)-7 b(.)44+b(It)30 b(is)h(therefore)e(a)h Fs(very)j(danger)l(ous)38+b Fx(command.)44 b(When)291 1605 y(there)31 b(are)g(no)g(lo)r(cal)g(c)n+(hanges,)g(obliterate)g(is)g(equiv)-5 b(alen)n(t)32 b(to)f(an)g+(unrecord)g(follo)n(w)n(ed)f(b)n(y)291 1704 y(a)i(rev)n(ert,)g(except)h+(that)f(rev)n(ert)g(can)g(b)r(e)h(unrev)n(erted.)50 b(In)33+b(the)g(case)e(of)i(tags,)g(obliterate)291 1804 y(remo)n(v)n(es)25+b(the)j(tag)f(itself,)h(not)g(an)n(y)f(other)g(patc)n(hes.)415+1904 y(Note)i(that)h(unpull)g(w)n(as)e(the)i(old)f(name)g(for)g+(obliterate.)41 b(Unpull)31 b(is)e(still)g(an)g(hidden)291+2004 y(alias)d(for)h(obliterate.)415 2105 y Fv(W)-11+b(ARNING:)26 b Fx(Obliterate)g(should)h(not)f(b)r(e)h(run)g(when)g+(there)f(is)h(a)f(p)r(ossibilit)n(y)h(that)291 2204 y(another)34+b(user)h(ma)n(y)g(b)r(e)g(pulling)h(from)f(the)h(same)f(rep)r(ository)+-7 b(.)59 b(A)n(ttempting)36 b(to)f(do)h(so)291 2304+y(ma)n(y)26 b(cause)h(rep)r(ository)f(corruption.)p 527+2490 2392 4 v 527 2565 a Fr(--from-match,)38 b(--from-patch,)g+(--from-tag,)h(--last)p 527 2620 V 415 2806 a Fx(Usually)d(y)n(ou)g+(only)g(w)n(an)n(t)g(to)g(obliterate)g(the)g(latest)h(c)n(hanges,)g+(and)f(almost)g(nev)n(er)291 2906 y(w)n(ould)g(y)n(ou)f(w)n(an)n(t)h+(to)h(obliterate)f(c)n(hanges)f(b)r(efore)h(a)g(tag|y)n(ou)f(w)n(ould)h+(ha)n(v)n(e)g(to)g(ha)n(v)n(e)291 3005 y(obliterated)28+b(the)i(tag)e(as)h(w)n(ell)g(to)g(do)g(that.)42 b(Therefore,)29+b(and)g(for)g(e\016ciency)-7 b(,)29 b(darcs)f(only)291+3105 y(prompts)f(y)n(ou)g(for)g(the)h(latest)f(patc)n(hes,)g(after)g+(some)g(optimal)h(tag.)415 3206 y(If)33 b(y)n(ou)e(do)g(w)n(an)n(t)h+(to)g(obliterate)f(more)g(patc)n(hes)g(in)h(one)g(go,)g(there)g(are)f+(the)h Fr(--from)291 3305 y Fx(and)27 b Fr(--last)e Fx(options)i(to)h+(set)f(the)h(earliest)f(patc)n(h)g(selectable)g(to)h(obliterate.)p+527 3491 V 527 3566 a Fr(--matches,)39 b(--patches,)h(--tags,)g+(--no-deps)p 527 3621 V 415 3807 a Fx(The)25 b Fr(--patches)p+Fx(,)c Fr(--matches)p Fx(,)g Fr(--tags)p Fx(,)i(and)h+Fr(--no-deps)d Fx(options)j(can)g(b)r(e)h(used)f(to)291+3907 y(select)j(whic)n(h)h(patc)n(hes)f(to)g(obliterate,)g(as)g+(describ)r(ed)g(in)h(subsection)f(6.1.)415 4008 y(With)22+b(these)e(options)g(y)n(ou)g(can)h(sp)r(ecify)g(what)f(patc)n(h)h(or)e+(patc)n(hes)h(to)h(b)r(e)g(prompted)f(for)291 4107 y(b)n(y)i+(obliterate.)35 b(This)23 b(is)f(esp)r(ecially)h(useful)g(when)g(y)n+(ou)f(w)n(an)n(t)g(to)h(obliterate)f(patc)n(hes)g(with)291+4207 y(dep)r(endencies,)30 b(since)g(all)f(the)h(dep)r(enden)n(t)g+(patc)n(hes)f(\(but)i(no)e(others\))g(will)h(b)r(e)g(included)291+4307 y(in)c(the)g(c)n(hoices.)36 b(Or)25 b(if)h(y)n(ou)g(use)f+Fr(--no-deps)e Fx(y)n(ou)i(w)n(on't)h(b)r(e)g(ask)n(ed)f(ab)r(out)h+(patc)n(hes)g(that)291 4406 y(can't)h(b)r(e)h(obliterated)f(due)h(to)f+(dep)r(ending)h(patc)n(hes.)415 4507 y(Selecting)e(patc)n(hes)e(can)i+(b)r(e)f(slo)n(w,)g(so)g(darcs)g(cuts)g(the)h(searc)n(h)e(at)i(the)f+(last)h(optimized)291 4606 y(tag.)36 b(Use)27 b(the)h+Fr(--from)e Fx(or)g Fr(--last)f Fx(options)j(to)f(searc)n(h)f(more)h+(or)g(few)n(er)g(patc)n(hes.)291 4844 y Fk(6.9.5)112+b(darcs)38 b(rev)m(ert)291 4998 y Fr(Usage:)j(darcs)g(revert)g+([OPTION]...)e([FILE)j(or)h(DIRECTORY]...)p eop end+%%Page: 94 94+TeXDict begin 94 93 bop 739 282 a Fx(94)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)863 515 y Fx(Options:)913+627 y Fr(-a)99 b(--all)708 b Fx(answ)n(er)26 b(y)n(es)h(to)g(all)h+(patc)n(hes)913 727 y Fr(-i)99 b(--interactive)356 b+Fx(prompt)27 b(user)g(in)n(teractiv)n(ely)1100 856 y+Fr(--repodir)40 b(DIRECTORY)2028 814 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)f(to)2028+914 y(run)863 997 y(Adv)-5 b(anced)28 b(options:)1013+1109 y Fr(--ignore-times)1723 1117 y Fx(don't)f(trust)h(the)g(\014le)g+(mo)r(di\014cation)f(times)1013 1209 y Fr(--umask)41+b(UMASK)141 b Fx(sp)r(ecify)28 b(umask)f(to)g(use)h(when)f(writing)863+1322 y(Rev)n(ert)32 b(is)g(used)g(to)g(undo)g(c)n(hanges)f(made)h(to)g+(the)g(w)n(orking)f(cop)n(y)g(whic)n(h)h(ha)n(v)n(e)f(not)739+1422 y(y)n(et)e(b)r(een)g(recorded.)39 b(Y)-7 b(ou)29+b(will)g(b)r(e)g(prompted)g(for)f(whic)n(h)h(c)n(hanges)f(y)n(ou)g+(wish)g(to)h(undo.)739 1521 y(The)22 b(last)h(rev)n(ert)e(can)h(b)r(e)h+(undone)f(safely)g(using)g(the)h(unrev)n(ert)e(command)h(if)h(the)g(w)n+(orking)739 1621 y(cop)n(y)e(w)n(as)g(not)h(mo)r(di\014ed)h(in)f(the)g+(mean)n(time.)35 b(The)23 b(actions)e(of)h(a)f(rev)n(ert)g(ma)n(y)h(b)r+(e)g(rev)n(ersed)739 1721 y(using)33 b(the)i(unrev)n(ert)d(command)i+(\(see)f(subsection)h(6.9.6\).)54 b(Ho)n(w)n(ev)n(er,)34+b(if)g(y)n(ou'v)n(e)e(made)739 1820 y(c)n(hanges)26 b(since)h(the)h+(rev)n(ert)f(y)n(our)f(mileage)h(ma)n(y)g(v)-5 b(ary)e(,)27+b(so)g(please)g(b)r(e)h(careful.)863 1937 y(Y)-7 b(ou)26+b(can)f(giv)n(e)f(rev)n(ert)g(optional)h(argumen)n(ts)f(indicating)h+(\014les)g(or)g(directories.)34 b(If)26 b(y)n(ou)739+2037 y(do)h(so)f(it)i(will)f(only)g(prompt)g(y)n(ou)f(to)h(rev)n(ert)f+(c)n(hanges)f(in)j(those)f(\014les)g(or)f(in)h(\014les)g(in)h(those)739+2137 y(directories.)739 2462 y Fk(6.9.6)112 b(darcs)38+b(unrev)m(ert)739 2648 y Fr(Usage:)j(darcs)h(unrevert)e([OPTION]...)863+2765 y Fx(Options:)1100 2877 y Fr(--ignore-times)2028+2885 y Fx(don't)28 b(trust)f(the)h(\014le)g(mo)r(di\014cation)f(times)+913 2976 y Fr(-a)99 b(--all)708 b Fx(answ)n(er)26 b(y)n(es)h(to)g(all)h+(patc)n(hes)913 3076 y Fr(-i)99 b(--interactive)356 b+Fx(prompt)27 b(user)g(in)n(teractiv)n(ely)1100 3205 y+Fr(--repodir)40 b(DIRECTORY)2028 3164 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)f(to)2028+3263 y(run)863 3347 y(Adv)-5 b(anced)28 b(options:)1013+3463 y Fr(--umask)41 b(UMASK)97 b Fx(sp)r(ecify)28 b(umask)f(to)h(use)f+(when)h(writing)863 3581 y(Unrev)n(ert)i(is)g(used)g(to)g(undo)g(the)h+(results)f(of)g(a)g(rev)n(ert)f(command.)44 b(It)31 b(is)f(only)g+(guar-)739 3681 y(an)n(teed)g(to)g(w)n(ork)e(prop)r(erly)h(if)i(y)n(ou)+e(ha)n(v)n(en't)g(made)h(an)n(y)g(c)n(hanges)e(since)i(the)g(rev)n(ert)+f(w)n(as)739 3780 y(p)r(erformed.)863 3897 y(The)21 b(command)f(mak)n+(es)g(a)g(b)r(est)h(e\013ort)g(to)f(merge)g(the)h(unrev)n(ersion)e+(with)i(an)n(y)f(c)n(hanges)739 3997 y(y)n(ou)36 b(ha)n(v)n(e)g(since)h+(made.)66 b(In)37 b(fact,)j(unrev)n(ert)c(should)h(ev)n(en)f(w)n(ork)g+(if)i(y)n(ou'v)n(e)e(recorded)739 4097 y(c)n(hanges)26+b(since)h(rev)n(erting.)739 4464 y Fq(6.10)135 b(Adv)-7+b(anced)44 b(examination)j(of)e(the)g(rep)t(ository)739+4695 y Fk(6.10.1)112 b(darcs)38 b(di\013)739 4881 y Fr(Usage:)j(darcs)h+(diff)f([OPTION]...)e([FILE)j(or)h(DIRECTORY]...)863+4998 y Fx(Options:)p eop end+%%Page: 95 95+TeXDict begin 95 94 bop 291 282 a Fu(6.10.)63 b(AD)n(V)-9+b(ANCED)28 b(EXAMINA)-7 b(TION)29 b(OF)e(THE)g(REPOSITOR)-7+b(Y)479 b Fx(95)652 532 y Fr(--to-match)39 b(PATTERN)1710+490 y Fx(select)28 b(c)n(hanges)e(up)i(to)f(a)g(patc)n(h)h(matc)n(hing)+1710 590 y(P)-7 b(A)g(TTERN)652 689 y Fr(--to-patch)39+b(REGEXP)1710 647 y Fx(select)28 b(c)n(hanges)e(up)i(to)f(a)g(patc)n(h)+h(matc)n(hing)1710 747 y(REGEXP)652 846 y Fr(--to-tag)40+b(REGEXP)1710 804 y Fx(select)28 b(c)n(hanges)e(up)i(to)f(a)g(tag)g+(matc)n(hing)1710 904 y(REGEXP)652 1012 y Fr(--from-match)38+b(PATTERN)1710 962 y Fx(select)28 b(c)n(hanges)e(starting)h(with)h(a)f+(patc)n(h)1710 1061 y(matc)n(hing)g(P)-7 b(A)g(TTERN)652+1185 y Fr(--from-patch)38 b(REGEXP)1710 1135 y Fx(select)28+b(c)n(hanges)e(starting)h(with)h(a)f(patc)n(h)1710 1235+y(matc)n(hing)g(REGEXP)652 1350 y Fr(--from-tag)39 b(REGEXP)1710+1309 y Fx(select)28 b(c)n(hanges)e(starting)h(with)h(a)f(tag)g(matc)n+(hing)1710 1408 y(REGEXP)652 1478 y Fr(--match)40 b(PATTERN)402+b Fx(select)28 b(a)f(single)g(patc)n(h)g(matc)n(hing)g(P)-7+b(A)g(TTERN)465 1578 y Fr(-p)99 b(--patch)40 b(REGEXP)446+b Fx(select)28 b(a)f(single)g(patc)n(h)g(matc)n(hing)g(REGEXP)652+1677 y Fr(--last)41 b(NUMBER)489 b Fx(select)28 b(the)g(last)f(NUMBER)h+(patc)n(hes)652 1777 y Fr(--diff-command)38 b(COMMAND)96+b Fx(sp)r(ecify)28 b(di\013)g(command)g(\(ignores)e({di\013-opts\))652+1876 y Fr(--diff-opts)39 b(OPTIONS)227 b Fx(options)27+b(to)h(pass)f(to)g(di\013)465 1976 y Fr(-u)99 b(--unified)662+b Fx(pass)27 b(-u)h(option)f(to)g(di\013)652 2105 y Fr(--repodir)40+b(DIRECTORY)1710 2064 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e+(directory)g(in)i(whic)n(h)g(to)1710 2163 y(run)652 2263+y Fr(--store-in-memor)o(y)1710 2221 y Fx(do)g(patc)n(h)f(application)g+(in)h(memory)e(rather)h(than)1710 2321 y(on)h(disk)415+2387 y(Di\013)38 b(can)f(b)r(e)h(used)f(to)g(create)f(a)h(di\013)h(b)r+(et)n(w)n(een)f(t)n(w)n(o)g(v)n(ersions)e(whic)n(h)i(are)g(in)g(y)n+(our)291 2486 y(rep)r(ository)-7 b(.)35 b(Sp)r(ecifying)26+b(just)h({from-patc)n(h)e(will)i(get)f(y)n(ou)g(a)g(di\013)h(against)e+(y)n(our)h(w)n(orking)291 2586 y(cop)n(y)-7 b(.)34 b(If)24+b(y)n(ou)f(giv)n(e)g(di\013)h(no)f(v)n(ersion)f(argumen)n(ts,)h(it)h+(giv)n(es)e(y)n(ou)h(the)h(same)f(information)g(as)291+2685 y(whatsnew)k(except)g(that)h(the)g(patc)n(h)g(is)f(formatted)g(as)+g(the)h(output)h(of)e(a)g(di\013)i(command)p 527 2862+2392 4 v 527 2936 a Fr(--diff-opts)p 527 2991 V 415 3168+a Fx(Di\013)d(calls)e(an)h(external)f(\\di\013)6 b(")26+b(command)e(to)h(do)g(the)g(actual)g(w)n(ork,)f(and)h(passes)f(an)n(y)+291 3267 y(unrecognized)i(\015ags)h(to)g(this)h(di\013)g(command.)37+b(Th)n(us)27 b(y)n(ou)g(can)g(call)291 3428 y Fr(\045)43+b(darcs)e(diff)h(-t)h(0.9.8)e(-t)i(0.9.10)e(--)i(-u)291+3589 y Fx(to)22 b(get)g(a)g(di\013)h(in)f(the)h(uni\014ed)g(format.)34+b(Actually)-7 b(,)24 b(thanks)e(to)g(the)h(w)n(onders)d(of)j(getopt)f+(y)n(ou)291 3689 y(need)28 b(the)h(\\)p Fr(--)p Fx(")e(sho)n(wn)h(ab)r+(o)n(v)n(e)g(b)r(efore)g(an)n(y)g(argumen)n(ts)f(to)i(di\013.)41+b(Y)-7 b(ou)29 b(can)f(also)g(sp)r(ecify)291 3788 y(additional)f+(argumen)n(ts)g(to)h(di\013)h(using)f(the)h Fr(--diff-opts)24+b Fx(\015ag.)38 b(The)28 b(ab)r(o)n(v)n(e)f(command)291+3888 y(w)n(ould)g(lo)r(ok)g(lik)n(e)g(this:)291 4049+y Fr(\045)43 b(darcs)e(diff)h(--diff-opts)d(-u)k(-t)g(0.9.8)e(-t)i+(0.9.10)291 4210 y Fx(This)30 b(ma)n(y)f(not)h(seem)g(lik)n(e)g(an)f+(impro)n(v)n(emen)n(t,)h(but)g(it)h(really)e(pa)n(ys)g(o\013)h(when)g+(y)n(ou)g(w)n(an)n(t)291 4310 y(to)d(alw)n(a)n(ys)f(giv)n(e)g(di\013)j+(the)f(same)f(options.)36 b(Y)-7 b(ou)28 b(can)f(do)g(this)h(b)n(y)f+(adding)291 4470 y Fr(\045)43 b(diff)f(diff-opts)e(-udp)291+4631 y Fx(to)27 b(y)n(our)f Fr(_darcs/prefs/defa)o(ult)o(s)21+b Fx(\014le.)415 4731 y(If)30 b(y)n(ou)e(w)n(an)n(t)g(to)h(view)g(only)+g(the)g(di\013erences)g(to)g(one)f(or)g(more)h(\014les,)g(y)n(ou)f(can)+h(do)g(so)291 4831 y(with)f(a)f(command)g(suc)n(h)g(as)291+4992 y Fr(\045)43 b(darcs)e(diff)h(foo.c)g(bar.c)f(baz/)p+eop end+%%Page: 96 96+TeXDict begin 96 95 bop 739 282 a Fx(96)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)p 975 515 2392 4+v 975 590 a Fr(--diff-command)p 975 627 V 863 811 a Fx(Y)-7+b(ou)36 b(can)g(use)g(a)f(di\013eren)n(t)h(program)e(to)i(view)f+(di\013erences)h(b)n(y)g(including)g(the)g(\015ag)739+910 y Fr(--diff-command)p Fx(,)22 b(e.g.)739 1077 y Fr(--diff-command)+38 b('opendiff)i(\0451)i(\0452'.)739 1245 y Fx(The)35+b Fr(\0451)f Fx(and)h Fr(\0452)f Fx(are)g(replaced)g(with)h(the)g(t)n+(w)n(o)g(v)n(ersions)e(to)h(b)r(e)i(merged.)58 b(The)35+b(ab)r(o)n(v)n(e)739 1344 y(example)27 b(w)n(orks)f(with)j(the)f+(FileMerge.app)e(to)r(ol)i(that)g(comes)f(with)h(Apple's)g(dev)n(elop)r+(er)739 1444 y(to)r(ols.)36 b(T)-7 b(o)28 b(use)f(xxdi\013,)h(y)n(ou)f+(w)n(ould)g(use)739 1611 y Fr(--diff-command)38 b('xxdiff)i(\0451)j+(\0452')739 1778 y Fx(T)-7 b(o)27 b(use)h Fr(kdiff3)p+Fx(,)d(y)n(ou)i(can)g(use)739 1946 y Fr(--diff-command)38+b('kdiff3)i(\0451)j(\0452')863 2113 y Fx(Note)25 b(that)g(the)h+(command)e(is)h(split)g(in)n(to)f(space-separated)f(w)n(ords)g(and)i+(the)g(\014rst)g(one)739 2212 y(is)38 b Fr(exec)p Fx(ed)e(with)i(the)h+(rest)e(as)g(argumen)n(ts|it)g(is)h(not)g(a)f(shell)h(command.)67+b(Also)38 b(the)739 2312 y(substitution)31 b(of)f(the)h+Fr(\045)f Fx(escap)r(es)g(is)g(only)g(done)g(on)h(complete)f(w)n(ords.)+44 b(See)30 b(6.1)g(for)g(ho)n(w)739 2411 y(y)n(ou)d(migh)n(t)g(w)n+(ork)f(around)h(this)h(fact,)g(for)f(example,)g(with)h(Emacs')f+(Edi\013)g(pac)n(k)-5 b(age.)863 2511 y(Note)28 b(also)f(that)g(the)h+Fr(--diff-opts)c Fx(\015ag)i(is)i(ignored)e(if)i(y)n(ou)f(use)h(this)g+(option.)739 2746 y Fk(6.10.2)112 b(darcs)38 b(annotate)739+2899 y Fr(Usage:)j(darcs)h(annotate)e([OPTION]...)f([FILE)i(or)i+(DIRECTORY]...)863 2999 y Fx(Options:)913 3094 y Fr(-s)99+b(--summary)532 b Fx(summarize)27 b(c)n(hanges)1100 3193+y Fr(--no-summary)400 b Fx(don't)28 b(summarize)e(c)n(hanges)913+3323 y Fr(-u)99 b(--unified)2028 3281 y Fx(output)28+b(patc)n(h)f(in)h(a)f(darcs-sp)r(eci\014c)f(format)2028+3381 y(similar)h(to)g(di\013)h(-u)1100 3450 y Fr(--human-readable)224+b Fx(giv)n(e)26 b(h)n(uman-readable)g(output)1100 3550+y Fr(--xml-output)400 b Fx(generate)26 b(XML)i(formatted)f(output)1100+3650 y Fr(--match)41 b(PATTERN)271 b Fx(select)27 b(a)g(single)h(patc)n+(h)f(matc)n(hing)g(P)-7 b(A)g(TTERN)913 3749 y Fr(-p)99+b(--patch)41 b(REGEXP)315 b Fx(select)27 b(a)g(single)h(patc)n(h)f+(matc)n(hing)g(REGEXP)913 3849 y Fr(-t)99 b(--tag)42+b(REGEXP)402 b Fx(select)27 b(tag)g(matc)n(hing)g(REGEXP)1100+3949 y Fr(--creator-hash)38 b(HASH)98 b Fx(sp)r(ecify)28+b(hash)f(of)g(creator)f(patc)n(h)i(\(see)f(do)r(cs\))1100+4078 y Fr(--repodir)40 b(DIRECTORY)2028 4036 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)f(to)2028+4136 y(run)863 4202 y(Displa)n(y)43 b(whic)n(h)h(patc)n(h)f(last)g(mo)r+(di\014ed)h(something.)83 b(Annotate)44 b(displa)n(ys)e(whic)n(h)739+4302 y(patc)n(hes)c(created)g(or)g(last)g(mo)r(di\014ed)i(a)e+(directory)f(\014le)i(or)f(line.)71 b(It)39 b(can)f(also)g(displa)n(y)+739 4401 y(the)28 b(con)n(ten)n(ts)f(of)g(a)h(particular)e(patc)n(h)h+(in)h(darcs)e(format.)p 975 4585 V 975 4660 a Fr(--human-readable)o(,)+38 b(--summary,)h(--unified,)h(--xml--output)p 975 4715+V 863 4899 a Fx(When)33 b(called)f(with)h(just)g(a)f(patc)n(h)g(name,)i+(annotate)d(outputs)i(the)g(patc)n(h)f(in)g(darcs)739+4998 y(format,)27 b(whic)n(h)h(is)f(the)h(same)f(as)g+Fr(--human-readable)o Fx(.)p eop end+%%Page: 97 97+TeXDict begin 97 96 bop 291 282 a Fu(6.10.)63 b(AD)n(V)-9+b(ANCED)28 b(EXAMINA)-7 b(TION)29 b(OF)e(THE)g(REPOSITOR)-7+b(Y)479 b Fx(97)415 515 y Fr(--xml-output)23 b Fx(is)k(the)h+(alternativ)n(e)f(to)g Fr(--human-readable)o Fx(.)415+621 y Fr(--summary)15 b Fx(can)j(b)r(e)h(used)f(with)h(either)f(the)h+Fr(--xml-output)13 b Fx(or)18 b(the)h Fr(--human-readabl)o(e)291+721 y Fx(options)k(to)g(alter)g(the)h(results.)35 b(It)24+b(is)g(do)r(cumen)n(ted)f(fully)i(in)e(the)h(`common)g(options')f(p)r+(or-)291 821 y(tion)k(of)h(the)g(man)n(ual.)415 927 y(Giving)h(the)g+Fr(--unified)d Fx(\015ag)i(implies)h Fr(--human-readable)p+Fx(,)23 b(and)29 b(causes)f(the)h(out-)291 1026 y(put)37+b(to)g(remain)g(in)g(a)g(darcs-sp)r(eci\014c)f(format)g(that)i(is)f+(similar)f(to)h(that)g(pro)r(duced)g(b)n(y)291 1126 y+Fr(diff)42 b(--unified)p Fx(.)415 1232 y(If)20 b(a)f(directory)f(name)h+(is)g(giv)n(en,)h(annotate)f(will)h(output)g(details)f(of)g(the)h(last)+f(mo)r(difying)291 1332 y(patc)n(h)24 b(for)h(eac)n(h)f(\014le)h(in)g+(the)h(directory)e(and)g(the)i(directory)e(itself.)36+b(The)25 b(details)g(lo)r(ok)f(lik)n(e)291 1431 y(this:)334+1646 y Fr(#)43 b(Created)e(by)i([bounce)d(handling)h(patch)334+1746 y(#)i(mark**20040526202)o(21)o(6])81 b(as)43 b(./test/m7/bounc)o+(e_h)o(an)o(dl)o(ing)o(.p)o(l)465 1846 y(bounce_handling.)o(pl)415+2054 y Fx(If)31 b(a)g(patc)n(h)f(name)h(and)g(a)f(directory)g(are)g+(giv)n(en,)g(these)h(details)g(are)f(output)h(for)g(the)291+2154 y(time)c(after)g(that)h(patc)n(h)e(w)n(as)h(applied.)36+b(If)28 b(a)f(directory)f(and)h(a)f(tag)h(name)g(are)f(giv)n(en,)h(the)+291 2253 y(details)g(of)g(the)h(patc)n(hes)f(in)n(v)n(olv)n(ed)g(in)g+(the)h(sp)r(eci\014ed)g(tagged)f(v)n(ersion)f(will)i(b)r(e)g(output.)+415 2359 y(If)33 b(a)f(\014le)h(name)g(is)f(giv)n(en,)h(the)g(last)g+(mo)r(difying)g(patc)n(h)f(details)g(of)h(that)g(\014le)g(will)g(b)r(e)+291 2459 y(output,)23 b(along)d(with)i(markup)f(indicating)h(patc)n(h)f+(details)h(when)f(eac)n(h)g(line)h(w)n(as)f(last)g(\(and)291+2559 y(p)r(erhaps)27 b(next\))h(mo)r(di\014ed.)p 527+2767 2392 4 v 527 2842 a Fr(--creator-hash)38 b(HASH)p+527 2878 V 415 3087 a Fx(The)27 b Fr(--creator-hash)21+b Fx(option)26 b(should)h(only)f(b)r(e)h(used)g(in)g(com)n(bination)f+(with)h(a)g(\014le)291 3187 y(or)h(directory)f(to)i(b)r(e)g(annotated.)+41 b(In)29 b(this)g(case,)f(the)i(name)e(of)h(that)g(\014le)g(or)f+(directory)g(is)291 3286 y(in)n(terpreted)f(to)h(b)r(e)g(its)h(name)e+Fs(at)j(the)h(time)f(it)g(was)h(cr)l(e)l(ate)l(d)p Fx(,)d(and)g(the)g+(hash)g(giv)n(en)f(along)291 3386 y(with)41 b Fr(--creator-hash)34+b Fx(indicates)41 b(the)f(patc)n(h)h(that)f(created)g(the)h(\014le)f+(or)g(directory)-7 b(.)291 3485 y(This)26 b(allo)n(ws)f(y)n(ou)h(to)g+(\(relativ)n(ely\))g(easily)f(examine)h(a)g(\014le)h(ev)n(en)f(if)h(it)+g(has)f(b)r(een)h(renamed)291 3585 y(m)n(ultiple)h(times.)291+3852 y Fk(6.10.3)112 b(darcs)38 b(sho)m(w)291 4017 y+Fx(The)24 b(sho)n(w)e(command)i(pro)n(vides)e(access)h(to)h(sev)n(eral)+e(sub)r(commands)h(whic)n(h)h(can)g(b)r(e)g(used)291+4117 y(to)j(in)n(v)n(estigate)f(the)i(state)g(of)f(a)g(rep)r(ository)-7+b(.)291 4367 y Fv(darcs)32 b(sho)m(w)g(authors)291 4532+y Fr(Usage:)41 b(darcs)g(show)h(authors)f([OPTION]...)415+4638 y Fx(Options:)565 4769 y Fr(--repodir)e(DIRECTORY)1492+4727 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e(directory)g(in)i(whic)n+(h)g(to)1492 4826 y(run)415 4899 y(The)f(authors)f(command)h(writes)f+(a)h(list)g(of)g(all)g(patc)n(h)f(authors)g(in)h(the)h(rep)r(ository)d+(to)291 4998 y(standard)h(output.)p eop end+%%Page: 98 98+TeXDict begin 98 97 bop 739 282 a Fx(98)1378 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)739 515 y Fv(darcs)33+b(sho)m(w)e(con)m(ten)m(ts)739 674 y Fr(Usage:)41 b(darcs)h(show)f+(contents)g([OPTION]...)e([FILE]...)863 777 y Fx(Options:)1100+874 y Fr(--match)i(PATTERN)271 b Fx(select)27 b(a)g(single)h(patc)n(h)f+(matc)n(hing)g(P)-7 b(A)g(TTERN)913 974 y Fr(-p)99 b(--patch)41+b(REGEXP)315 b Fx(select)27 b(a)g(single)h(patc)n(h)f(matc)n(hing)g+(REGEXP)913 1073 y Fr(-t)99 b(--tag)42 b(REGEXP)402 b+Fx(select)27 b(tag)g(matc)n(hing)g(REGEXP)1100 1203 y+Fr(--repodir)40 b(DIRECTORY)2028 1161 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)f(to)2028+1261 y(run)863 1334 y(Sho)n(w)33 b(con)n(ten)n(ts)f(can)h(b)r(e)g(used)+h(to)e(displa)n(y)h(an)f(earlier)g(v)n(ersion)g(of)h(some)f+(\014le\(s\).)54 b(If)739 1434 y(y)n(ou)31 b(giv)n(e)g(sho)n(w)f(con)n+(ten)n(ts)h(no)h(v)n(ersion)e(argumen)n(ts,)i(it)g(displa)n(ys)e(the)j+(recorded)d(v)n(ersion)739 1534 y(of)d(the)h(\014le\(s\).)739+1766 y Fv(darcs)33 b(sho)m(w)e(\014les)739 1925 y Fr(Usage:)41+b(darcs)h(show)f(files)h([OPTION]...)863 2027 y Fx(Options:)1100+2125 y Fr(--files)620 b Fx(include)28 b(\014les)f(in)h(output)g([DEF)-9+b(A)n(UL)i(T])1100 2224 y Fr(--no-files)488 b Fx(don't)28+b(include)g(\014les)f(in)h(output)1100 2324 y Fr(--directories)356+b Fx(include)28 b(directories)e(in)i(output)g([DEF)-9+b(A)n(UL)i(T])1100 2424 y Fr(--no-directories)224 b Fx(don't)28+b(include)g(directories)e(in)i(output)1100 2563 y Fr(--pending)2028+2511 y Fx(re\015ect)f(p)r(ending)h(patc)n(hes)f(in)h(output)2028+2611 y([DEF)-9 b(A)n(UL)i(T])1100 2701 y Fr(--no-pending)400+b Fx(only)27 b(included)h(recorded)e(patc)n(hes)h(in)h(output)913+2801 y Fr(-0)99 b(--null)664 b Fx(separate)26 b(\014le)i(names)f(b)n(y)+g(NUL)h(c)n(haracters)1100 2930 y Fr(--repodir)40 b(DIRECTORY)2028+2888 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e(directory)g(in)i(whic)n+(h)f(to)2028 2988 y(run)863 3057 y(The)d(\014les)g(command)f(lists)h+(the)g(v)n(ersion-con)n(trolled)d(\014les)i(in)h(the)g(w)n(orking)e+(cop)n(y)-7 b(.)35 b(The)739 3157 y(similar)27 b(manifest)h(command,)f+(lists)g(the)h(same)f(\014les,)h(excluding)f(an)n(y)g(directories.)863+3259 y(By)i(default)h(\(and)g(if)f(the)h Fr(--pending)c+Fx(option)j(is)g(sp)r(eci\014ed\),)h(the)g(e\013ect)g(of)f(p)r(ending)+739 3359 y(patc)n(hes)j(on)g(the)h(rep)r(ository)e(is)h(tak)n(en)g(in)n+(to)h(accoun)n(t.)50 b(In)33 b(other)f(w)n(ords,)g(if)i(y)n(ou)d(add)i+(a)739 3459 y(\014le)24 b(using)g Fr(darcs)42 b(add)p+Fx(,)24 b(it)g(immediately)h(app)r(ears)e(in)h(the)h(output)g(of)f+Fr(query)41 b(manifest)p Fx(,)739 3558 y(ev)n(en)32 b(if)g(it)h(is)f+(not)g(y)n(et)g(recorded.)49 b(If)33 b(y)n(ou)e(sp)r(ecify)h(the)h+Fr(--no-pending)27 b Fx(option,)33 b Fr(query)739 3658+y(manifest)24 b Fx(will)k(only)f(list)h(recorded)e(\014les)i(\(and)f+(directories\).)863 3761 y(The)35 b Fr(--files)c Fx(and)k+Fr(--directories)29 b Fx(options)k(con)n(trol)g(whether)i(\014les)f+(and)g(direc-)739 3860 y(tories)k(are)h(included)h(in)f(the)h(output.)+73 b(The)39 b Fr(--no-files)d Fx(and)j Fr(--no-directories)739+3960 y Fx(options)28 b(ha)n(v)n(e)g(the)i(rev)n(erse)d(e\013ect.)42+b(The)29 b(default)h(is)f(to)f(include)i(\014les,)f(but)h(not)f+(directo-)739 4059 y(ries.)863 4162 y(If)39 b(y)n(ou)f(sp)r(ecify)g+(the)h Fr(--null)d Fx(option,)k(the)f(\014le)f(names)g(are)g(written)g+(to)g(standard)739 4262 y(output)28 b(in)g(unescap)r(ed)f(form,)g(and)g+(separated)f(b)n(y)i(ASCI)r(I)g(NUL)g(b)n(ytes.)36 b(This)27+b(format)g(is)739 4361 y(suitable)g(for)g(further)h(automatic)f(pro)r+(cessing)f(\(for)h(example,)h(using)f Fr(xargs)41 b(-0)p+Fx(\).)739 4594 y Fv(darcs)33 b(sho)m(w)e(tags)739 4752+y Fr(Usage:)41 b(darcs)h(show)f(tags)h([OPTION]...)863+4855 y Fx(Options:)1013 4982 y Fr(--repodir)e(DIRECTORY)1941+4940 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)d(directory)i(in)h(whic)n+(h)f(to)1941 5040 y(run)p eop end+%%Page: 99 99+TeXDict begin 99 98 bop 291 282 a Fu(6.11.)63 b(RAREL)-7+b(Y)28 b(NEEDED)f(AND)i(OBSCURE)e(COMMANDS)621 b Fx(99)415+515 y(The)37 b(tags)f(command)h(writes)g(a)f(list)i(of)f(all)g(tags)f+(in)h(the)h(rep)r(ository)d(to)i(standard)291 615 y(output.)415+715 y(T)-7 b(ab)29 b(c)n(haracters)d(\(ASCI)r(I)k(c)n(haracter)c(9\))j+(in)g(tag)f(names)g(are)g(c)n(hanged)f(to)i(spaces)e(for)291+814 y(b)r(etter)h(in)n(terop)r(erabilit)n(y)e(with)i(shell)f(to)r(ols.)+37 b(A)28 b(w)n(arning)e(is)h(prin)n(ted)h(if)g(this)g(happ)r(ens.)291+1029 y Fv(darcs)k(sho)m(w)g(rep)s(o)291 1182 y Fr(Usage:)41+b(darcs)g(show)h(repo)g([OPTION]...)415 1282 y Fx(Options:)565+1406 y Fr(--repodir)d(DIRECTORY)1492 1364 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)e(directory)g(in)i(whic)n(h)g(to)1492+1464 y(run)565 1533 y Fr(--files)619 b Fx(include)28+b(\014les)g(in)g(output)g([DEF)-9 b(A)n(UL)i(T])565 1633+y Fr(--no-files)487 b Fx(don't)28 b(include)g(\014les)g(in)f(output)565+1733 y Fr(--xml-output)399 b Fx(generate)27 b(XML)h(formatted)f(output)+415 1828 y(The)e Fr(show)42 b(repo)23 b Fx(displa)n(ys)g(information)h+(ab)r(out)h(the)f(curren)n(t)g(rep)r(ository:)34 b(the)25+b(lo)r(ca-)291 1928 y(tion,)i(the)h(t)n(yp)r(e,)g(etc.)415+2028 y(This)23 b(is)f(pro)n(vided)f(as)h(informational)g(output)h(for)f+(t)n(w)n(o)f(purp)r(oses:)34 b(curious)21 b(users)h(and)291+2127 y(scripts)d(in)n(v)n(oking)g(darcs.)34 b(F)-7 b(or)19+b(the)i(latter,)g(this)g(information)f(can)g(b)r(e)g(parsed)g(to)g+(facilitate)291 2227 y(the)34 b(script;)j(for)c(example,)i+Fr(darcs)42 b(show)g(repo)g(|)h(grep)f(Root:)f(|)j(awk)e({print)f($2})+291 2327 y Fx(can)36 b(b)r(e)h(used)f(to)g(lo)r(cate)g(the)h(top-lev)n+(el)f Fr(_darcs)e Fx(directory)h(from)h(an)n(yplace)f(within)i(a)291+2426 y(darcs)26 b(rep)r(ository)g(w)n(orking)g(directory)-7+b(.)p 527 2603 2392 4 v 527 2678 a Fr(--files,)40 b(--no-files)p+527 2726 V 415 2903 a Fx(If)29 b(the)h Fr(--files)c Fx(option)i(is)h+(sp)r(eci\014ed)g(\(the)h(default\),)g(then)f(the)g Fr(show)42+b(repo)27 b Fx(op)r(era-)291 3002 y(tion)f(will)h(read)e(patc)n(h)h+(information)g(from)g(the)h(rep)r(ository)e(and)h(displa)n(y)g(the)h(n)+n(um)n(b)r(er)f(of)291 3102 y(patc)n(hes)g(in)h(the)g(rep)r(ository)-7+b(.)35 b(The)27 b Fr(--no-files)c Fx(option)j(can)h(b)r(e)g(used)g(to)g+(suppress)f(this)291 3202 y(op)r(eration)g(\(and)i(impro)n(v)n(e)e(p)r+(erformance\).)p 527 3378 V 527 3453 a Fr(--human-readable)o(,)37+b(--xml-output)p 527 3508 V 415 3685 a Fx(By)24 b(default,)i(the)f+Fr(show)42 b(repo)23 b Fx(displa)n(ys)g(output)i(in)g(h)n(uman)f+(readable)g(form,)g(but)i(the)291 3785 y Fr(--xml-output)16+b Fx(option)21 b(can)g(b)r(e)h(used)f(to)h(obtain)f(XML-formatted)g(to)+g(facilitate)h(regular)291 3884 y(parsing)k(b)n(y)h(external)g(to)r+(ols.)291 4158 y Fq(6.11)135 b(Rarely)46 b(needed)f(and)g(obscure)g+(commands)291 4356 y Fk(6.11.1)112 b(darcs)38 b(con)m(v)m(ert)291+4510 y Fr(Usage:)j(darcs)g(convert)g([OPTION]...)e(<REPOSITORY>)g+([<DIRECTORY>])415 4609 y Fx(Options:)565 4703 y Fr(--repo-name)g+(DIRECTORY)444 b Fx(path)28 b(of)f(output)i(directory)565+4803 y Fr(--set-scripts-e)o(xec)o(ut)o(ab)o(le)311 b+Fx(mak)n(e)27 b(scripts)g(executable)565 4903 y Fr(--dont-set-scri)o+(pts)o(-e)o(xe)o(cut)o(ab)o(le)93 b Fx(don't)28 b(mak)n(e)f(scripts)g+(executable)415 4998 y(Adv)-5 b(anced)28 b(options:)p+eop end+%%Page: 100 100+TeXDict begin 100 99 bop 739 282 a Fx(100)1336 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)1013 542 y Fr(--no-ssh-cm)1592+490 y Fx(don't)g(use)f(SSH)h(Con)n(trolMaster)e(feature)1592+590 y([DEF)-9 b(A)n(UL)i(T])1013 680 y Fr(--ssh-cm)1592+688 y Fx(use)27 b(SSH)i(Con)n(trolMaster)c(feature)863+777 y(Y)-7 b(ou)31 b(ma)n(y)f(sp)r(ecify)h(the)f(name)h(of)f(the)h(rep)+r(ository)e(created)g(b)n(y)i(pro)n(viding)e(a)h(second)739+876 y(argumen)n(t)c(to)i(con)n(v)n(ert,)e(whic)n(h)i(is)f(a)g+(directory)g(name.)739 1112 y Fk(6.11.2)112 b(darcs)38+b(mark-con\015icts)739 1267 y Fr(Usage:)j(darcs)h(mark-conflicts)37+b([OPTION]...)863 1367 y Fx(Options:)1013 1462 y Fr(--ignore-times)1941+1470 y Fx(don't)27 b(trust)h(the)g(\014le)g(mo)r(di\014cation)f(times)+1013 1591 y Fr(--repodir)40 b(DIRECTORY)1941 1549 y Fx(sp)r(ecify)28+b(the)g(rep)r(ository)d(directory)i(in)h(whic)n(h)f(to)1941+1649 y(run)863 1716 y(Adv)-5 b(anced)28 b(options:)1013+1815 y Fr(--umask)41 b(UMASK)97 b Fx(sp)r(ecify)28 b(umask)f(to)h(use)f+(when)h(writing)863 1916 y(Mark-con\015icts)e(is)h(used)h(to)f(mark)f+(and)h(resolv)n(e)f(an)n(y)h(con\015icts)g(that)g(ma)n(y)g(exist)g(in)h+(a)739 2016 y(rep)r(ository)-7 b(.)35 b(Note)27 b(that)g(this)g+(trashes)f(an)n(y)g(unrecorded)f(c)n(hanges)h(in)h(the)g(w)n(orking)e+(cop)n(y)-7 b(.)739 2252 y Fk(6.11.3)112 b(darcs)38 b(dist)739+2407 y Fr(Usage:)j(darcs)h(dist)f([OPTION]...)863 2507+y Fx(Options:)913 2602 y Fr(-d)99 b(--dist-name)39 b(DISTNAME)2071+2610 y Fx(name)28 b(of)f(v)n(ersion)1100 2731 y Fr(--repodir)40+b(DIRECTORY)2071 2689 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)e+(directory)h(in)g(whic)n(h)h(to)2071 2789 y(run)863 2856+y(Create)f(a)g(distribution)h(tarball.)863 2956 y(Dist)e(is)e(a)h+(handy)f(to)r(ol)g(for)h(implemen)n(ting)g(a)f("mak)n(e)f(dist")i+(target)f(in)g(y)n(our)g(mak)n(e\014le.)739 3056 y(It)39+b(creates)f(a)g(tarball)g(of)h(the)g(recorded)f(edition)h(of)g(y)n(our)+e(tree.)71 b(Basically)-7 b(,)40 b(y)n(ou)e(will)739+3155 y(t)n(ypically)27 b(use)g(it)h(in)g(a)f(mak)n(e\014le)g(rule)h+(suc)n(h)f(as)739 3324 y Fr(dist:)913 3424 y(darcs)42+b(dist)g(--dist-name)d(darcs-`./darcs)f(--version`)739+3592 y(darcs)j(dist)29 b Fx(then)h(simply)g(creates)f(a)g(clean)h(cop)n+(y)f(of)h(the)g(source)e(tree,)j(whic)n(h)e(it)i(then)739+3691 y(tars)f(and)h(gzips.)48 b(If)31 b(y)n(ou)g(use)g(programs)e(suc)n+(h)i(as)g(auto)r(conf)g(or)f(automak)n(e,)h(y)n(ou)f(really)739+3791 y(should)d(run)g(them)h(on)f(the)h(clean)f(tree)g(b)r(efore)h+(tarring)e(it)h(up)h(and)f(distributing)h(it.)37 b(Y)-7+b(ou)739 3891 y(can)25 b(do)f(this)i(using)e(the)i(pref)f(v)-5+b(alue)25 b(\\predist",)f(whic)n(h)h(is)g(a)g(shell)g(command)f(that)h+(is)g(run)739 3990 y(prior)h(to)i(tarring)e(up)i(the)g(distribution:)+739 4159 y Fr(\045)43 b(darcs)f(setpref)e(predist)h("autoconf)f(&&)j+(automake")739 4395 y Fk(6.11.4)112 b(darcs)38 b(trac)m(kdo)m(wn)739+4549 y Fr(Usage:)j(darcs)h(trackdown)d([OPTION]...)g([[INITIALIZATION])+e(COMMAND])863 4650 y Fx(Options:)1013 4774 y Fr(--repodir)j(DIRECTORY)+1941 4733 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)d(directory)i(in)h+(whic)n(h)f(to)1941 4832 y(run)863 4899 y(T)-7 b(rac)n(kdo)n(wn)39+b(tries)h(to)h(\014nd)g(the)g(most)g(recen)n(t)f(v)n(ersion)f(in)i(the)+g(rep)r(ository)e(whic)n(h)739 4998 y(passes)32 b(a)g(test.)53+b(Giv)n(en)33 b(no)g(argumen)n(ts,)g(it)g(uses)f(the)i(default)f(rep)r+(ository)e(test.)53 b(Giv)n(en)p eop end+%%Page: 101 101+TeXDict begin 101 100 bop 291 282 a Fu(6.11.)63 b(RAREL)-7+b(Y)28 b(NEEDED)f(AND)i(OBSCURE)e(COMMANDS)579 b Fx(101)291+515 y(one)31 b(argumen)n(t,)g(it)h(treats)f(it)h(as)f(a)g(test)h+(command.)48 b(Giv)n(en)31 b(t)n(w)n(o)g(argumen)n(ts,)g(the)h(\014rst)+291 615 y(is)f(an)f(initialization)h(command)g(with)h(is)f(run)g(only)f+(once,)i(and)f(the)h(second)e(is)h(the)h(test)291 715+y(command.)415 815 y(T)-7 b(rac)n(kdo)n(wn)28 b(is)h(helpful)i(for)e+(lo)r(cating)g(when)h(something)f(w)n(as)g(brok)n(en.)42+b(It)30 b(creates)e(a)291 914 y(temp)r(orary)d(directory)h(with)h(the)g+(latest)g(rep)r(ository)e(con)n(ten)n(t)i(in)g(it)g(and)g(cd)g(to)g+(it.)37 b(First,)291 1014 y(and)27 b(only)g(once,)g(it)h(runs)g(the)g+(initialization)f(command)g(if)h(an)n(y)-7 b(,)27 b(for)g(example)291+1182 y Fr('autoconf;)39 b(./configure)g(>/dev/null')291+1350 y Fx(Then)27 b(it)h(runs)g(the)g(test)f(command,)h(for)f(example)+291 1518 y Fr('make)41 b(&&)i(cd)g(tests)e(&&)i(sh)g(/tmp/test.sh')291+1686 y Fx(While)25 b(the)h(test)f(command)g(exits)g(with)h(an)f(error)e+(return)i(co)r(de,)g(darcs)f(\\unapplies")g(one)291 1786+y(patc)n(h)g(from)g(the)h(v)n(ersion)e(con)n(trolled)g(\014les)i(to)f+(retriev)n(e)f(an)h(earlier)g(v)n(ersion,)f(and)i(rep)r(eats)291+1885 y(the)c(test)h(command.)34 b(If)22 b(the)g(test)g(command)f+(\014nally)g(succeeds,)h(the)g(name)f(of)g(the)h(h)n(un)n(ted)291+1985 y(do)n(wn)27 b(patc)n(h)g(is)g(found)h(in)g(the)g(output)g(b)r+(efore)g(the)g(last)f(test)h(run.)415 2085 y(FIXME:)38+b(It)g(is)g(still)g(rather)e(primitiv)n(e.)68 b(Curren)n(tly)36+b(it)j(just)f(go)r(es)f(bac)n(k)g(o)n(v)n(er)f(the)291+2185 y(history)31 b(in)h(rev)n(erse)e(order)h(trying)g(eac)n(h)g(v)n+(ersion.)48 b(I'd)33 b(lik)n(e)e(for)h(it)g(to)g(explore)f(di\013eren)n+(t)291 2284 y(patc)n(h)j(com)n(binations,)h(to)f(try)g(to)h(\014nd)g+(the)f(minim)n(um)i(n)n(um)n(b)r(er)e(of)g(patc)n(hes)g(that)h(y)n(ou)+291 2384 y(w)n(ould)27 b(need)g(to)h(obliterate)f(in)h(order)e(to)h+(mak)n(e)g(the)h(test)g(succeed.)415 2484 y(FIXME:)e(I)h(also)e(w)n+(ould)g(lik)n(e)h(to)g(add)g(an)g(in)n(terface)g(b)n(y)g(whic)n(h)g(y)n+(ou)f(can)h(tell)g(it)h(whic)n(h)291 2584 y(patc)n(hes)f(it)i(should)f+(consider)g(not)g(including.)37 b(Without)28 b(suc)n(h)f(a)g(feature,)g+(the)h(follo)n(wing)291 2683 y(command:)291 2852 y Fr(\045)43+b(darcs)e(trackdown)f('make)i(&&)g(false')291 3020 y+Fx(w)n(ould)29 b(result)h(in)h(compiling)e(ev)n(ery)g(v)n(ersion)g(in)h+(the)h(rep)r(ository{whic)n(h)d(is)i(a)g(rather)f(te-)291+3119 y(dious)e(prosp)r(ect.)291 3338 y Fv(Example)k(usage)291+3492 y Fx(If)d(y)n(ou)g(w)n(an)n(t)f(to)i(\014nd)f(the)h(last)f(v)n+(ersion)f(of)h(darcs)f(that)i(had)f(a)g(FIXME)g(note)h(in)f(the)h+(\014le)291 3592 y(Record.lhs,)d(y)n(ou)h(could)h(run)291+3760 y Fr(\045)43 b(darcs)e(trackdown)f('grep)i(FIXME)f(Record.lhs')415+3928 y Fx(T)-7 b(o)27 b(\014nd)h(the)g(latest)g(v)n(ersion)e(that)i+(compiles,)f(y)n(ou)g(can)g(run)291 4096 y Fr(\045)43+b(darcs)e(trackdown)f('autoconf')g('./configure)e(&&)43+b(make')415 4264 y Fx(T)-7 b(rac)n(kdo)n(wn)28 b(can)i(also)f(b)r(e)i+(used)f(to)g(see)g(ho)n(w)g(other)f(features)h(of)g(the)h(co)r(de)f(c)n+(hanged)291 4364 y(with)e(time.)37 b(F)-7 b(or)27 b(example)291+4532 y Fr(\045)43 b(darcs)e(trackdown)f('autoconf;)g(./configure')e(\\)+421 4631 y("make)k(darcs)f(>)j(/dev/null)39 b(&&)k(cd)g(~/darcs)e(&&)h+(time)g(darcs)g(check)f(&&)i(false")291 4799 y Fx(w)n(ould)28+b(let)h(y)n(ou)f(see)h(ho)n(w)f(long)g(`darcs)g(c)n(hec)n(k')g(tak)n+(es)g(to)g(run)h(on)g(eac)n(h)f(previous)f(v)n(ersion)291+4899 y(of)34 b(darcs)g(that)h(will)g(actually)f(compile.)58+b(The)34 b(\\)p Fr(&&)43 b(false)p Fx(")32 b(ensures)i(that)h(trac)n+(kdo)n(wn)291 4998 y(k)n(eeps)26 b(going.)p eop end+%%Page: 102 102+TeXDict begin 102 101 bop 739 282 a Fx(102)1336 b Fu(CHAPTER)27+b(6.)64 b(D)n(AR)n(CS)28 b(COMMANDS)739 515 y Fk(6.11.5)112+b(darcs)38 b(repair)739 669 y Fr(Usage:)j(darcs)h(repair)f([OPTION]...)+863 768 y Fx(Options:)1013 892 y Fr(--repodir)f(DIRECTORY)1941+850 y Fx(sp)r(ecify)28 b(the)g(rep)r(ository)d(directory)i(in)h(whic)n+(h)f(to)1941 950 y(run)863 1016 y(Adv)-5 b(anced)28 b(options:)1013+1114 y Fr(--umask)41 b(UMASK)97 b Fx(sp)r(ecify)28 b(umask)f(to)h(use)f+(when)h(writing)863 1215 y(Repair)f(attempts)h(to)g(\014x)f(corruption)+g(that)h(ma)n(y)f(ha)n(v)n(e)f(en)n(tered)h(y)n(our)f(rep)r(ository)-7+b(.)863 1315 y(Repair)33 b(curren)n(tly)f(will)h(only)f(repair)g+(damage)g(to)h(the)g(pristine)g(tree.)53 b(F)-7 b(ortunately)739+1414 y(this)28 b(is)f(just)h(the)g(sort)f(of)h(corruption)e(that)i(is)f+(most)h(lik)n(ely)f(to)g(happ)r(en.)p eop end+%%Page: 103 103+TeXDict begin 103 102 bop 291 1140 a Ft(App)5 b(endix)64+b(A)291 1558 y Fw(Theory)77 b(of)g(patc)-6 b(hes)291+2042 y Fq(A.1)134 b(Bac)l(kground)291 2228 y Fx(I)36+b(think)h(a)f(little)h(bac)n(kground)e(on)h(the)h(author)e(is)h(in)h+(order.)62 b(I)37 b(am)f(a)g(ph)n(ysicist,)i(and)291+2328 y(think)23 b(lik)n(e)g(a)g(ph)n(ysicist.)36 b(The)23+b(pro)r(ofs)g(and)g(theorems)g(giv)n(en)f(here)h(are)g(what)g(I)g(w)n+(ould)g(call)291 2428 y(\\ph)n(ysicist")i(pro)r(ofs)i(and)g(theorems,)f+(whic)n(h)h(is)g(to)g(sa)n(y)f(that)h(while)h(the)f(pro)r(ofs)g(ma)n(y)+f(not)291 2527 y(b)r(e)j(rigorous,)e(they)i(are)f(practical,)h(and)g+(the)g(theorems)f(are)g(in)n(tended)i(to)f(giv)n(e)f(ph)n(ysical)291+2627 y(insigh)n(t.)37 b(It)28 b(w)n(ould)f(b)r(e)h(great)f(to)h(ha)n(v)+n(e)e(a)i(mathematician)f(w)n(ork)f(on)i(this,)g(but)h(I)e(am)h(not)291+2726 y(a)f(mathematician,)g(and)h(don't)f(care)g(for)g(math.)415+2829 y(F)-7 b(rom)27 b(the)h(b)r(eginning)g(of)f(this)h(theory)-7+b(,)27 b(whic)n(h)h(originated)e(as)h(the)h(result)f(of)h(a)f(series)+291 2928 y(of)22 b(email)g(discussions)f(with)i(T)-7+b(om)22 b(Lord,)h(I)g(ha)n(v)n(e)e(lo)r(ok)n(ed)g(at)h(patc)n(hes)g(as)+g(b)r(eing)g(analogous)291 3028 y(to)34 b(the)g(op)r(erators)e(of)i+(quan)n(tum)h(mec)n(hanics.)55 b(I)35 b(include)f(in)h(this)f(app)r+(endix)g(fo)r(otnotes)291 3127 y(explaining)27 b(the)i(theory)e(of)h+(patc)n(hes)g(in)g(terms)g(of)g(the)h(theory)e(of)h(quan)n(tum)h(mec)n+(hanics.)291 3227 y(I)c(kno)n(w)f(that)i(for)e(most)h(p)r(eople)g(this)+h(w)n(on't)f(help)g(at)g(all,)g(but)h(man)n(y)f(of)g(m)n(y)g(friends)g+(\(and)291 3327 y(as)e(I)i(write)f(this)g(all)g(three)h(of)f(darcs')f+(users\))h(are)f(ph)n(ysicists,)i(and)f(this)h(will)f(b)r(e)h(helpful)g+(to)291 3426 y(them.)38 b(T)-7 b(o)27 b(non-ph)n(ysicists,)g(p)r+(erhaps)g(it)h(will)g(pro)n(vide)f(some)g(insigh)n(t)h(in)n(to)f(ho)n+(w)h(at)f(least)291 3526 y(this)g(ph)n(ysicist)h(thinks.)291+3813 y Fq(A.2)134 b(In)l(tro)t(duction)291 4000 y Fx(A)35+b(patc)n(h)g(describ)r(es)f(a)h(c)n(hange)f(to)h(the)h(tree.)59+b(It)35 b(could)g(b)r(e)h(either)f(a)f(primitiv)n(e)h(patc)n(h)291+4099 y(\(suc)n(h)c(as)g(a)g(\014le)g(add/remo)n(v)n(e,)g(a)g(directory)+f(rename,)i(or)e(a)h(h)n(unk)h(replacemen)n(t)e(within)291+4199 y(a)g(\014le\),)i(or)e(a)g(comp)r(osite)g(patc)n(h)h(describing)f+(man)n(y)g(suc)n(h)g(c)n(hanges.)45 b(Ev)n(ery)29 b(patc)n(h)i(t)n(yp)r+(e)291 4299 y(m)n(ust)24 b(satisfy)g(the)g(conditions)g(describ)r(ed)g+(in)g(this)h(app)r(endix.)36 b(The)24 b(theory)f(of)h(patc)n(hes)g(is)+291 4398 y(indep)r(enden)n(t)k(of)f(the)h(data)f(whic)n(h)h(the)f(patc)+n(hes)g(manipulate,)h(whic)n(h)f(is)h(what)f(mak)n(es)f(it)291+4498 y(b)r(oth)g(p)r(o)n(w)n(erful)g(and)g(useful,)h(as)e(it)i(pro)n+(vides)d(a)i(framew)n(ork)e(up)r(on)j(whic)n(h)f(one)g(can)f(build)291+4598 y(a)i(revision)f(con)n(trol)g(system)i(in)g(a)f(sane)g(manner.)415+4700 y(Although)36 b(in)f(a)g(sense,)i(the)f(de\014ning)f(prop)r(ert)n+(y)g(of)g(an)n(y)g(patc)n(h)g(is)g(that)h(it)g(can)f(b)r(e)291+4799 y(applied)26 b(to)h(a)f(certain)g(tree,)h(and)g(th)n(us)g(mak)n(e)+e(a)i(certain)f(c)n(hange,)g(this)h(c)n(hange)e(do)r(es)i(not)291+4899 y(wholly)i(de\014ne)h(the)g(patc)n(h.)44 b(A)30+b(patc)n(h)g(is)f(de\014ned)i(b)n(y)e(a)h Fs(r)l(epr)l(esentation)p+Fx(,)g(together)f(with)291 4998 y(a)e(set)h(of)f(rules)g(for)h(ho)n(w)f+(it)h(b)r(eha)n(v)n(es)e(\(whic)n(h)i(it)g(has)g(in)g(common)f(with)h+(its)g(patc)n(h)f(t)n(yp)r(e\).)1660 5208 y(103)p eop+end+%%Page: 104 104+TeXDict begin 104 103 bop 739 282 a Fx(104)1196 b Fu(APPENDIX)28+b(A.)56 b(THEOR)-7 b(Y)27 b(OF)g(P)-7 b(A)g(TCHES)739+515 y Fx(The)24 b Fs(r)l(epr)l(esentation)32 b Fx(of)24+b(a)g(patc)n(h)g(de\014nes)h(what)f(c)n(hange)f(that)i(particular)e+(patc)n(h)h(mak)n(es,)739 615 y(and)35 b(m)n(ust)g(b)r(e)g(de\014ned)g+(in)g(the)g(con)n(text)g(of)f(a)h(sp)r(eci\014c)g(tree.)58+b(The)35 b(theory)f(of)h(patc)n(hes)739 715 y(is)k(a)f(theory)g(of)h+(the)g(man)n(y)f(w)n(a)n(ys)g(one)g(can)g(c)n(hange)g(the)h(represen)n+(tation)e(of)i(a)g(patc)n(h)739 814 y(to)33 b(place)g(it)g(in)h(the)f+(con)n(text)g(of)g(a)g(di\013eren)n(t)h(tree.)53 b(The)33+b(patc)n(h)g(itself)h(is)f(not)g(c)n(hanged,)739 914+y(since)39 b(it)g(describ)r(es)g(a)f(single)h(c)n(hange,)i(whic)n(h)e+(m)n(ust)g(b)r(e)g(the)h(same)e(regardless)f(of)i(its)739+1013 y(represen)n(tation)1256 983 y Fm(1)1291 1013 y+Fx(.)863 1123 y(So)28 b(ho)n(w)e(do)r(es)i(one)f(de\014ne)g(a)g(tree,)h+(or)e(the)i(con)n(text)f(of)h(a)f(patc)n(h?)36 b(The)28+b(simplest)f(w)n(a)n(y)739 1223 y(to)e(de\014ne)h(a)f(tree)g(is)g(as)f+(the)i(result)f(of)g(a)g(series)g(of)g(patc)n(hes)g(applied)g(to)g(the)+h(empt)n(y)f(tree)3543 1192 y Fm(2)3580 1223 y Fx(.)739+1322 y(Th)n(us,)i(the)h(con)n(text)f(of)h(a)f(patc)n(h)h(consists)e(of)+i(the)g(set)f(of)h(patc)n(hes)f(that)h(precede)f(it.)739+1649 y Fq(A.3)135 b(Applying)44 b(patc)l(hes)739 1866+y Fk(A.3.1)112 b(Hunk)38 b(patc)m(hes)739 2038 y Fx(Hunks)28+b(are)e(an)h(example)g(of)h(a)f(complex)g(\014lepatc)n(h.)36+b(A)28 b(h)n(unk)g(is)f(a)g(set)h(of)f(lines)g(of)h(a)f(text)739+2137 y(\014le)f(to)f(b)r(e)h(replaced)f(b)n(y)h(a)f(di\013eren)n(t)h+(set)f(of)h(lines.)36 b(Either)25 b(of)h(these)g(sets)f(ma)n(y)g(b)r(e)+h(empt)n(y)-7 b(,)739 2237 y(whic)n(h)27 b(w)n(ould)h(mean)f(a)g+(deletion)h(or)e(insertion)i(of)f(lines.)739 2522 y Fk(A.3.2)112+b(T)-9 b(ok)m(en)37 b(replace)i(patc)m(hes)739 2693 y+Fx(Although)22 b(most)g(\014lepatc)n(hes)g(will)g(b)r(e)h(h)n(unks,)g+(darcs)e(is)h(clev)n(er)f(enough)h(to)g(supp)r(ort)g(other)739+2793 y(t)n(yp)r(es)d(of)h(c)n(hanges)e(as)h(w)n(ell.)34+b(A)20 b(\\tok)n(en)e(replace")g(patc)n(h)i(replaces)e(all)h(instances)+g(of)h(a)f(giv)n(en)739 2892 y(tok)n(en)32 b(with)h(some)f(other)f(v)n+(ersion.)50 b(A)33 b(tok)n(en,)g(here,)g(is)g(de\014ned)g(b)n(y)f(a)g+(regular)e(expres-)739 2992 y(sion,)25 b(whic)n(h)g(m)n(ust)h(b)r(e)f+(of)g(the)h(simple)f([a{z.)13 b(.)h(.)g(])25 b(t)n(yp)r(e,)h+(indicating)f(whic)n(h)g(c)n(haracters)e(are)739 3092+y(allo)n(w)n(ed)j(in)i(a)f(tok)n(en,)g(with)i(all)e(other)g(c)n+(haracters)e(acting)j(as)f(delimiters.)37 b(F)-7 b(or)27+b(example,)739 3191 y(a)g(C)h(iden)n(ti\014er)f(w)n(ould)g(b)r(e)h(a)g+(tok)n(en)f(with)h(the)g(\015ag)e Fr([A-Za-z_0-9])p Fx(.)863+3301 y(What)i(mak)n(es)d(the)i(tok)n(en)f(replace)g(patc)n(h)h(sp)r+(ecial)f(is)h(the)g(fact)g(that)g(a)f(tok)n(en)g(replace)739+3400 y(can)j(b)r(e)g(merged)f(with)i(almost)e(an)n(y)g(ordinary)g(h)n+(unk,)h(giving)f(exactly)g(what)h(y)n(ou)g(w)n(ould)739+3500 y(w)n(an)n(t.)49 b(F)-7 b(or)32 b(example,)h(y)n(ou)e(migh)n(t)h+(w)n(an)n(t)f(to)h(c)n(hange)f(the)h(patc)n(h)g(t)n(yp)r(e)g+Fr(TokReplace)c Fx(to)739 3600 y Fr(TokenReplace)23 b+Fx(\(if)29 b(y)n(ou)e(decided)h(that)h(sa)n(ving)d(t)n(w)n(o)h(c)n+(haracters)f(of)i(space)f(w)n(as)g(stupid\).)739 3699+y(If)k(y)n(ou)g(did)g(this)h(using)e(h)n(unks,)i(it)g(w)n(ould)e(mo)r+(dify)i(ev)n(ery)e(line)h(where)g Fr(TokReplace)c Fx(o)r(c-)739+3799 y(curred,)i(and)h(quite)g(lik)n(ely)f(pro)n(v)n(ok)n(e)e(a)j+(con\015ict)f(with)h(another)f(patc)n(h)h(mo)r(difying)g(those)739+3899 y(lines.)42 b(On)30 b(the)f(other)g(hand,)h(if)g(y)n(ou)f(did)h+(this)g(using)f(a)g(tok)n(en)g(replace)f(patc)n(h,)i(the)g(only)739+3998 y(c)n(hange)k(that)i(it)g(could)f(con\015ict)g(with)h(w)n(ould)f+(b)r(e)h(if)g(someone)e(else)h(had)h(used)f(the)h(to-)739+4098 y(k)n(en)25 b(\\)p Fr(TokenReplace)p Fx(")19 b(in)25+b(their)g(patc)n(h)g(rather)f(than)i(T)-7 b(okReplace|and)23+b(that)j(actually)739 4197 y(w)n(ould)h(b)r(e)h(a)f(real)g(con\015ict!)+p 739 4290 1146 4 v 831 4344 a Fp(1)866 4367 y Fl(F)-6+b(or)22 b(those)i(comfortable)f(with)g(quan)n(tum)h(mec)n(hanics,)f+(think)g(of)g(a)f(patc)n(h)i(as)f(a)g(quan)n(tum)h(mec)n(hani-)739+4446 y(cal)c(op)r(erator,)h(and)g(the)g(represen)n(tation)g(as)f(the)h+(basis)f(set.)30 b(The)21 b(analogy)g(breaks)f(do)n(wn)h(prett)n(y)g+(quic)n(kly)-6 b(,)739 4525 y(ho)n(w)n(ev)n(er,)25 b(since)f(an)h(op)r+(erator)g(could)g(b)r(e)g(describ)r(ed)f(in)g(an)n(y)h(complete)h+(basis)e(set,)g(while)g(a)h(patc)n(h)g(mo)r(d-)739 4604+y(ifying)f(the)j(\014le)e Fo(foo)h Fl(can)g(only)f(b)r(e)h(describ)r+(ed)f(in)g(the)h(rather)g(small)e(set)i(of)f(con)n(texts)i(whic)n(h)e+(ha)n(v)n(e)i(a)e(\014le)739 4683 y Fo(foo)f Fl(to)h(b)r(e)f(mo)r+(di\014ed.)831 4738 y Fp(2)866 4762 y Fl(This)30 b(is)g(v)n(ery)g+(similar)f(to)i(the)g(second-quan)n(tized)i(picture,)f(in)f(whic)n(h)f+(an)n(y)h(state)h(is)e(seen)h(as)f(the)739 4841 y(result)g(of)g(a)h(n)n+(um)n(b)r(er)g(of)f(creation)h(op)r(erators)g(acting)h(on)f(the)g(v)l+(acuum,)i(and)e(pro)n(vides)f(a)h(similar)e(set)739 4920+y(of)35 b(simpli\014cations|in)f(particular,)k(the)e(exclusion)g+(principle)e(is)h(v)n(ery)g(elegan)n(tly)i(enforced)f(b)n(y)f(the)739+4998 y(prop)r(erties)24 b(of)f(the)i(an)n(ti-hermitian)e(fermion)g+(creation)i(op)r(erators.)p eop end+%%Page: 105 105+TeXDict begin 105 104 bop 291 282 a Fu(A.4.)64 b(P)-7+b(A)g(TCH)28 b(RELA)-7 b(TIONSHIPS)1527 b Fx(105)291+515 y Fq(A.4)134 b(P)l(atc)l(h)46 b(relationships)291+698 y Fx(The)29 b(simplest)h(relationship)f(b)r(et)n(w)n(een)g(t)n(w)n+(o)g(patc)n(hes)g(is)g(that)h(of)g(\\sequen)n(tial")d(patc)n(hes,)291+798 y(whic)n(h)19 b(means)h(that)g(the)g(con)n(text)g(of)g(the)g+(second)f(patc)n(h)h(\(the)h(one)e(on)h(the)g(left\))h(consists)e(of)+291 897 y(the)i(\014rst)f(patc)n(h)g(\(on)h(the)g(righ)n(t\))f(plus)h+(the)g(con)n(text)f(of)h(the)g(\014rst)g(patc)n(h.)34+b(The)21 b(comp)r(osition)291 997 y(of)32 b(t)n(w)n(o)h(patc)n(hes)f+(\(whic)n(h)h(is)g(also)f(a)g(patc)n(h\))h(refers)f(to)h(the)g(patc)n+(h)g(whic)n(h)g(is)g(formed)f(b)n(y)291 1097 y(\014rst)27+b(applying)g(one)g(and)h(then)g(the)g(other.)36 b(The)28+b(comp)r(osition)f(of)g(t)n(w)n(o)g(patc)n(hes,)g Fi(P)2956+1109 y Fm(1)3021 1097 y Fx(and)291 1196 y Fi(P)344 1208+y Fm(2)409 1196 y Fx(is)g(represen)n(ted)g(as)g Fi(P)1089+1208 y Fm(2)1126 1196 y Fi(P)1179 1208 y Fm(1)1217 1196+y Fx(,)g(where)h Fi(P)1561 1208 y Fm(1)1626 1196 y Fx(is)f(to)h(b)r(e)g+(applied)f(\014rst,)h(then)g Fi(P)2651 1208 y Fm(2)2688+1166 y(3)415 1296 y Fx(There)c(is)g(one)g(other)g(v)n(ery)f(useful)i+(relationship)f(that)h(t)n(w)n(o)e(patc)n(hes)h(can)g(ha)n(v)n(e,)g+(whic)n(h)291 1396 y(is)32 b(to)h(b)r(e)g(parallel)e(patc)n(hes,)j+(whic)n(h)e(means)g(that)h(the)g(t)n(w)n(o)f(patc)n(hes)g(ha)n(v)n(e)g+(an)g(iden)n(tical)291 1496 y(con)n(text)27 b(\(i.e.)g(their)h+(represen)n(tation)d(applies)i(to)h(iden)n(tical)f(trees\).)36+b(This)28 b(is)f(represen)n(ted)291 1595 y(b)n(y)e Fi(P)457+1607 y Fm(1)518 1595 y Fn(k)d Fi(P)635 1607 y Fm(2)673+1595 y Fx(.)36 b(Of)26 b(course,)f(t)n(w)n(o)h(patc)n(hes)f(ma)n(y)g+(also)g(ha)n(v)n(e)g(no)g(simple)h(relationship)f(to)h(one)291+1695 y(another.)50 b(In)33 b(that)f(case,)h(if)g(y)n(ou)f(w)n(an)n(t)f+(to)i(do)f(something)g(with)h(them,)h(y)n(ou'll)e(ha)n(v)n(e)f(to)291+1794 y(manipulate)24 b(them)g(with)h(resp)r(ect)f(to)g(other)f(patc)n+(hes)h(un)n(til)h(they)f(are)f(either)h(in)g(sequence)291+1894 y(or)i(in)i(parallel.)415 1994 y(The)f(most)g(fundamen)n(tal)g+(and)g(simple)g(prop)r(ert)n(y)f(of)h(patc)n(hes)f(is)h(that)g(they)g+(m)n(ust)h(b)r(e)291 2094 y(in)n(v)n(ertible.)35 b(The)25+b(in)n(v)n(erse)f(of)h(a)g(patc)n(h)f(is)h(describ)r(ed)g(b)n(y:)36+b Fi(P)2172 2064 y Fd(\000)p Fm(1)2261 2094 y Fx(.)g(In)25+b(the)h(darcs)e(implemen-)291 2194 y(tation,)34 b(the)g(in)n(v)n(erse)e+(is)i(required)e(to)h(b)r(e)h(computable)g(from)f(kno)n(wledge)f(of)h+(the)h(patc)n(h)291 2293 y(only)-7 b(,)35 b(without)f(kno)n(wledge)e+(of)i(its)g(con)n(text,)h(but)f(that)g(\(although)f(con)n(v)n(enien)n+(t\))g(is)h(not)291 2393 y(required)26 b(b)n(y)i(the)f(theory)g(of)h+(patc)n(hes.)291 2561 y Fv(De\014nition)i(1)42 b Fs(The)28+b(inverse)h(of)g(p)l(atch)f Fi(P)40 b Fs(is)28 b Fi(P)1834+2531 y Fd(\000)p Fm(1)1923 2561 y Fs(,)h(which)g(is)f(the)g+(\\simplest")g(p)l(atch)h(for)291 2660 y(which)i(the)f(c)l(omp)l+(osition)h Fi(P)1183 2630 y Fd(\000)p Fm(1)1272 2660+y Fi(P)42 b Fs(makes)30 b(no)g(changes)g(to)g(the)g(tr)l(e)l(e.)291+2828 y Fx(Using)d(this)h(de\014nition,)g(it)g(is)f(trivial)g(to)h(pro)n+(v)n(e)e(the)i(follo)n(wing)e(theorem)h(relating)g(to)h(the)291+2928 y(in)n(v)n(erse)e(of)h(a)g(comp)r(osition)g(of)h(t)n(w)n(o)f(patc)+n(hes.)291 3096 y Fv(Theorem)k(1)41 b Fs(The)31 b(inverse)f(of)h(the)f+(c)l(omp)l(osition)h(of)g(two)e(p)l(atches)i(is)1334+3279 y Fx(\()p Fi(P)1419 3291 y Fm(2)1457 3279 y Fi(P)1510+3291 y Fm(1)1548 3279 y Fx(\))1580 3245 y Fd(\000)p Fm(1)1692+3279 y Fx(=)23 b Fi(P)1845 3244 y Fd(\000)p Fm(1)1833+3302 y(1)1934 3279 y Fi(P)1999 3244 y Fd(\000)p Fm(1)1987+3302 y(2)2088 3279 y Fi(:)291 3464 y Fx(Moreo)n(v)n(er,)18+b(it)i(is)f(p)r(ossible)g(to)g(sho)n(w)g(that)g(the)h(righ)n(t)f(in)n+(v)n(erse)f(of)h(a)g(patc)n(h)g(is)h(equal)e(to)i(its)f(left)291+3563 y(in)n(v)n(erse.)50 b(In)32 b(this)h(resp)r(ect,)h(patc)n(hes)e+(con)n(tin)n(ue)g(to)g(b)r(e)h(analogous)d(to)i(square)g(matrices,)291+3663 y(and)37 b(indeed)g(the)g(pro)r(ofs)g(relating)f(to)h(these)g+(prop)r(erties)f(of)h(the)h(in)n(v)n(erse)d(are)h(en)n(tirely)291+3763 y(analogous)25 b(to)j(the)g(pro)r(ofs)f(in)h(the)g(case)f(of)g+(matrix)h(m)n(ultiplication.)37 b(The)28 b(comp)r(ositions)291+3862 y(pro)r(ofs)19 b(can)g(also)g(readily)g(b)r(e)h(extended)h(to)f+(the)g(comp)r(osition)f(of)h(more)f(than)h(t)n(w)n(o)f(patc)n(hes.)291+4139 y Fq(A.5)134 b(Comm)l(uting)46 b(patc)l(hes)291+4339 y Fk(A.5.1)112 b(Comp)s(osite)38 b(patc)m(hes)291+4493 y Fx(Comp)r(osite)33 b(patc)n(hes)g(are)f(made)i(up)g(of)f(a)g+(series)g(of)h(patc)n(hes)e(in)n(tended)i(to)g(b)r(e)g(applied)291+4593 y(sequen)n(tially)-7 b(.)46 b(They)30 b(are)g(represen)n(ted)g(b)n+(y)g(a)h(list)g(of)g(patc)n(hes,)g(with)g(the)g(\014rst)g(patc)n(h)g+(in)291 4692 y(the)d(list)f(b)r(eing)h(applied)g(\014rst.)p+291 4764 1146 4 v 383 4817 a Fp(3)418 4841 y Fl(This)g(notation)i(is)d+(inspired)h(b)n(y)h(the)g(notation)h(of)e(matrix)h(m)n(ultiplication)f+(or)g(the)i(application)f(of)291 4920 y(op)r(erators)22+b(up)r(on)g(a)g(Hilb)r(ert)f(space.)32 b(In)22 b(the)h(algebra)f(of)f+(patc)n(hes,)j(there)e(is)f(m)n(ultiplication)h(\(i.e.)f(comp)r(o-)291+4998 y(sition\),)i(whic)n(h)h(is)f(asso)r(ciativ)n(e)i(but)f(not)g+(comm)n(utativ)n(e,)i(but)e(no)g(addition)g(or)g(subtraction.)p+eop end+%%Page: 106 106+TeXDict begin 106 105 bop 739 282 a Fx(106)1196 b Fu(APPENDIX)28+b(A.)56 b(THEOR)-7 b(Y)27 b(OF)g(P)-7 b(A)g(TCHES)863+515 y Fx(The)31 b(\014rst)f(w)n(a)n(y)e(\(of)j(only)e(t)n(w)n(o\))h(to)+g(c)n(hange)f(the)i(con)n(text)e(of)h(a)g(patc)n(h)g(is)g(b)n(y)g(comm)+n(u-)739 615 y(tation,)d(whic)n(h)h(is)f(the)h(pro)r(cess)f(of)g(c)n+(hanging)g(the)h(order)e(of)h(t)n(w)n(o)g(sequen)n(tial)g(patc)n(hes.)+739 753 y Fv(De\014nition)k(2)41 b Fs(The)31 b(c)l(ommutation)e(of)i(p)+l(atches)g Fi(P)2384 765 y Fm(1)2451 753 y Fs(and)f Fi(P)2665+765 y Fm(2)2732 753 y Fs(is)g(r)l(epr)l(esente)l(d)g(by)1856+900 y Fi(P)1909 912 y Fm(2)1946 900 y Fi(P)1999 912 y+Fm(1)2060 900 y Fn( )-14 b(!)23 b Fi(P)2288 912 y Fm(1)2326+864 y Fd(0)2349 900 y Fi(P)2402 912 y Fm(2)2440 864 y+Fd(0)2463 900 y Fi(:)739 1047 y Fs(Her)l(e)29 b Fi(P)1002+1017 y Fd(0)990 1068 y Fm(1)1056 1047 y Fs(is)g(intende)l(d)g(to)g+(describ)l(e)h(the)f(same)g(change)h(as)g Fi(P)2671 1059+y Fm(1)2708 1047 y Fs(,)g(with)f(the)g(only)g(di\013er)l(enc)l(e)739+1147 y(b)l(eing)h(that)g Fi(P)1186 1117 y Fd(0)1174 1168+y Fm(1)1241 1147 y Fs(is)g(applie)l(d)i(after)f Fi(P)1874+1117 y Fd(0)1862 1168 y Fm(2)1929 1147 y Fs(r)l(ather)f(than)g(b)l+(efor)l(e)g Fi(P)2655 1159 y Fm(2)2693 1147 y Fs(.)739+1285 y Fx(The)21 b(ab)r(o)n(v)n(e)f(de\014nition)i(is)g(ob)n(viously)e+(rather)g(v)-5 b(ague,)22 b(the)g(reason)e(b)r(eing)h(that)h(what)g(is)+f(the)739 1384 y(\\same)h(c)n(hange")f(has)h(not)h(b)r(een)h+(de\014ned,)g(and)f(w)n(e)f(simply)h(assume)f(\(and)h(hop)r(e\))h(that)+f(the)739 1484 y(co)r(de's)28 b(view)h(of)g(what)g(is)f(the)i(\\same)d+(c)n(hange")g(will)j(matc)n(h)e(those)h(of)f(its)h(h)n(uman)g(users.)+739 1584 y(The)36 b(`)p Fn( )-14 b(!)p Fx(')36 b(op)r(erator)e(should)h+(b)r(e)h(read)f(as)g(something)h(lik)n(e)f(the)h(==)f(op)r(erator)f(in)+i(C,)739 1683 y(indicating)29 b(that)h(the)f(righ)n(t)g(hand)g(side)h+(p)r(erforms)e(iden)n(tical)h(c)n(hanges)f(to)i(the)f(left)h(hand)739+1783 y(side,)h(but)h(the)f(t)n(w)n(o)f(patc)n(hes)g(are)g(in)h(rev)n+(ersed)e(order.)45 b(When)31 b(read)f(in)h(this)g(manner,)g(it)739+1883 y(is)e(clear)e(that)i(comm)n(utation)g(m)n(ust)f(b)r(e)i(a)e(rev)n+(ersible)f(pro)r(cess,)h(and)h(indeed)g(this)g(means)739+1982 y(that)36 b(comm)n(utation)g Fs(c)l(an)42 b Fx(fail,)d(and)d(m)n+(ust)g(fail)g(in)h(certain)e(cases.)61 b(F)-7 b(or)36+b(example,)i(the)739 2082 y(creation)26 b(and)i(deletion)g(of)f(the)h+(same)f(\014le)h(cannot)g(b)r(e)g(comm)n(uted.)37 b(When)28+b(t)n(w)n(o)f(patc)n(hes)739 2181 y(fail)e(to)g(comm)n(utex,)g(it)g(is)+g(said)f(that)h(the)h(second)e(patc)n(h)g(dep)r(ends)i(on)e(the)i+(\014rst,)f(meaning)739 2281 y(that)30 b(it)h(m)n(ust)f(ha)n(v)n(e)f+(the)h(\014rst)g(patc)n(h)g(in)g(its)h(con)n(text)e(\(remem)n(b)r+(ering)h(that)g(the)h(con)n(text)739 2381 y(of)c(a)h(patc)n(h)f(is)g(a)+h(set)f(of)h(patc)n(hes,)f(whic)n(h)g(is)h(ho)n(w)f(w)n(e)g(represen)n+(t)f(a)i(tree\).)3103 2351 y Fm(4)739 2590 y Fv(Merge)82+b Fx(The)26 b(second)g(w)n(a)n(y)e(one)i(can)g(c)n(hange)e(the)j(con)n+(text)e(of)h(a)g(patc)n(h)g(is)g(b)n(y)f(a)h Fv(merge)739+2690 y Fx(op)r(eration.)52 b(A)33 b(merge)f(is)h(an)g(op)r(eration)f+(that)h(tak)n(es)f(t)n(w)n(o)g(parallel)g(patc)n(hes)h(and)f(giv)n(es)+739 2790 y(a)e(pair)f(of)h(sequen)n(tial)g(patc)n(hes.)44+b(The)30 b(merge)f(op)r(eration)g(is)h(represen)n(ted)f(b)n(y)h(the)g+(arro)n(w)739 2889 y(\\=)-15 b Fn(\))p Fx(".)739 3027+y Fv(De\014nition)31 b(3)41 b Fs(The)36 b(r)l(esult)f(of)h(a)g(mer)l+(ge)g(of)g(two)g(p)l(atches,)i Fi(P)2751 3039 y Fm(1)2824+3027 y Fs(and)e Fi(P)3044 3039 y Fm(2)3117 3027 y Fs(is)g(one)g(of)g+(two)739 3127 y(p)l(atches,)31 b Fi(P)1120 3097 y Fd(0)1108+3147 y Fm(1)1175 3127 y Fs(and)g Fi(P)1402 3097 y Fd(0)1390+3147 y Fm(2)1427 3127 y Fs(,)f(which)i(satisfy)e(the)g(r)l+(elationship:)1632 3274 y Fi(P)1685 3286 y Fm(2)1745+3274 y Fn(k)23 b Fi(P)1863 3286 y Fm(1)1923 3274 y Fx(=)-14+b Fn(\))23 b Fi(P)2133 3286 y Fm(2)2171 3238 y Fd(0)2194+3274 y Fi(P)2247 3286 y Fm(1)2308 3274 y Fn( )-14 b(!)23+b Fi(P)2536 3286 y Fm(1)2574 3238 y Fd(0)2597 3274 y+Fi(P)2650 3286 y Fm(2)2687 3274 y Fi(:)739 3421 y Fx(Note)h(that)g(the)+h(sequen)n(tial)e(patc)n(hes)h(resulting)f(from)h(a)g(merge)f(are)g+Fs(r)l(e)l(quir)l(e)l(d)33 b Fx(to)24 b(comm)n(u-)739+3521 y(tex.)35 b(This)21 b(is)h(an)f(imp)r(ortan)n(t)g(consideration,)g+(as)g(without)h(it)g(most)f(of)h(the)g(manipulations)739+3621 y(w)n(e)33 b(w)n(ould)g(lik)n(e)g(to)g(p)r(erform)f(w)n(ould)h+(not)h(b)r(e)f(p)r(ossible.)54 b(The)33 b(other)g(imp)r(ortan)n(t)g+(fact)g(is)739 3720 y(that)e(a)f(merge)g Fs(c)l(annot)i(fail)p+Fx(.)48 b(Naiv)n(ely)-7 b(,)31 b(those)f(t)n(w)n(o)g(requiremen)n(ts)g+(seem)g(con)n(tradictory)-7 b(.)739 3820 y(In)28 b(realit)n(y)-7+b(,)28 b(what)g(it)h(means)e(is)i(that)f(the)h(result)f(of)g(a)g(merge)+f(ma)n(y)h(b)r(e)g(a)g(patc)n(h)g(whic)n(h)g(is)739 3919+y(m)n(uc)n(h)f(more)g(complex)g(than)h(an)n(y)f(w)n(e)g(ha)n(v)n(e)f(y)+n(et)i(considered)2676 3889 y Fm(5)2712 3919 y Fx(.)p+739 3975 1146 4 v 831 4028 a Fp(4)866 4052 y Fl(The)20+b(fact)h(that)g(comm)n(utation)g(can)g(fail)e(mak)n(es)h(a)g(h)n(uge)h+(di\013erence)g(in)e(the)i(whole)f(patc)n(h)h(formalism.)739+4131 y(It)c(ma)n(y)g(b)r(e)g(p)r(ossible)f(to)i(create)f(a)g(formalism)+e(in)h(whic)n(h)h(comm)n(utation)h(alw)n(a)n(ys)f(succeeds,)i(with)e+(the)g(result)739 4209 y(of)25 b(what)h(w)n(ould)g(otherwise)g(b)r(e)g+(a)g(comm)n(utation)h(that)g(fails)d(b)r(eing)i(something)h(lik)n(e)e+(a)g(virtual)h(particle)739 4288 y(\(whic)n(h)e(can)g(violate)g+(conserv)l(ation)h(of)f(energy\),)g(and)g(it)f(ma)n(y)h(b)r(e)g(that)h+(suc)n(h)f(a)f(formalism)f(w)n(ould)h(allo)n(w)739 4367+y(strict)d(mathematical)h(pro)r(ofs)f(\(whereas)h(those)g(used)f(in)g+(the)g(curren)n(t)h(formalism)d(are)i(mostly)g(only)g(hand)739+4446 y(w)n(a)n(ving)25 b(\\ph)n(ysicist")g(pro)r(ofs\).)34+b(Ho)n(w)n(ev)n(er,)24 b(I'm)h(not)g(sure)f(ho)n(w)h(y)n(ou'd)g(deal)g+(with)f(a)h(request)g(to)g(delete)h(a)739 4525 y(\014le)e(that)h(has)g+(not)g(y)n(et)g(b)r(een)g(created,)g(for)f(example.)33+b(Ob)n(viously)24 b(y)n(ou'd)h(need)g(to)f(create)i(some)e(kind)g(of)+739 4604 y(an)n(ti\014le,)29 b(whic)n(h)f(w)n(ould)h(annihilate)f(with)+g(the)h(\014le)f(when)h(that)g(\014le)f(\014nally)g(got)h(created,)h+(but)f(I'm)e(not)739 4683 y(en)n(tirely)21 b(sure)g(ho)n(w)g(I'd)g(go)g+(ab)r(out)h(doing)g(this.)47 b(\177)-52 b Ff(_)20 b Fl(So)h(I'm)g(stic)+n(king)g(with)g(m)n(y)g(hand)h(w)n(a)n(ving)f(formalism.)831+4738 y Fp(5)866 4762 y Fl(Alas,)h(I)h(don't)g(kno)n(w)h(ho)n(w)f(to)g+(pro)n(v)n(e)h(that)g(the)g(t)n(w)n(o)f(constrain)n(ts)h(ev)n(en)g+Fc(c)l(an)k Fl(b)r(e)c(satis\014ed.)31 b(The)23 b(b)r(est)739+4841 y(I)e(ha)n(v)n(e)g(b)r(een)h(able)f(to)g(do)g(is)f(to)h(b)r(eliev)+n(e)g(that)h(they)g(can)f(b)r(e)g(satis\014ed,)g(and)h(to)f(b)r(e)g+(unable)g(to)g(\014nd)g(an)g(case)739 4920 y(in)g(whic)n(h)g(m)n(y)g+(implemen)n(tation)h(fails)e(to)i(satisfy)f(them.)31+b(These)21 b(t)n(w)n(o)h(requiremen)n(ts)g(are)f(the)h(foundation)739+4998 y(of)h(the)i(en)n(tire)f(theory)g(of)g(patc)n(hes)h(\(ha)n(v)n(e)g+(y)n(ou)f(b)r(een)h(coun)n(ting)g(ho)n(w)f(man)n(y)g(foundations)h(it)f+(has?\).)p eop end+%%Page: 107 107+TeXDict begin 107 106 bop 291 282 a Fu(A.5.)64 b(COMMUTING)28+b(P)-7 b(A)g(TCHES)1551 b Fx(107)291 515 y Fk(A.5.2)112+b(Ho)m(w)37 b(merges)h(are)f(actually)i(p)s(erformed)291+684 y Fx(The)22 b(constrain)n(t)g(that)h(an)n(y)f(t)n(w)n(o)g+(compatible)g(patc)n(hes)g(\(patc)n(hes)g(whic)n(h)h(can)f+(successfully)291 783 y(b)r(e)29 b(applied)g(to)g(the)h(same)e(tree\))h+(can)g(b)r(e)h(merged)e(is)h(actually)g(quite)g(di\016cult)h(to)f+(apply)-7 b(.)291 883 y(The)20 b(ab)r(o)n(v)n(e)f(merge)h(constrain)n+(ts)f(also)g(imply)i(that)g(the)g(result)f(of)g(a)h(series)e(of)h+(merges)g(m)n(ust)291 983 y(b)r(e)26 b(indep)r(enden)n(t)i(of)e(the)h+(order)e(of)h(the)h(merges.)35 b(So)27 b(I'm)f(putting)h(a)f(whole)g+(section)g(here)291 1082 y(for)j(the)i(in)n(terested)f(to)g(see)f(what)+h(algorithms)f(I)h(use)g(to)g(actually)g(p)r(erform)g(the)g(merges)291+1182 y(\(as)d(this)h(is)f(prett)n(y)g(close)g(to)h(b)r(eing)f(the)h+(most)g(di\016cult)g(part)f(of)h(the)g(co)r(de\).)415+1290 y(The)34 b(\014rst)f(case)f(is)h(that)h(in)g(whic)n(h)f(the)h(t)n+(w)n(o)e(merges)g(don't)i(actually)e(con\015ict,)j(but)291+1389 y(don't)29 b(trivially)g(merge)g(either)h(\(e.g.)f(h)n(unk)h(patc)+n(hes)f(on)h(the)g(same)f(\014le,)h(where)g(the)g(line)291+1489 y(n)n(um)n(b)r(er)c(has)h(to)f(b)r(e)i(shifted)f(as)f(they)h(are)f+(merged\).)36 b(This)27 b(kind)g(of)g(merge)f(can)h(actually)291+1588 y(b)r(e)h(v)n(ery)e(elegan)n(tly)h(dealt)g(with)h(using)f(only)h+(comm)n(utation)f(and)g(in)n(v)n(ersion.)415 1696 y(There)33+b(is)g(a)g(handy)g(little)h(theorem)f(whic)n(h)g(is)h(immensely)f+(useful)h(when)f(trying)g(to)291 1796 y(merge)26 b(t)n(w)n(o)h(patc)n+(hes.)291 1994 y Fv(Theorem)k(2)41 b Fi(P)850 1964 y+Fd(0)838 2015 y Fm(2)876 1994 y Fi(P)929 2006 y Fm(1)994+1994 y Fn( )-14 b(!)29 b Fi(P)1240 1964 y Fd(0)1228 2015+y Fm(1)1265 1994 y Fi(P)1318 2006 y Fm(2)1388 1994 y+Fs(if)34 b(and)f(only)g(if)h Fi(P)1968 1959 y Fd(0\000)p+Fm(1)1956 2016 y(1)2076 1994 y Fi(P)2141 1964 y Fd(0)2129+2015 y Fm(2)2194 1994 y Fn( )-14 b(!)29 b Fi(P)2428 2006+y Fm(2)2465 1994 y Fi(P)2530 1959 y Fd(\000)p Fm(1)2518+2016 y(1)2619 1994 y Fs(,)34 b(pr)l(ovide)l(d)g(b)l(oth)291+2094 y(c)l(ommutations)29 b(suc)l(c)l(e)l(e)l(d.)38 b(If)31+b(either)f(c)l(ommutex)f(fails,)j(this)e(the)l(or)l(em)g(do)l(es)g(not)+g(apply.)291 2284 y Fx(This)j(can)g(easily)g(b)r(e)h(pro)n(v)n(en)e(b)n+(y)h(m)n(ultiplying)h(b)r(oth)g(sides)f(of)g(the)h(\014rst)f(comm)n+(utation)291 2384 y(b)n(y)d Fi(P)474 2348 y Fd(0\000)p+Fm(1)462 2406 y(1)613 2384 y Fx(on)g(the)h(left,)h(and)f(b)n(y)f+Fi(P)1397 2348 y Fd(\000)p Fm(1)1385 2406 y(1)1517 2384+y Fx(on)g(the)h(righ)n(t.)46 b(Besides)30 b(b)r(eing)g(used)h(in)g+(merging,)291 2483 y(this)38 b(theorem)g(is)g(also)f(useful)i(in)g(the)+g(recursiv)n(e)d(comm)n(utations)i(of)g(mergers.)67 b(F)-7+b(rom)291 2583 y(Theorem)29 b(2,)i(w)n(e)f(see)f(that)i(the)g(merge)e+(of)h Fi(P)1727 2595 y Fm(1)1795 2583 y Fx(and)g Fi(P)2024+2553 y Fd(0)2012 2604 y Fm(2)2080 2583 y Fx(is)g(simply)h(the)f(comm)n+(utation)g(of)291 2683 y Fi(P)344 2695 y Fm(2)413 2683+y Fx(with)j Fi(P)672 2647 y Fd(\000)p Fm(1)660 2705 y(1)793+2683 y Fx(\(making)e(sure)g(to)h(do)g(the)g(comm)n(utation)g(the)g+(righ)n(t)f(w)n(a)n(y\).)49 b(Of)32 b(course,)291 2782+y(if)f(this)f(comm)n(utation)g(fails,)h(the)g(patc)n(hes)f(con\015ict.)+46 b(Moreo)n(v)n(er,)28 b(one)i(m)n(ust)h(c)n(hec)n(k)f(that)291+2882 y(the)23 b(merged)f(result)h(actually)f(comm)n(utes)h(with)h+Fi(P)1877 2894 y Fm(1)1914 2882 y Fx(,)g(as)f(the)g(theorem)f(applies)h+(only)g(when)291 2982 y Fs(b)l(oth)34 b Fx(comm)n(utations)27+b(are)f(successful.)415 3089 y(Of)k(course,)g(there)f(are)g(patc)n(hes)+h(that)g(actually)g(con\015ict,)g(meaning)g(a)f(merge)g(where)291+3189 y(the)k(t)n(w)n(o)f(patc)n(hes)g(truly)h(cannot)g(b)r(oth)g(b)r(e)+g(applied)g(\(e.g.)g(trying)g(to)f(create)g(a)h(\014le)g(and)291+3289 y(a)28 b(directory)g(with)i(the)f(same)g(name\).)42+b(W)-7 b(e)29 b(deal)g(with)h(this)f(case)g(b)n(y)f(creating)g(a)h(sp)r+(ecial)291 3388 y(kind)e(of)g(patc)n(h)g(to)g(supp)r(ort)g(the)h+(merge,)e(whic)n(h)h(w)n(e)g(will)g(call)g(a)g(\\merger".)34+b(Basically)-7 b(,)26 b(a)291 3488 y(merger)k(is)h(a)h(patc)n(h)f(that)+h(con)n(tains)f(the)h(t)n(w)n(o)f(patc)n(hes)g(that)h(con\015icted,)h+(and)e(instructs)291 3587 y(darcs)25 b(basically)g(to)h(resolv)n(e)e+(the)i(con\015ict.)37 b(By)26 b(construction)f(a)h(merger)e(will)j+(satisfy)f(the)291 3687 y(comm)n(utation)18 b(prop)r(ert)n(y)h(\(see)g+(De\014nition)h(3\))f(that)h(c)n(haracterizes)d(all)i(merges.)33+b(Moreo)n(v)n(er)291 3787 y(the)22 b(merger's)f(prop)r(erties)h(are)f+(what)h(mak)n(es)g(the)h(order)e(of)h(merges)f(unimp)r(ortan)n(t)i+(\(whic)n(h)291 3886 y(is)k(a)g(rather)g(critical)g(prop)r(ert)n(y)f+(for)h(darcs)g(as)g(a)g(whole\).)415 3994 y(The)35 b(job)g(of)h(a)e+(merger)g(is)h(basically)f(to)h(undo)g(the)h(t)n(w)n(o)e(con\015icting)+h(patc)n(hes,)h(and)291 4094 y(then)d(apply)f(some)g(sort)f(of)i(a)f+(\\resolution")e(of)i(the)h(t)n(w)n(o)f(instead.)51 b(In)33+b(the)g(case)e(of)i(t)n(w)n(o)291 4193 y(con\015icting)24+b(h)n(unks,)g(this)h(will)f(lo)r(ok)g(m)n(uc)n(h)g(lik)n(e)g(what)g+(CVS)h(do)r(es,)f(where)g(it)h(inserts)e(b)r(oth)291+4293 y(v)n(ersions)35 b(in)n(to)h(the)i(\014le.)65 b(In)37+b(general,)h(of)f(course,)h(the)f(t)n(w)n(o)g(con\015icting)f(patc)n+(hes)h(ma)n(y)291 4393 y(b)r(oth)c(b)r(e)h(mergers)e(themselv)n(es,)i+(in)g(whic)n(h)f(case)g(the)g(situation)h(is)f(considerably)f(more)291+4492 y(complicated.)415 4600 y(Muc)n(h)24 b(of)h(the)g(merger)e(co)r+(de)h(dep)r(ends)h(on)f(a)g(routine)g(whic)n(h)g(recreates)e(from)i(a)g+(single)291 4700 y(merger)30 b(the)i(en)n(tire)f(sequence)g(of)h(patc)n+(hes)e(whic)n(h)i(led)g(up)g(to)f(that)h(merger)e(\(this)i(is,)h(of)291+4799 y(course,)21 b(assuming)f(that)h(this)h(is)f(the)g(complicated)g+(general)f(case)g(of)h(a)g(merger)e(of)j(mergers)291+4899 y(of)37 b(mergers\).)64 b(This)37 b(\\un)n(wind")f(pro)r(cedure)h+(is)g(rather)f(complicated,)j(but)f(absolutely)291 4998+y(critical)e(to)h(the)g(merger)e(co)r(de,)40 b(as)c(without)h(it)g(w)n+(e)g(w)n(ouldn't)g(ev)n(en)f(b)r(e)i(able)e(to)h(undo)p+eop end+%%Page: 108 108+TeXDict begin 108 107 bop 739 282 a Fx(108)1196 b Fu(APPENDIX)28+b(A.)56 b(THEOR)-7 b(Y)27 b(OF)g(P)-7 b(A)g(TCHES)739+515 y Fx(the)28 b(e\013ects)g(of)g(the)g(patc)n(hes)f(in)n(v)n(olv)n+(ed)g(in)h(the)g(merger,)e(since)i(w)n(e)f(w)n(ouldn't)h(kno)n(w)f+(what)739 615 y(patc)n(hes)g(w)n(ere)f(all)i(in)n(v)n(olv)n(ed)e(in)i+(it.)863 715 y(Basically)-7 b(,)27 b(un)n(wind)h(tak)n(es)e(a)h(merger)+g(suc)n(h)g(as)739 881 y Fr(M\()43 b(M\(A,B\),)d(M\(A,M\(C,D\)\)\))739+1047 y Fx(F)-7 b(rom)27 b(whic)n(h)h(it)g(recreates)d(a)j(merge)e+(history:)739 1213 y Fr(C)739 1312 y(A)739 1412 y(M\(A,B\))739+1512 y(M\()43 b(M\(A,B\),)d(M\(A,M\(C,D\)\)\))739 1678+y Fx(\(F)-7 b(or)26 b(the)h(curious,)e(y)n(es)h(I)h(can)f(easily)f(un)n+(wind)i(this)f(merger)f(in)i(m)n(y)f(head)g([and)h(on)f(pap)r(er)739+1777 y(can)f(un)n(wind)h(insanely)f(more)g(complex)g(mergers]|that's)g+(what)g(comes)g(of)h(w)n(orking)e(for)739 1877 y(a)38+b(few)h(mon)n(ths)g(on)f(an)h(algorithm.\))69 b(Let's)39+b(start)f(with)i(a)e(simple)h(un)n(winding.)70 b(The)739+1976 y(merger)27 b Fr(M\(A,B\))e Fx(simply)k(means)e(that)i(t)n(w)n(o)e+(patc)n(hes)g(\()p Fr(A)h Fx(and)g Fr(B)p Fx(\))h(con\015icted,)f(and)g+(of)g(the)739 2076 y(t)n(w)n(o)h(of)g(them)i Fr(A)e Fx(is)g(\014rst)h+(in)g(the)g(history)-7 b(.)42 b(The)30 b(last)f(t)n(w)n(o)g(patc)n(hes)+g(in)h(the)g(un)n(winding)f(of)739 2176 y(an)n(y)e(merger)f(are)h(alw)n+(a)n(ys)e(just)j(this)g(easy)-7 b(.)36 b(So)28 b(this)f(un)n(winds)h+(to:)739 2342 y Fr(A)739 2441 y(M\(A,B\))739 2607 y Fx(What)35+b(ab)r(out)g(a)f(merger)g(of)h(mergers?)57 b(Ho)n(w)34+b(ab)r(out)h Fr(M\(A,M\(C,D\)\))p Fx(.)30 b(In)35 b(this)h(case)e(w)n+(e)739 2707 y(kno)n(w)27 b(the)h(t)n(w)n(o)e(most)i(recen)n(t)f(patc)n+(hes)g(are:)739 2873 y Fr(A)739 2973 y(M\(A,M\(C,D\)\))739+3139 y Fx(But)e(ob)n(viously)f(the)h(un)n(winding)g(isn't)h(complete,)f+(since)g(w)n(e)g(don't)g(y)n(et)g(see)f(where)h Fr(C)f+Fx(and)739 3238 y Fr(D)k Fx(came)f(from.)38 b(In)29 b(this)f(case)f(w)n+(e)h(tak)n(e)f(the)i(un)n(winding)f(of)g Fr(M\(C,D\))e+Fx(and)i(drop)f(its)h(latest)739 3338 y(patc)n(h)20 b(\(whic)n(h)i(is)e+Fr(M\(C,D\))f Fx(itself)6 b(\))22 b(and)f(place)f(that)h(at)g(the)g(b)r+(eginning)g(of)g(our)f(patc)n(h)h(train:)739 3504 y Fr(C)739+3604 y(A)739 3703 y(M\(A,M\(C,D\)\))739 3869 y Fx(As)28+b(w)n(e)g(lo)r(ok)f(at)i Fr(M\()42 b(M\(A,B\),)f(M\(A,M\(C,D\)\)\))p+Fx(,)23 b(w)n(e)28 b(consider)f(the)i(un)n(windings)f(of)g(eac)n(h)739+3969 y(of)f(its)h(subpatc)n(hes:)1175 4135 y Fr(C)739+4235 y(A)392 b(A)739 4334 y(M\(A,B\))172 b(M\(A,M\(C,D\)\))739+4500 y Fx(As)28 b(w)n(e)g(did)g(with)g Fr(M\(A,M\(C,D\)\))p+Fx(,)c(w)n(e'll)k(drop)f(the)h(\014rst)g(patc)n(h)g(on)f(the)i(righ)n+(t)e(and)h(insert)739 4600 y(the)g(\014rst)f(patc)n(h)h(on)f(the)h+(left.)38 b(That)28 b(mo)n(v)n(es)e(us)i(up)g(to)f(the)i(t)n(w)n(o)d+Fr(A)p Fx('s.)37 b(Since)28 b(these)g(agree,)739 4700+y(w)n(e)i(can)g(use)g(just)h(one)f(of)h(them)g(\(they)g(\\should")e+(agree\).)44 b(That)31 b(lea)n(v)n(es)d(us)j(with)g(the)g+Fr(C)739 4799 y Fx(whic)n(h)c(go)r(es)g(\014rst.)863+4899 y(The)41 b(catc)n(h)f(is)h(that)g(things)f(don't)h(alw)n(a)n(ys)e+(turn)h(out)h(this)g(easily)-7 b(.)75 b(There)40 b(is)h(no)739+4998 y(guaran)n(tee)22 b(that)i(the)h(t)n(w)n(o)e Fr(A)p+Fx('s)g(w)n(ould)h(come)f(out)h(at)g(the)g(same)g(time,)h(and)f(if)g+(they)g(didn't,)p eop end+%%Page: 109 109+TeXDict begin 109 108 bop 291 282 a Fu(A.6.)64 b(CONFLICTS)2036+b Fx(109)291 515 y(w)n(e'd)20 b(ha)n(v)n(e)g(to)h(rearrange)c(things)k+(un)n(til)g(they)g(did.)35 b(Or)20 b(if)i(there)e(w)n(as)g(no)h(w)n(a)n+(y)e(to)i(rearrange)291 615 y(things)h(so)g(that)h(they)f(w)n(ould)g+(agree,)g(w)n(e)h(ha)n(v)n(e)e(to)h(go)g(on)g(to)h(plan)f(B,)g(whic)n+(h)h(I)f(will)h(explain)291 715 y(no)n(w.)415 818 y(Consider)32+b(the)i(case)e(of)h Fr(M\()43 b(M\(A,B\),)e(M\(C,D\)\))p+Fx(.)30 b(W)-7 b(e)34 b(can)e(easily)h(un)n(wind)g(the)h(t)n(w)n(o)291+918 y(subpatc)n(hes)291 1101 y Fr(A)391 b(C)291 1201+y(M\(A,B\))171 b(M\(C,D\))291 1380 y Fx(No)n(w)28 b(w)n(e)g(need)h(to)g+(reconcile)f(the)h Fr(A)g Fx(and)f Fr(C)p Fx(.)h(Ho)n(w)f(do)h(w)n(e)f+(do)h(this?)41 b(W)-7 b(ell,)29 b(as)g(usual,)g(the)291+1479 y(solution)i(is)g(to)h(use)f(the)h(most)f(w)n(onderful)g(Theorem)g+(2.)49 b(In)31 b(this)h(case)f(w)n(e)g(ha)n(v)n(e)g(to)g(use)291+1579 y(it)f(in)h(the)f(rev)n(erse)e(of)j(ho)n(w)e(w)n(e)h(used)g(it)h+(when)f(merging,)g(since)g(w)n(e)g(kno)n(w)f(that)h Fr(A)g+Fx(and)g Fr(C)291 1679 y Fx(could)d(either)h(one)g(b)r(e)g(the)g+Fs(last)37 b Fx(patc)n(h)27 b(applied)h(b)r(efore)g Fr(M\(A,B\))d+Fx(or)i Fr(M\(C,D\))p Fx(.)f(So)i(w)n(e)f(can)291 1778+y(\014nd)h Fr(C')e Fx(using)1386 1891 y Fi(A)1448 1856+y Fd(\000)p Fm(1)1537 1891 y Fi(C)j Fn( )-14 b(!)24 b+Fi(C)1866 1856 y Fd(0)1889 1891 y Fi(A)1951 1856 y Fd(0\000)p+Fm(1)291 2053 y Fx(Giving)j(an)g(un)n(winding)h(of)291+2236 y Fr(C')291 2336 y(A)291 2435 y(M\(A,B\))291 2535+y(M\()42 b(M\(A,B\),)f(M\(C,D\))g(\))291 2714 y Fx(There)28+b(is)h(a)f(bit)h(more)f(complexit)n(y)h(to)f(the)i(un)n(winding)e(pro)r+(cess)g(\(mostly)h(ha)n(ving)f(to)g(do)291 2814 y(with)33+b(cases)f(where)g(y)n(ou)h(ha)n(v)n(e)f(deep)r(er)g(nesting\),)j(but)f+(I)f(think)g(the)h(general)d(principles)291 2913 y(that)c(are)g(follo)n+(w)n(ed)g(are)f(prett)n(y)i(m)n(uc)n(h)f(included)h(in)g(the)g(ab)r(o)n+(v)n(e)e(discussion.)291 3210 y Fq(A.6)134 b(Con\015icts)291+3400 y Fx(There)29 b(are)h(a)g(couple)g(of)g(simple)h(constrain)n(ts)e+(on)h(the)h(routine)f(whic)n(h)g(determines)h(ho)n(w)291+3500 y(to)39 b(resolv)n(e)e(t)n(w)n(o)h(con\015icting)h(patc)n(hes)f+(\(whic)n(h)i(is)f(called)g(`glump'\).)71 b(These)39+b(m)n(ust)h(b)r(e)291 3599 y(satis\014ed)c(in)i(order)e(that)i(the)f+(result)g(of)h(a)f(series)f(of)h(merges)f(is)i(alw)n(a)n(ys)d(indep)r+(enden)n(t)291 3699 y(of)e(their)f(order.)52 b(Firstly)-7+b(,)34 b(the)g(output)f(of)g(glump)g(cannot)g(c)n(hange)f(when)h(the)g+(order)f(of)291 3799 y(the)g(t)n(w)n(o)g(con\015icting)f(patc)n(hes)h+(is)g(switc)n(hed.)50 b(If)33 b(it)g(did,)g(then)g(comm)n(uting)f(the)g+(merger)291 3898 y(could)e(c)n(hange)f(the)i(resulting)e(patc)n(h,)i+(whic)n(h)g(w)n(ould)f(b)r(e)g(bad.)45 b(Secondly)-7+b(,)31 b(the)g(result)f(of)291 3998 y(the)d(merge)f(of)h(three)f(\(or)h+(more\))f(con\015icting)h(patc)n(hes)f(cannot)h(dep)r(end)g(on)g(the)g+(order)f(in)291 4098 y(whic)n(h)h(the)h(merges)f(are)f(p)r(erformed.)+415 4201 y(The)40 b(con\015ict)g(resolution)f(co)r(de)h(\(glump\))g(b)r+(egins)g(b)n(y)g(\\unra)n(v)n(elling")d(the)j(merger)291+4301 y(in)n(to)c(a)g(set)h(of)g(sequences)f(of)h(patc)n(hes.)63+b(Eac)n(h)36 b(sequence)g(of)h(patc)n(hes)f(corresp)r(onds)f(to)291+4401 y(one)28 b(non-con\015icted)h(patc)n(h)f(that)i(got)e(merged)h+(together)f(with)h(the)h(others.)40 b(The)29 b(result)291+4500 y(of)k(the)h(unra)n(v)n(elling)d(of)j(a)f(series)f(of)h(merges)g+(m)n(ust)g(ob)n(viously)f(b)r(e)i(indep)r(enden)n(t)g(of)g(the)291+4600 y(order)28 b(in)h(whic)n(h)h(those)f(merges)f(are)g(p)r(erformed.)+42 b(This)30 b(unra)n(v)n(elling)d(co)r(de)j(\(whic)n(h)f(uses)291+4700 y(the)e(un)n(wind)g(co)r(de)g(men)n(tioned)g(ab)r(o)n(v)n(e\))f+(uses)g(probably)g(the)h(second)g(most)f(complicated)291+4799 y(algorithm.)49 b(F)-7 b(ortunately)g(,)33 b(if)g(w)n(e)f(can)g+(successfully)g(unra)n(v)n(el)e(the)j(merger,)f(almost)g(an)n(y)291+4899 y(function)26 b(of)g(the)h(unra)n(v)n(elled)e(merger)f+(satis\014es)i(the)g(t)n(w)n(o)f(constrain)n(ts)g(men)n(tioned)h(ab)r+(o)n(v)n(e)291 4998 y(that)h(the)h(con\015ict)g(resolution)f(co)r(de)g+(m)n(ust)h(satisfy)-7 b(.)p eop end+%%Page: 110 110+TeXDict begin 110 109 bop 739 282 a Fx(110)1196 b Fu(APPENDIX)28+b(A.)56 b(THEOR)-7 b(Y)27 b(OF)g(P)-7 b(A)g(TCHES)739+515 y Fq(A.7)135 b(P)l(atc)l(h)45 b(string)g(formatting)739+697 y Fx(Of)36 b(course,)g(in)g(order)e(to)i(store)e(our)h(patc)n(hes)g+(in)h(a)f(\014le,)j(w)n(e'll)e(ha)n(v)n(e)e(to)i(sa)n(v)n(e)e(them)i+(as)739 797 y(some)30 b(sort)g(of)g(strings.)46 b(The)31+b(con)n(v)n(en)n(tion)e(is)h(that)h(eac)n(h)f(patc)n(h)h(string)f(will)+h(end)f(with)i(a)739 896 y(newline,)c(but)g(on)f(parsing)g(w)n(e)g+(skip)g(an)n(y)g(amoun)n(t)g(of)h(whitespace)f(b)r(et)n(w)n(een)g(patc)+n(hes.)739 1112 y Fv(Merger)39 b(patc)m(hes)84 b Fx(Merge)33+b(t)n(w)n(o)h(patc)n(hes.)56 b(The)34 b(MER)n(GER)-9+b(VERSION)34 b(is)g(included)739 1212 y(to)28 b(allo)n(w)e(some)h+(degree)g(of)h(bac)n(kw)n(ards)d(compatibilit)n(y)j(if)g(the)g(merger)f+(algorithm)f(needs)739 1311 y(to)h(b)r(e)h(c)n(hanged.)739+1477 y Fr(merger)41 b(MERGERVERSION)739 1577 y(<first)g(patch>)739+1677 y(<second)g(patch>)739 1893 y Fv(Named)f(patc)m(hes)84+b Fx(Named)36 b(patc)n(hes)f(are)f(displa)n(y)n(ed)h(as)g(a)g(\\patc)n+(h)g(id")g(whic)n(h)h(is)f(in)739 1992 y(square)25 b(brac)n(k)n(ets,)g+(follo)n(w)n(ed)h(b)n(y)g(a)g(patc)n(h.)37 b(Optionally)-7+b(,)26 b(after)g(the)h(patc)n(h)f(id)h(\(but)h(b)r(efore)739+2092 y(the)g(patc)n(h)f(itself)6 b(\))28 b(can)f(come)g(a)g(list)h(of)f+(dep)r(endencies)h(surrounded)e(b)n(y)h(angle)g(brac)n(k)n(ets.)739+2191 y(Eac)n(h)f(dep)r(endency)i(consists)f(of)h(a)f(patc)n(h)g(id.)p+eop end+%%Page: 111 111+TeXDict begin 111 110 bop 291 1138 a Ft(App)5 b(endix)64+b(B)291 1553 y Fw(DarcsRep)6 b(o)78 b(format)291 1985+y Fx(A)36 b(rep)r(ository)f(consists)g(of)i(a)f(w)n(orking)e(directory)+-7 b(,)38 b(whic)n(h)e(has)g(within)h(it)f(a)g(directory)291+2084 y(called)18 b Fr(_darcs)p Fx(.)31 b(There)18 b(m)n(ust)g(also)g(b)+r(e)g(a)g(sub)r(directory)g(within)h Fr(_darcs)d Fx(named)i+Fr(patches)p Fx(.)291 2184 y(The)27 b Fr(patches)d Fx(directory)i(con)n+(tains)g(the)h(actual)g(patc)n(hes)f(whic)n(h)h(are)g(in)g(the)g(rep)r+(ository)-7 b(.)291 2284 y(There)28 b(m)n(ust)h(also)f(b)r(e)i(a)f+Fs(pristine)i(tr)l(e)l(e)p Fx(,)f(whic)n(h)f(ma)n(y)f(either)h(b)r(e)g+(a)g(directory)f(con)n(taining)291 2383 y(a)g(cac)n(he)f(of)h(the)h(v)n+(ersion)e(of)i(the)f(tree)g(whic)n(h)h(has)f(b)r(een)h(recorded,)e(or)g+(a)h(stub,)h(and)g(ma)n(y)291 2483 y(b)r(e)f(named)f(either)h(\\curren)+n(t")d(or)i(\\pristine".)415 2583 y Fs(W)-6 b(ARNING!)40+b Fx(Viewing)30 b(\014les)g(in)g(the)h(pristine)f(cac)n(he)f(is)h(p)r+(erfectly)g(acceptable,)g(but)291 2682 y(if)39 b(y)n(ou)g(view)g(them)h+(with)f(an)g(editor)g(\(e.g.)g(vi)g(or)g(Emacs\),)i(that)f(editor)e(ma)+n(y)h(create)291 2782 y(temp)r(orary)28 b(\014les)i(in)g(the)g+(pristine)f(tree)h(\()p Fr(_darcs/pristine/)23 b Fx(or)29+b Fr(_darcs/current/)o Fx(\),)291 2881 y(whic)n(h)c(will)g(temp)r+(orarily)f(cause)h(y)n(our)f(rep)r(ository)f(to)j(b)r(e)f(inconsisten)n+(t.)36 b(So)25 b Fs(don)-8 b('t)28 b(r)l(e)l(c)l(or)l(d)291+2981 y(any)i(p)l(atches)i(while)g(viewing)f(\014les)g(in)p+1530 2981 26 4 v 61 w(dar)l(cs/curr)l(ent)f(with)h(an)g(e)l(ditor!)51+b Fx(A)28 b(b)r(etter)h(plan)291 3081 y(w)n(ould)c(b)r(e)h(to)g+(restrict)f(y)n(ourself)g(to)h(viewing)f(these)h(\014les)g(with)h(a)e+(pager)g(suc)n(h)g(as)h(more)f(or)291 3180 y(less.)415+3280 y(Also)34 b(within)h Fr(_darcs)d Fx(is)j(the)g Fr(inventory)30+b Fx(\014le,)37 b(whic)n(h)d(lists)h(all)f(the)h(patc)n(hes)f(that)291+3380 y(are)27 b(in)j(the)f(rep)r(ository)-7 b(.)39 b(Moreo)n(v)n(er,)26+b(it)k(also)d(giv)n(es)h(the)h(order)f(of)h(the)g(represen)n(tation)e+(of)291 3479 y(the)35 b(patc)n(hes)g(as)g(they)g(are)f(stored.)59+b(Giv)n(en)35 b(a)g(source)f(of)i(patc)n(hes,)g(i.e.)g(an)n(y)e(other)h+(set)291 3579 y(of)f(rep)r(ositories)e(whic)n(h)i(ha)n(v)n(e)f(b)r(et)n+(w)n(een)h(them)h(all)f(the)h(patc)n(hes)e(con)n(tained)h(in)g(a)g(giv)+n(en)291 3678 y(rep)r(ository)-7 b(,)37 b(that)g(rep)r(ository)e(can)h+(b)r(e)h(repro)r(duced)e(based)h(on)h(only)f(the)h(information)291+3778 y(in)i(the)g Fr(inventory)c Fx(\014le.)70 b(Under)39+b(those)f(circumstances,)i(the)g(order)d(of)h(the)i(patc)n(hes)291+3878 y(sp)r(eci\014ed)g(in)g(the)h Fr(inventory)c Fx(\014le)j(w)n(ould)+g(b)r(e)g(unimp)r(ortan)n(t,)j(as)d(this)g(order)f(is)h(only)291+3977 y(needed)34 b(to)g(pro)n(vide)f(con)n(text)h(for)g(the)h(in)n+(terpretation)e(of)h(the)h(stored)e(patc)n(hes)h(in)h(this)291+4077 y(rep)r(ository)-7 b(.)415 4177 y(There)40 b(is)g(a)f(v)n(ery)g+(sp)r(ecial)h(patc)n(h)g(whic)n(h)g(ma)n(y)f(b)r(e)i(stored)e(in)i+Fr(patches)c Fx(whic)n(h)j(is)291 4276 y(called)c(`p)r(ending'.)64+b(This)36 b(patc)n(h)g(describ)r(es)g(an)n(y)g(c)n(hanges)f(whic)n(h)h+(ha)n(v)n(e)g(not)g(y)n(et)g(b)r(een)291 4376 y(recorded,)21+b(and)h(cannot)g(b)r(e)g(determined)h(b)n(y)e(a)h(simple)g(di\013.)36+b(F)-7 b(or)21 b(example,)i(\014le)f(additions)291 4475+y(or)39 b(renames)h(are)f(placed)h(in)h(p)r(ending)g(un)n(til)g(they)g+(are)e(recorded.)74 b(Similarly)-7 b(,)44 b(tok)n(en)291+4575 y(replaces)26 b(are)h(stored)f(in)i(p)r(ending)g(un)n(til)g(they)g+(are)e(recorded.)415 4675 y(The)41 b Fr(_darcs)d Fx(directory)h(also)g+(con)n(tains)h(a)g(directory)f(called)h(\\)p Fr(prefs)p+Fx(",)h(whic)n(h)f(is)291 4774 y(describ)r(ed)27 b(in)h(Chapter)f(4.)+1660 5208 y(111)p eop end+%%Page: 112 112+TeXDict begin 112 111 bop 739 282 a Fx(112)1200 b Fu(APPENDIX)27+b(B.)56 b(D)n(AR)n(CSREPO)26 b(F)n(ORMA)-7 b(T)p eop+end+%%Page: 113 113+TeXDict begin 113 112 bop 291 1140 a Ft(App)5 b(endix)64+b(C)291 1557 y Fw(The)77 b(GNU)f(General)h(Public)291+1806 y(License)291 2290 y Fq(V)-11 b(ersion)44 b(2,)i(June)f(1991)1346+2475 y Fx(V)-7 b(ersion)27 b(2,)g(June)g(1991)708 2577+y(Cop)n(yrigh)n(t)1121 2574 y(c)1098 2577 y Fn(\015)g+Fx(1989,)f(1991)g(F)-7 b(ree)27 b(Soft)n(w)n(are)f(F)-7+b(oundation,)28 b(Inc.)606 2786 y(51)f(F)-7 b(ranklin)27+b(Street,)h(Fifth)g(Flo)r(or,)f(Boston,)g(MA)h(02110-1301)23+b(USA)346 2996 y(Ev)n(ery)n(one)i(is)j(p)r(ermitted)g(to)g(cop)n(y)e+(and)i(distribute)g(v)n(erbatim)e(copies)h(of)h(this)g(license)967+3095 y(do)r(cumen)n(t,)g(but)g(c)n(hanging)f(it)h(is)f(not)h(allo)n(w)n+(ed.)291 3381 y Fq(Pream)l(ble)498 3566 y Fx(The)h(licenses)f(for)g+(most)h(soft)n(w)n(are)e(are)h(designed)g(to)h(tak)n(e)f(a)n(w)n(a)n(y)+e(y)n(our)i(free-)498 3666 y(dom)h(to)g(share)f(and)g(c)n(hange)g(it.)+42 b(By)28 b(con)n(trast,)g(the)i(GNU)f(General)g(Public)498+3766 y(License)g(is)h(in)n(tended)g(to)f(guaran)n(tee)f(y)n(our)g+(freedom)h(to)h(share)e(and)i(c)n(hange)498 3865 y(free)22+b(soft)n(w)n(are|to)f(mak)n(e)h(sure)f(the)i(soft)n(w)n(are)e(is)h+(free)g(for)g(all)g(its)h(users.)34 b(This)498 3965 y(General)22+b(Public)h(License)f(applies)g(to)h(most)f(of)h(the)g(F)-7+b(ree)23 b(Soft)n(w)n(are)e(F)-7 b(ounda-)498 4065 y(tion's)28+b(soft)n(w)n(are)f(and)h(to)h(an)n(y)e(other)h(program)f(whose)g+(authors)h(commit)g(to)498 4164 y(using)g(it.)39 b(\(Some)28+b(other)g(F)-7 b(ree)28 b(Soft)n(w)n(are)f(F)-7 b(oundation)28+b(soft)n(w)n(are)e(is)i(co)n(v)n(ered)498 4264 y(b)n(y)21+b(the)g(GNU)h(Library)d(General)i(Public)g(License)f(instead.\))35+b(Y)-7 b(ou)21 b(can)g(apply)498 4363 y(it)28 b(to)g(y)n(our)e+(programs,)f(to)r(o.)498 4500 y(When)36 b(w)n(e)g(sp)r(eak)f(of)h(free)+g(soft)n(w)n(are,)g(w)n(e)f(are)g(referring)f(to)i(freedom,)h(not)498+4600 y(price.)43 b(Our)29 b(General)g(Public)h(Licenses)f(are)g+(designed)g(to)h(mak)n(e)f(sure)g(that)498 4700 y(y)n(ou)19+b(ha)n(v)n(e)f(the)i(freedom)f(to)g(distribute)h(copies)e(of)i(free)f+(soft)n(w)n(are)f(\(and)h(c)n(harge)498 4799 y(for)27+b(this)g(service)f(if)h(y)n(ou)g(wish\),)g(that)g(y)n(ou)g(receiv)n(e)e+(source)h(co)r(de)h(or)f(can)h(get)498 4899 y(it)e(if)g(y)n(ou)f(w)n+(an)n(t)g(it,)i(that)f(y)n(ou)f(can)g(c)n(hange)g(the)h(soft)n(w)n(are)+e(or)g(use)i(pieces)f(of)h(it)498 4998 y(in)j(new)g(free)f(programs;)e+(and)j(that)g(y)n(ou)e(kno)n(w)h(y)n(ou)g(can)g(do)h(these)f(things.)+1660 5208 y(113)p eop end+%%Page: 114 114+TeXDict begin 114 113 bop 739 282 a Fx(114)545 b Fu(APPENDIX)27+b(C.)56 b(THE)27 b(GNU)h(GENERAL)g(PUBLIC)f(LICENSE)946+515 y Fx(T)-7 b(o)41 b(protect)f(y)n(our)g(righ)n(ts,)j(w)n(e)e(need)g+(to)f(mak)n(e)g(restrictions)g(that)h(forbid)946 615+y(an)n(y)n(one)20 b(to)h(den)n(y)g(y)n(ou)g(these)g(righ)n(ts)f(or)h+(to)g(ask)f(y)n(ou)h(to)g(surrender)f(the)i(righ)n(ts.)946+715 y(These)28 b(restrictions)f(translate)f(to)i(certain)f(resp)r+(onsibilities)h(for)f(y)n(ou)g(if)h(y)n(ou)946 814 y(distribute)g+(copies)f(of)h(the)g(soft)n(w)n(are,)e(or)g(if)j(y)n(ou)d(mo)r(dify)i+(it.)946 947 y(F)-7 b(or)37 b(example,)i(if)e(y)n(ou)f(distribute)h+(copies)g(of)f(suc)n(h)h(a)g(program,)g(whether)946 1047+y(gratis)c(or)f(for)h(a)g(fee,)i(y)n(ou)e(m)n(ust)h(giv)n(e)e(the)i+(recipien)n(ts)f(all)g(the)h(righ)n(ts)e(that)946 1146+y(y)n(ou)25 b(ha)n(v)n(e.)34 b(Y)-7 b(ou)25 b(m)n(ust)h(mak)n(e)e(sure)+g(that)h(they)-7 b(,)26 b(to)r(o,)f(receiv)n(e)f(or)g(can)h(get)f(the)+946 1246 y(source)33 b(co)r(de.)57 b(And)35 b(y)n(ou)f(m)n(ust)g(sho)n+(w)f(them)i(these)f(terms)g(so)g(they)g(kno)n(w)946 1345+y(their)28 b(righ)n(ts.)946 1478 y(W)-7 b(e)33 b(protect)e(y)n(our)f+(righ)n(ts)h(with)h(t)n(w)n(o)f(steps:)45 b(\(1\))32+b(cop)n(yrigh)n(t)e(the)i(soft)n(w)n(are,)946 1578 y(and)37+b(\(2\))h(o\013er)e(y)n(ou)h(this)g(license)g(whic)n(h)g(giv)n(es)g(y)n+(ou)f(legal)g(p)r(ermission)h(to)946 1677 y(cop)n(y)-7+b(,)27 b(distribute)h(and/or)e(mo)r(dify)i(the)g(soft)n(w)n(are.)946+1810 y(Also,)c(for)e(eac)n(h)g(author's)f(protection)h(and)g(ours,)h(w)+n(e)f(w)n(an)n(t)g(to)h(mak)n(e)e(certain)946 1910 y(that)38+b(ev)n(ery)n(one)d(understands)i(that)h(there)f(is)g(no)h(w)n(arran)n+(t)n(y)c(for)j(this)h(free)946 2009 y(soft)n(w)n(are.)64+b(If)38 b(the)f(soft)n(w)n(are)e(is)i(mo)r(di\014ed)h(b)n(y)f(someone)f+(else)h(and)f(passed)946 2109 y(on,)e(w)n(e)f(w)n(an)n(t)f(its)g+(recipien)n(ts)h(to)f(kno)n(w)g(that)h(what)g(they)g(ha)n(v)n(e)e(is)i+(not)f(the)946 2209 y(original,)e(so)f(that)h(an)n(y)g(problems)f(in)n+(tro)r(duced)h(b)n(y)f(others)h(will)g(not)g(re\015ect)946+2308 y(on)e(the)g(original)e(authors')g(reputations.)946+2441 y(Finally)-7 b(,)21 b(an)n(y)c(free)h(program)f(is)h(threatened)g+(constan)n(tly)g(b)n(y)g(soft)n(w)n(are)e(paten)n(ts.)946+2541 y(W)-7 b(e)33 b(wish)g(to)f(a)n(v)n(oid)f(the)i(danger)f(that)h+(redistributors)e(of)h(a)g(free)h(program)946 2640 y(will)22+b(individually)e(obtain)h(paten)n(t)g(licenses,)h(in)f(e\013ect)g+(making)f(the)i(program)946 2740 y(proprietary)-7 b(.)35+b(T)-7 b(o)27 b(prev)n(en)n(t)f(this,)i(w)n(e)f(ha)n(v)n(e)f(made)h(it)+h(clear)e(that)h(an)n(y)g(paten)n(t)946 2840 y(m)n(ust)h(b)r(e)g+(licensed)g(for)f(ev)n(ery)n(one's)e(free)i(use)h(or)f(not)g(licensed)h+(at)f(all.)946 2972 y(The)d(precise)e(terms)h(and)g(conditions)f(for)h+(cop)n(ying,)g(distribution)g(and)g(mo)r(d-)946 3072+y(i\014cation)28 b(follo)n(w.)1273 3304 y Fb(GNU)45 b(General)h(Public)+f(License)1067 3474 y(Terms)g(and)h(Conditions)f(F)m(or)f(Copying,)1233+3588 y(Distribution)i(and)f(Modifica)-8 b(tion)840 3770+y Fx(0.)41 b(This)23 b(License)f(applies)f(to)i(an)n(y)e(program)f(or)i+(other)f(w)n(ork)g(whic)n(h)h(con)n(tains)g(a)f(notice)946+3869 y(placed)38 b(b)n(y)g(the)g(cop)n(yrigh)n(t)e(holder)h(sa)n(ying)g+(it)h(ma)n(y)f(b)r(e)i(distributed)f(under)g(the)946+3969 y(terms)e(of)f(this)h(General)f(Public)g(License.)60+b(The)36 b(\\Program",)e(b)r(elo)n(w,)j(refers)d(to)946+4069 y(an)n(y)g(suc)n(h)f(program)f(or)h(w)n(ork,)h(and)g(a)f(\\w)n+(ork)f(based)h(on)h(the)g(Program")d(means)946 4168 y(either)25+b(the)h(Program)c(or)i(an)n(y)h(deriv)-5 b(ativ)n(e)24+b(w)n(ork)g(under)h(cop)n(yrigh)n(t)e(la)n(w:)35 b(that)25+b(is)g(to)946 4268 y(sa)n(y)-7 b(,)28 b(a)g(w)n(ork)f(con)n(taining)g+(the)i(Program)d(or)h(a)h(p)r(ortion)g(of)g(it,)h(either)g(v)n(erbatim)+e(or)946 4368 y(with)e(mo)r(di\014cations)e(and/or)f(translated)h(in)n+(to)g(another)g(language.)33 b(\(Hereinafter,)946 4467+y(translation)40 b(is)g(included)h(without)g(limitation)f(in)h(the)g+(term)f(\\mo)r(di\014cation".\))946 4567 y(Eac)n(h)27+b(licensee)g(is)h(addressed)e(as)h(\\y)n(ou".)946 4700+y(Activities)k(other)e(than)g(cop)n(ying,)h(distribution)f(and)h(mo)r+(di\014cation)f(are)g(not)h(co)n(v-)946 4799 y(ered)i(b)n(y)g(this)h+(License;)h(they)e(are)g(outside)g(its)g(scop)r(e.)50+b(The)33 b(act)f(of)g(running)g(the)946 4899 y(Program)g(is)j(not)f+(restricted,)i(and)e(the)h(output)g(from)f(the)h(Program)d(is)i(co)n(v)+n(ered)946 4998 y(only)26 b(if)h(its)g(con)n(ten)n(ts)f(constitute)g(a)+g(w)n(ork)f(based)h(on)h(the)f(Program)e(\(indep)r(enden)n(t)p+eop end+%%Page: 115 115+TeXDict begin 115 114 bop 3030 282 a Fx(115)498 515 y(of)39+b(ha)n(ving)f(b)r(een)h(made)g(b)n(y)g(running)f(the)h(Program\).)69+b(Whether)39 b(that)g(is)g(true)498 615 y(dep)r(ends)28+b(on)f(what)h(the)g(Program)d(do)r(es.)392 791 y(1.)41+b(Y)-7 b(ou)39 b(ma)n(y)f(cop)n(y)g(and)h(distribute)g(v)n(erbatim)g+(copies)f(of)h(the)g(Program's)d(source)498 891 y(co)r(de)d(as)f(y)n+(ou)f(receiv)n(e)h(it,)i(in)f(an)n(y)f(medium,)j(pro)n(vided)c(that)i+(y)n(ou)f(conspicuously)498 990 y(and)h(appropriately)e(publish)i(on)f+(eac)n(h)g(cop)n(y)g(an)h(appropriate)e(cop)n(yrigh)n(t)g(notice)498+1090 y(and)i(disclaimer)f(of)g(w)n(arran)n(t)n(y;)h(k)n(eep)f(in)n+(tact)h(all)f(the)i(notices)e(that)h(refer)f(to)h(this)498+1190 y(License)25 b(and)h(to)g(the)g(absence)f(of)g(an)n(y)g(w)n(arran)+n(t)n(y;)f(and)i(giv)n(e)e(an)n(y)h(other)h(recipien)n(ts)498+1289 y(of)i(the)g(Program)d(a)i(cop)n(y)f(of)i(this)g(License)f(along)g+(with)h(the)g(Program.)498 1427 y(Y)-7 b(ou)28 b(ma)n(y)g(c)n(harge)e+(a)i(fee)g(for)g(the)g(ph)n(ysical)f(act)h(of)g(transferring)f(a)g(cop)+n(y)-7 b(,)28 b(and)g(y)n(ou)498 1527 y(ma)n(y)f(at)g(y)n(our)g(option)+g(o\013er)g(w)n(arran)n(t)n(y)e(protection)i(in)h(exc)n(hange)e(for)h+(a)g(fee.)392 1703 y(2.)41 b(Y)-7 b(ou)27 b(ma)n(y)g(mo)r(dify)g(y)n+(our)f(cop)n(y)g(or)g(copies)h(of)g(the)g(Program)d(or)j(an)n(y)f(p)r+(ortion)g(of)h(it,)498 1803 y(th)n(us)f(forming)g(a)g(w)n(ork)f(based)h+(on)g(the)g(Program,)e(and)i(cop)n(y)g(and)g(distribute)g(suc)n(h)498+1902 y(mo)r(di\014cations)k(or)f(w)n(ork)f(under)i(the)g(terms)g(of)f+(Section)h(1)g(ab)r(o)n(v)n(e,)f(pro)n(vided)g(that)498+2002 y(y)n(ou)e(also)f(meet)i(all)g(of)f(these)h(conditions:)533+2197 y(\(a\))42 b(Y)-7 b(ou)26 b(m)n(ust)g(cause)g(the)g(mo)r(di\014ed)+g(\014les)g(to)g(carry)f(prominen)n(t)h(notices)f(stating)681+2297 y(that)j(y)n(ou)e(c)n(hanged)h(the)h(\014les)g(and)f(the)h(date)f+(of)h(an)n(y)f(c)n(hange.)529 2435 y(\(b\))42 b(Y)-7+b(ou)39 b(m)n(ust)h(cause)f(an)n(y)g(w)n(ork)f(that)i(y)n(ou)f+(distribute)h(or)f(publish,)k(that)d(in)681 2535 y(whole)24+b(or)g(in)i(part)e(con)n(tains)g(or)g(is)h(deriv)n(ed)f(from)h(the)g+(Program)d(or)i(an)n(y)g(part)681 2634 y(thereof,)36+b(to)f(b)r(e)g(licensed)f(as)g(a)h(whole)f(at)g(no)h(c)n(harge)e(to)h+(all)h(third)g(parties)681 2734 y(under)27 b(the)h(terms)g(of)f(this)h+(License.)538 2872 y(\(c\))42 b(If)20 b(the)g(mo)r(di\014ed)f(program)f+(normally)g(reads)h(commands)g(in)n(teractiv)n(ely)f(when)681+2971 y(run,)40 b(y)n(ou)d(m)n(ust)g(cause)g(it,)k(when)c(started)h+(running)f(for)g(suc)n(h)g(in)n(teractiv)n(e)681 3071+y(use)31 b(in)g(the)g(most)g(ordinary)f(w)n(a)n(y)-7+b(,)30 b(to)h(prin)n(t)g(or)f(displa)n(y)h(an)f(announcemen)n(t)681+3171 y(including)39 b(an)f(appropriate)f(cop)n(yrigh)n(t)g(notice)i+(and)f(a)h(notice)f(that)h(there)681 3270 y(is)g(no)h(w)n(arran)n(t)n+(y)d(\(or)i(else,)k(sa)n(ying)38 b(that)i(y)n(ou)g(pro)n(vide)e(a)i(w)n+(arran)n(t)n(y\))d(and)681 3370 y(that)25 b(users)g(ma)n(y)f+(redistribute)h(the)h(program)d(under)i(these)h(conditions,)f(and)681+3470 y(telling)33 b(the)h(user)f(ho)n(w)g(to)g(view)g(a)g(cop)n(y)g(of)+g(this)h(License.)54 b(\(Exception:)48 b(if)681 3569+y(the)26 b(Program)d(itself)j(is)g(in)n(teractiv)n(e)e(but)j(do)r(es)e+(not)h(normally)e(prin)n(t)i(suc)n(h)f(an)681 3669 y(announcemen)n(t,)+32 b(y)n(our)f(w)n(ork)g(based)g(on)h(the)g(Program)d(is)j(not)g+(required)f(to)681 3768 y(prin)n(t)c(an)h(announcemen)n(t.\))498+3964 y(These)e(requiremen)n(ts)f(apply)h(to)g(the)h(mo)r(di\014ed)g(w)n+(ork)e(as)g(a)h(whole.)36 b(If)27 b(iden)n(ti\014able)498+4064 y(sections)19 b(of)h(that)g(w)n(ork)f(are)g(not)h(deriv)n(ed)f+(from)g(the)i(Program,)d(and)i(can)g(b)r(e)g(reason-)498+4163 y(ably)29 b(considered)f(indep)r(enden)n(t)h(and)g(separate)f(w)n+(orks)f(in)i(themselv)n(es,)g(then)h(this)498 4263 y(License,)25+b(and)f(its)h(terms,)g(do)f(not)h(apply)f(to)h(those)f(sections)g(when)+h(y)n(ou)f(distribute)498 4362 y(them)36 b(as)e(separate)f(w)n(orks.)57+b(But)35 b(when)g(y)n(ou)f(distribute)h(the)g(same)f(sections)h(as)498+4462 y(part)d(of)g(a)g(whole)g(whic)n(h)g(is)g(a)g(w)n(ork)e(based)i+(on)g(the)g(Program,)f(the)i(distribution)498 4562 y(of)c(the)g(whole)f+(m)n(ust)h(b)r(e)f(on)h(the)g(terms)f(of)h(this)f(License,)h(whose)f(p)+r(ermissions)f(for)498 4661 y(other)22 b(licensees)g(extend)h(to)f(the)+h(en)n(tire)f(whole,)i(and)e(th)n(us)h(to)f(eac)n(h)g(and)g(ev)n(ery)f+(part)498 4761 y(regardless)k(of)j(who)f(wrote)g(it.)498+4899 y(Th)n(us,)35 b(it)g(is)e(not)h(the)g(in)n(ten)n(t)g(of)g(this)g+(section)g(to)f(claim)h(righ)n(ts)f(or)g(con)n(test)g(y)n(our)498+4998 y(righ)n(ts)24 b(to)h(w)n(ork)f(written)h(en)n(tirely)g(b)n(y)g(y)+n(ou;)g(rather,)g(the)g(in)n(ten)n(t)h(is)f(to)g(exercise)f(the)p+eop end+%%Page: 116 116+TeXDict begin 116 115 bop 739 282 a Fx(116)545 b Fu(APPENDIX)27+b(C.)56 b(THE)27 b(GNU)h(GENERAL)g(PUBLIC)f(LICENSE)946+515 y Fx(righ)n(t)f(to)h(con)n(trol)e(the)i(distribution)f(of)h(deriv)+-5 b(ativ)n(e)25 b(or)h(collectiv)n(e)g(w)n(orks)f(based)h(on)946+615 y(the)i(Program.)946 746 y(In)g(addition,)f(mere)g(aggregation)e+(of)i(another)f(w)n(ork)g(not)h(based)g(on)g(the)h(Program)946+845 y(with)f(the)g(Program)d(\(or)i(with)h(a)f(w)n(ork)f(based)h(on)g+(the)h(Program\))d(on)i(a)g(v)n(olume)g(of)946 945 y(a)f(storage)d(or)i+(distribution)g(medium)h(do)r(es)f(not)h(bring)f(the)h(other)e(w)n(ork)+h(under)g(the)946 1045 y(scop)r(e)k(of)f(this)h(License.)840+1206 y(3.)41 b(Y)-7 b(ou)30 b(ma)n(y)e(cop)n(y)g(and)h(distribute)g+(the)h(Program)c(\(or)j(a)f(w)n(ork)g(based)h(on)f(it,)i(under)946+1306 y(Section)g(2\))f(in)g(ob)5 b(ject)29 b(co)r(de)g(or)f(executable)+h(form)g(under)g(the)g(terms)g(of)h(Sections)946 1406+y(1)e(and)f(2)g(ab)r(o)n(v)n(e)f(pro)n(vided)h(that)h(y)n(ou)f(also)f+(do)i(one)f(of)g(the)h(follo)n(wing:)982 1582 y(\(a\))41+b(Accompan)n(y)i(it)h(with)g(the)f(complete)h(corresp)r(onding)d(mac)n+(hine-readable)1129 1682 y(source)22 b(co)r(de,)i(whic)n(h)g(m)n(ust)f+(b)r(e)h(distributed)g(under)f(the)h(terms)f(of)h(Sections)f(1)1129+1781 y(and)i(2)g(ab)r(o)n(v)n(e)e(on)i(a)g(medium)g(customarily)f(used)+h(for)f(soft)n(w)n(are)g(in)n(terc)n(hange;)1129 1881+y(or,)977 2010 y(\(b\))42 b(Accompan)n(y)30 b(it)h(with)g(a)f(written)h+(o\013er,)f(v)-5 b(alid)31 b(for)f(at)g(least)g(three)h(y)n(ears,)e(to)+1129 2109 y(giv)n(e)20 b(an)n(y)g(third)h(part)n(y)-7+b(,)22 b(for)e(a)h(c)n(harge)e(no)h(more)g(than)h(y)n(our)f(cost)g(of)h+(ph)n(ysically)1129 2209 y(p)r(erforming)j(source)g(distribution,)h(a)g+(complete)g(mac)n(hine-readable)d(cop)n(y)i(of)1129 2309+y(the)29 b(corresp)r(onding)e(source)h(co)r(de,)h(to)f(b)r(e)i+(distributed)f(under)g(the)g(terms)f(of)1129 2408 y(Sections)k(1)f(and)+h(2)g(ab)r(o)n(v)n(e)e(on)i(a)f(medium)i(customarily)e(used)h(for)f+(soft)n(w)n(are)1129 2508 y(in)n(terc)n(hange;)26 b(or,)986+2637 y(\(c\))42 b(Accompan)n(y)20 b(it)h(with)h(the)f(information)f(y)n+(ou)g(receiv)n(ed)g(as)g(to)h(the)g(o\013er)g(to)g(dis-)1129+2736 y(tribute)30 b(corresp)r(onding)d(source)h(co)r(de.)41+b(\(This)29 b(alternativ)n(e)f(is)h(allo)n(w)n(ed)f(only)1129+2836 y(for)d(noncommercial)f(distribution)h(and)g(only)g(if)h(y)n(ou)e+(receiv)n(ed)h(the)g(program)1129 2935 y(in)j(ob)5 b(ject)28+b(co)r(de)g(or)f(executable)h(form)f(with)i(suc)n(h)f(an)f(o\013er,)h+(in)g(accord)f(with)1129 3035 y(Subsection)h(b)f(ab)r(o)n(v)n(e.\))946+3211 y(The)40 b(source)e(co)r(de)h(for)g(a)g(w)n(ork)f(means)h(the)h+(preferred)e(form)i(of)f(the)h(w)n(ork)e(for)946 3311+y(making)24 b(mo)r(di\014cations)g(to)g(it.)36 b(F)-7+b(or)24 b(an)g(executable)g(w)n(ork,)f(complete)h(source)f(co)r(de)946+3411 y(means)k(all)h(the)g(source)e(co)r(de)h(for)g(all)g(mo)r(dules)h+(it)g(con)n(tains,)e(plus)i(an)n(y)f(asso)r(ciated)946+3510 y(in)n(terface)j(de\014nition)g(\014les,)g(plus)g(the)g(scripts)f+(used)h(to)g(con)n(trol)e(compilation)h(and)946 3610+y(installation)c(of)h(the)g(executable.)36 b(Ho)n(w)n(ev)n(er,)24+b(as)h(a)g(sp)r(ecial)g(exception,)h(the)f(source)946+3710 y(co)r(de)34 b(distributed)h(need)f(not)g(include)g(an)n(ything)g+(that)g(is)g(normally)f(distributed)946 3809 y(\(in)h(either)e(source)g+(or)f(binary)h(form\))h(with)g(the)g(ma)5 b(jor)31 b(comp)r(onen)n(ts)i+(\(compiler,)946 3909 y(k)n(ernel,)28 b(and)g(so)g(on\))g(of)h(the)f+(op)r(erating)g(system)g(on)g(whic)n(h)g(the)h(executable)f(runs,)946+4008 y(unless)g(that)g(comp)r(onen)n(t)f(itself)h(accompanies)e(the)i+(executable.)946 4139 y(If)k(distribution)e(of)h(executable)f(or)g(ob)5+b(ject)30 b(co)r(de)h(is)f(made)h(b)n(y)f(o\013ering)g(access)f(to)946+4239 y(cop)n(y)f(from)h(a)f(designated)h(place,)f(then)i(o\013ering)e+(equiv)-5 b(alen)n(t)28 b(access)g(to)h(cop)n(y)f(the)946+4338 y(source)23 b(co)r(de)h(from)g(the)g(same)g(place)f(coun)n(ts)h+(as)f(distribution)h(of)g(the)h(source)d(co)r(de,)946+4438 y(ev)n(en)i(though)f(third)h(parties)f(are)g(not)h(comp)r(elled)g+(to)f(cop)n(y)g(the)i(source)d(along)h(with)946 4538+y(the)28 b(ob)5 b(ject)28 b(co)r(de.)840 4700 y(4.)41+b(Y)-7 b(ou)32 b(ma)n(y)f(not)g(cop)n(y)-7 b(,)32 b(mo)r(dify)-7+b(,)33 b(sublicense,)g(or)e(distribute)g(the)h(Program)d(except)946+4799 y(as)d(expressly)f(pro)n(vided)g(under)h(this)g(License.)36+b(An)n(y)26 b(attempt)h(otherwise)e(to)h(cop)n(y)-7 b(,)946+4899 y(mo)r(dify)g(,)34 b(sublicense)e(or)f(distribute)i(the)f(Program)+d(is)j(v)n(oid,)h(and)f(will)g(automati-)946 4998 y(cally)24+b(terminate)g(y)n(our)f(righ)n(ts)g(under)h(this)g(License.)35+b(Ho)n(w)n(ev)n(er,)23 b(parties)h(who)f(ha)n(v)n(e)p+eop end+%%Page: 117 117+TeXDict begin 117 116 bop 3030 282 a Fx(117)498 515 y(receiv)n(ed)27+b(copies,)g(or)g(righ)n(ts,)g(from)g(y)n(ou)g(under)h(this)g(License)g+(will)g(not)f(ha)n(v)n(e)g(their)498 615 y(licenses)g(terminated)h(so)f+(long)g(as)g(suc)n(h)g(parties)g(remain)g(in)g(full)i(compliance.)392+787 y(5.)41 b(Y)-7 b(ou)37 b(are)f(not)g(required)g(to)h(accept)f(this)+h(License,)i(since)d(y)n(ou)g(ha)n(v)n(e)g(not)g(signed)498+887 y(it.)54 b(Ho)n(w)n(ev)n(er,)32 b(nothing)h(else)f(gran)n(ts)g(y)n+(ou)g(p)r(ermission)g(to)h(mo)r(dify)h(or)e(distribute)498+986 y(the)c(Program)e(or)h(its)h(deriv)-5 b(ativ)n(e)27+b(w)n(orks.)36 b(These)28 b(actions)f(are)g(prohibited)h(b)n(y)g(la)n+(w)498 1086 y(if)33 b(y)n(ou)f(do)h(not)f(accept)h(this)g(License.)52+b(Therefore,)33 b(b)n(y)f(mo)r(difying)h(or)f(distribut-)498+1186 y(ing)d(the)h(Program)c(\(or)i(an)n(y)h(w)n(ork)f(based)g(on)h+(the)g(Program\),)f(y)n(ou)g(indicate)h(y)n(our)498 1285+y(acceptance)j(of)g(this)h(License)f(to)g(do)h(so,)g(and)f(all)g(its)h+(terms)f(and)g(conditions)g(for)498 1385 y(cop)n(ying,)27+b(distributing)g(or)g(mo)r(difying)h(the)g(Program)d(or)h(w)n(orks)g+(based)h(on)h(it.)392 1557 y(6.)41 b(Eac)n(h)29 b(time)h(y)n(ou)g+(redistribute)f(the)i(Program)c(\(or)i(an)n(y)h(w)n(ork)e(based)i(on)f+(the)i(Pro-)498 1656 y(gram\),)g(the)g(recipien)n(t)f(automatically)g+(receiv)n(es)f(a)i(license)f(from)h(the)g(original)e(li-)498+1756 y(censor)h(to)h(cop)n(y)-7 b(,)31 b(distribute)g(or)g(mo)r(dify)g+(the)h(Program)c(sub)5 b(ject)31 b(to)g(these)g(terms)498+1856 y(and)i(conditions.)51 b(Y)-7 b(ou)33 b(ma)n(y)f(not)h(imp)r(ose)f+(an)n(y)g(further)h(restrictions)e(on)i(the)g(re-)498+1955 y(cipien)n(ts')26 b(exercise)f(of)h(the)h(righ)n(ts)e(gran)n(ted)g+(herein.)36 b(Y)-7 b(ou)26 b(are)f(not)h(resp)r(onsible)f(for)498+2055 y(enforcing)i(compliance)g(b)n(y)g(third)h(parties)f(to)g(this)h+(License.)392 2227 y(7.)41 b(If,)31 b(as)e(a)g(consequence)f(of)i(a)f+(court)g(judgmen)n(t)h(or)e(allegation)g(of)i(paten)n(t)f(infringe-)498+2327 y(men)n(t)c(or)f(for)g(an)n(y)g(other)g(reason)g(\(not)h(limited)g+(to)g(paten)n(t)g(issues\),)g(conditions)f(are)498 2426+y(imp)r(osed)36 b(on)f(y)n(ou)f(\(whether)i(b)n(y)f(court)g(order,)h+(agreemen)n(t)e(or)h(otherwise\))g(that)498 2526 y(con)n(tradict)24+b(the)i(conditions)e(of)i(this)f(License,)g(they)h(do)f(not)g(excuse)f+(y)n(ou)h(from)g(the)498 2626 y(conditions)37 b(of)h(this)g(License.)66+b(If)38 b(y)n(ou)f(cannot)g(distribute)h(so)f(as)g(to)g(satisfy)g(si-)+498 2725 y(m)n(ultaneously)25 b(y)n(our)f(obligations)h(under)g(this)h+(License)f(and)h(an)n(y)e(other)i(p)r(ertinen)n(t)498+2825 y(obligations,)e(then)g(as)f(a)h(consequence)f(y)n(ou)g(ma)n(y)h+(not)g(distribute)g(the)h(Program)c(at)498 2924 y(all.)35+b(F)-7 b(or)23 b(example,)h(if)g(a)f(paten)n(t)g(license)g(w)n(ould)g+(not)h(p)r(ermit)g(ro)n(y)n(alt)n(y-free)c(redistri-)498+3024 y(bution)i(of)f(the)h(Program)d(b)n(y)i(all)g(those)g(who)g+(receiv)n(e)f(copies)g(directly)i(or)e(indirectly)498+3124 y(through)25 b(y)n(ou,)h(then)g(the)g(only)f(w)n(a)n(y)g(y)n(ou)g+(could)g(satisfy)g(b)r(oth)i(it)f(and)f(this)h(License)498+3223 y(w)n(ould)h(b)r(e)h(to)g(refrain)e(en)n(tirely)h(from)h+(distribution)f(of)h(the)g(Program.)498 3359 y(If)34+b(an)n(y)f(p)r(ortion)f(of)i(this)f(section)g(is)h(held)f(in)n(v)-5+b(alid)34 b(or)e(unenforceable)g(under)i(an)n(y)498 3459+y(particular)f(circumstance,)j(the)e(balance)g(of)g(the)h(section)f(is)+g(in)n(tended)h(to)f(apply)498 3558 y(and)28 b(the)g(section)f(as)g(a)g+(whole)g(is)h(in)n(tended)g(to)f(apply)g(in)h(other)f(circumstances.)+498 3694 y(It)h(is)f(not)h(the)g(purp)r(ose)f(of)h(this)f(section)h(to)+f(induce)h(y)n(ou)f(to)g(infringe)g(an)n(y)g(paten)n(ts)498+3794 y(or)33 b(other)g(prop)r(ert)n(y)f(righ)n(t)h(claims)g(or)f(to)i+(con)n(test)f(v)-5 b(alidit)n(y)33 b(of)g(an)n(y)g(suc)n(h)g(claims;)+498 3894 y(this)22 b(section)g(has)f(the)i(sole)e(purp)r(ose)h(of)f+(protecting)h(the)g(in)n(tegrit)n(y)f(of)h(the)g(free)g(soft-)498+3993 y(w)n(are)c(distribution)i(system,)g(whic)n(h)g(is)f(implemen)n+(ted)h(b)n(y)f(public)h(license)f(practices.)498 4093+y(Man)n(y)26 b(p)r(eople)g(ha)n(v)n(e)f(made)h(generous)e(con)n+(tributions)i(to)g(the)g(wide)g(range)f(of)h(soft-)498+4192 y(w)n(are)c(distributed)i(through)f(that)g(system)h(in)f(reliance)+g(on)g(consisten)n(t)g(application)498 4292 y(of)28 b(that)h(system;)f+(it)g(is)g(up)h(to)f(the)g(author/donor)e(to)i(decide)g(if)h(he)f(or)f+(she)h(is)g(will-)498 4392 y(ing)d(to)g(distribute)h(soft)n(w)n(are)d+(through)i(an)n(y)f(other)h(system)g(and)g(a)g(licensee)f(cannot)498+4491 y(imp)r(ose)k(that)g(c)n(hoice.)498 4627 y(This)i(section)g(is)g+(in)n(tended)g(to)g(mak)n(e)g(thoroughly)e(clear)h(what)i(is)e(b)r+(eliev)n(ed)i(to)f(b)r(e)498 4727 y(a)d(consequence)g(of)g(the)h(rest)g+(of)f(this)h(License.)392 4899 y(8.)41 b(If)24 b(the)g(distribution)g+(and/or)e(use)h(of)h(the)g(Program)c(is)k(restricted)f(in)h(certain)f+(coun-)498 4998 y(tries)j(either)g(b)n(y)g(paten)n(ts)f(or)h(b)n(y)g+(cop)n(yrigh)n(ted)e(in)n(terfaces,)i(the)g(original)f(cop)n(yrigh)n(t)+p eop end+%%Page: 118 118+TeXDict begin 118 117 bop 739 282 a Fx(118)545 b Fu(APPENDIX)27+b(C.)56 b(THE)27 b(GNU)h(GENERAL)g(PUBLIC)f(LICENSE)946+515 y Fx(holder)35 b(who)g(places)g(the)h(Program)c(under)j(this)h+(License)f(ma)n(y)g(add)g(an)g(explicit)946 615 y(geographical)21+b(distribution)i(limitation)g(excluding)g(those)g(coun)n(tries,)g(so)f+(that)i(dis-)946 715 y(tribution)32 b(is)g(p)r(ermitted)g(only)g(in)g+(or)e(among)h(coun)n(tries)g(not)g(th)n(us)h(excluded.)49+b(In)946 814 y(suc)n(h)21 b(case,)h(this)g(License)f(incorp)r(orates)e+(the)j(limitation)g(as)e(if)i(written)g(in)f(the)h(b)r(o)r(dy)946+914 y(of)28 b(this)g(License.)840 1085 y(9.)41 b(The)23+b(F)-7 b(ree)22 b(Soft)n(w)n(are)e(F)-7 b(oundation)22+b(ma)n(y)g(publish)h(revised)e(and/or)g(new)h(v)n(ersions)e(of)946+1185 y(the)30 b(General)e(Public)g(License)g(from)h(time)g(to)g(time.)+40 b(Suc)n(h)29 b(new)g(v)n(ersions)e(will)i(b)r(e)946+1285 y(similar)d(in)h(spirit)f(to)h(the)g(presen)n(t)f(v)n(ersion,)f+(but)i(ma)n(y)f(di\013er)h(in)f(detail)h(to)f(address)946+1384 y(new)i(problems)f(or)g(concerns.)946 1520 y(Eac)n(h)36+b(v)n(ersion)f(is)i(giv)n(en)f(a)g(distinguishing)g(v)n(ersion)g(n)n+(um)n(b)r(er.)64 b(If)37 b(the)g(Program)946 1619 y(sp)r(eci\014es)f(a)+g(v)n(ersion)f(n)n(um)n(b)r(er)g(of)h(this)h(License)e(whic)n(h)h+(applies)g(to)g(it)h(and)e(\\an)n(y)946 1719 y(later)29+b(v)n(ersion",)e(y)n(ou)i(ha)n(v)n(e)e(the)j(option)f(of)g(follo)n+(wing)f(the)h(terms)g(and)g(conditions)946 1819 y(either)21+b(of)g(that)g(v)n(ersion)e(or)h(of)g(an)n(y)g(later)g(v)n(ersion)g+(published)h(b)n(y)f(the)h(F)-7 b(ree)21 b(Soft)n(w)n(are)946+1918 y(F)-7 b(oundation.)66 b(If)37 b(the)h(Program)c(do)r(es)j(not)g+(sp)r(ecify)h(a)e(v)n(ersion)g(n)n(um)n(b)r(er)h(of)g(this)946+2018 y(License,)28 b(y)n(ou)f(ma)n(y)g(c)n(ho)r(ose)f(an)n(y)h(v)n+(ersion)g(ev)n(er)f(published)j(b)n(y)e(the)h(F)-7 b(ree)28+b(Soft)n(w)n(are)946 2118 y(F)-7 b(oundation.)799 2289+y(10.)40 b(If)29 b(y)n(ou)f(wish)g(to)g(incorp)r(orate)f(parts)h(of)g+(the)h(Program)d(in)n(to)i(other)f(free)i(programs)946+2389 y(whose)40 b(distribution)g(conditions)g(are)f(di\013eren)n(t,)k+(write)d(to)g(the)h(author)e(to)h(ask)946 2488 y(for)35+b(p)r(ermission.)58 b(F)-7 b(or)34 b(soft)n(w)n(are)f(whic)n(h)i(is)f+(cop)n(yrigh)n(ted)f(b)n(y)i(the)g(F)-7 b(ree)35 b(Soft)n(w)n(are)946+2588 y(F)-7 b(oundation,)33 b(write)f(to)f(the)i(F)-7+b(ree)31 b(Soft)n(w)n(are)g(F)-7 b(oundation;)33 b(w)n(e)f(sometimes)f+(mak)n(e)946 2688 y(exceptions)20 b(for)f(this.)34 b(Our)19+b(decision)g(will)h(b)r(e)g(guided)g(b)n(y)f(the)h(t)n(w)n(o)f(goals)f+(of)i(preserv-)946 2787 y(ing)27 b(the)g(free)g(status)f(of)h(all)g+(deriv)-5 b(ativ)n(es)25 b(of)i(our)f(free)h(soft)n(w)n(are)e(and)i(of)+f(promoting)946 2887 y(the)i(sharing)f(and)g(reuse)g(of)h(soft)n(w)n+(are)d(generally)-7 b(.)1852 3110 y Fb(No)46 b(W)-14+b(arranty)799 3333 y Fx(11.)40 b Fa(Beca)n(use)e(the)f(pr)n(ogram)h(is)+f(licensed)g(free)h(of)f(char)n(ge,)i(there)e(is)g(no)946+3432 y(w)-7 b(arranty)41 b(f)n(or)f(the)h(pr)n(ogram,)i(to)d(the)h+(extent)g(permitted)g(by)g(ap-)946 3532 y(plicable)h(la)-7+b(w.)72 b(Ex)n(cept)42 b(when)g(other)-7 b(wise)43 b(st)-6+b(a)g(ted)42 b(in)g(writing)h(the)946 3631 y(copyright)32+b(holders)g(and/or)f(other)g(p)-6 b(ar)g(ties)34 b(pr)n(o)n(vide)e(the)+g(pr)n(ogram)946 3731 y(\\as)d(is")g(without)h(w)-7 b(arranty)28+b(of)i(any)e(kind,)h(either)h(expressed)g(or)f(im-)946+3831 y(plied,)44 b(including,)g(but)e(not)f(limited)h(to,)i(the)e+(implied)g(w)-7 b(arranties)946 3930 y(of)31 b(mer)n(chant)-6+b(ability)30 b(and)g(fitness)h(f)n(or)f(a)g(p)-6 b(ar)g(ticular)31+b(purpose.)41 b(The)946 4030 y(entire)27 b(risk)e(as)h(to)f(the)h+(quality)f(and)g(perf)n(ormance)i(of)f(the)g(pr)n(ogram)946+4130 y(is)32 b(with)f(you.)40 b(Should)30 b(the)h(pr)n(ogram)h(pr)n(o)n+(ve)f(defective,)h(you)f(assume)946 4229 y(the)h(cost)f(of)h(all)f+(necessar)-6 b(y)32 b(ser)-7 b(vicing,)31 b(rep)-6 b(air)32+b(or)g(correction.)799 4401 y Fx(12.)40 b Fa(In)e(no)g(event)g(unless)g+(required)h(by)f(applicable)g(la)-7 b(w)38 b(or)f(a)n(greed)i(to)946+4500 y(in)48 b(writing)h(will)f(any)g(copyright)g(holder,)j(or)d(any)g+(other)g(p)-6 b(ar)g(ty)946 4600 y(who)23 b(ma)-6 b(y)23+b(modify)g(and/or)f(redistribute)i(the)f(pr)n(ogram)g(as)f(permitted)+946 4700 y(abo)n(ve,)39 b(be)e(liable)g(to)g(you)f(f)n(or)h(d)n(ama)n+(ges,)i(including)e(any)f(general,)946 4799 y(special,)45+b(incident)-6 b(al)42 b(or)f(consequential)g(d)n(ama)n(ges)i(arising)e+(out)h(of)946 4899 y(the)h(use)f(or)g(inability)g(to)g(use)g(the)h(pr)n+(ogram)f(\(including)g(but)g(not)946 4998 y(limited)32+b(to)g(loss)f(of)h(d)n(a)-6 b(t)g(a)32 b(or)g(d)n(a)-6+b(t)g(a)32 b(being)h(rendered)f(ina)n(ccura)-6 b(te)32+b(or)p eop end+%%Page: 119 119+TeXDict begin 119 118 bop 291 282 a Fu(C.1.)51 b(APPENDIX:)19+b(HO)n(W)f(TO)g(APPL)-7 b(Y)18 b(THESE)g(TERMS)g(TO)g(YOUR)h(NEW)f(PR)n+(OGRAMS)p Fx(119)498 515 y Fa(losses)39 b(sust)-6 b(ained)39+b(by)g(you)f(or)h(third)g(p)-6 b(ar)g(ties)40 b(or)f(a)g(f)-7+b(ailure)38 b(of)i(the)498 615 y(pr)n(ogram)e(to)g(opera)-6+b(te)39 b(with)f(any)g(other)g(pr)n(ograms\),)h(even)g(if)f(such)498+715 y(holder)c(or)h(other)g(p)-6 b(ar)g(ty)36 b(has)e(been)i(ad)n+(vised)f(of)g(the)g(possibility)g(of)498 814 y(such)c(d)n(ama)n(ges.)+813 1004 y Fb(End)44 b(of)i(Terms)e(and)i(Conditions)291+1289 y Fq(C.1)135 b(App)t(endix:)76 b(Ho)l(w)55 b(to)f(Apply)e(These)i+(T)-11 b(erms)53 b(to)627 1438 y(Y)-11 b(our)44 b(New)h(Programs)291+1624 y Fx(If)32 b(y)n(ou)g(dev)n(elop)g(a)g(new)g(program,)g(and)g(y)n+(ou)g(w)n(an)n(t)g(it)h(to)f(b)r(e)h(of)f(the)h(greatest)e(p)r(ossible)+291 1723 y(use)26 b(to)g(the)h(public,)h(the)f(b)r(est)g(w)n(a)n(y)e+(to)h(ac)n(hiev)n(e)f(this)i(is)g(to)f(mak)n(e)g(it)h(free)f(soft)n(w)n+(are)f(whic)n(h)291 1823 y(ev)n(ery)n(one)g(can)i(redistribute)h(and)f+(c)n(hange)g(under)g(these)h(terms.)415 1924 y(T)-7 b(o)28+b(do)g(so,)f(attac)n(h)h(the)g(follo)n(wing)g(notices)f(to)h(the)h+(program.)36 b(It)29 b(is)f(safest)g(to)g(attac)n(h)291+2024 y(them)g(to)g(the)h(start)e(of)h(eac)n(h)g(source)e(\014le)j(to)f+(most)g(e\013ectiv)n(ely)f(con)n(v)n(ey)g(the)i(exclusion)e(of)291+2124 y(w)n(arran)n(t)n(y;)g(and)i(eac)n(h)f(\014le)h(should)g(ha)n(v)n+(e)f(at)g(least)h(the)g(\\cop)n(yrigh)n(t")e(line)i(and)g(a)f(p)r(oin)n+(ter)291 2223 y(to)f(where)g(the)h(full)g(notice)g(is)f(found.)498+2413 y Fi(<)p Fx(one)34 b(line)h(to)g(giv)n(e)f(the)i(program's)c(name)+j(and)g(a)f(brief)h(idea)g(of)g(what)g(it)498 2513 y(do)r(es.)p+Fi(>)498 2613 y Fx(Cop)n(yrigh)n(t)26 b(\(C\))i Fi(<)p+Fx(y)n(ear)p Fi(>)e(<)p Fx(name)h(of)g(author)p Fi(>)498+2849 y Fx(This)d(program)e(is)i(free)g(soft)n(w)n(are;)g(y)n(ou)f(can)h+(redistribute)g(it)g(and/or)f(mo)r(dify)498 2948 y(it)k(under)g(the)g+(terms)g(of)g(the)g(GNU)h(General)e(Public)g(License)h(as)f(published)+498 3048 y(b)n(y)h(the)g(F)-7 b(ree)27 b(Soft)n(w)n(are)f(F)-7+b(oundation;)27 b(either)g(v)n(ersion)e(2)i(of)g(the)g(License,)g(or)+498 3148 y(\(at)h(y)n(our)e(option\))i(an)n(y)f(later)g(v)n(ersion.)498+3284 y(This)33 b(program)d(is)i(distributed)h(in)g(the)g(hop)r(e)f+(that)h(it)g(will)g(b)r(e)g(useful,)h(but)498 3384 y(WITHOUT)23+b(ANY)h(W)-9 b(ARRANTY;)24 b(without)f(ev)n(en)f(the)h(implied)g(w)n+(arran)n(t)n(y)498 3483 y(of)18 b(MER)n(CHANT)-7 b(ABILITY)19+b(or)f(FITNESS)g(F)n(OR)g(A)h(P)-7 b(AR)g(TICULAR)19+b(PUR-)498 3583 y(POSE.)27 b(See)g(the)h(GNU)h(General)d(Public)i+(License)f(for)g(more)g(details.)498 3720 y(Y)-7 b(ou)24+b(should)f(ha)n(v)n(e)f(receiv)n(ed)g(a)h(cop)n(y)g(of)g(the)h(GNU)g+(General)f(Public)g(License)498 3819 y(along)34 b(with)i(this)f+(program;)i(if)f(not,)h(write)e(to)g(the)g(F)-7 b(ree)35+b(Soft)n(w)n(are)f(F)-7 b(oun-)498 3919 y(dation,)30+b(Inc.,)f(59)g(T)-7 b(emple)29 b(Place)f(-)h(Suite)h(330,)f(Boston,)f+(MA)i(02111-1307,)498 4019 y(USA.)415 4209 y(Also)d(add)h(information)f+(on)g(ho)n(w)g(to)g(con)n(tact)g(y)n(ou)g(b)n(y)g(electronic)g(and)h+(pap)r(er)f(mail.)415 4310 y(If)g(the)f(program)f(is)h(in)n(teractiv)n+(e,)f(mak)n(e)h(it)g(output)h(a)f(short)g(notice)g(lik)n(e)f(this)i+(when)f(it)291 4410 y(starts)g(in)i(an)g(in)n(teractiv)n(e)e(mo)r(de:)+498 4600 y(Gnomo)n(vision)g(v)n(ersion)g(69,)g(Cop)n(yrigh)n(t)g(\(C\))+i Fi(<)p Fx(y)n(ear)p Fi(>)d(<)p Fx(name)h(of)i(author)p+Fi(>)498 4700 y Fx(Gnomo)n(vision)22 b(comes)g(with)i(ABSOLUTEL)-7+b(Y)23 b(NO)f(W)-9 b(ARRANTY;)25 b(for)e(de-)498 4799+y(tails)k(t)n(yp)r(e)h(`sho)n(w)f(w'.)498 4899 y(This)k(is)g(free)g+(soft)n(w)n(are,)g(and)g(y)n(ou)f(are)g(w)n(elcome)h(to)g(redistribute)+g(it)g(under)498 4998 y(certain)c(conditions;)g(t)n(yp)r(e)h(`sho)n(w)f+(c')g(for)h(details.)p eop end+%%Page: 120 120+TeXDict begin 120 119 bop 739 282 a Fx(120)545 b Fu(APPENDIX)27+b(C.)56 b(THE)27 b(GNU)h(GENERAL)g(PUBLIC)f(LICENSE)863+515 y Fx(The)38 b(h)n(yp)r(othetical)g(commands)g Fr(show)j(w)d+Fx(and)g Fr(show)k(c)c Fx(should)f(sho)n(w)g(the)i(appro-)739+615 y(priate)31 b(parts)g(of)h(the)g(General)f(Public)g(License.)49+b(Of)32 b(course,)f(the)h(commands)f(y)n(ou)g(use)739+715 y(ma)n(y)i(b)r(e)i(called)f(something)g(other)f(than)i+Fr(show)42 b(w)33 b Fx(and)h Fr(show)42 b(c)p Fx(;)c(they)c(could)g(ev)+n(en)g(b)r(e)739 814 y(mouse-clic)n(ks)26 b(or)h(men)n(u)g+(items|whatev)n(er)g(suits)h(y)n(our)e(program.)863 914+y(Y)-7 b(ou)32 b(should)f(also)g(get)g(y)n(our)g(emplo)n(y)n(er)f(\(if)+i(y)n(ou)f(w)n(ork)f(as)h(a)g(programmer\))f(or)g(y)n(our)739+1013 y(sc)n(ho)r(ol,)36 b(if)g(an)n(y)-7 b(,)37 b(to)e(sign)g(a)g+(\\cop)n(yrigh)n(t)f(disclaimer")g(for)h(the)g(program,)h(if)g+(necessary)-7 b(.)739 1113 y(Here)27 b(is)h(a)f(sample;)g(alter)g(the)h+(names:)946 1296 y(Y)-7 b(o)n(y)n(o)r(dyne,)36 b(Inc.,)g(hereb)n(y)e+(disclaims)g(all)h(cop)n(yrigh)n(t)e(in)n(terest)h(in)h(the)g(pro-)946+1395 y(gram)946 1495 y(`Gnomo)n(vision')27 b(\(whic)n(h)h(mak)n(es)f+(passes)f(at)i(compilers\))f(written)h(b)n(y)g(James)946+1595 y(Hac)n(k)n(er.)946 1827 y Fi(<)p Fx(signature)e(of)i(T)n(y)f(Co)r+(on)p Fi(>)p Fx(,)g(1)g(April)h(1989)946 1927 y(T)n(y)g(Co)r(on,)f+(Presiden)n(t)f(of)i(Vice)863 2109 y(This)36 b(General)f(Public)h+(License)g(do)r(es)f(not)h(p)r(ermit)h(incorp)r(orating)d(y)n(our)g+(program)739 2209 y(in)n(to)h(proprietary)e(programs.)56+b(If)36 b(y)n(our)d(program)g(is)i(a)g(subroutine)f(library)-7+b(,)36 b(y)n(ou)e(ma)n(y)739 2309 y(consider)e(it)i(more)e(useful)i(to)+f(p)r(ermit)g(linking)h(proprietary)d(applications)h(with)i(the)f(li-)+739 2408 y(brary)-7 b(.)60 b(If)37 b(this)f(is)g(what)f(y)n(ou)h(w)n+(an)n(t)f(to)g(do,)j(use)e(the)g(GNU)h(Library)d(General)h(Public)739+2508 y(License)27 b(instead)h(of)f(this)h(License.)p+eop end+%%Trailer++userdict /end-hook known{end-hook}if+%%EOF
+ src/darcsman.hs view
@@ -0,0 +1,98 @@+-- Copyright (C) 2003 David Roundy+--+-- 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, 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.++module Main (main) where++import Autoconf ( datadir )+import Darcs.Commands+import Darcs.TheCommands+import Time++main :: IO ()+main = man (extract_commands command_control_list)++man :: [DarcsCommand] -> IO ()+man cs = do man_header+            unorganized <- man_organizer cs+            putStrLn ".SH OTHER COMMANDS"+            man_helper unorganized+            man_trailer++man_organizer :: [DarcsCommand] -> IO [DarcsCommand]+man_organizer commands = mo commands+                         [("CREATING REPOSITORIES",+                           ["initialize","get"]),+                          ("MODIFYING REPOSITORY CONTENTS",+                           ["add","remove","mv","replace"]),+                          ("WORKING WITH CHANGES",+                           ["record","pull","push","send","apply"]),+                          ("SEEING WHAT YOU'VE DONE",+                           ["whatsnew","query"])+                         ]+    where mo :: [DarcsCommand] -> [(String,[String])] -> IO [DarcsCommand]+          mo cs [] = return cs+          mo cs ((t,a):xs) =+              do putStrLn $ ".SH " ++ t+                 man_helper $ filter ((`elem` a) . command_name) cs+                 mo (filter (not . (`elem` a) . command_name) cs) xs++man_helper :: [DarcsCommand] -> IO ()+man_helper cmds =+  helper' "" cmds+  where helper' _ [] = return ()+        helper' s (c@DarcsCommand { }:cs) = do+            putStrLn $ ".TP"+            putStrLn $ ".B "++ s ++ " "  ++ command_name c+            putStrLn $ command_help c+            helper' s cs+        helper' s (c@SuperCommand { }:cs) = do+            helper' (command_name c ++ " " ++ s)+                      (extract_commands (command_sub_commands c))+            helper' s cs++man_trailer :: IO ()+man_trailer = do putStrLn ""+                 putStrLn ".SH BUGS"+                 putStrLn "Report bugs by mail to"+                 putStrLn ".B bugs@darcs.net"+                 putStrLn "or via the web site at"+                 putStrLn ".BR http://bugs.darcs.net/ ."+                 putStrLn ""+                 putStrLn ".SH AUTHOR"+                 putStrLn "David Roundy <droundy@abridgegame.org>."++man_header :: IO ()+man_header = do+  putStr ".TH DARCS \"1\" \""+  cl <- getClockTime+  ct <- toCalendarTime cl+  putStr $ show (ctMonth ct) ++ " " ++ show (ctYear ct)+  putStr "\" \"darcs\" \"User Commands\"\n"+  putStr $+   ".SH NAME\n"+++   "darcs \\- an advanced revision control system\n"+++   ".SH SYNOPSIS\n"+++   ".B darcs\n"+++   "\\fICOMMAND \\fR...\n"+++   ".SH DESCRIPTION\n"+++   "\n"+++   "darcs is a nifty revision control tool.  For more a detailed description,\n"+++   "see the html documentation, which should be available at\n"+++   datadir++"/doc/darcs/manual/index.html.  To easily get more specific help\n"+++   "on each command, you can call `darcs COMMAND --help'\n"+++   "\n"++
+ src/features.tex view
@@ -0,0 +1,88 @@+\section{Features}++\paragraph{Record changes locally}+In darcs, the equivalent of a cvs ``commit'' is called record, because it+doesn't put the change into any remote or centralized repository.  Changes+are always recorded locally, meaning no net access is required in order to+work on your project and record changes as you make them.  Moreover, this+means that there is no need for a separate ``disconnected operation'' mode.++\paragraph{Interactive records}+You can choose to perform an interactive record, in which case darcs will+prompt you for each change you have made and ask if you wish to record it.+Of course, you can tell darcs to record all the changes in a given file, or+to skip all the changes in a given file, or go back to a previous change,+or whatever.  There is also an experimental graphical interface, which+allows you to view and choose changes even more easily, and in whichever+order you like.++\paragraph{Unrecord local changes}+As a corollary to the ``local'' nature of the record operation, if a change+hasn't yet been published to the world---that is, if the local repository+isn't accessible by others---you can safely unrecord a change (even if it+wasn't the most recently recorded change) and then re-record it+differently, for example if you forgot to add a file, introduced a bug or+realized that what you recorded as a single change was really two separate+changes.++\paragraph{Interactive everything else}+Most darcs commands support an interactive interface.  The ``revert''+command, for example, which undoes unrecorded changes has the same+interface as record, so you can easily revert just a single change.  Pull,+push, send and apply all allow you to view and interactively select which+changes you wish to pull, push, send or apply.++\paragraph{Test suites}+Darcs has support for integrating a test suite with a repository.  If you+choose to use this, you can define a test command (e.g.\ ``make check'') and+have darcs run that command on a clean copy of the project either prior to+recording a change or prior to applying changes---and to reject changes+that cause the test to fail.++\paragraph{Any old server}+Darcs does not require a specialized server in order to make a repository+available for read access.  You can use http, ftp, or even just a plain old+ssh server to access your darcs repository.++\paragraph{You decide write permissions}+Darcs doesn't try to manage write access.  That's your business.  Supported+push methods include direct ssh access (if you're willing to \emph{give}+direct ssh access away), using sudo to allow users who already have shell+access to only apply changes to the repository, or verification of+gpg-signed changes sent by email against a list of allowed keys.  In+addition, there is good support for submission of patches by email that+are not automatically applied, but can easily be applied with a shell escape+from a mail reader (this is how I deal with contributions to darcs).++\paragraph{Symmetric repositories}+Every darcs repository is created equal (well, with the exception of a+``partial'' repository, which doesn't contain a full history\ldots), and every+working directory has an associated repository.  As a result, there is a+symmetry between ``uploading'' and ``downloading'' changes---you can use+the same commands (push or pull) for either purpose.++\paragraph{CGI script}+Darcs has a CGI script that allows browsing of the repositories.++\paragraph{Portable}+Darcs runs on UNIX (or UNIX-like) systems (which includes Mac~OS~X) as well+as on Microsoft Windows.++\paragraph{File and directory moves}+Renames or moves of files and directories, of course are handled properly,+so when you rename a file or move it to a different directory, its history+is unbroken, and merges with repositories that don't have the file renamed+will work as expected.++\paragraph{Token replace}+You can use the ``darcs replace'' command to modify all occurrences of a+particular token (defined by a configurable set of characters that are+allowed in ``tokens'') in a file.  This has the advantage that merges with+changes that introduce new copies of the old token will have the effect of+changing it to the new token---which comes in handy when changing a+variable or function name that is used throughout a project.++\paragraph{Configurable defaults}+You can easily configure the default flags passed to any command on either+a per-repository or a per-user basis or a combination thereof.+
+ src/fpstring.c view
@@ -0,0 +1,215 @@+/*+ * Copyright (C) 2003 David Roundy+ * Most of the UTF code is Copyright (C) 1999-2001 Free Software Foundation, Inc.+ * This file is part of darcs.+ *+ * Darcs is free software; you can redistribute it and/or modify it under+ * the terms of the GNU Library General Public License as published by the+ * Free Software Foundation; either version 2 of the License, or (at your+ * option) any later version.+ *+ * You should have received a copy of the GNU Library General Public+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.+ * If not, write to the Free Software Foundation, Inc., 51 Franklin Street,+ * Fifth Floor, Boston, MA 02110-1301, USA.+ *+ */+#include "fpstring.h"++#include <stdlib.h>+#include <string.h>+#include <stdio.h>++#ifdef _WIN32+#include <windows.h>+#else+#include <sys/mman.h>+#endif++/* A locale-independent isspace(3) so patches are interpreted the same+ * everywhere. */+#define ISSPACE(c) \+    ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')++int first_white(const char *s, int len)+{+    const char *start;+    const char *end;++    for (start = s, end = s + len; s < end && !ISSPACE(*s); s++);++    return s - start;+}++int first_nonwhite(const char *s, int len)+{+    const char *start;+    const char *end;++    for (start = s, end = s + len; s < end && ISSPACE(*s); s++);++    return s - start;+}++int has_funky_char(const char *s, int len)+{+  // We check first for the more likely \0 so we can break out of+  // memchr that much sooner.+  return !!(memchr(s, 0, len) || memchr(s, 26, len));++}++// mmapping...++#ifdef _WIN32++/* I have no idea if this works or not, and it is very tied to the usage+ * of mmap in FastPackedString. Most arguments are ignored...+ */++char *my_mmap(size_t length, int fd)+{+  exit(1); /* mmap is not implemented on Windows */+}++int munmap(void *start, size_t length)+{+    UnmapViewOfFile(start);+}++#else++char *my_mmap(size_t len, int fd) {+  void *maybeok = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);+  if (maybeok == MAP_FAILED) return NULL;+  else return (char *)maybeok;+}++#endif++// ForeignPtr debugging stuff...++static int num_alloced = 0;++void debug_free(void *p) {+  num_alloced--;+  fprintf(stderr, "Freeing %p (%d left)\n", p, num_alloced);+}++void debug_alloc(void *p, const char *name) {+  num_alloced++;+  fprintf(stderr, "Allocating %p named %s (%d left)\n",+          p, name, num_alloced);+}++/* Specification: RFC 2279 */++int utf8_to_ints(HsInt *pwc, const unsigned char *s, int n) {+  /* returns number of unicode chars in the output.  The output array is+     assumed to have the same number of elements as the input array, which+     is n. */++  HsInt *pwc_original = pwc;+  while (n > 0) {+    unsigned char c = s[0];++    if (c < 0x80) {+      *pwc++ = c;+      n--;+      s++;+    } else if (c < 0xc2) {+      return -1;+    } else if (c < 0xe0) {+      if (n < 2) return -1;+      if (!((s[1] ^ 0x80) < 0x40)) return -1;+      *pwc++ = ((unsigned) (c & 0x1f) << 6)+        | (unsigned) (s[1] ^ 0x80);+      n -= 2;+      s += 2;+    } else if (c < 0xf0) {+      if (n < 3) return -1;+      if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40+            && (c >= 0xe1 || s[1] >= 0xa0)))+        return -1;+      *pwc++ = ((unsigned) (c & 0x0f) << 12)+        | ((unsigned) (s[1] ^ 0x80) << 6)+        | (unsigned) (s[2] ^ 0x80);+      n -= 3;+      s += 3;+    } else if (c < 0xf8 && sizeof(unsigned)*8 >= 32) {+      if (n < 4) return -1;+      if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40+            && (s[3] ^ 0x80) < 0x40+            && (c >= 0xf1 || s[1] >= 0x90)))+        return -1;+      *pwc++ = ((unsigned) (c & 0x07) << 18)+        | ((unsigned) (s[1] ^ 0x80) << 12)+        | ((unsigned) (s[2] ^ 0x80) << 6)+        | (unsigned) (s[3] ^ 0x80);+      n -= 4;+      s += 4;+    } else if (c < 0xfc && sizeof(unsigned)*8 >= 32) {+      if (n < 5) return -1;+      if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40+            && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40+            && (c >= 0xf9 || s[1] >= 0x88)))+        return -1;+      *pwc++ = ((unsigned) (c & 0x03) << 24)+        | ((unsigned) (s[1] ^ 0x80) << 18)+        | ((unsigned) (s[2] ^ 0x80) << 12)+        | ((unsigned) (s[3] ^ 0x80) << 6)+        | (unsigned) (s[4] ^ 0x80);+      n -= 5;+      s += 5;+    } else if (c < 0xfe && sizeof(unsigned)*8 >= 32) {+      if (n < 6) return -1;+      if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40+            && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40+            && (s[5] ^ 0x80) < 0x40+            && (c >= 0xfd || s[1] >= 0x84)))+        return -1;+      *pwc++ = ((unsigned) (c & 0x01) << 30)+        | ((unsigned) (s[1] ^ 0x80) << 24)+        | ((unsigned) (s[2] ^ 0x80) << 18)+        | ((unsigned) (s[3] ^ 0x80) << 12)+        | ((unsigned) (s[4] ^ 0x80) << 6)+        | (unsigned) (s[5] ^ 0x80);+      n -= 6;+      s += 6;+    } else+      return -1;+  }+  return pwc - pwc_original;+}++/* Conversion to and from hex */++void conv_to_hex(unsigned char *dest, unsigned char *from, int num_chars)+{+    static char hex[] = "0123456789abcdef";+    unsigned char *end;++    for (end = from + num_chars; from < end; from++) {+        *dest++ = hex[*from >> 4];+        *dest++ = hex[*from & 0xf];+    }++    return;+}++#define NYBBLE_TO_INT(c) \+    ((c) - ((c) >= 'a' ? 'a' - 10 : '0'))++void conv_from_hex(unsigned char *dest, unsigned char *from, int num_chars)+{+    unsigned char *end;+    unsigned char c;++    end = dest + num_chars;+    while (dest < end) {+        c = NYBBLE_TO_INT(*from) << 4, from++;+        *dest++ = c | NYBBLE_TO_INT(*from), from++;+    }++    return;+}
+ src/fpstring.h view
@@ -0,0 +1,18 @@+#include <HsFFI.h>+#include <sys/types.h>++int wfindps_helper(char c, const char *s, int len);+void debug_free(void *p);+void debug_alloc(void *p, const char *name);++int first_white(const char *s, int len);+int first_nonwhite(const char *s, int len);+int has_funky_char(const char *s, int len);++char *my_mmap(size_t len, int fd);++int utf8_to_ints(HsInt *pwc, const unsigned char *s, int n);++void conv_to_hex(unsigned char *dest, unsigned char *from, int num_chars);+void conv_from_hex(unsigned char *dest, unsigned char *from, int num_chars);+
+ src/gadts.h view
@@ -0,0 +1,11 @@+#ifdef GADT_WITNESSES++#define C(contexts) contexts+#define FORALL(types) forall types.++#else++#define C(contexts)+#define FORALL(types)++#endif
+ src/gpl.tex view
@@ -0,0 +1,414 @@+% This is the FSF GPL, reformatted as an appendix by David Roundy++% This file is intended to be included in another file.++\chapter{The GNU General Public License}+\label{gpl}+\section*{Version 2, June 1991}++\begin{center}+Version 2, June 1991++Copyright \copyright\ 1989, 1991 Free Software Foundation, Inc.++\bigskip++51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA++\bigskip++Everyone is permitted to copy and distribute verbatim copies+of this license document, but changing it is not allowed.++\end{center}++\section*{Preamble}+\begin{quote}+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.+\end{quote}++\begin{center}+{\Large \sc GNU General Public License+\\\vspace{3mm}Terms and Conditions For Copying, Distribution and Modification}+\end{center}+++\begin{enumerate}++\addtocounter{enumi}{-1}++\item ++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.++\item 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.++\item++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:++\begin{enumerate}++\item ++You must cause the modified files to carry prominent notices stating that+you changed the files and the date of any change.++\item++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.++\item+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.)++\end{enumerate}+++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.++\item+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:++\begin{enumerate}++\item++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,++\item++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,++\item++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.)++\end{enumerate}+++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.++\item+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.++\item+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.++\item+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.++\item+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.++\item+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.++\item+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.++\item+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.++\begin{center}+{\Large\sc+No Warranty+}+\end{center}++\item+{\sc 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.}++\item+{\sc 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{enumerate}+++\begin{center}+{\Large\sc End of Terms and Conditions}+\end{center}++\section{Appendix: 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.++\begin{quote}+$<$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.+\end{quote}++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:++\begin{quote}+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.+\end{quote}+++The hypothetical commands {\tt show w} and {\tt show c} should show the+appropriate parts of the General Public License.  Of course, the commands+you use may be called something other than {\tt show w} and {\tt 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:++\begin{quote}+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+\end{quote}+++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.
+ src/hscurl.c view
@@ -0,0 +1,287 @@+#ifdef HAVE_CURL++#include "hscurl.h"++#include <curl/curl.h>+#include <stdlib.h>+#include <string.h>++enum RESULT_CODES+  {+    RESULT_OK = 0,+    RESULT_MALLOC_FAIL,+    RESULT_SELECT_FAIL,+    RESULT_MULTI_INIT_FAIL,+    RESULT_EASY_INIT_FAIL,+    RESULT_SLIST_APPEND_FAIL,+    RESULT_NO_RUNNING_HANDLES,+    RESULT_MULTI_INFO_READ_FAIL,+    RESULT_UNKNOWN_MESSAGE,+    RESULT_FILE_OPEN_FAIL+  };++static const char *error_strings[] =+  {+    "",+    "malloc() failed",+    "select() failed",+    "curl_multi_init() failed",+    "curl_easy_init() failed",+    "curl_slist_append() failed",+    "curl_multi_perform() - no running handles",+    "curl_multi_info_read() failed",+    "curl_multi_info_read() returned unknown message",+    "fopen() failed"+  };++struct UrlData+{+  char *url;+  FILE *file;+  struct curl_slist *headers;+};++static const char user_agent[] =+  "darcs/" PACKAGE_VERSION " libcurl/" LIBCURL_VERSION;+static const char *proxypass;+static int init_done = 0;+static CURLM *multi = NULL;+static int msgs_in_queue = 0;+static char *last_url = NULL;++static const char *perform()+{+  int error;+  int running_handles, running_handles_last;+  fd_set fd_read, fd_write, fd_except;+  int max_fd;+  long timeout;+  struct timeval tval;++  error = curl_multi_perform(multi, &running_handles);+  if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM)+    return curl_multi_strerror(error);+  if (running_handles == 0)+    return error_strings[RESULT_NO_RUNNING_HANDLES];++  running_handles_last = running_handles;+  while (1)+    {+      while (error == CURLM_CALL_MULTI_PERFORM)+        error = curl_multi_perform(multi, &running_handles);++      if (error != CURLM_OK)+        return curl_multi_strerror(error);++      if (running_handles < running_handles_last)+        break;++      FD_ZERO(&fd_read);+      FD_ZERO(&fd_write);+      FD_ZERO(&fd_except);++      error = curl_multi_fdset(multi, &fd_read, &fd_write, &fd_except, &max_fd);+      if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM)+        return curl_multi_strerror(error);++#ifdef CURL_MULTI_TIMEOUT+      error = curl_multi_timeout(multi, &timeout);+      if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM)+        return curl_multi_strerror(error);++      if (timeout == -1)+#endif+        timeout = 100;++      tval.tv_sec = timeout / 1000;+      tval.tv_usec = timeout % 1000 * 1000;++      if (select(max_fd + 1, &fd_read, &fd_write, &fd_except, &tval) < 0)+        return error_strings[RESULT_SELECT_FAIL];++      error = CURLM_CALL_MULTI_PERFORM;+    }++  return NULL;+}++const char *curl_request_url(const char *url,+                             const char *filename,+                             int cache_time)+{+  int error;++  if (init_done == 0)+    {+      error = curl_global_init(CURL_GLOBAL_ALL);+      if (error != CURLE_OK)+        return curl_easy_strerror(error);+      proxypass = getenv("DARCS_PROXYUSERPWD");+      init_done = 1;+    }++  if (multi == NULL)+    {+      multi = curl_multi_init();+      if (multi == NULL)+        return error_strings[RESULT_MULTI_INIT_FAIL];+#ifdef CURL_PIPELINING+      error = curl_multi_setopt(multi, CURLMOPT_PIPELINING, 1);+      if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM)+        return curl_multi_strerror(error);+#endif+    }++  CURL *easy = curl_easy_init();+  if (easy == NULL)+    return error_strings[RESULT_EASY_INIT_FAIL];++#ifdef CURL_DEBUG+  error = curl_easy_setopt(easy, CURLOPT_VERBOSE, 1);+  if (error != CURLE_OK)+    return curl_easy_strerror(error);+#endif++  struct UrlData *url_data = malloc(sizeof(struct UrlData));+  if (url_data == NULL)+    return error_strings[RESULT_MALLOC_FAIL];++  url_data->url = strdup(url);+  if (url_data->url == NULL)+    return error_strings[RESULT_MALLOC_FAIL];++  url_data->file = fopen(filename,"wb");+  if (url_data->file == NULL)+    return error_strings[RESULT_FILE_OPEN_FAIL];++  error = curl_easy_setopt(easy, CURLOPT_PRIVATE, url_data);+  if (error != CURLE_OK)+    return curl_easy_strerror(error);++  error = curl_easy_setopt(easy, CURLOPT_URL, url_data->url);+  if (error != CURLE_OK)+    return curl_easy_strerror(error);++#ifdef CURLOPT_WRITEDATA+  error = curl_easy_setopt(easy, CURLOPT_WRITEDATA, url_data->file);+#else+  error = curl_easy_setopt(easy, CURLOPT_FILE, url_data->file);+#endif+  if (error != CURLE_OK)+    return curl_easy_strerror(error);++  error = curl_easy_setopt(easy, CURLOPT_USERAGENT, user_agent);+  if (error != CURLE_OK)+    return curl_easy_strerror(error);++  error = curl_easy_setopt(easy, CURLOPT_FOLLOWLOCATION, 1);+  if (error != CURLE_OK)+    return curl_easy_strerror(error);++  error = curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1);+  if (error != CURLE_OK)+    return curl_easy_strerror(error);++  error = curl_easy_setopt(easy, CURLOPT_HTTPAUTH, CURLAUTH_ANY);+  if (error != CURLE_OK)+    return curl_easy_strerror(error);++  /* libcurl currently always sends Pragma: no-cache, but never+     Cache-Control, which is contradictory.  We override both, just to+     be sure. */+  url_data->headers = curl_slist_append(NULL, "Accept: */*");+  if(cache_time == 0)+    {+      url_data->headers =+        curl_slist_append(url_data->headers, "Pragma: no-cache");+      url_data->headers =+        curl_slist_append(url_data->headers, "Cache-Control: no-cache");+    }+  else if(cache_time > 0)+    {+      /* This won't work well with HTTP/1.0 proxies. */+      char buf[40];+      snprintf(buf, sizeof(buf), "Cache-Control: max-age=%d", cache_time);+      buf[sizeof(buf) - 1] = '\n';+      url_data->headers = curl_slist_append(url_data->headers, "Pragma:");+      url_data->headers = curl_slist_append(url_data->headers, buf);+    }+  else+    {+      url_data->headers = curl_slist_append(url_data->headers, "Pragma:");+      url_data->headers = curl_slist_append(url_data->headers, "Cache-Control:");+    }+  if (url_data->headers == NULL)+    return error_strings[RESULT_SLIST_APPEND_FAIL];++  error = curl_easy_setopt(easy, CURLOPT_HTTPHEADER, url_data->headers);+  if (error != CURLE_OK)+    return curl_easy_strerror(error);++  if (proxypass && *proxypass)+    {+      error = curl_easy_setopt(easy, CURLOPT_PROXYUSERPWD, proxypass);+      if (error != CURLE_OK)+        return curl_easy_strerror(error);+    }++  error = curl_multi_add_handle(multi, easy);+  if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM)+    return curl_multi_strerror(error);++  return error_strings[RESULT_OK];+}++const char *curl_wait_next_url()+{+  if (last_url != NULL)+    {+      free(last_url);+      last_url = NULL;+    }++  if (msgs_in_queue == 0)+    {+      const char *error = perform();+      if (error != NULL)+        return error;+    }++  CURLMsg *msg = curl_multi_info_read(multi, &msgs_in_queue);+  if (msg == NULL)+    return error_strings[RESULT_MULTI_INFO_READ_FAIL];++  if (msg->msg == CURLMSG_DONE)+    {+      CURL *easy = msg->easy_handle;+      CURLcode result = msg->data.result;+      struct UrlData *url_data;+      int error = curl_easy_getinfo(easy, CURLINFO_PRIVATE, (char **)&url_data);+      if (error != CURLE_OK)+        return curl_easy_strerror(error);++      last_url = url_data->url;+      fclose(url_data->file);+      curl_slist_free_all(url_data->headers);+      free(url_data);++      error = curl_multi_remove_handle(multi, easy);+      if (error != CURLM_OK && error != CURLM_CALL_MULTI_PERFORM)+        return curl_multi_strerror(error);+      curl_easy_cleanup(easy);++      if (result != CURLE_OK)+        return curl_easy_strerror(result);+    }+  else+    return error_strings[RESULT_UNKNOWN_MESSAGE];++  return error_strings[RESULT_OK];+}++const char *curl_last_url()+{+  return last_url != NULL ? last_url : "";+}++#endif
+ src/hscurl.h view
@@ -0,0 +1,7 @@+const char *curl_request_url(const char *url,+                             const char *filename,+                             int cache_time);++const char *curl_wait_next_url();++const char *curl_last_url();
+ src/hslibwww.c view
@@ -0,0 +1,179 @@+#ifdef HAVE_LIBWWW++#include "hslibwww.h"++#include <stdio.h>+#include <string.h>++static const char darcs_version[] = PACKAGE_VERSION;++#include <WWWLib.h>+#include <WWWInit.h>++enum RESULT_CODES+  {+    RESULT_OK = 0,+    RESULT_REQUEST_NEW_FAIL,+    RESULT_NET_ADD_AFTER_FAIL,+    RESULT_REQUEST_ADD_CACHE_CONTROL_FAIL,+    RESULT_LOAD_TO_FILE_FAIL,+    RESULT_MALLOC_FAIL,+    RESULT_LIST_NEW_FAIL,+    RESULT_LIST_APPEND_OBJECT_FAIL,+    RESULT_EVENTLIST_NEW_LOOP+  };++static const char *error_strings[] =+  {+    "",+    "HTRequest_new() failed",+    "HTNet_addAfter() failed",+    "HTRequest_addCacheControl() failed",+    "HTLoadToFile() failed",+    "malloc() failed",+    "HTList_new() failed",+    "HTList_appendObject() failed",+    "HTEventList_newLoop() failed"+  };++struct Completed+{+  int error;+  char *url;+};++static BOOL init_done = NO;+static int error;+static HTList *completed_list = NULL;+static char *last_url = NULL;+static char libwww_error[80];+static const char libwww_error_fmt[] = "libwww error code: %i";++int terminate_handler(HTRequest *request,+                      HTResponse *response,+                      void *param,+                      int status)+{+  struct Completed *completed = malloc(sizeof(struct Completed));+  if (completed == NULL)+    error = RESULT_MALLOC_FAIL;+  else+    {+      if (HTList_appendObject(completed_list, completed) == NO)+        {+          error = RESULT_LIST_APPEND_OBJECT_FAIL;+          free(completed);+        }+      else+        {+          error = RESULT_OK;+          completed->error = status;+          completed->url = HTRequest_context(request);+        }+    }++  HTRequest_delete(request);+  HTEventList_stopLoop();++  // Return not HT_OK to stop executing after filters.+  return HT_ERROR;+}++const char *libwww_request_url(const char *url,+                               const char *filename,+                               int cache_time)+{+  BOOL result;++  if (init_done == NO)+    {+      HTProfile_newNoCacheClient("darcs", darcs_version);+      HTProxy_getEnvVar();+      HTAlert_setInteractive(NO);+      HTFormat_addCoding("*", NULL, HTIdentityCoding, 1.0);+#ifdef LIBWWW_DEBUG+      HTSetTraceMessageMask("sop");+#endif+      init_done = YES;+    }++  if (completed_list == NULL)+    {+      completed_list = HTList_new();+      if (completed_list == NULL)+        return error_strings[RESULT_LIST_NEW_FAIL];+    }++  HTRequest *const request = HTRequest_new();+  if (request == NULL)+    return error_strings[RESULT_REQUEST_NEW_FAIL];++  HTRequest_setContext(request, strdup(url));++  result = HTNet_addAfter(terminate_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST);+  if (result == NO)+    return error_strings[RESULT_NET_ADD_AFTER_FAIL];++  if (cache_time == 0)+    {+      HTRequest_addGnHd(request, HT_G_PRAGMA_NO_CACHE);+      result = HTRequest_addCacheControl(request, "no-cache", "");+    }+  else if (cache_time > 0)+    {+      char buf[8];+      snprintf(buf, sizeof(buf), "%d", cache_time);+      buf[sizeof(buf) - 1] = '\0';+      result = HTRequest_addCacheControl(request, "max-age", buf);+    }+  if (result == NO)+    return error_strings[RESULT_REQUEST_ADD_CACHE_CONTROL_FAIL];++  result = HTLoadToFile(url, request, filename);+  if (result == NO)+    return error_strings[RESULT_LOAD_TO_FILE_FAIL];++  return error_strings[RESULT_OK];+}++const char *libwww_wait_next_url()+{+  if (last_url != NULL)+    {+      free(last_url);+      last_url = NULL;+    }++  error = RESULT_OK;+  if (HTList_isEmpty(completed_list) == YES &&+      HTNet_isEmpty() == NO &&+      HTEventList_newLoop() != HT_OK)+    return error_strings[RESULT_EVENTLIST_NEW_LOOP];++  if (HTList_isEmpty(completed_list) == NO)+    {+      struct Completed *completed = HTList_firstObject(completed_list);+      if (completed->error == HT_LOADED)+        libwww_error[0] = '\0';+      else+        {+          snprintf(libwww_error, sizeof(libwww_error),+                   libwww_error_fmt, completed->error);+          libwww_error[sizeof(libwww_error) - 1] = '\0';+        }+      last_url = completed->url;+      HTList_removeFirstObject(completed_list);+      free(completed);++      return libwww_error;+    }++  return error_strings[error];+}++const char *libwww_last_url()+{+  return last_url != NULL ? last_url : "";+}++#endif
+ src/hslibwww.h view
@@ -0,0 +1,7 @@+const char *libwww_request_url(const char *url,+                               const char *filename,+                               int cache_time);++const char *libwww_wait_next_url();++const char *libwww_last_url();
+ src/impossible.h view
@@ -0,0 +1,10 @@+import Darcs.Bug++#define darcsBug (\imp_funny_name -> imp_funny_name (__FILE__,__LINE__,__TIME__,__DATE__))++#define bug        (darcsBug _bug)+#define bugLoc     (darcsBug _bugLoc)+#define withBugLoc (darcsBug _withBugLoc)+#define impossible (darcsBug _impossible)+#define fromJust   (darcsBug _fromJust)+#define bugDoc     (darcsBug _bugDoc)
+ src/make_changelog.hs view
@@ -0,0 +1,232 @@+-- Copyright (C) 2005 Tomasz Zielonka+--+-- 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, 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;  see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++module Main (main) where++import Darcs.Arguments ( showFriendly )+import Darcs.Flags ( DarcsFlag(Summary) )+import Darcs.Repository ( read_repo, withRepository, ($-) )+import Darcs.Repository.Prefs ( boring_file_filter )+import Darcs.Patch.Match ( match_parser, match_pattern, apply_matcher, Matcher,+                    make_matcher )+import Darcs.Patch.MatchData ( PatchMatch(..) )+import Darcs.Patch.Info ( PatchInfo, just_name, just_author, pi_date, pi_tag )+import Darcs.Patch.Ordered ( unsafeUnRL, concatRL )+import Darcs.Hopefully ( info )+import Darcs.Sealed ( liftSM )++import Data.Char ( isSpace )+import Data.Maybe ( catMaybes, mapMaybe, isNothing )+import Data.List ( intersperse, unfoldr )++import Text.ParserCombinators.Parsec+import Printer ( Doc, text, (<+>), (<>), parens, renderString, vcat )+import System (getArgs)+import Control.Monad.Writer+import System.Time ( formatCalendarTime )+import System.Locale ( defaultTimeLocale, rfc822DateFormat )+import System.IO (hPutStr, stderr)++type ChangeLogEntry p = ([Matcher p], Maybe Doc)++main :: IO ()+main = withRepository [] $- \repository -> do+    boring_filter <- boring_file_filter+    entries <- liftM concat $ do+        fnames <- boring_filter `liftM` getArgs+        mapM loadEntryFile fnames++    history <- do+        full_backward_history <- concatRL `liftSM` read_repo repository+        return $+            reverse $+            takeWhile (not . (apply_matcher matchTag_1_0_2)) $+            unsafeUnRL $ full_backward_history++    let (unmatched, docs) = runWriter (foldM processPatch entries history)++    putStr (renderDocs (reverse docs))++    when (not (null unmatched)) $ do+        hPutStr stderr $ concat+            [ "\nunmatched ChangeLog entries (upcoming?):\n\n"+            , renderDocs (mapMaybe snd unmatched)+            ]++    let unlogged = filter (\p -> not $ any (`apply_matcher` p) allpatterns)+                 . filter (isNothing . pi_tag . info) $ history+         where allpatterns = concat $ map fst entries+    when (not (null unlogged)) $ do+        hPutStr stderr $ concat+           [ "\npatches which have not yet been changelogged\n\n"+           , renderDocs $ map (showFriendly [Summary]) unlogged+           ]++  where+    processPatch entries patch = do+        let pinfo = info patch+        entries' <- liftM catMaybes $ (`mapM` entries) $ \(patterns, descr) -> do+            let patterns' = filter (not . (`apply_matcher` patch)) patterns+            if null patterns'+              then do+                case descr of+                 Nothing -> return ()+                 Just d  -> tell [d]+                return Nothing+              else do+                return (Just (patterns', descr))+        when (matchTag `apply_matcher` patch) $ do+            let 'T':'A':'G':' ':tagName = just_name pinfo+            when (isStableTag tagName) $ do+                tell [text (" -- " ++ just_author pinfo ++ "  " ++ show_pi_date pinfo)]+                tell [text "darcs" <+> parens (text tagName)]+        return entries'++show_pi_date :: PatchInfo -> String+show_pi_date pinfo =+    formatCalendarTime defaultTimeLocale rfc822DateFormat (pi_date pinfo)++matchTag :: Matcher p+matchTag = match_pattern (PatternMatch "name \"^TAG \"")++matchTag_1_0_2 :: Matcher p+matchTag_1_0_2 = match_pattern (PatternMatch "exact \"TAG 1.0.2\"")++isStableTag :: String -> Bool+isStableTag tagName = +    case parse p "" tagName of+        Left _ -> False+        Right _ -> True+  where+    p = do+        many1 digit+        char '.'+        many1 digit+        char '.'+        many1 digit+        many letter+        many digit+        eof++render :: Doc -> String+render = renderString++renderDocs :: [Doc] -> String+renderDocs = unlines . intersperse "" . map render++--------------------------------------------------------------------------------+-- Parsing ChangeLog entries++restOfLine :: CharParser st String+restOfLine = do+    rest <- many (noneOf "\r\n")+    optional (char '\r')+    return rest++formatEntry :: [String] -> Doc+formatEntry descr =+    vcat . indent 2 '*' . map text+         . wrap 75+         . unwords . concatMap words $ descr++wrap :: Int -> String -> [String]+wrap n = unfoldr cut+ where+   cut ""  = Nothing+   cut str =+    let (xy,z)  = splitAt n str+        (_y,_x) = break isSpace (reverse xy)+        x = reverse . drop 1 $ _x+        y = reverse _y+    in Just $ if null z then      (xy, z)+              else if null x then (y ++ z, "")+                   else           (x, y ++ z)++indent :: Int -> Char -> [Doc] -> [Doc]+indent _ _ []      = []+indent n b (x:xs)  = prefixH x : map prefixT xs+ where+   prefixH h = padding n <> text [b] <+> h+   prefixT t = padding (n+1)         <+> t+   padding p = text . take p . repeat $ ' '++entry :: CharParser st (ChangeLogEntry p)+entry =+ do emptyLine+    e <- matchEntry <|> ignoreEntry+    emptyLine+    return e++ignoreEntry :: CharParser st (ChangeLogEntry p)+ignoreEntry = do+    patterns <- many1 $ do+        try (string "ignore:")+        startPos <- getPosition+        -- take the characters to the end of line+        s <- restOfLine+        endState <- getParserState+        -- and parse them again as a match pattern+        setPosition startPos+        setInput s+        m <- match_parser+        -- restore parser state+        setParserState endState+        newline+        return (make_matcher s m)+    return (patterns, Nothing)++matchEntry :: CharParser st (ChangeLogEntry p)+matchEntry = do+    patterns <- many1 $ do+        try (string "match:")+        startPos <- getPosition+        -- take the characters to the end of line+        s <- restOfLine+        endState <- getParserState+        -- and parse them again as a match pattern+        setPosition startPos+        setInput s+        m <- match_parser+        -- restore parser state+        setParserState endState+        newline+        return (make_matcher s m)+    emptyLine+    descr <- many1 $ do+        char '>'+        skipMany (char ' ' <|> char '\t')+        cs <- restOfLine+        newline+        return cs+    return (patterns, Just $ formatEntry descr)++emptyLine :: CharParser st ()+emptyLine = skipMany $ do optional (char '#' >> restOfLine)+                          newline++entryFile :: CharParser st [ChangeLogEntry p]+entryFile = do es <- many entry+               eof+               return es++loadEntryFile :: FilePath -> IO [ChangeLogEntry p]+loadEntryFile fname = do+    cs <- readFile fname -- ratify readFile: not part of darcs executable+    case parse entryFile fname cs of+        Left err -> fail (show err)+        Right x -> return x+
+ src/maybe_relink.c view
@@ -0,0 +1,173 @@+/*+  Copyright (C) 2005 Juliusz Chroboczek++  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, 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; see the file COPYING.  If not, write to+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+  Boston, MA 02110-1301, USA.+*/++#include <sys/types.h>+#include <sys/stat.h>+#include <fcntl.h>+#include <string.h>+#include <stdio.h>+#include <stdlib.h>++#include <unistd.h>+#include <errno.h>+#include <sys/time.h>++#ifdef _WIN32+int+maybe_relink(const char *src, const char *dst, int careful)+{+    return 0;+}++#else++/* Tries to link src to dst if both files exist and have the same+   contents.  If careful is false only the file sizes are compared; if+   it is true, the full contents are compared.++   This code assumes that dst cannot change behind our back -- the+   caller is supposed to protect it by a lock.  On the other hand, it+   does handle simultaneous access to src, but only if src is never+   modified in place.  It should also be safe over NFS.++   Assumes that rename cannot fail mid-way on a single filesystem.++   Returns 1 on success, 0 if the files are already linked, -1 for an+   error in errno, -2 if the files cannot be linked because they are not+   the same, on different devices, or on a filesystem with no support for+   hard links, -3 if there was a race condition, -4 if something unexpected+   happened. */++int+maybe_relink(char *src, char *dst, int careful)+{+#define RELINK_BUFFER_SIZE 8192++    int len, rc, saved_errno;+    char *tempname;+    struct stat srcstat, dststat, tempstat;+    struct timeval now;++    rc = stat(src, &srcstat);+    if(rc < 0) {+        if(errno == ENOENT)+            return -2;+        else+            return -1;+    }++    rc = stat(dst, &dststat);+    if(rc < 0) return -1;++    if(!S_ISREG(srcstat.st_mode) || !S_ISREG(dststat.st_mode)) {+        return -4;+    }++    if(srcstat.st_dev != dststat.st_dev) {+        return -2;+    }++    if(srcstat.st_ino == dststat.st_ino)+        /* Files are already linked */+        return 0;++    if(srcstat.st_size != dststat.st_size)+        return -2;++    /* link is atomic even on NFS, we will fail gracefully if the name+       is not unique. */+    gettimeofday(&now, NULL);+    rc = strlen(dst) + 6;+    tempname = malloc(rc);+    if(tempname == NULL) return -1;+    len = snprintf(tempname, rc, "%s-%04x", dst,+                   ((unsigned)(now.tv_usec ^ (now.tv_usec >> 16))) & 0xFFFF);+    if(len < 0 || len >= rc) {+        free(tempname);+        return -4;+    }++    rc = link(src, tempname);+    if(rc < 0) {+        /* We need to try to remove the link in case this was a+           problem with NFS over an unreliable transport. */+        goto fail;+    }++    rc = stat(tempname, &tempstat);+    if(rc < 0) goto fail;++    /* Check for a race condition.  The size and mtime checks are+       gratuitious, but they don't cost much, and might save your data+       if you're on a filesystem without i-nodes. */+    if(tempstat.st_ino != srcstat.st_ino ||+       tempstat.st_size != srcstat.st_size ||+       tempstat.st_mtime != srcstat.st_mtime) {+        unlink(tempname);+        free(tempname);+        return -3;+    }+    if(careful) {+        int fd1, fd2, i, rc1, rc2;+        char buf1[RELINK_BUFFER_SIZE], buf2[RELINK_BUFFER_SIZE];++        fd1 = open(tempname, O_RDONLY);+        if(fd1 < 0) goto fail;+        fd2 = open(dst, O_RDONLY);+        if(fd2 < 0) { close(fd1); goto fail; }++        i = 0;+        /* This comparison is approximate: it doesn't deal with short+           reads and EINTR.  It's okay, as these cases are rare and if+           they happen, we're still safe. */+        while(i < tempstat.st_size) {+            rc1 = read(fd1, buf1, RELINK_BUFFER_SIZE);+            if(rc1 < 0) { close(fd1); close(fd2); goto fail; }+            rc2 = read(fd2, buf2, RELINK_BUFFER_SIZE);+            if(rc2 < 0) { close(fd1); close(fd2); goto fail; }+            if(rc1 == 0 || rc1 != rc2 || memcmp(buf1, buf2, rc1) != 0) {+                close(fd1); close(fd2);+                unlink(tempname);+                free(tempname);+                return -2;+            }+            i += rc1;+        }+        close(fd1); close(fd2);+    }++    rc = rename(tempname, dst);+    if(rc < 0) goto fail;++    free(tempname);+    return 1;++ fail:+    saved_errno = errno;+    unlink(tempname);+    free(tempname);+    errno = saved_errno;+    if(errno == EPERM || errno == EOPNOTSUPP)+        return -2;+    return -1;++#undef RELINK_BUFFER_SIZE+}++#endif
+ src/maybe_relink.h view
@@ -0,0 +1,1 @@+int maybe_relink(const char *src, const char *dst, int careful);
+ src/patch-theory.pdf view

binary file changed (absent → 43270 bytes)

+ src/preproc.hs view
@@ -0,0 +1,128 @@+import System+import Text.Regex ( matchRegex, mkRegex )++import Darcs.Commands+import Darcs.Arguments+import Darcs.Commands.Help ( command_control_list )+import Darcs.FilePathUtils ( (///) )+import Autoconf ( darcs_version )++the_commands :: [DarcsCommand]+the_commands = extract_commands command_control_list++main :: IO ()+main = do+  args <- getArgs+  if length args < 1+     then exitWith $ ExitFailure 1+     else return ()+  putStrLn "%% This file was automatically generated by preproc."+  c <- preproc ["\\input{"++head args++"}"]+  mapM_ putStrLn c++am_html :: IO Bool+am_html = do args <- getArgs+             case args of+               [_,"--html"] -> return True+               _ -> return False++preproc :: [String] -> IO [String]+preproc ("\\usepackage{html}":ss) = -- only use html package with latex2html+    do rest <- preproc ss+       ah <- am_html+       if ah then return $ "\\usepackage{html}" : rest+             else return $ "\\newcommand{\\htmladdnormallink}[2]{#1}" :+                  "\\newcommand{\\htmladdnormallinkfoot}[2]{#1\\footnotetext{\\tt #2}}"+                  : rest+preproc ("\\begin{code}":ss) = ignore ss+preproc ("\\begin{options}":ss) =+    do rest <- preproc ss+       ah <- am_html+       if ah then return $ "\\begin{rawhtml}" : "<div class=\"cmd-opt-hdr\">" : rest+             else return $ ("\\begin{Verbatim}[frame=lines,xleftmargin=1cm," +++                            "xrightmargin=1cm]") : rest+preproc ("\\end{options}":ss) =+    do rest <- preproc ss+       ah <- am_html+       if ah then return $ "</div>" : "\\end{rawhtml}" : rest+             else return $ "\\end{Verbatim}" : rest+preproc (s:ss) = do+  rest <- preproc ss+  case matchRegex (mkRegex "^\\\\input\\{(.+)\\}$") s of+    Just (fn:_) -> do cs <- readFile $ "src" /// fn -- ratify readFile: not part of+                                        -- darcs executable+                      this <- preproc $ lines cs+                      return $ this ++ rest+    _ -> case matchRegex (mkRegex "^(.*)\\\\haskell\\{(.+)\\}(.*)$") s of+         Just (before:var:after:_) ->+             case breakLast '_' var of+             (cn,"help") -> return $ (before++gh cn++after):rest+             (cn,"description") -> return $ (before++gd cn++after):rest+             ("darcs","version") -> return $ (before++darcs_version++after):rest+             aack -> error $ show aack+         _ -> case matchRegex (mkRegex "^(.*)\\\\options\\{(.+)\\}(.*)$") s of+              Just (before:comm:after:_) ->+                  return $ (before++get_options comm++after):rest+              _ ->  case matchRegex (mkRegex "^(.*)\\\\example\\{(.+)\\}(.*)$") s of+                    Just (before:fn:after:_) -> do+                        filecont <- readFile fn -- ratify readFile: not part of+                                                -- darcs executable+                        return $ (before++"\\begin{verbatim}"+++                                  filecont++"\\end{verbatim}"+                                  ++after):rest+                    _ -> return $ s : rest+  where breakLast chr str = (reverse $ tail l, reverse f)+            where (f, l) = break (==chr) $ reverse str++preproc [] = return []++get_options :: String -> String+get_options comm = get_com_options $ get_c names the_commands+    where names = words comm++get_c :: [String] -> [DarcsCommand] -> [DarcsCommand]+get_c (name:ns) commands =+    case ns of+    [] -> [get name commands]+    _ -> case get name commands of+         c@SuperCommand { } ->+             c:(get_c ns $ extract_commands $ command_sub_commands c)+         _ ->+             error $ "Not a supercommand: " ++ name+    where get n (c:cs) | command_name c == n = c+                       | otherwise = get n cs+          get n [] = error $ "No such command:  "++n+get_c [] _ = error "no command specified"++get_com_options :: [DarcsCommand] -> String+get_com_options c =+    "\\verb!Usage: darcs " ++ cmd ++ " [OPTION]... " +++    args ++ "!\n\n" ++ "Options:\n\n" ++ options_latex opts1 +++    (if null opts2 then "" else "\n\n" ++ "Advanced options:\n\n" ++ options_latex opts2)+    where cmd = unwords $ map command_name c+          args = unwords $ command_extra_arg_help $ last c+          opts1 = command_basic_options $ last c+          opts2 = command_advanced_options $ last c++ignore :: [String] -> IO [String]+ignore ("\\end{code}":ss) = preproc ss+ignore (_:ss) = ignore ss+ignore [] = return []++command_property :: (DarcsCommand -> String) -> [DarcsCommand] -> String+                 -> String+command_property property commands name =+    property $ last c+    where words_ :: String -> [String] -- "word" with '_' instead of spaces+          words_ s =+              case dropWhile (=='_') s of+                       "" -> []+                       s' -> w : words_ s''+                           where (w, s'') = break (=='_') s'+          names = words_ name+          c = get_c names commands++gh :: String -> String+gh = command_property command_help the_commands+gd :: String -> String+gd = command_property command_description the_commands
+ src/switching.tex view
@@ -0,0 +1,147 @@+\section{Switching from CVS}++Darcs is refreshingly different from CVS.++CVS keeps version controlled data in a central repository, and+requires that users check out a working directory whenever they wish+to access the version-controlled sources.  In order to modify the+central repository, a user needs to have write access to the central+repository; if he doesn't, CVS merely becomes a tool to get the latest+sources.++In darcs there is no distinction between working directories and+repositories.  In order to work on a project, a user makes a local+copy of the repository he wants to work in; he may then harness the+full power of version control locally.  In order to distribute his+changes, a user who has write access can \emph{push} them to the+remote repository; one who doesn't can simply send them by e-mail in a+format that makes them easy to apply on the remote system.++\paragraph{Darcs commands for CVS users}+Because of the different models used by cvs and darcs, it is+difficult to provide a complete equivalence between cvs and darcs.+A rough correspondence for the everyday commands follows:\\+% The \hspace commands force a line break in the postscript output,+% but they are effectively ignored in the html output.+\begin{description}\addtolength{\itemsep}{-0.5\baselineskip}+\item[{\tt cvs checkout}\hspace*{100em}]+   {\tt darcs get}+\item[{\tt cvs update}\hspace*{100em}]+   {\tt darcs pull}+\item[{\tt cvs -n update}\hspace*{100em}]+   {\tt darcs pull \verb!--dry-run!}+      (summarize remote changes)+\item[{\tt cvs -n update}\hspace*{100em}]+   {\tt darcs whatsnew \verb!--summary!}+      (summarize local changes)+\item[{\tt cvs -n update | grep '?'}\hspace*{100em}]+   {\tt darcs whatsnew -ls | grep \verb!^a! }+      (list potential files to add)+\item[{\tt rm foo.txt; cvs update foo.txt}\hspace*{100em}]+   {\tt darcs revert foo.txt}+      (revert to foo.txt from repo)+\item[{\tt cvs diff}\hspace*{100em}]+   {\tt darcs whatsnew}+      (if checking local changes)+\item[{\tt cvs diff}\hspace*{100em}]+   {\tt darcs diff}+      (if checking recorded changes)+\item[{\tt cvs commit}\hspace*{100em}]+   {\tt darcs record}+      (if committing locally)+\item[{\tt cvs commit}\hspace*{100em}]+   {\tt darcs tag}+      (if marking a version for later use)+\item[{\tt cvs commit}\hspace*{100em}]+   {\tt darcs push} or {\tt darcs send}+      (if committing remotely)+\item[{\tt cvs diff | mail}\hspace*{100em}]+   {\tt darcs send}+\item[{\tt cvs add}\hspace*{100em}]+   {\tt darcs add}+\item[{\tt cvs tag -b}\hspace*{100em}]+   {\tt darcs get}+\item[{\tt cvs tag}\hspace*{100em}]+   {\tt darcs tag}+\end{description}++\paragraph{Migrating CVS repositories to darcs}++Tools and instructions for migrating CVS repositories to darcs are provided+on the darcs community website: +\htmladdnormallinkfoot{http://darcs.net/DarcsWiki/ConvertingFromCvs}{http://darcs.net/DarcsWiki/ConvertingFromCvs}+++\section{Switching from arch}++Although arch, like darcs, is a distributed system, and the two systems+have many similarities (both require no special server, for example), their+essential organization is very different.++Like CVS, arch keeps data in two types of data structures:+repositories (called ``archives'') and working directories.  In order+to modify a repository, one must first check out a corresponding+working directory. This requires that users remember a number of+different ways of pushing data around --- \verb|tla| \verb|get|,+\verb|update|, \verb|commit|, \verb|archive-mirror| and so on.++In darcs, on the other hand, there is no distinction between working+directories and repositories, and just checking out your sources+creates a local copy of a repository.  This allows you to harness the+full power of version control in any scratch copy of your sources, and+also means that there are just two ways to push data around:+\verb|darcs| \verb|record|, which stores edits into your local+repository, and \verb|pull|, which moves data between repositories.+(\verb|darcs| \verb|push| is merely the opposite of \verb|pull|;+\verb|send| and \verb|apply| are just the two halves of \verb|push|).++\paragraph{Darcs commands for arch users}++Because of the different models used by arch and darcs, it is+difficult to provide a complete equivalence between arch and darcs.+A rough correspondence for the everyday commands follows:\\+\begin{description}\addtolength{\itemsep}{-0.5\baselineskip}+\item[{\tt tla init-tree}\hspace*{100em}]+   {\tt darcs initialize}+\item[{\tt tla get}\hspace*{100em}]+   {\tt darcs get}+\item[{\tt tla update}\hspace*{100em}]+   {\tt darcs pull}+\item[{\tt tla file-diffs f | patch -R }\hspace*{100em}]+   {\tt darcs revert}+\item[{\tt tla changes --diffs}\hspace*{100em}]+   {\tt darcs whatsnew}+\item[{\tt tla logs}\hspace*{100em}]+   {\tt darcs changes}+\item[{\tt tla file-diffs}\hspace*{100em}]+   {\tt darcs diff -u}+\item[{\tt tla add}\hspace*{100em}]+   {\tt darcs add}+\item[{\tt tla mv}\hspace*{100em}]+   {\tt darcs mv}+      (not {\tt tla move})+\item[{\tt tla commit}\hspace*{100em}]+   {\tt darcs record}+      (if committing locally)+\item[{\tt tla commit}\hspace*{100em}]+   {\tt darcs tag}+      (if marking a version for later use)+\item[{\tt tla commit}\hspace*{100em}]+   {\tt darcs push} or {\tt darcs send}+      (if committing remotely)+\item[{\tt tla archive-mirror}\hspace*{100em}]+   {\tt darcs pull} or {\tt darcs push}+\item[{\tt tla tag}\hspace*{100em}]+   {\tt darcs get}+      (if creating a branch)+\item[{\tt tla tag}\hspace*{100em}]+   {\tt darcs tag}+      (if creating a tag).+\end{description}++\paragraph{Migrating arch repositories to darcs}++Tools and instructions for migrating arch repositories to darcs are provided+on the darcs community website: +\htmladdnormallinkfoot{http://darcs.net/DarcsWiki/ConvertingFromArch}{http://darcs.net/DarcsWiki/ConvertingFromArch}+
+ src/umask.c view
@@ -0,0 +1,34 @@+#include <sys/types.h>+#include <sys/stat.h>+#include <stdlib.h>+#include <errno.h>+#include "umask.h"++int+set_umask(char *mask_string)+{+#ifndef WIN32+    int rc;+    unsigned mask;+    char *end;++    mask = strtoul(mask_string, &end, 8);+    if(!end || *end != '\0') {+        errno = EINVAL;+        return -1;+    }++    rc = umask(mask);+    return rc;+#else+    /* umask() has no useful meaning on win32. */+    return 0;+#endif /* #ifndef WIN32 ... else ... */+}++int+reset_umask(int old_mask)+{+    umask(old_mask);+    return 1;+}
+ src/umask.h view
@@ -0,0 +1,2 @@+int set_umask(char *mask_string);+int reset_umask(int old_mask);
+ src/unit.lhs view
@@ -0,0 +1,810 @@+%  Copyright (C) 2002-2005,2007 David Roundy+%+%  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, 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; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\documentclass{report}+\usepackage{color}++\usepackage{verbatim}+\newenvironment{code}{\color{blue}\verbatim}{\endverbatim}++\begin{document}++% Definition of title page:+\title{+    Unit Testing for darcs in Haskell+}+\author{+    David Roundy    % insert author(s) here+}++\maketitle++\tableofcontents  % Table of Contents++\chapter{Introduction}++This is a unit testing program, which is intended to make sure that all the+functions of my darcs code work properly.++\begin{code}+{-# OPTIONS_GHC -cpp -fno-warn-orphans -fno-warn-deprecations -fglasgow-exts #-}+module Main (main) where+\end{code}++\begin{code}+import Control.Monad (when)+import FastPackedString+import Darcs.Patch+import Darcs.Patch.Test+import Darcs.Patch.Unit ( run_patch_unit_tests )+import Lcs ( shiftBoundaries )+import Test.QuickCheck+import System ( ExitCode(..), exitWith )+import System.IO ( hSetBuffering, stdout, BufferMode(..) )+import Data.IORef ( IORef, newIORef, readIORef, modifyIORef )+import Printer ( renderPS, text )+import Darcs.Patch.Commute+import Control.Monad ( liftM )+import Data.Array.Base+import Data.Array.Unboxed+import Control.Monad.ST+import Darcs.Patch.Ordered+import Darcs.Sealed ( Sealed(Sealed), unsafeUnseal )++import Darcs.Email ( make_email, read_email )+#include "impossible.h"+\end{code}++\chapter{Main body of code}++\begin{code}+main :: IO ()+main = do+  hSetBuffering stdout NoBuffering+  returnval <- newIORef 0+  patch_failures <- run_patch_unit_tests+  if patch_failures > 0+      then do putStrLn $ show patch_failures ++ " failures in Darcs.Patch.Unit."+              exitWith $ ExitFailure 1+      else putStrLn "No failures in Darcs.Patch.Unit."+  when (unpackPSfromUTF8 (packString "hello world") /= "hello world") $+       do putStr "Problem with unpackPSfromUTF8\n"+          putStr $ "hello world isn't '" +++                 unpackPSfromUTF8 (packString "hello world")++"'\n"+          exitWith $ ExitFailure 1+  when (unpackPS (fromHex2PS $ fromPS2Hex $ packString "hello world")+        /= "hello world") $+       do putStr "Problem with binary to hex conversion and back again\n"+          exitWith $ ExitFailure 1+  putStr "Checking that email can be parsed... "+  quickCheck $ \s ->+      unlines ("":s++["", ""]) ==+              unpackPS (read_email (renderPS+                       $ make_email "reponame" (Just (text "contents\n"))+                       (text $ unlines s) (Just "filename")))+  --putStr $ test_patch+  --exitWith ExitSuccess+  case run_tests returnval of+    run -> do+      putStr ("There are a total of "++(show (length primitive_test_patches))+              ++" primitive patches.\n")+      putStr ("There are a total of "+++              (show (length test_patches))++" patches.\n")+      putStr "Checking that concatPS works... "+      quickCheck prop_concatPS+      putStr "Checking that hex conversion works... "+      quickCheck prop_hex_conversion+      putStr "Checking that show and read work right... "+      quickCheck prop_read_show+      run "Checking known commutes... " commute_tests+      run "Checking known merges... " merge_tests+      run "Checking known canons... " canonization_tests+      check_subcommutes subcommutes_inverse "patch and inverse both commutex"+      check_subcommutes subcommutes_nontrivial_inverse+                            "nontrivial commutes are correct"+      check_subcommutes subcommutes_failure "inverses fail"+      putStr "Checking that commuting by patch and its inverse is ok... "+      quickCheck prop_commute_inverse+      --putStr "Checking that conflict resolution is valid... "+      --quickCheck prop_resolve_conflicts_valid+      putStr "Checking that a patch followed by its inverse is identity... "+      quickCheck prop_patch_and_inverse_is_identity+      -- The following tests are "wrong" with the Conflictor code.+      --putStr "Checking that a simple smart_merge is sufficient... "+      --quickCheck prop_simple_smart_merge_good_enough+      --putStr "Checking that an elegant merge is sufficient... "+      --quickCheck prop_elegant_merge_good_enough+      putStr "Checking that commutes are equivalent... "+      quickCheck prop_commute_equivalency+      putStr "Checking that merges are valid... "+      quickCheck prop_merge_valid+      putStr "Checking inverses being valid... "+      quickCheck prop_inverse_valid+      putStr "Checking other inverse being valid... "+      quickCheck prop_other_inverse_valid+      run "Checking merge swaps... " merge_swap_tests+      -- The patch generator isn't smart enough to generate correct test+      -- cases for the following: (which will be obsoleted soon, anyhow)+      --putStr "Checking the order dependence of unravel... "+      --quickCheck prop_unravel_order_independent+      --putStr "Checking the unravelling of three merges... "+      --quickCheck prop_unravel_three_merge+      --putStr "Checking the unravelling of a merge of a sequence... "+      --quickCheck prop_unravel_seq_merge+      putStr "Checking inverse of inverse... "+      quickCheck prop_inverse_composition+      putStr "Checking the order of commutes... "+      quickCheck prop_commute_either_order+      putStr "Checking commutex either way... "+      quickCheck prop_commute_either_way+      putStr "Checking the double commutex... "+      quickCheck prop_commute_twice+      putStr "Checking that merges commutex and are well behaved... "+      quickCheck prop_merge_is_commutable_and_correct+      putStr "Checking that merges can be swapped... "+      quickCheck prop_merge_is_swapable+      putStr "Checking again that merges can be swapped (I'm paranoid) ... "+      quickCheck prop_merge_is_swapable+      run "Checking that the patch validation works... " test_check+      run "Checking commutex/recommute... " commute_recommute_tests+      run "Checking merge properties... " generic_merge_tests+      run "Testing the lcs code... " show_lcs_tests+      run "Checking primitive patch IO functions... " primitive_show_read_tests+      run "Checking IO functions... " show_read_tests+      run "Checking primitive commutex/recommute... "+          primitive_commute_recommute_tests+      trv <- readIORef returnval+      if trv == 0+         then exitWith ExitSuccess+         else exitWith $ ExitFailure trv+\end{code}++\section{run\_tests}++run\_tests is used to run a series of tests (which return a list of strings+describing their failures) and then update n IORef so the program can exit+with an error if one of the tests failed.++\begin{code}+run_tests :: (IORef Int) -> String -> [String] -> IO ()+run_tests return_val s ss = do+    putStr s+    if null ss+       then putStr "good.\n"+       else do modifyIORef return_val (+1)+               print_strings ss+               exitWith $ ExitFailure 1++print_strings :: [String] -> IO ()+print_strings [] = return ()+print_strings (s:ss) = do+  putStr s+  print_strings ss+\end{code}++\chapter{Unit Tester}++The unit tester function is really just a glorified map for functions that+return lists, in which the lists get concatenated (where map would end up+with a list of lists).++\begin{code}+type PatchUnitTest p = p -> [String]+type TwoPatchUnitTest = Patch -> Patch -> [String]+unit_tester :: PatchUnitTest p -> [p] -> [String]+unit_tester _ []        = []+unit_tester thetest (p:ps) = (thetest p)++(unit_tester thetest ps)++parallel_pair_unit_tester :: TwoPatchUnitTest -> [(Patch:\/:Patch)] -> [String]+parallel_pair_unit_tester _ []        = []+parallel_pair_unit_tester thetest ((p1:\/:p2):ps)+    = (thetest p1 p2)++(parallel_pair_unit_tester thetest ps)++pair_unit_tester :: TwoPatchUnitTest -> [(Patch:<Patch)] -> [String]+pair_unit_tester _ []        = []+pair_unit_tester thetest ((p1:<p2):ps)+    = (thetest p1 p2)++(pair_unit_tester thetest ps)+\end{code}++\chapter{LCS}++Here are a few quick tests of the shiftBoundaries function.++\begin{code}+show_lcs_tests :: [String]+show_lcs_tests = concatMap check_known_shifts known_shifts+check_known_shifts :: ([Int],[Int],String,String,[Int],[Int])+                   -> [String] +check_known_shifts (ca, cb, sa, sb, ca', cb') = runST (+    do ca_arr <- newListArray (0, length ca) $ toBool (0:ca)+       cb_arr <- newListArray (0, length cb) $ toBool (0:cb)+       let p_a = listArray (0, length sa) $ nilPS:(toPS sa)+           p_b = listArray (0, length sb) $ nilPS:(toPS sb)+       shiftBoundaries ca_arr cb_arr p_a 1 1+       shiftBoundaries cb_arr ca_arr p_b 1 1+       ca_res <- liftM (fromBool . tail) $ getElems ca_arr+       cb_res <- liftM (fromBool . tail) $ getElems cb_arr+       return $ if ca_res  == ca' && cb_res == cb' then []+                else ["shiftBoundaries failed on "++sa++" and "++sb++" with "+                      ++(show (ca,cb))++" expected "++(show (ca', cb'))+                      ++" got "++(show (ca_res, cb_res))++"\n"])+ where toPS = map (\c -> if c == ' ' then nilPS else packString [c])+       toBool = map (>0)+       fromBool = map (\b -> if b then 1 else 0)++known_shifts :: [([Int],[Int],String,String,[Int],[Int])]+known_shifts =+  [([0,0,0],[0,1,0,1,0],"aaa","aaaaa",+    [0,0,0],[0,0,0,1,1]),+   ([0,1,0],[0,1,1,0],"cd ","c a ",+    [0,1,0],[0,1,1,0]),+   ([1,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,1,1,1,1,1,0,0,0], "fg{} if{}","dg{} ih{} if{}",+    [1,0,0,0,0,0,0,0,0],[1,0,0,0,0,1,1,1,1,1,0,0,0,0]), -- prefer empty line at end+   ([0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,1,1,1,1,0,0,0], "fg{} if{}","fg{} ih{} if{}",+    [0,0,0,0,0,0,0,0,0],[0,0,0,0,0,1,1,1,1,1,0,0,0,0]), -- prefer empty line at end+   ([],[1,1],"","aa",[],[1,1]),+   ([1,1],[],"aa","",[1,1],[])]+++\end{code}++\chapter{Show/Read tests}++This test involves calling ``show'' to print a string describing a patch,+and then using readPatch to read it back in, and making sure the patch we+read in is the same as the original.  Useful for making sure that I don't+have any stupid IO bugs.++\begin{code}+show_read_tests :: [String]+show_read_tests = unit_tester t_show_read test_patches +++                  unit_tester t_show_read test_patches_named+primitive_show_read_tests :: [String]+primitive_show_read_tests = unit_tester t_show_read primitive_test_patches+t_show_read :: (Eq p, Show p, Patchy p) => PatchUnitTest p+t_show_read p =+    case readPatch $ renderPS $ showPatch p of+    Just (Sealed p',_) -> if p' == p then []+                          else ["Failed to read shown:  "++(show p)++"\n"]+    Nothing -> ["Failed to read at all:  "++(show p)++"\n"]++instance MyEq p => Eq (Named p) where+    (==) = unsafeCompare+\end{code}++\chapter{Canonization tests}++This is a set of known correct canonizations, to make sure that I'm+canonizing as I ought.++\begin{code}+canonization_tests :: [String]+canonization_tests = concatMap check_known_canon known_canons+check_known_canon :: (Patch, Patch) -> [String]+check_known_canon (p1,p2) =+    if (fromPrims $ concatFL $ mapFL_FL canonize $ sort_coalesceFL $ effect p1) == p2+    then []+    else ["Canonization failed:\n"++show p1++"canonized is\n"+          ++show (fromPrims $ concatFL $ mapFL_FL canonize $ sort_coalesceFL $ effect p1 :: Patch)+          ++"which is not\n"++show p2]+known_canons :: [(Patch,Patch)]+known_canons =+    [(quickhunk 1 "abcde" "ab",  quickhunk 3 "cde"   ""),+     (quickhunk 1 "abcde" "bd", join_patches [quickhunk 1 "a" "",+                                              quickhunk 2 "c" "",+                                              quickhunk 3 "e" ""]),+     (join_patches [quickhunk 4 "a" "b",+                    quickhunk 1 "c" "d"],+      join_patches [quickhunk 1 "c" "d",+                    quickhunk 4 "a" "b"]),+     (join_patches [quickhunk 1 "a" "",+                    quickhunk 1 "" "b"],+      quickhunk 1 "a" "b"),+     (join_patches [quickhunk 1 "ab" "c",+                    quickhunk 1 "cd" "e"],+      quickhunk 1 "abd" "e"),+     (quickhunk 1 "abcde" "cde", quickhunk 1 "ab" ""),+     (quickhunk 1 "abcde" "acde", quickhunk 2 "b" "")]+quickhunk :: Int -> String -> String -> Patch+quickhunk l o n = fromPrim $ hunk "test" l (map (\c -> packString [c]) o)+                                             (map (\c -> packString [c]) n)+\end{code}++\chapter{Merge/unmgerge tests}++It should always be true that if two patches can be unmerged, then merging+the resulting patches should give them back again.+\begin{code}+generic_merge_tests :: [String]+generic_merge_tests =+  case take 400 [(p1:\/:p2)|+                 i <- [0..(length test_patches)-1],+                 p1<-[test_patches!!i],+                 p2<-drop i test_patches,+                 check_a_patch $ join_patches [invert p2,p1]] of+  merge_pairs -> (parallel_pair_unit_tester t_merge_either_way_valid merge_pairs) +++                 (parallel_pair_unit_tester t_merge_swap_merge merge_pairs)+t_merge_either_way_valid   :: TwoPatchUnitTest+t_merge_either_way_valid p1 p2 =+  case join_patches [p2, quickmerge (p1:\/: p2)] of+  combo2 ->+    case join_patches [p1, quickmerge (p2:\/: p1)] of+    combo1 ->+      if not $ check_a_patch $ join_patches [combo1]+      then ["oh my combo1 invalid:\n"++show p1++"and...\n"++show p2++show combo1]+      else+        if check_a_patch $ join_patches [invert combo1, combo2]+        then []+        else ["merge both ways invalid:\n"++show p1++"and...\n"++show p2+++              show combo1+++              show combo2]+t_merge_swap_merge   :: TwoPatchUnitTest+t_merge_swap_merge p1 p2 =+  if (swapp $ merge (p2:\/: p1)) == merge (p1:\/:p2)+  then []+  else ["Failed to swap merges:\n"++show p1++"and...\n"++show p2+        ++"merged:\n"++show (merge (p1:\/:p2))++"\n"+        ++"merged and swapped:\n"++show (swapp $ merge (p2:\/: p1))++"\n"]+    where swapp (x :/\: y) = y :/\: x++instance Show p => Show (p :/\: p) where+   show (x :/\: y) = show x ++ " :/\\: " ++ show y+instance Eq p => Eq (p :/\: p) where+   (x :/\: y) == (x' :/\: y') = x == x' && y == y'+\end{code}++\chapter{Commute/recommute tests}++Here we test to see if commuting patch A and patch B and then commuting the+result gives us patch A and patch B again.  The set of patches (A,B) is+chosen from the set of all pairs of test patches by selecting those which+commutex with one another.++\begin{code}+commute_recommute_tests :: [String]+commute_recommute_tests =+  case take 200 [(p2:<p1)|+                 p1<-test_patches,+                 p2<-filter (\p->checkseq [p1,p]) test_patches,+                 commutex (p2:<p1) /= Nothing] of+  commute_pairs -> pair_unit_tester t_commute_recommute commute_pairs+  where checkseq ps = check_a_patch $ join_patches ps+primitive_commute_recommute_tests :: [String]+primitive_commute_recommute_tests =+  pair_unit_tester t_commute_recommute+    [(p1:<p2)|+     p1<-primitive_test_patches,+     p2<-primitive_test_patches,+     commutex (p1:<p2) /= Nothing,+     check_a_patch $ join_patches [p2,p1]]+t_commute_recommute   :: TwoPatchUnitTest+t_commute_recommute p1 p2 =+    if (commutex (p1:<p2) >>= commutex) == Just (p1:<p2)+       then []+       else ["Failed to recommute:\n"++(show p1)++(show p2)+++            "we saw it as:\n"++show (commutex (p1:<p2))+++             "\nAnd recommute was:\n"++show (commutex (p1:<p2) >>= commutex)+             ++ "\n"]+\end{code}++\chapter{Commute tests}++Here we provide a set of known interesting commutes.+\begin{code}+commute_tests :: [String]+commute_tests =+    concatMap check_known_commute known_commutes+++    concatMap check_cant_commute known_cant_commute+check_known_commute :: (Patch:< Patch, Patch:< Patch) -> [String]+check_known_commute (p1:<p2,p2':<p1') =+   case commutex (p1:<p2) of+   Just (p2a:<p1a) ->+       if (p2a:< p1a) == (p2':< p1')+       then []+       else ["Commute gave wrong value!\n"++show p1++"\n"++show p2+             ++"should be\n"++show p2'++"\n"++show p1'+             ++"but is\n"++show p2a++"\n"++show p1a]+   Nothing -> ["Commute failed!\n"++show p1++"\n"++show p2]+   +++   case commutex (p2':<p1') of+   Just (p1a:<p2a) ->+       if (p1a:< p2a) == (p1:< p2)+       then []+       else ["Commute gave wrong value!\n"++show p2a++"\n"++show p1a+             ++"should have been\n"++show p2'++"\n"++show p1']+   Nothing -> ["Commute failed!\n"++show p2'++"\n"++show p1']+known_commutes :: [(Patch:<Patch,Patch:<Patch)]+known_commutes = [+                  (testhunk 1 [] ["A"]:<+                   testhunk 2 [] ["B"],+                   testhunk 3 [] ["B"]:<+                   testhunk 1 [] ["A"]),+                  (fromPrim (tokreplace "test" "A-Za-z_" "old" "new"):<+                   testhunk 2+                   ["hello world all that is old is good old_"]+                   ["I don't like old things"],+                   testhunk 2+                   ["hello world all that is new is good old_"]+                   ["I don't like new things"]:<+                   fromPrim (tokreplace "test" "A-Za-z_" "old" "new")),+                  (testhunk 1 ["A"] ["B"]:<+                   testhunk 2 ["C"] ["D"],+                   testhunk 2 ["C"] ["D"]:<+                   testhunk 1 ["A"] ["B"]),+                  (fromPrim (rmfile "NwNSO"):<+                   (quickmerge (fromPrim (addfile "hello"):\/:fromPrim (addfile "hello"))),+                   (quickmerge (fromPrim (addfile "hello"):\/:fromPrim (addfile "hello"))):<+                   fromPrim (rmfile "NwNSO")),++                  (quickmerge (testhunk 3 ["o"] ["n"]:\/:+                               testhunk 3 ["o"] ["v"]):<+                   testhunk 1 [] ["a"],+                   testhunk 1 [] ["a"]:<+                   quickmerge (testhunk 2 ["o"] ["n"]:\/:+                               testhunk 2 ["o"] ["v"])),++                  (testhunk 1 ["A"] []:<+                   testhunk 3 ["B"] [],+                   testhunk 2 ["B"] []:<+                   testhunk 1 ["A"] []),++                  (testhunk 1 ["A"] ["B"]:<+                   testhunk 2 ["B"] ["C"],+                   testhunk 2 ["B"] ["C"]:<+                   testhunk 1 ["A"] ["B"]),++                  (testhunk 1 ["A"] ["B"]:<+                   testhunk 3 ["B"] ["C"],+                   testhunk 3 ["B"] ["C"]:<+                   testhunk 1 ["A"] ["B"]),++                  (testhunk 1 ["A"] ["B","C"]:<+                   testhunk 2 ["B"] ["C","D"],+                   testhunk 3 ["B"] ["C","D"]:<+                   testhunk 1 ["A"] ["B","C"])]+  where testhunk l o n = fromPrim $ hunk "test" l (map packString o) (map packString n)++check_cant_commute :: (Patch:< Patch) -> [String]+check_cant_commute (p1:<p2) =+    case commutex (p1:<p2) of+    Nothing -> []+    _ -> [show p1 ++ "\n\n" ++ show p2 +++          "\nArgh, these guys shouldn't commutex!\n"]+known_cant_commute :: [(Patch:< Patch)]+known_cant_commute = [+                      (testhunk 2 ["o"] ["n"]:<+                       testhunk 1 [] ["A"]),+                      (testhunk 1 [] ["A"]:<+                       testhunk 1 ["o"] ["n"]),+                      (quickmerge (testhunk 2 ["o"] ["n"]:\/:+                                   testhunk 2 ["o"] ["v"]):<+                       testhunk 1 [] ["a"]),+                      (fromPrim (hunk "test" 1 ([packString "a"]) ([packString "b"])):<+                       fromPrim (addfile "test"))]+  where testhunk l o n = fromPrim $ hunk "test" l (map packString o) (map packString n)+\end{code}++\chapter{Merge tests}++Here we provide a set of known interesting merges.+\begin{code}+merge_tests :: [String]+merge_tests =+    concatMap check_known_merge_equiv known_merge_equivs+++    concatMap check_known_merge known_merges+check_known_merge :: (Patch:\/: Patch, Patch:< Patch) -> [String]+check_known_merge (p1:\/:p2,p1':<p2') =+   case merge (p1:\/:p2) of+   _ :/\: p1a ->+       if (p1a:< p2) == (p1':< p2')+       then []+       else ["Merge gave wrong value!\n"++show p1++show p2+             ++"I expected\n"++show p1'++show p2'+             ++"but found instead\n"++show p1a]+known_merges :: [(Patch:\/:Patch,Patch:<Patch)]+known_merges = [+                (testhunk 2 [packString "c"] [packString "d",packString "e"]:\/:+                 testhunk 1 [packString "x"] [packString "a",packString "b"],+                 testhunk 3 [packString "c"] [packString "d",packString "e"]:<+                 testhunk 1 [packString "x"] [packString "a",packString "b"]),+                (testhunk 1 [packString "x"] [packString "a",packString "b"]:\/:+                 testhunk 2 [packString "c"] [packString "d",packString "e"],+                 testhunk 1 [packString "x"] [packString "a",packString "b"]:<+                 testhunk 2 [packString "c"] [packString "d",packString "e"]),+                (testhunk 3 [packString "A"] []:\/:+                 testhunk 1 [packString "B"] [],+                 testhunk 2 [packString "A"] []:<+                 testhunk 1 [packString "B"] []),+                (fromPrim (rmdir "./test/world"):\/:+                 fromPrim (hunk "./world" 3 [packString "A"] []),+                 fromPrim (rmdir "./test/world"):<+                 fromPrim (hunk "./world" 3 [packString "A"] [])),++                (join_patches [quickhunk 1 "a" "bc",+                               quickhunk 6 "d" "ef"]:\/:+                 join_patches [quickhunk 3 "a" "bc",+                               quickhunk 8 "d" "ef"],+                 join_patches [quickhunk 1 "a" "bc",+                               quickhunk 7 "d" "ef"]:<+                 join_patches [quickhunk 3 "a" "bc",+                               quickhunk 8 "d" "ef"]),++                (testhunk 1 [packString "A"] [packString "B"]:\/:+                 testhunk 2 [packString "B"] [packString "C"],+                 testhunk 1 [packString "A"] [packString "B"]:<+                 testhunk 2 [packString "B"] [packString "C"]),++                (testhunk 2 [packString "A"] [packString "B",packString "C"]:\/:+                 testhunk 1 [packString "B"] [packString "C",packString "D"],+                 testhunk 3 [packString "A"] [packString "B",packString "C"]:<+                 testhunk 1 [packString "B"] [packString "C",packString "D"])]+  where testhunk l o n = fromPrim $ hunk "test" l o n+check_known_merge_equiv :: (Patch:\/:Patch,Patch) -> [String]+check_known_merge_equiv (p1:\/: p2, pe) =+    case quickmerge (p1:\/:p2) of+    p1' -> if check_a_patch $ join_patches [invert p1, p2, p1', invert pe]+           then []+           else ["Oh no, merger isn't equivalent...\n"++show p1++"\n"++show p2+                 ++"in other words\n" ++ show (p1 :\/: p2)+                 ++"merges as\n" ++ show (merge $ p1 :\/: p2)+                 ++"merges to\n" ++ show (quickmerge $ p1 :\/: p2)+                 ++"which is equivalent to\n" ++ show (effect p1')+                 ++ "should all work out to\n"+                 ++ show pe]+known_merge_equivs :: [(Patch:\/: Patch, Patch)]+known_merge_equivs = [++                     -- The following tests are going to be failed by the+                     -- Conflictor code as a cleanup.++                     --(addfile "test":\/:+                     -- adddir "test",+                     -- join_patches [adddir "test",+                     --               addfile "test-conflict"]),+                     --(move "silly" "test":\/:+                     -- adddir "test",+                     -- join_patches [adddir "test",+                     --               move "silly" "test-conflict"]),+                     --(addfile "test":\/:+                     -- move "old" "test",+                     -- join_patches [addfile "test",+                     --               move "old" "test-conflict"]),+                     --(move "a" "test":\/:+                     -- move "old" "test",+                     -- join_patches [move "a" "test",+                     --               move "old" "test-conflict"]),+                     (fromPrim (hunk "test" 1 [] [packString "A"]):\/:+                      fromPrim (hunk "test" 1 [] [packString "B"]),+                      fromPrim (hunk "test" 1 [] [packString "A", packString "B"])),+                     (fromPrim (hunk "test" 1 [] [packString "a"]):\/:+                      fromPrim (hunk "test" 1 [packString "b"] []),+                      identity),+                      --hunk "test" 1 [] [packString "v v v v v v v",+                      --                  packString "*************",+                      --                  packString "a",+                      --                  packString "b",+                      --                  packString "^ ^ ^ ^ ^ ^ ^"]),+                     (quickhunk 4 "a"  "":\/:+                      quickhunk 3 "a"  "",+                      quickhunk 3 "aa" ""),+                     (join_patches [quickhunk 1 "a" "bc",+                                    quickhunk 6 "d" "ef"]:\/:+                      join_patches [quickhunk 3 "a" "bc",+                                    quickhunk 8 "d" "ef"],+                      join_patches [quickhunk 3 "a" "bc",+                                    quickhunk 8 "d" "ef",+                                    quickhunk 1 "a" "bc",+                                    quickhunk 7 "d" "ef"]),+                     (quickmerge (quickhunk 2 "" "bd":\/:quickhunk 2 "" "a"):\/:+                              quickmerge (quickhunk 2 "" "c":\/:quickhunk 2 "" "a"),+                              quickhunk 2 "" "abdc")+                     ]+\end{code}++It also is useful to verify that it doesn't matter which order we specify+the patches when we merge.++\begin{code}+merge_swap_tests :: [String]+merge_swap_tests =+    concat+              [check_merge_swap p1 p2 |+               p1<-primitive_test_patches,+               p2<-primitive_test_patches,+               check_a_patch $ join_patches [invert p1,p2]+              ]+check_merge_swap :: Patch -> Patch -> [String]+check_merge_swap p1 p2 =+    case merge (p2:\/:p1) of+    _ :/\: p2' ->+        case merge (p1:\/:p2) of+        _ :/\: p1' ->+            case commutex (p2':<p1) of+            Just (p1'b:<_) ->+                if p1'b /= p1'+                then ["Merge swapping problem with...\np1 "+++                      show p1++"merged with\np2 "+++                      show p2++"p1' is\np1' "+++                      show p1'++"p1'b is\np1'b  "+++                      show p1'b+                     ]+                else []+            Nothing -> ["Merge commuting problem with...\np1 "+++                        show p1++"merged with\np2 "+++                        show p2++"gives\np2' "+++                        show p2'++"which doesn't commutex with p1.\n"+                       ]+\end{code}++\chapter{Patch test data}++This is where we define the set of patches which we run our tests on.  This+should be kept up to date with as many interesting permutations of patch+types as possible.++\begin{code}+test_patches :: [Patch]+test_patches_named :: [Named Patch]+test_patches_addfile :: [Patch]+test_patches_rmfile :: [Patch]+test_patches_hunk :: [Patch]+primitive_test_patches :: [Patch]+test_patches_binary :: [Patch]+test_patches_composite_nocom :: [Patch]+test_patches_composite :: [Patch]+test_patches_two_composite_hunks :: [Patch]+test_patches_composite_hunks :: [Patch]+test_patches_composite_four_hunks :: [Patch]+test_patches_merged :: [Patch]+valid_patches :: [Patch]++test_patches_named = [namepatch "date is" "patch name" "David Roundy" []+                                (fromPrim $ addfile "test"),+                      namepatch "Sat Oct 19 08:31:13 EDT 2002"+                                "This is another patch" "David Roundy"+                                ["This log file has","two lines in it"]+                                (fromPrim $ rmfile "test")]+test_patches_addfile = map fromPrim+                       [addfile "test",adddir "test",addfile "test/test"]+test_patches_rmfile = map invert test_patches_addfile+test_patches_hunk  =+    [fromPrim $ hunk file line old new |+     file <- ["test"],+     line <- [1,2],+     old <- map (map packString) partials,+     new <- map (map packString) partials,+     old /= new+    ]+    where partials  = [["A"],["B"],[],["B","B2"]]++primitive_test_patches = test_patches_addfile +++                         test_patches_rmfile +++                         test_patches_hunk +++                         [unsafeUnseal.fst.fromJust.readPatch $+                          packString "move ./test/test ./hello",+                          unsafeUnseal.fst.fromJust.readPatch $+                          packString "move ./test ./hello"] +++                         test_patches_binary++test_patches_binary =+    [fromPrim $ binary "./hello"+     (packString $ "agadshhdhdsa75745457574asdgg" +++      "a326424677373735753246463gadshhdhdsaasdgg" +++      "a326424677373735753246463gadshhdhdsaasdgg" +++      "a326424677373735753246463gadshhdhdsaasdgg")+     (packString $ "adafjttkykrehhtrththrthrthre" +++      "a326424677373735753246463gadshhdhdsaasdgg" +++      "a326424677373735753246463gadshhdhdsaasdgg" +++      "a326424677373735753246463gadshhdhdsaagg"),+     fromPrim $ binary "./hello"+     nilPS+     (packString "adafjttkykrere")]++test_patches_composite_nocom =+    take 50 [join_patches [p1,p2]|+             p1<-primitive_test_patches,+             p2<-filter (\p->checkseq [p1,p]) primitive_test_patches,+             commutex (p2:<p1) == Nothing]+    where checkseq ps = check_a_patch $ join_patches ps++test_patches_composite =+    take 100 [join_patches [p1,p2]|+              p1<-primitive_test_patches,+              p2<-filter (\p->checkseq [p1,p]) primitive_test_patches,+              commutex (p2:<p1) /= Nothing,+              commutex (p2:<p1) /= Just (p1:<p2)]+    where checkseq ps = check_a_patch $ join_patches ps++test_patches_two_composite_hunks =+    take 100 [join_patches [p1,p2]|+              p1<-test_patches_hunk,+              p2<-filter (\p->checkseq [p1,p]) test_patches_hunk]+    where checkseq ps = check_a_patch $ join_patches ps++test_patches_composite_hunks =+    take 100 [join_patches [p1,p2,p3]|+              p1<-test_patches_hunk,+              p2<-filter (\p->checkseq [p1,p]) test_patches_hunk,+              p3<-filter (\p->checkseq [p1,p2,p]) test_patches_hunk]+    where checkseq ps = check_a_patch $ join_patches ps++test_patches_composite_four_hunks =+    take 100 [join_patches [p1,p2,p3,p4]|+              p1<-test_patches_hunk,+              p2<-filter (\p->checkseq [p1,p]) test_patches_hunk,+              p3<-filter (\p->checkseq [p1,p2,p]) test_patches_hunk,+              p4<-filter (\p->checkseq [p1,p2,p3,p]) test_patches_hunk]+    where checkseq ps = check_a_patch $ join_patches ps++test_patches_merged =+  take 200+    [joinPatches $ flattenFL p2+>+flattenFL (quickmerge (p1:\/:p2)) |+     p1<-take 10 (drop 15 test_patches_composite_hunks)++primitive_test_patches+         ++take 10 (drop 15 test_patches_two_composite_hunks)+         ++ take 2 (drop 4 test_patches_composite_four_hunks),+     p2<-take 10 test_patches_composite_hunks++primitive_test_patches+         ++take 10 test_patches_two_composite_hunks+         ++take 2 test_patches_composite_four_hunks,+     check_a_patch $ join_patches [invert p1, p2],+     commutex (p1:<p2) /= Just (p2:<p1)+    ]++test_patches =  primitive_test_patches +++                test_patches_composite +++                test_patches_composite_nocom +++                test_patches_merged+\end{code}++\chapter{Check patch test}+Check patch is supposed to verify that a patch is valid.++\begin{code}+valid_patches = [(join_patches [quickhunk 4 "a" "b",+                                quickhunk 1 "c" "d"]),+                 (join_patches [quickhunk 1 "a" "bc",+                                quickhunk 1 "b" "d"]),+                 (join_patches [quickhunk 1 "a" "b",+                                quickhunk 1 "b" "d"])]++test_patches++test_check :: [String]+test_check = unit_tester t_test_check valid_patches+t_test_check :: PatchUnitTest Patch+t_test_check p = if check_a_patch p+                 then []+                 else ["Failed the check:  "++show p++"\n"]+\end{code}++\begin{code}+prop_hex_conversion :: String -> Bool+prop_hex_conversion s =+    fromHex2PS (fromPS2Hex $ packString s) == packString s+prop_concatPS :: [String] -> Bool+prop_concatPS ss = concat ss == unpackPS (concatPS $ map packString ss)+\end{code}++\begin{code}+check_subcommutes :: Testable a => [(String, a)] -> String -> IO ()+check_subcommutes [] _ = return ()+check_subcommutes ((n,c):r) expl =+    do putStr $ "Checking " ++ expl ++ " for subcommute " ++ n ++ "... "+       quickCheck c+       check_subcommutes r expl+\end{code}++\end{document}++
+ src/win32/CtrlC.hs view
@@ -0,0 +1,20 @@+{-# OPTIONS -fffi #-}+module CtrlC (withCtrlCHandler) where++import Data.Word ( Word32 )+import Foreign.Ptr ( FunPtr )+import Control.Exception ( bracket )++type Handler = Word32 -> IO Int++foreign import ccall "wrapper" wrap :: Handler -> IO (FunPtr Handler)+foreign import stdcall "SetConsoleCtrlHandler" setConsoleCtrlHandler :: FunPtr Handler -> Int -> IO ()+++withCtrlCHandler :: IO () -> IO a -> IO a+withCtrlCHandler handler m = do+    fp <- wrap (\_ctrlType -> handler >> return 1)+    bracket (setConsoleCtrlHandler fp 1) (const $ setConsoleCtrlHandler fp 0) (const m)+++
+ src/win32/System/Posix.hs view
@@ -0,0 +1,41 @@+{-# OPTIONS_GHC -fglasgow-exts -fffi #-}+module System.Posix where++import Foreign.Ptr ( Ptr, castPtr, plusPtr )+import Foreign.Storable ( peek, poke, sizeOf )+import Foreign.C.Types ( CInt, CUInt, CULong, CTime )+import Foreign.C.String ( CString, withCString )+import Foreign.Marshal.Alloc ( allocaBytes )++import System.Posix.Types ( EpochTime )+import System.IO ( Handle )+++foreign import ccall "sys/utime.h _utime" c_utime :: CString -> Ptr a -> IO CInt++setFileTimes :: FilePath -> EpochTime -> EpochTime -> IO ()+setFileTimes path atime mtime = path `withCString` \s -> do+  allocaBytes 8 $ \p -> do+    poke (castPtr p :: Ptr CTime) (atime)+    poke (castPtr (plusPtr p 4) :: Ptr CTime) (mtime)+    c_utime s p+    return ()+++foreign import ccall "time" c_ctime :: Ptr CTime -> IO CInt++epochTime :: IO EpochTime+epochTime = do+    allocaBytes (sizeOf (undefined :: CTime)) $ \p -> do+      c_ctime p+      t <- peek p :: IO CTime+      return t++foreign import stdcall "winbase.h SleepEx" c_SleepEx :: CULong -> CUInt -> IO CInt++sleep :: Integer -> IO CInt+sleep n = c_SleepEx (1000 * fromIntegral n) 1++handleToFd :: Handle -> IO Int+handleToFd _ = fail "handleToFd not supported!"+
+ src/win32/System/Posix/Files.hsc view
@@ -0,0 +1,70 @@+module System.Posix.Files where++import Foreign.Marshal.Alloc ( allocaBytes )+import Foreign.C.Error ( throwErrnoIfMinus1Retry )+import Foreign.C.String ( withCString )+import Foreign.C.Types ( CTime, CInt )+import Foreign.Ptr ( Ptr )++import System.Posix.Internals+          ( FDType, CStat, c_fstat, lstat, +            sizeof_stat, statGetType, +            st_mode, st_size, st_mtime,+            s_isreg, s_isdir, s_isfifo, )+import System.Posix.Types ( Fd(..), CMode, COff, EpochTime, FileOffset, FileMode )++import Data.Bits ( (.|.) )++data FileStatus = FileStatus {+    fst_type :: FDType,+    fst_mode :: CMode,+    fst_mtime :: CTime,+    fst_size :: COff+ }++getFdStatus :: Fd -> IO FileStatus+getFdStatus (Fd fd) = do+  do_stat (c_fstat fd)++do_stat :: (Ptr CStat -> IO CInt) -> IO FileStatus+do_stat stat_func = do+  allocaBytes sizeof_stat $ \p -> do+    throwErrnoIfMinus1Retry "do_stat" $+      stat_func p+    tp <- statGetType p+    mode <- st_mode p+    mtime <- st_mtime p+    size <- st_size p+    return (FileStatus tp mode mtime size)++isNamedPipe :: FileStatus -> Bool+isNamedPipe = s_isfifo . fst_mode++isDirectory :: FileStatus -> Bool+isDirectory = s_isdir . fst_mode++isRegularFile :: FileStatus -> Bool+isRegularFile = s_isreg . fst_mode++isSymbolicLink :: FileStatus -> Bool+isSymbolicLink = const False++linkCount :: FileStatus -> Int+linkCount _ = 1++modificationTime :: FileStatus -> EpochTime+modificationTime = fst_mtime++fileSize :: FileStatus -> FileOffset+fileSize = fst_size++#include <sys/stat.h>+stdFileMode :: FileMode+stdFileMode = (#const S_IRUSR) .|. (#const S_IWUSR)++++getSymbolicLinkStatus :: FilePath -> IO FileStatus+getSymbolicLinkStatus fp = +  do_stat (\p -> (fp `withCString` (`lstat` p)))+
+ src/win32/System/Posix/IO.hsc view
@@ -0,0 +1,69 @@+module System.Posix.IO where++import Foreign.C.String ( withCString )+import Foreign.C.Error ( throwErrnoIfMinus1, throwErrnoIfMinus1_ )++import GHC.Handle ( fdToHandle )++import System.Posix.Internals ( c_open, c_close, c_dup2 )+import System.Posix.Types ( Fd(..), FileMode )+import System.IO ( Handle )++import Data.Bits ( (.|.) )+++stdOutput :: Fd+stdOutput = Fd 1++stdError :: Fd+stdError = Fd 2++data OpenFileFlags = + OpenFileFlags {+  append :: Bool,+  exclusive :: Bool,+  noctty :: Bool,+  nonBlock :: Bool,+  trunc :: Bool+ }+++-- Adapted from System.Posix.IO in ghc+#include <fcntl.h>++openFd :: FilePath -> OpenMode -> Maybe FileMode -> OpenFileFlags -> IO Fd+openFd name how maybe_mode off = do+  withCString name $ \s -> do+   fd <- throwErrnoIfMinus1 "openFd" (c_open s all_flags mode_w)+   return (Fd fd)+ where+   all_flags = binary .|. creat .|. flags .|. open_mode+   flags =+    (if append off    then (#const O_APPEND)   else 0) .|.+    (if exclusive off then (#const O_EXCL)     else 0) .|.+    (if trunc off     then (#const O_TRUNC)    else 0)+   binary = (#const O_BINARY)+   (creat, mode_w) = maybe (0,0) (\x->((#const O_CREAT),x)) maybe_mode+   open_mode = case how of+                ReadOnly  -> (#const O_RDONLY)+                WriteOnly -> (#const O_WRONLY)+                ReadWrite -> (#const O_RDWR)++closeFd :: Fd -> IO ()+closeFd (Fd fd) = throwErrnoIfMinus1_ "closeFd" (c_close fd)+++fdToHandle :: Fd -> IO Handle+fdToHandle fd = GHC.Handle.fdToHandle (fromIntegral fd)++dupTo :: Fd -> Fd -> IO Fd+dupTo (Fd fd1) (Fd fd2) = do+  r <- throwErrnoIfMinus1 "dupTo" (c_dup2 fd1 fd2)+  return (Fd r)++data OpenMode = ReadOnly | WriteOnly | ReadWrite++defaultFileFlags :: OpenFileFlags+defaultFileFlags = OpenFileFlags False False False False False++
+ src/win32/send_email.c view
@@ -0,0 +1,211 @@+++#include <windows.h>+#include <mapi.h>+#include <stdio.h>++#include "send_email.h"++typedef struct sMapiFuns {+    LPMAPILOGON logon;+    LPMAPISENDMAIL sendmail;+    LPMAPIRESOLVENAME resolve;+    LPMAPIFREEBUFFER free_buf;+    LPMAPILOGOFF logoff;+    HMODULE dll;+} MapiFuns;+++int load_dll(const char* name, MapiFuns* funs);+void free_dll(MapiFuns* funs);++void get_recipient(MapiFuns* funs, const char *name, ULONG recipClass, MapiRecipDesc *desc, lpMapiRecipDesc *desc_lookup);++int send_email(const char *sendname, +               const char *recvname, +               const char *ccname, +               const char *subj,+               const char *body,+               const char *path)+{+    FLAGS flags;+    MapiMessage msg;+    ULONG send_res;+    MapiRecipDesc orig;+    MapiRecipDesc recips[2];+    MapiRecipDesc *orig_lookup, *recip_lookup, *cc_lookup;+    int num_recip = 1, return_code = -1;+    MapiFileDesc attachment;+    MapiFileTagExt file_type;+    const char *filename;+    char *attachment_path = 0;+    MapiFuns funs;+    +    if(load_dll("mapistub.dll", &funs) || load_dll("mapi32.dll", &funs)) {+        return_code=0;+    } else {+        fprintf(stderr, "Unable to load mapistub.dll or mapi32.dll: Bailing out. \n");+        return_code=-1;+    }++    if(return_code==0) {+        LHANDLE session;+        /* logon seems to be necessary for outlook express, sometimes,+        and doesn't seem to hurt, otherwise.+        */+        funs.logon(0, 0, 0, MAPI_LOGON_UI, 0, &session);++        +        orig_lookup = recip_lookup = cc_lookup = NULL;+        +        get_recipient(&funs, sendname, MAPI_ORIG, &orig, &orig_lookup);+        get_recipient(&funs, recvname, MAPI_TO, &recips[0], &recip_lookup);++        if (ccname && strlen(ccname) > 0) {+            get_recipient(&funs, ccname, MAPI_CC, &recips[1], &cc_lookup);+            num_recip++;+        }++        memset(&msg, 0, sizeof(msg));+        msg.lpOriginator = &orig;+        msg.lpRecips = recips;+        msg.lpszMessageType = "text/plain";+        msg.lpszNoteText = (LPSTR) body;+        msg.lpszSubject = (LPSTR)subj;+        msg.nRecipCount = num_recip;+        msg.flFlags = 0;++        if (path) {+            attachment_path = strdup(path);+            /* convert / to \  (thunderbird doesn't like /) */+            char *p = attachment_path;+            while ((p = strchr(p, '/')))+                *p = '\\';++            /* find filename */+            filename = strrchr(attachment_path, '\\');+            if (filename == 0)+                filename = attachment_path;+            else+                filename++;++            memset(&attachment, 0, sizeof(attachment));+            attachment.nPosition = -1;+            attachment.lpszPathName = (LPTSTR)attachment_path;+            attachment.lpszFileName = (LPTSTR)filename;++            attachment.lpFileType = &file_type;+            +            memset(&file_type, 0, sizeof(file_type));+            file_type.lpTag = "text/plain";+            file_type.cbTag = sizeof(file_type.lpTag);++            msg.nFileCount = 1;+            msg.lpFiles = &attachment;+        }++        flags = 0;+        send_res = funs.sendmail(0, 0, &msg, flags, 0);++        if (send_res == SUCCESS_SUCCESS)+            return_code = 0;+        else {+            return_code=-1;+            if(send_res==MAPI_E_USER_ABORT)                 fprintf(stderr, "MAPI error: User aborted.\n");+            else if(send_res== MAPI_E_FAILURE)              fprintf(stderr, "MAPI error: Generic error.\n");+            else if(send_res== MAPI_E_LOGIN_FAILURE)        fprintf(stderr, "MAPI error: Login failure.\n");+            else if(send_res== MAPI_E_DISK_FULL)            fprintf(stderr, "MAPI error: Disk full.\n");+            else if(send_res== MAPI_E_INSUFFICIENT_MEMORY)  fprintf(stderr, "MAPI error: Insufficient memory.\n");+            else if(send_res== MAPI_E_ACCESS_DENIED)        fprintf(stderr, "MAPI error: Access denied.\n");+            else if(send_res== MAPI_E_TOO_MANY_SESSIONS)    fprintf(stderr, "MAPI error: Too many sessions\n");+            else if(send_res== MAPI_E_TOO_MANY_FILES)       fprintf(stderr, "MAPI error: Too many files.\n");+            else if(send_res== MAPI_E_TOO_MANY_RECIPIENTS)  fprintf(stderr, "MAPI error: Too many recipients.\n");+            else if(send_res== MAPI_E_ATTACHMENT_NOT_FOUND) fprintf(stderr, "MAPI error: Attachment not found.\n");+            else if(send_res== MAPI_E_ATTACHMENT_OPEN_FAILURE)  fprintf(stderr, "MAPI error: Failed to open attachment.\n");+            else if(send_res== MAPI_E_ATTACHMENT_WRITE_FAILURE) fprintf(stderr, "MAPI error: Failed to write attachment.\n");+            else if(send_res== MAPI_E_UNKNOWN_RECIPIENT)    fprintf(stderr, "MAPI error: Unknown recipient\n");+            else if(send_res== MAPI_E_BAD_RECIPTYPE)        fprintf(stderr, "MAPI error: Bad type of recipent.\n");+            else if(send_res== MAPI_E_NO_MESSAGES)          fprintf(stderr, "MAPI error: No messages.\n");+            else if(send_res== MAPI_E_INVALID_MESSAGE)      fprintf(stderr, "MAPI error: Invalid message.\n");+            else if(send_res== MAPI_E_TEXT_TOO_LARGE)       fprintf(stderr, "MAPI error: Text too large.\n");+            else if(send_res== MAPI_E_INVALID_SESSION)      fprintf(stderr, "MAPI error: Invalid session.\n");+            else if(send_res== MAPI_E_TYPE_NOT_SUPPORTED)   fprintf(stderr, "MAPI error: Type not supported.\n");+            else if(send_res== MAPI_E_AMBIGUOUS_RECIP)      fprintf(stderr, "MAPI error: Ambigious recipient.\n");+            else if(send_res== MAPI_E_MESSAGE_IN_USE)       fprintf(stderr, "MAPI error: Messag in use.\n");+            else if(send_res== MAPI_E_NETWORK_FAILURE)      fprintf(stderr, "MAPI error: Network failure.\n");+            else if(send_res== MAPI_E_INVALID_EDITFIELDS)   fprintf(stderr, "MAPI error: Invalid editfields\n");+            else if(send_res== MAPI_E_INVALID_RECIPS)       fprintf(stderr, "MAPI error: Invalid recipient(s)\n");+            else if(send_res== MAPI_E_NOT_SUPPORTED)        fprintf(stderr, "MAPI error: Operation not supported.\n");+            else fprintf(stderr, "MAPISendMail returned %ld\n", send_res);+        }++        +        if (orig_lookup) funs.free_buf(orig_lookup);+        if (recip_lookup) funs.free_buf(recip_lookup);+        if (cc_lookup) funs.free_buf(cc_lookup);+        if (attachment_path) free(attachment_path);++        funs.logoff(session, 0, 0, 0);+    }+    free_dll(&funs);+    return return_code;+}++void get_recipient(MapiFuns* funs, const char *name, ULONG recipClass, MapiRecipDesc *desc, lpMapiRecipDesc *desc_lookup) {+    ULONG ret = funs->resolve(0, 0, (LPSTR) name, 0, 0, desc_lookup);+    if (ret == SUCCESS_SUCCESS) {+        memcpy(desc, *desc_lookup, sizeof(MapiRecipDesc));+    } else {+        /* Default to something sensible if MAPIResolveName is not supported +         * by the mail client (thunderbird)+         */+        memset(desc, 0, sizeof(MapiRecipDesc));+        desc->lpszName = (LPSTR)name;+        desc->lpszAddress = (LPSTR)name;+        desc->lpEntryID = 0;+        desc->ulEIDSize = 0;+    }+    desc->ulRecipClass = recipClass;+}+++int load_dll(const char* name, MapiFuns* funs) {+    funs->dll = 0;+    funs->dll = LoadLibrary(name);+    if(funs->dll!=NULL) {+        /* We try first loading by easy name, then by ordinal, and then by other names seen */+        funs->logon     = (LPMAPILOGON)         GetProcAddress(funs->dll, "MAPILogon");+        if(funs->logon==NULL)+            funs->logon     = (LPMAPILOGON)         GetProcAddress(funs->dll, (LPCSTR)209);++        funs->logoff    = (LPMAPILOGOFF)        GetProcAddress(funs->dll, "MAPILogOff");+        if(funs->logoff==NULL)+            funs->logoff    = (LPMAPILOGOFF)        GetProcAddress(funs->dll, (LPCSTR)210);++        funs->resolve   = (LPMAPIRESOLVENAME)   GetProcAddress(funs->dll, "MAPIResolveName");+        if(funs->resolve==NULL)+            funs->resolve   = (LPMAPIRESOLVENAME)   GetProcAddress(funs->dll, (LPCSTR)219);++        funs->free_buf  = (LPMAPIFREEBUFFER)    GetProcAddress(funs->dll, "MAPIFreeBuffer");+        if(funs->free_buf==NULL)+            funs->free_buf  = (LPMAPIFREEBUFFER)    GetProcAddress(funs->dll, (LPCSTR)16);+        if(funs->free_buf==NULL)+            funs->free_buf  = (LPMAPIFREEBUFFER)    GetProcAddress(funs->dll, "MAPIFreeBuffer@4");++        funs->sendmail  = (LPMAPISENDMAIL)      GetProcAddress(funs->dll, "MAPISendMail");+        if(funs->sendmail==NULL)+            funs->sendmail  = (LPMAPISENDMAIL)      GetProcAddress(funs->dll, (LPCSTR)211);+    }+    return +            funs->dll!=NULL+        &&  funs->logon!=NULL+        &&  funs->logoff!=NULL+        &&  funs->resolve!=NULL+        &&  funs->free_buf!=NULL+        &&  funs->sendmail!=NULL;+}+void free_dll(MapiFuns* funs) {+    if(funs->dll!=NULL) FreeLibrary(funs->dll);+    funs->dll=NULL;+}+
+ src/win32/send_email.h view
@@ -0,0 +1,9 @@++int send_email(const char *sendname, +               const char *recvname, +               const char *ccname, +               const char *subj,+               const char *body,+               const char *path);++
+ src/win32/sys/mman.h view
@@ -0,0 +1,7 @@++#include <sys/types.h>++void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);+int munmap(void *start, size_t length);++
+ tools/cgi/README view
@@ -0,0 +1,42 @@+darcs.cgi is the darcs repository viewer.  It provides a web interface+for viewing darcs repositories, using XSLT to transform darcs' XML+output into XHTML. It is written in perl and is more featureful than+the older haskell cgi program darcs_cgi.lhs (seen in URLs as "darcs").++dependencies++  darcs.cgi requires with the following tools and has been tested with+  the version mentioned:++  darcs-1.0.1           http://www.darcs.net+  libxslt-1.1.6         http://xmlsoft.org/XSLT/+  perl-5.8.0            http://www.perl.com++installation++  1) copy darcs.cgi to your webserver's cgi directory, eg+     /usr/lib/cgi-bin. A symlink probably won't do. Make+     sure it's executable.+  2) copy cgi.conf to ${prefix}/etc/darcs/cgi.conf and edit appropriately.+     You can overwrite the cgi.conf used by the old darcs cgi script.+     You probably don't need to change anything here.+  3) copy the xslt directory to ${datarootdir}/darcs/xslt+  4) copy xslt/styles.css to ${prefix}/etc/darcs/styles.css++  Test by browsing "http://<host>/cgi-bin/darcs.cgi/".++troubleshooting++  if the configuration is incorrect error messages will be printed to+  the webserver's error log, for example "/var/log/apache/error.log".++  you can also double check the configuration by running darcs.cgi+  from the command line and supplying a --check argument:++     $ ./darcs.cgi --check++character encodings++  if your repositories contain files with characters encoded in+  something other than ASCII or UTF-8, change the 'xml_encoding'+  setting in cgi.conf to the appropriate encoding.
+ tools/cgi/README.in view
@@ -0,0 +1,42 @@+darcs.cgi is the darcs repository viewer.  It provides a web interface+for viewing darcs repositories, using XSLT to transform darcs' XML+output into XHTML. It is written in perl and is more featureful than+the older haskell cgi program darcs_cgi.lhs (seen in URLs as "darcs").++dependencies++  darcs.cgi requires with the following tools and has been tested with+  the version mentioned:++  darcs-1.0.1           http://www.darcs.net+  libxslt-1.1.6         http://xmlsoft.org/XSLT/+  perl-5.8.0            http://www.perl.com++installation++  1) copy darcs.cgi to your webserver's cgi directory, eg+     /usr/lib/cgi-bin. A symlink probably won't do. Make+     sure it's executable.+  2) copy cgi.conf to @sysconfdir@/darcs/cgi.conf and edit appropriately.+     You can overwrite the cgi.conf used by the old darcs cgi script.+     You probably don't need to change anything here.+  3) copy the xslt directory to @datadir@/darcs/xslt+  4) copy xslt/styles.css to @sysconfdir@/darcs/styles.css++  Test by browsing "http://<host>/cgi-bin/darcs.cgi/".++troubleshooting++  if the configuration is incorrect error messages will be printed to+  the webserver's error log, for example "/var/log/apache/error.log".++  you can also double check the configuration by running darcs.cgi+  from the command line and supplying a --check argument:++     $ ./darcs.cgi --check++character encodings++  if your repositories contain files with characters encoded in+  something other than ASCII or UTF-8, change the 'xml_encoding'+  setting in cgi.conf to the appropriate encoding.
+ tools/cgi/cgi.conf view
@@ -0,0 +1,31 @@+# This is an example for cgi.conf++# reposdir is the directory containing the repositories++reposdir = /var/www/repos++# cachedir is a directory writable by www-data (or whatever user your cgi+# scripts run as) which is used to cache the web pages.++cachedir = /var/cache/darcs++# The following are used by darcs.cgi (not darcs_cgi)+PATH = /bin:/usr/bin:/usr/local/bin++# paths to executables, or just the executables if they are in 'PATH'+#darcs = darcs+#xsltproc = xsltproc++# Path to XSLT templates (default is /usr/local/share/darcs/xslt)+xslt_dir = ${datarootdir}/darcs/xslt++# HTTP request path of the style sheet, the default will magically read +# ${prefix}/etc/darcs/styles.css+#stylesheet = /cgi-bin/darcs.cgi/styles.css++css_styles  = ${prefix}/etc/darcs/styles.css++# encoding to include in XML declaration.  Set this to the encoding used+# by the files in your repositories.++xml_encoding = UTF-8
+ tools/cgi/cgi.conf.in view
@@ -0,0 +1,31 @@+# This is an example for cgi.conf++# reposdir is the directory containing the repositories++reposdir = /var/www/repos++# cachedir is a directory writable by www-data (or whatever user your cgi+# scripts run as) which is used to cache the web pages.++cachedir = /var/cache/darcs++# The following are used by darcs.cgi (not darcs_cgi)+PATH = /bin:/usr/bin:/usr/local/bin++# paths to executables, or just the executables if they are in 'PATH'+#darcs = darcs+#xsltproc = xsltproc++# Path to XSLT templates (default is /usr/local/share/darcs/xslt)+xslt_dir = @datadir@/darcs/xslt++# HTTP request path of the style sheet, the default will magically read +# @sysconfdir@/darcs/styles.css+#stylesheet = /cgi-bin/darcs.cgi/styles.css++css_styles  = @sysconfdir@/darcs/styles.css++# encoding to include in XML declaration.  Set this to the encoding used+# by the files in your repositories.++xml_encoding = UTF-8
+ tools/cgi/darcs.cgi view
@@ -0,0 +1,491 @@+#!/usr/bin/perl -T+#+# darcs.cgi - the darcs repository viewer+#+# Copyright (c) 2004 Will Glozer+#+# Permission is hereby granted, free of charge, to any person obtaining+# a copy of this software and associated documentation files (the+# "Software"), to deal in the Software without restriction, including+# without limitation the rights to use, copy, modify, merge, publish,+# distribute, sublicense, and/or sell copies of the Software, and to+# permit persons to whom the Software is furnished to do so, subject to+# the following conditions+#+# The above copyright notice and this permission notice shall be+# included in all copies or substantial portions of the Software.+#+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.++#+# This program calls darcs (or its own subroutines) to generate XML+# which is rendered into HTML by XSLT.  It is capable of displaying+# the files in a repository, various patch histories, annotations, etc.+#++use strict;++use CGI qw( :standard );+use CGI::Util;+use File::Basename;+use File::stat;+use IO::File;+use POSIX;++## the following variables can be customized to reflect your system+## configuration by defining them appropriately in the file+## "${prefix}/etc/darcs/cgi.conf".  The syntax accepts equals signs or simply+## blanks separating values from assignments.++$ENV{'PATH'} = read_conf('PATH', $ENV{'PATH'});++# path to executables, or just the executable if they are in $ENV{'PATH'}+my $darcs_program    = read_conf("darcs", "darcs");+my $xslt_program     = read_conf("xsltproc", "xsltproc");++# directory containing repositories+my $repository_root  = read_conf("reposdir", "/var/www");++# XSLT template locations+my $template_root = read_conf("xslt_dir", '${datarootdir}/darcs/xslt');++my $xslt_annotate = "$template_root/annotate.xslt";+my $xslt_browse   = "$template_root/browse.xslt";+my $xslt_patches  = "$template_root/patches.xslt";+my $xslt_repos    = "$template_root/repos.xslt";+my $xslt_rss      = "$template_root/rss.xslt";++my $xslt_errors   = "$template_root/errors.xslt";++# CSS stylesheet that XSLT templates refer to.  This is a HTTP request+# path, not a local file system path. The default will cause darcs.cgi+# to serve the stylesheet rather than the web server.+my $stylesheet = read_conf("stylesheet", "/cgi-bin/darcs.cgi/styles.css");++# location of the CSS stylesheet that darcs.cgi will serve if it+# receives a request for '/styles.css'+my $css_styles = read_conf("css_styles", '${prefix}/etc/darcs/styles.css');++# location of the favicon that darcs.cgi will serve if it+# receives a request for '/[\w\-]+/favicon.ico'+my $favicon = read_conf("favicon", "/cgi-bin/favicon.ico");++# XML source for the error pages+my $xml_errors = "$template_root/errors.xml";++# encoding to include in XML declaration+my $xml_encoding = read_conf("xml_encoding", "UTF-8");++## end customization++# ----------------------------------------------------------------------++# read a value from the cgi.conf file.+{+  my(%conf);++  sub read_conf {+    my ($flag, $val) = @_;+    $val = "" if !defined($val);+    +    if (!%conf && open(CGI_CONF, '${prefix}/etc/darcs/cgi.conf')) {+      while (<CGI_CONF>) {+        chomp;+	next if /^\s*(?:\#.*)?$/;   # Skip blank lines and comment lines+        if (/^\s*(\S+)\s*(?:\=\s*)?(\S+)\s*$/) {+           $conf{$1} = $2;+	   # print "read_conf: $1 = $2\n";+        } else {+           warn "read_conf: $_\n";+        }+      }+      close(CGI_CONF);+    }++    $val = $conf{$flag} if exists($conf{$flag});++    return $val;+  }+}++# open xsltproc to transform and output `xml' with stylesheet file `xslt'+sub transform {+    my ($xslt, $args, $content_type) = @_;++    $| = 1;+    printf "Content-type: %s\r\n\r\n", $content_type || "text/html";+    my $pipe = new IO::File "| $xslt_program $args $xslt -";+    $pipe->autoflush(0);+    return $pipe;+}++sub pristine_dir {+    my ($repo) = @_;+    my $pristine = "current";+    if (! -d "${repository_root}/${repo}/_darcs/$pristine") {+        $pristine = "pristine";+    }+    return "${repository_root}/${repo}/_darcs/$pristine";+}++# begin an XML document with a root element and the repository path+sub make_xml {+    my ($fh, $repo, $dir, $file) = @_;+    my ($full_path, $path) = '/';++    printf $fh qq(<?xml version="1.0" encoding="$xml_encoding"?>\n);++    printf $fh qq(<darcs repository="$repo" target="%s/%s%s">\n),+        $repo, ($dir ? "$dir/" : ''), ($file ? "$file" : '');++    print $fh qq(<path>\n);+    foreach $path (split('/', "$repo/$dir")) {+        $full_path .= "$path/";+        print $fh qq(<directory full-path="$full_path">$path</directory>\n);+    }+    if ($file) {+        print $fh qq(<file full-path="$full_path$file">$file</file>\n) if $file;+    }+    print $fh qq(</path>\n\n);+}++# finish XML output+sub finish_xml {+    my ($fh) = @_;+    print $fh "\n</darcs>\n";+    $fh->flush;+}++# run darcs and wrap the output in an XML document+sub darcs_xml {+    my ($fh, $repo, $cmd, $args, $dir, $file) = @_;++    make_xml($fh, $repo, $dir, $file);++    push(@$args, '--xml-output');+    darcs($fh, $repo, $cmd, $args, $dir, $file);++    finish_xml($fh);+}++# run darcs with output redirected to the specified file handle+sub darcs {+    my ($fh, $repo, $cmd, $args, $dir, $file) = @_;+    my (@darcs_argv) = ($darcs_program, $cmd, @$args);++    # push target only if there is one, otherwise darcs will get an empty param+    if ($dir || $file) {+        push(@darcs_argv, sprintf("%s%s%s", $dir, ($dir ? '/' : ''), $file));+    }++    my($pid) = fork;+    if ($pid) {+	# in the parent process+	my($status) = waitpid($pid, 0);+	die "$darcs_program exited with status $?\n" if $?;+    } elsif(defined($pid)) {+	# in the child process+	open(STDIN, '/dev/null');+	if (defined($fh)) {+	    open(STDOUT, '>&', $fh)+		|| die "can't dup to stdout: $!\n";+	}+	chdir "$repository_root/$repo"+	    || die "chdir: $repository_root/$repo: $!\n";+	exec @darcs_argv;+	die "can't exec ".$darcs_argv[0].": $!\n";+    } else {+	# fork failed+	die "can't fork: $!\n";+    }+}++# get a directory listing as XML output+sub dir_listing {+    my ($fh, $repo, $dir) = @_;+    make_xml($fh, $repo, $dir, '');++    print $fh "<files>\n";+    my $dir_ = pristine_dir ($repo) . "/$dir";+    opendir(DH, $dir_);+    while( defined (my $file_ = readdir(DH)) ) {+        next if $file_ =~ /^\.\.?$/;+        my $file = "$dir_/$file_";+        my $secs  = stat($file)->mtime;+        my $mtime = localtime($secs);+        my $ts = POSIX::strftime("%Y%m%d%H%M%S", gmtime $secs);++        my ($name, $type);++         if (-d $file) {+             ($name, $type) = (basename($file) . '/', 'directory');+         } else {+             ($name, $type) = (basename($file), 'file');+         }+         printf $fh qq(  <$type name="$name" modified="$mtime" ts="$ts" />\n);+    }+    closedir(DH);+    print $fh "</files>\n";++    finish_xml($fh);+}++# get a repository listing as XML output+sub repo_listing {+    my($fh) = @_;++    make_xml($fh, "", "", "");++    print $fh "<repositories>\n";+    opendir(DH, $repository_root);+    while( defined (my $name = readdir(DH)) ) {+        next if $name =~ /^\.\.?$/;+        if (-d "$repository_root/$name/_darcs") {+            printf $fh qq(  <repository name="$name" />\n);+        }+    }+    closedir(DH);+    print $fh "</repositories>\n";++    finish_xml($fh);+    return $fh;+}++# show an error page+sub show_error {+    my ($type, $code, $message) = @_;+    my $xml;++    # set the xslt processing arguments+    my $xslt_args = qq {+        --stringparam error-type '$type'+        --stringparam stylesheet '$stylesheet'+    };+    $xslt_args =~ s/\s+/ /gm;++    print "Status: $code $message\r\n\r\n";+    system("$xslt_program $xslt_args $xslt_errors $xml_errors");+}++# check if the requested resource has been modified since the client last+# saw it. If not send HTTP status code 304, otherwise set the Last-modified+# and Cache-control headers.+sub is_cached {+    my ($path) = @_;+    my ($stat) = stat($path);++    # stat may fail because the path was renamed or deleted but still referred+    # to by older darcs patches+    if ($stat) {+        my $last_modified = CGI::expires($stat->mtime);++        if (http('If-Modified-Since') eq $last_modified) {+            print("Status: 304 Not Modified\r\n\r\n");+            return 1;+        }++        print("Cache-control: max-age=0, must-revalidate\r\n");+        print("Last-modified: $last_modified\r\n");+    }+    return 0;+}++# safely extract a parameter from the http request.  This applies a regexp+# to the parameter which should group only the appropriate parameter value+sub safe_param {+    my ($param, $regex, $default) = @_;+    my $value = CGI::Util::unescape(param($param));+    return ($value =~ $regex) ? $1 : $default;+}++# common regular expressions for validating passed parameters+my $hash_regex = qr/^([\w\-.]+)$/;+my $path_regex = qr@^([^\\!\$\^&*()\[\]{}<>`|';"?\r\n]+)$@;++# respond to a CGI request+sub respond {+    # untaint the full URL to this CGI+    my $cgi_url = CGI::Util::unescape(url());+    $cgi_url =~ $path_regex or die qq(bad url "$cgi_url");+    $cgi_url = $1;++    # untaint script_name, reasonable to expect only \w, -, /, and . in the name+    my $script_name = CGI::Util::unescape(script_name());+    $script_name =~ qr~^([\w/.\-\~]+)$~ or die qq(bad script_name "$script_name");+    $script_name = $1;++    # untaint simple parameters, which can only have chars matching \w++    my $cmd  = safe_param('c', '^(\w+)$', 'browse');+    my $sort = safe_param('s', '^(\w+)$', '');++    # set the xslt processing arguments+    my $xslt_args = qq {+        --stringparam cgi-program '$script_name'+        --stringparam cgi-url '$cgi_url'+        --stringparam sort-by '$sort'+        --stringparam stylesheet '$stylesheet'+    };+    $xslt_args =~ s/\s+/ /gm;++    my ($path) = CGI::Util::unescape(path_info());+    # don't allow ./ or ../ in paths+    $path =~ s|[.]+/||g;++    # check whether we're asking for styles.css+    if ($path eq '/styles.css') {+        return if is_cached($css_styles);++        open (STYLES_CSS, $css_styles) or die qq(couldn't open "${css_styles}");+        my $size = stat($css_styles)->size;++        print "Content-length: $size\r\n";+        print "Content-type: text/css\r\n\r\n";++        while (<STYLES_CSS>) {+          print $_;+        }+        close (STYLES_CSS);+        return;+    }++    # check whether we're asking for favicon.ico+    if ($path =~ '/[\w\-]+/favicon.ico') {+        return if is_cached($favicon);++        open (FAVICON, $favicon) or die qq(couldn't open "${favicon}");+        my $size = stat($favicon)->size;++        print "Content-length: $size\r\n";+        print "Content-type: image/x-icon\r\n\r\n";++        while (<FAVICON>) {+          print $_;+        }+        close (FAVICON);+        return;+    }++    # when no repository is requested display available repositories+    if (length($path) < 2) {+        my $fh = transform($xslt_repos, $xslt_args);+        repo_listing($fh);+        return;+    }++    # don't allow any shell meta characters in paths+    $path =~ $path_regex or die qq(bad path_info "$path");+    my @path = split('/', substr($1, 1));++    # split the path into a repository, directory, and file+    my ($repo, $dir, $file, @bits) = ('', '', '');+    while (@path > 0) {+        $repo = join('/', @path);+        # check if remaining path elements refer to a repo+        if (-d "${repository_root}/${repo}/_darcs") {+            if (@bits > 1) {+                $dir  = join('/', @bits[0..$#bits - 1]);+            }+            $file = $bits[$#bits];+            # check if last element of path, stored in $file, is really a dir+            if (-d (pristine_dir ($repo) . "/${dir}/${file}")) {+                $dir = ($dir ? "$dir/$file" : $file);+                $file = '';+            }+            last;+        } else {+            $repo = '';+            unshift(@bits, pop @path);+        }+    }++    # make sure the repository exists+    unless ($repo) {+        show_error('invalid-repository', '404', 'Invalid repository');+        return;+    }++    # don't generate output unless the requested path has been+    # modified since the client last saw it.+    return if is_cached(pristine_dir ($repo) . "/$dir/$file");++    # untaint patches and tags. Tags can have arbitrary values, so+    # never pass these unquoted, on pain of pain!+    my $patch = safe_param('p', $hash_regex);+    my $tag   = safe_param('t', '^(.+)$');++    my @darcs_args;+    push(@darcs_args, '--match', "hash $patch") if $patch;+    push(@darcs_args, '-t', $tag) if $tag;++    # process the requested command+    if ($cmd eq 'browse') {+        my $fh = transform($xslt_browse, $xslt_args);+        dir_listing($fh, $repo, $dir);+    } elsif ($cmd eq 'patches') {+        # patches as an option is used to support "--patches"+        if (my $patches = safe_param('patches','^(.+)$')) {+            push @darcs_args, '--patches', $patches;+        }++        my $fh = transform($xslt_patches, $xslt_args);+        darcs_xml($fh, $repo, "changes", \@darcs_args, $dir, $file);+    } elsif ($cmd eq 'annotate') {+        push(@darcs_args, '--summary');++        my $creator_hash  = safe_param('ch', $hash_regex);+        my $original_path = safe_param('o', $path_regex);+        my $fh = transform($xslt_annotate, $xslt_args);++        # use the creator hash and original file name when available so+        # annotations can span renames+        if ($creator_hash ne '' && $original_path ne '') {+            push(@darcs_args, '--creator-hash', $creator_hash);+            darcs_xml($fh, $repo, "annotate", \@darcs_args, '', $original_path);+        } else {+            darcs_xml($fh, $repo, "annotate", \@darcs_args, $dir, $file);+        }+    } elsif ($cmd eq 'diff') {+        push(@darcs_args, '-u');+        print "Content-type: text/plain\r\n\r\n";+        darcs(undef, $repo, "diff", \@darcs_args, $dir, $file);+    } elsif ($cmd eq 'rss') {+        push(@darcs_args, '--last', '25');++        my $fh = transform($xslt_rss, $xslt_args, "application/rss+xml");+        darcs_xml($fh, $repo, "changes", \@darcs_args, $dir, $file);+    } else {+        show_error('invalid-command', '400', 'Invalid command');+    }+}++# run a self-test when the --check argument is supplied+if ($ARGV[0] eq '--check') {+    (read_conf("css_styles", "abc") ne "abc") ||+        die "cannot read config file: $!\n";++    (`$darcs_program`) ||+        die "cannot execute darcs as '$darcs_program': $!\n";+    (`$xslt_program`) ||+        die "cannot execute xstlproc as '$xslt_program': $!\n";++    (-d $repository_root && -r $repository_root) ||+        die "cannot read repository root directory '$repository_root': $!\n";+    (-d $template_root && -r $template_root) ||+        die "cannot read template root directory '$template_root': $!\n";+    (-f $css_styles) ||+        die "cannot read css stylesheet '$css_styles': $!\n";+    (-f $xml_errors) ||+        die "cannot read error messages '$xml_errors': $!\n";++    exit 0;+}++# handle the CGI request+respond();+
+ tools/cgi/darcs.cgi.in view
@@ -0,0 +1,491 @@+#!/usr/bin/perl -T+#+# darcs.cgi - the darcs repository viewer+#+# Copyright (c) 2004 Will Glozer+#+# Permission is hereby granted, free of charge, to any person obtaining+# a copy of this software and associated documentation files (the+# "Software"), to deal in the Software without restriction, including+# without limitation the rights to use, copy, modify, merge, publish,+# distribute, sublicense, and/or sell copies of the Software, and to+# permit persons to whom the Software is furnished to do so, subject to+# the following conditions+#+# The above copyright notice and this permission notice shall be+# included in all copies or substantial portions of the Software.+#+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.++#+# This program calls darcs (or its own subroutines) to generate XML+# which is rendered into HTML by XSLT.  It is capable of displaying+# the files in a repository, various patch histories, annotations, etc.+#++use strict;++use CGI qw( :standard );+use CGI::Util;+use File::Basename;+use File::stat;+use IO::File;+use POSIX;++## the following variables can be customized to reflect your system+## configuration by defining them appropriately in the file+## "@sysconfdir@/darcs/cgi.conf".  The syntax accepts equals signs or simply+## blanks separating values from assignments.++$ENV{'PATH'} = read_conf('PATH', $ENV{'PATH'});++# path to executables, or just the executable if they are in $ENV{'PATH'}+my $darcs_program    = read_conf("darcs", "darcs");+my $xslt_program     = read_conf("xsltproc", "xsltproc");++# directory containing repositories+my $repository_root  = read_conf("reposdir", "/var/www");++# XSLT template locations+my $template_root = read_conf("xslt_dir", '@datadir@/darcs/xslt');++my $xslt_annotate = "$template_root/annotate.xslt";+my $xslt_browse   = "$template_root/browse.xslt";+my $xslt_patches  = "$template_root/patches.xslt";+my $xslt_repos    = "$template_root/repos.xslt";+my $xslt_rss      = "$template_root/rss.xslt";++my $xslt_errors   = "$template_root/errors.xslt";++# CSS stylesheet that XSLT templates refer to.  This is a HTTP request+# path, not a local file system path. The default will cause darcs.cgi+# to serve the stylesheet rather than the web server.+my $stylesheet = read_conf("stylesheet", "/cgi-bin/darcs.cgi/styles.css");++# location of the CSS stylesheet that darcs.cgi will serve if it+# receives a request for '/styles.css'+my $css_styles = read_conf("css_styles", '@sysconfdir@/darcs/styles.css');++# location of the favicon that darcs.cgi will serve if it+# receives a request for '/[\w\-]+/favicon.ico'+my $favicon = read_conf("favicon", "/cgi-bin/favicon.ico");++# XML source for the error pages+my $xml_errors = "$template_root/errors.xml";++# encoding to include in XML declaration+my $xml_encoding = read_conf("xml_encoding", "UTF-8");++## end customization++# ----------------------------------------------------------------------++# read a value from the cgi.conf file.+{+  my(%conf);++  sub read_conf {+    my ($flag, $val) = @_;+    $val = "" if !defined($val);+    +    if (!%conf && open(CGI_CONF, '@sysconfdir@/darcs/cgi.conf')) {+      while (<CGI_CONF>) {+        chomp;+	next if /^\s*(?:\#.*)?$/;   # Skip blank lines and comment lines+        if (/^\s*(\S+)\s*(?:\=\s*)?(\S+)\s*$/) {+           $conf{$1} = $2;+	   # print "read_conf: $1 = $2\n";+        } else {+           warn "read_conf: $_\n";+        }+      }+      close(CGI_CONF);+    }++    $val = $conf{$flag} if exists($conf{$flag});++    return $val;+  }+}++# open xsltproc to transform and output `xml' with stylesheet file `xslt'+sub transform {+    my ($xslt, $args, $content_type) = @_;++    $| = 1;+    printf "Content-type: %s\r\n\r\n", $content_type || "text/html";+    my $pipe = new IO::File "| $xslt_program $args $xslt -";+    $pipe->autoflush(0);+    return $pipe;+}++sub pristine_dir {+    my ($repo) = @_;+    my $pristine = "current";+    if (! -d "${repository_root}/${repo}/_darcs/$pristine") {+        $pristine = "pristine";+    }+    return "${repository_root}/${repo}/_darcs/$pristine";+}++# begin an XML document with a root element and the repository path+sub make_xml {+    my ($fh, $repo, $dir, $file) = @_;+    my ($full_path, $path) = '/';++    printf $fh qq(<?xml version="1.0" encoding="$xml_encoding"?>\n);++    printf $fh qq(<darcs repository="$repo" target="%s/%s%s">\n),+        $repo, ($dir ? "$dir/" : ''), ($file ? "$file" : '');++    print $fh qq(<path>\n);+    foreach $path (split('/', "$repo/$dir")) {+        $full_path .= "$path/";+        print $fh qq(<directory full-path="$full_path">$path</directory>\n);+    }+    if ($file) {+        print $fh qq(<file full-path="$full_path$file">$file</file>\n) if $file;+    }+    print $fh qq(</path>\n\n);+}++# finish XML output+sub finish_xml {+    my ($fh) = @_;+    print $fh "\n</darcs>\n";+    $fh->flush;+}++# run darcs and wrap the output in an XML document+sub darcs_xml {+    my ($fh, $repo, $cmd, $args, $dir, $file) = @_;++    make_xml($fh, $repo, $dir, $file);++    push(@$args, '--xml-output');+    darcs($fh, $repo, $cmd, $args, $dir, $file);++    finish_xml($fh);+}++# run darcs with output redirected to the specified file handle+sub darcs {+    my ($fh, $repo, $cmd, $args, $dir, $file) = @_;+    my (@darcs_argv) = ($darcs_program, $cmd, @$args);++    # push target only if there is one, otherwise darcs will get an empty param+    if ($dir || $file) {+        push(@darcs_argv, sprintf("%s%s%s", $dir, ($dir ? '/' : ''), $file));+    }++    my($pid) = fork;+    if ($pid) {+	# in the parent process+	my($status) = waitpid($pid, 0);+	die "$darcs_program exited with status $?\n" if $?;+    } elsif(defined($pid)) {+	# in the child process+	open(STDIN, '/dev/null');+	if (defined($fh)) {+	    open(STDOUT, '>&', $fh)+		|| die "can't dup to stdout: $!\n";+	}+	chdir "$repository_root/$repo"+	    || die "chdir: $repository_root/$repo: $!\n";+	exec @darcs_argv;+	die "can't exec ".$darcs_argv[0].": $!\n";+    } else {+	# fork failed+	die "can't fork: $!\n";+    }+}++# get a directory listing as XML output+sub dir_listing {+    my ($fh, $repo, $dir) = @_;+    make_xml($fh, $repo, $dir, '');++    print $fh "<files>\n";+    my $dir_ = pristine_dir ($repo) . "/$dir";+    opendir(DH, $dir_);+    while( defined (my $file_ = readdir(DH)) ) {+        next if $file_ =~ /^\.\.?$/;+        my $file = "$dir_/$file_";+        my $secs  = stat($file)->mtime;+        my $mtime = localtime($secs);+        my $ts = POSIX::strftime("%Y%m%d%H%M%S", gmtime $secs);++        my ($name, $type);++         if (-d $file) {+             ($name, $type) = (basename($file) . '/', 'directory');+         } else {+             ($name, $type) = (basename($file), 'file');+         }+         printf $fh qq(  <$type name="$name" modified="$mtime" ts="$ts" />\n);+    }+    closedir(DH);+    print $fh "</files>\n";++    finish_xml($fh);+}++# get a repository listing as XML output+sub repo_listing {+    my($fh) = @_;++    make_xml($fh, "", "", "");++    print $fh "<repositories>\n";+    opendir(DH, $repository_root);+    while( defined (my $name = readdir(DH)) ) {+        next if $name =~ /^\.\.?$/;+        if (-d "$repository_root/$name/_darcs") {+            printf $fh qq(  <repository name="$name" />\n);+        }+    }+    closedir(DH);+    print $fh "</repositories>\n";++    finish_xml($fh);+    return $fh;+}++# show an error page+sub show_error {+    my ($type, $code, $message) = @_;+    my $xml;++    # set the xslt processing arguments+    my $xslt_args = qq {+        --stringparam error-type '$type'+        --stringparam stylesheet '$stylesheet'+    };+    $xslt_args =~ s/\s+/ /gm;++    print "Status: $code $message\r\n\r\n";+    system("$xslt_program $xslt_args $xslt_errors $xml_errors");+}++# check if the requested resource has been modified since the client last+# saw it. If not send HTTP status code 304, otherwise set the Last-modified+# and Cache-control headers.+sub is_cached {+    my ($path) = @_;+    my ($stat) = stat($path);++    # stat may fail because the path was renamed or deleted but still referred+    # to by older darcs patches+    if ($stat) {+        my $last_modified = CGI::expires($stat->mtime);++        if (http('If-Modified-Since') eq $last_modified) {+            print("Status: 304 Not Modified\r\n\r\n");+            return 1;+        }++        print("Cache-control: max-age=0, must-revalidate\r\n");+        print("Last-modified: $last_modified\r\n");+    }+    return 0;+}++# safely extract a parameter from the http request.  This applies a regexp+# to the parameter which should group only the appropriate parameter value+sub safe_param {+    my ($param, $regex, $default) = @_;+    my $value = CGI::Util::unescape(param($param));+    return ($value =~ $regex) ? $1 : $default;+}++# common regular expressions for validating passed parameters+my $hash_regex = qr/^([\w\-.]+)$/;+my $path_regex = qr@^([^\\!\$\^&*()\[\]{}<>`|';"?\r\n]+)$@;++# respond to a CGI request+sub respond {+    # untaint the full URL to this CGI+    my $cgi_url = CGI::Util::unescape(url());+    $cgi_url =~ $path_regex or die qq(bad url "$cgi_url");+    $cgi_url = $1;++    # untaint script_name, reasonable to expect only \w, -, /, and . in the name+    my $script_name = CGI::Util::unescape(script_name());+    $script_name =~ qr~^([\w/.\-\~]+)$~ or die qq(bad script_name "$script_name");+    $script_name = $1;++    # untaint simple parameters, which can only have chars matching \w++    my $cmd  = safe_param('c', '^(\w+)$', 'browse');+    my $sort = safe_param('s', '^(\w+)$', '');++    # set the xslt processing arguments+    my $xslt_args = qq {+        --stringparam cgi-program '$script_name'+        --stringparam cgi-url '$cgi_url'+        --stringparam sort-by '$sort'+        --stringparam stylesheet '$stylesheet'+    };+    $xslt_args =~ s/\s+/ /gm;++    my ($path) = CGI::Util::unescape(path_info());+    # don't allow ./ or ../ in paths+    $path =~ s|[.]+/||g;++    # check whether we're asking for styles.css+    if ($path eq '/styles.css') {+        return if is_cached($css_styles);++        open (STYLES_CSS, $css_styles) or die qq(couldn't open "${css_styles}");+        my $size = stat($css_styles)->size;++        print "Content-length: $size\r\n";+        print "Content-type: text/css\r\n\r\n";++        while (<STYLES_CSS>) {+          print $_;+        }+        close (STYLES_CSS);+        return;+    }++    # check whether we're asking for favicon.ico+    if ($path =~ '/[\w\-]+/favicon.ico') {+        return if is_cached($favicon);++        open (FAVICON, $favicon) or die qq(couldn't open "${favicon}");+        my $size = stat($favicon)->size;++        print "Content-length: $size\r\n";+        print "Content-type: image/x-icon\r\n\r\n";++        while (<FAVICON>) {+          print $_;+        }+        close (FAVICON);+        return;+    }++    # when no repository is requested display available repositories+    if (length($path) < 2) {+        my $fh = transform($xslt_repos, $xslt_args);+        repo_listing($fh);+        return;+    }++    # don't allow any shell meta characters in paths+    $path =~ $path_regex or die qq(bad path_info "$path");+    my @path = split('/', substr($1, 1));++    # split the path into a repository, directory, and file+    my ($repo, $dir, $file, @bits) = ('', '', '');+    while (@path > 0) {+        $repo = join('/', @path);+        # check if remaining path elements refer to a repo+        if (-d "${repository_root}/${repo}/_darcs") {+            if (@bits > 1) {+                $dir  = join('/', @bits[0..$#bits - 1]);+            }+            $file = $bits[$#bits];+            # check if last element of path, stored in $file, is really a dir+            if (-d (pristine_dir ($repo) . "/${dir}/${file}")) {+                $dir = ($dir ? "$dir/$file" : $file);+                $file = '';+            }+            last;+        } else {+            $repo = '';+            unshift(@bits, pop @path);+        }+    }++    # make sure the repository exists+    unless ($repo) {+        show_error('invalid-repository', '404', 'Invalid repository');+        return;+    }++    # don't generate output unless the requested path has been+    # modified since the client last saw it.+    return if is_cached(pristine_dir ($repo) . "/$dir/$file");++    # untaint patches and tags. Tags can have arbitrary values, so+    # never pass these unquoted, on pain of pain!+    my $patch = safe_param('p', $hash_regex);+    my $tag   = safe_param('t', '^(.+)$');++    my @darcs_args;+    push(@darcs_args, '--match', "hash $patch") if $patch;+    push(@darcs_args, '-t', $tag) if $tag;++    # process the requested command+    if ($cmd eq 'browse') {+        my $fh = transform($xslt_browse, $xslt_args);+        dir_listing($fh, $repo, $dir);+    } elsif ($cmd eq 'patches') {+        # patches as an option is used to support "--patches"+        if (my $patches = safe_param('patches','^(.+)$')) {+            push @darcs_args, '--patches', $patches;+        }++        my $fh = transform($xslt_patches, $xslt_args);+        darcs_xml($fh, $repo, "changes", \@darcs_args, $dir, $file);+    } elsif ($cmd eq 'annotate') {+        push(@darcs_args, '--summary');++        my $creator_hash  = safe_param('ch', $hash_regex);+        my $original_path = safe_param('o', $path_regex);+        my $fh = transform($xslt_annotate, $xslt_args);++        # use the creator hash and original file name when available so+        # annotations can span renames+        if ($creator_hash ne '' && $original_path ne '') {+            push(@darcs_args, '--creator-hash', $creator_hash);+            darcs_xml($fh, $repo, "annotate", \@darcs_args, '', $original_path);+        } else {+            darcs_xml($fh, $repo, "annotate", \@darcs_args, $dir, $file);+        }+    } elsif ($cmd eq 'diff') {+        push(@darcs_args, '-u');+        print "Content-type: text/plain\r\n\r\n";+        darcs(undef, $repo, "diff", \@darcs_args, $dir, $file);+    } elsif ($cmd eq 'rss') {+        push(@darcs_args, '--last', '25');++        my $fh = transform($xslt_rss, $xslt_args, "application/rss+xml");+        darcs_xml($fh, $repo, "changes", \@darcs_args, $dir, $file);+    } else {+        show_error('invalid-command', '400', 'Invalid command');+    }+}++# run a self-test when the --check argument is supplied+if ($ARGV[0] eq '--check') {+    (read_conf("css_styles", "abc") ne "abc") ||+        die "cannot read config file: $!\n";++    (`$darcs_program`) ||+        die "cannot execute darcs as '$darcs_program': $!\n";+    (`$xslt_program`) ||+        die "cannot execute xstlproc as '$xslt_program': $!\n";++    (-d $repository_root && -r $repository_root) ||+        die "cannot read repository root directory '$repository_root': $!\n";+    (-d $template_root && -r $template_root) ||+        die "cannot read template root directory '$template_root': $!\n";+    (-f $css_styles) ||+        die "cannot read css stylesheet '$css_styles': $!\n";+    (-f $xml_errors) ||+        die "cannot read error messages '$xml_errors': $!\n";++    exit 0;+}++# handle the CGI request+respond();+
+ tools/cgi/xslt/annotate.xslt view
@@ -0,0 +1,390 @@+<?xml version="1.0" encoding="utf-8"?>++<!--+ template for converting darcs' `annotate` output from XML to XHTML.  This+ template expects the following external variables:++   cgi-program    - path to the CGI executable, to place in links+   sort-by        - field to sort by+   stylesheet     - path to the CSS stylesheet++-->+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">+  <xsl:strip-space elements="*"/>++  <xsl:include href="common.xslt"/>++  <xsl:template match="path">+    <h1 class="target">+        annotations for <span class="path"><a href="{$cgi-program}">projects</a></span> / <span class="path"><xsl:apply-templates/></span>+    </h1>+  </xsl:template>++  <!-- patch annotate tags -->+  <xsl:template match="/darcs/patch">+    <xsl:call-template name="show-patch-info">+      <xsl:with-param name="patch" select="."/>+      <xsl:with-param name="show-comment" select="true()"/>+      <xsl:with-param name="show-author" select="true()"/>+      <xsl:with-param name="show-date" select="true()"/>+    </xsl:call-template>+  </xsl:template>+  +  <xsl:template match="summary">+    <xsl:variable name="hash" select="../patch/@hash"/>+      +    <table>+      <tr class="annotate">+        <th>file</th>+        <th>change</th>+        <th></th>+        <th></th>+      </tr>++      <xsl:apply-templates/>+    </table>++    <form action="{$command}" method="get">+      <p>+        <input type="submit" name="c" value="diff"/>+        <input type="hidden" name="p" value="{$hash}"/>+      </p>+    </form>+  </xsl:template>+  +  <xsl:template match="modify_file">+    <xsl:variable name="file" select="text()"/>+    <xsl:variable name="hash" select="/darcs/patch/@hash" />+      +    <tr class="modified-file">+      <td><xsl:value-of select="$file"/></td>++      <td class="line-count">+        <xsl:for-each select="added_lines">+          +<xsl:value-of select="@num"/>/+        </xsl:for-each>+        <xsl:for-each select="removed_lines">-<xsl:value-of select="@num"/>+        </xsl:for-each>+        lines+      </td>++      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>+      <td><a href="{$command}{$file}?c=patches">patches</a></td>+    </tr>+  </xsl:template>++  <xsl:template match="add_file">+    <xsl:variable name="file" select="text()"/>+    <xsl:variable name="hash" select="/darcs/patch/@hash" />+    +    <tr class="add-remove-file">+      <td><xsl:value-of select="$file"/></td>+      <td>added file</td>+      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>+      <td><a href="{$command}{$file}?c=patches">patches</a></td>+    </tr>+  </xsl:template>++  <xsl:template match="move">+    <xsl:variable name="file" select="@to"/>+    <xsl:variable name="old-file" select="@from"/>    +    <xsl:variable name="hash" select="/darcs/patch/@hash" />+    +    <tr class="add-remove-file">+      <td><xsl:value-of select="$file"/></td>+      <td>moved from <xsl:value-of select="$old-file"/></td>+      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>+      <td><a href="{$command}{$file}?c=patches">patches</a></td>+    </tr>+  </xsl:template>++  <xsl:template match="remove_file">+    <xsl:variable name="file" select="text()"/>+    <xsl:variable name="hash" select="/darcs/patch/@hash" />+    +    <tr class="add-remove-file">+      <td><xsl:value-of select="$file"/></td>+      <td>removed file</td>+      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>+      <td><a href="{$command}{$file}?c=patches">patches</a></td>+    </tr>+  </xsl:template>++  <xsl:template match="add_directory">+    <xsl:variable name="dir" select="text()"/>+    <xsl:variable name="hash" select="/darcs/patch/@hash" />+    +    <tr class="add-remove-file">+      <td><xsl:value-of select="$dir"/></td>+      <td>added directory</td>+      <td><a href="{$command}{$dir}/?c=annotate&amp;p={$hash}">annotate</a></td>+      <td><a href="{$command}{$dir}/?c=patches">patches</a></td>+    </tr>+  </xsl:template>++  <xsl:template match="remove_directory">+    <xsl:variable name="dir" select="text()"/>+    <xsl:variable name="hash" select="/darcs/patch/@hash" />+    +    <tr class="add-remove-file">+      <td><xsl:value-of select="$dir"/></td>+      <td>removed directory</td>+      <td><a href="{$command}{$dir}/?c=annotate&amp;p={$hash}">annotate</a></td>+      <td><a href="{$command}{$dir}/?c=patches">patches</a></td>+    </tr>+  </xsl:template>+  +  <!-- directory annotate templates -->+  <xsl:template match="/darcs/directory">+    <xsl:call-template name="show-patch-info">+      <xsl:with-param name="patch" select="modified/patch"/>+    </xsl:call-template>++    <table>+      <tr class="annotate">+        <th>file</th>+        <th>change</th>+        <th></th>+        <th></th>+      </tr>++      <xsl:apply-templates/>+    </table>+  </xsl:template>+  +  <xsl:template match="directory/modified/modified_how">+    <xsl:variable name="hash" select="../patch/@hash" />+    <xsl:variable name="how" select="substring(text(), 0, 10)"/>+    <xsl:variable name="target" select="/darcs/@target"/>++    <!--+      annotating a directory outputs the directory itself as well as+      any contents.  this ugly code checks if the matching element is+      the original directory so that the 'annotate' and 'patch' links+      don't append the directory twice.+    -->+    <xsl:variable name="last" select="//darcs/path/directory[last()]"/>+    <xsl:variable name="name" select="../../@name"/>+    <xsl:variable name="dir">+      <xsl:choose>+        <xsl:when test="$last = $name"></xsl:when>+        <xsl:otherwise><xsl:value-of select="$name"/>/</xsl:otherwise>+      </xsl:choose>+    </xsl:variable>++    <tr class="add-remove-file">+      <td><xsl:value-of select="$name"/></td>+      <td>+        <xsl:choose>+          <xsl:when test="$how = 'Dir added'">added directory</xsl:when>+          <xsl:when test="$how = 'Dir moved'">moved directory</xsl:when>+          <xsl:when test="$how = 'Dir remov'">removed directory</xsl:when>+        </xsl:choose>+      </td>+      <td>+        <a href="{$command}{$dir}?c=annotate&amp;p={$hash}">annotate</a>+      </td>+      <td><a href="{$command}{$dir}?c=patches">patches</a></td>+    </tr>+  </xsl:template>++  <xsl:template match="directory/file/modified/modified_how">+    <xsl:variable name="file" select="../../@name"/>+    <xsl:variable name="hash" select="../patch/@hash" />+    <xsl:variable name="how" select="substring(text(), 0, 11)"/>+    +    <tr class="add-remove-file">+      <td><xsl:value-of select="$file"/></td>+      <td>+        <xsl:choose>+          <xsl:when test="$how = 'File added'">added file</xsl:when>+          <xsl:when test="$how = 'File moved'">moved file</xsl:when>+          <xsl:when test="$how = 'File remov'">removed file</xsl:when>+        </xsl:choose>+      </td>+      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>+      <td><a href="{$command}{$file}?c=patches">patches</a></td>+    </tr>+  </xsl:template>+   +  <!-- file annotate templates -->+  <xsl:template match="/darcs/file">+    <xsl:variable name="modified_how" select="modified/modified_how/text()"/>+    +    <xsl:call-template name="show-patch-info">+      <xsl:with-param name="patch" select="modified/patch"/>+    </xsl:call-template>++    <!-- don't display table of changes when file's contents are modified -->+    <xsl:if test="$modified_how != 'File modified'">+      <xsl:variable name="file" select="@name"/>+      <xsl:variable name="how" select="substring($modified_how, 0, 11)"/>++      <xsl:variable name="annotate-href">+        <xsl:call-template name="make-annotate-href">+          <xsl:with-param name="hash" select="modified/patch/@hash"/>+        </xsl:call-template>+      </xsl:variable>+      +      <table>+        <tr class="annotate">+          <th>file</th>+          <th>change</th>+          <th></th>+          <th></th>+        </tr>++        <tr class="add-remove-file">+          <td><xsl:value-of select="$file"/></td>+          <td>+            <xsl:choose>+              <xsl:when test="$how = 'File added'">added file</xsl:when>+              <xsl:when test="$how = 'File moved'">moved file</xsl:when>+              <xsl:when test="$how = 'File remov'">removed file</xsl:when>+            </xsl:choose>+          </td>+          <td><a href="{$annotate-href}">annotate</a></td>+          <td><a href="{$command}?c=patches">patches</a></td>+        </tr>+      </table>+    </xsl:if>++    <!-- the empty <p/> element is a Konqueror bug workaround -->+    <pre xml:space="preserve"><p/>+      <xsl:apply-templates/>+    </pre>+  </xsl:template>+  +  <xsl:template match="added_line">+    <xsl:variable name="annotate-href">+      <xsl:call-template name="make-annotate-href">+        <xsl:with-param name="hash" select="preceding::modified/patch/@hash"/>+      </xsl:call-template>+    </xsl:variable>++    <xsl:variable name="annotate-name" select="preceding::modified/patch/name"/>+    <xsl:variable name="author" select="preceding::modified/patch/@author"/>+    +    <a class="added-line" href="{$annotate-href}" title="added with '{$annotate-name}' by '{$author}'">+      <pre><xsl:value-of select="text()"/></pre>+    </a>+    <xsl:call-template name="check-removed-by"/>+  </xsl:template>++  <xsl:template match="normal_line">+    <xsl:variable name="annotate-href">+      <xsl:call-template name="make-annotate-href">+        <xsl:with-param name="hash" select="*/patch/@hash"/>+      </xsl:call-template>+    </xsl:variable>++    <xsl:variable name="annotate-name" select="*/patch/name"/>+    <xsl:variable name="author" select="*/patch/@author"/>++    <a class="normal-line" href="{$annotate-href}" title="last changed with '{$annotate-name}' by '{$author}'">+      <pre><xsl:value-of select="text()"/></pre>+    </a>+    <xsl:call-template name="check-removed-by"/>+  </xsl:template>++  <xsl:template match="removed_line">+    <xsl:variable name="annotate-href">+      <xsl:call-template name="make-annotate-href">+        <xsl:with-param name="hash" select="*/patch/@hash"/>+      </xsl:call-template>+    </xsl:variable>++    <xsl:variable name="annotate-name" select="*/patch/name"/>+    <xsl:variable name="author" select="*/patch/@author"/>+    +    <!-- don't display removed lines when a file is removed -->+    <xsl:if test="../modified/modified_how/text() != 'File removed'">+      +        <a class="removed-line" href="{$annotate-href}" title="removed with '{$annotate-name}' by '{$author}'">+        <pre><xsl:value-of select="text()"/></pre>+      </a>+      <xsl:call-template name="check-removed-by"/>+    </xsl:if>+  </xsl:template>++  <xsl:template name="check-removed-by">+    <xsl:variable name="hash" select="removed_by/patch/@hash"/>+    +    <xsl:variable name="annotate-href">+      <xsl:call-template name="make-annotate-href">+        <xsl:with-param name="hash" select="$hash"/>+      </xsl:call-template>+    </xsl:variable>+    +    <xsl:choose>+      <xsl:when test="$hash != ''">+        <a class="removed-by" href="{$annotate-href}">-</a>+      </xsl:when>+    </xsl:choose>++    <!-- put a newline after the hyperlink -->      +    <xsl:text xml:space="preserve">+    </xsl:text>+  </xsl:template>++  <xsl:template name="show-patch-info">+    <xsl:param name="patch"/>+    <xsl:param name="show-comment"/>+    <xsl:param name="show-author"/>+    <xsl:param name="show-date"/>+    +    <xsl:variable name="hash" select="$patch/@hash"/>+    <xsl:variable name="name" select="$patch/name"/>+    <xsl:variable name="author" select="$patch/@author"/>+    <xsl:variable name="local_date" select="$patch/@local_date"/>+    +    <h2 class="patch">+      patch "<span class="path">+      <a href="{$cgi-program}/{$repo}/?c=annotate&amp;p={$hash}">+        <xsl:value-of select="$name"/>+      </a>+      </span>"+    </h2>++    <xsl:if test="$show-comment">+        <xsl:if test="$patch/comment">+          <h2 class="patch">+            comment "<span class="comment">+            <xsl:value-of select="$patch/comment"/>+            </span>"+            </h2>+        </xsl:if>+        </xsl:if>++      <xsl:if test="$show-author"> +          <h2 class="author">+        by <span class="author">+        <xsl:value-of select="$patch/@author"/>+        </span>++      <xsl:if test="$show-date"> +        on <span class="local_date">+        <xsl:value-of select="$patch/@local_date"/>+        </span>+    </xsl:if>+    </h2>+    </xsl:if>++  </xsl:template>++  <xsl:template name="make-annotate-href" xml:space="default">+    <xsl:param name="hash"/>++    <xsl:variable name="created-as" select="/darcs/*/created_as"/>+    <xsl:variable name="creator-hash" select="$created-as/patch/@hash"/>+    <xsl:variable name="original-name" select="$created-as/@original_name"/>+    +    <xsl:value-of select="$command"/>?c=annotate&amp;p=<xsl:value-of select="$hash"/>&amp;ch=<xsl:value-of select="$creator-hash"/>&amp;o=<xsl:value-of select="$original-name"/>+  </xsl:template>++  <!-- ignore <name>, <comment> and <modified_how> children -->+  <xsl:template match="name"/>+  <xsl:template match="comment"/>+  <xsl:template match="author"/>+  <xsl:template match="modified_how"/>+</xsl:stylesheet>
+ tools/cgi/xslt/browse.xslt view
@@ -0,0 +1,110 @@+<?xml version="1.0" encoding="utf-8"?>++<!--+ template for converting a darcs current/ directory listing from XML to+ XHTML.  This template expects the following external variables:++   cgi-program    - path to the CGI executable, to place in links+   sort-by        - field to sort by+   stylesheet     - path to the CSS stylesheet++ the input XML must have the following structure, aside from what common.xslt+ expects:++ <files>+   <directory name="" modified=""/>+   <file name="" modified=""/>+ </files>+-->+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">+  <xsl:include href="common.xslt"/>++  <xsl:template match="path">+    <h1 class="target">+      files in <span class="path"><a href="{$cgi-program}">projects</a></span> / <span class="path"><xsl:apply-templates/></span>+    </h1>+  </xsl:template>+  +  <xsl:template match="files">+    <table>+      <tr class="browse">+        <th>+          <a class="sort" href="{$command}?c=browse&amp;s=name">name</a>+          <a class="revsort" href="{$command}?c=browse&amp;s=revname"> (rev)</a>+        </th>+        <th>+          <a class="sort" href="{$command}?c=browse&amp;s=ts">modified</a>+          <a class="revsort" href="{$command}?c=browse&amp;s=revts"> (rev)</a>+        </th>+        <th></th>+        <th></th>+      </tr>+      +      <xsl:choose>+        <xsl:when test="$sort-by = 'ts'">+          <xsl:apply-templates>+            <xsl:sort select="name(self::node())"/>+            <xsl:sort select="@ts"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:when test="$sort-by = 'revts'">+          <xsl:apply-templates>+            <xsl:sort select="name(self::node())"/>+            <xsl:sort select="@ts" order="descending"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:when test="$sort-by = 'name'">+          <xsl:apply-templates>+            <xsl:sort select="name(self::node())"/>+            <xsl:sort select="@name"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:when test="$sort-by = 'revname'">+          <xsl:apply-templates>+            <xsl:sort select="name(self::node())"/>+            <xsl:sort select="@name" order="descending"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:otherwise>+          <xsl:apply-templates>+            <xsl:sort select="name(self::node())"/>+            <xsl:sort select="@name"/>+          </xsl:apply-templates>+        </xsl:otherwise>+      </xsl:choose>+    </table>+  </xsl:template>+  +  <xsl:template match="directory">+    <xsl:variable name="name" select="@name"/>+    <xsl:variable name="type" select="@type"/>+    +    <tr class="directory">+      <td>+        <a href="{$command}{$name}?c=browse"><xsl:value-of select="@name"/></a>+      </td>+      <td><xsl:value-of select="@modified"/></td>+      <td>+        <a href="{$command}{$name}?c=annotate">annotate</a>+      </td>+      <td>+        <a href="{$command}{$name}?c=patches">patches</a>+      </td>+    </tr>++    <xsl:apply-templates/>+  </xsl:template>++  <xsl:template match="file">+    <xsl:variable name="name" select="@name"/>+    +    <tr class="file">+      <td><xsl:value-of select="@name"/></td>+      <td><xsl:value-of select="@modified"/></td>+      <td><a href="{$command}{$name}?c=annotate">annotate</a></td>+      <td><a href="{$command}{$name}?c=patches">patches</a></td>+    </tr>++    <xsl:apply-templates/>+  </xsl:template>+</xsl:stylesheet>
+ tools/cgi/xslt/common.xslt view
@@ -0,0 +1,66 @@+<!--+ templates fragments shared by all templates.  This template expects+ the following external variables:++   cgi-program    - path to the CGI executable, to place in links+   stylesheet     - path to the CSS stylesheet++ the input XML must have the following structure, plus any elements+ that are not common to all templates:++ <darcs repository="">+   <path>+     <element full-path=""></element>+   </path>++   ...+ + </darcs>+-->+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">+  <xsl:variable name="command">+    <xsl:value-of select="$cgi-program"/>/<xsl:value-of select="/darcs/@target"/>+  </xsl:variable>++  <xsl:variable name="repo" select="/darcs/@repository"/>+  +  <xsl:template match="/darcs">+    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">+      <head>+        <title>darcs repository</title>+        <link rel="stylesheet" href="{$stylesheet}"/>+        <link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="{$command}?c=rss" />+      </head>++      <body>+        <xsl:apply-templates/>++        <form action="{$command}" method="get">+          <p>+            <input class="patches" type="submit" name="c" value="patches"/>+            +            <a href="{$command}?c=rss">rss</a>+            +            <span class="version">+              <a class="home" href="http://darcs.net/">darcs.cgi</a>+              v1.0+            </span>+          </p>+        </form>+      </body>+    </html>+  </xsl:template>++  <xsl:template match="path/directory">+    <xsl:variable name="full-path"  select="@full-path"/>+    +    <a href="{$cgi-program}{$full-path}?c=browse">+      <xsl:apply-templates/>+    </a> /+  </xsl:template>++  <xsl:template match="path/file">+    <xsl:apply-templates/>+  </xsl:template>+  +</xsl:stylesheet>
+ tools/cgi/xslt/errors.xml view
@@ -0,0 +1,22 @@+<!--+  HTML templates for all potential error pages.  Each <error> element+  should contain all of the HTML <body> content to be output if that+  error occurs+-->+<errors>+  <error type="invalid-command" title="Invalid command">+    <h1>Invalid command</h1>++    <p>+      The requested command is invalid.+    </p>+  </error>++  <error type="invalid-repository" title="Invalid repository">+    <h1>Invalid repository</h1>++    <p>+      The requested repository does not exist on this server.+    </p>+  </error>+</errors>
+ tools/cgi/xslt/errors.xslt view
@@ -0,0 +1,36 @@+<?xml version="1.0" encoding="utf-8"?>++<!--+ template for converting selected content of errors.xml XML to XHTML. This+ template expects the following external variables:++   error-type     - the type of error+   stylesheet     - path to the CSS stylesheet++ the input XML must have the following structure++ <errors>+   <error type="" title="">+     ...+   </error>+ </errors>+-->+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">+  <xsl:template match="error[@type = $error-type]">+    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">+      <head>+        <title>+          <xsl:value-of select="@title"/>+        </title>+        <link rel="stylesheet" href="{$stylesheet}"/>+      </head>++      <body>+        <xsl:copy-of select="*"/>+      </body>+    </html>+  </xsl:template>++  <!-- ignore errors that don't match -->+  <xsl:template match="error"/>+</xsl:stylesheet>
+ tools/cgi/xslt/patches.xslt view
@@ -0,0 +1,125 @@+<?xml version="1.0" encoding="utf-8"?>++<!--+ template for converting darcs' `changes` output from XML to XHTML.  This+ template expects the following external variables:++   cgi-program    - path to the CGI executable, to place in links+   sort-by        - field to sort by+   stylesheet     - path to the CSS stylesheet++ the input XML must have the following structure, aside from what common.xslt+ expects:++ <changelog>+   <patch author="" date="" localdate="" inverted="" hash="">+     <name></name>+   </patch>+ </changelog>+-->+<xsl:stylesheet version="1.0"+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"+                xmlns:str="http://exslt.org/strings">+  +  <xsl:include href="common.xslt"/>++  <xsl:template match="path">+    <h1 class="target">+      patches applied to <span class="path"><a href="{$cgi-program}">projects</a></span> / <span class="path"><xsl:apply-templates/></span>+    </h1>+  </xsl:template>+  +  +  <xsl:template match="changelog">+    <table>+      <tr class="patches">+        <th>+          <a class="sort" href="{$command}?c=patches&amp;s=name">name</a>+          <a class="revsort" href="{$command}?c=patches&amp;s=revname"> (rev)</a>+        </th>+        <th>+          <a class="sort" href="{$command}?c=patches&amp;s=date">date</a>+          <a class="revsort" href="{$command}?c=patches&amp;s=revdate"> (rev)</a>+        </th>+        <th>+          <a class="sort" href="{$command}?c=patches&amp;s=author">author</a>+          <a class="revsort" href="{$command}?c=patches&amp;s=revauthor"> (rev)</a>+        </th>+        <th>+        </th>+      </tr>++      <xsl:choose>+        <xsl:when test="$sort-by = 'name'">+          <xsl:apply-templates>+            <xsl:sort select="name"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:when test="$sort-by = 'revname'">+          <xsl:apply-templates>+            <xsl:sort select="name" order="descending"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:when test="$sort-by = 'date'">+          <xsl:apply-templates>+            <xsl:sort select="@date"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:when test="$sort-by = 'revdate'">+          <xsl:apply-templates>+            <xsl:sort select="@date" order="descending"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:when test="$sort-by = 'author'">+          <xsl:apply-templates>+            <xsl:sort select="@author"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:when test="$sort-by = 'revauthor'">+          <xsl:apply-templates>+            <xsl:sort select="@author" order="descending"/>+          </xsl:apply-templates>+        </xsl:when>+        <xsl:otherwise>+          <!-- use the repository's natural order -->+          <xsl:apply-templates/>+        </xsl:otherwise>+      </xsl:choose>+    </table>+  </xsl:template>++  <xsl:template match="patch">+    <xsl:variable name="author" select="@author"/>+    <xsl:variable name="hash"   select="@hash"/>+    <xsl:variable name="name"   select="name"/>+    <xsl:variable name="repo"   select="/darcs/@repository"/>++    <xsl:variable name="created-as" select="/darcs/changelog/created_as"/>+    <xsl:variable name="creator-hash" select="$created-as/patch/@hash"/>+    <xsl:variable name="original-name" select="$created-as/@original_name"/>++    <xsl:variable name="annotate-href">+      <xsl:value-of select="$command"/>?c=annotate&amp;p=<xsl:value-of select="$hash"/>++      <xsl:if test="$creator-hash">&amp;ch=<xsl:value-of select="$creator-hash"/></xsl:if>+      <xsl:if test="$original-name">&amp;o=<xsl:value-of select="$original-name"/></xsl:if>+    </xsl:variable>+    +    <tr class="patch">+      <td><a href="{$annotate-href}"><xsl:value-of select="name"/></a></td>+      <td><xsl:value-of select="@local_date"/></td>+      <td>+        <a href="mailto:{$author}"><xsl:value-of select="$author"/></a>+      </td>+      <td>+        <a href="{$cgi-program}/{$repo}/?c=annotate&amp;p={$hash}">detail</a>+      </td>+    </tr>+    <xsl:apply-templates/>+  </xsl:template>++  <!-- ignore <created_as>, <name> and <comment> children of <patch> -->+  <xsl:template match="created_as"/>+  <xsl:template match="name"/>+  <xsl:template match="comment"/>+</xsl:stylesheet>
+ tools/cgi/xslt/repos.xslt view
@@ -0,0 +1,59 @@+<?xml version="1.0" encoding="utf-8"?>++<!--+ template for displaying a list of available repositories, used when a+ CGI request has no repository path information.  This template expects+ the following external variables:++   cgi-program    - path to the CGI executable, to place in links+   stylesheet     - path to the CSS stylesheet++ the input XML must have the following structure:++ <darcs repository="">+   <repositories>+     <repository name=""/>+   </repositories>+ </darcs>+-->+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">+  <xsl:variable name="command">+    <xsl:value-of select="$cgi-program"/>/<xsl:value-of select="/darcs/@target"/>+  </xsl:variable>+  +  <xsl:template match="/darcs">+    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">+      <head>+        <title>darcs repository viewer</title>+        <link rel="stylesheet" href="{$stylesheet}"/>+      </head>++      <body>+        <h1 class="target">Available Repositories</h1>++        <table>+          <xsl:apply-templates/>+        </table>+      </body>+    </html>+  </xsl:template>++  <xsl:template match="repositories">+    <xsl:apply-templates>+      <xsl:sort select="name(self::node())"/>+      <xsl:sort select="@name"/>+    </xsl:apply-templates>+  </xsl:template>++  <xsl:template match="repositories/repository">+    <xsl:variable name="repository"  select="@name"/>++    <tr>+      <td>+        <a href="{$cgi-program}/{$repository}/?c=browse">+          <xsl:value-of select="$repository"/>+        </a>+      </td>+    </tr>+  </xsl:template>+</xsl:stylesheet>
+ tools/cgi/xslt/rss.xslt view
@@ -0,0 +1,92 @@+<?xml version="1.0" encoding="utf-8"?>++<!--+ template for converting darcs' `changes` output from XML to RSS.  This+ template expects the following external variables:++   cgi-url    - full URL to the CGI executable, to place in links++ the input XML must have the following structure:++ <darcs repository="">+   <changelog>+     <patch author="" date="" localdate="" inverted="" hash="">+       <name></name>+       <comment></comment>+     </patch>+   </changelog>+ </darcs>+-->+<xsl:stylesheet version="1.0"+                exclude-result-prefixes="str"+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"+                xmlns:str="http://exslt.org/strings">++  <xsl:variable name="repo" select="/darcs/@repository"/>++  <xsl:variable name="command">+    <xsl:value-of select="$cgi-url"/>/<xsl:value-of select="/darcs/@target"/>+  </xsl:variable>++  <xsl:template match="changelog">+    <rss version="2.0">+      <channel>+        <title>changes to <xsl:value-of select="$repo"/></title>+        <link><xsl:value-of select="$command"/></link>+        <description>+          Recent patches applied to the darcs repository named+          "<xsl:value-of select='$repo'/>".+        </description>++        <xsl:apply-templates>+          <xsl:sort select="@date"/>+        </xsl:apply-templates>+      </channel>+    </rss>+  </xsl:template>++  <xsl:template match="patch">+    <xsl:variable name="hash"       select="@hash"/>++    <xsl:variable name="created-as" select="/darcs/changelog/created_as"/>+    <xsl:variable name="creator-hash" select="$created-as/patch/@hash"/>+    <xsl:variable name="original-name" select="$created-as/@original_name"/>++    <xsl:variable name="annotate-href">+      <xsl:value-of select="$command"/>?c=annotate&amp;p=<xsl:value-of select="$hash"/>++      <xsl:if test="$creator-hash">&amp;ch=<xsl:value-of select="$creator-hash"/></xsl:if>+      <xsl:if test="$original-name">&amp;o=<xsl:value-of select="$original-name"/></xsl:if>+    </xsl:variable>++    <xsl:variable name="date-nodes" select="str:tokenize(@local_date, ' ')"/>+    <xsl:variable name="rfc-date">+      <xsl:value-of select="$date-nodes[1]"/>+      <xsl:value-of select="', '"/>+      <xsl:if test="$date-nodes[3] &lt; 10">0</xsl:if>+      <xsl:value-of select="$date-nodes[3]"/>+      <xsl:value-of select="' '"/>+      <xsl:value-of select="$date-nodes[2]"/>+      <xsl:value-of select="' '"/>+      <xsl:value-of select="$date-nodes[6]"/>+      <xsl:value-of select="' '"/>+      <xsl:value-of select="$date-nodes[4]"/>+      <xsl:value-of select="' '"/>+      <xsl:value-of select="$date-nodes[5]"/>+    </xsl:variable>++    <item>+      <title><xsl:value-of select="name"/></title>+      <link><xsl:value-of select="$annotate-href"/></link>+      <author><xsl:value-of select="@author"/></author>+      <description><xsl:value-of select="comment"/></description>+      <pubDate><xsl:value-of select="$rfc-date"/></pubDate>+    </item>+  </xsl:template>++  <!-- ignore <path> <created_as>, <name> and <comment> children of <patch> -->+  <xsl:template match="path"/>+  <xsl:template match="created_as"/>+  <xsl:template match="name"/>+  <xsl:template match="comment"/>+</xsl:stylesheet>
+ tools/cgi/xslt/styles.css view
@@ -0,0 +1,91 @@+/**+ stylesheet for darcs repository browser+**/++a:link, a:visited {+  color: blue;+  text-decoration: none;+}++a:hover { text-decoration: underline; }+a.sort  { color: black; }+a.revsort  { +  color: black;+  font-size: 75%;+}+a.home  { color: #9292C9; }++body { margin: 10px 10px 10px 10px; }++h1.target {+  font-size: 150%;+  font-weight: bold;+}++h2.patch {+  font-size: 125%;+  font-weight: bold;+  margin-top: -10px;+  padding-left: 10px;+}++h2.author {+  font-size: smaller;+  margin-top: -10px;+  font-weight: bold;+  padding-left: 30px;+}++input.patches {  margin-right: 20px; }+label.tag     {  margin-right: 5px; }++span.path, span.path > a { color: #2A2A6B; }++span.version {+  color: #9292C9;  +  margin-left: 75px;+}++span.comment {+  color: #2A2A6B;+  white-space: pre;+}++th,td {+  text-align: left;+  padding: 5px 10px 5px 10px;  +}++tr.annotate { background-color: #FFAAAA; }+tr.browse { background-color: #FFFF99; }+tr.patches { background-color: #AAFFAA; }+tr.directory { background-color: #CFCFCF; }+tr.file, tr.patch, tr.modified-file { background-color: #DCDCDA; }+tr.modified-file, tr.add-remove-file { background-color: #DCDCDA; }++pre {+    margin: 0 0 0 0;+}++a.added-line {+    color: #00AA00;+    float: left;+}++a.normal-line {+    color: #000000;+    float: left;+}++a.removed-line {+    color: #CC0000;+    float: left;+    text-decoration: line-through;+}++a.removed-by {+    clear: right;+    color: #CC0000;+    float: right;+    font-size: 125%;+}
+ tools/cygwin-wrapper.bash view
@@ -0,0 +1,263 @@+#! /bin/bash++DIRNAME=`dirname "${0}"`+if [ "${DIRNAME:0:1}" = "/" ] ; then+ DARCSPACKAGEDIR="${DIRNAME}"+else+ DARCSPACKAGEDIR="${PWD}/${DIRNAME}"+fi++# If the DARCSPACKAGEDIR assignment above doesn't work for some funny reason, +# you could set these variables by hand.  Or fix the script to work +# automatically and submit a patch.++# Should be set to the full Cygwin path to the directory containing the +# putty executables.+putty_binary_dir="${DARCSPACKAGEDIR}"+# Should be set to the full Cygwin path to the directory containing the +# Windows binary "darcs.exe".+darcs_binary_dir="$putty_binary_dir"+# Should be set to the full Cygwin path to the Windows binary+# "darcs.exe".+darcs_binary="${darcs_binary_dir}/realdarcs.exe"++#---------------------------------------------------------------------+# Darcs Wrapper for Cygwin+#+# A Bash script that allows Cywin paths on the command line when using+# a version of Darcs compiled for Windows.  Darcs will still use still+# Windows paths internally.+#+#---------------------------------------------------------------------+# Usage+# +# Edit this file and set the variables above.  Then, rename this +# script to "darcs" and put it in your PATH somewhere before the +# original binary.+#+# Darcs needs to launch itself for some operations and so the original+# binary needs to be in your Windows PATH.  Do not rename it.+#+#---------------------------------------------------------------------+# Known Issues+#+# This script is just a stopgap measure.  Things don't work perfectly.+# We really need a Cygwin build of Darcs.+#+# No path conversion is performed on:+#    - Any preferences set with "setpref"+#    - The "COMMAND" argument to "darcs trackdown"+#+# When Darcs launches external programs, it uses a Windows system call+# to do so.  This means you may not be able to run "hash bang" scripts+# directly.  For example, to run the Bash script "myscript", you'll+# have to tell Darcs to run "bash myscript".+#+# --------------------------------------------------------------------+++PATH="$putty_binary_dir:$darcs_binary_dir:${PATH}"++debug=false++cmd="$1"++# Print each argument to stderr on a separate line.  Then exit.+function die() {+   local line+   for line in "$@"; do+      echo "$line" > /dev/stderr+   done+   exit 2+}++# Make sure 'darcs_binary_dir' is set.+if [ ! -d "$darcs_binary_dir" ]; then+   die "Please edit this script and set the 'darcs_binary_dir' variable" \+       "to refer to a valid directory." \+       "      script path = '$0'"  \+       "     darcs_binary_dir = '$darcs_binary_dir'"+fi++# Special case for when the first argument is an option.+if expr match "$cmd" '-' > /dev/null; then+   if $debug; then+      # echo "SIMPLE CASE:"+      for arg in "$@"; do+         echo "  arg = '$arg'"+      done+   else+      # echo about to exec -a darcs "$darcs_binary" "$@"+      exec -a darcs "$darcs_binary" "$@"+   fi+fi++# Shift off the darcs command name+shift++function is_opaque_opt() {+   local opt+   for opt in "${opaque_binary_opts[@]}"; do+      if [ "$opt" == "$1" ]; then+         return 0+      fi+   done+   return 1+}++function is_file_opt() {+   local opt+   for opt in "${file_binary_opts[@]}"; do+      if [ "$opt" == "$1" ]; then+         return 0+      fi+   done+   return 1+}++# Options are not dealt with in a command-specific way.  AFAIK, Darcs+# doesn't use the same option in two different ways, so we should be+# fine.++# List of "opaque" binary options.  These are options where we don't+# treat the option argument like a file.+declare -a opaque_binary_opts=( \+   '--repo-name' \+   '--to-match' '--to-patch' '--to-tag' \+   '--from-match' '--from-patch' '--from-tag' \+   '-t' '--tag' '--tags' '--tag-name' \+   '-p' '--patch' '--patches' \+   '-m' '--patch-name' \+   '--matches' '--match' \+   '--token-chars' \+   '-A' '--author' '--from' '--to' '--cc' \+   '--sign-as' '--creator-hash' \+   '--last' '--diff-opts' \+   '-d' '--dist-name' \+   '--log-file' \+   '--apply-as' \+   )++# List of binary options that take file arguments that need to be converted.+declare -a file_binary_opts=( \+   '--repodir' '--repo' '--sibling' \+   '--context' \+   '--logfile' '-o' '--output' \+   '--external-merge' \+   '--sign-ssl' '--verify' '--verify-ssl' \+   )++# --------------------------------------------------------------------+# The three command categories.  We only use the first one, but the+# others are listed to make sure we've covered everything.  Luckily,+# there aren't any commands that have some args that need to be+# converted and some that don't.++# Commands whose arguments are file paths that need to be translated.+cmds_convert_nonoption_args='|get|put|pull|push|send|apply'++# Commands who's arguments should be left alone.  File paths that+# refer to files in the repo should NOT be converted because they+# are relative paths, which Darcs will handle just fine.  Cygwin+# sometimes makes them absolute paths, which confuses Darcs.+#cmds_no_convert_nonoption_paths='|add|remove|mv|replace|record|whatsnew|changes|setpref|trackdown|amend-record|revert|diff|annotate'++# Commands that don't accept non-option arguments+#cmds_no_nonoption_args='|initialize|tag|check|optimize|rollback|unrecord|unpull|resolve|dist|repair'++# See if we need to convert the non-option args for the current+# command.  This matches some prefix of one of the commands in the+# list.  The match may not be unambiguous, we can rely on Darcs to+# deal with that correctly.+if expr match "$cmds_convert_nonoption_args" ".*|$cmd" > /dev/null; then+   convert_nonoption_args=true+else+   convert_nonoption_args=false+fi++function convert_path() {+   # echo "converting path ${*} ..." >> /tmp/log+   if expr match "$1" '[-@._A-Za-z0-9]*:' > /dev/null; then+      # Some sort of URL or remote ssh pathname ("xxx:/")+      echo "$1"+      # echo "converting path ${*} ... to ${1}" >> /tmp/log+   elif [ "$1" == '.' ]; then+      # Compensate for stupid 'cygpath' behavior.+      echo '.'+      # echo "converting path ${*} ... to ." >> /tmp/log+   else+      cygpath -wl -- "$1"+      # echo "converting path ${*} ... to `cygpath -wl -- ${1}`" >> /tmp/log+   fi+}++declare -a params=("$cmd")++num_nonoption_args=0++while [ $# -gt 0 ]; do+   arg=$1+   shift+   if expr match "$arg" '-' > /dev/null; then+      # It's an option.  Check to see if it's an opaque binary option.++      if expr match "$arg" '.*=' > /dev/null; then+         # The option has an '=' in it.+         opt=`expr match "$arg" '\([^=]*\)'`+         opt_arg=`expr match "$arg" '[^=]*=\(.*\)'`+         if is_opaque_opt "$opt"; then+            true;+         elif is_file_opt "$opt"; then+            opt_arg=`convert_path "$opt_arg"`+         else+            die "darcs-wrapper: I don't think '$opt' accepts an argument." \+                "[ If it does, then there is a bug in the wrapper script. ]"+         fi+         params[${#params[*]}]="$opt=$opt_arg"++      else+         # The option doesn't have an '='+         opt="$arg"+         if is_opaque_opt "$opt"; then+            if [ $# -eq 0 ]; then+               die "darcs-wrapper: I think '$arg' requires an argument." \+                   "[ If it doesn't, then there is a bug in the wrapper script. ]"+            fi+            opt_arg="$1"+            shift+            params[${#params[*]}]="$opt"+            params[${#params[*]}]="$opt_arg"+         elif is_file_opt "$opt"; then+            if [ $# -eq 0 ]; then+               die "darcs-wrapper: I think '$arg' requires an argument." \+                   "[ If it doesn't, then there is a bug in the wrapper script. ]"+            fi+            opt_arg=`convert_path "$1"`+            shift+            params[${#params[*]}]="$opt"+            params[${#params[*]}]="$opt_arg"+         else+            params[${#params[*]}]="$opt"+         fi+      fi++   else+      if $convert_nonoption_args; then+         arg=`convert_path "$arg"`+      fi+      params[${#params[*]}]="$arg"+      (( num_nonoption_args += 1 ))+   fi+done++# DEBUG+if $debug; then+   echo "ARGS:"+   for arg in "${params[@]}"; do+      echo "  arg = '$arg'"+   done+else+   # echo about to exec -a darcs "$darcs_binary" "${params[@]}"+   exec -a darcs "$darcs_binary" "${params[@]}"+fi+
+ tools/darcs_completion view
@@ -0,0 +1,52 @@+#-*- mode: shell-script;-*-++# darcs command line completion.+# Copyright 2002 "David Roundy" <droundy@abridgegame.org>+#+have darcs &&+_darcs()+{+    local cur+    cur=${COMP_WORDS[COMP_CWORD]}++    COMPREPLY=()++    if (($COMP_CWORD == 1)); then+        COMPREPLY=( $( darcs --commands | grep "^$cur" ) )+        return 0+    fi++    local IFS=$'\n' # So that the following "command-output to array" operation splits only at newlines, not at each space, tab or newline.+    COMPREPLY=( $( darcs ${COMP_WORDS[1]} --list-option | grep "^${cur//./\\.}") )++	# Then, we adapt the resulting strings to be reusable by bash. If we don't+	# do this, in the case where we have two repositories named+	# ~/space in there-0.1 and ~/space in there-0.2, the first completion will+	# give us:+	# bash> darcs push ~/space in there-0.+	# ~/space in there-0.1 ~/space in there-0.2+	# and we have introduced two spaces in the command line (if we try to+	# recomplete that, it won't find anything, as it doesn't know anything+	# starting with "there-0.").+	# printf %q will gracefully add the necessary backslashes.+	#+	# Bash also interprets colon as a separator. If we didn't handle it+	# specially, completing http://example.org/repo from http://e would +	# give us:+	# bash> darcs pull http:http://example.org/repo+	# An option would be to require the user to escape : as \: and we+	# would do the same here. Instead, we return only the part after+	# the last colon that is already there, and thus fool bash. The+	# downside is that bash only shows this part to the user.+    local i=${#COMPREPLY[*]}+    local colonprefixes=${cur%"${cur##*:}"}+    while [ $((--i)) -ge 0 ]; do+      COMPREPLY[$i]=`printf %q "${COMPREPLY[$i]}"`++      COMPREPLY[$i]=${COMPREPLY[$i]#"$colonprefixes"} +    done+    return 0++}+[ "$have" ] && complete -F _darcs -o default darcs+
+ tools/update_roundup.pl view
@@ -0,0 +1,78 @@+#!/usr/bin/perl++use strict;+use warnings;++# A script to update the status of an issue in a Roundup bug tracker+# based on the format of a darcs patch name.+# It is intended to be run from a darcs posthook.++# The format we look for is:+#   resolved issue123 +# in the first line of the patch. ++use Getopt::Long;++use MIME::Lite;+use XML::Simple;++unless ($ENV{DARCS_PATCHES_XML}) {+    die "DARCS_PATCHES_XML was expected to be set in the environment, but was not found. +          Are you running this from a Darcs 2.0 or newer posthook?"+}++my $xml = eval { XMLin($ENV{DARCS_PATCHES_XML}); };+die "hmmm.. we couldn't parse your XML. The error was: $@"  if $@;++# $xml structure returned looks like this: +#  'patch' => {+#    'resolved issue123: adding t.t' => {+#        'hash' => '20080215033723-20bb4-54f935f89817985a3e98f3de8e8ac9dad5e8e0e5.gz',+#        'inverted' => 'False',+#        'date' => '20080215033723',+#        'author' => 'Mark Stosberg <mark@summersault.com>',+#        'local_date' => 'Thu Feb 14 22:37:23 EST 2008'+#        },+#     'some other patch' => { ... }, ++for my $patch_name (keys %{ $xml->{patch} }) {+    my $issue_re = qr/resolved? \s+ (issue\d+)/msxi;++    next unless ($patch_name =~ $issue_re);+    my $issue = $1;+    my $patch = $xml->{patch}{$patch_name};++    # Using the Command Line would be a simpler alternative. +    # my $out = `roundup-admin -i /var/lib/roundup/trackers/darcs set $issue status=resolved-in-unstable`;+    # warn "unexpected output: $out" if $out;++    my $author = $patch->{author};+    # If the Author name contains an @ sign, we take it to be an e-mail address.+    # Otherwise, we default to darcs-devel as the sender. +    my $email = ($author =~ m/\@/) ? $author : 'darcs-devel@darcs.net';++    my $comment = $patch->{comment} ? "\n$patch->{comment}" : '';++    my $patch_name_minus_status = $patch_name; +    $patch_name_minus_status =~ s/$issue_re(:?\s?)//;++     # Each patches can potentially update the status of a different issue, so generates a different e-mail+    my $msg = MIME::Lite->new(+         From     => $email, +         To      =>'bugs@darcs.net',+         #To       =>'mark@stosberg.com',+         Subject  =>"[$issue] $patch_name_minus_status [status=resolved-in-unstable]",+         Type     =>'text/plain',+         Data     => qq!The following patch updated the status of $issue to be resolved:++* $patch_name $comment++!+     );+     $msg->send;+     # An alternative to actually sending, for debugging. +     # use File::Slurp;+     # write_file("msg-$patch->{hash}.out",$msg->as_string);+}++
+ tools/upload.cgi view
@@ -0,0 +1,72 @@+#!/usr/bin/perl++use strict;+use Fcntl;++# this is a sample cgi script to accept darcs patches via POST+# it simply takes patches and places them in a Maildir style+# mailbox.++# set this to the maildir you wish patches to be sent to.+my $maildir = "/tmp/maildir";++sub error_page {+    my ($m) = @_;+    print "Status: 500 Error accepting patch\n";+    print "Content-Type: text/plain\n\n";+    print($m || "There was an error processing your request");+    print "\n";+    exit 0;+}++sub success_page {+    print "Content-Type: text/plain\n\n";+    print "Thank you for your contribution!\n";+    exit 0;+}+++if($ENV{CONTENT_TYPE} eq 'message/rfc822') {+        my $m = start_message($maildir) or error_page("could not open maildir: $maildir");+        my $fh = $m->{fh};+        my ($totalbytes,$bytesread,$buffer);+        do {+            $bytesread=read(STDIN,$buffer,1024);+            print $fh $buffer;+            $totalbytes += $bytesread;+        } while($bytesread);+        my $r = end_message($m);+        $r ? error_page($r) : success_page();+} elsif($ENV{CONTENT_TYPE}) {+    error_page("invalid content type, I expect something of message/rfc822");+} else {+    error_page("This url is for accepting darcs patches");+}++++sub temp_file {+    my ($temp_dir) = @_;+    my $base_name = sprintf("patch-%d-%d-0000", $temp_dir, $$, time());+    local *FH;+    my $count = 0;+    until (defined(fileno(FH)) || $count++ > 100) {+        $base_name =~ s/-(\d+)$/"-" . (1 + $1)/e;+        sysopen(FH, "$temp_dir/$base_name", O_WRONLY|O_EXCL|O_CREAT);+    }+    defined(fileno(FH)) ? return (*FH, $base_name) : return ();+}++sub start_message {+    my ($maildir) = @_;+    my ($fh,$fname) = temp_file("$maildir/tmp") or return undef;+    return { maildir => $maildir, fh => $fh, filename => $fname };+}++sub end_message {+    my ($m) = @_;+    close $m->{fh} or return "$!: $m->{filename} - Could not close filehandle";+    link "$m->{maildir}/tmp/$m->{filename}", "$m->{maildir}/new/$m->{filename}" or return "$@: $m->{filename} - could not link to new";+    unlink "$m->{maildir}/tmp/$m->{filename}";+    return 0;+}
+ tools/zsh_completion_new view
@@ -0,0 +1,533 @@+#compdef darcs++# The Z Shell is copyright (c) 1992-2004 Paul Falstad, Richard Coleman,+# Zoltán Hidvégi, Andrew Main, Peter Stephenson, Sven Wischnowsky, and+# others.  All rights reserved.  Individual authors, whether or not+# specifically named, retain copyright in all changes; in what follows, they+# are referred to as `the Zsh Development Group'.  This is for convenience+# only and this body has no legal status.  The Z shell is distributed under+# the following licence; any provisions made in individual files take+# precedence.+#+# Permission is hereby granted, without written agreement and without+# licence or royalty fees, to use, copy, modify, and distribute this+# software and to distribute modified versions of this software for any+# purpose, provided that the above copyright notice and the following+# two paragraphs appear in all copies of this software.+#+# In no event shall the Zsh Development Group be liable to any party for+# direct, indirect, special, incidental, or consequential damages arising out+# of the use of this software and its documentation, even if the Zsh+# Development Group have been advised of the possibility of such damage.+#+# The Zsh Development Group specifically disclaim any warranties, including,+# but not limited to, the implied warranties of merchantability and fitness+# for a particular purpose.  The software provided hereunder is on an "as is"+# basis, and the Zsh Development Group have no obligation to provide+# maintenance, support, updates, enhancements, or modifications.++# This completion module is based on section 6.8 of 'A User's Guide to the Z-Shell' +# by Peter Stephenson and on the tla completion module by Jason McCarty.++# EXTENDED_GLOB is required fr pattern backreferences.+setopt EXTENDED_GLOB++local DARCS=$words[1]++# test whether to hide short options from completion+autoload is-at-least+local hide_short+if zstyle -s ":completion:${curcontext}" hide-shortopts hide_short; then+  case $hide_short in+    true|yes|on|1) hide_short='!' ;;+    *) hide_short='' ;;+  esac+else+  is-at-least 4.1 || hide_short='!'+fi++++_darcs_main() {+local DARCS=$words[1]+local arguments+local curcontext="$curcontext"++if (( CURRENT > 2 )); then+    local cmd=${words[2]}+    local var_cmd=cmd_${cmd//-/_}+    curcontext="${curcontext%:*:*}:darcs-${cmd}:"+    (( CURRENT-- ))+    shift words++    local short long arg desc action+    short=()+    long=()+    arg=()+    desc=()+    action=()   +    arguments=()+    +    # Collect all help lines which have a leading space.+    local input+    input=(${(f)"$($DARCS $cmd -h)"})+    input=(${input:#[^\ ]*})+    local i+    for (( i=1 ; i <= ${#input} ; i++ )); do+	# Assumption: the the argument descriptions from `darcs cmd -h` +	# have the following format:+	# [spaces]<-f>[spaces][--flag]<=<spaces>argument>[spaces][description]+	[[ "$input[i]" = (#b)' '#(-?|)' '#([^' ']#|)' '#(--[^=' ']#)(=([^' ']#)|)' '#(*) ]] \+		|| _message -e messages "cannot parse command help output." || return 1++	short[i]="$match[1]"+	long[i]="$match[3]"+	arg[i]="$match[5]"+	desc[i]="$match[6]"+	desc[i]="${${desc[i]//\[/\\[}//\]/\\]}" # escape brackets	++	case $arg[i] in+	DIRECTORY)+	  action[i]='_files -/' ;;+	FILE|FILENAME|IDFILE|KEYS)+	  action[i]='_files' ;;+	USERNAME)+	  action[i]='_users' ;;+	EMAIL|FROM)+	  action[i]='_email_addresses' ;;+	*)+ 	  action[i]='' ;;+ 	esac+    done+    +    # Compute the exludes for _arguments++    local excluded short_excluded long_excluded k++    for (( i=1 ; i <= ${#input} ; i++ )); do+	excluded=()+	for opt (${=excludes[$long[i]]}); do+	    k=$long[(i)$opt]+	    excluded=($excluded $short[k] $long[k])+	done++	# Generate arguments for _arguments.+	# Make long and short options mutually exclusive.+	short_excluded=($long[i] $excluded)+	long_excluded=($short[i] $excluded)+	[ $short[i] ] && arguments=("$arguments[@]"+	    "${hide_short}(${short_excluded})${short[i]}[${desc[i]}]${arg[i]:+:$arg[i]:$action[i]}")+	[ $long[i] ] && arguments=("$arguments[@]"+	    "(${long_excluded})${long[i]}${arg[i]:+=}[${desc[i]}]${arg[i]:+:$arg[i]:$action[i]}")+    done++    arguments=("$arguments[@]" "${(@P)var_cmd-*:FILE:_files}")+else+    local hline+    local -a cmdlist+    _call_program help-commands darcs --help | while read -A hline; do+	(( ${#hline} < 2 )) && continue+	[[ $hline[1] == darcs ]] && continue+ 	[[ $hline[1] == Usage: ]] && continue+ 	[[ $hline[1] == Use ]] && continue+ 	cmdlist=( $cmdlist "${hline[1]}:${hline[2,-1]}" )+     done+    arguments=(':commands:(($cmdlist))')+fi++_arguments -S -A '-*' \+    "$arguments[@]"+}++++#+# Command argument definitions+#+local -a cmd_initialize cmd_get+cmd_initialize=()+cmd_get=(':repository:_files -/' ':new repository name:_files -/')++local -a cmd_add cmd_remove cmd_move cmd_replace+cmd_add=('*:new files:_darcs_new_file_or_tree')+cmd_remove=('*:existing controlled files:_darcs_controlled_files -e')+cmd_move=('*:existing controlled files:_darcs_controlled_files -e')+cmd_replace=(':old token:' ':new token:' '*:existing controlled files:_darcs_controlled_files -e')++local -a cmd_record cmd_pull cmd_push cmd_send cmd_apply+cmd_record=('*:controlled files:_darcs_controlled_files')+cmd_pull=(':repository:_darcs_repository_or_tree')+cmd_push=(':repository:_darcs_repository_or_tree')+cmd_send=(':repository:_darcs_repository_or_tree')+cmd_apply=(':patch file:_files')++local -a cmd_whatsnew cmd_changes+cmd_whatsnew=('*:controlled files:_darcs_controlled_files')+cmd_changes=('*:controlled files:_darcs_controlled_files')++local -a cmd_tag cmd_setpref cmd_check cmd_optimize+cmd_tag=()+cmd_setpref=(':preference key:(test predist boringfile binaries)' ':value:_files')+cmd_check=()+cmd_optimize=()++local -a cmd_amend_record cmd_rollback cmd_unrecord cmd_unpull cmd_revert cmd_unrevert+cmd_amend_record=('*:controlled files:_darcs_controlled_files')+cmd_rollback=()+cmd_unrecord=()+cmd_unpull=()+cmd_revert=('*:controlled files:_darcs_controlled_files')+cmd_unrevert=()++local -a cmd_diff cmd_annotate+cmd_diff=('*:controlled files:_darcs_controlled_files')+cmd_annotate=('*:controlled files:_darcs_controlled_files')++local -a cmd_resolve cmd_dist cmd_trackdown cmd_repair+cmd_resolve=()+cmd_dist=()+cmd_trackdown=(':initialization:' ':command:')+cmd_repair=()+++#+# Completion functions+#++(( $+functions[_darcs_new_files] )) ||+_darcs_new_files () {+    local -a new_files+    local -a local_files+    local in_tree_head in_tree_tail+    _darcs_make_tree_path in_tree_head in_tree_tail || return 1+    new_files=(${(f)"$(cd $(_darcs_absolute_tree_root)/$in_tree_head; $DARCS whatsnew -sl .)"})  +    new_files=(${${new_files:#[^a]*}//a /})++    local_files=()+    for file ($new_files); do+	[[ $file:h = $in_tree_head && $file:t = ${in_tree_tail}* ]] && local_files+=$file:t+    done++    compset -P '*/'+    _description new_files expl "new files"+    compadd "$expl[@]" "$local_files[@]"+}+++++# _darcs_controlled_files [-e|r] [-f|d]+#+# Adds controlled files to the completion. Can take either+# -e or -r as flags which respectively only add the existing+# files or the deleted files. Can take either -f or -d which+# respectively add only the files or directories.+(( $+functions[_darcs_controlled_files] )) ||+_darcs_controlled_files() {+    local abs_root=$(_darcs_absolute_tree_root)+    local only_removed only_existing only_files only_dirs+    zparseopts -E \+	'r=only_removed' 'e=only_existing' \+	'f=only_files' 'd=only_dirs'++    local in_tree_head in_tree_tail+    _darcs_make_tree_path in_tree_head in_tree_tail+    local recorded_dir+    if [[ -d $abs_root/_darcs/current ]]; then+        recorded_dir="$abs_root/_darcs/current/$in_tree_head"+    else+        recorded_dir="$abs_root/_darcs/pristine/$in_tree_head"+    fi+    local -a controlled_files controlled_dirs existing_files existing_dirs +    local -a dir_display_strs removed_dir_display_strs+    controlled_files=${(z)$(print $recorded_dir/$in_tree_tail*(.:t))}+    controlled_dirs=${(z)$(print $recorded_dir/$in_tree_tail*(/:t))}+    existing_files=() existing_dirs=()+    removed_files=() removed_dirs=() +    dir_display_strs=() removed_dir_display_strs=()+    local dir file+    for dir ($controlled_dirs); do+	if [[ -e $abs_root/$in_tree_head/$dir ]]; then+	    existing_dirs+="$dir"+	    dir_display_strs+="$dir/"	+	else+	    removed_dirs+="$dir"+	    removed_dir_display_strs+="$dir/"+	fi+    done+    for file ($controlled_files); do+	if [[ -e $abs_root/$in_tree_head/$file ]]; then+	    existing_files+="$file"+	else+	    removed_files+="$file"+	fi+    done++    compset -P '*/'+    if (( ! ${#only_removed} )); then +	_description controlled_files expl "existing revision controlled files"+	(( ! ${#only_dirs} )) && compadd "$expl[@]" $existing_files+	(( ! ${#only_files} )) \+	    && compadd "$expl[@]" -q -S / -d dir_display_strs -a -- existing_dirs+    fi+    if (( ! ${#only_existing} )); then+	_description removed_files expl "removed revision controlled files"+	(( ! ${#only_dirs} )) && compadd "$expl[@]" $removed_files+	(( ! ${#only_files} )) \+	    && compadd "$expl[@]" -q -S / -d removed_dir_display_strs -a -- removed_dirs+    fi+}++(( $+functions[_darcs_repositories] )) ||+_darcs_repositories() {+    local local_repos_path="$(_darcs_absolute_tree_root)/_darcs/prefs/repos"+    local global_repos_path="$HOME/.darcs/repos"+    local -a local_repos global_repos+    local -a global_repos+    [[ -e $local_repos_path ]] && cat $local_repos_path | read -A local_repos+    [[ -e $global_repos_path ]] && cat $global_repos_path | read -A global_repos+    local_repos=${local_repos:# #}+    global_repos=${global_repos:# #}+    _description repositories expl "repositories"+    (( ${#local_repos} )) && compadd "$expl[@]" -- "$local_repos[@]"+    (( ${#global_repos} )) && compadd "$expl[@]" -- "$global_repos[@]"+}++++# Combination completion functions++(( $+functions[_darcs_new_file_or_tree] )) ||+_darcs_new_file_or_tree() {+    local base_dir=$( cd ${$(_darcs_repodir):-.}; pwd -P)+    [[ -z $(_darcs_absolute_tree_root $base_dir) ]] && return 1+    local -a ignored_files+    ignored_files=(_darcs)+    _alternative 'newfiles:new file:_darcs_new_files' \+		 "directories:tree:_path_files -/ -W$base_dir -Fignored_files"+}++(( $+functions[_darcs_repository_or_tree] )) ||+_darcs_repository_or_tree() {+    local -a ignored_files+    ignored_files=(_darcs)+    _alternative 'repository:repository:_darcs_repositories' \+		 "directories:directories:_path_files -/ -Fignored_files"+}+++#+# Mutually exclusive options +#++typeset -A excludes+excludes=(+# Output+    --summary                     '--no-summary'+    --no-summary                  '--summary'+    --context                     '          --xml-output --human-readable --unified'+    --xml-output                  '--context              --human-readable --unified'+    --human-readable              '--context --xml-output                  --unified'+    --unified                     '--context --xml-output --human-readable          '++# Verbosity+    --verbose                     '          --quiet --standard-verbosity'+    --quiet                       '--verbose         --standard-verbosity'+    --standard-verbosity          '--verbose --quiet                     '++# Traversal+    --recursive                   '--not-recursive'+    --not-recursive               '--recursive'+    --look-for-adds               '--dont-look-for-adds'+    --dont-look-for-adds          '--look-for-adds'++# Pattern+    --from-match                  '             --from-patch --from-tag'+    --from-patch                  '--from-match              --from-tag'+    --from-tag                    '--from-patch --from-match           '+    --to-match                    '           --to-patch -to-tag'+    --to-patch                    '--to-match            -to-tag'+    --to-tag                      '--to-match --to-patch        '++# Repository Properties+    --plain-pristine-tree         '--no-pristine-tree'+    --no-pristine-tree            '--plain-pristine-tree'+    --parial                      '--complete'+    --complete                    '--partial'+    --compress                    '--dont-compress'+    --dont-compress               '--compress'+    --set-default                 '--no-set-default'+    --no-set-default              '--set-default'++# Logs+    --edit-long-comment           '--skip-long-comment --leave-test-directory'+    --skip-long-comment           '--edit-long-comment --leave-test-directory'+    --prompt-long-comment         '--edit-long-comment --skip-long-comment'++# Security+    --sign                        '       --sign-as --sign-ssl --dont-sign'+    --sign-as                     '--sign           --sign-ssl --dont-sign'+    --sign-ssl                    '--sign --sign-as            --dont-sign'+    --dont-sign                   '--sign --sign-as --sign-ssl            '+    --verify                      '         --verify-ssl --no-verify'+    --verify-ssl                  '--verify              --no-verify'+    --no-verify                   '--verify --verify-ssl            '+    --apply-as                    '--apply-as-myself'+    --apply-as-myself             '--apply-as'++# Conflicts+    --mark-conflicts              '--allow-conflicts --no-resolve-conflicts --dont-allow-conflicts'+    --allow-conflicts             '--mark-conflicts --no-resolve-conflicts --dont-allow-conflicts'+    --no-resolve-conflicts        '--mark-conflicts --allow-conflicts --dont-allow-conflicts'+    --dont-allow-conflicts        '--mark-conflicts --allow-conflicts --no-resolve-conflicts '++# Test+    --test                        '--no-test'+    --no-test                     '--test'+    --leave-test-directory        '--remove-test-directory'+    --remove-test-directory       '--leave-test-directory'++# Misc+    --force                       '--no-force'+    --no-force                    '--force'+    --ask-deps                    '--no-ask-deps'+    --no-ask-deps                 '--ask-deps'+    --date-trick                  '--no-date-trick'+    --no-date-trick               '--date-trick'+    --set-scripts-executable      '--dont-set-scripts-executable'+    --dont-set-scripts-executable '--set-scripts-executable'+)++++#+# Utility functions+#++# _darcs_make_tree_path in_tree_head_name in_tree_tail_name path+# Set in_tree_head_name in_tree_tail_name to the corresponding path+# parts from inside the current darcs tree.+_darcs_make_tree_path () {+    [[ -z $3 || $3 = '.' ]] && 3=${PREFIX:-./}+    local _in_tree=$(_darcs_path_from_root ${$(_darcs_repodir):-.}/$3)+    [[ -z $_in_tree ]] && return 1+    4='' 5=''+    if [[ ${3[-1]} = / ]]; then +	4=$_in_tree+    else+	4=$_in_tree:h+	[[ $_in_tree:t != . ]] && 5=$_in_tree:t+    fi+    set -A "$1" "$4"+    set -A "$2" "$5"+}++_darcs_repodir () {+    local index=$words[(i)--repodir*]+    if (( index < CURRENT )); then+	if [[ $words[$index] = --repodir ]]; then+	    (( index++ ))+	    print $words[$index]+	else+	    print ${words[$index]#*=}+	fi+    fi+}++_darcs_absolute_tree_root () {+    local root=$(_darcs_repodir)+    [[ -z $root ]] && root=$(pwd -P)+    while [[ ! $root -ef / ]]; do+	[[ -d $root/_darcs ]] && break+	root="$root/.."+    done+    [[ $root -ef / ]] || print $(cd $root; pwd -P)+}++_darcs_tree_root () {+    local abs=$(_darcs_absolute_tree_root)+    local rel=$(_darcs_relative_path $abs $(pwd -P))+    [[ -n $abs ]] && print $rel+}++# _darcs_paths_from_root name paths+# Sets name to the paths relative to the darcs tree root.+# If no argument is given then the current directory+# is assumed.+_darcs_paths_from_root () {+    local name=$1+    abs=$(_darcs_absolute_tree_root)+    [[ -z $abs ]] && set -A "$name" && return 1+    shift+    1=${1:=$PWD}+    local -a subpaths+    _darcs_filter_for_subpaths subpaths $abs $*+    local i+    for (( i=1; i<=${#subpaths}; i++ )); do+	[[ $subpaths[$i] != '.' ]] && subpaths[$i]="./$subpaths[$i]"+    done+    set -A "$name" "$subpaths[@]"+}++_darcs_path_from_root() {+    local path+    _darcs_paths_from_root path $1+    [[ -n $path ]] && print "$path"+}++# _darcs_filter_for_in_dir name dir paths+# Sets name to the relative paths from dir to the given paths which +# traverse dir. It ignores paths which are not in dir.+_darcs_filter_for_subpaths () {+    local name=$1 dir=$2 +    shift 2+    local p rel+    local -a accepted_paths +    accepted_paths=()+    for p; do+	rel=$(_darcs_path_difference $p $dir)+	[[ -n $rel ]] && accepted_paths+="$rel"+    done+    set -A "$name" "$accepted_paths[@]"+}++# _darcs_path_difference p1 p2+# Print the path from p2 to p1. If p2 is not an ancestor of p1 then it +# prints a blank string. If they point to the same directory then it returns+# a single period. p2 needs to be a directory path.+_darcs_path_difference () {+    local diff=$(_darcs_relative_path $1 $2)+    [[ ${diff%%/*} != .. ]] && print $diff || return 1+}+++# Print the a relative path from the second directory to the first,+# defaulting the second directory to $PWD if none is specified.+# Taken from the zsh mailing list.+_darcs_relative_path () {+    2=${2:=$PWD}+    [[ -d $2 && -d $1:h ]] || return 1+    [[ ! -d $1 ]] && 3=$1:t 1=$1:h+    1=$(cd $1; pwd -P)+    2=$(cd $2; pwd -P)+    [[ $1 -ef $2 ]] && print ${3:-.} && return++    local -a cur abs+    cur=(${(s:/:)2})        # Split 'current' directory into cur+    abs=(${(s:/:)1} $3)     # Split target directory into abs++    # Compute the length of the common prefix, or discover a subdiretory:+    integer i=1+    while [[ i -le $#abs && $abs[i] == $cur[i] ]]+    do+	((++i > $#cur)) && print ${(j:/:)abs[i,-1]} && return+    done++    2=${(j:/:)cur[i,-1]/*/..}       # Up to the common prefix directory and+    1=${(j:/:)abs[i,-1]}            # down to the target directory or file++    print $2${1:+/$1}+}++# Code to make sure _darcs is run when we load it+_darcs_main "$@"
+ tools/zsh_completion_old view
@@ -0,0 +1,26 @@+#-*- mode: shell-script;-*-++# darcs command line completion for zsh -- example+# Copyright 2002 "David Roundy" <droundy@abridgegame.org>+#++# Old zsh compctl style+_darcs_first()+{+    local prefix+    prefix=$1+    reply=( $( darcs --commands | grep "^${prefix}" ) )+}++_darcs_rest()+{+    local first second prefix rest+    prefix=$1+    read -c first second rest+    reply=( $( darcs ${second} --list-option | grep "^${prefix}") )+}+# this would complete on files as well, if first and rest didn't match.+# since darcs does this when passed --list-option, no need+# compctl -F -x 'p[1,1]' -K _darcs_first - 'p[2,-1]' -K _darcs_rest -- darcs+compctl -x 'p[1,1]' -K _darcs_first - 'p[2,-1]' -K _darcs_rest -- darcs+