diff --git a/DPM.cabal b/DPM.cabal
new file mode 100644
--- /dev/null
+++ b/DPM.cabal
@@ -0,0 +1,92 @@
+Name:           DPM
+Version:        0.1.0
+License:        GPL
+License-File:   LICENSE
+Copyright:      (c) 2009-2010 Stefan Wehr
+Category:       Development
+Author:         Stefan Wehr <mail@stefanwehr.de>
+Maintainer:     Stefan Wehr <mail@stefanwehr.de>
+Bug-Reports:    mailto:mail@stefanwehr.de
+Synopsis:       Darcs Patch Manager
+Description:
+
+  The Darcs Patch Manager (/DPM/ for short) is a tool that simplifies working
+  with the revision control system darcs (<http://darcs.net>). It is most
+  effective when used in an environment where developers do not push their
+  patches directly to the main repository but where patches undergo a
+  reviewing process before they are actually applied. See the documentation
+  of the module "DPM.Tutorial" for a short tutorial.
+
+Stability:      Beta
+Cabal-Version:  >= 1.6
+Build-Type:     Simple
+
+flag test
+  description:          Enable the test configuration: Build the test
+                        executable, reduce build time.
+  default:              False
+
+Executable dpm-tests
+  Main-Is:        AllTests.hs
+  Hs-Source-Dirs: src
+  Other-Modules:  DPM.Core.Lexer, DPM.Core.QueryParser
+  -- WARNING: The build-depends property is duplicated for the dpm executable.
+  --          Can we avoid this somehow?
+  Build-Depends:  darcs >= 2.3.0
+                  , bytestring >= 0.9
+                  , time
+                  , old-locale
+                  , convertible
+                  , filepath >= 1.1
+                  , base >= 4 && < 5
+                  , containers
+                  , array
+                  , split
+                  , mtl
+                  , syb
+                  , regex-posix
+                  , process
+                  , directory
+                  , pretty
+                  , unix
+                  , HTF >= 0.3
+                  , HSH >= 2
+  if flag(test)
+    Buildable:    True
+  else
+    Buildable:    False
+
+Executable dpm
+  Main-Is:        CommandlineMain.hs
+  Hs-Source-Dirs: src
+  Other-Modules:  DPM.Core.Lexer, DPM.Core.QueryParser
+  Build-Depends:  darcs >= 2.3.0
+                  , bytestring >= 0.9
+                  , time
+                  , old-locale
+                  , convertible
+                  , filepath >= 1.1
+                  , base >= 4 && < 5
+                  , containers
+                  , array
+                  , split
+                  , mtl
+                  , syb
+                  , regex-posix
+                  , process
+                  , directory
+                  , pretty
+                  , unix
+                  , HTF >= 0.3
+                  , HSH >= 2
+                  -- FIXME: specify dependency on happy and alex
+  Ghc-Options:    -Werror -fwarn-incomplete-patterns -fwarn-tabs -fwarn-missing-fields -fwarn-incomplete-record-updates -fwarn-duplicate-exports -fwarn-warnings-deprecations -fwarn-deprecated-flags -funbox-strict-fields
+
+Source-Repository head
+  Type:           darcs
+  Location:       http://www.stefanwehr.de/darcs/DPM
+
+-- Just a dummy library to force building the documentation per default
+Library
+  Exposed-Modules: DPM.Tutorial
+  Hs-Source-Dirs:  src
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+module Main where
+import Distribution.Simple
+main = defaultMain
diff --git a/dist/build/dpm/dpm-tmp/DPM/Core/Lexer.hs b/dist/build/dpm/dpm-tmp/DPM/Core/Lexer.hs
new file mode 100644
--- /dev/null
+++ b/dist/build/dpm/dpm-tmp/DPM/Core/Lexer.hs
@@ -0,0 +1,346 @@
+{-# OPTIONS -fglasgow-exts -cpp #-}
+{-# LINE 1 "src/DPM/Core/Lexer.x" #-}
+
+{-# OPTIONS_GHC -w #-}
+module DPM.Core.Lexer (scan, Token(..)) where
+
+#if __GLASGOW_HASKELL__ >= 603
+#include "ghcconfig.h"
+#elif defined(__GLASGOW_HASKELL__)
+#include "config.h"
+#endif
+#if __GLASGOW_HASKELL__ >= 503
+import Data.Array
+import Data.Char (ord)
+import Data.Array.Base (unsafeAt)
+#else
+import Array
+import Char (ord)
+#endif
+#if __GLASGOW_HASKELL__ >= 503
+import GHC.Exts
+#else
+import GlaExts
+#endif
+{-# LINE 1 "templates/wrappers.hs" #-}
+{-# LINE 1 "templates/wrappers.hs" #-}
+{-# LINE 1 "<built-in>" #-}
+{-# LINE 1 "<command-line>" #-}
+{-# LINE 1 "templates/wrappers.hs" #-}
+-- -----------------------------------------------------------------------------
+-- Alex wrapper code.
+--
+-- This code is in the PUBLIC DOMAIN; you may copy it freely and use
+-- it for any purpose whatsoever.
+
+{-# LINE 18 "templates/wrappers.hs" #-}
+
+-- -----------------------------------------------------------------------------
+-- The input type
+
+{-# LINE 35 "templates/wrappers.hs" #-}
+
+{-# LINE 51 "templates/wrappers.hs" #-}
+
+-- -----------------------------------------------------------------------------
+-- Token positions
+
+-- `Posn' records the location of a token in the input text.  It has three
+-- fields: the address (number of chacaters preceding the token), line number
+-- and column of a token within the file. `start_pos' gives the position of the
+-- start of the file and `eof_pos' a standard encoding for the end of file.
+-- `move_pos' calculates the new position after traversing a given character,
+-- assuming the usual eight character tab stops.
+
+{-# LINE 74 "templates/wrappers.hs" #-}
+
+-- -----------------------------------------------------------------------------
+-- Default monad
+
+{-# LINE 162 "templates/wrappers.hs" #-}
+
+
+-- -----------------------------------------------------------------------------
+-- Monad (with ByteString input)
+
+{-# LINE 251 "templates/wrappers.hs" #-}
+
+
+-- -----------------------------------------------------------------------------
+-- Basic wrapper
+
+
+type AlexInput = (Char,String)
+
+alexGetChar (_, [])   = Nothing
+alexGetChar (_, c:cs) = Just (c, (c,cs))
+
+alexInputPrevChar (c,_) = c
+
+-- alexScanTokens :: String -> [token]
+alexScanTokens str = go ('\n',str)
+  where go inp@(_,str) =
+          case alexScan inp 0 of
+                AlexEOF -> []
+                AlexError _ -> error "lexical error"
+                AlexSkip  inp' len     -> go inp'
+                AlexToken inp' len act -> act (take len str) : go inp'
+
+
+
+-- -----------------------------------------------------------------------------
+-- Basic wrapper, ByteString version
+
+{-# LINE 297 "templates/wrappers.hs" #-}
+
+{-# LINE 322 "templates/wrappers.hs" #-}
+
+
+-- -----------------------------------------------------------------------------
+-- Posn wrapper
+
+-- Adds text positions to the basic model.
+
+{-# LINE 339 "templates/wrappers.hs" #-}
+
+
+-- -----------------------------------------------------------------------------
+-- Posn wrapper, ByteString version
+
+{-# LINE 354 "templates/wrappers.hs" #-}
+
+
+-- -----------------------------------------------------------------------------
+-- GScan wrapper
+
+-- For compatibility with previous versions of Alex, and because we can.
+
+alex_base :: AlexAddr
+alex_base = AlexA# "\xf8\xff\xff\xff\xfd\xff\xff\xff\x02\x00\x00\x00\x07\x00\x00\x00\x1f\x00\x00\x00\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2b\x00\x00\x00\x30\x00\x00\x00"#
+
+alex_table :: AlexAddr
+alex_table = AlexA# "\x00\x00\x05\x00\x05\x00\x05\x00\x05\x00\x05\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xff\xff\x00\x00\x00\x00\x00\x00\x02\x00\x04\x00\x04\x00\x04\x00\x04\x00\x04\x00\x05\x00\x05\x00\x05\x00\x05\x00\x05\x00\x06\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\xff\xff\x00\x00\x00\x00\x00\x00\x03\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
+
+alex_check :: AlexAddr
+alex_check = AlexA# "\xff\xff\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\xff\xff\xff\xff\xff\xff\x20\x00\xff\xff\xff\xff\xff\xff\xff\xff\x20\x00\xff\xff\xff\xff\xff\xff\xff\xff\x20\x00\x2b\x00\xff\xff\xff\xff\xff\xff\x20\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\x3a\x00\xff\xff\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\xff\xff\x20\x00\xff\xff\xff\xff\xff\xff\xff\xff\x20\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x2b\x00\x20\x00\xff\xff\xff\xff\xff\xff\x2b\x00\x20\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x5e\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7b\x00\xff\xff\x7d\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"#
+
+alex_deflt :: AlexAddr
+alex_deflt = AlexA# "\x0a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x0b\x00\x0b\x00"#
+
+alex_accept = listArray (0::Int,11) [[],[],[(AlexAcc (alex_action_0))],[],[],[(AlexAcc (alex_action_1))],[(AlexAcc (alex_action_2))],[(AlexAcc (alex_action_3))],[(AlexAcc (alex_action_4))],[(AlexAcc (alex_action_5))],[(AlexAcc (alex_action_6))],[(AlexAcc (alex_action_6))]]
+{-# LINE 18 "src/DPM/Core/Lexer.x" #-}
+
+
+data Token = TSpecial -- ':'
+           | TNot     -- '^'
+           | TAnd     -- ' '
+           | TOr      -- ' + '
+           | TOpen    -- '{'
+           | TClose   -- '}'
+           | TString String
+           deriving (Eq,Show)
+
+scan :: String -> [Token]
+scan = alexScanTokens
+
+alex_action_0 =  \_ -> TOr 
+alex_action_1 =  \_ -> TAnd 
+alex_action_2 =  \_ -> TSpecial 
+alex_action_3 =  \_ -> TNot 
+alex_action_4 =  \_ -> TOpen 
+alex_action_5 =  \_ -> TClose 
+alex_action_6 =  TString 
+{-# LINE 1 "templates/GenericTemplate.hs" #-}
+{-# LINE 1 "templates/GenericTemplate.hs" #-}
+{-# LINE 1 "<built-in>" #-}
+{-# LINE 1 "<command-line>" #-}
+{-# LINE 1 "templates/GenericTemplate.hs" #-}
+-- -----------------------------------------------------------------------------
+-- ALEX TEMPLATE
+--
+-- This code is in the PUBLIC DOMAIN; you may copy it freely and use
+-- it for any purpose whatsoever.
+
+-- -----------------------------------------------------------------------------
+-- INTERNALS and main scanner engine
+
+{-# LINE 37 "templates/GenericTemplate.hs" #-}
+
+{-# LINE 47 "templates/GenericTemplate.hs" #-}
+
+
+data AlexAddr = AlexA# Addr#
+
+#if __GLASGOW_HASKELL__ < 503
+uncheckedShiftL# = shiftL#
+#endif
+
+{-# INLINE alexIndexInt16OffAddr #-}
+alexIndexInt16OffAddr (AlexA# arr) off =
+#ifdef WORDS_BIGENDIAN
+  narrow16Int# i
+  where
+	i    = word2Int# ((high `uncheckedShiftL#` 8#) `or#` low)
+	high = int2Word# (ord# (indexCharOffAddr# arr (off' +# 1#)))
+	low  = int2Word# (ord# (indexCharOffAddr# arr off'))
+	off' = off *# 2#
+#else
+  indexInt16OffAddr# arr off
+#endif
+
+
+
+
+
+{-# INLINE alexIndexInt32OffAddr #-}
+alexIndexInt32OffAddr (AlexA# arr) off = 
+#ifdef WORDS_BIGENDIAN
+  narrow32Int# i
+  where
+   i    = word2Int# ((b3 `uncheckedShiftL#` 24#) `or#`
+		     (b2 `uncheckedShiftL#` 16#) `or#`
+		     (b1 `uncheckedShiftL#` 8#) `or#` b0)
+   b3   = int2Word# (ord# (indexCharOffAddr# arr (off' +# 3#)))
+   b2   = int2Word# (ord# (indexCharOffAddr# arr (off' +# 2#)))
+   b1   = int2Word# (ord# (indexCharOffAddr# arr (off' +# 1#)))
+   b0   = int2Word# (ord# (indexCharOffAddr# arr off'))
+   off' = off *# 4#
+#else
+  indexInt32OffAddr# arr off
+#endif
+
+
+
+
+
+#if __GLASGOW_HASKELL__ < 503
+quickIndex arr i = arr ! i
+#else
+-- GHC >= 503, unsafeAt is available from Data.Array.Base.
+quickIndex = unsafeAt
+#endif
+
+
+
+
+-- -----------------------------------------------------------------------------
+-- Main lexing routines
+
+data AlexReturn a
+  = AlexEOF
+  | AlexError  !AlexInput
+  | AlexSkip   !AlexInput !Int
+  | AlexToken  !AlexInput !Int a
+
+-- alexScan :: AlexInput -> StartCode -> AlexReturn a
+alexScan input (I# (sc))
+  = alexScanUser undefined input (I# (sc))
+
+alexScanUser user input (I# (sc))
+  = case alex_scan_tkn user input 0# input sc AlexNone of
+	(AlexNone, input') ->
+		case alexGetChar input of
+			Nothing -> 
+
+
+
+				   AlexEOF
+			Just _ ->
+
+
+
+				   AlexError input'
+
+	(AlexLastSkip input len, _) ->
+
+
+
+		AlexSkip input len
+
+	(AlexLastAcc k input len, _) ->
+
+
+
+		AlexToken input len k
+
+
+-- Push the input through the DFA, remembering the most recent accepting
+-- state it encountered.
+
+alex_scan_tkn user orig_input len input s last_acc =
+  input `seq` -- strict in the input
+  let 
+	new_acc = check_accs (alex_accept `quickIndex` (I# (s)))
+  in
+  new_acc `seq`
+  case alexGetChar input of
+     Nothing -> (new_acc, input)
+     Just (c, new_input) -> 
+
+
+
+	let
+		!(base) = alexIndexInt32OffAddr alex_base s
+		!((I# (ord_c))) = ord c
+		!(offset) = (base +# ord_c)
+		!(check)  = alexIndexInt16OffAddr alex_check offset
+		
+		!(new_s) = if (offset >=# 0#) && (check ==# ord_c)
+			  then alexIndexInt16OffAddr alex_table offset
+			  else alexIndexInt16OffAddr alex_deflt s
+	in
+	case new_s of 
+	    -1# -> (new_acc, input)
+		-- on an error, we want to keep the input *before* the
+		-- character that failed, not after.
+    	    _ -> alex_scan_tkn user orig_input (len +# 1#) 
+			new_input new_s new_acc
+
+  where
+	check_accs [] = last_acc
+	check_accs (AlexAcc a : _) = AlexLastAcc a input (I# (len))
+	check_accs (AlexAccSkip : _)  = AlexLastSkip  input (I# (len))
+	check_accs (AlexAccPred a pred : rest)
+	   | pred user orig_input (I# (len)) input
+	   = AlexLastAcc a input (I# (len))
+	check_accs (AlexAccSkipPred pred : rest)
+	   | pred user orig_input (I# (len)) input
+	   = AlexLastSkip input (I# (len))
+	check_accs (_ : rest) = check_accs rest
+
+data AlexLastAcc a
+  = AlexNone
+  | AlexLastAcc a !AlexInput !Int
+  | AlexLastSkip  !AlexInput !Int
+
+data AlexAcc a user
+  = AlexAcc a
+  | AlexAccSkip
+  | AlexAccPred a (AlexAccPred user)
+  | AlexAccSkipPred (AlexAccPred user)
+
+type AlexAccPred user = user -> AlexInput -> Int -> AlexInput -> Bool
+
+-- -----------------------------------------------------------------------------
+-- Predicates on a rule
+
+alexAndPred p1 p2 user in1 len in2
+  = p1 user in1 len in2 && p2 user in1 len in2
+
+--alexPrevCharIsPred :: Char -> AlexAccPred _ 
+alexPrevCharIs c _ input _ _ = c == alexInputPrevChar input
+
+--alexPrevCharIsOneOfPred :: Array Char Bool -> AlexAccPred _ 
+alexPrevCharIsOneOf arr _ input _ _ = arr ! alexInputPrevChar input
+
+--alexRightContext :: Int -> AlexAccPred _
+alexRightContext (I# (sc)) user _ _ input = 
+     case alex_scan_tkn user input 0# input sc AlexNone of
+	  (AlexNone, _) -> False
+	  _ -> True
+	-- TODO: there's no need to find the longest
+	-- match when checking the right context, just
+	-- the first match will do.
+
+-- used by wrappers
+iUnbox (I# (i)) = i
diff --git a/dist/build/dpm/dpm-tmp/DPM/Core/QueryParser.hs b/dist/build/dpm/dpm-tmp/DPM/Core/QueryParser.hs
new file mode 100644
--- /dev/null
+++ b/dist/build/dpm/dpm-tmp/DPM/Core/QueryParser.hs
@@ -0,0 +1,492 @@
+{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}
+{-# OPTIONS -fglasgow-exts -cpp #-}
+{-# OPTIONS_GHC -w #-}
+module DPM.Core.QueryParser (parseQuery, querySyntax) where
+
+import DPM.Core.DataTypes
+import DPM.Core.Lexer
+-- import Test.Framework
+#if __GLASGOW_HASKELL__ >= 503
+import qualified Data.Array as Happy_Data_Array
+#else
+import qualified Array as Happy_Data_Array
+#endif
+#if __GLASGOW_HASKELL__ >= 503
+import qualified GHC.Exts as Happy_GHC_Exts
+#else
+import qualified GlaExts as Happy_GHC_Exts
+#endif
+
+-- parser produced by Happy Version 1.18.4
+
+newtype HappyAbsSyn t4 t5 t6 t7 = HappyAbsSyn HappyAny
+#if __GLASGOW_HASKELL__ >= 607
+type HappyAny = Happy_GHC_Exts.Any
+#else
+type HappyAny = forall a . a
+#endif
+happyIn4 :: t4 -> (HappyAbsSyn t4 t5 t6 t7)
+happyIn4 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn4 #-}
+happyOut4 :: (HappyAbsSyn t4 t5 t6 t7) -> t4
+happyOut4 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut4 #-}
+happyIn5 :: t5 -> (HappyAbsSyn t4 t5 t6 t7)
+happyIn5 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn5 #-}
+happyOut5 :: (HappyAbsSyn t4 t5 t6 t7) -> t5
+happyOut5 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut5 #-}
+happyIn6 :: t6 -> (HappyAbsSyn t4 t5 t6 t7)
+happyIn6 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn6 #-}
+happyOut6 :: (HappyAbsSyn t4 t5 t6 t7) -> t6
+happyOut6 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut6 #-}
+happyIn7 :: t7 -> (HappyAbsSyn t4 t5 t6 t7)
+happyIn7 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn7 #-}
+happyOut7 :: (HappyAbsSyn t4 t5 t6 t7) -> t7
+happyOut7 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut7 #-}
+happyInTok :: (Token) -> (HappyAbsSyn t4 t5 t6 t7)
+happyInTok x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyInTok #-}
+happyOutTok :: (HappyAbsSyn t4 t5 t6 t7) -> (Token)
+happyOutTok x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOutTok #-}
+
+
+happyActOffsets :: HappyAddr
+happyActOffsets = HappyA# "\x07\x00\x07\x00\x20\x00\x18\x00\x00\x00\x00\x00\x14\x00\x10\x00\x07\x00\x00\x00\x01\x00\x07\x00\x02\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x0b\x00\x00\x00"#
+
+happyGotoOffsets :: HappyAddr
+happyGotoOffsets = HappyA# "\x13\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\x00\x00\x04\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
+
+happyDefActions :: HappyAddr
+happyDefActions = HappyA# "\x00\x00\x00\x00\x00\x00\xfd\xff\xfb\xff\xf9\xff\x00\x00\x00\x00\x00\x00\xf6\xff\x00\x00\x00\x00\x00\x00\xf7\xff\xfa\xff\x00\x00\xfc\xff\xf8\xff\xfe\xff"#
+
+happyCheck :: HappyAddr
+happyCheck = HappyA# "\xff\xff\x03\x00\x01\x00\x01\x00\x00\x00\x01\x00\x02\x00\x03\x00\x06\x00\x08\x00\x03\x00\x04\x00\x05\x00\x02\x00\x07\x00\x00\x00\x01\x00\x02\x00\x03\x00\x00\x00\x01\x00\x02\x00\x03\x00\x07\x00\x04\x00\x05\x00\x02\x00\x07\x00\x01\x00\x02\x00\x03\x00\x02\x00\x03\x00\x01\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"#
+
+happyTable :: HappyAddr
+happyTable = HappyA# "\x00\x00\x0e\x00\x0c\x00\x0c\x00\x0c\x00\x03\x00\x04\x00\x05\x00\x12\x00\xff\xff\x07\x00\x08\x00\x09\x00\x10\x00\x0a\x00\x02\x00\x03\x00\x04\x00\x05\x00\x0a\x00\x03\x00\x04\x00\x05\x00\x0e\x00\x08\x00\x09\x00\x10\x00\x0a\x00\x12\x00\x04\x00\x05\x00\x10\x00\x05\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
+
+happyReduceArr = Happy_Data_Array.array (1, 9) [
+	(1 , happyReduce_1),
+	(2 , happyReduce_2),
+	(3 , happyReduce_3),
+	(4 , happyReduce_4),
+	(5 , happyReduce_5),
+	(6 , happyReduce_6),
+	(7 , happyReduce_7),
+	(8 , happyReduce_8),
+	(9 , happyReduce_9)
+	]
+
+happy_n_terms = 9 :: Int
+happy_n_nonterms = 4 :: Int
+
+happyReduce_1 = happySpecReduce_3  0# happyReduction_1
+happyReduction_1 happy_x_3
+	happy_x_2
+	happy_x_1
+	 =  case happyOut4 happy_x_1 of { happy_var_1 -> 
+	case happyOut5 happy_x_3 of { happy_var_3 -> 
+	happyIn4
+		 (QOr happy_var_1 happy_var_3
+	)}}
+
+happyReduce_2 = happySpecReduce_1  0# happyReduction_2
+happyReduction_2 happy_x_1
+	 =  case happyOut5 happy_x_1 of { happy_var_1 -> 
+	happyIn4
+		 (happy_var_1
+	)}
+
+happyReduce_3 = happySpecReduce_3  1# happyReduction_3
+happyReduction_3 happy_x_3
+	happy_x_2
+	happy_x_1
+	 =  case happyOut5 happy_x_1 of { happy_var_1 -> 
+	case happyOut6 happy_x_3 of { happy_var_3 -> 
+	happyIn5
+		 (QAnd happy_var_1 happy_var_3
+	)}}
+
+happyReduce_4 = happySpecReduce_1  1# happyReduction_4
+happyReduction_4 happy_x_1
+	 =  case happyOut6 happy_x_1 of { happy_var_1 -> 
+	happyIn5
+		 (happy_var_1
+	)}
+
+happyReduce_5 = happySpecReduce_2  2# happyReduction_5
+happyReduction_5 happy_x_2
+	happy_x_1
+	 =  case happyOut7 happy_x_2 of { happy_var_2 -> 
+	happyIn6
+		 (QNot happy_var_2
+	)}
+
+happyReduce_6 = happySpecReduce_1  2# happyReduction_6
+happyReduction_6 happy_x_1
+	 =  case happyOut7 happy_x_1 of { happy_var_1 -> 
+	happyIn6
+		 (happy_var_1
+	)}
+
+happyReduce_7 = happySpecReduce_3  3# happyReduction_7
+happyReduction_7 happy_x_3
+	happy_x_2
+	happy_x_1
+	 =  case happyOut4 happy_x_2 of { happy_var_2 -> 
+	happyIn7
+		 (happy_var_2
+	)}
+
+happyReduce_8 = happySpecReduce_2  3# happyReduction_8
+happyReduction_8 happy_x_2
+	happy_x_1
+	 =  case happyOutTok happy_x_2 of { (TString happy_var_2) -> 
+	happyIn7
+		 (trySpecial happy_var_2
+	)}
+
+happyReduce_9 = happySpecReduce_1  3# happyReduction_9
+happyReduction_9 happy_x_1
+	 =  case happyOutTok happy_x_1 of { (TString happy_var_1) -> 
+	happyIn7
+		 (QPrim happy_var_1
+	)}
+
+happyNewToken action sts stk [] =
+	happyDoAction 8# notHappyAtAll action sts stk []
+
+happyNewToken action sts stk (tk:tks) =
+	let cont i = happyDoAction i tk action sts stk tks in
+	case tk of {
+	TOr -> cont 1#;
+	TAnd -> cont 2#;
+	TNot -> cont 3#;
+	TSpecial -> cont 4#;
+	TOpen -> cont 5#;
+	TClose -> cont 6#;
+	TString happy_dollar_dollar -> cont 7#;
+	_ -> happyError' (tk:tks)
+	}
+
+happyError_ tk tks = happyError' (tk:tks)
+
+happyThen :: () => Maybe a -> (a -> Maybe b) -> Maybe b
+happyThen = (>>=)
+happyReturn :: () => a -> Maybe a
+happyReturn = (return)
+happyThen1 m k tks = (>>=) m (\a -> k a tks)
+happyReturn1 :: () => a -> b -> Maybe a
+happyReturn1 = \a tks -> (return) a
+happyError' :: () => [(Token)] -> Maybe a
+happyError' = parseError
+
+parse tks = happySomeParser where
+  happySomeParser = happyThen (happyParse 0# tks) (\x -> happyReturn (happyOut4 x))
+
+happySeq = happyDontSeq
+
+
+querySyntax :: String
+querySyntax = unlines $
+ ["Query ::= Query ' + ' Query  -- logical OR"
+ ,"        | Query ' '   Query  -- logical AND"
+ ,"        | '^' Query          -- logical NOT"
+ ,"        | '{' Query '}'      -- grouping"
+ ,"        | ':' Special"
+ ,"        | String"
+ ,""
+ ,"Special is one of \"undecided\", \"rejected\", \"obsolete\", \"applied\","
+ ,"\"reviewed\", \"open\", or \"closed\", and String is an arbitrary sequence "
+ ,"of non-whitespace characters not starting with '^', '{', '}', '+', or ':'."]
+
+parseError :: [Token] -> Maybe a
+parseError _ = Nothing
+
+trySpecial :: String -> Query
+trySpecial s =
+    case s of
+      "undecided" -> QState PatchStateUNDECIDED
+      "rejected" -> QState (PatchStateDISCARDED ReasonRejected)
+      "obsolete" -> QState (PatchStateDISCARDED ReasonObsolete)
+      "applied" -> QState PatchStateAPPLIED
+      "reviewed" -> QReviewed
+      "open" -> QGroupState PatchGroupOpen
+      "closed" -> QGroupState PatchGroupClosed
+      _ -> QPrim s
+
+parseQuery :: String -> Maybe Query
+parseQuery = parse . scan
+
+-- FIXME: tests
+{-# LINE 1 "templates/GenericTemplate.hs" #-}
+{-# LINE 1 "templates/GenericTemplate.hs" #-}
+{-# LINE 1 "<built-in>" #-}
+{-# LINE 1 "<command-line>" #-}
+{-# LINE 1 "templates/GenericTemplate.hs" #-}
+-- Id: GenericTemplate.hs,v 1.26 2005/01/14 14:47:22 simonmar Exp 
+
+{-# LINE 28 "templates/GenericTemplate.hs" #-}
+
+
+data Happy_IntList = HappyCons Happy_GHC_Exts.Int# Happy_IntList
+
+
+
+
+
+{-# LINE 49 "templates/GenericTemplate.hs" #-}
+
+{-# LINE 59 "templates/GenericTemplate.hs" #-}
+
+{-# LINE 68 "templates/GenericTemplate.hs" #-}
+
+infixr 9 `HappyStk`
+data HappyStk a = HappyStk a (HappyStk a)
+
+-----------------------------------------------------------------------------
+-- starting the parse
+
+happyParse start_state = happyNewToken start_state notHappyAtAll notHappyAtAll
+
+-----------------------------------------------------------------------------
+-- Accepting the parse
+
+-- If the current token is 0#, it means we've just accepted a partial
+-- parse (a %partial parser).  We must ignore the saved token on the top of
+-- the stack in this case.
+happyAccept 0# tk st sts (_ `HappyStk` ans `HappyStk` _) =
+	happyReturn1 ans
+happyAccept j tk st sts (HappyStk ans _) = 
+	(happyTcHack j (happyTcHack st)) (happyReturn1 ans)
+
+-----------------------------------------------------------------------------
+-- Arrays only: do the next action
+
+
+
+happyDoAction i tk st
+	= {- nothing -}
+
+
+	  case action of
+		0#		  -> {- nothing -}
+				     happyFail i tk st
+		-1# 	  -> {- nothing -}
+				     happyAccept i tk st
+		n | (n Happy_GHC_Exts.<# (0# :: Happy_GHC_Exts.Int#)) -> {- nothing -}
+
+				     (happyReduceArr Happy_Data_Array.! rule) i tk st
+				     where rule = (Happy_GHC_Exts.I# ((Happy_GHC_Exts.negateInt# ((n Happy_GHC_Exts.+# (1# :: Happy_GHC_Exts.Int#))))))
+		n		  -> {- nothing -}
+
+
+				     happyShift new_state i tk st
+				     where new_state = (n Happy_GHC_Exts.-# (1# :: Happy_GHC_Exts.Int#))
+   where off    = indexShortOffAddr happyActOffsets st
+	 off_i  = (off Happy_GHC_Exts.+# i)
+	 check  = if (off_i Happy_GHC_Exts.>=# (0# :: Happy_GHC_Exts.Int#))
+			then (indexShortOffAddr happyCheck off_i Happy_GHC_Exts.==#  i)
+			else False
+ 	 action | check     = indexShortOffAddr happyTable off_i
+		| otherwise = indexShortOffAddr happyDefActions st
+
+{-# LINE 127 "templates/GenericTemplate.hs" #-}
+
+
+indexShortOffAddr (HappyA# arr) off =
+#if __GLASGOW_HASKELL__ > 500
+	Happy_GHC_Exts.narrow16Int# i
+#elif __GLASGOW_HASKELL__ == 500
+	Happy_GHC_Exts.intToInt16# i
+#else
+	Happy_GHC_Exts.iShiftRA# (Happy_GHC_Exts.iShiftL# i 16#) 16#
+#endif
+  where
+#if __GLASGOW_HASKELL__ >= 503
+	i = Happy_GHC_Exts.word2Int# (Happy_GHC_Exts.or# (Happy_GHC_Exts.uncheckedShiftL# high 8#) low)
+#else
+	i = Happy_GHC_Exts.word2Int# (Happy_GHC_Exts.or# (Happy_GHC_Exts.shiftL# high 8#) low)
+#endif
+	high = Happy_GHC_Exts.int2Word# (Happy_GHC_Exts.ord# (Happy_GHC_Exts.indexCharOffAddr# arr (off' Happy_GHC_Exts.+# 1#)))
+	low  = Happy_GHC_Exts.int2Word# (Happy_GHC_Exts.ord# (Happy_GHC_Exts.indexCharOffAddr# arr off'))
+	off' = off Happy_GHC_Exts.*# 2#
+
+
+
+
+
+data HappyAddr = HappyA# Happy_GHC_Exts.Addr#
+
+
+
+
+-----------------------------------------------------------------------------
+-- HappyState data type (not arrays)
+
+{-# LINE 170 "templates/GenericTemplate.hs" #-}
+
+-----------------------------------------------------------------------------
+-- Shifting a token
+
+happyShift new_state 0# tk st sts stk@(x `HappyStk` _) =
+     let i = (case Happy_GHC_Exts.unsafeCoerce# x of { (Happy_GHC_Exts.I# (i)) -> i }) in
+--     trace "shifting the error token" $
+     happyDoAction i tk new_state (HappyCons (st) (sts)) (stk)
+
+happyShift new_state i tk st sts stk =
+     happyNewToken new_state (HappyCons (st) (sts)) ((happyInTok (tk))`HappyStk`stk)
+
+-- happyReduce is specialised for the common cases.
+
+happySpecReduce_0 i fn 0# tk st sts stk
+     = happyFail 0# tk st sts stk
+happySpecReduce_0 nt fn j tk st@((action)) sts stk
+     = happyGoto nt j tk st (HappyCons (st) (sts)) (fn `HappyStk` stk)
+
+happySpecReduce_1 i fn 0# tk st sts stk
+     = happyFail 0# tk st sts stk
+happySpecReduce_1 nt fn j tk _ sts@((HappyCons (st@(action)) (_))) (v1`HappyStk`stk')
+     = let r = fn v1 in
+       happySeq r (happyGoto nt j tk st sts (r `HappyStk` stk'))
+
+happySpecReduce_2 i fn 0# tk st sts stk
+     = happyFail 0# tk st sts stk
+happySpecReduce_2 nt fn j tk _ (HappyCons (_) (sts@((HappyCons (st@(action)) (_))))) (v1`HappyStk`v2`HappyStk`stk')
+     = let r = fn v1 v2 in
+       happySeq r (happyGoto nt j tk st sts (r `HappyStk` stk'))
+
+happySpecReduce_3 i fn 0# tk st sts stk
+     = happyFail 0# tk st sts stk
+happySpecReduce_3 nt fn j tk _ (HappyCons (_) ((HappyCons (_) (sts@((HappyCons (st@(action)) (_))))))) (v1`HappyStk`v2`HappyStk`v3`HappyStk`stk')
+     = let r = fn v1 v2 v3 in
+       happySeq r (happyGoto nt j tk st sts (r `HappyStk` stk'))
+
+happyReduce k i fn 0# tk st sts stk
+     = happyFail 0# tk st sts stk
+happyReduce k nt fn j tk st sts stk
+     = case happyDrop (k Happy_GHC_Exts.-# (1# :: Happy_GHC_Exts.Int#)) sts of
+	 sts1@((HappyCons (st1@(action)) (_))) ->
+        	let r = fn stk in  -- it doesn't hurt to always seq here...
+       		happyDoSeq r (happyGoto nt j tk st1 sts1 r)
+
+happyMonadReduce k nt fn 0# tk st sts stk
+     = happyFail 0# tk st sts stk
+happyMonadReduce k nt fn j tk st sts stk =
+        happyThen1 (fn stk tk) (\r -> happyGoto nt j tk st1 sts1 (r `HappyStk` drop_stk))
+       where sts1@((HappyCons (st1@(action)) (_))) = happyDrop k (HappyCons (st) (sts))
+             drop_stk = happyDropStk k stk
+
+happyMonad2Reduce k nt fn 0# tk st sts stk
+     = happyFail 0# tk st sts stk
+happyMonad2Reduce k nt fn j tk st sts stk =
+       happyThen1 (fn stk tk) (\r -> happyNewToken new_state sts1 (r `HappyStk` drop_stk))
+       where sts1@((HappyCons (st1@(action)) (_))) = happyDrop k (HappyCons (st) (sts))
+             drop_stk = happyDropStk k stk
+
+             off    = indexShortOffAddr happyGotoOffsets st1
+             off_i  = (off Happy_GHC_Exts.+# nt)
+             new_state = indexShortOffAddr happyTable off_i
+
+
+
+
+happyDrop 0# l = l
+happyDrop n (HappyCons (_) (t)) = happyDrop (n Happy_GHC_Exts.-# (1# :: Happy_GHC_Exts.Int#)) t
+
+happyDropStk 0# l = l
+happyDropStk n (x `HappyStk` xs) = happyDropStk (n Happy_GHC_Exts.-# (1#::Happy_GHC_Exts.Int#)) xs
+
+-----------------------------------------------------------------------------
+-- Moving to a new state after a reduction
+
+
+happyGoto nt j tk st = 
+   {- nothing -}
+   happyDoAction j tk new_state
+   where off    = indexShortOffAddr happyGotoOffsets st
+	 off_i  = (off Happy_GHC_Exts.+# nt)
+ 	 new_state = indexShortOffAddr happyTable off_i
+
+
+
+
+-----------------------------------------------------------------------------
+-- Error recovery (0# is the error token)
+
+-- parse error if we are in recovery and we fail again
+happyFail  0# tk old_st _ stk =
+--	trace "failing" $ 
+    	happyError_ tk
+
+{-  We don't need state discarding for our restricted implementation of
+    "error".  In fact, it can cause some bogus parses, so I've disabled it
+    for now --SDM
+
+-- discard a state
+happyFail  0# tk old_st (HappyCons ((action)) (sts)) 
+						(saved_tok `HappyStk` _ `HappyStk` stk) =
+--	trace ("discarding state, depth " ++ show (length stk))  $
+	happyDoAction 0# tk action sts ((saved_tok`HappyStk`stk))
+-}
+
+-- Enter error recovery: generate an error token,
+--                       save the old token and carry on.
+happyFail  i tk (action) sts stk =
+--      trace "entering error recovery" $
+	happyDoAction 0# tk action sts ( (Happy_GHC_Exts.unsafeCoerce# (Happy_GHC_Exts.I# (i))) `HappyStk` stk)
+
+-- Internal happy errors:
+
+notHappyAtAll = error "Internal Happy error\n"
+
+-----------------------------------------------------------------------------
+-- Hack to get the typechecker to accept our action functions
+
+
+happyTcHack :: Happy_GHC_Exts.Int# -> a -> a
+happyTcHack x y = y
+{-# INLINE happyTcHack #-}
+
+
+-----------------------------------------------------------------------------
+-- Seq-ing.  If the --strict flag is given, then Happy emits 
+--	happySeq = happyDoSeq
+-- otherwise it emits
+-- 	happySeq = happyDontSeq
+
+happyDoSeq, happyDontSeq :: a -> b -> b
+happyDoSeq   a b = a `seq` b
+happyDontSeq a b = b
+
+-----------------------------------------------------------------------------
+-- Don't inline any functions from the template.  GHC has a nasty habit
+-- of deciding to inline happyGoto everywhere, which increases the size of
+-- the generated parser quite a bit.
+
+
+{-# NOINLINE happyDoAction #-}
+{-# NOINLINE happyTable #-}
+{-# NOINLINE happyCheck #-}
+{-# NOINLINE happyActOffsets #-}
+{-# NOINLINE happyGotoOffsets #-}
+{-# NOINLINE happyDefActions #-}
+
+{-# NOINLINE happyShift #-}
+{-# NOINLINE happySpecReduce_0 #-}
+{-# NOINLINE happySpecReduce_1 #-}
+{-# NOINLINE happySpecReduce_2 #-}
+{-# NOINLINE happySpecReduce_3 #-}
+{-# NOINLINE happyReduce #-}
+{-# NOINLINE happyMonadReduce #-}
+{-# NOINLINE happyGoto #-}
+{-# NOINLINE happyFail #-}
+
+-- end of Happy Template.
diff --git a/src/AllTests.hs b/src/AllTests.hs
new file mode 100644
--- /dev/null
+++ b/src/AllTests.hs
@@ -0,0 +1,29 @@
+import qualified DPM.Core.TestDarcs
+import qualified DPM.Core.Model
+import qualified DPM.Core.Utils
+import qualified DPM.Core.Storage
+import qualified DPM.Core.ShortID
+import qualified DPM.Core.QueryParser
+import qualified DPM.Core.ReverseDependencies
+
+import System.Environment
+import Test.Framework
+
+import qualified Data.ByteString as B
+import qualified DPM.Core.Darcs as Darcs
+import DPM.Core.DataTypes ( PatchData(..), PatchID(..) )
+
+allTestSuites :: [TestSuite]
+allTestSuites = [DPM.Core.TestDarcs.allHTFTests
+                ,DPM.Core.Model.allHTFTests
+                ,DPM.Core.Utils.allHTFTests
+                ,DPM.Core.ShortID.allHTFTests
+                ,DPM.Core.ReverseDependencies.allHTFTests
+                ]
+
+testSuite :: TestSuite
+testSuite = makeAnonTestSuite (map testSuiteAsTest allTestSuites)
+
+main =
+    do args <- getArgs
+       runTestWithArgs args testSuite
diff --git a/src/CommandlineMain.hs b/src/CommandlineMain.hs
new file mode 100644
--- /dev/null
+++ b/src/CommandlineMain.hs
@@ -0,0 +1,12 @@
+module Main where
+
+import System.Environment
+
+import qualified DPM.UI.Commandline.Main as M
+
+mainWithArgs = M.mainWithArgs
+               
+main = 
+    do args <- getArgs
+       mainWithArgs args
+         
diff --git a/src/DPM/Core/Lexer.x b/src/DPM/Core/Lexer.x
new file mode 100644
--- /dev/null
+++ b/src/DPM/Core/Lexer.x
@@ -0,0 +1,31 @@
+{
+{-# OPTIONS_GHC -w #-}
+module DPM.Core.Lexer (scan, Token(..)) where
+}
+
+%wrapper "basic"
+
+tokens :-
+
+  $white+ "+" $white+         { \_ -> TOr }
+  $white+                     { \_ -> TAnd }
+  ":"                         { \_ -> TSpecial }
+  "^"                         { \_ -> TNot }
+  "{"                         { \_ -> TOpen }
+  "}"                         { \_ -> TClose }
+  [^$white\+:\^\{\}]~$white*  { TString }
+
+{
+
+data Token = TSpecial -- ':'
+           | TNot     -- '^'
+           | TAnd     -- ' '
+           | TOr      -- ' + '
+           | TOpen    -- '{'
+           | TClose   -- '}'
+           | TString String
+           deriving (Eq,Show)
+
+scan :: String -> [Token]
+scan = alexScanTokens
+}
diff --git a/src/DPM/Core/QueryParser.y b/src/DPM/Core/QueryParser.y
new file mode 100644
--- /dev/null
+++ b/src/DPM/Core/QueryParser.y
@@ -0,0 +1,74 @@
+{
+{-# OPTIONS_GHC -w #-}
+module DPM.Core.QueryParser (parseQuery, querySyntax) where
+
+import DPM.Core.DataTypes
+import DPM.Core.Lexer
+-- import Test.Framework
+
+}
+
+%name parse
+%tokentype { Token }
+%error { parseError }
+%monad { Maybe }
+
+%token
+      '+'            { TOr }
+      ' '            { TAnd }
+      '^'            { TNot }
+      ':'            { TSpecial }
+      '{'            { TOpen }
+      '}'            { TClose }
+      string         { TString $$ }
+
+%%
+
+Query : Query '+' Query1    { QOr $1 $3 }
+      | Query1              { $1 }
+
+Query1 : Query1 ' ' Query2  { QAnd $1 $3 }
+       | Query2             { $1 }
+
+Query2 : '^' Query3         { QNot $2 }
+       | Query3             { $1 }
+
+Query3 : '{' Query '}'      { $2 }
+       | ':' string         { trySpecial $2 }
+       | string             { QPrim $1 }
+
+{
+
+querySyntax :: String
+querySyntax = unlines $
+ ["Query ::= Query ' + ' Query  -- logical OR"
+ ,"        | Query ' '   Query  -- logical AND"
+ ,"        | '^' Query          -- logical NOT"
+ ,"        | '{' Query '}'      -- grouping"
+ ,"        | ':' Special"
+ ,"        | String"
+ ,""
+ ,"Special is one of \"undecided\", \"rejected\", \"obsolete\", \"applied\","
+ ,"\"reviewed\", \"open\", or \"closed\", and String is an arbitrary sequence "
+ ,"of non-whitespace characters not starting with '^', '{', '}', '+', or ':'."]
+
+parseError :: [Token] -> Maybe a
+parseError _ = Nothing
+
+trySpecial :: String -> Query
+trySpecial s =
+    case s of
+      "undecided" -> QState PatchStateUNDECIDED
+      "rejected" -> QState (PatchStateDISCARDED ReasonRejected)
+      "obsolete" -> QState (PatchStateDISCARDED ReasonObsolete)
+      "applied" -> QState PatchStateAPPLIED
+      "reviewed" -> QReviewed
+      "open" -> QGroupState PatchGroupOpen
+      "closed" -> QGroupState PatchGroupClosed
+      _ -> QPrim s
+
+parseQuery :: String -> Maybe Query
+parseQuery = parse . scan
+
+-- FIXME: tests
+}
diff --git a/src/DPM/Tutorial.hs b/src/DPM/Tutorial.hs
new file mode 100644
--- /dev/null
+++ b/src/DPM/Tutorial.hs
@@ -0,0 +1,201 @@
+{-|
+
+This module provides a short tutorial on how to use DPM.
+
+Suppose that Dave Developer implements a very cool feature. After
+polishing his patch, Dave uses @darcs send@ to send the patch:
+
+>  $ darcs send host:MAIN_REPO
+>  Tue Mar 16 16:55:09 CET 2010  Dave Developer <dave@example.com>
+>    * very cool feature
+>  Shall I send this patch? (1/1)  [ynWsfvplxdaqjk], or ? for help: y
+>  Successfully sent patch bundle to: patches@example.com
+
+After the patch has been sent to the address @patches\@example.com@, DPM
+comes into play. For this example, we assume that mail devivery for
+@patches\@example.com@ is handled by some mailfilter program such as maildrop
+(<http://www.courier-mta.org/maildrop/>) or procmail
+(<http://www.procmail.org/>). The task of the mailfilter program is the add
+all patches sent to @patches\@example.com@ to the DPM database. This is
+achieved with the DPM command @add@:
+
+>  $ dpm add --help
+>  add: Put the given patch bundles under DPM's control (use '-' to read from stdin).
+>  Usage: add FILE...
+>
+>  Command options:
+>
+>  Global options:
+>    -r DIR  --repo-dir=DIR                  directory of the darcs repository
+>    -s DIR  --storage-dir=DIR               directory for storing DPM data
+>    -v      --verbose                       be verbose
+>            --debug                         output debug messages
+>            --batch                         run in batch mode
+>            --no-colors                     do not use colors when printing text
+>            --user=USER                     current user
+>            --from=EMAIL_ADDRESS            from address for emails
+>            --review-address=EMAIL_ADDRESS  email address for sending reviews
+>    -h, -?  --help                          display this help message
+
+Now suppose that Dave's patch is in the DPM database. A reviewer, call him
+Richard Reviewer, uses the DPM command @list@ to see what patches are
+available in this database:
+
+>  $ dpm list --help
+>  list: List the patches matching the given query.
+>
+>  Query ::= Query ' + ' Query  -- logical OR
+>          | Query ' '   Query  -- logical AND
+>          | '^' Query          -- logical NOT
+>          | '{' Query '}'      -- grouping
+>          | ':' Special
+>          | String
+>
+>  Special is one of "undecided", "rejected", "obsolete", "applied",
+>  "reviewed", "open", or "closed", and String is an arbitrary sequence
+>  of non-whitespace characters not starting with '^', '{', '}', '+', or ':'.
+>
+>  If no query is given, DPM lists all open patch groups.
+>
+>  Usage: list QUERY ...
+>
+>  Command options:
+>
+>  Global options:
+>    -r DIR  --repo-dir=DIR                  directory of the darcs repository
+>    -s DIR  --storage-dir=DIR               directory for storing DPM data
+>    -v      --verbose                       be verbose
+>            --debug                         output debug messages
+>            --batch                         run in batch mode
+>            --no-colors                     do not use colors when printing text
+>            --user=USER                     current user
+>            --from=EMAIL_ADDRESS            from address for emails
+>            --review-address=EMAIL_ADDRESS  email address for sending reviews
+>    -h, -?  --help                          display this help message
+
+In our example, the output of the list command might look as follows:
+
+>  $ dpm -r MAIN_REPO -s DPM_DB list
+>    very cool feature [State: OPEN]
+>      7861 Tue Mar 16 17:20:45  2010 Dave Devloper <dave@example.com>
+>           State: UNDECIDED, Reviewed: no
+>           added
+>    some other patch [State: OPEN]
+>      7631 Tue Mar 16 13:15:20  2010 Eric E. <eric@example.com>
+>           State: REJECTED, Reviewed: yes
+>           added
+>    ...
+
+(The @-r@ option specifies a directory containing the DPM
+database. Initially, you simply create an empty directory. The @-s@ option
+specifies the path to the darcs repository in question.)
+
+DPM groups all patches with the same name inside a /patch group/. Patch
+groups allow keeping track of multiple revisions of the same patch. In the
+example, the patch group of name /very cool feature/ has only a single
+member, which is the patch Dave just created. The patch is identified by a
+unique suffix of its hash (7861 in the example). The output of the list
+command further tells us that no reviewer decided yet what to do with the
+patch (its in state UNDECIDED).
+
+At this point, Richard Reviewer reviews Dave's patch. During the review,
+he detects a minor bug so he rejects the patch:
+
+>  $ dpm -r MAIN_REPO -s DPM_DB review 7861
+>    Reviewing patch 7861
+>    Starting editor on DPM_DB/reviews/2010-03-16_7861_swehr_24166.dpatch
+>      <inspect patch in editor>
+>    Mark patch 7861 as reviewed? [Y/n] y
+>    Patch 7861 is in state UNDECIDED, reject this patch? [y/N] y
+>    Enter a comment: one minor bug
+>    Marked patch 7861 as reviewed
+>    Moved patch 7861 to REJECTED state
+>    Send review to Dave Developer <dave@example.com>? [Y/n] y
+>    Mail sent successfully.
+
+Now Dave Developer receives an email stating that has patch has been
+rejected. The email also contains the full review so that Dave sees why
+the patch has been rejected. Thus, Dave starts fixing the bug, does an
+@amend-record@ of the patch, and finally sends the patch again:
+
+>  $ darcs send MAIN_REPO
+>  Tue Mar 16 16:55:09 CET 2010  Dave Developer <dave@example.com>
+>    * very cool feature
+>  Shall I send this patch? (1/1)  [ynWsfvplxdaqjk], or ? for help: y
+>  Successfully sent patch bundle to: patches@example.com
+
+Once the email is received, the improved patch is added to the DPM
+database. The output of the @list@ command now looks like this:
+
+>  $ dpm -r MAIN_REPO -s DPM_DB list
+>    very cool feature [State: OPEN]
+>      2481 Tue Mar 16 17:50:23  2010 Dave Devloper <dave@example.com>
+>           State: UNDECIDED, Reviewed: no
+>           added
+>      7861 Tue Mar 16 17:20:45  2010 Dave Devloper <dave@example.com>
+>           State: REJECTED, Reviewed: yes
+>           marked as rejected: one minor bug
+>    some other patch [State: OPEN]
+>      7631 Tue Mar 16 13:15:20  2010 Eric E. <eric@example.com>
+>           State: REJECTED, Reviewed: yes
+>           added
+>    ...
+
+The patch 2481 is the improved revision of the original patch 7861. It is
+in the same group as the original patch because both patches have the same
+name. Richard Reviewer reviews the improved patch and has no complains
+anymore:
+
+>  $ dpm -r MAIN_REPO -s DPM_DB review 2481
+>    Reviewing patch 2481
+>    Starting editor on DPM_DB/reviews/2010-03-16_2481_swehr_876102.dpatch
+>      <inspect patch in editor>
+>    Mark patch 2481 as reviewed? [Y/n] y
+>    Patch 2481 is in state UNDECIDED, reject this patch? [y/N] n
+>    Enter a comment: ok
+>    Marked patch 2481 as reviewed
+>    Send review to Dave Developer <dave@example.com>? [y/N] n
+
+At this point, Richard Developer applies the patch with the very cool
+feature:
+
+>  $ dpm apply 2481
+>    About to apply patch 2481
+>    Entering DPM's dumb (aka interactive) apply command.
+>    Future will hopefully bring more intelligence.
+>
+>    Instructions:
+>    =============
+>    - Press 'n' until you reach
+>      Tue Mar 16 17:50:23  2010 Dave Devloper <dave@example.com>
+>        * very cool feature
+>      (Hash: 20100316162041-c71f4-871aedab8f4dd3bd042b9188f1496011c7dd2481)
+>    - Press 'y' once
+>    - Press 'd'
+>
+>    Tue Mar 16 17:50:23  2010 Dave Devloper <dave@example.com>
+>      * very cool feature
+>    Shall I apply this patch? (1/1)  [ynWsfvplxdaqjk], or ? for help: y
+>    Finished applying...
+>    Patch 2481 applied successfully
+>    Send notification to author Dave Developer <dave@example.com> of patch 2481? [Y/n] y
+>    Mail sent successfully.
+
+Applying a patch closes the corresponding patch group. Per default, the @list@ command
+doesn't display closed patch groups, but we can force it to do so with the @:closed@
+query:
+
+>  $ dpm list :closed
+>    very cool feature [State: CLOSED]
+>      2481 Tue Mar 16 17:50:23  2010 Dave Devloper <dave@example.com>
+>           State: APPLIED, Reviewed: yes
+>           marked as applied: -
+>      7861 Tue Mar 16 17:20:45  2010 Dave Devloper <dave@example.com>
+>           State: REJECTED, Reviewed: yes
+>           marked as rejected: one minor bug
+>      ...
+-}
+
+module DPM.Tutorial where
+
+foo = foo
