diff --git a/EditTimeReport.cabal b/EditTimeReport.cabal
new file mode 100644
--- /dev/null
+++ b/EditTimeReport.cabal
@@ -0,0 +1,29 @@
+Name:               EditTimeReport
+Version:            1.0
+Cabal-Version:      >= 1.2
+License:            GPL
+License-file:       LICENSE
+Author:             Bart Spaans
+Maintainer:         Bart Spaans <bart.spaans@gmail.com>
+Synopsis:           Query language and report generator for edit logs.
+Description:        This program can be used to see exactly how much time 
+                    you spent working on file X, project Y or language Z. 
+                    It can also be used to see for instance what your most 
+                    productive time of the year, month or week is. 
+
+                    In the long-run, this might help you make better time 
+                    estimates, while also providing you with an overview 
+                    of what you have worked on (which can also be nice for CV's).
+                    In short; this program allows you to query your logs
+                    and generate reports in plain text, html, xhtml and CSV.
+                    Support for more output formats is planned for the future.
+                    See the github page for more information.
+Homepage:           http://github.com/bspaans/EditTimeReport
+Category:           Utils
+Bug-Reports:        mailto:bart.spaans@gmail.com
+Build-Type:         Simple
+
+Executable report
+  Main-Is:          Main.hs
+  Build-Depends:    base >= 3 && < 5, haskell98, xhtml, html, pretty, filepath, containers, array, editline, directory, csv
+  Other-Modules:    QueryLexer, QueryParser, Edits, Printers, Query, QueryAST, Stats
diff --git a/Edits.hs b/Edits.hs
new file mode 100644
--- /dev/null
+++ b/Edits.hs
@@ -0,0 +1,125 @@
+-- | Provides a low level view of the log file.
+
+module Edits ( -- * AST
+               Edits, Edit(..),
+               -- ** Parsing
+               editsFromFile,        
+               -- * Grouping
+               groupWith , fileGroup,
+               -- ** Predicates
+               Pred,
+               -- * Calendars
+               Calendar(..), flatten,              
+               -- ** Calendar of Edits
+               calendarE, CalendarE  
+             ) where
+
+
+import Char
+import Maybe (mapMaybe)
+import Control.Applicative
+import Data.List as L (groupBy)
+import qualified Data.Map as D hiding (map, filter, mapMaybe)
+import System.FilePath
+
+
+
+-- | Abstract syntax for an editor log entry.
+--
+data Edit  = Edit {   year    :: Int
+                    , month   :: Int
+                    , day     :: Int
+                    , hour    :: Int
+                    , minute  :: Int
+                    , seconds :: Int
+                    , dow     :: Int     -- ^ Day of the week
+                    , doy     :: Int     -- ^ Day of the year
+                    , file    :: FilePath } deriving (Show, Eq)
+type Edits = [Edit]
+
+
+
+
+-- | Parses log files generated by timechartd.py 
+-- daemon or editor.
+--
+editsFromFile :: FilePath -> IO Edits
+editsFromFile f = parseEdits <$> readFile f
+
+
+parseEdits :: String   -> Edits
+parseEdit  :: String   -> Maybe Edit
+
+parseEdits  = mapMaybe parseEdit . lines
+parseEdit s = if a then Just $ Edit y m d h mi se dw dy (unwords (drop 9 w))
+                   else Nothing
+                   where w = words s
+                         i = take 8 w
+                         a = length w >= 9 && all (all isDigit) i && w !! 8 == "EDIT"
+                         (y:m:d:h:mi:se:dw:dy:[]) = map read i
+
+
+-- | A simple abstraction for predicates 
+--
+type Pred a = a -> Bool
+
+
+
+
+-- | Use a function's result to group by.
+--
+groupWith  :: Eq a => (b -> a) -> [b] -> [[b]]
+groupWith y = groupBy (\f g -> y f == y g)
+
+-- | Group Edits on year.
+--
+yearGroup  :: Edits -> [Edits]
+yearGroup   = groupWith year
+
+-- | Group Edits on month.
+--
+monthGroup :: Edits -> [Edits]
+monthGroup  = groupWith month
+
+-- | Group Edits on day of the month.
+--
+dayGroup   :: Edits -> [Edits]
+dayGroup    = groupWith day
+
+-- | Group Edits on file name.
+--
+fileGroup  :: Edits -> [Edits]
+fileGroup   = groupWith file
+
+
+-- | The Calendar type is an abstraction over lists of days in 
+-- lists of months in lists of years:
+--
+-- >      [ [ [ a ] ] ]
+-- >              | | + years
+-- >              | + months
+-- >              + days  
+--
+newtype Calendar a = Calendar [[[a]]] deriving (Eq, Show)
+
+instance Functor Calendar where
+  fmap f (Calendar as) = Calendar (map (map (map f)) as)
+
+
+-- Getting items out of the Calendar container
+--
+fromCalendar :: Calendar a -> [[[a]]]
+flatten      :: Calendar a -> [a]
+
+fromCalendar (Calendar as) = as
+flatten = concat . concat . fromCalendar
+
+
+-- Calendar of Edits
+-- Using the grouping functions to build it.
+-- Expects a chronological list of edits.
+--
+type CalendarE = Calendar Edits
+
+calendarE :: Edits -> CalendarE
+calendarE = Calendar . map (map dayGroup . monthGroup) . yearGroup 
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,93 @@
+module Main where
+
+
+import Query
+import Stats
+
+import Control.Applicative
+import Control.Monad
+import Control.Arrow
+import Data.Maybe
+import System 
+import System.Console.GetOpt
+import System.FilePath
+import System.Directory
+
+
+usage = unlines ["Report generator\nCopyright 2009-2010, Bart Spaans\n",
+        "Usage: report [OPTIONS] LOGFILE [QUERYFILE..]]\n"]
+
+data Options = Options {
+                         interactive :: Bool
+                       , askOptions  :: Bool
+                       , lang        :: [(String, String)]
+                       , proj        :: [(String, String)]
+                       , home        :: Maybe (IO String)  
+                       , format      :: [String]
+                       , commands    :: [String]
+                       } 
+
+defaultOptions :: Options
+defaultOptions = Options { interactive = False
+                         , lang = []
+                         , proj = []
+                         , home = Just (getHomeDirectory)
+                         , askOptions = False
+                         , format = []
+                         , commands = []
+                         }
+
+options :: [ OptDescr (Options -> IO Options) ]
+options = [Option "h" ["help"]        (NoArg outputHelp)          "Output command info"
+         , Option "f" ["format"]      (ReqArg setFormat "FORMAT") "Set default format (csv, html, text, xhtml)"
+         , Option "H" ["home"]        (ReqArg setHome "HOME")     "Set HOME directory"
+         , Option "i" ["interactive"] (NoArg setInteractive)      "Start interactive query session"
+         , Option "l" ["language"]    (ReqArg setLanguage "PATH") "Set languages directory"
+         , Option "q" ["query"]     (ReqArg addCommand "QUERY")   "Evaluate query."
+         , Option "p" ["project"]     (ReqArg setProject "PATH")  "Set projects directory"
+          ]
+
+
+addCommand c opt     = return opt { commands = c : commands opt }
+outputHelp _         = putStrLn (usageInfo usage options) >> exitWith ExitSuccess
+setFormat f opt      = return opt { format = f : format opt } 
+setHome h opt        = return opt { home = Just (return h) }
+setInteractive opt   = return opt { interactive = True }
+setLanguage path opt = return opt { lang = parseDescription path : (lang opt) } 
+setProject  path opt = return opt { proj = parseDescription path : (proj opt) } 
+
+
+makeStatOptions :: Options -> IO StatOptions
+makeStatOptions opts = do h <- fromMaybe (return "none") $ home opts
+                          return SO { languages  = toMatches $ lang opts
+                                    , projects   = toMatches $ proj opts
+                                    , homePath   =  h }
+
+makePO :: Options -> E PrintOptions
+makePO = setPrinters . format 
+
+
+main = do 
+    args <- getArgs
+    let (actions, nonOpts, msgs) = getOpt RequireOrder options args 
+    when (msgs /= []) (error $ concat msgs)
+    opts <- foldl (>>=) (return defaultOptions) actions
+    so <- makeStatOptions opts
+    po <- case makePO opts of { Failed s -> error s ; Ok a -> return a }
+    if null nonOpts then putStrLn usage else exec' so po opts nonOpts
+
+
+exec' so po opts nonOpts= 
+  do stats <- statsFromFile (head nonOpts) so
+     let i = interactiveQueries po stats
+     if not . null $ commands opts
+       then putStr $ execute' emptyEnv po (commands opts) stats 
+       else when (length nonOpts <= 1) (i emptyEnv)
+     if length nonOpts > 1 
+       then do co <- commandsFromFiles emptyEnv (tail nonOpts)
+               case co of 
+                 Failed s   -> error s
+                 Ok (st, e) -> do putStr $ execute emptyEnv po co stats 
+                                  when (interactive opts) (i e)
+       else when (interactive opts) (i emptyEnv)
+
diff --git a/Printers.hs b/Printers.hs
new file mode 100644
--- /dev/null
+++ b/Printers.hs
@@ -0,0 +1,152 @@
+module Printers (
+                 -- * Printers
+                 printTree, printCSV, printHtml,
+                 printPlainText, printXHtml,    
+
+                 -- * Options
+                 PrintOptions, POption(..),
+                 PrinterF(..), emptyPO,
+                 isSet, set, unSet, setPrinters,
+
+                 -- * Time strings
+                 showTime, 
+
+                 -- * String converters
+                 getMonth, getDow,
+                ) where
+
+import QueryAST 
+import Stats
+
+import Control.Applicative
+import Data.Char
+import qualified Data.Set as S
+import qualified Text.CSV as C
+import qualified Text.Html as H
+import qualified Text.XHtml as X
+import Text.Printf
+
+
+type PrintOptions = S.Set POption
+data POption      = PrinterF !PrinterF
+                  | Ident !Int
+                  deriving (Eq, Ord, Show)
+data PrinterF = Csv 
+              | Html 
+              | Text 
+              | XHtml 
+              deriving (Eq, Ord, Show)
+
+emptyPO :: PrintOptions
+emptyPO = S.fromList []
+
+
+-- Handling PrintOptions
+--
+isSet       :: POption -> PrintOptions -> Bool
+set         :: POption -> PrintOptions -> PrintOptions
+unSet       :: POption -> PrintOptions -> PrintOptions
+getPrinters :: PrintOptions -> [StatsTree -> String]
+setPrinters :: [String] -> E PrintOptions
+
+isSet   = S.member 
+set     = S.insert
+unSet   = S.delete
+
+getPrinters = map (printer . fromPrinters) . filter isPrinter . S.elems
+  where printer Csv               = printCSV 
+        printer Html              = printHtml 
+        printer Text              = printPlainText 
+        printer XHtml             = printXHtml 
+        fromPrinters (PrinterF p) = p
+        isPrinter (PrinterF _)    = True
+        isPrinter _               = False
+
+parsePrinter "CSV"   = Ok Csv
+parsePrinter "HTML"  = Ok Html
+parsePrinter "TEXT"  = Ok Text
+parsePrinter "XHTML" = Ok XHtml
+parsePrinter s = Failed $ "No such format `" ++ s ++ "'"
+
+setPrinters [] = Ok (S.fromList [PrinterF Text])
+setPrinters p = S.fromList <$> f p
+  where f = mapM (fmap PrinterF . parsePrinter . map toUpper) 
+
+
+
+-- | Selects the printers described in the PrintOptions.
+--
+printTree :: PrintOptions -> [StatsTree] -> String
+printTree po st = if null p then "No printers selected." 
+                            else p >>= (\p' -> concatMap (p'$) (reverse st))
+  where p = getPrinters po
+
+
+
+-- String Conversions
+--
+getMonth :: Int -> String
+getDow   :: Int -> String
+showTime :: Time -> String
+months   :: [String]
+days     :: [String]
+
+getMonth n = months !! (min 12 (max 1 n) - 1)
+months     = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", 
+              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+
+getDow n   = days !! min 6 (max 0 n)
+days       = ["Sunday"  , "Monday", "Tuesday" , "Wednesday",
+              "Thursday", "Friday", "Saturday"]
+
+showTime (h, m, s) = concat [f h, ":", f m, ":", f s]
+  where f = printf "%02d"
+
+
+
+-- | StatsTree to Plain Text
+--
+printPlainText :: StatsTree -> String
+printPlainText (Root [] _ _ _)   = "No matches"
+printPlainText (Root ns _ t ti)  = concatMap (tts' 1) ns ++ "\n\n   Total time: " 
+                                ++ showTime ti ++ "\n" 
+  where tts' lvl (Leaf time)     = printf "%10s" (showTime time)
+        tts' lvl (Node _ _ s tr) = '\n' : replicate (lvl * 4) ' ' 
+                                ++ printf "%-70s" s 
+                                ++ concatMap (tts' (lvl + 1)) tr
+
+
+-- | StatsTree to Html table (no HTML header)
+--
+printHtml :: StatsTree -> String
+printHtml = H.prettyHtml . foldTree (root, node, leaf)
+  where root ns h t ti = H.h2 (H.toHtml t) H.+++ H.table (headers h 
+                         H.+++ makeTable ns H.+++ total) H.+++ H.hr
+          where total  = H.tr(H.td (H.toHtml "TOTAL") H.! [H.colspan (length h - 1)] 
+                         H.+++ H.td (H.toHtml . showTime $ ti))
+        headers        = H.tr . H.concatHtml . map (H.th . H.toHtml) 
+        makeTable      = H.concatHtml . concatMap (map H.tr) 
+        node cspan t   = concatMap . map  . (H.+++) . H.td . H.toHtml
+        leaf           = pure . H.td . H.toHtml . showTime
+
+-- | StatsTree to XHtml table (includes HTML header)
+--
+printXHtml :: StatsTree -> String
+printXHtml = X.prettyHtml . foldTree (root, node, leaf)
+  where root ns h t ti = X.h2 (X.toHtml t) X.+++ X.table (headers h 
+                         X.+++ makeTable ns X.+++ total) X.+++ X.hr
+          where total  = X.tr(X.td (X.toHtml "TOTAL") X.! [X.colspan (length h - 1)] 
+                         X.+++ X.td (X.toHtml . showTime $ ti))
+        headers        = X.tr . X.concatHtml . map (X.th . X.toHtml) 
+        makeTable      = X.concatHtml . concatMap (map X.tr) 
+        node cspan t   = concatMap . map  . (X.+++) . X.td . X.toHtml
+        leaf           = pure . X.td . X.toHtml . showTime
+
+
+-- | StatsTree to CSV String.
+--
+printCSV :: StatsTree -> String
+printCSV = C.printCSV . foldTree (root, node, leaf)
+  where root ns h _ _ = h : concat ns
+        node _ _      = concatMap . map . (:)
+        leaf          = pure . pure . showTime
diff --git a/Query.hs b/Query.hs
new file mode 100644
--- /dev/null
+++ b/Query.hs
@@ -0,0 +1,376 @@
+-- | This module can take a parsed query, 
+-- convert it into something it can use and 
+-- execute it; resulting in a StatsTree, which 
+-- can be printed by one of the Printers.
+--
+module Query ( 
+               -- * Commands
+               Commands, Queries, Query, SubQuery, 
+               View, Constraint, Group, Env,
+               -- * Execute Queries 
+               interactiveQueries, 
+               commandsFromFile, commandsFromFiles,
+               makeTree, QueryAST.E(..),
+               emptyEnv, execute, execute' 
+             , module Printers 
+             ) where
+
+
+import Stats
+import Printers
+import QueryParser
+import QueryAST
+import Char
+import Data.List
+import Data.Function
+import qualified Data.Map as D
+import Maybe
+import Control.Applicative
+import System.Console.Editline.Readline
+import System.IO
+import System.Directory
+import System.FilePath
+import Text.Printf
+import Control.Monad
+
+
+type Commands   = (Queries, Env)
+type ExecResult = ([StatsTree], Env)
+type Queries    = [Query]
+type Env        = D.Map String Query
+
+-- | Each query is represented by sub queries, 
+-- each of which adds a new level to the tree.
+--
+type Query      = [SubQuery]
+type SubQuery   = (Header, View, Constraint, Group)
+type Constraint = Stats -> (Stats, Stats)
+type View       = EditStats -> String
+type Group      = Stats -> [Stats]
+
+
+-- | Read commands from files in a given environment.
+--
+commandsFromFiles :: Env -> [FilePath] -> IO (E Commands)
+commandsFromFiles env []     = return $ Ok ([], env)
+commandsFromFiles env (f:fp) = do o <- commandsFromFile env f
+                                  case o of 
+                                    Ok (q,e) -> do o2 <- commandsFromFiles e fp 
+                                                   case o2 of 
+                                                     Ok (q2,e) -> return (Ok (q ++ q2, e))
+                                                     Failed s -> return (Failed s)
+                                    Failed s -> return (Failed s)
+
+-- | Read commands from a file in a given environment.
+--
+commandsFromFile :: Env -> FilePath -> IO (E Commands)
+commandsFromFile env = fmap (>>= fromQCommands env) . parseFile
+
+
+-- | This function executes Commands in a given environment
+-- and then uses the Printers defined in the PrintOptions 
+-- to return a String representation of the StatsTree.
+--
+execute :: Env -> PrintOptions -> E Commands -> Stats -> String
+execute env po q st = case tr of 
+                        Ok c -> printTree po c
+                        Failed f -> error f 
+  where tr = fst . executeCommands st <$> q
+ 
+execute' env po q st = execute env po (mapM parseCommands q >>= fromQCommands env . concat) st
+
+emptyEnv :: Env
+emptyEnv = D.fromList []
+
+
+-- A Constraint separates Stats matching 
+-- a predicate from the ones that don't
+-- (P(s), ¬P(s))
+--
+makeConstraint :: Pred EditStats -> Constraint
+makeConstraint p = con ([], [])
+  where con (yes, no) [] = (yes, no)
+        con (yes, no) (s:st) = con n st
+          where n = if p s then (s : yes, no) else (yes, s:no)
+
+
+
+executeCommands :: Stats -> Commands -> ExecResult
+makeTree'       :: Stats -> Query -> Time -> [StatsTree]
+makeNode        :: String -> Stats -> Query -> StatsTree
+treeFromQuery   :: String -> Env -> Stats -> E ExecResult
+
+executeCommands st (q, env) = (map (flip makeTree st) q, env)
+
+-- | Executing a Query: 
+-- A Query works on Stats, which is a flat list of EditStats.
+-- For our results to be meaningful we need to 
+-- create a StatsTree, where each level represents another
+-- subquery. Executing a query can thus be seen 
+-- as building a tree from a list. 
+--
+makeTree        :: Query -> Stats -> StatsTree
+makeTree [] s = Root [] [] "" (0,0,0)
+makeTree q  s = Root nodes headers title time
+  where nodes = makeTree' s q (0,0,0)
+        headers = map (\(h,_,_,_) -> h) q ++ ["Edit Time"]
+        title = concat . intersperse " / " $ reverse headers
+        time = sumTime' (map f nodes)
+        f (Node _ t _ _) = t
+        f _ = (0,0,0)
+
+makeTree' s []            t = [Leaf t]
+makeTree' s ((_,v,c, g):cs) t = pruneNodeTrees nodes
+  where (yes, no) = c s
+        nodes = map (\gr -> makeNode (v . head $ gr) gr cs) (g yes)
+
+
+-- Pruning is pretty easy because we need to remove 
+-- the trees that don't have any leafs in them, 
+-- and we already keep that information in the Nodes.
+--
+pruneNodeTrees :: [StatsTree] -> [StatsTree]
+pruneNodeTrees = filter ((/=0) . f) 
+  where f (Node i _ _ _) = i
+        f _              = 1
+
+-- A Node is made of an Int describing the number of leafs,
+-- a string that is used for printing, and of course its children.
+--
+makeNode s yes cs = Node (n tr) time s tr
+  where tr = makeTree' yes cs time
+        time = sumTime yes
+        n [] = 0       -- Count children
+        n ((Node i _ _ _):cs) = i + n cs
+        n ((Leaf _):cs) = 1 + n cs
+       
+
+-- A helper function that builds a StatsTree out 
+-- of a String in the Query language.
+--
+treeFromQuery s env st = executeCommands st <$> (parseCommands s >>= fromQCommands env)
+
+
+
+-- | Interactive Query prompt using editline
+--
+interactiveQueries :: PrintOptions -> Stats -> Env -> IO()
+promptStart :: IO Bool
+
+type Action = Stats -> Env -> PrintOptions -> IO()
+
+printerDict = [("csv", Csv), ("html", Html), ("text", Text), ("xhtml", XHtml)]
+
+
+makePrintAction (s, pr) = [('-' : s, (m un , "Disable " ++ s ++ " printer"))
+                         , ('+' : s, (m se , "Enable "  ++ s ++ " printer"))]
+  where un = unSet (PrinterF pr)
+        se = set   (PrinterF pr)
+        m f stats env = repl stats env . f
+
+
+
+replCommands = concatMap makePrintAction printerDict
+            ++ [("exit", (\_ _ _ -> onExit, "Exit Program"))
+              , ("help", (\s e p -> printHelp >> repl s e p, "Output help"))]
+
+
+printHelp = putStrLn $ '\n' : unlines (sort (map h replCommands))
+  where h (c, (_, d)) = printf "   %-8s  %s" c d
+
+
+interactiveQueries po stats env = promptStart >> repl stats env po
+repl stats env po = do
+         setCompletionEntryFunction (Just $ qCompleter env)
+         maybeLine <- readline "> " 
+         case maybeLine of
+           Nothing      -> onExit
+           Just ""      -> repl stats env po
+           Just s       -> case lookup s replCommands of 
+                             Just (c, _) -> c stats env po
+                             Nothing -> eval stats env po s
+
+eval stats env po s = do 
+  addHistory s
+  case treeFromQuery s env stats of
+    Ok (st, e) -> (putStrLn $ printTree po st) >> repl stats e po
+    Failed e -> putStrLn e >> repl stats env po
+  
+
+
+
+promptStart = do putStrLn (unlines ["Time Report 1.0a, interactive session"
+                                   , "Copyright 2009-2010, Bart Spaans"
+                                   , "Type \"help\" for more information"])
+                 hSetBuffering stdout NoBuffering  -- remove LineBuffering from stdout
+                 historyLocation >>= readHistory
+
+onExit = putStr "\n" >> historyLocation >>= writeHistory >> return ()
+
+historyLocation :: IO FilePath
+historyLocation = (</> ".report_history") <$> getUserDocumentsDirectory
+
+qCompleter :: Env -> String -> IO [String]
+qCompleter env s = return (filter (startsWith s) known)
+  where known = ["extension", "language", "project", "filename"
+               , "year", "month", "day", "dow", "doy", "limit"
+               , "asc", "desc"] ++ D.keys env ++ map fst replCommands
+
+
+-- Convert AST to Query
+-- We have to transform the parsing result (QCommands) into 
+-- SubQueries (ie. a view function, a constraint and a 
+-- group function) and an Environment.
+--
+fromQCommands    :: Env -> QCommands -> E Commands
+fromQCommand     :: Env -> QCommand -> E (Either Query Env)
+fromQQuery       :: Env -> QQuery -> E Query
+fromQSubQuery    :: Env -> QSubQuery -> E Query
+fromQIndex       :: QIndex -> (EditStats -> String)
+addGrouping      :: Ord a => Bool -> (EditStats -> a) -> Group
+
+fromQCommands env qs = fromQCommands' env [] qs
+  where fromQCommands' env res []     = Ok (res, env)
+        fromQCommands' env res (q:qs) = fromQCommand env q >>= f
+          where f (Left qr) = fromQCommands' env (qr : res) qs 
+                f (Right e) = fromQCommands' newEnv res qs
+                   where newEnv = D.union e env
+ 
+
+fromQCommand env (Left q)  = Left <$> fromQQuery env q
+fromQCommand env (Right a) = Right <$> i a
+  where i (QAssign s q) = flip (D.insert s) env <$> fromQQuery env q
+
+
+-- First convert all the subqueries, then apply
+-- ordering and limiting to the last grouping function
+-- 
+fromQQuery env []     = Ok []
+fromQQuery env (c:cs) = fromQSubQuery env c >>= (\a -> (a++) <$> fromQQuery env cs)
+
+
+
+
+-- Sub queries
+--
+fromQSubQuery _ q@(QSubQuery _ Ext   _ _ _ _) = makeQuery q (takeExtension . fileName)
+fromQSubQuery _ q@(QSubQuery _ Lang  _ _ _ _) = makeQuery q language
+fromQSubQuery _ q@(QSubQuery _ Proj  _ _ _ _) = makeQuery q project
+fromQSubQuery _ q@(QSubQuery _ File  _ _ _ _) = makeQuery q fileName
+fromQSubQuery _ q@(QSubQuery _ Year  _ _ _ _) = makeQuery q (year . edit)
+fromQSubQuery _ q@(QSubQuery _ Month _ _ _ _) = makeQuery q (month . edit)
+fromQSubQuery _ q@(QSubQuery _ Day   _ _ _ _) = makeQuery q (day . edit)
+fromQSubQuery _ q@(QSubQuery _ Dow   _ _ _ _) = makeQuery q (dow . edit)
+fromQSubQuery _ q@(QSubQuery _ Doy   _ _ _ _) = makeQuery q (doy . edit)
+fromQSubQuery env (QCall s)                 = case D.lookup s env of 
+                                                Just q -> Ok q
+                                                Nothing -> Failed $ "Unknown definition `" ++ s ++ "'"
+
+makeQuery (QSubQuery gr t c h o l) f  = Ok [(fromQAs h t, view, constraints, grouping)]
+   where view = fromQIndex t
+         constraints = fromQConstraints t c
+         grouping = fromQLimit l . fromQOrder o . addGrouping gr f
+
+
+fromQAs (As s) _     = s
+fromQAs _      Ext   = "Extension"
+fromQAs _      Lang  = "Language"
+fromQAs _      Proj  = "Project"
+fromQAs _      File  = "File Name"
+fromQAs _      Year  = "Year"
+fromQAs _      Month = "Month"
+fromQAs _      Day   = "Day"
+fromQAs _      Dow   = "Day of the Week"
+fromQAs _      Doy   = "Day of the Year"
+
+-- Limiting and ordering is done before passing 
+-- the grouped Stats on to the constraint function
+--
+fromQOrder :: QOrder -> [Stats] -> [Stats]
+fromQOrder NoOrder = id
+fromQOrder Asc     = sortBy (compare `on` sumTime)
+fromQOrder Desc    = sortBy (flip compare `on` sumTime)
+
+
+fromQLimit :: QLimit -> [Stats] -> [Stats]
+fromQLimit NoLimit   = id
+fromQLimit (Limit i) = take i 
+
+
+-- The view function
+--
+fromQIndex Ext   = takeExtension . fileName
+fromQIndex Lang  = maybe "Unknown language" snd . language
+fromQIndex Proj  = maybe "Unknown project" snd . project
+fromQIndex File  = fileName
+fromQIndex Year  = show . year . edit
+fromQIndex Month = getMonth . month . edit
+fromQIndex Day   = show . day . edit
+fromQIndex Dow   = getDow . dow . edit
+fromQIndex Doy   = show . doy . edit
+
+
+
+-- The grouping function
+--
+addGrouping False _ = map (:[]) -- dontGroup
+addGrouping True  f = groupWith f . sortBy (compare `on` f)
+
+
+addToGrouping [] _ = error "Empty query, can't add to grouping"
+addToGrouping cs f = init cs ++ [add (last cs)]
+  where add (v, cs, gr) = (v, cs, f . gr)
+
+
+
+-- QConstraints to Constraints
+-- Individual QConstraints are first converted to predicates
+-- and get turned into one Constraint using makeConstraint.
+--
+fromQConstraints :: QIndex -> [QConstraint] -> Constraint
+makePred         :: QIndex -> QConstraint -> Pred EditStats
+
+
+fromQConstraints i qc = makeConstraint $ foldr f (const True) preds
+  where f a b p       = a p && b p 
+        preds         = map (makePred i) qc
+
+makePred i (QC File  op e) = fromQOper op (fromQExpr e) . fileName
+makePred i (QC Month op e) = numStringC op e month getMonth
+makePred i (QC Dow   op e) = numStringC op e dow getDow
+makePred i (QC Year  op e) = numericalC op year e
+makePred i (QC Day   op e) = numericalC op day e
+makePred i (QC Doy   op e) = numericalC op doy e
+makePred i (QC ind   op e) = fromQOper op (fromQExpr e) . fromQIndex ind
+makePred i (QCOE     op e) = makePred i (QC i op e)
+makePred i (QCE         e) = makePred i (QC i QE e)
+
+
+-- helper functions; to do the conversion
+stringC op s f    = fromQOper op (map toUpper s) . map toUpper . f . edit
+numericalC op g e = fromQOper op (read (fromQExpr e)) . g . edit
+maybeC op g h e   = maybe False (fromQOper op (fromQExpr e) . h) . g
+
+numStringC op (QInt i) num _      = fromQOper op i . num . edit
+numStringC op (QString s) num str = stringC op s (str . num)
+
+
+-- Expressions 
+--
+fromQExpr :: QExpr -> String
+fromQExpr (QInt i) = show i
+fromQExpr (QString s) = s
+
+
+-- Operators are written flipped around to make it easier 
+-- to write in a point-free style (see above)
+--
+fromQOper :: Ord a => QOper -> (a -> a -> Bool)
+fromQOper QL  = (>)  
+fromQOper QG  = (<)  
+fromQOper QLE = (>=) 
+fromQOper QGE = (<=) 
+fromQOper QE  = (==)
+fromQOper QNE = (/=)
+
+
diff --git a/QueryAST.hs b/QueryAST.hs
new file mode 100644
--- /dev/null
+++ b/QueryAST.hs
@@ -0,0 +1,33 @@
+module QueryAST where
+
+import Control.Applicative
+
+-- A straight forward AST for the Query DSL
+--
+type QCommands   = [QCommand]
+type QCommand    = Either QQuery QAssign 
+type QQuery      = [QSubQuery]
+data QAssign     = QAssign String QQuery
+data QSubQuery   = QSubQuery Bool QIndex [QConstraint] QAs QOrder QLimit | QCall String
+data QIndex      = Ext | Lang | Proj | File | Year
+                 | Month | Day | Dow | Doy deriving (Eq, Show)
+data QConstraint = QC QIndex QOper QExpr | QCOE QOper QExpr | QCE QExpr
+data QOper       = QL | QLE | QG | QGE | QE | QNE
+data QExpr       = QInt Int | QString String
+data QOrder      = Asc | Desc | NoOrder
+data QLimit      = Limit Int | NoLimit
+data QAs         = As String | DefaultAs
+
+-- A Succes/Failure data type used for parsing
+--
+data E a = Ok a | Failed String
+
+instance Functor E where
+  fmap f (Ok a)  = Ok $ f a
+  fmap f (Failed e) = Failed e
+
+instance Monad E where
+  return = Ok
+  m >>= k = case m of { Ok a -> k a ; Failed e -> Failed e }
+  fail = Failed
+
diff --git a/QueryLexer.x b/QueryLexer.x
new file mode 100644
--- /dev/null
+++ b/QueryLexer.x
@@ -0,0 +1,159 @@
+{
+module QueryLexer where
+
+import Data.Either
+}
+
+%wrapper "posn"
+
+$digit = 0-9
+$alpha = [a-zA-Z]
+$upper = A-Z
+$ident = [a-zA-Z0-9]
+$s     = [^'"']
+
+tokens :-
+
+  $white+       ;
+  "#".*         ;
+  ">"           { \p s -> TL p                      }
+  "<"           { \p s -> TG p                      }
+  "<="          { \p s -> TLE p                     }
+  ">="          { \p s -> TGE p                     }
+  "=="          { \p s -> TEqual p                  }
+  "="           { \p s -> TEqual p                  }
+  "!="          { \p s -> TNEqual p                 }
+  "/="          { \p s -> TNEqual p                 }
+  "("           { \p s -> TParenOpen p              }
+  ")"           { \p s -> TParenClose p             }
+  ","           { \p s -> TComma p                  }
+  "*"           { \p s -> TProduct p                }
+  ":="          { \p s -> TAssign p                 }
+  ";"           { \p s -> TSemiColon p              }
+  extension     { \p s -> TExtension p              }
+  extensions    { \p s -> TExtension p              }
+  exts          { \p s -> TExtension p              }
+  ext           { \p s -> TExtension p              }
+  e             { \p s -> TExtension p              }
+  languages     { \p s -> TLanguage p               }
+  language      { \p s -> TLanguage p               }
+  langs         { \p s -> TLanguage p               }
+  lang          { \p s -> TLanguage p               }
+  l             { \p s -> TLanguage p               }
+  projects      { \p s -> TProject p                }
+  project       { \p s -> TProject p                }
+  proj          { \p s -> TProject p                }
+  p             { \p s -> TProject p                }
+  filenames     { \p s -> TFilename p               }
+  filename      { \p s -> TFilename p               }
+  files         { \p s -> TFilename p               }
+  file          { \p s -> TFilename p               }
+  f             { \p s -> TFilename p               }
+  years         { \p s -> TYear p                   }
+  year          { \p s -> TYear p                   }
+  y             { \p s -> TYear p                   }
+  months        { \p s -> TMonth p                  }
+  month         { \p s -> TMonth p                  }
+  m             { \p s -> TMonth p                  }
+  days          { \p s -> TDay p                    }
+  day           { \p s -> TDay p                    }
+  da            { \p s -> TDay p                    }
+  dow           { \p s -> TDow p                    }
+  doy           { \p s -> TDoy p                    }
+  ascending     { \p s -> TAscending p              }
+  descending    { \p s -> TDescending p             }
+  asc           { \p s -> TAscending p              }
+  as            { \p s -> TAs p                     }
+  desc          { \p s -> TDescending p             }
+  limit         { \p s -> TLimit p                  }
+  group         { \p s -> TGroup p                  }
+  "&"           { \p s -> TGroup p                  }
+  nogrouping    { \p s -> TDontGroup p              }
+  nogroup       { \p s -> TDontGroup p              }
+  "!"           { \p s -> TDontGroup p              }
+  $digit+       { \p s -> TInteger p (read s)       }
+  $upper$ident* { \p s -> TIdent p s                }
+  \"$s*\"       { \p s -> TString p (init (tail s)) }
+  
+{
+data ConstraintToken = TExtension AlexPosn
+                     | TLanguage AlexPosn
+                     | TProject AlexPosn
+                     | TFilename AlexPosn
+                     | TYear AlexPosn
+                     | TMonth AlexPosn
+                     | TDay AlexPosn
+                     | TDow AlexPosn
+                     | TDoy AlexPosn
+                     | TGroup AlexPosn
+                     | TDontGroup AlexPosn
+                     | TAscending AlexPosn
+                     | TDescending AlexPosn
+                     | TLimit AlexPosn
+                     | TParenOpen AlexPosn
+                     | TParenClose AlexPosn
+                     | TComma AlexPosn
+                     | TProduct AlexPosn
+                     | TEqual AlexPosn
+                     | TNEqual AlexPosn
+                     | TL AlexPosn
+                     | TG AlexPosn
+                     | TLE AlexPosn
+                     | TGE AlexPosn
+                     | TSemiColon AlexPosn
+                     | TAs AlexPosn
+                     | TInteger AlexPosn Int
+                     | TIdent AlexPosn String
+                     | TAssign AlexPosn
+                     | TString AlexPosn String
+                     deriving (Eq, Show)
+
+
+alexScanTokens' :: String -> Either String [ConstraintToken]
+alexScanTokens' str = case go (alexStartPos, '\n', str) of
+                          [] -> Right []
+                          cs -> case last cs of 
+                                  Left a -> Left a
+                                  _      -> Right (rights cs)
+  where go inp@(pos,_,str) =
+          case alexScan inp 0 of
+                AlexEOF -> []
+                AlexError _ -> [Left $ "Lexical error on " ++ showPos pos
+                                        ++ if null str then "."
+                                             else ". Not a valid token: '" ++ (head . words $ str) ++ "'"]
+                AlexSkip  inp' len     -> go inp'
+                AlexToken inp' len act -> Right (act pos (take len str)): go inp'
+
+showPos (AlexPn _ li co) = unwords ["line", show li, ", column", show co]
+
+showTokenPos (TExtension p)  = showPos p
+showTokenPos (TLanguage p)   = showPos p
+showTokenPos (TProject p)    = showPos p
+showTokenPos (TFilename p)   = showPos p
+showTokenPos (TYear p)       = showPos p
+showTokenPos (TMonth p)      = showPos p
+showTokenPos (TDay p)        = showPos p
+showTokenPos (TDow p)        = showPos p
+showTokenPos (TDoy p)        = showPos p
+showTokenPos (TGroup p)      = showPos p
+showTokenPos (TDontGroup p)  = showPos p
+showTokenPos (TAscending p)  = showPos p
+showTokenPos (TDescending p) = showPos p
+showTokenPos (TLimit p)      = showPos p
+showTokenPos (TParenOpen p)  = showPos p
+showTokenPos (TParenClose p) = showPos p
+showTokenPos (TComma p)      = showPos p
+showTokenPos (TProduct p)    = showPos p
+showTokenPos (TEqual p)      = showPos p
+showTokenPos (TNEqual p)     = showPos p
+showTokenPos (TL p)          = showPos p
+showTokenPos (TG p)          = showPos p
+showTokenPos (TLE p)         = showPos p
+showTokenPos (TGE p)         = showPos p
+showTokenPos (TInteger p _)  = showPos p
+showTokenPos (TString p _)   = showPos p
+showTokenPos (TAssign p)     = showPos p
+showTokenPos (TIdent p _)    = showPos p
+showTokenPos (TSemiColon p)  = showPos p
+showTokenPos (TAs p)         = showPos p
+}
diff --git a/QueryParser.y b/QueryParser.y
new file mode 100644
--- /dev/null
+++ b/QueryParser.y
@@ -0,0 +1,153 @@
+{
+module QueryParser (ParseResult, parseCommands, parseFile) where
+
+import Prelude hiding (catch)
+import qualified Control.Exception as C
+
+import QueryLexer
+import QueryAST
+
+}
+
+%name queryParser
+
+%tokentype  { ConstraintToken }
+%error      { parseError      }
+
+%monad      { E } 
+
+%token 
+  '>'       { TL p          } 
+  '<'       { TG p          } 
+  '<='      { TLE p         } 
+  '>='      { TGE p         } 
+  '!='      { TNEqual p     } 
+  '=='      { TEqual p      } 
+  '('       { TParenOpen p  } 
+  ')'       { TParenClose p } 
+  ','       { TComma p      } 
+  '*'       { TProduct p    } 
+  ':='      { TAssign p     }
+  ';'       { TSemiColon p  }
+  as        { TAs p         }
+  extension { TExtension p  } 
+  language  { TLanguage p   } 
+  project   { TProject p    } 
+  filename  { TFilename p   } 
+  year      { TYear p       } 
+  month     { TMonth p      } 
+  day       { TDay p        } 
+  dow       { TDow p        } 
+  doy       { TDoy p        } 
+  group     { TGroup p      } 
+  nogroup   { TDontGroup p  }
+  limit     { TLimit p      } 
+  asc       { TAscending p  } 
+  desc      { TDescending p } 
+  integer   { TInteger p $$ } 
+  string    { TString p $$  }
+  ident     { TIdent p $$   }
+
+%%
+
+
+COMMANDS : MULTICOMMAND         { $1 }
+         | MULTICOMMAND COMMAND { $1 ++ [$2] }
+         | COMMAND              { [$1] }
+
+MULTICOMMAND: MULTICOMMAND SINGLECOMMAND  { $1 ++ [$2] } 
+            | SINGLECOMMAND               { [$1]       }
+
+SINGLECOMMAND : COMMAND ';' { $1 }
+
+
+
+COMMAND : QUERY       { Left $1  } 
+        | ASSIGNMENT  { Right $1 }
+
+
+ASSIGNMENT : ident ':=' QUERY { QAssign $1 $3 }
+
+QUERY : SUBQUERY            { [$1]        }
+      | QUERY '*' SUBQUERY  { $1 ++ [$3]  }
+
+SUBQUERY : GROUP INDEX CONSTRAINTS AS ORDER LIMIT {% if typeCheckConstraints $2 $3 
+                                        then return $ QSubQuery $1 $2 $3 $4 $5 $6
+                                        else fail "Parse error in constraints: expecting an integer"}
+         | ident                               { QCall $1 }
+
+GROUP : group             { True  }
+      | nogroup           { False }
+      |                   { True  }
+
+INDEX : extension         { Ext   }
+      | language          { Lang  } 
+      | project           { Proj  } 
+      | filename          { File  } 
+      | year              { Year  } 
+      | month             { Month } 
+      | day               { Day   } 
+      | dow               { Dow   } 
+      | doy               { Doy   } 
+     
+CONSTRAINTS : '(' CONS ')'  { $2 } 
+        | CONS              { $1 }
+        |                   { [] }
+
+CONS : CONSTRAINT                       { [$1]       }
+     | CONS ',' CONSTRAINT              { $1 ++ [$3] }
+
+CONSTRAINT : INDEX OPERATOR EXPR        {% typeCheckQC $1 $2 $3 }
+           | OPERATOR EXPR              { QCOE $1 $2 }
+           | EXPR                       { QCE $1 } 
+
+AS : as string { As $2 }
+   |           { DefaultAs }
+
+OPERATOR : '<'           { QL  }
+         | '>'           { QG  }
+         | '<='          { QLE }
+         | '>='          { QGE }
+         | '=='          { QE  }
+         | '!='          { QNE }
+
+EXPR : integer           { QInt $1 }
+     | string            { QString $1 }
+
+ORDER : asc           { Asc     }
+      | desc          { Desc    }
+      |               { NoOrder }
+
+LIMIT: limit integer  { Limit $2 }
+     |                { NoLimit  }
+
+{
+
+typeCheckConstraints i cs = all typeCheck cs
+  where typeCheck (QC _ _ _) = True
+        typeCheck (QCOE _ e) = check e
+        typeCheck (QCE e) = check e
+        check e = if elem i [Year, Day, Doy] 
+                    then case e of { QInt _ -> True ; _ -> False }
+                    else True
+                            
+
+typeCheckQC a b c = if elem a [Year, Day, Doy] 
+                      then case c of 
+                            QInt _ -> return $ QC a b c
+                            QString s -> fail $ "Expecting an integer, but got string \"" ++ s ++ "\"" 
+                      else (return $ QC a b c)
+
+type ParseResult = E QCommands
+
+parseError    :: [ConstraintToken]  -> E a
+parseCommands :: String   -> ParseResult
+parseFile     :: FilePath -> IO ParseResult
+
+parseError    s = fail "Parse error."
+parseCommands s = case alexScanTokens' s of 
+                    Left err -> fail err
+                    Right a -> queryParser a
+parseFile     f = readFile f >>= return . parseCommands
+
+}
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/Stats.hs b/Stats.hs
new file mode 100644
--- /dev/null
+++ b/Stats.hs
@@ -0,0 +1,187 @@
+module Stats ( -- * Statistics
+               EditStats(..), Stats, 
+               Description, Languages, Projects, Children, 
+               Matches, Match, SplitPath,statsFromFile,
+               -- ** Options
+               StatOptions(..),
+               -- ** Time
+               Time, sumTime, sumTime',
+               -- * Trees
+               Header, Title,
+               StatsTree(..),
+               StatsTreeAlgebra, foldTree,
+               -- * Misc.
+               -- ** Match parser for Main
+               parseDescription, toMatches,
+               -- ** Handy functions
+               both, startsWith,
+               module Edits
+             ) where 
+
+import Edits
+import Control.Applicative
+import Control.Arrow
+import Data.Char
+import Data.List
+import Data.Maybe 
+import qualified Data.Map as D hiding (map, filter, mapMaybe)
+import System.FilePath
+
+type Description = String
+type SplitPath   = [FilePath]
+type Match       = (SplitPath, Description)
+type Matches     = [Match]
+type Languages   = Matches
+type Projects    = Matches
+
+
+-- | Used to store the amount of time that was spent
+-- on a certain file while also listing some other 
+-- classifications.
+--
+data EditStats  = ES { language       :: Maybe (Description, String)
+                     , project        :: Maybe (Description, String)
+                     , fileName       :: FilePath
+                     , editTime       :: Time
+                     , edit           :: Edit } deriving (Show, Eq)
+type Stats      = [EditStats]
+
+
+-- | Options to be used when creating new Stats.
+--
+data StatOptions = SO { languages  :: Languages,   -- ^ Languages src locations 
+                        projects   :: Projects,    -- ^ Projects src locations
+                        homePath   :: String       -- ^ HOME directory
+                      }
+
+
+-- Stats — Build EditStats
+--
+stats      :: Edit -> Edit -> StatOptions -> EditStats
+matchFile  :: Edit -> Matches -> Maybe (Description, Match)
+startsWith :: Eq a => [a] -> [a] -> Bool
+both       :: (a -> b) -> a -> a -> (b, b)
+
+
+-- Create EditStats (ie match languages, projects and 
+-- home directory, count edit time) from two Edits
+--
+stats e e2 (SO lang proj home) = ES l p n t e
+  where (l, p)           = both (fmap (second snd)) la pr
+        (la, pr)         = both (matchFile e) lang (maybe [] new la ++ proj)
+        new (c, (fs, d)) = if d == slash then [] else [(fs ++ [d ++ slash] , d)]
+        n                = if startsWith home f then replaceHome else f
+        (t, f)           = (diffEdit e e2, file e)
+        replaceHome      = '~' : drop (length home) f
+
+
+-- Try to match a File with a Project or Language
+--
+matchFile edit matches'  = snd <$> (listToMaybe . reverse . sort $ matches)
+  where matches          = mapMaybe (uncurry match) matches'
+        match fs c       = if check then j else Nothing
+          where path     = if [last p] == slash then init p else slash
+                check    = startsWith fs s && length s > length fs
+                (s, p)   = (splitPath (file edit), s !! length fs)
+                j        = Just (length fs, (c, (fs, path))) 
+
+
+slash :: String
+slash = [pathSeparator]
+
+
+-- Matches — Description Parsers
+--
+parseDescription :: String -> (String, String)
+toMatches        :: [(String, String)] -> Matches
+
+
+parseDescription [] = ("", "")
+parseDescription s  = maybe noDesc desc getDesc 
+  where reversed    = reverse s
+	desc (x,y)  = (reverse x, reverse y)
+	noDesc      = (s, dropTrailingPathSeparator . last . splitPath $ s)
+	getDesc     = do c <- elemIndex ')' reversed
+			 o <- elemIndex '(' reversed
+			 if all isSpace (take c reversed) 
+			   then return (drop (o + 1) reversed, 
+					take (o + 1) (drop (c + 1) reversed))
+			   else Nothing
+
+toMatches = map (first $ splitPath . addTrailingPathSeparator)
+
+
+-- Times
+--
+diffEdit    :: Edit -> Edit -> Time
+toSeconds   :: Time -> Seconds
+fromSeconds :: Seconds -> Time
+sumTime     :: Stats -> Time
+sumTime'    :: [Time] -> Time
+
+
+type Seconds        = Int
+type Time           = (Int, Int, Int)
+
+
+diffEdit (Edit _ _ _ h m s _ _ _) (Edit _ _ _ h' m' s' _ _ _) = fromSeconds t
+     where t        = toSeconds (h', m', s') - toSeconds (h, m , s)
+
+
+toSeconds (h, m, s) = h * 3600 + m * 60 + s
+fromSeconds t       = (div t 3600, div (mod t 3600) 60, mod (mod t 3600) 60)
+sumTime             = fromSeconds . sum . map (toSeconds . editTime)
+sumTime'            = fromSeconds . sum . map toSeconds 
+
+
+-- Helper functions
+--
+both f a b = (f a, f b)
+
+startsWith []     _      = True
+startsWith _      []     = False
+startsWith (a:as) (b:bs) = a == b && startsWith as bs
+
+
+
+-- Calendar of Stats 
+--
+type CalendarS  = Calendar Stats
+
+calendarEtoS   :: StatOptions -> CalendarE -> CalendarS
+calendarS      :: StatOptions -> Edits -> CalendarS
+statsFromFile  :: FilePath -> StatOptions -> IO Stats
+
+calendarEtoS so = fmap stat 
+     where stat = map (\e -> stats (head e) (last e) so) . fileGroup 
+
+calendarS so       = calendarEtoS so . calendarE
+statsFromFile f so = concat . flatten . calendarS so <$> editsFromFile f
+
+
+
+-- Stats — Trees
+--
+type Children  = Int -- Total number of children in tree
+type Header    = String
+type Title     = String
+
+-- | Trees are used to represent the result of a Query.
+--
+data StatsTree = Root [StatsTree] [Header] Title Time
+               | Node Children Time String [StatsTree] 
+               | Leaf Time
+                    deriving (Eq, Show)
+
+type StatsTreeAlgebra r n = ([n] -> [Header] -> Title -> Time -> r 
+                          , Int -> Time -> String -> [n] -> n
+                          , Time -> n)
+
+-- | A fold for StatsTrees. Most of the Printers are 
+-- written using this fold.
+--
+foldTree :: StatsTreeAlgebra r n -> StatsTree -> r
+foldTree (root, node, leaf) (Root tr h s t) = root (map f tr) h s t
+  where f (Node i t s tr) = node i t s (map f tr)
+        f (Leaf e)      = leaf e
+
diff --git a/dist/build/report/report-tmp/QueryLexer.hs b/dist/build/report/report-tmp/QueryLexer.hs
new file mode 100644
--- /dev/null
+++ b/dist/build/report/report-tmp/QueryLexer.hs
@@ -0,0 +1,482 @@
+{-# OPTIONS -fglasgow-exts -cpp #-}
+{-# LINE 1 "QueryLexer.x" #-}
+
+module QueryLexer where
+
+import Data.Either
+
+#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
+
+
+type AlexInput = (AlexPosn,     -- current position,
+                  Char,         -- previous char
+                  String)       -- current input string
+
+alexInputPrevChar :: AlexInput -> Char
+alexInputPrevChar (p,c,s) = c
+
+alexGetChar :: AlexInput -> Maybe (Char,AlexInput)
+alexGetChar (p,c,[]) = Nothing
+alexGetChar (p,_,(c:s))  = let p' = alexMove p c in p' `seq`
+                                Just (c, (p', c, s))
+
+
+{-# 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.
+
+
+data AlexPosn = AlexPn !Int !Int !Int
+        deriving (Eq,Show)
+
+alexStartPos :: AlexPosn
+alexStartPos = AlexPn 0 1 1
+
+alexMove :: AlexPosn -> Char -> AlexPosn
+alexMove (AlexPn a l c) '\t' = AlexPn (a+1)  l     (((c+7) `div` 8)*8+1)
+alexMove (AlexPn a l c) '\n' = AlexPn (a+1) (l+1)   1
+alexMove (AlexPn a l c) _    = AlexPn (a+1)  l     (c+1)
+
+
+-- -----------------------------------------------------------------------------
+-- Default monad
+
+{-# LINE 162 "templates/wrappers.hs" #-}
+
+
+-- -----------------------------------------------------------------------------
+-- Monad (with ByteString input)
+
+{-# LINE 251 "templates/wrappers.hs" #-}
+
+
+-- -----------------------------------------------------------------------------
+-- Basic wrapper
+
+{-# LINE 273 "templates/wrappers.hs" #-}
+
+
+-- -----------------------------------------------------------------------------
+-- Basic wrapper, ByteString version
+
+{-# LINE 297 "templates/wrappers.hs" #-}
+
+{-# LINE 322 "templates/wrappers.hs" #-}
+
+
+-- -----------------------------------------------------------------------------
+-- Posn wrapper
+
+-- Adds text positions to the basic model.
+
+
+--alexScanTokens :: String -> [token]
+alexScanTokens str = go (alexStartPos,'\n',str)
+  where go inp@(pos,_,str) =
+          case alexScan inp 0 of
+                AlexEOF -> []
+                AlexError _ -> error "lexical error"
+                AlexSkip  inp' len     -> go inp'
+                AlexToken inp' len act -> act pos (take len str) : go inp'
+
+
+
+-- -----------------------------------------------------------------------------
+-- 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\x03\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\xd5\xff\xff\xff\xd6\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7\xff\xff\xff\x00\x00\x00\x00\xd8\xff\xff\xff\x00\x00\x00\x00\xd9\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xda\xff\xff\xff\x00\x00\x00\x00\xa9\xff\xff\xff\xb1\xff\xff\xff\xb6\xff\xff\xff\xbd\xff\xff\xff\xc4\xff\xff\xff\xca\xff\xff\xff\xee\xff\xff\xff\xe0\xff\xff\xff\xdd\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xff\xff\xff\xf2\xff\xff\xff\xf1\xff\xff\xff\xf9\xff\xff\xff\xed\xff\xff\xff\xf4\xff\xff\xff\xf5\xff\xff\xff\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xff\xff\xff\xf7\xff\xff\xff\x09\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\xfe\xff\xff\xff\x02\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x0b\x00\x00\x00\x08\x00\x00\x00\x12\x00\x00\x00\x0a\x00\x00\x00\x11\x00\x00\x00\x0d\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x0f\x00\x00\x00\x19\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x14\x00\x00\x00\x13\x00\x00\x00\x17\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x1a\x00\x00\x00\x1d\x00\x00\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x1c\x00\x00\x00\x20\x00\x00\x00\x24\x00\x00\x00\x21\x00\x00\x00\x28\x00\x00\x00\x2b\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x29\x00\x00\x00\x27\x00\x00\x00\x2d\x00\x00\x00\x33\x00\x00\x00\x2a\x00\x00\x00\x34\x00\x00\x00\x37\x00\x00\x00\x2c\x00\x00\x00\x00\x00\x00\x00\x2e\x00\x00\x00\x32\x00\x00\x00\x2f\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x31\x00\x00\x00\x35\x00\x00\x00\x36\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3a\x00\x00\x00\x39\x00\x00\x00\x3c\x00\x00\x00\x3b\x00\x00\x00\x38\x00\x00\x00\x3d\x00\x00\x00\x3e\x00\x00\x00\x42\x00\x00\x00\x3f\x00\x00\x00\x81\x00\x00\x00\x8b\x00\x00\x00\xd6\x00\x00\x00\x00\x00\x00\x00\x47\x01\x00\x00\x48\x01\x00\x00"#
+
+alex_table :: AlexAddr
+alex_table = AlexA# "\x00\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\xff\xff\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\xff\xff\x08\x00\x07\x00\x09\x00\x0b\x00\x0d\x00\x13\x00\x02\x00\x0c\x00\x79\x00\x03\x00\x1f\x00\x02\x00\x6a\x00\x16\x00\x0f\x00\x10\x00\x12\x00\x02\x00\x11\x00\x17\x00\x18\x00\x0e\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x14\x00\x15\x00\x06\x00\x0a\x00\x05\x00\x19\x00\x1a\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x76\x00\x1b\x00\x1c\x00\x1d\x00\x21\x00\x22\x00\x23\x00\x57\x00\x24\x00\x26\x00\x4b\x00\x1e\x00\x3b\x00\x69\x00\x2a\x00\x20\x00\x25\x00\x27\x00\x29\x00\x47\x00\x74\x00\x28\x00\x32\x00\x2b\x00\x2e\x00\x2c\x00\x2d\x00\x30\x00\x2f\x00\x64\x00\x34\x00\x41\x00\x33\x00\x36\x00\x31\x00\x35\x00\x38\x00\x3a\x00\x37\x00\x39\x00\x3f\x00\x40\x00\x43\x00\x3c\x00\x4a\x00\x3d\x00\x00\x00\x3e\x00\x60\x00\x42\x00\x46\x00\x45\x00\x4f\x00\x44\x00\x52\x00\x51\x00\x50\x00\x48\x00\x4d\x00\x54\x00\x55\x00\x53\x00\x58\x00\x56\x00\x4c\x00\x49\x00\x4e\x00\x59\x00\x5a\x00\x5b\x00\x5c\x00\x5d\x00\x5e\x00\x62\x00\x63\x00\x00\x00\x00\x00\x5f\x00\x65\x00\x6b\x00\x61\x00\x00\x00\x67\x00\x6d\x00\x66\x00\x6c\x00\x68\x00\x72\x00\x00\x00\x6e\x00\x70\x00\x6f\x00\x73\x00\x00\x00\x71\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x75\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\x77\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x78\x00\x78\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\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\x0a\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\x0a\x00\x3d\x00\x3d\x00\x3d\x00\x3d\x00\x3d\x00\x3d\x00\x20\x00\x21\x00\x22\x00\x23\x00\x73\x00\x20\x00\x26\x00\x6e\x00\x28\x00\x29\x00\x2a\x00\x20\x00\x2c\x00\x6f\x00\x69\x00\x2f\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\x3a\x00\x3b\x00\x3c\x00\x3d\x00\x3e\x00\x73\x00\x6e\x00\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\x65\x00\x74\x00\x78\x00\x73\x00\x65\x00\x67\x00\x61\x00\x61\x00\x67\x00\x64\x00\x65\x00\x66\x00\x67\x00\x73\x00\x73\x00\x75\x00\x6e\x00\x6c\x00\x6d\x00\x6e\x00\x61\x00\x70\x00\x73\x00\x65\x00\x74\x00\x63\x00\x6f\x00\x6a\x00\x69\x00\x65\x00\x79\x00\x73\x00\x61\x00\x72\x00\x6d\x00\x65\x00\x69\x00\x6e\x00\x6c\x00\x61\x00\x65\x00\x68\x00\x73\x00\x61\x00\x73\x00\xff\xff\x72\x00\x65\x00\x73\x00\x6f\x00\x6e\x00\x67\x00\x74\x00\x64\x00\x69\x00\x6e\x00\x73\x00\x6f\x00\x65\x00\x63\x00\x6e\x00\x67\x00\x73\x00\x77\x00\x79\x00\x79\x00\x6e\x00\x69\x00\x64\x00\x6e\x00\x65\x00\x63\x00\x69\x00\x6d\x00\xff\xff\xff\xff\x73\x00\x70\x00\x67\x00\x74\x00\xff\xff\x6f\x00\x69\x00\x75\x00\x6e\x00\x72\x00\x67\x00\xff\xff\x70\x00\x6f\x00\x75\x00\x6f\x00\xff\xff\x72\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\x0a\x00\x0a\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\x22\x00\x22\x00\xff\xff\xff\xff\xff\xff\x27\x00\x27\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\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\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# "\xff\xff\xff\xff\xff\xff\x04\x00\x04\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\x7a\x00\x7a\x00"#
+
+alex_accept = listArray (0::Int,122) [[],[],[(AlexAccSkip)],[(AlexAccSkip)],[(AlexAccSkip)],[(AlexAcc (alex_action_2))],[(AlexAcc (alex_action_3))],[(AlexAcc (alex_action_4))],[(AlexAcc (alex_action_5))],[(AlexAcc (alex_action_6))],[(AlexAcc (alex_action_7))],[(AlexAcc (alex_action_8))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_9))],[],[(AlexAcc (alex_action_10))],[(AlexAcc (alex_action_11))],[(AlexAcc (alex_action_12))],[(AlexAcc (alex_action_13))],[(AlexAcc (alex_action_14))],[],[(AlexAcc (alex_action_15))],[(AlexAcc (alex_action_16))],[],[],[],[],[],[(AlexAcc (alex_action_19))],[],[(AlexAcc (alex_action_20))],[(AlexAcc (alex_action_17))],[(AlexAcc (alex_action_18))],[(AlexAcc (alex_action_21))],[(AlexAcc (alex_action_22))],[],[],[],[(AlexAcc (alex_action_24))],[],[],[(AlexAcc (alex_action_25))],[(AlexAcc (alex_action_23))],[(AlexAcc (alex_action_26))],[(AlexAcc (alex_action_27))],[],[],[(AlexAcc (alex_action_28))],[],[],[(AlexAcc (alex_action_29))],[(AlexAcc (alex_action_30))],[(AlexAcc (alex_action_31))],[],[],[],[(AlexAcc (alex_action_33))],[],[],[(AlexAcc (alex_action_34))],[(AlexAcc (alex_action_32))],[(AlexAcc (alex_action_35))],[(AlexAcc (alex_action_36))],[],[],[(AlexAcc (alex_action_37))],[(AlexAcc (alex_action_38))],[(AlexAcc (alex_action_39))],[],[],[],[(AlexAcc (alex_action_40))],[(AlexAcc (alex_action_41))],[(AlexAcc (alex_action_42))],[(AlexAcc (alex_action_43))],[],[(AlexAcc (alex_action_44))],[],[(AlexAcc (alex_action_45))],[(AlexAcc (alex_action_46))],[],[],[],[],[],[(AlexAcc (alex_action_48))],[(AlexAcc (alex_action_49))],[],[(AlexAcc (alex_action_47))],[],[],[],[],[],[(AlexAcc (alex_action_50))],[],[],[(AlexAcc (alex_action_51))],[],[],[],[(AlexAcc (alex_action_52))],[],[],[],[],[(AlexAcc (alex_action_53))],[(AlexAcc (alex_action_54))],[],[],[(AlexAcc (alex_action_55))],[],[],[],[],[],[],[(AlexAcc (alex_action_57))],[(AlexAcc (alex_action_58))],[(AlexAcc (alex_action_58))],[(AlexAcc (alex_action_59))],[],[]]
+{-# LINE 78 "QueryLexer.x" #-}
+
+data ConstraintToken = TExtension AlexPosn
+                     | TLanguage AlexPosn
+                     | TProject AlexPosn
+                     | TFilename AlexPosn
+                     | TYear AlexPosn
+                     | TMonth AlexPosn
+                     | TDay AlexPosn
+                     | TDow AlexPosn
+                     | TDoy AlexPosn
+                     | TGroup AlexPosn
+                     | TDontGroup AlexPosn
+                     | TAscending AlexPosn
+                     | TDescending AlexPosn
+                     | TLimit AlexPosn
+                     | TParenOpen AlexPosn
+                     | TParenClose AlexPosn
+                     | TComma AlexPosn
+                     | TProduct AlexPosn
+                     | TEqual AlexPosn
+                     | TNEqual AlexPosn
+                     | TL AlexPosn
+                     | TG AlexPosn
+                     | TLE AlexPosn
+                     | TGE AlexPosn
+                     | TSemiColon AlexPosn
+                     | TAs AlexPosn
+                     | TInteger AlexPosn Int
+                     | TIdent AlexPosn String
+                     | TAssign AlexPosn
+                     | TString AlexPosn String
+                     deriving (Eq, Show)
+
+
+alexScanTokens' :: String -> Either String [ConstraintToken]
+alexScanTokens' str = case go (alexStartPos, '\n', str) of
+                          [] -> Right []
+                          cs -> case last cs of 
+                                  Left a -> Left a
+                                  _      -> Right (rights cs)
+  where go inp@(pos,_,str) =
+          case alexScan inp 0 of
+                AlexEOF -> []
+                AlexError _ -> [Left $ "Lexical error on " ++ showPos pos
+                                        ++ if null str then "."
+                                             else ". Not a valid token: '" ++ (head . words $ str) ++ "'"]
+                AlexSkip  inp' len     -> go inp'
+                AlexToken inp' len act -> Right (act pos (take len str)): go inp'
+
+showPos (AlexPn _ li co) = unwords ["line", show li, ", column", show co]
+
+showTokenPos (TExtension p)  = showPos p
+showTokenPos (TLanguage p)   = showPos p
+showTokenPos (TProject p)    = showPos p
+showTokenPos (TFilename p)   = showPos p
+showTokenPos (TYear p)       = showPos p
+showTokenPos (TMonth p)      = showPos p
+showTokenPos (TDay p)        = showPos p
+showTokenPos (TDow p)        = showPos p
+showTokenPos (TDoy p)        = showPos p
+showTokenPos (TGroup p)      = showPos p
+showTokenPos (TDontGroup p)  = showPos p
+showTokenPos (TAscending p)  = showPos p
+showTokenPos (TDescending p) = showPos p
+showTokenPos (TLimit p)      = showPos p
+showTokenPos (TParenOpen p)  = showPos p
+showTokenPos (TParenClose p) = showPos p
+showTokenPos (TComma p)      = showPos p
+showTokenPos (TProduct p)    = showPos p
+showTokenPos (TEqual p)      = showPos p
+showTokenPos (TNEqual p)     = showPos p
+showTokenPos (TL p)          = showPos p
+showTokenPos (TG p)          = showPos p
+showTokenPos (TLE p)         = showPos p
+showTokenPos (TGE p)         = showPos p
+showTokenPos (TInteger p _)  = showPos p
+showTokenPos (TString p _)   = showPos p
+showTokenPos (TAssign p)     = showPos p
+showTokenPos (TIdent p _)    = showPos p
+showTokenPos (TSemiColon p)  = showPos p
+showTokenPos (TAs p)         = showPos p
+
+alex_action_2 =  \p s -> TL p                      
+alex_action_3 =  \p s -> TG p                      
+alex_action_4 =  \p s -> TLE p                     
+alex_action_5 =  \p s -> TGE p                     
+alex_action_6 =  \p s -> TEqual p                  
+alex_action_7 =  \p s -> TEqual p                  
+alex_action_8 =  \p s -> TNEqual p                 
+alex_action_9 =  \p s -> TNEqual p                 
+alex_action_10 =  \p s -> TParenOpen p              
+alex_action_11 =  \p s -> TParenClose p             
+alex_action_12 =  \p s -> TComma p                  
+alex_action_13 =  \p s -> TProduct p                
+alex_action_14 =  \p s -> TAssign p                 
+alex_action_15 =  \p s -> TSemiColon p              
+alex_action_16 =  \p s -> TExtension p              
+alex_action_17 =  \p s -> TExtension p              
+alex_action_18 =  \p s -> TExtension p              
+alex_action_19 =  \p s -> TExtension p              
+alex_action_20 =  \p s -> TExtension p              
+alex_action_21 =  \p s -> TLanguage p               
+alex_action_22 =  \p s -> TLanguage p               
+alex_action_23 =  \p s -> TLanguage p               
+alex_action_24 =  \p s -> TLanguage p               
+alex_action_25 =  \p s -> TLanguage p               
+alex_action_26 =  \p s -> TProject p                
+alex_action_27 =  \p s -> TProject p                
+alex_action_28 =  \p s -> TProject p                
+alex_action_29 =  \p s -> TProject p                
+alex_action_30 =  \p s -> TFilename p               
+alex_action_31 =  \p s -> TFilename p               
+alex_action_32 =  \p s -> TFilename p               
+alex_action_33 =  \p s -> TFilename p               
+alex_action_34 =  \p s -> TFilename p               
+alex_action_35 =  \p s -> TYear p                   
+alex_action_36 =  \p s -> TYear p                   
+alex_action_37 =  \p s -> TYear p                   
+alex_action_38 =  \p s -> TMonth p                  
+alex_action_39 =  \p s -> TMonth p                  
+alex_action_40 =  \p s -> TMonth p                  
+alex_action_41 =  \p s -> TDay p                    
+alex_action_42 =  \p s -> TDay p                    
+alex_action_43 =  \p s -> TDay p                    
+alex_action_44 =  \p s -> TDow p                    
+alex_action_45 =  \p s -> TDoy p                    
+alex_action_46 =  \p s -> TAscending p              
+alex_action_47 =  \p s -> TDescending p             
+alex_action_48 =  \p s -> TAscending p              
+alex_action_49 =  \p s -> TAs p                     
+alex_action_50 =  \p s -> TDescending p             
+alex_action_51 =  \p s -> TLimit p                  
+alex_action_52 =  \p s -> TGroup p                  
+alex_action_53 =  \p s -> TGroup p                  
+alex_action_54 =  \p s -> TDontGroup p              
+alex_action_55 =  \p s -> TDontGroup p              
+alex_action_56 =  \p s -> TDontGroup p              
+alex_action_57 =  \p s -> TInteger p (read s)       
+alex_action_58 =  \p s -> TIdent p s                
+alex_action_59 =  \p s -> TString p (init (tail s)) 
+{-# 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 35 "templates/GenericTemplate.hs" #-}
+
+{-# LINE 45 "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/report/report-tmp/QueryParser.hs b/dist/build/report/report-tmp/QueryParser.hs
new file mode 100644
--- /dev/null
+++ b/dist/build/report/report-tmp/QueryParser.hs
@@ -0,0 +1,897 @@
+{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}
+{-# OPTIONS -fglasgow-exts -cpp #-}
+module QueryParser (ParseResult, parseCommands, parseFile) where
+
+import Prelude hiding (catch)
+import qualified Control.Exception as C
+
+import QueryLexer
+import QueryAST
+#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 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20 = 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 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn4 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn4 #-}
+happyOut4 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t4
+happyOut4 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut4 #-}
+happyIn5 :: t5 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn5 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn5 #-}
+happyOut5 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t5
+happyOut5 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut5 #-}
+happyIn6 :: t6 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn6 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn6 #-}
+happyOut6 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t6
+happyOut6 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut6 #-}
+happyIn7 :: t7 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn7 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn7 #-}
+happyOut7 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t7
+happyOut7 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut7 #-}
+happyIn8 :: t8 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn8 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn8 #-}
+happyOut8 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t8
+happyOut8 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut8 #-}
+happyIn9 :: t9 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn9 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn9 #-}
+happyOut9 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t9
+happyOut9 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut9 #-}
+happyIn10 :: t10 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn10 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn10 #-}
+happyOut10 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t10
+happyOut10 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut10 #-}
+happyIn11 :: t11 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn11 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn11 #-}
+happyOut11 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t11
+happyOut11 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut11 #-}
+happyIn12 :: t12 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn12 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn12 #-}
+happyOut12 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t12
+happyOut12 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut12 #-}
+happyIn13 :: t13 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn13 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn13 #-}
+happyOut13 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t13
+happyOut13 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut13 #-}
+happyIn14 :: t14 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn14 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn14 #-}
+happyOut14 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t14
+happyOut14 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut14 #-}
+happyIn15 :: t15 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn15 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn15 #-}
+happyOut15 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t15
+happyOut15 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut15 #-}
+happyIn16 :: t16 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn16 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn16 #-}
+happyOut16 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t16
+happyOut16 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut16 #-}
+happyIn17 :: t17 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn17 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn17 #-}
+happyOut17 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t17
+happyOut17 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut17 #-}
+happyIn18 :: t18 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn18 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn18 #-}
+happyOut18 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t18
+happyOut18 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut18 #-}
+happyIn19 :: t19 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn19 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn19 #-}
+happyOut19 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t19
+happyOut19 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut19 #-}
+happyIn20 :: t20 -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyIn20 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyIn20 #-}
+happyOut20 :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> t20
+happyOut20 x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOut20 #-}
+happyInTok :: (ConstraintToken) -> (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20)
+happyInTok x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyInTok #-}
+happyOutTok :: (HappyAbsSyn t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 t16 t17 t18 t19 t20) -> (ConstraintToken)
+happyOutTok x = Happy_GHC_Exts.unsafeCoerce# x
+{-# INLINE happyOutTok #-}
+
+
+happyActOffsets :: HappyAddr
+happyActOffsets = HappyA# "\x42\x00\x42\x00\x42\x00\x00\x00\x79\x00\x00\x00\x7a\x00\x00\x00\x2e\x00\x00\x00\x00\x00\x78\x00\x63\x00\x2f\x00\x75\x00\x00\x00\x00\x00\x75\x00\x40\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x74\x00\x73\x00\x76\x00\x00\x00\x5f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x62\x00\x53\x00\x00\x00\x1e\x00\x1d\x00\x61\x00\x19\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4d\x00\x00\x00\x00\x00"#
+
+happyGotoOffsets :: HappyAddr
+happyGotoOffsets = HappyA# "\x4f\x00\x24\x00\x6d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x59\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x00\x00\x52\x00\x51\x00\x00\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3d\x00\x3a\x00\x00\x00\x2b\x00\x00\x00\x00\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
+
+happyDefActions :: HappyAddr
+happyDefActions = HappyA# "\xef\xff\x00\x00\xef\xff\xfa\xff\x00\x00\xf7\xff\xf8\xff\xf5\xff\x00\x00\xf1\xff\xf0\xff\xf2\xff\x00\x00\xef\xff\xfc\xff\xf9\xff\xfb\xff\xfd\xff\xef\xff\xe3\xff\xee\xff\xed\xff\xec\xff\xeb\xff\xea\xff\xe9\xff\xe8\xff\xe7\xff\xe6\xff\xef\xff\xf4\xff\xf2\xff\x00\x00\xdc\xff\xe4\xff\xe2\xff\x00\x00\xde\xff\xda\xff\xdb\xff\xd9\xff\xd8\xff\xd6\xff\xd7\xff\x00\x00\xd5\xff\xd4\xff\xf6\xff\x00\x00\xdf\xff\x00\x00\xd1\xff\x00\x00\x00\x00\xe0\xff\xdd\xff\xcf\xff\xd3\xff\xd2\xff\xe1\xff\xe5\xff\xf3\xff\x00\x00\xd0\xff"#
+
+happyCheck :: HappyAddr
+happyCheck = HappyA# "\xff\xff\x10\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x12\x00\x13\x00\x14\x00\x15\x00\x16\x00\x05\x00\x06\x00\x07\x00\x06\x00\x07\x00\x1c\x00\x1d\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x12\x00\x13\x00\x14\x00\x15\x00\x16\x00\x1c\x00\x1d\x00\x1a\x00\x1b\x00\x0e\x00\x1c\x00\x1d\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x12\x00\x13\x00\x14\x00\x15\x00\x16\x00\x08\x00\x17\x00\x18\x00\x0b\x00\x0f\x00\x0d\x00\x0e\x00\x0e\x00\x1e\x00\x1f\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x17\x00\x18\x00\x17\x00\x18\x00\x08\x00\x09\x00\x0c\x00\x1e\x00\x0d\x00\x1e\x00\x08\x00\x09\x00\x0a\x00\x0b\x00\x08\x00\x0d\x00\x0e\x00\x08\x00\x1c\x00\x0a\x00\x0b\x00\x0a\x00\x0d\x00\x0e\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x1c\x00\x1d\x00\x19\x00\x1d\x00\x09\x00\x0d\x00\x0c\x00\x1f\x00\x0b\x00\x0a\x00\x0c\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"#
+
+happyTable :: HappyAddr
+happyTable = HappyA# "\x00\x00\x3d\x00\x27\x00\x28\x00\x29\x00\x2a\x00\x2b\x00\x2c\x00\x2d\x00\x10\x00\x11\x00\x05\x00\x06\x00\x07\x00\x08\x00\x15\x00\x16\x00\x17\x00\x18\x00\x19\x00\x1a\x00\x1b\x00\x1c\x00\x1d\x00\x2f\x00\x07\x00\x08\x00\x1e\x00\x08\x00\x2e\x00\x2f\x00\x27\x00\x28\x00\x29\x00\x2a\x00\x2b\x00\x2c\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08\x00\x15\x00\x16\x00\x17\x00\x18\x00\x19\x00\x1a\x00\x1b\x00\x1c\x00\x1d\x00\x2e\x00\x2f\x00\x3a\x00\x3b\x00\x36\x00\x2e\x00\x2f\x00\x15\x00\x16\x00\x17\x00\x18\x00\x19\x00\x1a\x00\x1b\x00\x1c\x00\x1d\x00\x20\x00\x0a\x00\x0b\x00\x3b\x00\x38\x00\x24\x00\x25\x00\x31\x00\x0c\x00\xfe\xff\x0c\x00\x0d\x00\x03\x00\x0e\x00\x05\x00\x06\x00\x07\x00\x08\x00\x0a\x00\x0b\x00\x0a\x00\x0b\x00\x3d\x00\x33\x00\x33\x00\x20\x00\x35\x00\x0c\x00\x20\x00\x21\x00\x22\x00\x23\x00\x13\x00\x24\x00\x25\x00\x20\x00\x40\x00\x30\x00\x23\x00\x1e\x00\x24\x00\x25\x00\x10\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08\x00\x27\x00\x28\x00\x29\x00\x2a\x00\x2b\x00\x2c\x00\x2e\x00\x2f\x00\x3f\x00\x38\x00\x33\x00\x35\x00\x10\x00\xff\xff\x13\x00\x1e\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
+
+happyReduceArr = Happy_Data_Array.array (1, 48) [
+	(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),
+	(10 , happyReduce_10),
+	(11 , happyReduce_11),
+	(12 , happyReduce_12),
+	(13 , happyReduce_13),
+	(14 , happyReduce_14),
+	(15 , happyReduce_15),
+	(16 , happyReduce_16),
+	(17 , happyReduce_17),
+	(18 , happyReduce_18),
+	(19 , happyReduce_19),
+	(20 , happyReduce_20),
+	(21 , happyReduce_21),
+	(22 , happyReduce_22),
+	(23 , happyReduce_23),
+	(24 , happyReduce_24),
+	(25 , happyReduce_25),
+	(26 , happyReduce_26),
+	(27 , happyReduce_27),
+	(28 , happyReduce_28),
+	(29 , happyReduce_29),
+	(30 , happyReduce_30),
+	(31 , happyReduce_31),
+	(32 , happyReduce_32),
+	(33 , happyReduce_33),
+	(34 , happyReduce_34),
+	(35 , happyReduce_35),
+	(36 , happyReduce_36),
+	(37 , happyReduce_37),
+	(38 , happyReduce_38),
+	(39 , happyReduce_39),
+	(40 , happyReduce_40),
+	(41 , happyReduce_41),
+	(42 , happyReduce_42),
+	(43 , happyReduce_43),
+	(44 , happyReduce_44),
+	(45 , happyReduce_45),
+	(46 , happyReduce_46),
+	(47 , happyReduce_47),
+	(48 , happyReduce_48)
+	]
+
+happy_n_terms = 32 :: Int
+happy_n_nonterms = 17 :: Int
+
+happyReduce_1 = happySpecReduce_1  0# happyReduction_1
+happyReduction_1 happy_x_1
+	 =  case happyOut5 happy_x_1 of { happy_var_1 -> 
+	happyIn4
+		 (happy_var_1
+	)}
+
+happyReduce_2 = happySpecReduce_2  0# happyReduction_2
+happyReduction_2 happy_x_2
+	happy_x_1
+	 =  case happyOut5 happy_x_1 of { happy_var_1 -> 
+	case happyOut7 happy_x_2 of { happy_var_2 -> 
+	happyIn4
+		 (happy_var_1 ++ [happy_var_2]
+	)}}
+
+happyReduce_3 = happySpecReduce_1  0# happyReduction_3
+happyReduction_3 happy_x_1
+	 =  case happyOut7 happy_x_1 of { happy_var_1 -> 
+	happyIn4
+		 ([happy_var_1]
+	)}
+
+happyReduce_4 = happySpecReduce_2  1# happyReduction_4
+happyReduction_4 happy_x_2
+	happy_x_1
+	 =  case happyOut5 happy_x_1 of { happy_var_1 -> 
+	case happyOut6 happy_x_2 of { happy_var_2 -> 
+	happyIn5
+		 (happy_var_1 ++ [happy_var_2]
+	)}}
+
+happyReduce_5 = happySpecReduce_1  1# happyReduction_5
+happyReduction_5 happy_x_1
+	 =  case happyOut6 happy_x_1 of { happy_var_1 -> 
+	happyIn5
+		 ([happy_var_1]
+	)}
+
+happyReduce_6 = happySpecReduce_2  2# happyReduction_6
+happyReduction_6 happy_x_2
+	happy_x_1
+	 =  case happyOut7 happy_x_1 of { happy_var_1 -> 
+	happyIn6
+		 (happy_var_1
+	)}
+
+happyReduce_7 = happySpecReduce_1  3# happyReduction_7
+happyReduction_7 happy_x_1
+	 =  case happyOut9 happy_x_1 of { happy_var_1 -> 
+	happyIn7
+		 (Left happy_var_1
+	)}
+
+happyReduce_8 = happySpecReduce_1  3# happyReduction_8
+happyReduction_8 happy_x_1
+	 =  case happyOut8 happy_x_1 of { happy_var_1 -> 
+	happyIn7
+		 (Right happy_var_1
+	)}
+
+happyReduce_9 = happySpecReduce_3  4# happyReduction_9
+happyReduction_9 happy_x_3
+	happy_x_2
+	happy_x_1
+	 =  case happyOutTok happy_x_1 of { (TIdent p happy_var_1) -> 
+	case happyOut9 happy_x_3 of { happy_var_3 -> 
+	happyIn8
+		 (QAssign happy_var_1 happy_var_3
+	)}}
+
+happyReduce_10 = happySpecReduce_1  5# happyReduction_10
+happyReduction_10 happy_x_1
+	 =  case happyOut10 happy_x_1 of { happy_var_1 -> 
+	happyIn9
+		 ([happy_var_1]
+	)}
+
+happyReduce_11 = happySpecReduce_3  5# happyReduction_11
+happyReduction_11 happy_x_3
+	happy_x_2
+	happy_x_1
+	 =  case happyOut9 happy_x_1 of { happy_var_1 -> 
+	case happyOut10 happy_x_3 of { happy_var_3 -> 
+	happyIn9
+		 (happy_var_1 ++ [happy_var_3]
+	)}}
+
+happyReduce_12 = happyMonadReduce 6# 6# happyReduction_12
+happyReduction_12 (happy_x_6 `HappyStk`
+	happy_x_5 `HappyStk`
+	happy_x_4 `HappyStk`
+	happy_x_3 `HappyStk`
+	happy_x_2 `HappyStk`
+	happy_x_1 `HappyStk`
+	happyRest) tk
+	 = happyThen (case happyOut11 happy_x_1 of { happy_var_1 -> 
+	case happyOut12 happy_x_2 of { happy_var_2 -> 
+	case happyOut13 happy_x_3 of { happy_var_3 -> 
+	case happyOut16 happy_x_4 of { happy_var_4 -> 
+	case happyOut19 happy_x_5 of { happy_var_5 -> 
+	case happyOut20 happy_x_6 of { happy_var_6 -> 
+	( if typeCheckConstraints happy_var_2 happy_var_3 
+                                        then return $ QSubQuery happy_var_1 happy_var_2 happy_var_3 happy_var_4 happy_var_5 happy_var_6
+                                        else fail "Parse error in constraints: expecting an integer")}}}}}}
+	) (\r -> happyReturn (happyIn10 r))
+
+happyReduce_13 = happySpecReduce_1  6# happyReduction_13
+happyReduction_13 happy_x_1
+	 =  case happyOutTok happy_x_1 of { (TIdent p happy_var_1) -> 
+	happyIn10
+		 (QCall happy_var_1
+	)}
+
+happyReduce_14 = happySpecReduce_1  7# happyReduction_14
+happyReduction_14 happy_x_1
+	 =  happyIn11
+		 (True
+	)
+
+happyReduce_15 = happySpecReduce_1  7# happyReduction_15
+happyReduction_15 happy_x_1
+	 =  happyIn11
+		 (False
+	)
+
+happyReduce_16 = happySpecReduce_0  7# happyReduction_16
+happyReduction_16  =  happyIn11
+		 (True
+	)
+
+happyReduce_17 = happySpecReduce_1  8# happyReduction_17
+happyReduction_17 happy_x_1
+	 =  happyIn12
+		 (Ext
+	)
+
+happyReduce_18 = happySpecReduce_1  8# happyReduction_18
+happyReduction_18 happy_x_1
+	 =  happyIn12
+		 (Lang
+	)
+
+happyReduce_19 = happySpecReduce_1  8# happyReduction_19
+happyReduction_19 happy_x_1
+	 =  happyIn12
+		 (Proj
+	)
+
+happyReduce_20 = happySpecReduce_1  8# happyReduction_20
+happyReduction_20 happy_x_1
+	 =  happyIn12
+		 (File
+	)
+
+happyReduce_21 = happySpecReduce_1  8# happyReduction_21
+happyReduction_21 happy_x_1
+	 =  happyIn12
+		 (Year
+	)
+
+happyReduce_22 = happySpecReduce_1  8# happyReduction_22
+happyReduction_22 happy_x_1
+	 =  happyIn12
+		 (Month
+	)
+
+happyReduce_23 = happySpecReduce_1  8# happyReduction_23
+happyReduction_23 happy_x_1
+	 =  happyIn12
+		 (Day
+	)
+
+happyReduce_24 = happySpecReduce_1  8# happyReduction_24
+happyReduction_24 happy_x_1
+	 =  happyIn12
+		 (Dow
+	)
+
+happyReduce_25 = happySpecReduce_1  8# happyReduction_25
+happyReduction_25 happy_x_1
+	 =  happyIn12
+		 (Doy
+	)
+
+happyReduce_26 = happySpecReduce_3  9# happyReduction_26
+happyReduction_26 happy_x_3
+	happy_x_2
+	happy_x_1
+	 =  case happyOut14 happy_x_2 of { happy_var_2 -> 
+	happyIn13
+		 (happy_var_2
+	)}
+
+happyReduce_27 = happySpecReduce_1  9# happyReduction_27
+happyReduction_27 happy_x_1
+	 =  case happyOut14 happy_x_1 of { happy_var_1 -> 
+	happyIn13
+		 (happy_var_1
+	)}
+
+happyReduce_28 = happySpecReduce_0  9# happyReduction_28
+happyReduction_28  =  happyIn13
+		 ([]
+	)
+
+happyReduce_29 = happySpecReduce_1  10# happyReduction_29
+happyReduction_29 happy_x_1
+	 =  case happyOut15 happy_x_1 of { happy_var_1 -> 
+	happyIn14
+		 ([happy_var_1]
+	)}
+
+happyReduce_30 = happySpecReduce_3  10# happyReduction_30
+happyReduction_30 happy_x_3
+	happy_x_2
+	happy_x_1
+	 =  case happyOut14 happy_x_1 of { happy_var_1 -> 
+	case happyOut15 happy_x_3 of { happy_var_3 -> 
+	happyIn14
+		 (happy_var_1 ++ [happy_var_3]
+	)}}
+
+happyReduce_31 = happyMonadReduce 3# 11# happyReduction_31
+happyReduction_31 (happy_x_3 `HappyStk`
+	happy_x_2 `HappyStk`
+	happy_x_1 `HappyStk`
+	happyRest) tk
+	 = happyThen (case happyOut12 happy_x_1 of { happy_var_1 -> 
+	case happyOut17 happy_x_2 of { happy_var_2 -> 
+	case happyOut18 happy_x_3 of { happy_var_3 -> 
+	( typeCheckQC happy_var_1 happy_var_2 happy_var_3)}}}
+	) (\r -> happyReturn (happyIn15 r))
+
+happyReduce_32 = happySpecReduce_2  11# happyReduction_32
+happyReduction_32 happy_x_2
+	happy_x_1
+	 =  case happyOut17 happy_x_1 of { happy_var_1 -> 
+	case happyOut18 happy_x_2 of { happy_var_2 -> 
+	happyIn15
+		 (QCOE happy_var_1 happy_var_2
+	)}}
+
+happyReduce_33 = happySpecReduce_1  11# happyReduction_33
+happyReduction_33 happy_x_1
+	 =  case happyOut18 happy_x_1 of { happy_var_1 -> 
+	happyIn15
+		 (QCE happy_var_1
+	)}
+
+happyReduce_34 = happySpecReduce_2  12# happyReduction_34
+happyReduction_34 happy_x_2
+	happy_x_1
+	 =  case happyOutTok happy_x_2 of { (TString p happy_var_2) -> 
+	happyIn16
+		 (As happy_var_2
+	)}
+
+happyReduce_35 = happySpecReduce_0  12# happyReduction_35
+happyReduction_35  =  happyIn16
+		 (DefaultAs
+	)
+
+happyReduce_36 = happySpecReduce_1  13# happyReduction_36
+happyReduction_36 happy_x_1
+	 =  happyIn17
+		 (QL
+	)
+
+happyReduce_37 = happySpecReduce_1  13# happyReduction_37
+happyReduction_37 happy_x_1
+	 =  happyIn17
+		 (QG
+	)
+
+happyReduce_38 = happySpecReduce_1  13# happyReduction_38
+happyReduction_38 happy_x_1
+	 =  happyIn17
+		 (QLE
+	)
+
+happyReduce_39 = happySpecReduce_1  13# happyReduction_39
+happyReduction_39 happy_x_1
+	 =  happyIn17
+		 (QGE
+	)
+
+happyReduce_40 = happySpecReduce_1  13# happyReduction_40
+happyReduction_40 happy_x_1
+	 =  happyIn17
+		 (QE
+	)
+
+happyReduce_41 = happySpecReduce_1  13# happyReduction_41
+happyReduction_41 happy_x_1
+	 =  happyIn17
+		 (QNE
+	)
+
+happyReduce_42 = happySpecReduce_1  14# happyReduction_42
+happyReduction_42 happy_x_1
+	 =  case happyOutTok happy_x_1 of { (TInteger p happy_var_1) -> 
+	happyIn18
+		 (QInt happy_var_1
+	)}
+
+happyReduce_43 = happySpecReduce_1  14# happyReduction_43
+happyReduction_43 happy_x_1
+	 =  case happyOutTok happy_x_1 of { (TString p happy_var_1) -> 
+	happyIn18
+		 (QString happy_var_1
+	)}
+
+happyReduce_44 = happySpecReduce_1  15# happyReduction_44
+happyReduction_44 happy_x_1
+	 =  happyIn19
+		 (Asc
+	)
+
+happyReduce_45 = happySpecReduce_1  15# happyReduction_45
+happyReduction_45 happy_x_1
+	 =  happyIn19
+		 (Desc
+	)
+
+happyReduce_46 = happySpecReduce_0  15# happyReduction_46
+happyReduction_46  =  happyIn19
+		 (NoOrder
+	)
+
+happyReduce_47 = happySpecReduce_2  16# happyReduction_47
+happyReduction_47 happy_x_2
+	happy_x_1
+	 =  case happyOutTok happy_x_2 of { (TInteger p happy_var_2) -> 
+	happyIn20
+		 (Limit happy_var_2
+	)}
+
+happyReduce_48 = happySpecReduce_0  16# happyReduction_48
+happyReduction_48  =  happyIn20
+		 (NoLimit
+	)
+
+happyNewToken action sts stk [] =
+	happyDoAction 31# notHappyAtAll action sts stk []
+
+happyNewToken action sts stk (tk:tks) =
+	let cont i = happyDoAction i tk action sts stk tks in
+	case tk of {
+	TL p -> cont 1#;
+	TG p -> cont 2#;
+	TLE p -> cont 3#;
+	TGE p -> cont 4#;
+	TNEqual p -> cont 5#;
+	TEqual p -> cont 6#;
+	TParenOpen p -> cont 7#;
+	TParenClose p -> cont 8#;
+	TComma p -> cont 9#;
+	TProduct p -> cont 10#;
+	TAssign p -> cont 11#;
+	TSemiColon p -> cont 12#;
+	TAs p -> cont 13#;
+	TExtension p -> cont 14#;
+	TLanguage p -> cont 15#;
+	TProject p -> cont 16#;
+	TFilename p -> cont 17#;
+	TYear p -> cont 18#;
+	TMonth p -> cont 19#;
+	TDay p -> cont 20#;
+	TDow p -> cont 21#;
+	TDoy p -> cont 22#;
+	TGroup p -> cont 23#;
+	TDontGroup p -> cont 24#;
+	TLimit p -> cont 25#;
+	TAscending p -> cont 26#;
+	TDescending p -> cont 27#;
+	TInteger p happy_dollar_dollar -> cont 28#;
+	TString p happy_dollar_dollar -> cont 29#;
+	TIdent p happy_dollar_dollar -> cont 30#;
+	_ -> happyError' (tk:tks)
+	}
+
+happyError_ tk tks = happyError' (tk:tks)
+
+happyThen :: () => E a -> (a -> E b) -> E b
+happyThen = (>>=)
+happyReturn :: () => a -> E a
+happyReturn = (return)
+happyThen1 m k tks = (>>=) m (\a -> k a tks)
+happyReturn1 :: () => a -> b -> E a
+happyReturn1 = \a tks -> (return) a
+happyError' :: () => [(ConstraintToken)] -> E a
+happyError' = parseError
+
+queryParser tks = happySomeParser where
+  happySomeParser = happyThen (happyParse 0# tks) (\x -> happyReturn (happyOut4 x))
+
+happySeq = happyDontSeq
+
+
+typeCheckConstraints i cs = all typeCheck cs
+  where typeCheck (QC _ _ _) = True
+        typeCheck (QCOE _ e) = check e
+        typeCheck (QCE e) = check e
+        check e = if elem i [Year, Day, Doy] 
+                    then case e of { QInt _ -> True ; _ -> False }
+                    else True
+                            
+
+typeCheckQC a b c = if elem a [Year, Day, Doy] 
+                      then case c of 
+                            QInt _ -> return $ QC a b c
+                            QString s -> fail $ "Expecting an integer, but got string \"" ++ s ++ "\"" 
+                      else (return $ QC a b c)
+
+type ParseResult = E QCommands
+
+parseError    :: [ConstraintToken]  -> E a
+parseCommands :: String   -> ParseResult
+parseFile     :: FilePath -> IO ParseResult
+
+parseError    s = fail "Parse error."
+parseCommands s = case alexScanTokens' s of 
+                    Left err -> fail err
+                    Right a -> queryParser a
+parseFile     f = readFile f >>= return . parseCommands
+{-# 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.
