diff --git a/BioInf/ViennaRNA.hs b/BioInf/ViennaRNA.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/ViennaRNA.hs
@@ -0,0 +1,5 @@
+
+-- | Ease-of-use module exporting the major functionality.
+
+module BioInf.ViennaRNA where
+
diff --git a/BioInf/ViennaRNA/Internal.hs b/BioInf/ViennaRNA/Internal.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/ViennaRNA/Internal.hs
@@ -0,0 +1,33 @@
+
+-- | Internal mutex system to be used as long as the ViennaRNA package is not
+-- thread-safe.
+
+module BioInf.ViennaRNA.Internal
+  ( viennaRNAmutex
+  , withMutex
+  , unsafePerformIO
+  ) where
+
+import Control.Concurrent.MVar (MVar, newMVar, withMVar, takeMVar, putMVar)
+import System.IO.Unsafe (unsafePerformIO, unsafeInterleaveIO)
+import Debug.Trace
+
+-- | The mutex guarding single-threaded access to the @ViennaRNA@ bindings as
+-- long as the @C@ library is not multi-threaded.
+
+viennaRNAmutex ∷ MVar ()
+viennaRNAmutex = unsafePerformIO $! newMVar ()
+{-# NoInline viennaRNAmutex #-}
+
+-- | Work with the ViennaRNA mutex.
+--
+-- This version seems strict enough to not block indefinitely.
+
+withMutex ∷ IO a → IO a
+withMutex f = do
+  () ← takeMVar viennaRNAmutex
+  !x ← f
+  putMVar viennaRNAmutex ()
+  return $! x
+{-# NoInline withMutex #-}
+
diff --git a/BioInf/ViennaRNA/Parsers/RNAfold.hs b/BioInf/ViennaRNA/Parsers/RNAfold.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/ViennaRNA/Parsers/RNAfold.hs
@@ -0,0 +1,78 @@
+
+-- | An efficient pipes-based parser for @RNAfold@ output.
+
+module BioInf.ViennaRNA.Parsers.RNAfold where
+
+{-
+-- | Lazily read @RNAfold@ structures.
+--
+-- TODO use @pipes/machines@! we need lazy reading of files and live in an exceptt transformer stack!
+-- TODO generalize transformer stack
+
+readRNAfoldFiles
+  ∷ FilePath
+  → IO [RNAfoldResult]
+readRNAfoldFiles fp = do
+  let go [] = return []
+      go (f:fs) = do
+        bs ← unsafeInterleaveIO (putStrLn ("#" ++ f) >> decompress <$> BSL.readFile f)
+        let rs = either error id $ runExcept (bslToRNAfoldResult bs)
+        rss ← go fs
+        return $ rs ++ rss
+      go ∷ [FilePath] → IO [RNAfoldResult]
+  FP.find FP.always (FP.extension FP.==? ".gz")  (fp </> "structures") >>= go
+{-# NoInline readRNAfoldFiles #-}
+
+-- |
+
+bslToRNAfoldResult ∷ (Monad m) ⇒ BSL.ByteString → ExceptT String m [RNAfoldResult]
+bslToRNAfoldResult bs = do
+  case A.eitherResult $ A.parse pRNAfold bs of
+    Left e  → throwE e
+    Right r → return r
+{-# Inline bslToRNAfoldResult #-}
+
+-- | Parser for @RNAfold@ output. @RNAfold@ can have between 2 and 5 output lines.
+--
+-- TODO Extend the parser to deal with all cases. Our best hint is probably if
+-- there is whitespace in a line.
+--
+-- @
+-- echo "CCCAAAGGG\nCCCAAAGGG" | ./RNAfold -p
+-- CCCAAAGGG
+-- (((...))) ( -1.20)
+-- (((...))) [ -1.41]
+-- (((...))) { -1.20 d=1.06}
+--  frequency of mfe structure in ensemble 0.707288; ensemble diversity 1.67  
+-- CCCAAAGGG
+-- (((...))) ( -1.20)
+-- (((...))) [ -1.41]
+-- (((...))) { -1.20 d=1.06}
+--  frequency of mfe structure in ensemble 0.707288; ensemble diversity 1.67  
+-- @
+
+pRNAfold ∷ A.Parser [RNAfoldResult]
+pRNAfold = A.many1' go <* A.endOfInput where
+  go = do
+    -- 1. sequence
+    rnaFoldSequence       ← BS.copy <$> AC.takeWhile AC.isAlpha_ascii <* AC.skipSpace A.<?> "RNAfold sequence"
+    -- 2. mfe
+    rnaFoldMFEStruc       ← BS.copy <$> AC.takeTill AC.isSpace <* AC.skipSpace A.<?> "RNAfold MFE structure"
+    rnaFoldMFEEner        ← AC.char '(' *> AC.skipSpace *> AC.double <* AC.char ')' <* AC.skipSpace A.<?> "RNAfold MFE energy"
+    -- 3. ensemble
+    rnaFoldEnsembleStruc  ← BS.copy <$> AC.takeTill AC.isSpace <* AC.skipSpace
+    rnaFoldEnsembleEner   ← AC.char '[' *> AC.skipSpace *> AC.double <* AC.char ']' <* AC.skipSpace
+    -- 4. centroid
+    rnaFoldCentroidStruc  ← BS.copy <$> AC.takeTill AC.isSpace <* AC.skipSpace
+    rnaFoldCentroidEner   ← AC.char '{' *> AC.skipSpace *> AC.double <* AC.skipSpace
+    dequal                ← AC.string "d=" *> AC.double <* AC.char '}' <* AC.skipSpace
+    -- 5.mfe frequency and diversity
+    AC.string "frequency of mfe structure in ensemble" *> AC.skipSpace A.<?> "frequency"
+    rnaFoldMfeFrequency ← AC.double
+    AC.string "; ensemble diversity" *> AC.skipSpace
+    rnaFoldDiversity ← AC.double
+    AC.skipSpace
+    return RNAfoldResult{..}
+{-# Inline pRNAfold #-}
+-}
+
diff --git a/BioInf/ViennaRNA/Parsers/Types.hs b/BioInf/ViennaRNA/Parsers/Types.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/ViennaRNA/Parsers/Types.hs
@@ -0,0 +1,18 @@
+
+-- | Data types for the different @ViennaRNA@ outputs.
+--
+-- TODO I think these should be more generic types to be filled in by
+-- high-level functions...
+
+module BioInf.ViennaRNA.Parsers.Types where
+
+import Data.ByteString (ByteString)
+import GHC.Generics (Generic)
+import Control.Lens
+
+import Biobase.Types.Sequence
+import Biobase.Types.Structure
+import Biobase.Types.Energy
+
+
+
diff --git a/BioInf/ViennaRNA/RNAeval.hs b/BioInf/ViennaRNA/RNAeval.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/ViennaRNA/RNAeval.hs
@@ -0,0 +1,21 @@
+
+module BioInf.ViennaRNA.RNAeval where
+
+import Biobase.Types.Energy (DG(..))
+import Biobase.Types.Sequence (RNAseq(..))
+import Biobase.Types.Structure (RNAss(..))
+import BioInf.ViennaRNA.Bindings (eosTemp)
+
+import BioInf.ViennaRNA.Internal
+
+
+
+-- | High-level wrapper for energy-of-struct calculations similar to the
+-- command line @RNAeval@.
+
+rnaeval ∷ Double → RNAseq → RNAss → DG
+rnaeval t (RNAseq s1) (RNAss s2)
+  = unsafePerformIO . withMutex
+  $! DG <$> eosTemp t s1 s2
+{-# NoInline rnaeval #-}
+
diff --git a/BioInf/ViennaRNA/RNAfold.hs b/BioInf/ViennaRNA/RNAfold.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/ViennaRNA/RNAfold.hs
@@ -0,0 +1,265 @@
+
+-- | Everything needed to wrap @RNAfold@ results, parse lines with @RNAfold@
+-- input, fold a sequence with @rnafold@, and more.
+
+module BioInf.ViennaRNA.RNAfold
+  ( module BioInf.ViennaRNA.RNAfold
+  , module BioInf.ViennaRNA.Types
+  ) where
+
+import           Control.Arrow
+import           Control.DeepSeq
+import           Control.Lens
+import           Control.Monad (guard)
+import           Data.Attoparsec.ByteString as A
+import           Data.Attoparsec.ByteString.Char8 as A8
+import           Data.ByteString.Builder
+import           Data.ByteString (ByteString)
+import           Data.ByteString.Char8 as BS
+import           Data.Char (toUpper)
+import           Data.Maybe.Strict
+import           Data.Monoid
+import           Data.Tuple (swap)
+import           Debug.Trace
+import           GHC.Generics (Generic)
+import           Prelude hiding(Maybe(..))
+import           Test.QuickCheck as QC
+import           Text.Printf
+
+import           Biobase.Types.Energy
+import           Biobase.Types.Sequence (mkRNAseq, RNAseq(..), rnaseq)
+import           Biobase.Types.Structure
+import qualified BioInf.ViennaRNA.Bindings as Bindings
+
+import           BioInf.ViennaRNA.Internal
+import           BioInf.ViennaRNA.Types
+
+
+
+-- | Space-efficient RNAfold structure. RNAfold allows a DNA input, but this is
+-- not allowed in this data structure. If you want that, keep the original
+-- input string around.
+--
+-- This structure provides only @Getter@'s. Only the @sequenceID@ can be
+-- updated via @sequenceIDlens@. This is to prevent accidental updates of
+-- fields that are actually interdependent.
+--
+-- Missing parts are sloppily encoded by bogus values and empty strings. All
+-- @Folded@ structures and derived values are lazy. In case @rnafold@ was used
+-- to construct the structure, calculations are deferred until needed.
+--
+-- TODO newtype the sequence id.
+--
+-- TODO temperature. How to encode? Kelvin? In BiobaseTypes! Could use (Nat)SciTypes!
+--
+-- TODO complete BP probability array
+--
+-- TODO lazy fields for computation on demand!
+--
+-- TODO Wrapped via @Maybe@?
+
+data RNAfold = RNAfold
+  { _sequenceID   ∷ !ByteString
+  -- ^ Set to @not . null@ if the sequence was given a name. This is (likely) a
+  -- fasta-style identifier.
+  , _input        ∷ !RNAseq
+  -- ^ The input sequence, converting into an RNA string.
+  , _mfe          ∷ !Folded
+  -- ^ Minimum-free energy and corresponding structure.
+  , _mfeFrequency ∷ !Double
+  -- ^ The mfe frequency can be calculated as follows: @exp ((ensemble energy -
+  -- mfe energy) / kT)@.
+  --
+  -- ^ TODO newtype wrapper?
+  , _ensemble     ∷ !Folded
+  -- ^ Uses special syntax with unpaired, weakly paired, somewhat paired,
+  -- somewhat paired up or down, strongly paired up or down for the ensemble.
+  -- The energy is the *ensemble free energy*.
+  , _centroid     ∷ !Folded
+  -- ^ Centroid energy and structure.
+  , _centroidDistance ∷ !Double
+  -- ^ Centroid distance to ensemble.
+  , _diversity        ∷ !Double
+  -- ^ Average basepair distance between all structures in the Boltzmann
+  -- ensemble
+  --
+  -- TODO Needs own newtype?
+  , _temperature      ∷ !(Maybe Double)
+  -- ^ Temperature in Celsius
+  --
+  -- TODO own newtype Celsius
+  }
+  deriving (Read,Show,Eq,Ord,Generic)
+makeLensesWith (lensRules & generateUpdateableOptics .~ False) ''RNAfold
+makeLensesFor [("_sequenceID", "sequenceIDlens")] ''RNAfold
+
+instance NFData RNAfold
+
+
+
+-- | Fold a sequence.
+--
+-- This function is threadsafe via the viennaRNA-mutex.
+--
+-- TODO add temperature parameter
+--
+-- TODO consider creating a "super-lens" that updates whenever @_input@ or
+-- @_temperature@ change.
+
+rnafold ∷ RNAseq → RNAfold
+rnafold _input = unsafePerformIO . withMutex $! do
+  let _temperature = Just 37
+  let _sequenceID = ""
+  _mfe      ← uncurry Folded . swap <$> (DG *** RNAss) <$> Bindings.mfe (_input^.rnaseq)
+  (_centroid, _centroidDistance) ← (\(e,s,d) → (Folded (RNAss s) (DG e), d)) <$> Bindings.centroidTemp 37 (_input^.rnaseq)
+  -- fucked up from here
+  let k0 = 273.15
+  let gasconst = 1.98717 -- in kcal * (K^(-1)) * (mol^(-1))
+  let kT = (k0 + 37) * gasconst * 1000
+  let _ensemble = Folded (RNAss "DO NOT USE ME") (DG 999999)
+  let _diversity = 999999
+  -- the energy of the mfe structure calculated with @dangles=1@ model,
+  -- otherwise we get different mfe frequency values compared to rnafold.
+  let d1mfeenergy = 0
+  let _mfeFrequency = exp $ (_centroid^.foldedEnergy.to dG - d1mfeenergy) / kT
+  return $! RNAfold {..}
+{-# NoInline rnafold #-}
+
+
+
+data RNArewrite
+  = NoRewrite
+  | ForceRNA
+  deriving (Read,Show,Eq,Ord,Generic)
+
+-- | Parsing for 'RNAfold'. This should parse all variants that @RNAfold@
+-- produces.
+--
+-- The parser for a 'Folded' structure has to deal with different "energy"
+-- types. The different energies are bracketed by different types of brackets.
+--
+-- @
+-- mfe        (((...))) ( -1.20)
+-- ensemble   (((...))) [ -1.41]
+-- centroid   (((...))) { -1.20 d=1.06}
+-- @
+--
+-- TODO Move into submodule.
+--
+-- TODO pipes-based streaming parser
+--
+-- TODO how to handle parsing the BP probability array, if known?
+--
+-- TODO I think it is possible to figure the line type based on the energy and
+-- the brackets around the energy.
+
+pRNAfold
+  ∷ RNArewrite
+  → Double
+  → Parser RNAfold
+pRNAfold r celsius = do
+  let _temperature = Just celsius
+  let endedLine = A.takeTill isEndOfLine <* endOfLine
+  let s2line = A8.takeWhile1 (`BS.elem` "(.)") <* skipSpace
+  let ensline = A8.takeWhile1 (`BS.elem` "(){}.,|") <* skipSpace
+  let nope = Folded (RNAss "") (DG 0)
+  let rewrite = case r of
+        NoRewrite → id
+        ForceRNA  → BS.map (go . toUpper) where
+          go x
+            | x `BS.elem` "ACGUacgu" = x
+          go x   = 'N'
+  _sequenceID ← option "" $ char '>' *> endedLine
+  _input      ← RNAseq <$> rewrite <$> endedLine
+  let l = _input^.rnaseq.to BS.length
+  let lenGuard s2 = guard (BS.length s2 == l)
+        <?> ("s2 line length /= _input length: " ++ show (s2,_input) ++ "")
+  -- mfe is always present ?!
+  _mfe ← do s2 ← s2line
+            lenGuard s2
+            skipSpace
+            e  ← char '(' *> skipSpace *> signed double <* char ')'
+            let _foldedStructure = RNAss s2
+            let _foldedEnergy    = DG e
+            return Folded{..}
+            <?> "mfe"
+  -- from here on, things are optional, including the newline after the mfe
+  -- energy!
+  _ensemble ← option nope $
+    (do endOfLine
+        s2 ← ensline
+        lenGuard s2
+        skipSpace
+        e  ← char '[' *> skipSpace *> signed double <* char ']'
+        let _foldedStructure = RNAss s2
+        let _foldedEnergy    = DG e
+        return Folded{..}
+        <?> "ensemble")
+  (_centroid, _centroidDistance) ← option (nope, 0) $
+    (do endOfLine
+        s2 ← s2line
+        lenGuard s2
+        e ← char '{' *> skipSpace *> signed double
+        -- TODO handle @d@ values
+        d ← skipSpace *> "d=" *> skipSpace *> double
+        skipSpace *> char '}'
+        let _foldedStructure  = RNAss s2
+        let _foldedEnergy     = DG e
+        return (Folded{..}, d)
+        <?> "centroid")
+  (_mfeFrequency, _diversity) ← option (0, 0) $
+    (do endOfLine -- previous line ending
+        skipSpace
+        "frequency of mfe structure in ensemble"
+        skipSpace
+        f ← double
+        "; ensemble diversity"
+        skipSpace
+        ed ← double
+        skipSpace
+        return (f, ed)
+        <?> "mfe frequency / diversity")
+  return RNAfold{..}
+
+
+
+builderRNAfold ∷ RNAfold → Builder
+builderRNAfold RNAfold{..} = mconcat [hdr, sqnce, emfe, nsmbl, cntrd]
+  where
+    -- SLOW!
+    dbl d = byteString . BS.pack $ printf "%.2f" (d∷Double)
+    addFolded l r Folded{..} = if BS.null (_rnass _foldedStructure)
+                               then mempty
+                               else nl <> byteString (_rnass _foldedStructure) <> char7 ' '
+                                    <> char7 l <> dbl (dG _foldedEnergy) <> char7 r
+    nl = char7 '\n'
+    hdr = if BS.null _sequenceID then mempty else char7 '>' <> byteString _sequenceID <> nl
+    sqnce = byteString (_input^.rnaseq)
+    emfe = addFolded '(' ')' _mfe
+    nsmbl = addFolded '[' ']' _ensemble
+    cntrd = let s = _centroid^.foldedStructure.rnass
+            in if BS.null (_centroid^.foldedStructure.rnass)
+                then mempty
+                else nl <> byteString s <> " {"
+                     <> dbl (_centroid^.foldedEnergy.to dG)
+                     <> " d=" <> dbl _diversity <> "}"
+
+
+
+-- ** QuickCheck generator for 'RNAfold'. This is slightly unusual but allows
+-- us to generate random sequence/structure pairs easily.
+--
+-- This should only be used for quickcheck testing, not anything involving
+-- properties of random RNAs.
+--
+-- Generation is simple: A sequence with @[0,100]@ characters from @ACGU@ is
+-- generated and the 'RNAfold' structure is filled by 'rnafold'. We test for
+-- size @0@ explicitly, too!
+
+instance Arbitrary RNAfold where
+  -- Generate a sequence and calculate the structure for it.
+  arbitrary =  choose (0,100)
+            >>= \k → rnafold <$> mkRNAseq <$> BS.pack <$> vectorOf k (QC.elements "ACGU")
+  -- Try with all sequences missing one character.
+  shrink rna = [ rnafold $ mkRNAseq $ BS.pack s | s ← shrink $ rna^.input.rnaseq.to unpack ]
+
diff --git a/BioInf/ViennaRNA/Types.hs b/BioInf/ViennaRNA/Types.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/ViennaRNA/Types.hs
@@ -0,0 +1,23 @@
+
+module BioInf.ViennaRNA.Types where
+
+import Control.Lens
+import Control.DeepSeq
+import GHC.Generics (Generic)
+
+import Biobase.Types.Energy
+import Biobase.Types.Structure
+
+
+
+-- | Holds a pair of energy and structure.
+
+data Folded = Folded
+  { _foldedStructure  ∷ !RNAss
+  , _foldedEnergy     ∷ !DG
+  }
+  deriving (Read,Show,Eq,Ord,Generic)
+makeLensesWith (lensRules & generateUpdateableOptics .~ False) ''Folded
+
+instance NFData Folded
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Christian Hoener zu Siederdissen 2010-2013
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Christian Hoener zu Siederdissen nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,16 @@
+[![Build Status](https://travis-ci.org/choener/ViennaRNA-extras.svg?branch=master)](https://travis-ci.org/choener/ViennaRNA-extras)
+
+# ViennaRNA extras
+
+A number of high-level functions that extend the functionality provided by
+ViennaRNA-bindings.
+
+
+
+#### Contact
+
+Christian Hoener zu Siederdissen  
+Leipzig University, Leipzig, Germany  
+choener@bioinf.uni-leipzig.de  
+http://www.bioinf.uni-leipzig.de/~choener/  
+
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/ViennaRNA-extras.cabal b/ViennaRNA-extras.cabal
new file mode 100644
--- /dev/null
+++ b/ViennaRNA-extras.cabal
@@ -0,0 +1,137 @@
+name:           ViennaRNA-extras
+version:        0.0.0.1
+author:         Christian Hoener zu Siederdissen, 2017
+copyright:      Christian Hoener zu Siederdissen, 2017
+license:        BSD3
+license-file:   LICENSE
+category:       Bioinformatics
+homepage:       https://github.com/choener/ViennaRNA-extras
+bug-reports:    https://github.com/choener/ViennaRNA-extras/issues
+maintainer:     choener@bioinf.uni-leipzig.de
+build-type:     Simple
+stability:      experimental
+cabal-version:  >= 1.10.0
+tested-with:    GHC == 8.0.2, GHC == 8.2.1
+synopsis:       ViennaRNA v2 extensions
+description:    
+                Extra functionality on top of the ViennaRNA bindings. Please
+                note the special license of the ViennaRNA bindings (while the
+                -extras library is BSD3, it is not very useful without the
+                bindings)!
+                .
+                .
+                If you use this software, please cite:
+                .
+                @
+                R. Lorenz, S.H. Bernhart, C. Hoener zu Siederdissen, H. Tafer, C. Flamm, P.F. Stadler and I.L. Hofacker (2011)
+                ViennaRNA Package 2.0
+                Algorithms for Molecular Biology: 6:26
+                @
+                .
+                <http://www.almob.org/content/6/1/26>
+
+
+
+Extra-Source-Files:
+  README.md
+  changelog.md
+
+
+
+flag debug
+  description:  Enable bounds checking and various other debug operations
+  default:      False
+  manual:       True
+
+
+
+library
+  exposed-modules:
+    BioInf.ViennaRNA
+    BioInf.ViennaRNA.Internal
+    BioInf.ViennaRNA.Parsers.RNAfold
+    BioInf.ViennaRNA.Parsers.Types
+    BioInf.ViennaRNA.RNAeval
+    BioInf.ViennaRNA.RNAfold
+    BioInf.ViennaRNA.Types
+  build-depends: base                   >= 4.7    && < 5.0
+               , array
+               , attoparsec             >= 0.13
+               , bytestring
+               , deepseq                >= 1.4
+               , lens                   >= 4.0
+--               , pipes                  >= 4.0
+               , QuickCheck             >= 2.0
+               , streaming              >= 0.1
+               , streaming-bytestring   >= 0.1
+               , strict                 >= 0.3
+               , strict-base-types      >= 0.5
+               --
+               , BiobaseTypes           == 0.1.3.*
+               , BiobaseXNA             == 0.10.0.*
+               , ViennaRNA-bindings     == 0.233.2.*
+  default-language:
+    Haskell2010
+  default-extensions: BangPatterns
+                    , DeriveDataTypeable
+                    , DeriveGeneric
+                    , GeneralizedNewtypeDeriving
+                    , OverloadedStrings
+                    , RecordWildCards
+                    , TemplateHaskell
+                    , UnicodeSyntax
+  ghc-options:
+    -O2 -funbox-strict-fields
+  if flag(debug)
+--    cpp-options: -DADPFUSION_CHECKS
+    ghc-options: -fno-ignore-asserts -O0
+
+
+
+test-suite properties
+  type:
+    exitcode-stdio-1.0
+  main-is:
+    properties.hs
+  ghc-options:
+    -threaded -rtsopts -with-rtsopts=-N
+  hs-source-dirs:
+    tests
+  default-language:
+    Haskell2010
+  default-extensions: BangPatterns
+                    , CPP
+                    , FlexibleContexts
+                    , FlexibleInstances
+                    , MultiParamTypeClasses
+                    , OverloadedStrings
+                    , ScopedTypeVariables
+                    , TemplateHaskell
+                    , TypeFamilies
+                    , TypeOperators
+                    , TypeSynonymInstances
+                    , UnicodeSyntax
+  build-depends: base
+               , attoparsec
+               , bytestring
+               , QuickCheck
+               , tasty                        >= 0.11
+               , tasty-quickcheck             >= 0.8
+               , tasty-th                     >= 0.1
+               , vector
+               --
+               , ViennaRNA-extras
+
+
+
+-- its a library, get it from hackage
+
+--source-repository this
+--  type: git
+--  location: git://github.com/choener/ViennaRNA-extras/tree/0.0.0.1
+--  tag: 0.0.0.1
+
+source-repository head
+  type: git
+  location: git://github.com/choener/ViennaRNA-extras
+
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,5 @@
+0.0.0.1
+-------
+
+- constraints to partial sums over base pair probability matrices
+
diff --git a/tests/properties.hs b/tests/properties.hs
new file mode 100644
--- /dev/null
+++ b/tests/properties.hs
@@ -0,0 +1,52 @@
+
+-- |
+--
+-- TODO golden tests of known good RNAfold output as parser input
+--
+-- TODO re-enable the build/parse paired tests.
+
+module Main where
+
+import Data.Attoparsec.ByteString.Char8 as A8
+import Data.ByteString.Builder
+import Data.ByteString.Lazy.Char8 (toStrict)
+import Data.List (intersperse)
+import Debug.Trace
+import Test.QuickCheck
+import Test.Tasty
+import Test.Tasty.QuickCheck (testProperty)
+import Test.Tasty.TH
+
+import BioInf.ViennaRNA.RNAfold
+
+-- prop_build ∷ RNAfold → Bool
+-- prop_build r
+--   | True = traceShow lbs False
+--   where
+--     bld = builderRNAfold r
+--     lbs = toStrict $ toLazyByteString bld
+-- 
+-- prop_build_parse ∷ RNAfold → Bool
+-- prop_build_parse r
+--   | Left err ← ap = traceShow (err,r) False
+--   | Right pr ← ap = pr == r
+--   where
+--     -- the final builder of all @RNAfold@ structures
+--     bld = builderRNAfold r
+--     lbs = toStrict $ toLazyByteString bld
+--     ap  = parseOnly ((pRNAfold NoRewrite 37) <* endOfInput) lbs
+-- 
+-- 
+-- prop_builds_parses ∷ [RNAfold] → Bool
+-- prop_builds_parses rs
+--   | Left err  ← ap = traceShow err False
+--   | Right prs ← ap = prs == rs
+--   where
+--     -- the final builder of all @RNAfold@ structures
+--     bld = mconcat $ intersperse "\n" $ map builderRNAfold rs
+--     lbs = toStrict $ toLazyByteString bld
+--     ap  = parseOnly (many' (pRNAfold NoRewrite 37) <* endOfInput) lbs
+
+main ∷ IO ()
+main = $(defaultMainGenerator)
+
