packages feed

cobot-io (empty) → 0.1.2.0

raw patch · 46 files changed

+5105/−0 lines, 46 filesdep +QuickCheckdep +arraydep +attoparsecsetup-changed

Dependencies added: QuickCheck, array, attoparsec, base, binary, bytestring, cobot-io, containers, data-msgpack, deepseq, hspec, http-conduit, hyraxAbif, lens, linear, mtl, neat-interpolation, split, text, vector

Files

+ ChangeLog.md view
@@ -0,0 +1,27 @@+# Changelog for cobot-io++## [Unreleased]++## [0.1.2.0] - 2019-09-03+### Added+- Parser for `FASTA`.+- Writer for `FASTA`.++## [0.1.1.1] - 2019-06-05+### Changed+- `length` on `Sequence` now works in O(1).++## [0.1.1.0] - 2019-05-13+### Added+- New version of module Bio.Sequence hat introduces `IsSequence` type class and `Sequence` datatype.+- Type `GenBankSequence` describing structure of .gb file.+- Parser for `GenBankSequence`.+- Writer for `GenBankSequence`.+### Changed+- ABI cleaner and decoder now work with type `ABIRaw`.++## [0.1.0.1] - 2019-02-28+### Added+- Field `chemCompType` in `Residue`.+### Fixed+- `codec10`.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Author name here (c) 2019++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 Author name here 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.
+ README.md view
@@ -0,0 +1,4 @@+# cobot-io++[![Travis](https://img.shields.io/travis/less-wrong/cobot-io.svg)](https://travis-ci.org/less-wrong/cobot-io)+[![license](https://img.shields.io/github/license/less-wrong/cobot-io.svg)]()
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cobot-io.cabal view
@@ -0,0 +1,126 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: b952542571739fbdf02508e11db35e6059993b82d37e4f7e27825e5c83fedfb1++name:           cobot-io+version:        0.1.2.0+synopsis:       Biological data file formats and IO+description:    Please see the README on GitHub at <https://github.com/less-wrong/cobot-io#readme>+category:       Bio+homepage:       https://github.com/less-wrong/cobot-io#readme+bug-reports:    https://github.com/less-wrong/cobot-io/issues+author:         Pavel Yakovlev, Bogdan Neterebskii, Alexander Sadovnikov+maintainer:     pavel@yakovlev.me+copyright:      2018-2019, Less Wrong Bio+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    ChangeLog.md++source-repository head+  type: git+  location: https://github.com/less-wrong/cobot-io++library+  exposed-modules:+      Bio.ABI+      Bio.ABI.Clean+      Bio.ABI.Decode+      Bio.FASTA+      Bio.FASTA.Parser+      Bio.FASTA.Type+      Bio.FASTA.Writer+      Bio.GB+      Bio.GB.Parser+      Bio.GB.Type+      Bio.GB.Writer+      Bio.MMTF+      Bio.MMTF.Decode+      Bio.MMTF.Decode.Codec+      Bio.MMTF.Decode.MessagePack+      Bio.MMTF.MessagePack+      Bio.MMTF.Type+      Bio.PDB+      Bio.PDB.Type+      Bio.Sequence+      Bio.Sequence.Basecalled+      Bio.Sequence.Basecalled.Type+      Bio.Sequence.Class+      Bio.Sequence.Functions.Marking+      Bio.Sequence.Functions.Sequence+      Bio.Sequence.Functions.Weight+      Bio.Sequence.Utilities+      Bio.Structure+      Bio.Uniprot+      Bio.Uniprot.Parser+      Bio.Uniprot.Type+  other-modules:+      Paths_cobot_io+  hs-source-dirs:+      src+  default-extensions: DeriveGeneric DeriveFunctor DeriveFoldable DeriveAnyClass FlexibleInstances InstanceSigs MultiParamTypeClasses RecordWildCards ScopedTypeVariables OverloadedStrings TypeFamilies DataKinds ConstraintKinds TypeOperators TemplateHaskell FlexibleContexts+  build-depends:+      array >=0.5 && <0.6+    , attoparsec >=0.10 && <0.14+    , base >=4.7 && <5+    , binary >=0.8.3.0 && <1.0+    , bytestring >=0.10.8.1 && <0.11+    , containers >=0.5.7.1 && <0.7+    , data-msgpack >=0.0.9 && <0.1+    , deepseq >=1.4 && <1.5+    , http-conduit >=2.3 && <2.4+    , hyraxAbif >=0.2.3.15 && <0.2.4.0+    , lens >=4.16 && <5.0+    , linear >=1.20 && <1.21+    , mtl >=2.2.1 && <2.3.0+    , split+    , text >=1.2.2.1 && <1.3+    , vector+  default-language: Haskell2010++test-suite cobot-io-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      ABISpec+      FastaParserSpec+      FASTASpec+      FastaWriterSpec+      GBParserSpec+      GBWriterSpec+      MMTFSpec+      SequenceSpec+      UniprotSpec+      Paths_cobot_io+  hs-source-dirs:+      test+  default-extensions: OverloadedStrings TypeFamilies+  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      QuickCheck >=2.9.2 && <2.13+    , array >=0.5 && <0.6+    , attoparsec >=0.10 && <0.14+    , base >=4.7 && <5+    , binary >=0.8.3.0 && <1.0+    , bytestring >=0.10.8.1 && <0.11+    , cobot-io+    , containers >=0.5.7.1 && <0.7+    , data-msgpack >=0.0.9 && <0.1+    , deepseq >=1.4 && <1.5+    , hspec >=2.4.1 && <2.7+    , http-conduit >=2.3 && <2.4+    , hyraxAbif >=0.2.3.15 && <0.2.4.0+    , lens >=4.16 && <5.0+    , linear >=1.20 && <1.21+    , mtl >=2.2.1 && <2.3.0+    , neat-interpolation >=0.3+    , split+    , text >=1.2.2.1 && <1.3+    , vector+  default-language: Haskell2010
+ src/Bio/ABI.hs view
@@ -0,0 +1,7 @@+module Bio.ABI +  ( module Bio.ABI.Clean+  ) where++import Bio.ABI.Clean+import Bio.ABI.Decode ()+
+ src/Bio/ABI/Clean.hs view
@@ -0,0 +1,77 @@+module Bio.ABI.Clean+  ( Cleanable (..)+  , Thresholds (..)+  ) where++import           Bio.Sequence            (mean, meanInRange)+import qualified Bio.Sequence            as S (drop, length, reverse, tail)+import           Bio.Sequence.Basecalled (BasecalledSequence)+import           Control.Monad           (join)++-- | Ability to clean initial data.+-- Returns cleaned variant or 'Nothing' if it can not be cleaned.+--+class Cleanable a where+  clean :: a -> Maybe a+  clean = cleanWith defaultThresholds++  cleanWith :: Thresholds -> a -> Maybe a++-- | Thresholds to clean the data.+-- ABI file contains sequence with quality.+-- By design of sanger sequencing method start and end of the sequence have bad quality.+-- Moreover, internal part of the sequence can also has bad quality.+-- To clean the data we make 2 steps.+--+-- Step 1. Clean edges:+--   * take frame with @frameSize@ and go through the sequence;+--   * on each step evaluate mean value;+--   * if mean value less than @edgeThreshold@, go further;+--   * if mean value more than @edgeThreshold@, stop and cut the sequence from END of this frame;+--   * repeat this algorithm for the right edge.+--+-- Step 2. Evaluate quality:+--   * for cropped sequence evaluate mean value;+--   * if mean value less then @innerThreshold@, sequence is bad;+--   * if mean value more then @innerThreshold@, sequence is acceptable.+--+-- Logic of this algorithm and 'defaultThresholds' were obtained by taking experiments with read ABI files.+--+data Thresholds+   = Thresholds { frameSize      :: Int+                , edgeThreshold  :: Double+                , innerThreshold :: Double+                }+  deriving (Eq, Show)++-- | This thresholds were selected by many experiments on ab1-files.+--+defaultThresholds :: Thresholds+defaultThresholds = Thresholds 10 20 30++instance Cleanable BasecalledSequence where+  cleanWith thr input = if fmap (checkInner thr) fromBoth == Just True+                          then fromBoth+                          else Nothing+    where+      fromLeft = cutEdge defaultThresholds input+      fromBoth =  fmap S.reverse+               .  join+               $  cutEdge defaultThresholds+               .  S.reverse+              <$> fromLeft++-------------------------------------------------------------------------------+-- INTERNAL+-------------------------------------------------------------------------------++checkInner :: Thresholds -> BasecalledSequence -> Bool+checkInner Thresholds{..} = (> innerThreshold) . mean++cutEdge :: Thresholds -> BasecalledSequence -> Maybe BasecalledSequence+cutEdge t@Thresholds{..} sequ | S.length sequ < frameSize                    = Just sequ+                              | meanInR < edgeThreshold && S.length sequ > 1 = cutEdge t $ S.tail sequ+                              | S.length sequ > frameSize                    = Just $ S.drop frameSize sequ+                              | otherwise                                    = Nothing+  where+    meanInR = meanInRange sequ (0, frameSize - 1)
+ src/Bio/ABI/Decode.hs view
@@ -0,0 +1,71 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Bio.ABI.Decode () where++import           Bio.Sequence               (SequenceDecodable (..),+                                             weightedSequence)+import           Bio.Sequence.Basecalled    (BasecalledSequence)+import           Data.ByteString            as BS (ByteString)+import           Data.ByteString.Lazy       as BSL (ByteString, fromStrict)+import           Data.ByteString.Lazy.Char8 as BSL8 (unpack)+import           Data.Char                  (ord)+import           Data.List                  (elem, find)+import           Data.Maybe                 (maybe)+import           Data.Text                  (Text)+import           Hyrax.Abif                 (Abif (..), Directory (..))+import           Hyrax.Abif.Read            (getAbif)++-- | Converts 'Data.ByteString.Lazy.ByteString' (that should be content of ABI file)+-- into 'BasecalledSequence'.+--+instance SequenceDecodable BSL.ByteString BasecalledSequence where+    sequenceDecode :: BSL.ByteString -> Either Text BasecalledSequence+    sequenceDecode bs = do+        abif      <- getAbif bs+        sequence' <- extractSequence abif+        quality'  <- extractQuality  abif+        weightedSequence sequence' quality'++-- | Converts 'Data.ByteString.ByteString' (that should be content of ABI file)+-- into 'BasecalledSequence'.+--+instance SequenceDecodable BS.ByteString BasecalledSequence where+    sequenceDecode :: BS.ByteString -> Either Text BasecalledSequence+    sequenceDecode = sequenceDecode . BSL.fromStrict++-------------------------------------------------------------------------------+-- INTERNAL+-------------------------------------------------------------------------------++-- | Extracts sequence from ABI file.+--+extractSequence :: Abif -> Either Text String+extractSequence abif = findDataByDirectory "PBAS" abif >>= checkACGT++-- | Extracts quality from ABI file.+-- Number are encoded with letters, thus we have function @fromIntegral . ord@.+--+extractQuality :: Abif -> Either Text [Double]+extractQuality abif = map (fromIntegral . ord) <$> findDataByDirectory "PCON" abif++-- | Checks that all chars are from alphabet ACGT+--+checkACGT :: String -> Either Text String+checkACGT str | all validChar str = Right str+              | otherwise         = Left "Bio.ABI.Decode: could not parse sequence"+  where+    validChar :: Char -> Bool+    validChar ch = ch `elem` ['A', 'C', 'G', 'T']++-- | Looks into ABI file and extract data by 'Directory' name.+--+findDataByDirectory :: Text -> Abif -> Either Text String+findDataByDirectory dirName abif =+    let directoryM = find (\Directory{..} -> dTagName == dirName) . aDirs $ abif+    in maybe (Left errorMsg) (Right . getData) directoryM+  where+    errorMsg :: Text+    errorMsg = "Bio.ABI.Decode: could not find directory " <> dirName++    getData :: Directory -> String+    getData = BSL8.unpack . dData
+ src/Bio/FASTA.hs view
@@ -0,0 +1,24 @@+module Bio.FASTA+  ( module T+  , fromFile+  , toFile+  , fastaP+  ) where++import           Bio.FASTA.Parser+import           Bio.FASTA.Type             as T+import           Bio.FASTA.Writer           (fastaToText)+import           Control.Monad.IO.Class     (MonadIO, liftIO)+import           Data.Attoparsec.Text       (parseOnly)+import           Data.Text.IO               (readFile, writeFile)+import           Prelude            hiding  (writeFile, readFile)++-- | Reads 'FastaSequence' from given file.+--+fromFile :: MonadIO m => FilePath -> m (Fasta Char)+fromFile f = liftIO (readFile f) >>= either fail pure . parseOnly fastaP++-- | Writes 'FastaSequence' to file.+--+toFile :: MonadIO m => Fasta Char -> FilePath -> m ()+toFile s f = liftIO $ writeFile f $ fastaToText s
+ src/Bio/FASTA/Parser.hs view
@@ -0,0 +1,37 @@+module Bio.FASTA.Parser+  ( fastaP+  ) where++import           Bio.FASTA.Type         (Fasta, FastaItem(..))+import           Bio.Sequence           (BareSequence, bareSequence)+import           Data.Attoparsec.Text   (Parser, many', many1', char, endOfLine, letter,+                                            takeWhile, choice, endOfInput)+import           Data.Text              (Text, strip)+import           Prelude         hiding (takeWhile)++-- | Parser of .fasta file.+--+fastaP :: Parser (Fasta Char)+fastaP = many' item++item :: Parser (FastaItem Char)+item = FastaItem <$> seqName <*> fastaSeq++seqName :: Parser (Text)+seqName = strip <$> (char '>' *> tabs *> takeWhile (`notElem` ['\n', '\r']) <* tabs <* eol)++fastaSeq :: Parser (BareSequence Char)+fastaSeq = bareSequence . mconcat <$> many' line++line :: Parser (String)+line = many1' letter <* eol++eol :: Parser ()+eol = tabs *> choice [slashN, endOfInput]++slashN :: Parser ()+slashN = () <$ many1' endOfLine++tabs :: Parser ()+tabs = () <$ many' (char '\t')+
+ src/Bio/FASTA/Type.hs view
@@ -0,0 +1,19 @@+module Bio.FASTA.Type+  ( Fasta+  , FastaItem (..)+  ) where++import           Bio.Sequence (BareSequence)+import           Data.Text    (Text)++-- | Type alias for FASTA file.+--  satisfies the following format : >(\s|\t)*[^\n\r]+(\s|\t)*(\n|\r)*(\w(\n|\r)*)*+type Fasta a = [FastaItem a]++-- | One record in FASTA file.+--+data FastaItem a+   = FastaItem { name :: Text           -- ^ name of the sequence+               , sequ :: BareSequence a -- ^ bare sequence+               }+  deriving (Eq, Show, Functor)
+ src/Bio/FASTA/Writer.hs view
@@ -0,0 +1,23 @@+module Bio.FASTA.Writer+  ( fastaToText+  ) where++import           Bio.FASTA.Type     (Fasta, FastaItem(..))+import           Bio.Sequence       (BareSequence, sequ)+import           Control.Lens       ((^.))+import           Data.Text          (Text, pack)+import           Data.List.Split    (chunksOf)+import           Data.Vector        (Vector, toList)+import           Prelude     hiding (drop)++fastaToText :: Fasta Char -> Text+fastaToText f = mconcat $ map writeItem f++writeItem :: FastaItem Char -> Text+writeItem (FastaItem name s) = ">" <> name <> "\n" <> seq2Text s++seq2Text :: BareSequence Char -> Text+seq2Text s = pack $ vector2Text $ s ^. Bio.Sequence.sequ++vector2Text :: Vector Char -> String+vector2Text v = concatMap (++ "\n") $ chunksOf 80 $ toList v
+ src/Bio/GB.hs view
@@ -0,0 +1,38 @@+module Bio.GB+  ( module T+  , fromFile+  , toFile+  , fromText+  , toText+  , genBankP+  ) where++import           Bio.GB.Parser+import           Bio.GB.Type            as T+import           Bio.GB.Writer          (genBankToText)+import           Control.Monad.IO.Class (MonadIO, liftIO)+import           Data.Attoparsec.Text   (parseOnly)+import           Data.Bifunctor         (first)+import           Data.Text              (Text)+import           Data.Text              (pack)+import qualified Data.Text.IO           as TIO (readFile, writeFile)++-- | Reads 'GenBankSequence' from givem file.+--+fromFile :: MonadIO m => FilePath -> m GenBankSequence+fromFile f = liftIO (TIO.readFile f) >>= either fail pure . parseOnly genBankP++-- | Writes 'GenBankSequence' to file.+--+toFile :: MonadIO m => GenBankSequence -> FilePath -> m ()+toFile s f = liftIO $ TIO.writeFile f $ genBankToText s++-- | Reads 'GenBankSequence' from 'Text'.+--+fromText :: Text -> Either Text GenBankSequence+fromText = first pack . parseOnly genBankP++-- | Writes 'GenBankSequence' to 'Text'.+--+toText :: GenBankSequence -> Text+toText = genBankToText
+ src/Bio/GB/Parser.hs view
@@ -0,0 +1,216 @@+{-# LANGUAGE OverloadedStrings #-}++module Bio.GB.Parser+  ( genBankP+  ) where++import           Bio.GB.Type          (Feature (..), Form (..),+                                       GenBankSequence (..), Locus (..),+                                       Meta (..), Reference (..), Source (..),+                                       Version (..))+import           Bio.Sequence         (MarkedSequence, Range, markedSequence)+import           Control.Applicative  ((<|>))+import           Data.Attoparsec.Text (Parser, char, decimal, digit, endOfInput,+                                       endOfLine, letter, many', many1',+                                       satisfy, string, takeWhile, takeWhile1)+import           Data.Bifunctor       (bimap)+import           Data.Char            (isAlphaNum, isSpace, isUpper)+import           Data.Functor         (($>))+import           Data.Text            (Text, intercalate, pack, splitOn, unpack)+import           Prelude              hiding (takeWhile)++-- | Parser of .gb file.+--+genBankP :: Parser GenBankSequence+genBankP =  GenBankSequence+        <$> metaP+        <*> gbSeqP+        <*  string "//" <* eolSpaceP <* endOfInput++--------------------------------------------------------------------------------+-- Block with meta-information.+--------------------------------------------------------------------------------++metaP :: Parser Meta+metaP = do+  locus'      <- locusP++  definitionM <- wrapMP definitionP+  accessionM  <- wrapMP accessionP+  versionM    <- wrapMP versionP+  keywordsM   <- wrapMP keywordsP+  sourceM     <- wrapMP sourceP+  referencesL <- many' referenceP+  commentsL   <- many' commentP++  pure $ Meta locus' definitionM accessionM versionM keywordsM sourceM referencesL commentsL++locusP :: Parser Locus+locusP = string "LOCUS" *> space *> (Locus+       <$> textP <* space                                      -- name+       <*> decimal <* space <* string "bp" <* space            -- sequence length+       <*> textP <* space                                      -- molecule type+       <*> wrapMP formP <* space                               -- form of sequence+       <*> wrapMP (pack <$> many1' (satisfy isUpper)) <* space -- GenBank division+       <*> textP                                               -- modification date+       <*  eolSpaceP)+  where+    textP = takeWhile1 $ not . isSpace++    formP :: Parser Form+    formP = (string "linear" $> Linear) <|> (string "circular" *> pure Circular)++definitionP :: Parser Text+definitionP =  string "DEFINITION" *> space *> (emptyP <|> someLinesP)++accessionP :: Parser Text+accessionP =  string "ACCESSION" *> space *> (emptyP <|> (pack+          <$> many1' (alphaNumChar <|> char '_')+          <*  eolSpaceP))++versionP :: Parser Version+versionP =  string "VERSION" *> space+         *> ((Version <$> emptyP <*> pure Nothing) <|> (Version+        <$> (pack <$> many1' versionP')+        <*> wrapMP (pack <$> (space *> string "GI:" *> many1' versionP'))+        <*  eolSpaceP))+  where+    versionP' = alphaNumChar <|> char '_' <|> char '.'++keywordsP :: Parser Text+keywordsP =  string "KEYWORDS"+          *> (emptyP+         <|> (space *> textWithSpacesP <* eolSpaceP))++sourceP :: Parser Source+sourceP =  string "SOURCE" *> space+        *> ((flip Source Nothing <$> emptyP) <|> (Source+       <$> someLinesP+       <*> wrapMP organismP))+  where+    organismP = string "  ORGANISM" *> space *> someLinesP++referenceP :: Parser Reference+referenceP = string "REFERENCE" *> space+           *> (((\x -> Reference x Nothing Nothing Nothing Nothing) <$> emptyP) <|> (Reference+          <$> someLinesP+          <*> wrapMP (string "  AUTHORS" *> space *> someLinesP)+          <*> wrapMP (string "  TITLE" *> space *> someLinesP)+          <*> wrapMP (string "  JOURNAL" *> space *> someLinesP)+          <*> wrapMP (string "  PUBMED" *> space *> someLinesP)))++commentP :: Parser Text+commentP = string "COMMENT" *> (emptyP <|> (many' (char ' ') *> someLinesP))++--------------------------------------------------------------------------------+-- Block with FEATURES table.+--------------------------------------------------------------------------------++featuresP :: Parser [(Feature, Range)]+featuresP =  string "FEATURES" *> space+          *> textWithSpacesP <* eolSpaceP+          *> many1' featureP++featureP :: Parser (Feature, Range)+featureP = do+    _ <- string featureIndent1++    featureName'      <- takeWhile (not . isSpace) <* space+    (strand53, range) <- rangeP <* eolSpaceP++    props <- many1' propsP++    pure (Feature featureName' strand53 props, range)++rangeP :: Parser (Bool, Range)+rangeP =  (string "complement(" *> rP False <* char ')') <|> rP True+  where+    rP :: Bool -> Parser (Bool, Range)+    rP b =  fmap (bimap pred id)+        <$> (,) b+        <$> (((,) <$> decimal <* string ".." <*> decimal) <|> ((\x -> (x, x)) <$> decimal))++propsP :: Parser (Text, Text)+propsP = do+    _ <- string featureIndent2+    _ <- char '/'+    propName <- takeWhile1 (/= '=')+    _ <- char '='++    propText <- ((char '\"' *> takeWhile1 (/= '\"') <* char '\"')+             <|> textWithSpacesP)+             <* eolSpaceP++    let propTextCorrect = mconcat $ filter (/= featureIndent2) $ splitOn featureIndent2 propText++    pure (propName, propTextCorrect)++-- | First level of identation in FEATURES table file.+--+featureIndent1 :: Text+featureIndent1 = pack $ replicate 5 ' '++-- | Second level of identation in FEATURES table file.+--+featureIndent2 :: Text+featureIndent2 = pack $ replicate 21 ' '++--------------------------------------------------------------------------------+-- Block with ORIGIN table.+--------------------------------------------------------------------------------++originP :: Parser String+originP =  string "ORIGIN" *> eolSpaceP+        *> pure toText+       <*> many1' (space *> many1' digit *> space1+        *> many1' (many1' letter <* (space1 <|> eolSpaceP)))+  where+    toText :: [[String]] -> String+    toText = concat . fmap concat++--------------------------------------------------------------------------------+-- Parser of 'GenBankSequence' from FEATURES and ORIGIN tables.+--------------------------------------------------------------------------------+gbSeqP :: Parser (MarkedSequence Feature Char)+gbSeqP = do+    features <- featuresP+    origin   <- originP++    either (fail . unpack) pure (markedSequence origin features)++--------------------------------------------------------------------------------+-- Utility functions.+--------------------------------------------------------------------------------++-- | First level of identation in .gb file.+--+firstIndent :: Text+firstIndent = pack $ replicate 12 ' '++eolSpaceP :: Parser ()+eolSpaceP = () <$ many' (char ' ') <* endOfLine++emptyP :: Parser Text+emptyP = many' (char ' ') *> char '.' *> eolSpaceP *> pure "."++textWithSpacesP :: Parser Text+textWithSpacesP = takeWhile (`notElem` ['\n', '\r'])++someLinesP :: Parser Text+someLinesP = intercalate "\n" <$> someLinesIndentP firstIndent++someLinesIndentP :: Text -> Parser [Text]+someLinesIndentP indent =  (:) <$> textWithSpacesP <* eolSpaceP+                       <*> (many' (string indent *> textWithSpacesP <* eolSpaceP))++wrapMP :: Parser a -> Parser (Maybe a)+wrapMP p = fmap Just p <|> pure Nothing++space :: Parser ()+space = () <$ (many' $ satisfy isSpace)++space1 :: Parser ()+space1 = () <$ (many1' $ satisfy isSpace)++alphaNumChar :: Parser Char+alphaNumChar = satisfy isAlphaNum
+ src/Bio/GB/Type.hs view
@@ -0,0 +1,102 @@+module Bio.GB.Type+  ( GenBankSequence (..)+  , Meta (..)+  , Form (..)+  , Locus (..)+  , Version (..)+  , Source (..)+  , Reference (..)+  , Feature (..)+  ) where++import           Bio.Sequence (IsMarking, MarkedSequence)+import           Data.Text    (Text)++-- | Type that represents contents of .gb file that is used to store information about+-- genetic constructions.+--+data GenBankSequence = GenBankSequence { meta  :: Meta                        -- ^ meta-information about the sequence+                                       , gbSeq :: MarkedSequence Feature Char -- ^ sequence that is marked by 'Feature's+                                       }+  deriving (Eq, Show)++--------------------------------------------------------------------------------+-- Block with meta-information.+--------------------------------------------------------------------------------++-- | Meta-information about sequence.+--+data Meta = Meta { locus      :: Locus         -- ^ general info about sequence+                 , definition :: Maybe Text    -- ^ brief description of sequence+                 , accession  :: Maybe Text    -- ^ the unique identifier for a sequence record+                 , version    :: Maybe Version -- ^ id of sequence in GenBank database+                 , keywords   :: Maybe Text    -- ^ word or phrase describing the sequence+                 , source     :: Maybe Source  -- ^ free-format information including an abbreviated form of the organism name,+                                               --   sometimes followed by a molecule type+                 , references :: [Reference]   -- ^ publications by the authors of the sequence that discuss the data reported in the record+                 , comments   :: [Text]        -- ^ comments about the sequence (note that there can be (!!!) empty comments)+                 }+  deriving (Eq, Show)++-- | First line that should be present in every .gb file. Contains general info about sequence.+--+data Locus = Locus { name             :: Text       -- ^ name of sequence+                   , len              :: Int        -- ^ length of sequence+                   , molType          :: Text       -- ^ type of molecule that is sequenced+                   , form             :: Maybe Form -- ^ form of sequence+                   , gbDivision       :: Maybe Text -- ^ GenBank division to which a record belongs+                   , modificationDate :: Text       -- ^ date of last modification of sequence+                   }+  deriving (Eq, Show)++-- | At this moment there are two known (to me)+-- forms of seuqences that can be present in .gb file.+--+data Form = Linear | Circular+  deriving (Eq, Show)++-- | Id of sequence in GenBank database.+--+data Version = Version { versionT :: Text       -- ^ id itself+                       , gbId     :: Maybe Text -- ^ GenInfo Identifier that is assigned when sequence changes+                       }+  deriving (Eq, Show)++-- | Information about source of this sequence.+--+data Source = Source { sourceT  :: Text       -- ^ free-format (as if all this format is not too much "free format") information+                                              -- including an abbreviated form of the organism name,+                                              -- sometimes followed by a molecule type+                     , organism :: Maybe Text -- ^ the formal scientific name for the source organism+                     }+  deriving (Eq, Show)++-- | Publications by the authors of the sequence that discuss the data reported in the record.+--+data Reference = Reference { referenceT :: Text       -- ^ reference itself+                           , authors    :: Maybe Text -- ^ list of authors in the order in which they appear in the cited article+                           , title      :: Maybe Text -- ^ title of the published work+                           , journal    :: Maybe Text -- ^ MEDLINE abbreviation of the journal name+                           , pubmed     :: Maybe Text -- ^ PubMed Identifier+                           }+  deriving (Eq, Show)++--------------------------------------------------------------------------------+-- Block with FEATURES table.+--+-- FEATURES table contains information about genes and gene products, as well as regions of biological+-- significance reported in the sequence. These can include regions of the sequence+-- that code for proteins and RNA molecules, as well as a number of other features.+-- More about FEATURES table: http://www.insdc.org/documents/feature_table.html+--------------------------------------------------------------------------------++-- | One single feature.+--+data Feature = Feature { fName     :: Text           -- ^ main information about feature+                       , fStrand53 :: Bool           -- ^ set to True if sequence is contained on 5'-3' strand.+                                                     --   Set to False otherwise+                       , fProps    :: [(Text, Text)] -- ^ properties of feature (such as "label", "gene", "note" etc.)+                       }+  deriving (Eq, Show, Ord)++instance IsMarking Feature
+ src/Bio/GB/Writer.hs view
@@ -0,0 +1,189 @@+module Bio.GB.Writer+  ( genBankToText+  ) where++import           Bio.GB.Type     (Feature (..), GenBankSequence (..),+                                  Locus (..), Meta (..), Reference (..),+                                  Source (..), Version (..))+import           Bio.Sequence    (Range, markings, toList)+import           Control.Lens    ((^.))+import qualified Data.List.Split as S (chunksOf)+import           Data.Maybe      (fromMaybe)+import           Data.Text       (Text)+import qualified Data.Text       as T (append, chunksOf, intercalate, length,+                                       lines, null, pack, toLower, unwords)++genBankToText :: GenBankSequence -> Text+genBankToText GenBankSequence{..} = interNewLine parts <> "\n"+  where+    parts = [ metaToText meta+            , featuresToText $ gbSeq ^. markings+            , originToText $ T.pack $ toList gbSeq+            , "//"+            ]++--------------------------------------------------------------------------------+-- Block with meta-information.+--------------------------------------------------------------------------------++metaToText :: Meta -> Text+metaToText Meta{..} = interNewLine parts+  where+    parts = [ locusToText locus+            , textFromMaybe $ fmap (processMany metaIndent "DEFINITION") definition+            , textFromMaybe $ fmap (processMany metaIndent "ACCESSION") accession+            , textFromMaybe $ fmap versionToText version+            , textFromMaybe $ fmap (processMany metaIndent "KEYWORDS") keywords+            , textFromMaybe $ fmap sourceToText source+            ]+            <> fmap referenceToText references+            <> fmap (processMany metaIndent "COMMENT") comments++locusToText :: Locus -> Text+locusToText Locus{..} = toIndent metaIndent "LOCUS" <> locusText+  where+    locusList = [ name+                , showText len <> " bp"+                , molType+                , textFromMaybe $ fmap (T.toLower . showText) form+                , textFromMaybe gbDivision+                , modificationDate+                ]++    locusText = T.intercalate (spaces 5) $ filter (not . T.null) locusList++sourceToText :: Source -> Text+sourceToText Source{..} = interNewLine $ mainPart : pure (textFromMaybe organismPart)+  where+    mainPart     = processMany metaIndent "SOURCE" sourceT+    organismPart = fmap (processMany metaIndent (prependIndent metaPreIndent "ORGANISM")) organism++versionToText :: Version -> Text+versionToText Version{..} = toIndent metaIndent "VERSION" <> version+   where+     version = versionT <> spaces 5 <> maybe mempty ("GI:" <>) gbId++referenceToText :: Reference -> Text+referenceToText Reference{..} = interNewLine $ mainPart : parts+  where+    mainPart = processMany metaIndent "REFERENCE" referenceT++    sectionNames = fmap (prependIndent metaPreIndent) ["AUTHORS", "TITLE", "JOURNAL", "PUBMED"]+    sections     = [authors, title, journal, pubmed]++    parts = zipWith (\a -> textFromMaybe . fmap (processMany metaIndent a)) sectionNames sections++-- | Indentation of data in section with metainformation.+--+metaIndent :: Int+metaIndent = 12++-- | Indentation in subsections of section with meta-information.+--+metaPreIndent :: Int+metaPreIndent = 2++featuresToText :: [(Feature, Range)] -> Text+featuresToText l = interNewLine $ mainPart : sections+  where+    mainPart = processMany featuresIndent "FEATURES" featuresText+    sections = fmap featureToText l++    featuresText :: Text+    featuresText = "Location/Qualifiers"++--------------------------------------------------------------------------------+-- Block with FEATURES section.+--------------------------------------------------------------------------------++featureToText :: (Feature, Range) -> Text+featureToText (Feature{..}, range) = interNewLine $ mainPart : sections+  where+    mainPart = processMany featuresIndent (prependIndent featuresPreIndent fName) (featureRangeToText fStrand53 range)+    sections = fmap featurePropToText fProps++featurePropToText :: (Text, Text) -> Text+featurePropToText (nameF, textF) = mainPart+  where+    mainPart = processMany featuresIndent mempty ("/" <> nameF <> "=\"" <> textF <> "\"")++featureRangeToText :: Bool -> Range -> Text+featureRangeToText complement (l, r) | l == r - 1 = processComplement complement $ showText (l + 1)+                                     | otherwise  = processComplement complement $ showText (l + 1) <> ".." <> showText r+  where+    processComplement :: Bool -> Text -> Text+    processComplement True  text = text+    processComplement False text = "complement(" <> text <> ")"++-- | Indentation of feature's properties in FEATURES section.+--+featuresIndent :: Int+featuresIndent = 21++-- | Indentation in subsections of FEATURES section.+--+featuresPreIndent :: Int+featuresPreIndent = 5++--------------------------------------------------------------------------------+-- Block with ORIGIN table.+--------------------------------------------------------------------------------++originToText :: Text -> Text+originToText text = interNewLine $ mainPart : parts+  where+    mainPart = "ORIGIN"++    manyLines = S.chunksOf lengthOfLineChunk $ T.chunksOf lengthOfChunk text+    parts     = zipWith processLine [1, 1 + lengthOfChunk * lengthOfLineChunk..] manyLines++    processLine :: Int -> [Text] -> Text+    processLine startInd = T.unwords . (prependIndent (originIndent - T.length indText) indText :)+      where+        indText = showText startInd++    -- | Number of nucleotides in one chunk.+    --+    lengthOfChunk :: Int+    lengthOfChunk = 10++    -- | Number of chunks per line of sequence in ORIGIN section.+    --+    lengthOfLineChunk :: Int+    lengthOfLineChunk = 6++-- | Indentation of new line of sequence in ORIGIN section.+--+originIndent :: Int+originIndent = 9++--------------------------------------------------------------------------------+-- Utility functions.+--------------------------------------------------------------------------------++processMany :: Int -> Text -> Text -> Text+processMany indent name ""   = toIndent indent name+processMany indent name text = interNewLine resLines+  where+    (x : xs) = T.lines text++    resLines = toIndent indent name <> x+             : fmap (prependIndent indent) xs++interNewLine :: [Text] -> Text+interNewLine = T.intercalate "\n" . filter (not . T.null)++textFromMaybe :: Maybe Text -> Text+textFromMaybe = fromMaybe mempty++toIndent :: Int -> Text -> Text+toIndent indent name = name <> (spaces $ indent - (T.length name))++prependIndent :: Int -> Text -> Text+prependIndent = T.append . spaces++showText :: Show a => a -> Text+showText = T.pack . show++spaces :: Int -> Text+spaces = T.pack . flip replicate ' '
+ src/Bio/MMTF.hs view
@@ -0,0 +1,88 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Bio.MMTF+  ( module Bio.MMTF.Type+  , decode+  , fetch+  ) where++import           Bio.MMTF.MessagePack   ()+import           Bio.MMTF.Type   hiding ( IArray )+import           Bio.MMTF.Decode        ( l2a )+import           Bio.Structure++import           Data.Array             ( Array, (!), elems )+import           Data.Int               ( Int32 )+import           Data.Bifunctor         ( Bifunctor (..) )+import           Data.List              ( mapAccumL, zip3, zip4 )+import           Data.Text              ( Text )+import           Data.ByteString.Lazy   ( ByteString )+import           Data.MessagePack       ( unpack )+import           Data.Monoid            ( (<>) )+import           Data.String            ( IsString (..) )+import           Control.Monad.IO.Class ( MonadIO )+import           Network.HTTP.Simple    ( httpLBS, getResponseBody )+import           Linear.V3              ( V3 (..) )++-- | Decodes a 'ByteString' to 'MMTF'+--+decode :: Monad m => ByteString -> m MMTF+decode = unpack++-- | Fetches MMTF structure from RSCB+fetch :: MonadIO m => String -> m MMTF+fetch pdbid = do let url = fromString $ "https://mmtf.rcsb.org/v1.0/full/" <> pdbid+                 resp <- httpLBS url+                 decode (getResponseBody resp) ++instance StructureModels MMTF where+    modelsOf m = l2a (Model . l2a <$> zipWith (zipWith Chain) chainNames chainResis)+      where+        chainsCnts = fromIntegral <$> elems (chainsPerModel (model m))+        groupsCnts = fromIntegral <$> elems (groupsPerChain (chain m))+        groupsRaws = snd $ mapAccumL getGroups (0, 0) groupsCnts+        groups     = cutter chainsCnts groupsRaws+        chainNames = cutter chainsCnts (elems $ chainNameList $ chain m)+        chainResis = fmap (fmap (l2a . fmap mkResidue)) groups++        getGroups :: (Int, Int) -> Int -> ((Int, Int), [(GroupType, SecondaryStructure, [Atom])])+        getGroups (chOffset, atOffset) sz = let chEnd        = chOffset + sz+                                                gtl          = groupTypeList (group m)+                                                gl           = groupList (group m)+                                                ssl          = secStructList (group m)+                                                chr          = [chOffset .. chEnd - 1]+                                                rgt          = (gl !) . fromIntegral . (gtl !) <$> chr+                                                rss          = (ssl !) <$> chr+                                                (atEnd, ats) = mapAccumL getAtoms atOffset rgt+                                            in  ((chEnd, atEnd), zip3 rgt rss ats)++        getAtoms :: Int -> GroupType -> (Int, [Atom])+        getAtoms offset gt = let cl  = fmap fromIntegral . elems . gtFormalChargeList $ gt+                                 nl  = elems . gtAtomNameList $ gt+                                 el  = elems . gtElementList $ gt+                                 ics = [offset .. end - 1]+                                 end = offset + length cl+                             in  (end, mkAtom <$> zip4 cl nl el ics)++        mkResidue :: (GroupType, SecondaryStructure, [Atom]) -> Residue+        mkResidue (gt, ss, atoms) = Residue (gtGroupName gt) (l2a atoms)+                                            (mkBonds (gtBondAtomList gt) (gtBondOrderList gt))+                                             ss (gtChemCompType gt)++        mkBonds :: Array Int (Int32, Int32) -> Array Int Int32 -> Array Int Bond+        mkBonds bal bol = let ball = bimap fromIntegral fromIntegral <$> elems bal+                              boll = fromIntegral <$> elems bol+                              res  = zipWith (\(f, t) o -> Bond f t o) ball boll+                          in  l2a res++        mkAtom :: (Int, Text, Text, Int) -> Atom+        mkAtom (fc, n, e, idx) = let x = xCoordList (atom m)+                                     y = yCoordList (atom m)+                                     z = zCoordList (atom m)+                                     o = occupancyList (atom m)+                                     b = bFactorList (atom m)+                                 in  Atom n e (V3 (x ! idx) (y ! idx) (z ! idx)) fc (b ! idx) (o ! idx)++        cutter :: [Int] -> [a] -> [[a]]+        cutter []     []    = []+        cutter (x:xs) ys    = take x ys : cutter xs (drop x ys)+        cutter []     (_:_) = error "Cutter: you cannot be here"
+ src/Bio/MMTF/Decode.hs view
@@ -0,0 +1,141 @@+module Bio.MMTF.Decode where++import           Bio.MMTF.Decode.Codec+import           Bio.MMTF.Decode.MessagePack+import           Bio.MMTF.Type++import           Control.Monad               ((>=>))+import           Data.ByteString.Lazy        (empty)+import           Data.Map.Strict             (Map)+import           Data.MessagePack            (Object)+import           Data.Text                   (Text, pack)+import           Data.Char                   (ord)+import           Data.Array                  (listArray)++-- | Parses format data from ObjectMap+--+formatData :: Monad m => Map Text Object -> m FormatData+formatData mp = do v <- atP mp "mmtfVersion"  asStr+                   p <- atP mp "mmtfProducer" asStr+                   pure $ FormatData v p++-- | Parses model data from ObjectMap+--+modelData :: Monad m => Map Text Object -> m ModelData+modelData mp = ModelData . l2a <$> atP mp "chainsPerModel" asIntList++-- | Parses chain data from ObjectMap+--+chainData :: Monad m => Map Text Object -> m ChainData+chainData mp = do gpc <- atP mp "groupsPerChain" asIntList+                  cil <- codec5 . parseBinary <$> atP   mp "chainIdList"   asBinary+                  cnl <- codec5 . parseBinary <$> atPMD mp "chainNameList" asBinary empty+                  pure $ ChainData (l2a gpc) (l2a cil) (l2a cnl)++-- | Parses atom data from ObjectMap+--+atomData :: Monad m => Map Text Object -> m AtomData+atomData mp = do ail' <-       codec8 . parseBinary <$> atPMD mp "atomIdList"    asBinary empty+                 all' <- c2s . codec6 . parseBinary <$> atPMD mp "altLocList"    asBinary empty+                 bfl' <-      codec10 . parseBinary <$> atPMD mp "bFactorList"   asBinary empty+                 xcl' <-      codec10 . parseBinary <$> atP   mp "xCoordList"    asBinary+                 ycl' <-      codec10 . parseBinary <$> atP   mp "yCoordList"    asBinary+                 zcl' <-      codec10 . parseBinary <$> atP   mp "zCoordList"    asBinary+                 ol' <-        codec9 . parseBinary <$> atPMD mp "occupancyList" asBinary empty+                 pure $ AtomData (l2a ail') (l2a all') (l2a bfl') (l2a xcl') (l2a ycl') (l2a zcl') (l2a ol')++-- | Parses group data from ObjectMap+--+groupData :: Monad m => Map Text Object -> m GroupData+groupData mp = do gl' <-                                        atP   mp "groupList"          asObjectList >>= traverse (transformObjectMap >=> groupType)+                  gtl' <-              codec4 . parseBinary <$> atP   mp "groupTypeList"     asBinary+                  gil' <-              codec8 . parseBinary <$> atP   mp "groupIdList"       asBinary+                  ssl' <- fmap ssDec . codec2 . parseBinary <$> atPMD mp "secStructList"     asBinary empty+                  icl' <-        c2s . codec6 . parseBinary <$> atPMD mp "insCodeList"       asBinary empty+                  sil' <-              codec8 . parseBinary <$> atPMD mp "sequenceIndexList" asBinary empty+                  pure $ GroupData (l2a gl') (l2a gtl') (l2a gil') (l2a ssl') (l2a icl') (l2a sil')++-- | Parses group type from ObjectMap+--+groupType :: Monad m => Map Text Object -> m GroupType+groupType mp = do fcl' <-          atP mp "formalChargeList" asIntList+                  anl' <-          atP mp "atomNameList"     asStrList+                  el'  <-          atP mp "elementList"      asStrList+                  bal' <- l2pl <$> atP mp "bondAtomList"     asIntList+                  bol' <-          atP mp "bondOrderList"    asIntList+                  gn'  <-          atP mp "groupName"        asStr+                  slc' <-          atP mp "singleLetterCode" asChar+                  cct' <-          atP mp "chemCompType"     asStr+                  pure $ GroupType (l2a fcl') (l2a anl') (l2a el') (l2a bal') (l2a bol') gn' slc' cct'++-- | Parses structure data from ObjectMap+--+structureData :: Monad m => Map Text Object -> m StructureData+structureData mp = do ttl' <-                                  atPMD mp "title"               asStr        ""+                      sid' <-                                  atPMD mp "structureId"         asStr        ""+                      dd'  <-                                  atPMD mp "depositionDate"      asStr        ""+                      rd'  <-                                  atPMD mp "releaseDate"         asStr        ""+                      nb'  <-                                  atP   mp "numBonds"            asInt+                      na'  <-                                  atP   mp "numAtoms"            asInt+                      ng'  <-                                  atP   mp "numGroups"           asInt+                      nc'  <-                                  atP   mp "numChains"           asInt+                      nm'  <-                                  atP   mp "numModels"           asInt+                      sg'  <-                                  atPMD mp "spaceGroup"          asStr        ""+                      uc'  <-                  (>>= ucDec) <$> atPM  mp "unitCell"            asFloatList+                      nol' <-                       m44Dec <$> atPMD mp "ncsOperatorList"     asFloatList []+                      bal' <-                                  atPMD mp "bioAssemblyList"     asObjectList [] >>= traverse (transformObjectMap >=> bioAssembly)+                      el'  <-                                  atPMD mp "entityList"          asObjectList [] >>= traverse (transformObjectMap >=> entity)+                      res' <-                                  atPM  mp "resolution"          asFloat+                      rf'  <-                                  atPM  mp "rFree"               asFloat+                      rw'  <-                                  atPM  mp "rWork"               asFloat+                      em'  <-                                  atPMD mp "experimentalMethods" asStrList []+                      btl' <-  l2pl . codec4 . parseBinary <$> atPMD mp "bondAtomList"        asBinary empty+                      bol' <-         codec2 . parseBinary <$> atPMD mp "bondOrderList"       asBinary empty+                      pure $ StructureData ttl' sid' dd' rd' nb' na'+                                          ng' nc' nm' sg' uc' (l2a nol')+                                           (l2a bal') (l2a el') res' rf'+                                           rw' (l2a em') (l2a btl') (l2a bol')++-- | Parses bio assembly data from ObjectMap+--+bioAssembly :: Monad m => Map Text Object -> m Assembly+bioAssembly mp = do nme' <- atP mp "name"          asStr+                    tlt' <- atP mp "transformList" asObjectList >>= traverse (transformObjectMap >=> transform)+                    pure $ Assembly (l2a tlt') nme'++-- | Parses transform data from ObjectMap+--+transform :: Monad m => Map Text Object -> m Transform+transform mp = do cil' <- atP mp "chainIndexList" asIntList+                  mtx' <- atP mp "matrix"         asFloatList >>= m44Dec+                  pure $ Transform (l2a cil') mtx'++-- | Parses entity data from ObjectMap+--+entity :: Monad m => Map Text Object -> m Entity+entity mp = do cil' <- atP mp "chainIndexList" asIntList+               dsc' <- atP mp "description"    asStr+               tpe' <- atP mp "type"           asStr+               sqc' <- atP mp "sequence"       asStr+               pure $ Entity (l2a cil') dsc' tpe' sqc'++-- Helper functions++-- | Converts list of chars to list of one-sized+-- (or zero-sized in case of zero) strings+c2s :: [Char] -> [Text]+c2s [] = []+c2s (x:xs) | ord x == 0 = "":c2s xs+           | otherwise  = (pack [x]):c2s xs++-- | Converst list to an array+--+l2a :: [a] -> IArray a+l2a lst = listArray (0, length lst - 1) lst++-- | List to list of pairs+--+l2pl :: [a] -> [(a, a)]+l2pl []       = []+l2pl (x:y:xs) = (x,y) : l2pl xs+l2pl _        = error "Cannot convert a list of odd length to a list of pairs"
+ src/Bio/MMTF/Decode/Codec.hs view
@@ -0,0 +1,173 @@+module Bio.MMTF.Decode.Codec where++import           Data.Binary          (Binary, decode)+import           Data.ByteString.Lazy (ByteString)+import qualified Data.ByteString.Lazy as B (length, null, splitAt, unpack)+import           Data.Char            (chr)+import           Data.Int             (Int16, Int32, Int8)+import           Data.List            (mapAccumL)+import           Data.Text            (Text)+import qualified Data.Text            as T (pack)++import           Bio.MMTF.Type+import           Bio.Structure++codecCommon :: Binary a => (ByteString -> a) -> Int -> ByteString -> [a]+codecCommon  f th bs | B.null bs         = []+                     | B.length bs < ith = error "Wrong number of bytes in bytestring"+                     | otherwise         = let (start, rest) = B.splitAt ith bs+                                           in f start : codecCommon f th rest+  where ith = fromIntegral th++data BinaryData = BD { binaryCodec  :: !Int32+                     , binaryLength :: !Int32+                     , binaryParam  :: !Int32+                     , binaryData   :: !ByteString+                     }+  deriving Show++-- | Parse useless header for binary data+--+parseBinary :: ByteString -> BinaryData+parseBinary bs = let (cdc, rest1) = B.splitAt 4 bs+                     (lnh, rest2) = B.splitAt 4 rest1+                     (prm, rest)  = B.splitAt 4 rest2+                 in  BD (decode cdc) (decode lnh) (decode prm) rest++-- | Interpret bytes as array of 32-bit floating-point numbers.+--+codec1 :: BinaryData -> [Float]+codec1 = codecCommon decode 4 . binaryData++-- | Interpret bytes as array of 8-bit signed integers.+--+codec2 :: BinaryData -> [Int8]+codec2 = codecCommon decode 1 . binaryData++-- | Interpret bytes as array of 16-bit signed integers.+--+codec3 :: BinaryData -> [Int16]+codec3 = codecCommon decode 2 . binaryData++-- | Interpret bytes as array of 32-bit signed integers.+--+codec4 :: BinaryData -> [Int32]+codec4 = codecCommon decode 4 . binaryData++-- | Interpret bytes as array of 8-bit unsigned integers, then iteratively+-- consume length many bytes to form a string array.+--+codec5 :: BinaryData -> [Text]+codec5 bd = codecCommon decodeBytes (fromIntegral $ binaryParam bd) (binaryData bd)+  where decodeBytes :: ByteString -> Text+        decodeBytes bs = T.pack $ chr <$> filter (/=0) (fromIntegral <$> B.unpack bs)++-- | Interpret bytes as array of 32-bit signed integers, then run-length+-- decode into array of characters.+--+codec6 :: BinaryData -> [Char]+codec6 = map (chr . fromIntegral) . codec7++-- | Interpret bytes as array of 32-bit signed integers, then run-length+-- decode into array of 32-bit signed integers.+--+codec7 :: BinaryData -> [Int32]+codec7 = runLengthDec . codec4++-- | Interpret bytes as array of 32-bit signed integers, then run-length+-- decode into array of 32-bit signed integers, then delta decode into+-- array of 32-bit signed integers.+--+codec8 :: BinaryData -> [Int32]+codec8 = deltaDec . codec7++-- | Interpret bytes as array of 32-bit signed integers, then run-length+-- decode into array of 32-bit signed integers, then integer decode into+-- array of 32-bit floating-point numbers using the divisor parameter.+--+codec9 :: BinaryData -> [Float]+codec9 bd = integerDec (binaryParam bd) $ codec7 bd++-- | Interpret bytes as array of 16-bit signed integers, then unpack into+-- array of 32-bit integers, then delta decode into array of 32-bit+-- integers, then integer decode into array of 32-bit floating-point+-- numbers using the divisor parameter.+--+codec10 :: BinaryData -> [Float]+codec10 bd = integerDec (binaryParam bd) . map fromIntegral . deltaDec . recIndexDec $ codec3 bd++-- | Interpret bytes as array of 16-bit signed integers, then integer+-- decode into array of 32-bit floating-point numbers using the divisor parameter.+--+codec11 :: BinaryData -> [Float]+codec11 bd = integerDec (binaryParam bd) $ map fromIntegral $ codec3 bd++-- | Interpret bytes as array of 16-bit signed integers, then unpack into+-- array of 32-bit signed integers, then integer decode into array+-- of 32-bit floating-point numbers using the divisor parameter.+--+codec12 :: BinaryData -> [Float]+codec12 bd = integerDec (binaryParam bd) $ recIndexDec $ codec3 bd++-- | Interpret array of bytes as array of 8-bit signed integers, then+-- unpack into array of 32-bit signed integers, then integer decode into+-- array of 32-bit floating-point numbers using the divisor parameter.+--+codec13 :: BinaryData -> [Float]+codec13 bd = integerDec (binaryParam bd) $ recIndexDec $ codec2 bd++-- | Interpret bytes as array of 16-bit signed integers, then unpack+-- into array of 32-bit signed integers.+--+codec14 :: BinaryData -> [Int32]+codec14 bd = recIndexDec $ codec3 bd++-- | Interpret bytes as array of 8-bit signed integers, then unpack+-- into array of 32-bit signed integers.+--+codec15 :: BinaryData -> [Int32]+codec15 bd = recIndexDec $ codec2 bd++-- Decodings++runLengthDec :: Integral a => [a] -> [a]+runLengthDec [] = []+runLengthDec [_] = error "List must have even length for run-length encoding"+runLengthDec (x:l:xs) = replicate (fromIntegral l) x ++ runLengthDec xs++deltaDec :: Num a => [a] -> [a]+deltaDec = snd . mapAccumL (\x y -> (x+y,x+y)) 0++recIndexDec :: (Integral a, Bounded a, Eq a) => [a] -> [Int32]+recIndexDec [] = []+recIndexDec xs = recIndexDecAcc 0 xs+  where recIndexDecAcc :: (Integral a, Bounded a) => Int32 -> [a] -> [Int32]+        recIndexDecAcc acc []     | acc /= 0  = [acc]+                                  | otherwise = []+        recIndexDecAcc acc (x:ys) | x > minBound && x < maxBound = fromIntegral x + acc : recIndexDecAcc 0 ys+                                  | otherwise                    = recIndexDecAcc (fromIntegral x + acc) ys++integerDec :: Integral a => a -> [a] -> [Float]+integerDec divisor = map (\x -> fromIntegral x / fromIntegral divisor)++ssDec :: Int8 -> SecondaryStructure+ssDec n | n == 0    = PiHelix+        | n == 1    = Bend+        | n == 2    = AlphaHelix+        | n == 3    = Extended+        | n == 4    = ThreeTenHelix+        | n == 5    = Bridge+        | n == 6    = Turn+        | n == 7    = Coil+        | otherwise = Undefined++ucDec :: Monad m => [Float] -> m UnitCell+ucDec [a,b,c,d,e,f] = pure $ UnitCell a b c d e f+ucDec _             = fail "Wrong list format for unit cell"++m44Dec :: Monad m => [Float] -> m M44+m44Dec [ a11, a12, a13, a14+       , a21, a22, a23, a24+       , a31, a32, a33, a34+       , a41, a42, a43, a44] = pure $ M44 a11 a12 a13 a14 a21 a22 a23 a24 a31 a32 a33 a34 a41 a42 a43 a44+m44Dec _                     = fail "Wrong list format for 4x4 transformation matrix"
+ src/Bio/MMTF/Decode/MessagePack.hs view
@@ -0,0 +1,69 @@+module Bio.MMTF.Decode.MessagePack where++import           Data.ByteString.Lazy  (ByteString, fromStrict)+import           Data.Map.Strict       (Map, fromList)+import qualified Data.Map.Strict       as M (lookup)+import           Data.MessagePack+import           Data.Monoid           ((<>))+import           Data.Text             (Text)+import qualified Data.Text             as T (unpack)++transformObjectMap :: Monad m => Object -> m (Map Text Object)+transformObjectMap (ObjectMap kv) = let mkPair :: Monad m => (Object, Object) -> m (Text, Object)+                                        mkPair (ObjectStr txt, v) = pure (txt, v)+                                        mkPair _ = fail "Non-string key"+                                    in  fromList <$> traverse mkPair kv+transformObjectMap _ = fail "Wrong MessagePack MMTF format"++atP :: Monad m => Map Text Object -> Text -> (Text -> Object -> m a) -> m a+atP m k conv =+  case M.lookup k m of+    Just x  -> conv k x+    Nothing -> fail $ "Required field '" ++ uk ++ "' was not found"+  where uk = T.unpack k++atPM :: Monad m => Map Text Object -> Text -> (Text -> Object -> m a) -> m (Maybe a)+atPM m k conv = traverse (conv k) $ M.lookup k m++atPMD :: Monad m => Map Text Object -> Text -> (Text -> Object -> m a) -> a -> m a+atPMD m k conv def = do x <- atPM m k conv+                        case x of+                          Just r  -> pure r+                          Nothing -> pure def+                       +asStr :: Monad m => Text -> Object -> m Text+asStr _ (ObjectStr s) = pure s+asStr m _             = fail $ T.unpack m <> ": not a string data"++asChar :: Monad m => Text -> Object -> m Char+asChar m = (head . T.unpack <$>) . asStr m++asInt :: (Monad m, Integral a) => Text -> Object -> m a+asInt _ (ObjectInt i)  = pure (fromIntegral i)+asInt _ (ObjectWord w) = pure (fromIntegral w)+asInt m _              = fail $ T.unpack m <> ": not an int data"++asFloat :: Monad m => Text -> Object -> m Float+asFloat _ (ObjectFloat  f) = pure f+asFloat _ (ObjectDouble f) = pure (realToFrac f)+asFloat m _                = fail $ T.unpack m <> ": not a float data"++asIntList :: (Monad m, Integral a) => Text -> Object -> m [a]+asIntList m (ObjectArray l) = traverse (asInt m) l+asIntList m _               = fail $ T.unpack m <> ": not an array of ints data"++asStrList :: Monad m => Text -> Object -> m [Text]+asStrList m (ObjectArray l) = traverse (asStr m) l+asStrList m _               = fail $ T.unpack m <> ": not an array of string data"++asFloatList :: Monad m => Text -> Object -> m [Float]+asFloatList m (ObjectArray l) = traverse (asFloat m) l+asFloatList m _               = fail $ T.unpack m <> ": not an array of float data"++asObjectList :: Monad m => Text -> Object -> m [Object]+asObjectList _ (ObjectArray l) = pure l+asObjectList m _               = fail $ T.unpack m <> ": not an array data"++asBinary :: Monad m => Text -> Object -> m ByteString+asBinary _ (ObjectBin bs) = pure (fromStrict bs)+asBinary m _              = fail $ T.unpack m <> ": not a binary data"
+ src/Bio/MMTF/MessagePack.hs view
@@ -0,0 +1,20 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Bio.MMTF.MessagePack where++import           Bio.MMTF.Decode+import           Bio.MMTF.Decode.MessagePack+import           Bio.MMTF.Type++import           Data.MessagePack            (MessagePack (..))++instance MessagePack MMTF where+  toObject = undefined -- TODO: add MMTF encoding+  fromObject obj = do mp <- transformObjectMap obj+                      f <- formatData mp+                      s <- structureData mp+                      m <- modelData mp+                      c <- chainData mp+                      g <- groupData mp+                      a <- atomData mp+                      pure $ MMTF f s m c g a
+ src/Bio/MMTF/Type.hs view
@@ -0,0 +1,148 @@+module Bio.MMTF.Type where++import           Data.Int        ( Int32, Int8 )+import           Data.Text       ( Text )+import           Data.Array      ( Array )+import           GHC.Generics    ( Generic )+import           Control.DeepSeq ( NFData (..) )++import           Bio.Structure   ( SecondaryStructure )++-- | All arrays are int-indexed+--+type IArray a = Array Int a++-- | Transformation matrix+--+data M44 = M44 Float Float Float Float+               Float Float Float Float+               Float Float Float Float+               Float Float Float Float+  deriving (Show, Eq, Generic, NFData)++-- | Unit cell data+--+data UnitCell = UnitCell { ucA     :: !Float -- ^ length of side 'a'+                         , ucB     :: !Float -- ^ length of side 'b'+                         , ucC     :: !Float -- ^ length of side 'c'+                         , ucAlpha :: !Float -- ^ alpha angle in degrees+                         , ucBeta  :: !Float -- ^ beta angle in degrees+                         , ucGamma :: !Float -- ^ gamma angle in degrees+                         }+  deriving (Show, Eq, Generic, NFData)++-- | Transform data+--+data Transform = Transform { chainIndexList :: !(IArray Int32) -- ^ indices into the 'chainIdList' and 'chainNameList' fields+                           , matrix         :: !M44            -- ^ 4x4 transformation matrix+                           }+  deriving (Show, Eq, Generic, NFData)++-- | Assembly data+--+data Assembly = Assembly { transformList :: !(IArray Transform) -- ^ List of transform objects+                         , assemblyName  :: !Text               -- ^ Name of the biological assembly+                         }+  deriving (Show, Eq, Generic, NFData)++-- | Entity data+--+data Entity = Entity { entityChainIndexList :: !(IArray Int32) -- ^ indices into the 'chainIdList' and 'chainNameList' fields+                     , entityDescription    :: !Text           -- ^ Description of the entity+                     , entityType           :: !Text           -- ^ Name of the entity type+                     , entitySequence       :: !Text           -- ^ Sequence of the full construct in one-letter-code+                     }+  deriving (Show, Eq, Generic, NFData)++-- | Group type data+--+data GroupType = GroupType { gtFormalChargeList :: !(IArray Int32)          -- ^ List of formal charges+                           , gtAtomNameList     :: !(IArray Text)           -- ^ List of atom names+                           , gtElementList      :: !(IArray Text)           -- ^ List of elements+                           , gtBondAtomList     :: !(IArray (Int32, Int32)) -- ^ List of bonded atom indices+                           , gtBondOrderList    :: !(IArray Int32)          -- ^ List of bond orders+                           , gtGroupName        :: !Text                    -- ^ The name of the group+                           , gtSingleLetterCode :: !Char                    -- ^ The single letter code+                           , gtChemCompType     :: !Text                    -- ^ The chemical component type+                           }+  deriving (Show, Eq, Generic, NFData)++-- | MMTF format data+--+data FormatData = FormatData { mmtfVersion  :: !Text -- ^ The version number of the specification the file adheres to+                             , mmtfProducer :: !Text -- ^ The name and version of the software used to produce the file+                             }+  deriving (Show, Eq, Generic, NFData)++-- | Structure data+--+data StructureData = StructureData { title               :: !Text                    -- ^ A short description of the structural data included in the file+                                   , structureId         :: !Text                    -- ^ An ID for the structure, for example the PDB ID if applicable+                                   , depositionDate      :: !Text                    -- ^ A date that relates to the deposition of the structure in a database+                                   , releaseDate         :: !Text                    -- ^ A date that relates to the release of the structure in a database+                                   , numBonds            :: !Int32                   -- ^ The overall number of bonds+                                   , numAtoms            :: !Int32                   -- ^ The overall number of atoms in the structure+                                   , numGroups           :: !Int32                   -- ^ The overall number of groups in the structure+                                   , numChains           :: !Int32                   -- ^ The overall number of chains in the structure+                                   , numModels           :: !Int32                   -- ^ The overall number of models in the structure+                                   , spaceGroup          :: !Text                    -- ^ The Hermann-Mauguin space-group symbol+                                   , unitCell            :: !(Maybe UnitCell)        -- ^ Array of six values defining the unit cell+                                   , ncsOperatorList     :: !(IArray M44)            -- ^ List of 4x4 transformation matrices (transformation matrices describe noncrystallographic symmetry operations needed to create all molecules in the unit cell)+                                   , bioAssemblyList     :: !(IArray Assembly)       -- ^ List of instructions on how to transform coordinates for an array of chains to create (biological) assemblies+                                   , entityList          :: !(IArray Entity)         -- ^ List of unique molecular entities within the structure+                                   , resolution          :: !(Maybe Float)           -- ^ The experimental resolution in Angstrom+                                   , rFree               :: !(Maybe Float)           -- ^ The R-free value+                                   , rWork               :: !(Maybe Float)           -- ^ The R-work value+                                   , experimentalMethods :: !(IArray Text)           -- ^ List of experimental methods employed for structure determination+                                   , bondAtomList        :: !(IArray (Int32, Int32)) -- ^ Pairs of values represent indices of covalently bonded atoms [binary (type 4)]+                                   , bondOrderList       :: !(IArray Int8)           -- ^ List of bond orders for bonds in 'bondAtomList' [binary (type 2)]+                                   }+  deriving (Show, Eq, Generic, NFData)++-- | Models data+--+data ModelData = ModelData { chainsPerModel :: !(IArray Int32) -- ^ List of the number of chains in each model+                           }+  deriving (Show, Eq, Generic, NFData)++-- | Chains data+--+data ChainData = ChainData { groupsPerChain :: !(IArray Int32)       -- ^ List of the number of groups (aka residues) in each chain+                           , chainIdList    :: !(IArray Text)        -- ^ List of chain IDs [binary (type 5)]+                           , chainNameList  :: !(IArray Text)        -- ^ List of chain names [binary (type 5)]+                           }+  deriving (Show, Eq, Generic, NFData)++-- | Groups data+--+data GroupData = GroupData { groupList         :: !(IArray GroupType)              -- ^ List of groupType objects+                           , groupTypeList     :: !(IArray Int32)                  -- ^ List of pointers to 'groupType' entries in 'groupList' by their keys [binary (type 4)]+                           , groupIdList       :: !(IArray Int32)                  -- ^ List of group (residue) numbers [binary (type 8)]+                           , secStructList     :: !(IArray SecondaryStructure)     -- ^ List of secondary structure assignments [binary (type 2)]+                           , insCodeList       :: !(IArray Text)                   -- ^ List of insertion codes, one for each group (residue) [binary (type 6)]+                           , sequenceIndexList :: !(IArray Int32)                  -- ^ List of indices that point into the sequence property of an entity object in the 'entityList' field that is associated with the chain the group belongs to [binary (type 8)]+                           }+  deriving (Show, Eq, Generic, NFData)++-- | Atoms data+--+data AtomData = AtomData { atomIdList    :: !(IArray Int32)        -- ^ List of atom serial numbers [binary (type 8)]+                         , altLocList    :: !(IArray Text)         -- ^ List of alternate location labels, one for each atom [binary (type 6)]+                         , bFactorList   :: !(IArray Float)        -- ^ List of atom B-factors in in A^2, one for each atom [binary (type 10)]+                         , xCoordList    :: !(IArray Float)        -- ^ List of x atom coordinates in A, one for each atom [binary (type 10)]+                         , yCoordList    :: !(IArray Float)        -- ^ List of y atom coordinates in A, one for each atom [binary (type 10)]+                         , zCoordList    :: !(IArray Float)        -- ^ List of z atom coordinates in A, one for each atom [binary (type 10)]+                         , occupancyList :: !(IArray Float)        -- ^ List of atom occupancies, one for each atom [binary (type 9)]+                         }+  deriving (Show, Eq, Generic, NFData)++-- | MMTF datatype+--+data MMTF = MMTF { format    :: !FormatData    -- ^ MMTF format data+                 , structure :: !StructureData -- ^ Biological structure data+                 , model     :: !ModelData     -- ^ Models data+                 , chain     :: !ChainData     -- ^ Chains data+                 , group     :: !GroupData     -- ^ Groups data+                 , atom      :: !AtomData      -- ^ Atoms data+                 }+  deriving (Show, Eq, Generic, NFData)
+ src/Bio/PDB.hs view
@@ -0,0 +1,5 @@+module Bio.PDB+  (++  ) where+
+ src/Bio/PDB/Type.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE DuplicateRecordFields #-}+module Bio.PDB.Type where++import           Data.Text                      ( Text )+import           Data.Array                     ( Array )++data Header = Header { classification :: Text+                     , depDate        :: Text+                     , idCode         :: Text+                     }++data Obsoleted = Obsoleted { repDate      :: Text+                           , idCode       :: Text+                           , rIdCode      :: Array Int Text+                           }++data Caveat = Caveat { idCode       :: Text+                     , comment      :: Text+                     }++data Compound = Compound { molId            :: Text+                         , molecule         :: Text+                         , chain            :: Array Int Text+                         , fragment         :: Text+                         , synonym          :: Array Int Text+                         , enzymeCommission :: Array Int Int+                         , engineered       :: Bool+                         , mutation         :: Bool+                         , otherDetails     :: Array Int Text+                         }++data Organism = Organism { scientific :: Text+                         , common     :: Text+                         , taxId      :: Text+                         }++data ExpressionSystem = ExpressionSystem { name             :: Text+                                         , common           :: Text+                                         , taxId            :: Text+                                         , strain           :: Text+                                         , variant          :: Text+                                         , cellLine         :: Text+                                         , atcc             :: Text+                                         , organ            :: Text+                                         , tissue           :: Text+                                         , cell             :: Text+                                         , organelle        :: Text+                                         , cellularLocation :: Text+                                         , vectorType       :: Text+                                         , vector           :: Text+                                         , plasmid          :: Text+                                         , gene             :: Text+                                         , otherDetails     :: Text+                                         }++data Source = Source { molId            :: Text+                     , synthetic        :: Text+                     , fragment         :: Text+                     , organism         :: Organism+                     , strain           :: Text+                     , variant          :: Text+                     , cellLine         :: Text+                     , atcc             :: Text+                     , tissue           :: Text+                     , cell             :: Text+                     , organelle        :: Text+                     , secretion        :: Text+                     , cellularLocation :: Text+                     , plasmid          :: Text+                     , gene             :: Text+                     , expressionSystem :: ExpressionSystem+                     , otherDetails     :: Text+                     }++--+data Title = Title { header    :: Header+                   , obsoleted :: Obsoleted+                   , title     :: Text+                   , split     :: Array Int Text+                   , caveat    :: Caveat+                   , compound  :: Array Int Compound+                   -- TODO+                   }++data PrimaryStructure = PrimaryStructure -- TODO++data Heterogen = Heterogen -- TODO++data Helix = Helix {++                   }++data Sheet = Sheet {++                   }++data Secondary = Secondary { helixes :: Array Int Helix+                           , sheets  :: Array Int Sheet+                           }++data ConnectivityAnnotation = ConnectivityAnnotation -- TODO++data Miscellaneous = Miscellaneous -- TODO++data Transformation = Transformation -- TODO++data Coordinate = Coordinate {++                             }++data Connectivity = Connectivity -- TODO++data Bookkeeping = Bookkeeping -- TODO++data PDB = PDB { title                  :: Title+               , primaryStructure       :: PrimaryStructure+               , heterogen              :: Heterogen+               , secondary              :: Secondary+               , connectivityAnnotation :: ConnectivityAnnotation+               , miscellaneous          :: Miscellaneous+               , transformation         :: Transformation+               , coordinate             :: Coordinate+               , connectivity           :: Connectivity+               , bookkeeping            :: Bookkeeping+               }
+ src/Bio/Sequence.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE UndecidableInstances #-}++module Bio.Sequence+  ( module Bio.Sequence.Class+  , module Bio.Sequence.Functions.Sequence+  , module Bio.Sequence.Functions.Weight+  , module Bio.Sequence.Functions.Marking+  ) where++import           Bio.Sequence.Class              hiding (_sequenceInner)+import           Bio.Sequence.Functions.Marking+import           Bio.Sequence.Functions.Sequence+import           Bio.Sequence.Functions.Weight++
+ src/Bio/Sequence/Basecalled.hs view
@@ -0,0 +1,5 @@+module Bio.Sequence.Basecalled+  ( module Bio.Sequence.Basecalled.Type+  ) where++import           Bio.Sequence.Basecalled.Type
+ src/Bio/Sequence/Basecalled/Type.hs view
@@ -0,0 +1,18 @@+module Bio.Sequence.Basecalled.Type+  ( BasecalledSequence (..)+  ) where++import           Bio.Sequence (IsSequence (..), WeightedSequence)+import           Data.Coerce  (coerce)++newtype BasecalledSequence = BasecalledSequence (WeightedSequence Double Char)+  deriving (Eq, Show)++instance IsSequence BasecalledSequence where+  type Element BasecalledSequence = Char+  type Marking BasecalledSequence = ()+  type Weight BasecalledSequence  = Double++  toSequence = coerce+  fromSequence = coerce+
+ src/Bio/Sequence/Class.hs view
@@ -0,0 +1,324 @@+{-# LANGUAGE UndecidableInstances #-}++module Bio.Sequence.Class+  (+  -- class for decoding into sequence+    SequenceDecodable (..)++  -- 'Sequence' type itself+  , Sequence+  , WeightedSequence+  , MarkedSequence+  , BareSequence+  , Range+  , sequ+  , markings+  , weights++  -- classes for weights and markings of sequence+  , IsMarking+  , IsWeight (..)++  -- classes that are abstractions over 'Sequence'+  , IsSequence (..)+  , IsWeightedSequence+  , IsMarkedSequence+  , IsBareSequence+  , ContainsMarking+  , ContainsNoMarking+  , ContainsWeight+  , ContainsNoWeight++  -- constructors for 'IsSequence'+  , createSequence+  , unsafeCreateSequence+  , bareSequence+  , weightedSequence+  , unsafeWeightedSequence+  , markedSequence+  , unsafeMarkedSequence++  -- inner unsafe constructor that should be used only in module Bio.Sequence+  , _sequenceInner+  ) where++import           Bio.Sequence.Utilities (Range, checkRange, unsafeEither)+import           Control.Lens+import           Control.Monad.Except   (MonadError, throwError)+import           Data.Bifunctor         (bimap)+import           Data.Kind              (Constraint)+import qualified Data.List              as L (length, null)+import           Data.Text              (Text)+import           Data.Vector            (Vector)+import qualified Data.Vector            as V (fromList, length)+import           GHC.Generics           (Generic)+import           GHC.TypeLits           (ErrorMessage (..), TypeError)++--------------------------------------------------------------------------------+-- Sequence datatype.+--------------------------------------------------------------------------------++-- 'Sequence' represents sequence of objects of type 'a' that+-- can have different markings of type 'mk' and weights of type 'w'.+--+data Sequence mk w a = Sequence { _sequ     :: Vector a      -- ^ sequence itself+                                , _markings :: [(mk, Range)] -- ^ list of pairs containing marking and 'Range', that corresponds to it+                                , _weights  :: Vector w      -- ^ weights for all elements in sequence+                                }+  deriving (Eq, Show, Generic, Functor)++instance Semigroup (Sequence mk w a) where+  sequA <> sequB = res+    where+      newSequ     = sequA ^. sequ     <> sequB ^. sequ+      newMarkings = sequA ^. markings <> fmap (fmap (bimap addInd addInd)) (sequB ^. markings)+      newWeights  = sequA ^. weights  <> sequB ^. weights++      res = Sequence newSequ newMarkings newWeights++      addInd :: Int -> Int+      addInd = (+ V.length (sequA ^. sequ))++instance Monoid (Sequence mk () a) where+  mempty = Sequence mempty mempty mempty++instance Foldable (Sequence mk w) where+  foldMap f = foldMap f . _sequ++  length = V.length . _sequ++-- | Exported constructor for 'Sequence'. Should be used ONLY in module Bio.Sequence.+--+_sequenceInner :: Vector a -> [(mk, Range)] -> Vector w -> Sequence mk w a+_sequenceInner = Sequence++--------------------------------------------------------------------------------+-- Aliases for 'Sequence'.+--------------------------------------------------------------------------------++-- | Type alias for sequence that has no marking but is weighted.+--+type WeightedSequence w a = Sequence () w a++-- | Type alias for sequence that is not weighted, but has markings.+--+type MarkedSequence mk a = Sequence mk () a++-- | Type alias for sequence that is not weighted and has no markings.+--+type BareSequence a = Sequence () () a++--------------------------------------------------------------------------------+-- Lenses for 'Sequence'.+-- We create only getters, so user that couldn't ruin 'Sequence's invariant.+--------------------------------------------------------------------------------++sequ :: Getter (Sequence mk w a) (Vector a)+sequ = to _sequ++markings :: Getter (Sequence mk w a) [(mk, Range)]+markings = to _markings++weights :: Getter (Sequence mk w a) (Vector w)+weights  = to _weights+++--------------------------------------------------------------------------------+-- IsMarking class.+--------------------------------------------------------------------------------++-- | Class that reprsents objects that can be markings of 'IsSequence'.+--+class (Eq mk, Ord mk) => IsMarking mk where++instance IsMarking ()+++--------------------------------------------------------------------------------+-- IsWeight class.+--------------------------------------------------------------------------------++-- | Class that represents objects that can be weights of 'IsSequence's 'Element's.+--+class IsWeight w where+  toDouble :: w -> Double++instance IsWeight () where+  toDouble = error "Bio.Sequence.Class: () can't be valid 'Weight'."++instance IsWeight Double where+  toDouble = id+++--------------------------------------------------------------------------------+-- IsSequence class.+--------------------------------------------------------------------------------++-- | Type class that describes object that is isomorphisc to 'Sequence'+-- and contains elements of type 'Element', is marked with marking of type+-- 'Marking' and is weighted with weights of type 'Weight'.+--+-- Special cases, when 'IsSequence' has no markings, has no weights, or+-- has no weights and no markings at the same time are aliased:+--  * 'IsWeightedSequence' is alias for sequence with 'Marking' type set to () and 'Weight' not set to ()+--  * 'IsMarkedSequence' is alias for sequence with 'Weight' type set to () and 'Marking' not set to ().+--  * 'IsBareSequence' is alias for sequence with 'Marking' and 'Weight' types+--     set to ().+--+-- Instances of 'IsSequence' can be built only using special constructors:+--  * 'createSequence' creates 'IsSequence' that has 'Marking' and 'Weight'+--    that are not set to ().+--  * 'bareSequence' creates 'IsSequence' that has 'Marking' and 'Weight'+--    that are set to ().+--  * 'weightedSequence' creates 'IsSequence' that has 'Marking' set to () and+--    'Weight' that is not ().+--  * 'markedSequence' creates 'IsSequence' that has 'Weight' set to () and+--    'Marking' that is not ().+--+-- Constraints and constructors mentioned above gaurantee that 'IsSequence'+-- instances that have no 'Weight's will in compile-time+-- have () as types assosiated with their 'Weight's.+-- That is used to make functions that rely on 'IsSequence' instance+-- having not null weights type-safe.+--+class (IsMarking (Marking s), IsWeight (Weight s)) => IsSequence s where+  type Element s :: *+  type Marking s :: *+  type Weight  s :: *++  toSequence :: s -> Sequence (Marking s) (Weight s) (Element s)+  fromSequence :: Sequence (Marking s) (Weight s) (Element s) -> s++instance (IsMarking mk, IsWeight w) => IsSequence (Sequence mk w a) where+  type Element (Sequence mk w a) = a+  type Marking (Sequence mk w a) = mk+  type Weight  (Sequence mk w a) = w++  toSequence = id+  fromSequence = id++-- | Class that allows to decode something into Sequence representation+--+class IsSequence s => SequenceDecodable a s where+  sequenceDecode :: a -> Either Text s+++--------------------------------------------------------------------------------+-- Aliases for 'IsSequence'.+--------------------------------------------------------------------------------++-- | Type alias for constraint that checks whether given instance of 'IsSequence'+-- has no markings, but is weighted.+--+type IsWeightedSequence s = (IsSequence s, Unit (Marking s), NotUnit (Weight s))++-- | Type alias for constraint that checks whether given instance of 'IsSequence'+-- has markings, but is not weighted.+--+type IsMarkedSequence s = (IsSequence s, NotUnit (Marking s), Unit (Weight s))++-- | Type alias for constraint that checks whether given instance of 'IsSequence'+-- has no markings and is not weighted.+--+type IsBareSequence s = (IsSequence s, Unit (Marking s), Unit (Weight s))++-- | Type alias for constraint that checks whether given instance @s@ of 'IsSequence'+-- has markings, weights of @s@ are not checked.+--+type ContainsMarking s = (IsSequence s, NotUnit (Marking s))++-- | Type alias for constraint that checks whether given instance @s@ of 'IsSequence'+-- has no markings, weights of @s@ are not checked.+--+type ContainsNoMarking s = (IsSequence s, Unit (Marking s))++-- | Type alias for constraint that checks whether given instance @s@ of 'IsSequence'+-- has weights, markings of @s@ are not checked.+--+type ContainsWeight s = (IsSequence s, NotUnit (Weight s))++-- | Type alias for constraint that checks whether given instance @s@ of 'IsSequence'+-- has no weights, markings of @s@ are not checked.+--+type ContainsNoWeight s = (IsSequence s, Unit (Weight s))+++--------------------------------------------------------------------------------+-- Constructors for 'IsSequence's.+--------------------------------------------------------------------------------++-- | Create 'IsSequence' @s@ that has both markings and weights.+-- If any of the markings is invalid or length of weights list is not equal to length+-- of sequence, an error will be thrown.+--+createSequence :: (ContainsMarking s, ContainsWeight s, MonadError Text m) => [Element s] -> [(Marking s, Range)] -> [Weight s] -> m s+createSequence = createSequenceInner True True++unsafeCreateSequence :: (ContainsMarking s, ContainsWeight s) => [Element s] -> [(Marking s, Range)] -> [Weight s] -> s+unsafeCreateSequence s markings' = unsafeEither . createSequence s markings'++-- | Create 'IsBareSequence' @s@, simple sequence without markings and weights.+--+bareSequence :: IsBareSequence s => [Element s] -> s+bareSequence s = fromSequence $ Sequence (V.fromList s) mempty mempty++-- | Create 'IsMarkedSequence' @s@ from list of 'Element's and 'Marking's that+-- mark it. If at least one of ranges in given list of 'Marking's is out of bounds,+-- an error will be thrown.+--+markedSequence :: (IsMarkedSequence s, MonadError Text m) => [Element s] -> [(Marking s, Range)] -> m s+markedSequence s markings' = createSequenceInner True False s markings' []++unsafeMarkedSequence :: IsMarkedSequence s => [Element s] -> [(Marking s, Range)] -> s+unsafeMarkedSequence s = unsafeEither . markedSequence s++-- | Create 'IsWeightedSequence' @s@ from list of 'Element's and 'Weight's+-- that correspond to each 'Element'. If length of list of 'Weight's+-- is not equal to length of sequence or lis is null, an error will be thrown.+--+weightedSequence :: (IsWeightedSequence s, MonadError Text m) => [Element s] -> [Weight s] -> m s+weightedSequence s = createSequenceInner False True s []++unsafeWeightedSequence :: IsWeightedSequence s => [Element s] -> [Weight s] -> s+unsafeWeightedSequence s = unsafeEither . weightedSequence s++--------------------------------------------------------------------------------+-- Utility functions.+--------------------------------------------------------------------------------++type family NotUnit a :: Constraint where+  NotUnit () = TypeError ('Text "cobot-io: this function doesn't work with when parametrized by ().")+  NotUnit _  = ()++type family Unit a :: Constraint where+  Unit () = ()+  Unit _  = TypeError ('Text "cobot-io: this function doesn't work with when not parametrized by ().")++createSequenceInner :: (IsSequence s, MonadError Text m) => Bool -> Bool -> [Element s] -> [(Marking s, Range)] -> [Weight s] -> m s+createSequenceInner checkMk checkW s markings' weights' | checkMk && not checkRanges     = throwError rangesError+                                                        | checkW && not checkNullWeights = throwError weightsNullError+                                                        | checkW && not checkLenWeights  = throwError weightsLenError+                                                        | otherwise                      = pure resSequence+  where+    seqVector     = V.fromList s+    weightsVector = V.fromList weights'++    resSequence = fromSequence $ Sequence seqVector markings' weightsVector++    checkRanges :: Bool+    checkRanges = all (checkRange (L.length s)) $ fmap snd markings'++    checkNullWeights :: Bool+    checkNullWeights = not (L.null weights')++    checkLenWeights :: Bool+    checkLenWeights = L.length s == L.length weights'++    rangesError :: Text+    rangesError = "Bio.Sequence.Class: invalid 'Range' found in sequence's marking."++    weightsNullError :: Text+    weightsNullError = "Bio.Sequence.Class: weights are null for sequence."++    weightsLenError :: Text+    weightsLenError = "Bio.Sequence.Class: sequence and weights have different lengths."
+ src/Bio/Sequence/Functions/Marking.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE ViewPatterns #-}++module Bio.Sequence.Functions.Marking+  ( getMarking+  , unsafeGetMarking+  , toMarked+  , unsafeToMarked+  , addMarkings+  , unsafeAddMarkings+  , listMarkings+  ) where++import           Bio.Sequence.Class              (ContainsMarking,+                                                  IsBareSequence,+                                                  IsMarkedSequence,+                                                  IsSequence (..),+                                                  markedSequence, markings,+                                                  sequ, unsafeMarkedSequence,+                                                  weights, _sequenceInner)+import           Bio.Sequence.Functions.Sequence (length, unsafeGetRange)+import           Bio.Sequence.Utilities          (Range, checkRange,+                                                  unsafeEither)+import           Control.Lens+import           Control.Monad.Except            (MonadError, throwError)+import           Data.List                       (nub)+import           Data.List.NonEmpty              (NonEmpty (..))+import           Data.Text                       (Text)+import qualified Data.Vector                     as V (toList)+import           Prelude                         hiding (drop, head, length,+                                                  null, reverse, tail, take,+                                                  (!!))++-- | Function that retrieves all elements in 'IsSequence' @s@ that are covered by given 'Marking'' @s@.+-- Returns 'NonEmpty' list, because if 'Marking' is present in @s@, then list of+-- all 'Marking's for @s@ can't be empty. If given 'Marking is not found in @s@, an+-- error will be thrown.+--+-- > sequ = Sequence ['a', 'a', 'b', 'a'] [("Letter A", (0, 2)), ("Letter A", (3, 4)), ("Letter B", (2, 3))] mempty+-- > getMarking sequ "Letter A" == ['a', 'a'] :| [['a']]+--+getMarking :: (ContainsMarking s, MonadError Text m) => s -> Marking s -> m (NonEmpty [Element s])+getMarking (toSequence -> s) mk | not $ mk `member` (s ^. markings) = throwError markingNotFoundError+                                | otherwise                         = pure $ res+  where+    res = foldl1 (<>) $ fmap ((:| []) . unsafeGetRange s) $  mk `lookupAll` (s ^. markings)++    markingNotFoundError :: Text+    markingNotFoundError = "Bio.Sequence.Functions.Marking: given marking not found in Sequence."++unsafeGetMarking :: ContainsMarking s => s -> Marking s -> NonEmpty [Element s]+unsafeGetMarking mk = unsafeEither . getMarking mk++-- | Converts 'IsBareSequence' @s@ to 'IsMarkedSequence' @s'@ that is marked using provided list+-- of 'Marking's. If at least one of ranges in given list of 'Marking's is out of+-- bounds, an error will be thrown.+--+-- > sequBare = Sequence ['a', 'a', 'b', 'a'] mempty mempty :: BareSequence Char+-- > toMarked sequ [("Letter A", (0, 2)), ("Letter A", (3, 4))] :: MarkedSequence String Char+--+toMarked :: (IsBareSequence s, IsMarkedSequence s', Marking s' ~ mk, Element s ~ Element s', MonadError Text m) => s -> [(mk, Range)] -> m s'+toMarked (toSequence -> s) = markedSequence (V.toList $ s ^. sequ)++unsafeToMarked :: (IsBareSequence s, IsMarkedSequence s', Marking s' ~ mk, Element s ~ Element s') => s -> [(mk, Range)] -> s'+unsafeToMarked (toSequence -> s) = unsafeMarkedSequence (V.toList $ s ^. sequ)++-- | Adds new 'Marking's to given 'IsSequence' @s@. Type of new 'Marking's must+-- match type of 'Marking's that @s@ is already marked with. If at least one of ranges+-- in given list of 'Marking's is out of bounds, an error will be thrown.+--+-- > sequ = Sequence ['a', 'a', 'b', 'a'] [("Letter A", (0, 2)), ("Letter A", (3, 4)), ("Letter B", (2, 3))] mempty+-- > sequ' = Sequence ['a', 'a', 'b', 'a'] [("Letter A", (0, 2)), ("Letter A", (3, 4))] mempty+-- > addMarkings sequ' [("Letter B", (2, 3))] == sequ+--+addMarkings :: (ContainsMarking s, Marking s ~ mk, MonadError Text m) => s -> [(mk, Range)] -> m s+addMarkings (toSequence -> s) markings' | all (checkRange (length s) . snd) markings' = pure res+                                        | otherwise                                   = throwError rangesError+  where+    res = fromSequence $ _sequenceInner (s ^. sequ) (s ^. markings <> markings') (s ^. weights)++    rangesError :: Text+    rangesError = "Bio.Sequence.Functions.Marking: can't add markings to Sequence, because some of them are out of range."++unsafeAddMarkings :: (ContainsMarking s, Marking s ~ mk) => s -> [(mk, Range)] -> s+unsafeAddMarkings s = unsafeEither . addMarkings s++-- | Retrieves all 'Marking's from given sequence that 'ContainsMarking'.+--   Result is list of 'Marking's without dublicates.+--+-- > sequ = Sequence ['a', 'a', 'b', 'a'] [("Letter A", (0, 2)), ("Letter A", (3, 4)), ("Letter B", (2, 3))] mempty+-- > listMarkings sequ == ["Letter A", "Letter B"]+--+listMarkings :: ContainsMarking s => s -> [Marking s]+listMarkings (toSequence -> s) = nub $ fst <$> s ^. markings++--------------------------------------------------------------------------------+-- Inner functions.+--------------------------------------------------------------------------------++member :: Eq a => a -> [(a, b)] -> Bool+member a = (a `elem`) . fmap fst++lookupAll :: Eq a => a -> [(a, b)] -> [b]+lookupAll a = fmap snd . filter ((== a) . fst)
+ src/Bio/Sequence/Functions/Sequence.hs view
@@ -0,0 +1,135 @@+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns         #-}++module Bio.Sequence.Functions.Sequence+  ( drop+  , getRange, unsafeGetRange+  , length, null+  , reverse+  , tail+  , take+  , toList+  , (!), (!?)+  ) where++import           Bio.Sequence.Class     (ContainsNoMarking, IsSequence (..),+                                         markings, sequ, weights,+                                         _sequenceInner)+import           Bio.Sequence.Utilities (Range, checkRange, unsafeEither)+import           Control.Lens+import           Control.Monad.Except   (MonadError, throwError)+import           Data.Bifunctor         (bimap)+import qualified Data.Foldable          as F (length, null, toList)+import qualified Data.List              as L (drop, take)+import           Data.Maybe             (fromMaybe)+import           Data.Text              (Text)+import           Data.Tuple             (swap)+import qualified Data.Vector            as V (drop, reverse, take, (!?))+import           Prelude                hiding (drop, length, null, reverse,+                                         tail, take)++-- | Get elements from sequence that belong to given 'Range' (format of range is [a; b)).+-- If given 'Range' is out of bounds, an error will be thrown.+--+-- > sequ = Sequence ['a', 'a', 'b', 'a'] [("Letter A", (0, 2)), ("Letter A", (3, 4)), ("Letter B", (2, 3))] mempty+-- > getRange sequ (0, 3) == Just ['a', 'a', 'b']+--+getRange :: (IsSequence s, MonadError Text m) => s -> Range -> m [Element s]+getRange s r@(lInd, rInd) | checkRange (length s) r = pure $ L.take (rInd - lInd) $ L.drop lInd $ toList s+                          | otherwise               = throwError "Bio.Sequence.Functions.Sequence: invalid range in getRange."++unsafeGetRange :: IsSequence s => s -> Range -> [Element s]+unsafeGetRange s = unsafeEither . getRange s++-- | Unsafe operator to get elemnt at given position in @s@.+--+infixl 9 !+(!) :: IsSequence s => s -> Int -> Element s+(!) s = fromMaybe (error "Bio.Sequence.Functions.Sequence: index out of Sequence's length.") . (s !?)++-- | Safe operator to get element at given position in @s@.+--+infixl 9 !?+(!?) :: IsSequence s => s -> Int -> Maybe (Element s)+(!?) (toSequence -> s) = ((s ^. sequ) V.!?)++-- | List all elemnts of @s@.+--+toList :: IsSequence s => s -> [Element s]+toList = F.toList . toSequence++-- | Calculates length of @s@.+--+length :: IsSequence s => s -> Int+length = F.length . toSequence++-- | Returns 'True' if @s@ is empty. Returns 'False' otherwise.+--+null :: IsSequence s => s -> Bool+null = F.null . toSequence++-- | Reverses given 'IsSequence' @s@. 'Marking's and 'Weight's are reversed, too.+--+-- > sequ = Sequence ['a', 'a', 'b', 'a'] [("Letter A", (0, 2)), ("Letter A", (3, 4)), ("Letter B", (2, 3))] [1, 2, 3, 4]+-- > reverse sequ == Sequence ['a', 'b', 'a', 'a'] [("Letter A", (2, 4)), ("Letter A", (0, 1)), ("Letter B", (1, 2))] [4, 3, 2, 1]+--+reverse :: IsSequence s => s -> s+reverse (toSequence -> s) = res+  where+    newMaxInd = length s++    newSequ     = V.reverse $ s ^. sequ+    newMarkings = fmap (fmap $ swap . bimap ((-) newMaxInd) ((-) newMaxInd)) $ s ^. markings+    newWeights  = V.reverse $ s ^. weights++    res = fromSequence $ _sequenceInner newSequ newMarkings newWeights++-- | Unsafe drop:+--     * if n < 0, an error is thrown;+--     * if n >= length @s@, an error is thrown.+--+-- > sequWeighted = Sequence ['a', 'a', 'b', 'a'] mempty [0.1, 0.2, 0.3, 0.4]+-- > drop 2 sequWeighted == Sequence [b', 'a'] mempty [0.3, 0.4]+-- > drop (-1) sequWeighted == error+-- > drop 4 sequWeighted == error+--+drop :: ContainsNoMarking s => Int -> s -> s+drop n (toSequence -> s) | n < 0         = error "Bio.Sequence.Functions.Sequence: drop with negative value."+                         | n >= length s = error "Bio.Sequence.Functions.Sequence: empty sequence as result of drop."+                         | otherwise     = res+  where+    droppedSequ = V.drop n $ s ^. sequ+    newWeights  = V.drop n $ s ^. weights++    res = fromSequence $ _sequenceInner droppedSequ mempty newWeights++-- | Unsafe take:+--     * if n < 0, an error is thrown;+--     * if n == 0, an error is thrown.+--+-- > sequWeighted = Sequence ['a', 'a', 'b', 'a'] mempty [0.1, 0.2, 0.3, 0.4]+-- > take 2 sequWeighted == Sequence ['a', 'a'] mempty [0.1, 0.2]+-- > take -1 sequWeighted == error+-- > take 0 sequWeighted == error+--+take :: ContainsNoMarking s => Int -> s -> s+take n (toSequence -> s) | n < 0     = error "Bio.Sequence.Functions.Sequence: take with negative value."+                         | n == 0    = error "Bio.Sequence.Functions.Sequence: empty sequence as result of take."+                         | otherwise = res+  where+    takenSequ  = V.take n $ s ^. sequ+    newWeights = V.take n $ s ^. weights++    res = fromSequence $ _sequenceInner takenSequ mempty newWeights++-- | Unsafe tail:+--     * length @s@ == 0, an error is thrown;+--     * length @s@ == 1, an error is thrown.+--+-- > sequWeighted = Sequence ['a', 'a', 'b', 'a'] mempty [0.1, 0.2, 0.3, 0.4]+-- > tail sequWeighted == Sequence [a', 'b', 'a'] mempty [0.2, 0.3, 0.4]+-- > tail (tail (tail (tail (tail sequWeighted)))) == error+--+tail :: ContainsNoMarking s => s -> s+tail s | length s == 0 = error "Bio.Sequence.Functions.Sequence: tail from empty sequence."+       | otherwise     = drop 1 s
+ src/Bio/Sequence/Functions/Weight.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE ViewPatterns #-}++module Bio.Sequence.Functions.Weight+  ( mean+  , meanInRange+  , getWeight+  , unsafeGetWeight+  , getWeights+  , toWeighted+  , unsafeToWeighted+  ) where++import           Bio.Sequence.Class              (ContainsWeight,+                                                  IsBareSequence,+                                                  IsSequence (..),+                                                  IsWeight (..),+                                                  IsWeightedSequence, sequ,+                                                  unsafeWeightedSequence,+                                                  weightedSequence, weights)+import           Bio.Sequence.Functions.Sequence (length)+import           Bio.Sequence.Utilities          (unsafeEither)+import           Control.Lens+import           Control.Monad.Except            (MonadError, throwError)+import           Data.Text                       (Text)+import           Data.Vector                     (Vector)+import qualified Data.Vector                     as V (drop, length, take,+                                                       toList, (!))+import           Prelude                         hiding (drop, head, length,+                                                  null, reverse, tail, take,+                                                  (!!))++-- | Range of form [a, b].+--+type RangeInclusive = (Int, Int)++-- | Calculate mean weight for given @s@.+--+-- > sequWeighted = Sequence ['a', 'a', 'b', 'a'] someMarking [0.1, 0.2, 0.3, 0.4]+-- mean sequWeighted == 0.45+--+mean :: ContainsWeight s => s -> Double+mean s = meanInRange s (0, length s - 1)++-- | Calculate mean weight for given @s@ in range 'RangeInclusive'.+--+-- > sequWeighted = Sequence ['a', 'a', 'b', 'a'] someMarkings [0.1, 0.2, 0.3, 0.4]+-- > meanInRange sequWeighted (1, 2) == 0.25+--+meanInRange :: ContainsWeight s => s -> RangeInclusive -> Double+meanInRange (toSequence -> s) (lInd, rInd) = res+  where+    neededWeights = V.take (rInd + 1) $ V.drop lInd $ s ^. weights++    res = mean' $ fmap toDouble neededWeights++    mean' :: Vector Double -> Double+    mean' l = sum l / fromIntegral (V.length l)++-- | Get weight of element of @s@ at given position.+--+getWeight :: (ContainsWeight s, MonadError Text m) => s -> Int -> m (Weight s)+getWeight (toSequence -> s) i | i >= V.length ws = throwError indexError+                              | otherwise        = pure $ ws V.! i+  where+    ws = s ^. weights++    indexError :: Text+    indexError = "Bio.Sequence.Functions.Weight: index out of range."++unsafeGetWeight :: ContainsWeight s => s -> Int -> Weight s+unsafeGetWeight sequ' = unsafeEither . getWeight sequ'++-- | Get 'Weight's of all elements in @s@.+--+getWeights :: ContainsWeight s => s -> [Weight s]+getWeights = V.toList . (^. weights) . toSequence++-- | Converts 'IsBareSequence' @s@ to 'IsWeightedSequence' @s'@ that is weighted using provided list+-- of 'Weight's. If length of 'Weight's list is different from length of @s@, an+-- error is thrown.+--+-- > sequBare = Sequence ['a', 'a', 'b', 'a'] mempty mempty :: BareSequence Char+-- > toMarked sequ [0.1, 0.2, 0.3, 0.4] :: WeightedSequence Double Char+--+toWeighted :: (IsBareSequence s, IsWeightedSequence s', Weight s' ~ w, Element s ~ Element s', MonadError Text m) => s -> [w] -> m s'+toWeighted (toSequence -> s) = weightedSequence (V.toList $ s ^. sequ)++unsafeToWeighted :: (IsBareSequence s, IsWeightedSequence s', Weight s' ~ w, Element s ~ Element s') => s -> [w] -> s'+unsafeToWeighted (toSequence -> s) = unsafeWeightedSequence (V.toList $ s ^. sequ)+
+ src/Bio/Sequence/Utilities.hs view
@@ -0,0 +1,18 @@+module Bio.Sequence.Utilities+  ( Range+  , checkRange+  , unsafeEither+  ) where++import           Data.Text (Text)+import qualified Data.Text as T (unpack)++-- | Range of form [a, b).+--+type Range = (Int, Int)++checkRange :: Int -> Range -> Bool+checkRange len (lInd, rInd) = lInd < rInd && 0 <= lInd && rInd <= len++unsafeEither :: Either Text a -> a+unsafeEither = either (error . T.unpack) id
+ src/Bio/Structure.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE DeriveGeneric  #-}+{-# LANGUAGE DeriveAnyClass #-}+module Bio.Structure+  ( SecondaryStructure (..)+  , Atom (..), Bond (..)+  , Residue (..), Chain (..), Model (..)+  , StructureModels (..), StructureSerializable (..)+  ) where++import           Data.Array      ( Array )+import           Data.Text       ( Text )+import           GHC.Generics    ( Generic )+import           Control.DeepSeq ( NFData (..) )+import           Linear.V3       ( V3 )++-- | Protein secondary structure+--+data SecondaryStructure = PiHelix       -- ^ pi helix+                        | Bend          -- ^ bend+                        | AlphaHelix    -- ^ alpha helix+                        | Extended      -- ^ extended+                        | ThreeTenHelix -- ^ 3-10 helix+                        | Bridge        -- ^ brigde+                        | Turn          -- ^ turn+                        | Coil          -- ^ coil+                        | Undefined     -- ^ unknown structure+  deriving (Show, Eq, Generic)++instance NFData SecondaryStructure++-- | Generic atom representation+--+data Atom = Atom { atomName     :: Text     -- ^ IUPAC atom name +                 , atomElement  :: Text     -- ^ atom chemical element+                 , atomCoords   :: V3 Float -- ^ 3D coordinates of atom+                 , formalCharge :: Int      -- ^ Formal charge of atom+                 , bFactor      :: Float    -- ^ B-factor of atom+                 , occupancy    :: Float    -- ^ the amount of each conformation that is observed in the crystal+                 }+  deriving (Show, Eq, Generic)++instance NFData Atom++-- | Generic chemical bond+--+data Bond = Bond { bondStart :: Int  -- ^ index of first incident atom+                 , bondEnd   :: Int  -- ^ index of second incident atom+                 , bondOrder :: Int  -- ^ the order of chemical bond+                 }+  deriving (Show, Eq, Generic)++instance NFData Bond++-- | A set of atoms, organized to a residues+--+data Residue = Residue { resName         :: Text               -- ^ residue name+                       , resAtoms        :: Array Int Atom     -- ^ a set of residue atoms+                       , resBonds        :: Array Int Bond     -- ^ a set of residue bonds+                       , resSecondary    :: SecondaryStructure -- ^ residue secondary structure+                       , resChemCompType :: Text               -- ^ chemical component type+                       }+  deriving (Show, Eq, Generic, NFData)++-- | Chain organizes linear structure of residues+--+data Chain = Chain { chainName     :: Text              -- ^ name of a chain+                   , chainResidues :: Array Int Residue -- ^ residues of a chain+                   }+  deriving (Show, Eq, Generic, NFData)++-- | Model represents a single experiment of structure determination+--+newtype Model = Model { modelChains :: Array Int Chain }+  deriving (Show, Eq, Generic, NFData)++-- | Convert any format-specific data to an intermediate representation of structure+class StructureModels a where+    -- | Get an array of models+    modelsOf :: a -> Array Int Model++-- | Serialize an intermediate representation of sequence to some specific format+class StructureSerializable a where+    -- | Serialize an array of models to some format+    serializeModels :: Array Int Model -> a
+ src/Bio/Uniprot.hs view
@@ -0,0 +1,22 @@+module Bio.Uniprot+  ( module T+  , parseRecord+  , fetch+  ) where++import           Data.Text.Encoding     ( decodeUtf8 )+import           Data.String            ( IsString(..) )+import           Data.Attoparsec.Text   ( parseOnly )+import           Control.Monad.IO.Class ( MonadIO )+import           Network.HTTP.Simple    ( httpBS, getResponseBody )++import           Bio.Uniprot.Type       as T+import           Bio.Uniprot.Parser++-- | Fetches Uniprot record from Uniprot+fetch :: MonadIO m => String -> m Record+fetch recid = do let url = fromString $ "https://www.uniprot.org/uniprot/" <> recid <> ".txt"+                 resp <- httpBS url+                 case parseOnly parseRecord (decodeUtf8 $ getResponseBody resp) of+                   Left err -> fail err+                   Right r  -> pure r
+ src/Bio/Uniprot/Parser.hs view
@@ -0,0 +1,527 @@+{-# LANGUAGE TupleSections #-}+{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# OPTIONS_GHC -fno-warn-unused-matches #-}+{-# OPTIONS_GHC -fno-warn-unused-local-binds #-}++module Bio.Uniprot.Parser where++import           Prelude              hiding (null)+import qualified Prelude              as P (concat, init, last, null, tail)++import           Bio.Uniprot.Type+import           Control.Applicative  (liftA2, (<|>))+import           Control.Monad        (unless)+import           Data.Attoparsec.Text+import           Data.Bifunctor       (second)+import           Data.Char            (isSpace)+import           Data.Functor         (($>))+import           Data.Monoid          ((<>))+import           Data.Text            (Text, append, isPrefixOf, null, pack,+                                       splitOn, unpack)++-- | Describes possible name type of DE section.+data NameType = RecName | AltName | SubName | Flags | None+  deriving (Show)++-- | Parses ID line of UniProt-KB text file.+parseID :: Parser ID+parseID = do+    string "ID   "+    entryName <- pack <$> many1 (satisfy $ inClass "A-Z0-9_")+    many1 space+    status <- (string "Reviewed" $> Reviewed) <|>+              (string "Unreviewed" $> Unreviewed)+    char ';'+    many1 space+    seqLength <- decimal+    space >> string "AA."+    pure ID{..}++-- | Parses AC lines of UniProt-KB text file.+parseAC :: Parser AC+parseAC = do+    parseStartAC+    initAC <- P.concat <$> many' (parseOneAC <* endOfLine <* parseStartAC)+    lastAC <- parseOneAC+    let accessionNumbers = initAC ++ lastAC+    pure AC{..}+  where+    parseStartAC :: Parser ()+    parseStartAC = string "AC" >> count 3 space >> pure ()++    parseOneAC :: Parser [Text]+    parseOneAC = many1 $ do+        res <- pack <$> many1 (satisfy $ inClass "A-Z0-9_")+        char ';'+        option ' ' (satisfy isHorizontalSpace)+        pure res++-- | Parses 3 DT lines of UniProt-KB text file.+parseDT :: Parser DT+parseDT = do+    (dbIntegrationDate, dbName) <- parseOneDT "integrated into UniProtKB/" <* endOfLine+    (seqVersionDate, seqVersion) <- second (read . unpack) <$> parseOneDT "sequence version " <* endOfLine+    (entryVersionDate, entryVersion) <- second (read . unpack) <$> parseOneDT "entry version "+    pure DT{..}+  where+    parseOneDT :: Text -> Parser (Text, Text)+    parseOneDT txt = do+        string "DT   "+        day <- pack <$> many1 (satisfy $ inClass "A-Z0-9-")+        char ','+        many1 space+        string txt+        x <- pack <$> many1 (satisfy $ inClass "A-Za-z0-9_-")+        char '.'+        pure (day, x)++-- | Parses DE lines of UniProt-KB text file.+parseDE :: Parser DE+parseDE = do+    recName  <- optional $ parseNameDE 0 RecName+    altNames <- many' (endOfLine *> parseAltDE 0)+    subNames <- many' (endOfLine *> parseNameDE 0 SubName)+    includes <- many' (endOfLine *> parseInternal "Includes")+    contains <- many' (endOfLine *> parseInternal "Contains")+    flags    <- option [] (endOfLine *> parseFlagsDE)+    pure DE{..}+  where+    -- | Parses name section like RecName, AltName or SubName.+    parseNameDE :: Int -> NameType -> Parser Name+    parseNameDE indent nameType = do+        fullName <- parseDELine indent nameType "Full"+        shortName <- many' $ endOfLine *> parseDELine indent None "Short"+        ecNumber <- many' $ endOfLine *> parseDELine indent None "EC"+        pure Name{..}++    -- | Parses flag line of DE section+    parseFlagsDE :: Parser [Flag]+    parseFlagsDE = fmap (read . unpack) .+                       ("; " `splitOn`) <$> parseDELine 0 Flags ""++    -- | Parses AltName lines of DE section+    parseAltDE :: Int -> Parser AltName+    parseAltDE indent =+      (Simple <$> parseNameDE indent AltName) <|>+      (Allergen <$> parseDELine indent AltName "Allergen") <|>+      (Biotech <$> parseDELine indent AltName "Biotech") <|>+      (CDAntigen <$> parseDELine indent AltName "CD_antigen") <|>+      (INN <$> parseDELine indent AltName "INN")++    -- | Parses any DE line+    parseDELine :: Int -> NameType -> Text -> Parser Text+    parseDELine indent nameType tpe = do+        string "DE   "+        count indent (char ' ')+        case nameType of+          None -> string "         "+          a    -> string $ append (pack $ show a) ": "+        unless (null tpe) $ do+            string tpe+            string "="+            pure ()+        result <- pack . P.init <$> many1 (satisfy (not . isEndOfLine))+        pure . head $ " {ECO" `splitOn` result++    -- | Parses internal DE entities+    parseInternal :: Text -> Parser DE+    parseInternal name = do+        string "DE   " >> string name >> char ':'+        endOfLine+        recName  <- optional $ parseNameDE 2 RecName+        altNames <- many' (endOfLine *> parseAltDE 2)+        pure $ DE recName altNames [] [] [] []++-- | Parses DE lines of UniProt-KB text file.+parseGN :: Parser [GN]+parseGN = do+    string "GN   "+    geneName <- optional $ parseDefItem "Name"+    optional $ parseBreak "GN"+    synonyms <- option [] $ parseGNList "Synonyms"+    optional $ parseBreak "GN"+    orderedLocusNames <- option [] $ parseGNList "OrderedLocusNames"+    optional $ parseBreak "GN"+    orfNames <- option [] $ parseGNList "ORFNames"+    let gn = GN{..}+    optional $ parseBreak "GN"+    rest <- option [] $ string "and" *> endOfLine *> parseGN+    pure $ gn:rest+  where+    -- | Parses any list item of GN line (like `Synonyms` or `ORFNames`)+    parseGNList :: Text -> Parser [Text]+    parseGNList name = splitOn ", " <$> parseDefItem name++-- | Parses OS lines for one record of UniProt-KB text file.+parseOS :: Parser OS+parseOS = OS . pack . P.init <$> (string "OS   " >> parseMultiLineComment "OS" 3)++-- | Parser OG line of UniProt-KB text file.+parseOG :: Parser OG+parseOG = (parseOGNonPlasmid <* many' (char ' ' >> parseEvidence) <* char '.') <|>+          (Plasmid <$> parseOGPlasmid)+  where+    parseOGNonPlasmid :: Parser OG+    parseOGNonPlasmid = string "OG   " *>+      ((string "Hydrogenosome" $> Hydrogenosome) <|>+       (string "Mitochondrion" $> Mitochondrion) <|>+       (string "Nucleomorph" $> Nucleomorph) <|>+       (string "Plastid; Apicoplast" $> Plastid PlastidApicoplast) <|>+       (string "Plastid; Chloroplast" $> Plastid PlastidChloroplast) <|>+       (string "Plastid; Organellar chromatophore" $> Plastid PlastidOrganellarChromatophore) <|>+       (string "Plastid; Cyanelle" $> Plastid PlastidCyanelle) <|>+       (string "Plastid; Non-photosynthetic plastid" $> Plastid PlastidNonPhotosynthetic) <|>+       (string "Plastid" $> Plastid PlastidSimple))++    parseOGPlasmid :: Parser [Text]+    parseOGPlasmid = do+        string "OG   "+        name <- parseAnyPlasmid+        let separator = char ',' >> optional " and"+        rest <- many' $ separator *> char ' ' *> parseAnyPlasmid+        optional separator+        rest2 <- P.concat <$> many' (endOfLine *> parseOGPlasmid)+        pure $ name : rest ++ rest2++    parseAnyPlasmid :: Parser Text+    parseAnyPlasmid = parseOnePlasmid <|>+                      (("Plasmid" <* optional (char ' ' >> parseEvidence)+                                  <* optional (char '.')) $> "") -- ABSAA_ALCSP hack++    parseOnePlasmid :: Parser Text+    parseOnePlasmid = do+        string "Plasmid "+        pack <$> parsePlasmidName++    parsePlasmidName :: Parser String+    parsePlasmidName = do+        let p = many1 (satisfy $ liftA2 (&&) (notInClass ",{") (not . isEndOfLine))+        part <- p+        nextChar <- peekChar+        plasmid <- case nextChar of+          Just '{' -> parseEvidence >> optional (char '.') $> P.init part+          _        -> pure part+        pure $ if P.last plasmid == '.' then P.init plasmid else plasmid++    countElem :: Eq a => [a] -> a -> Int+    countElem []     _             = 0+    countElem (x:xs) y | x == y    = 1 + countElem xs y+                       | otherwise = countElem xs y++-- | Parser OC line of UniProt-KB text file.+parseOC :: Parser OC+parseOC = OC <$> parseNodes "OC" ';' '.'++-- | Parses OX lines of UniProt-KB text file.+parseOX :: Parser OX+parseOX = do+    string "OX   "+    databaseQualifier <- pack <$> many1 (notChar '=')+    char '='+    taxonomicCode <- pack <$> many1 (notChar ';')+    char ';'+    pure OX{..}++-- | Parses OH line of UniProt-KB text file.+parseOH :: Parser OH+parseOH = do+    string "OH   NCBI_TaxID="+    taxId <- pack <$> many1 (notChar ';')+    char ';'+    hostName' <- many' (satisfy $ not . isEndOfLine)+    let hostName = pack $ if P.null hostName'+                            then ""+                            else P.tail . P.init $ hostName'+    pure OH{..}++-- | Parses RN, RP, RC, RX, RG, RA, RT and RL lines of UniProt-KB text file.+parseRef :: Parser Reference+parseRef = do+    rn <- parseRN+    endOfLine+    rp <- parseRP+    endOfLine+    rc <- option [] (parseRCX STRAIN "RC" <* endOfLine)+    rx <- option [] (parseRCX MEDLINE "RX" <* endOfLine)+    rg <- option [] (many' $ parseRG <* endOfLine)+    ra <- option [] (parseNodes "RA" ',' ';' <* endOfLine)+    rt <- optional  (parseRT <* endOfLine)+    rl <- parseRL+    pure Reference{..}+  where+    parseRN :: Parser Int+    parseRN = do+        number <- (string "RN   [" *> decimal) <* char ']'+        -- Despite the specification, edivence may be presented here+        _ <- many' (char ' ' *> parseEvidence)+        pure number++    parseRP :: Parser Text+    parseRP = do+        string "RP   "+        pack . P.init <$> parseMultiLineComment "RP" 3++    parseRCX :: (Enum a, Show a) => a -> Text -> Parser [(a, Text)]+    parseRCX start name = do+       string name >> string "   "+       (:) <$> parseTokPair start+           <*> many' (parseBreak name *> parseTokPair start)+     where+       parseTokPair :: (Enum a, Show a) => a -> Parser (a, Text)+       parseTokPair x = foldl1 (<|>) $+                          (\x -> (x,) <$> parseDefItem (pack . show $ x)) <$> [x..]++    parseRG :: Parser Text+    parseRG = pack <$> (string "RG   " *> many1 (satisfy $ not . isEndOfLine))++    parseRT :: Parser Text+    parseRT = do+        string "RT   \""+        let p = many1 $ satisfy $ liftA2 (&&) (not . isEndOfLine) (notInClass "\"")+        referenceTitle <- (:) <$> p <*> many' (endOfLine *> string "RT  " *> p)+        string "\";"+        pure $ pack . hyphenConcat $ referenceTitle++    parseRL :: Parser Text+    parseRL = do+        string "RL   "+        pack . P.init <$> parseMultiLineComment "RL" 3++-- | Parses CC lines of UniProt-KB text file.+parseCC :: Parser CC+parseCC = do+    string "CC   -!- "+    topic <- pack <$> many1 (notChar ':')+    char ':'+    (char ' ' $> ()) <|> (endOfLine >> string "CC" >> count 7 space $> ())+    comment <- head . (" {ECO" `splitOn`) . pack <$> parseMultiLineComment "CC" 7+    pure CC{..}++-- | UniProt-KB copyright comment+copyrightCC :: Text+copyrightCC = "CC   -----------------------------------------------------------------------\nCC   Copyrighted by the UniProt Consortium, see https://www.uniprot.org/terms\nCC   Distributed under the Creative Commons Attribution (CC BY 4.0) License\nCC   -----------------------------------------------------------------------"+++-- | Parses DR lines of UniProt-KB text file.+parseDR :: Parser DR+parseDR = do+    string "DR   "+    resourceAbbr <- parseToken+    char ' '+    resourceId <- parseToken+    optionalInfo <- many1 (char ' ' *> parseToken)+    pure DR{..}+  where+    parseToken :: Parser Text+    parseToken = pack <$> parseTokenStr++    parseTokenStr :: Parser String+    parseTokenStr = do+        part <- many1 (satisfy $ liftA2 (&&) (/=';') (not . isEndOfLine))+        nextChar <- peekChar+        case nextChar of+          Nothing  -> pure . P.init $ part+          Just ';' -> do+              char ';'+              nextChar <- peekChar+              case nextChar of+                Nothing -> fail "You cannot be here"+                Just c  | isSpace c -> pure part+                Just c  -> (part <>) . (';':) <$> parseTokenStr+          Just c  -> pure . P.init $ part++-- | Parses PE line of UniProt-KB text file.+parsePE :: Parser PE+parsePE = (string "PE   1: Evidence at protein level;" $> EvidenceAtProteinLevel) <|>+          (string "PE   2: Evidence at transcript level;" $> EvidenceAtTranscriptLevel) <|>+          (string "PE   3: Inferred from homology;" $> InferredFromHomology) <|>+          (string "PE   4: Predicted;" $> Predicted) <|>+          (string "PE   5: Uncertain;" $> Uncertain)++-- | Parses KW lines of UniProt-KB text file.+parseKW :: Parser KW+parseKW = KW <$> parseNodes "KW" ';' '.'++-- | Parses FT lines of UniProt-KB text file. One FT section is parsed.+parseFT :: Parser FT+parseFT = do+    string "FT   "+    keyName <- pack <$> many1 (satisfy $ inClass "A-Z_")+    many1 space+    fromEP <- parseFTEndpoint+    many1 space+    toEP <- parseFTEndpoint+    description <- filter (not . ("{ECO" `isPrefixOf`)) . splitByMagic <$>+                     ((many' (char ' ') *> parseMultiLineComment "FT" 32) <|>+                      (hyphenConcat <$> parseMultiLine "FT" 32))+    pure FT{..}+  where+    -- | Parse FT endpoint+    parseFTEndpoint :: Parser Endpoint+    parseFTEndpoint = (UncertainEP <$> (char '?' *> decimal)) <|>+                      (NTerminalEP <$> (char '<' *> decimal)) <|>+                      (CTerminalEP <$> (char '>' *> decimal)) <|>+                      (ExactEP     <$> decimal) <|>+                      (char '?' $> UnknownEP)++    -- | Split string to tokens by periods outside brackets.+    splitByMagic :: String -> [Text]+    splitByMagic txt = pack <$> splitStr 0 [] txt+      where+        splitStr :: Int -> String -> String -> [String]+        splitStr _ _   []           = []+        splitStr 0 acc ['.']        = [reverse acc]+        splitStr 0 acc ('.':' ':xs) = reverse acc : splitStr 0 [] xs+        splitStr 0 acc ('.':xs)     = reverse acc : splitStr 0 [] xs+        splitStr n acc ('(':xs)     = splitStr (n+1) ('(':acc) xs+        splitStr n acc (')':xs)     = splitStr (n-1) (')':acc) xs+        splitStr n acc (x:xs)       = splitStr n (x:acc) xs++-- | Parses SQ lines of UniProt-KB text file.+parseSQ :: Parser SQ+parseSQ = do+    string "SQ   SEQUENCE"+    many1 space+    len <- decimal+    space >> string "AA;"+    many1 space+    molWeight <- decimal+    space >> string "MW;"+    many1 space+    crc64 <- pack <$> many1 (satisfy $ inClass "A-F0-9")+    space >> string "CRC64;"+    endOfLine+    sequ <- pack . P.concat <$>+            many1 (skipSpace *> many1 (satisfy $ inClass "A-Z"))+    pure SQ{..}++-- | Parses end of one UniProt record.+parseEnd :: Parser ()+parseEnd = string "//" >> pure ()++-- | Parses whole UniProt-KB record.+parseRecord :: Parser Record+parseRecord = Record <$>           (parseID  <* endOfLine)+                     <*>           (parseAC  <* endOfLine)+                     <*>           (parseDT  <* endOfLine)+                     <*>           (parseDE  <* endOfLine)+                     <*> option [] (parseGN  <* endOfLine)+                     <*>           (parseOS  <* endOfLine)+                     <*> many'     (parseOG  <* endOfLine)+                     <*>           (parseOC  <* endOfLine)+                     <*>           (parseOX  <* endOfLine)+                     <*> many'     (parseOH  <* endOfLine)+                     <*> many'     (parseRef <* endOfLine)+                     <*> many'     (parseCC  <* endOfLine) <* option "" (string copyrightCC <* endOfLine)+                     <*> many'     (parseDR  <* endOfLine)+                     <*>           (parsePE  <* endOfLine)+                     <*> optional  (parseKW  <* endOfLine)+                     <*> many'     (parseFT  <* endOfLine)+                     <*>           (parseSQ  <* endOfLine)+                     <*            parseEnd++parseEvidence :: Parser Text+parseEvidence = (\x y z -> x <> y <> z) <$>+                  string "{" <*> (pack <$> many1 (notChar '}')) <*> string "}"++-- = Helper parsers++-- | Transforms any parser to a parser of maybe value.+--+-- >>> parseOnly (optional digit) "1"+-- Right (Just 1)+--+-- >>> parseOnly (optional digit) ""+-- Right Nothing+optional :: Parser a -> Parser (Maybe a)+optional par = option Nothing (Just <$> par)++-- | Parses lines, that contain nodes splitted by `del` and ended by `end`.+parseNodes :: Text          -- ^Start 2-letter mark.+           -> Char          -- ^Delimeter char, that splits the nodes.+           -> Char          -- ^Terminal char, that ends the node list.+           -> Parser [Text]+parseNodes start del end = do+    string start >> count 3 (char ' ')+    parseNodesNoStart+  where+    parseNodesNoStart :: Parser [Text]+    parseNodesNoStart = do+        part <- parseNode+        c <- char del <|> char end+        if c == del+          then do (char ' ' $> ()) <|> (endOfLine >> string start >> count 3 (char ' ') $> ())+                  (part :) <$> parseNodesNoStart+          else do nextChar <- peekChar+                  case nextChar of+                    Nothing                -> pure [part]+                    Just c | isEndOfLine c -> pure [part]+                    Just c                 -> do (x:xs) <- parseNodesNoStart+                                                 pure (part <> x : xs)++    parseNode :: Parser Text+    parseNode = pack <$> many1 (satisfy $ liftA2 (&&) (notInClass [del,end]) (not . isEndOfLine))++-- | Parses line till the end.+parseTillEnd :: Parser String+parseTillEnd = many1 $ satisfy (not . isEndOfLine)++-- | Parses multiline comment as one string.+parseMultiLineComment :: Text -> Int -> Parser String+parseMultiLineComment start skip = hyphenConcat <$>+                                     ((:) <$> parseTillEnd+                                          <*> parseMultiLine start skip)++-- | Parses multiline comment from new line.+parseMultiLine :: Text -> Int -> Parser [String]+parseMultiLine start skip = many' $ do+    endOfLine+    string start+    count (skip - 1) (char ' ') -- leave one space to separate words+    parseTillEnd++-- | Parses line break for multiline section.+parseBreak :: Text -> Parser ()+parseBreak txt = ((endOfLine >> string txt >> string "   ") <|> string " ") $> ()++-- | Parses one item like "Something=Something else;"+parseDefItem :: Text -> Parser Text+parseDefItem name = do+    string name >> char '='+    head . (" {" `splitOn`) . pack <$> parseTillChar ';'++-- | Parses line till specific char (e.g. semicolon or dot) before space/endOfLine/endOfInput.+parseTillChar :: Char -> Parser String+parseTillChar c = do+    part <- many1 $ satisfy $ liftA2 (&&) (/=c) (not . isEndOfLine)+    nextChar <- peekChar+    case nextChar of+      Nothing                -> fail "You cannot be here!"+      Just d | d == c        -> do+          char c+          nextChar <- peekChar+          case nextChar of+            Nothing -> pure part+            Just d  | isSpace d -> pure part+            Just d  -> (part <>) . (d:) <$> parseTillChar c+      Just d | isEndOfLine d -> do+          endOfLine+          count 2 anyChar+          count 2 (char ' ')+          (part <>) <$> parseTillChar c+      Just _                 -> fail "You cannot be here!"++-- | Delete needless space after hyphen on concat.+hyphenConcat :: [String] -> String+hyphenConcat []       = []+hyphenConcat [x]      = x+hyphenConcat (x:y:ys) = x ++ hyphenConcat (sy:ys)+  where+    sy :: String+    sy | last x == '-'                  = tail y+       | isAA (last x) && isAA (y !! 1) = tail y+       | otherwise                      = y++    isAA :: Char -> Bool+    isAA = inClass "A-Z"
+ src/Bio/Uniprot/Type.hs view
@@ -0,0 +1,255 @@+module Bio.Uniprot.Type where++import           Data.Text    (Text)+import           GHC.Generics (Generic)++-- | Which taxonomic 'kingdom' an+--   organism belongs to.+data Kingdom+  = Archea    -- ^ 'A' for archaea (=archaebacteria)+  | Bacteria  -- ^ 'B' for bacteria (=prokaryota or eubacteria)+  | Eukaryota -- ^ 'E' for eukaryota (=eukarya)+  | Virus     -- ^ 'V' for viruses and phages (=viridae)+  | Other     -- ^ 'O' for others (such as artificial sequences)+  deriving (Generic, Show, Eq, Ord, Bounded, Enum)++-- | Controlled vocabulary of species+data Organism = Organism+  { code         :: Text       -- ^ Code of organism (up to 5 symbols)+  , kingdom      :: Kingdom    -- ^ Kingdom of organism+  , officialName :: Text       -- ^ Official (scientific) name+  , commonName   :: Maybe Text -- ^ Common name+  , synonym      :: Maybe Text -- ^ Synonym name+  } deriving (Generic, Show, Eq, Ord)++-- | To distinguish the fully annotated entries in the Swiss-Prot+--   section of the UniProt Knowledgebase from the computer-annotated+--   entries in the TrEMBL section, the 'status' of each entry is+--   indicated in the first (ID) line of each entry+data Status+  = Reviewed   -- ^ Entries that have been manually reviewed and annotated by UniProtKB curators+  | Unreviewed -- ^ Computer-annotated entries that have not been reviewed by UniProtKB curators+  deriving (Generic, Show, Eq, Ord, Bounded, Enum)++-- | IDentification+data ID = ID+  { entryName :: Text   -- ^ This name is a useful means of identifying a sequence, but it is not a stable identifier as is the accession number.+  , status    :: Status -- ^ The status of the entry+  , seqLength :: Int    -- ^ The length of the molecule, which is the total number of amino acids in the sequence. This number includes the positions reported to be present but which have not been determined (coded as 'X').+  } deriving (Generic, Show, Eq, Ord)++-- | ACcession numbers.+--   The purpose of accession numbers is to provide a stable way of+--   identifying entries from release to release. It is sometimes+--   necessary for reasons of consistency to change the names of the+--   entries, for example, to ensure that related entries have similar+--   names. However, an accession number is always conserved, and+--   therefore allows unambiguous citation of entries.+--   Researchers who wish to cite entries in their publications should+--   always cite the first accession number. This is commonly referred+--   to as the 'primary accession number'. 'Secondary accession numbers'+--   are sorted alphanumerically.+newtype AC = AC+  { accessionNumbers :: [Text]+  } deriving (Generic, Show, Eq, Ord)++-- | DaTe: the date of creation and last modification of the database entry.+data DT = DT+  { dbIntegrationDate :: Text -- ^ Indicates when the entry first appeared in the database.+  , dbName            :: Text -- ^ Indicates in which section of UniProtKB, Swiss-Prot or TrEMBL, the entry can be found.+  , seqVersionDate    :: Text -- ^ Indicates when the sequence data was last modified.+  , seqVersion        :: Int  -- ^ The sequence version number of an entry is incremented by one when the amino acid sequence shown in the sequence record is modified.+  , entryVersionDate  :: Text -- ^ Indicates when data other than the sequence was last modified.+  , entryVersion      :: Int  -- ^ The entry version number is incremented by one whenever any data in the flat file representation of the entry is modified.+  } deriving (Generic, Show, Eq, Ord)++data Name = Name+  { fullName  :: Text   -- ^ The full name.+  , shortName :: [Text] -- ^ A set of abbreviations of the full name or acronyms.+  , ecNumber  :: [Text] -- ^ A set of Enzyme Commission numbers.+  } deriving (Generic, Show, Eq, Ord)++data AltName = Simple Name+             | Allergen Text+             | Biotech Text+             | CDAntigen Text+             | INN Text+  deriving (Generic, Show, Eq, Ord)++data Flag+  = Fragment  -- ^ The complete sequence is not determined.+  | Fragments -- ^ The complete sequence is not determined.+  | Precursor -- ^ The sequence displayed does not correspond to the mature form of the protein.+  deriving (Generic, Show, Read, Eq, Ord, Bounded, Enum)++-- | DEscription - general descriptive information about the sequence stored.+data DE = DE+  { recName  :: Maybe Name -- ^ The name recommended by the UniProt consortium.+  , altNames :: [AltName]  -- ^ A synonym of the recommended name.+  , subNames :: [Name]     -- ^ A name provided by the submitter of the underlying nucleotide sequence.+  , includes :: [DE]       -- ^ A protein is known to include multiple functional domains each of which is described by a different name.+  , contains :: [DE]       -- ^ The functional domains of an enzyme are cleaved, but the catalytic activity can only be observed, when the individual chains reorganize in a complex.+  , flags    :: [Flag]     -- ^ Flags whether the entire is a precursor or/and a fragment.+  } deriving (Generic, Show, Eq, Ord)++-- | Gene Name - the name(s) of the gene(s) that code for the stored protein sequence.+data GN = GN+  { geneName          :: Maybe Text -- ^ The name used to represent a gene.+  , synonyms          :: [Text]     -- ^ Other (unofficial) names of a gene.+  , orderedLocusNames :: [Text]     -- ^ A name used to represent an ORF in a completely sequenced genome or chromosome.+  , orfNames          :: [Text]     -- ^ A name temporarily attributed by a sequencing project to an open reading frame.+  } deriving (Generic, Show, Eq, Ord)++-- | Organism Species - the organism which was the source of the stored sequence.+newtype OS = OS+  { specie :: Text+  } deriving (Generic, Show, Eq, Ord)++-- | A enum of possible plastid types, based on either taxonomic+--   lineage or photosynthetic capacity.+data Plastid = PlastidSimple                  -- ^ The term Plastid is used when the capacities of the organism are unclear; for example in the parasitic plants of the Cuscuta lineage, where sometimes young tissue is photosynthetic.+             | PlastidApicoplast              -- ^ Apicoplasts are the plastids found in Apicocomplexa parasites such as Eimeria, Plasmodium and Toxoplasma; they are not photosynthetic.+             | PlastidChloroplast             -- ^ Chloroplasts are the plastids found in all land plants and algae with the exception of the glaucocystophyte algae (see below). Chloroplasts in green tissue are photosynthetic; in other tissues they may not be photosynthetic and then may also have secondary information relating to subcellular location (e.g. amyloplasts, chromoplasts).+             | PlastidOrganellarChromatophore -- ^ Chloroplasts are the plastids found in all land plants and algae with the exception of the glaucocystophyte algae (see below). Chloroplasts in green tissue are photosynthetic; in other tissues they may not be photosynthetic and then may also have secondary information relating to subcellular location (e.g. amyloplasts, chromoplasts).+             | PlastidCyanelle                -- ^ Cyanelles are the plastids found in the glaucocystophyte algae. They are also photosynthetic but their plastid has a vestigial cell wall between the 2 envelope membranes.+             | PlastidNonPhotosynthetic       -- ^ Non-photosynthetic plastid is used when the plastid in question derives from a photosynthetic lineage but the plastid in question is missing essential genes. Some examples are Aneura mirabilis, Epifagus virginiana, Helicosporidium (a liverwort, higher plant and green alga respectively).+  deriving (Generic, Show, Eq, Ord, Bounded, Enum)++-- | OrGanelle - indicates if the gene coding for a protein originates+--   from mitochondria, a plastid, a nucleomorph or a plasmid.+data OG = Hydrogenosome   -- ^ Hydrogenosomes are membrane-enclosed redox organelles found in some anaerobic unicellular eukaryotes which contain hydrogenase and produce hydrogen and ATP by glycolysis. They are thought to have evolved from mitochondria; most hydrogenosomes lack a genome, but some like (e.g. the anaerobic ciliate Nyctotherus ovalis) have retained a rudimentary genome.+        | Mitochondrion   -- ^ Mitochondria are redox-active membrane-bound organelles found in the cytoplasm of most eukaryotic cells. They are the site of sthe reactions of oxidative phosphorylation, which results in the formation of ATP.+        | Nucleomorph     -- ^ Nucleomorphs are reduced vestigal nuclei found in the plastids of cryptomonad and chlorachniophyte algae. The plastids originate from engulfed eukaryotic phototrophs.+        | Plasmid [Text]  -- ^ Plasmid with a specific name. If an entry reports the sequence of a protein identical in a number of plasmids, the names of these plasmids will all be listed.+        | Plastid Plastid -- ^ Plastids are classified based on either their taxonomic lineage or in some cases on their photosynthetic capacity.+  deriving (Generic, Show, Eq, Ord)++-- | Organism Classification - the taxonomic classification of the source organism.+newtype OC = OC+  { nodes :: [Text]+  } deriving (Generic, Show, Eq, Ord)++-- | Organism taxonomy cross-reference indicates the identifier of a+--   specific organism in a taxonomic database.+data OX = OX+  { databaseQualifier :: Text -- ^ Taxonomy database Qualifier+  , taxonomicCode     :: Text -- ^ Taxonomic code+  } deriving (Generic, Show, Eq, Ord)++-- | Organism Host - indicates the host organism(s) that are susceptible +--   to be infected by a virus. Appears only in viral entries.+data OH = OH+  { taxId    :: Text -- ^+  , hostName :: Text -- ^+  } deriving (Generic, Show, Eq, Ord)++-- | Reference comment token.+data Token = STRAIN+           | PLASMID+           | TRANSPOSON+           | TISSUE+  deriving (Generic, Show, Eq, Ord, Bounded, Enum)++-- | Bibliographic database names.+data BibliographicDB = MEDLINE+                     | PubMed+                     | DOI+                     | AGRICOLA+  deriving (Generic, Show, Eq, Ord, Bounded, Enum)++-- | Reference Number - a sequential number to each reference citation in an entry.+data RN = RN+  { number   :: Int+  , evidence :: [Text]+  } deriving (Generic, Show, Eq, Ord)++-- | Reference lines.+data Reference = Reference+  { rn :: Int                       -- ^ Reference Number - a sequential number to each reference citation in an entry.+  , rp :: Text                      -- ^ Reference Position - the extent of the work relevant to the entry carried out by the authors.+  , rc :: [(Token, Text)]           -- ^ Reference Comment - comments relevant to the reference cited.+  , rx :: [(BibliographicDB, Text)] -- ^ Reference cross-reference - the identifier assigned to a specific reference in a bibliographic database.+  , rg :: [Text]                    -- ^ Reference Group - the consortium name associated with a given citation.+  , ra :: [Text]                    -- ^ Reference Author - authors of the paper (or other work) cited.+  , rt :: Maybe Text                -- ^ Reference Title - the title of the paper (or other work) cited as exactly as possible given the limitations of the computer character set.+  , rl :: Text                      -- ^ Reference Location - he conventional citation information for the reference.+  } deriving (Generic, Show, Eq, Ord)++-- | The comment blocks are arranged according to what we designate as 'topics'.+type Topic = Text++-- | Free text comments on the entry, and are used to convey any useful information.+data CC = CC+  { topic   :: Topic+  , comment :: Text+  } deriving (Generic, Show, Eq, Ord)++-- | Database cross-Reference - pointers to information in external+--   data resources that is related to UniProtKB entries.+data DR = DR+  { resourceAbbr :: Text   -- ^ The abbreviated name of the referenced resource (e.g. PDB).+  , resourceId   :: Text   -- ^ An unambiguous pointer to a record in the referenced resource.+  , optionalInfo :: [Text] -- ^ Used to provide optional information.+  } deriving (Generic, Show, Eq, Ord)++-- | Protein existence - indication on the evidences that we currently+--   have for the existence of a protein. Because most protein sequences+--   are derived from translation of nucleotide sequences and are mere+--   predictions, the PE line indicates what the evidences are of the+--   existence of a protein.+data PE = EvidenceAtProteinLevel+        | EvidenceAtTranscriptLevel+        | InferredFromHomology+        | Predicted+        | Uncertain+  deriving (Generic, Show, Eq, Ord)++-- | KeyWord - information that can be used to generate indexes of the+--   sequence entries based on functional, structural, or other categories.+newtype KW = KW+  { keywords :: [Text]+  } deriving (Generic, Show, Eq, Ord)++data Endpoint = ExactEP Int+              | NTerminalEP Int+              | CTerminalEP Int+              | UncertainEP Int+              | UnknownEP+  deriving (Generic, Show, Eq, Ord)++-- | Feature Table - means for the annotation of the sequence data.+data FT = FT+  { keyName     :: Text     -- ^ Key name.+  , fromEP      :: Endpoint -- ^ 'From' endpoint.+  , toEP        :: Endpoint -- ^ 'To' endpoint.+  , description :: [Text]   -- ^ Description.+  } deriving (Generic, Show, Eq, Ord)++-- | SeQuence header - sequence data and a quick summary of its content.+data SQ = SQ+  { len       :: Int  -- ^ Length of the sequence in amino acids.+  , molWeight :: Int  -- ^ Molecular weight rounded to the nearest mass unit (Dalton).+  , crc64     :: Text -- ^ Sequence 64-bit CRC (Cyclic Redundancy Check) value.+  , sequ      :: Text -- ^ Sequence of the protein+  } deriving (Generic, Show, Eq, Ord)++-- | Full UniProt record in UniProt-KB format.+data Record = Record+  { id   :: ID+  , ac   :: AC+  , dt   :: DT+  , de   :: DE+  , gn   :: [GN]+  , os   :: OS+  , og   :: [OG]+  , oc   :: OC+  , ox   :: OX+  , oh   :: [OH]+  , refs :: [Reference]+  , cc   :: [CC]+  , dr   :: [DR]+  , pe   :: PE+  , kw   :: Maybe KW+  , ft   :: [FT]+  , sq   :: SQ+  } deriving (Generic, Show, Eq, Ord)
+ test/ABISpec.hs view
@@ -0,0 +1,60 @@+module ABISpec where++import           Bio.ABI                 (Cleanable (..))+import           Bio.Sequence            (SequenceDecodable (..))+import qualified Bio.Sequence            as S (getWeights, length, toList)+import           Bio.Sequence.Basecalled (BasecalledSequence)+import           Data.ByteString.Lazy    as BSL (readFile)+import           Data.Text               (Text)+import           Test.Hspec++abiExtractSpec :: Spec+abiExtractSpec =+  describe "ABI decode" $ do+    it "decode good ABI file" $ do+      Right dat <- readData "test/ABI/test.ab1"+      S.length dat     `shouldBe` 465+      S.toList dat     `shouldBe` goodSequence+      S.getWeights dat `shouldBe` goodQuality++    it "not decode non-ABI file" $ do+      datM <- readData "test/ABI/not_ab1.txt"+      datM `shouldBe` Left "Error reading root: not enough bytes"+++abiCleanSpec :: Spec+abiCleanSpec =+  describe "ABI clean" $ do+    it "clean good ABI file" $+      checkFile "test/ABI/test.ab1" 465 428 "AGGGGT"++    it "clean another good ABI file" $+      checkFile "test/ABI/bad_at_the_end.ab1" 1116 955 "TTCCTT"++    it "totally clean bad ABI file" $ do+      Right dat <- readData "test/ABI/bad_quality.ab1"+      clean dat `shouldBe` Nothing+  where+    checkFile :: FilePath -> Int -> Int -> String -> IO ()+    checkFile path lengthBefore lengthAfter start = do+        Right dat <- readData path+        S.length dat `shouldBe` lengthBefore++        let Just cleaned = clean dat+        S.length cleaned `shouldBe` lengthAfter++        S.toList cleaned `shouldStartWith` start++readData :: FilePath -> IO (Either Text BasecalledSequence)+readData path = do+    bsl <- BSL.readFile path+    pure $ sequenceDecode bsl+++goodSequence :: String+goodSequence = "AATTGGCAGTATTTAGTAATAACAAATAGGGGTTCCGCGCACATTTCCCCGAAAAGTGCCACCTGCGGCCGCTGTACACTAGTGATCGTACGGGCCCATGCATGCTAGCAAGCTTGTCGACATTACCCTGTTATCCCTATTCGCTACCTTAGGACCGTTATAGTTACGACCCATACACTAGTGATCGTACGGGCCCATGCATGCTAGCAAGCTTGTCGACATTACCCTGTTATCCCTATTCGCTACCTTAGGACCGTTATAGTTACGCTTGTCGACATTACCCTGTTATCCCTATTCGCTACCTTAGGACCGTTATAGTTACGACCCATAATACCCATAATAGCTGTTTGCCAATCTAGAGGTACCTCCGGAATGTCGCTTCCTCGCTCACTGACTCGCTGCGCTCGGTCGTTCGGCTGCGGCGAGCGGTATCAGCTCACTCAAAGGCGGTAATACGGTTATCAA"++goodQuality :: [Double]+goodQuality = [11.0,6.0,3.0,3.0,3.0,3.0,4.0,4.0,6.0,4.0,5.0,11.0,23.0,6.0,14.0,5.0,4.0,10.0,26.0,6.0,7.0,7.0,26.0,26.0,26.0,51.0,39.0,41.0,51.0,58.0,49.0,49.0,58.0,54.0,58.0,58.0,54.0,58.0,36.0,29.0,48.0,46.0,28.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,41.0,41.0,62.0,62.0,62.0,47.0,49.0,62.0,62.0,49.0,62.0,54.0,54.0,47.0,41.0,24.0,24.0,27.0,22.0,27.0,22.0,22.0,14.0,11.0,16.0,32.0,51.0,62.0,59.0,59.0,59.0,59.0,28.0,35.0,54.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,59.0,59.0,59.0,62.0,62.0,59.0,62.0,59.0,59.0,46.0,54.0,48.0,62.0,59.0,62.0,62.0,59.0,59.0,59.0,62.0,59.0,59.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,54.0,54.0,59.0,59.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,54.0,54.0,62.0,54.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,59.0,59.0,62.0,59.0,59.0,59.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,59.0,62.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,59.0,59.0,50.0,59.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,54.0,62.0,62.0,54.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,59.0,62.0,51.0,62.0,62.0,62.0,62.0,54.0,49.0,62.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,51.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,56.0,56.0,62.0,62.0,56.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,43.0,43.0,62.0,62.0,62.0,59.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,59.0,59.0,46.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,56.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,62.0,49.0,49.0,62.0,62.0,62.0,62.0,56.0,42.0,42.0,56.0,46.0,56.0,43.0,36.0,43.0,51.0,62.0,7.0,8.0,8.0,9.0,5.0]++
+ test/FASTASpec.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE OverloadedStrings #-}++module FASTASpec where++import           Bio.FASTA          (fromFile, toFile)+import           Bio.FASTA.Type     (FastaItem(..), Fasta)+import           Bio.Sequence       (bareSequence)+import           Prelude     hiding (writeFile, readFile)+import           Test.Hspec++correctFasta :: Fasta Char+correctFasta = [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL"), FastaItem "7HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]++fastaSpec :: Spec+fastaSpec = describe "Fasta file parser." $ do+    parseFile "test/FASTA/correct.fasta"+    writeFile "test/FASTA/test.fasta"++parseFile :: FilePath -> Spec+parseFile path = describe "fromFile" $ do+    it "correctly parses fasta from file" $ do+        fasta <- fromFile path+        fasta `shouldBe` correctFasta++writeFile :: FilePath -> Spec+writeFile path = describe "writeFile" $ do+    it "correctly write fasta into file" $ do+        toFile correctFasta path+        fasta <- fromFile path+        fasta `shouldBe` correctFasta
+ test/FastaParserSpec.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE OverloadedStrings #-}++module FastaParserSpec where++import           Bio.FASTA.Parser       (fastaP)+import           Bio.FASTA.Type         (FastaItem(..))+import           Bio.Sequence           (bareSequence)+import           Data.Attoparsec.Text   (parseOnly)+import           Test.Hspec++fastaParserSpec :: Spec+fastaParserSpec = describe "Fasta format parser." $ do+    emptyFasta+    onlyName+    oneSequence+    twoSequences+    sequenceWithDigit+    sequenceWithWrongName+    sequenceWithSpacesInName+    sequenceWithSeveralEndOfLine+    sequenceWithSeveralEndOfLineInSequence+    sequenceWithTabsInName+    sequenceWithTabsInSequence++emptyFasta :: Spec+emptyFasta = describe "emptyFasta" $ do+    it "correctly parses empty fasta" $ do+        let res = parseOnly fastaP ""+        res `shouldBe` Right []++onlyName :: Spec+onlyName = describe "onlyName" $ do+    it "correctly parses fasta without sequence" $ do+        let res = parseOnly fastaP ">3HMX:A|PDBID|CHAIN|SEQUENCE"+        res `shouldBe` Right [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "")]++oneSequence :: Spec+oneSequence = describe "oneSequence" $ do+    it "correctly parses one correct sequence" $ do+        let res = parseOnly fastaP ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSE\nVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\n"+        res `shouldBe` Right [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]++twoSequences :: Spec+twoSequences = describe "twoSequences" $ do+    it "correctly parses two correct sequences" $ do+        let res = parseOnly fastaP ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSE\nVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\n>7HMX:A|PDBID|CHAIN|SEQUENCE\nEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\nVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL"+        res `shouldBe` Right [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL"), FastaItem "7HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]++sequenceWithDigit :: Spec+sequenceWithDigit = describe "sequenceWithDigit" $ do+    it "correctly parses incorrect sequence with digit" $ do+        let res = parseOnly fastaP ">123\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEE4GITWTLDQSSE"+        res `shouldBe` Right [FastaItem "123" (bareSequence "")]++sequenceWithWrongName :: Spec+sequenceWithWrongName = describe "sequenceWithWrongName" $ do+    it "correctly parses incorrect sequence with wrong name" $ do+        let res = parseOnly fastaP "123\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE"+        res `shouldBe` Right []++sequenceWithSpacesInName :: Spec+sequenceWithSpacesInName = describe "sequenceWithSpacesInName" $ do+    it "correctly parses sequence with spaces in name" $ do+        let res = parseOnly fastaP ">  this is my sequence   \nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE"+        res `shouldBe` Right [FastaItem "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE")]++sequenceWithSeveralEndOfLine :: Spec+sequenceWithSeveralEndOfLine = describe "sequenceWithSeveralEndOfLine" $ do+    it "correctly parses sequence with several \n after name" $ do+        let res = parseOnly fastaP ">this is my sequence\n\n\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE"+        res `shouldBe` Right [FastaItem "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE")]++sequenceWithSeveralEndOfLineInSequence :: Spec+sequenceWithSeveralEndOfLineInSequence = describe "sequenceWithSeveralEndOfLineInSequence" $ do+    it "correctly parses sequence with several \n between sequence parts" $ do+        let res = parseOnly fastaP ">this is my sequence\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE\n\n\nYYYYYYYYYYYYYYYYYYYYYYYY"+        res `shouldBe` Right [FastaItem "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSEYYYYYYYYYYYYYYYYYYYYYYYY")]++sequenceWithTabsInName :: Spec+sequenceWithTabsInName = describe "sequenceWithTabsInName" $ do+    it "correctly parses sequence with tabs in name" $ do+        let res = parseOnly fastaP ">\tthis\tis\tmy\tsequence\t\t\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE"+        res `shouldBe` Right [FastaItem "this\tis\tmy\tsequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE")]++sequenceWithTabsInSequence :: Spec+sequenceWithTabsInSequence = describe "sequenceWithTabsInSequence" $ do+    it "correctly parses sequence with tabs between sequence parts" $ do+        let res = parseOnly fastaP ">this is my sequence\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSE\t\t\nYYYYYYYYYYYYYYYYYYYYYYYY\t\n"+        res `shouldBe` Right [FastaItem "this is my sequence" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEGITWTLDQSSEYYYYYYYYYYYYYYYYYYYYYYYY")]
+ test/FastaWriterSpec.hs view
@@ -0,0 +1,37 @@+module FastaWriterSpec where++import           Bio.FASTA.Writer       (fastaToText)+import           Bio.FASTA.Type         (FastaItem(..))+import           Bio.Sequence           (bareSequence)+import           Test.Hspec++fastaWriterSpec :: Spec+fastaWriterSpec = describe "Fasta format parser." $ do+    emptyFasta+    oneShortSequence+    oneLongSequence+    twoSequences++emptyFasta :: Spec+emptyFasta = describe "emptyFasta" $ do+    it "correctly write empty fasta" $ do+        let res = fastaToText []+        res `shouldBe` ""++oneShortSequence :: Spec+oneShortSequence = describe "oneShortSequence" $ do+    it "correctly write one correct short (less than 80 chars) sequence" $ do+        let res = fastaToText [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL")]+        res `shouldBe` ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\n"++oneLongSequence :: Spec+oneLongSequence = describe "oneLongSequence" $ do+    it "correctly write one correct long (more than 80 chars) sequence" $ do+        let res = fastaToText [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLLLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRGDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTWSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS")]+        res `shouldBe` ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\nLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRG\nDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTW\nSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS\n"++twoSequences :: Spec+twoSequences = describe "twoSequences" $ do+    it "correctly write two correct sequences" $ do+        let res = fastaToText [FastaItem "3HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL"), FastaItem "7HMX:A|PDBID|CHAIN|SEQUENCE" (bareSequence "IWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLLLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRGDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTWSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS")]+        res `shouldBe` ">3HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\n>7HMX:A|PDBID|CHAIN|SEQUENCE\nIWELKKDVYVVELDWYPDAPGEMVVLTCDTPEEDGITWTLDQSSEVLGSGKTLTIQVKEFGDAGQYTCHKGGEVLSHSLL\nLLHKKEDGIWSTDILKDQKEPKNKTFLRCEAKNYSGRFTCWWLTTISTDLTFSVKSSRGSSDPQGVTCGAATLSAERVRG\nDNKEYEYSVECQEDSACPAAEESLPIEVMVDAVHKLKYENYTSSFFIRDIIKPDPPKNLQLKPLKNSRQVEVSWEYPDTW\nSTPHSYFSLTFCVQVQGKSKREKKDRVFTDKTSATVICRKNASISVRAQDRYYSSSWSEWASVPCS\n"
+ test/GBParserSpec.hs view
@@ -0,0 +1,153 @@+{-# LANGUAGE OverloadedStrings #-}++module GBParserSpec where++import           Bio.GB       (Feature (..), Form (..), GenBankSequence (..),+                               Locus (..), Meta (..), Reference (..),+                               Source (..), Version (..), fromFile)+import           Bio.Sequence (Range, unsafeMarkedSequence)+import           Test.Hspec++gbParserSpec :: Spec+gbParserSpec = describe "GenBank format parser." $ do+    pAAVGFPSpecP "test/GB/pAAV-GFP-CellBioLab.gb"+    pAAVCMVSpecP "test/GB/pAAV_CMV_RPE65_PolyA_linkers.gb"+    dottedMetaSpecP "test/GB/pAAV-GFP-CellBioLab-dots.gb"++pAAVGFPSpecP :: FilePath -> Spec+pAAVGFPSpecP path = describe "pAAVGFP" $ do+    it "correctly parses meta information" $ do+        mt <- meta <$> fromFile path+        mt `shouldBe` pAAVGFPMeta++    it "correctly parses structSeq" $ do+        gbS <- gbSeq <$> fromFile path+        gbS `shouldBe` unsafeMarkedSequence pAAVGFPOrigin pAAVGFPFeatures++pAAVCMVSpecP :: FilePath -> Spec+pAAVCMVSpecP path = describe "pAAVCMV" $ do+    it "parses meta information" $ do+        mt <- meta <$> fromFile path+        mt `shouldBe` pAAVCMVMeta++    it "correctly parses structSeq" $ do+        gbS <- gbSeq <$> fromFile path+        gbS `shouldBe` unsafeMarkedSequence pAAVCMVOrigin pAAVCMVFeatures++dottedMetaSpecP :: FilePath -> Spec+dottedMetaSpecP path = describe "Meta with dots." $ do+    it "correctly parses meta information with all info set to dots" $ do+        mt <- meta <$> fromFile path+        mt `shouldBe` dottedMeta+++pAAVGFPMeta :: Meta+pAAVGFPMeta = Meta { locus=Locus "pAAV-GFP-CellBio" 5374 "ds-DNA" (Just Circular) (Just "SYN") "15-AUG-2016"+                   , definition=Just $ "Saccharomyces cerevisiae TCP1-beta gene, partial cds, and Axl2p\n(AXL2) and Rev7p (REV7) genes, complete cds."+                   , accession=Just $ "U49845"+                   , version=Just $ Version "U49845.1" $ Just "1293613"+                   , keywords=Just "."+                   , source=Just $ Source "synthetic DNA construct" $ Just "synthetic DNA construct\nsynthetic DNA construct hmmm interesting"+                   , references=[ Reference "1  (bases 1 to 5374)" (Just "avprok") (Just "Direct Submission") (Just "Exported Monday, August 15, 2016 from SnapGene 3.1.4 to Vector \nNTI(R) format\nhttp://www.snapgene.com") Nothing+                                , Reference "2  (bases 1 to 5028)" (Just "Roemer,T., Madden,K., Chang,J. and Snyder,M.") (Just "Selection of axial growth sites in yeast requires Axl2p, a novel\nplasma membrane glycoprotein") (Just "Genes Dev. 10 (7), 777-793 (1996)") (Just "8846915")+                                , Reference "3  (bases 1 to 5028)" (Just "Roemer,T.") (Just "Direct Submission") (Just "Submitted (22-FEB-1996) Terry Roemer, Biology, Yale University, New\nHaven, CT, USA") Nothing+                                ]+                   , comments=["VNTDATE|745891200|", "VNTDBDATE|778204800|", "VNTNAME|pAAV-GFP-CellBioLab|", "VNTAUTHORNAME|avprok|"]+                   }++pAAVGFPFeatures :: [(Feature, Range)]+pAAVGFPFeatures = [ ( (Feature "misc_feature" True [ ("label", "Right ITR")+                                                                        ]+                                           ), (0, 130))+                                       , ( (Feature "enhancer" True [ ("label", "CMV enhancer")+                                                                    , ("note", "human cytomegalovirus immediate early enhancer")+                                                                    ]+                                           ), (205, 509))+                                       , ( (Feature "promoter" True [ ("label", "CMV promoter")+                                                                                                   , ("note", "human cytomegalovirus (CMV) immediate early \npromoter")+                                                                                                   ]+                                           ), (509, 712))+                                       , ( (Feature "misc_feature" True [ ("label", "Human beta-globin Intron")+                                                                                                            ]+                                           ), (804, 1297))+                                       , ( (Feature "CDS" True [ ("codon_start", "1")+                                                                                                , ("product", "enhanced GFP")+                                                                                                , ("label", "EGFP")+                                                                                                , ("note", "mammalian codon-optimized")+                                                                                                ]+                                           ), (1319, 2036))+                                       , ( (Feature "repeat_region" False [ ("label", "Left ITR")+                                                                                                         , ("note", "inverted terminal repeat of adeno-associated virus \nserotype 2\noooooo")+                                                                                                         , ("prop", "1")+                                                                                                         ]+                                           ), (2636, 2777))+                                       ]++pAAVGFPOrigin :: String+pAAVGFPOrigin =+  "cctgcaggcagctgcgcgctcgctcgctcactgaggccgcccgggcgtcgggcgacctttggtcgcccggcctcagtgagcgagcgagcgcgcagagagggagtggccaactccatcactaggggttcctgcggccgcacgcgtctagttattaatagtaatcaattacggggtcattagttcatagcccatatatggagttccgcgttacataacttacggtaaatggcccgcctggctgaccgcccaacgacccccgcccattgacgtcaataatgacgtatgttcccatagtaacgtcaatagggactttccattgacgtcaatgggtggagtatttacggtaaactgcccacttggcagtacatcaagtgtatcatatgccaagtacgccccctattgacgtcaatgacggtaaatggcccgcctggcattatgcccagtacatgaccttatgggactttcctacttggcagtacatctacgtattagtcatcgctattaccatggtgatgcggttttggcagtacatcaatgggcgtggatagcggtttgactcacggggatttccaagtctccaccccattgacgtcaatgggagtttgttttgcaccaaaatcaacgggactttccaaaatgtcgtaacaactccgccccattgacgcaaatgggcggtaggcgtgtacggtgggaggtctatataagcagagctcgtttagtgaaccgtcagatcgcctggagacgccatccacgctgttttgacctccatagaagacaccgggaccgatccagcctccgcggattcgaatcccggccgggaacggtgcattggaacgcggattccccgtgccaagagtgacgtaagtaccgcctatagagtctataggcccacaaaaaatgctttcttcttttaatatacttttttgtttatcttatttctaatactttccctaatctctttctttcagggcaataatgatacaatgtatcatgcctctttgcaccattctaaagaataacagtgataatttctgggttaaggcaatagcaatatttctgcatataaatatttctgcatataaattgtaactgatgtaagaggtttcatattgctaatagcagctacaatccagctaccattctgcttttattttatggttgggataaggctggattattctgagtccaagctaggcccttttgctaatcatgttcatacctcttatcttcctcccacagctcctgggcaacgtgctggtctgtgtgctggcccatcactttggcaaagaattgggattcgaacatcgattgaattctgaatggtgagcaagggcgaggagctgttcaccggggtggtgcccatcctggtcgagctggacggcgacgtaaacggccacaagttcagcgtgtccggcgagggcgagggcgatgccacctacggcaagctgaccctgaagttcatctgcaccaccggcaagctgcccgtgccctggcccaccctcgtgaccaccctgacctacggcgtgcagtgcttcagccgctaccccgaccacatgaagcagcacgacttcttcaagtccgccatgcccgaaggctacgtccaggagcgcaccatcttcttcaaggacgacggcaactacaagacccgcgccgaggtgaagttcgagggcgacaccctggtgaaccgcatcgagctgaagggcatcgacttcaaggaggacggcaacatcctggggcacaagctggagtacaactacaacagccacaacgtctatatcatggccgacaagcagaagaacggcatcaaggtgaacttcaagatccgccacaacatcgaggacggcagcgtgcagctcgccgaccactaccagcagaacacccccatcggcgacggccccgtgctgctgcccgacaaccactacctgagcacccagtccgccctgagcaaagaccccaacgagaagcgcgatcacatggtcctgctggagttcgtgaccgccgccgggatcactctcggcatggacgagctgtacaagtactcagatctcgagctcaagtagggatcctctagagtcgacctgcagaagcttgcctcgagcagcgctgctcgagagatctacgggtggcatccctgtgacccctccccagtgcctctcctggccctggaagttgccactccagtgcccaccagccttgtcctaataaaattaagttgcatcattttgtctgactaggtgtccttctataatattatggggtggaggggggtggtatggagcaaggggcaagttgggaagacaacctgtagggcctgcggggtctattgggaaccaagctggagtgcagtggcacaatcttggctcactgcaatctccgcctcctgggttcaagcgattctcctgcctcagcctcccgagttgttgggattccaggcatgcatgaccaggctcagctaatttttgtttttttggtagagacggggtttcaccatattggccaggctggtctccaactcctaatctcaggtgatctacccaccttggcctcccaaattgctgggattacaggcgtgaaccactgctcccttccctgtccttctgattttgtaggtaaccacgtgcggaccgagcggccgcaggaacccctagtgatggagttggccactccctctctgcgcgctcgctcgctcactgaggccgggcgaccaaaggtcgcccgacgcccgggctttgcccgggcggcctcagtgagcgagcgagcgcgcagctgcctgcaggggcgcctgatgcggtattttctccttacgcatctgtgcggtatttcacaccgcatacgtcaaagcaaccatagtacgcgccctgtagcggcgcattaagcgcggcgggtgtggtggttacgcgcagcgtgaccgctacacttgccagcgccctagcgcccgctcctttcgctttcttcccttcctttctcgccacgttcgccggctttccccgtcaagctctaaatcgggggctccctttagggttccgatttagtgctttacggcacctcgaccccaaaaaacttgatttgggtgatggttcacgtagtgggccatcgccctgatagacggtttttcgccctttgacgttggagtccacgttctttaatagtggactcttgttccaaactggaacaacactcaaccctatctcgggctattcttttgatttataagggattttgccgatttcggcctattggttaaaaaatgagctgatttaacaaaaatttaacgcgaattttaacaaaatattaacgtttacaattttatggtgcactctcagtacaatctgctctgatgccgcatagttaagccagccccgacacccgccaacacccgctgacgcgccctgacgggcttgtctgctcccggcatccgcttacagacaagctgtgaccgtctccgggagctgcatgtgtcagaggttttcaccgtcatcaccgaaacgcgcgagacgaaagggcctcgtgatacgcctatttttataggttaatgtcatgataataatggtttcttagacgtcaggtggcacttttcggggaaatgtgcgcggaacccctatttgtttatttttctaaatacattcaaatatgtatccgctcatgagacaataaccctgataaatgcttcaataatattgaaaaaggaagagtatgagtattcaacatttccgtgtcgcccttattcccttttttgcggcattttgccttcctgtttttgctcacccagaaacgctggtgaaagtaaaagatgctgaagatcagttgggtgcacgagtgggttacatcgaactggatctcaacagcggtaagatccttgagagttttcgccccgaagaacgttttccaatgatgagcacttttaaagttctgctatgtggcgcggtattatcccgtattgacgccgggcaagagcaactcggtcgccgcatacactattctcagaatgacttggttgagtactcaccagtcacagaaaagcatcttacggatggcatgacagtaagagaattatgcagtgctgccataaccatgagtgataacactgcggccaacttacttctgacaacgatcggaggaccgaaggagctaaccgcttttttgcacaacatgggggatcatgtaactcgccttgatcgttgggaaccggagctgaatgaagccataccaaacgacgagcgtgacaccacgatgcctgtagcaatggcaacaacgttgcgcaaactattaactggcgaactacttactctagcttcccggcaacaattaatagactggatggaggcggataaagttgcaggaccacttctgcgctcggcccttccggctggctggtttattgctgataaatctggagccggtgagcgtgggtctcgcggtatcattgcagcactggggccagatggtaagccctcccgtatcgtagttatctacacgacggggagtcaggcaactatggatgaacgaaatagacagatcgctgagataggtgcctcactgattaagcattggtaactgtcagaccaagtttactcatatatactttagattgatttaaaacttcatttttaatttaaaaggatctaggtgaagatcctttttgataatctcatgaccaaaatcccttaacgtgagttttcgttccactgagcgtcagaccccgtagaaaagatcaaaggatcttcttgagatcctttttttctgcgcgtaatctgctgcttgcaaacaaaaaaaccaccgctaccagcggtggtttgtttgccggatcaagagctaccaactctttttccgaaggtaactggcttcagcagagcgcagataccaaatactgtccttctagtgtagccgtagttaggccaccacttcaagaactctgtagcaccgcctacatacctcgctctgctaatcctgttaccagtggctgctgccagtggcgataagtcgtgtcttaccgggttggactcaagacgatagttaccggataaggcgcagcggtcgggctgaacggggggttcgtgcacacagcccagcttggagcgaacgacctacaccgaactgagatacctacagcgtgagctatgagaaagcgccacgcttcccgaagggagaaaggcggacaggtatccggtaagcggcagggtcggaacaggagagcgcacgagggagcttccagggggaaacgcctggtatctttatagtcctgtcgggtttcgccacctctgacttgagcgtcgatttttgtgatgctcgtcaggggggcggagcctatggaaaaacgccagcaacgcggcctttttacggttcctggccttttgctggccttttgctcacatgt"++pAAVCMVMeta :: Meta+pAAVCMVMeta = Meta { locus=Locus "pAAV_CMV_RPE65_P" 6265 "ds-DNA" (Just Linear) Nothing "23-JAN-2019"+                   , definition=Nothing+                   , accession=Nothing+                   , version=Nothing+                   , keywords=Nothing+                   , source=Nothing+                   , references=[]+                   , comments=["Created by vasilyevaas@biocad.ru", "Core from file: pAAV_core_ITR2", "", "ApEinfo:methylated:1"]+                   }++pAAVCMVFeatures :: [(Feature, Range)]+pAAVCMVFeatures = [ ( (Feature "rep_origin" True [ ("direction", "RIGHT")+                                                                                                       , ("note", "f1 bacteriophage origin of replication; arrow\r\nindicates direction of (+) strand synthesis")+                                                                                                       , ("label", "f1 ori")+                                                                                                       , ("ApEinfo_fwdcolor", "#999999")+                                                                                                       , ("ApEinfo_revcolor", "#999999")+                                                                                                       , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")+                                                                                                       ]+                      ), (3742, 4198))+                    , ( (Feature "promoter" True [ ("gene", "bla")+                                                                                                     , ("label", "AmpR promoter")+                                                                                                     , ("ApEinfo_fwdcolor", "#346ee0")+                                                                                                     , ("ApEinfo_revcolor", "#346ee0")+                                                                                                     , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")+                                                                                                     ]+                        ), (4479, 4584))+                    , ( (Feature "CDS" True [ ("codon_start", "1")+                                                                                                , ("gene", "bla")+                                                                                                , ("product", "beta-lactamase")+                                                                                                , ("note", "confers resistance to ampicillin, carbenicillin,\r\nand related antibiotics")+                                                                                                , ("label", "AmpR")+                                                                                                , ("ApEinfo_fwdcolor", "#e9d024")+                                                                                                , ("ApEinfo_revcolor", "#e9d024")+                                                                                                , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")+                                                                                                ]+                        ), (4584, 5445))+                     , ( (Feature "misc_feature" True [ ("label", "RightITR2")+                                                                                                         , ("ApEinfo_fwdcolor", "#7eff74")+                                                                                                         , ("ApEinfo_revcolor", "#7eff74")+                                                                                                         , ("ApEinfo_graphicformat", "arrow_data {{0 1 2 0 0 -1} {} 0}\r\nwidth 5 offset 0")+                                                                                                         ]+                         ), (3527, 3668))+                      , ( (Feature "misc_feature" False [ ("label", "A->T")+                                                                                                ]+                          ), (199, 200))+                                       ]++pAAVCMVOrigin :: String+pAAVCMVOrigin =+  "CCTGCAGGCAGCTGCGCGCTCGCTCGCTCACTGAGGCCGCCCGGGCGTCGGGCGACCTTTGGTCGCCCGGCCTCAGTGAGCGAGCGAGCGCGCAGAGAGGGAGTGGCCAACTCCATCACTAGGGGTTCCTGCGGCCCGACATTCCGGAGGTACCTCTAGATTGGCAAACAGCTATTATGGGTATTATGGGTctagttattaatagtaatcaattacggggtcattagttcatagcccatatatggagttccgcgttacataacttacggtaaatggcccgcctggctgaccgcccaacgacccccgcccattgacgtcaataatgacgtatgttcccatagtaacgccaatagggactttccattgacgtcaatgggtggagtatttacggtaaactgcccacttggcagtacatcaagtgtatcatatgccaagtacgccccctattgacgtcaatgacggtaaatggcccgcctggcattatgcccagtacatgaccttatgggactttcctacttggcagtacatctacgtattagtcatcgctattaccatggtgatgcggttttggcagtacatcaatgggcgtggatagcggtttgactcacggggatttccaagtctccaccccattgacgtcaatgggagtttgttttgGcaccaaaatcaacgggactttccaaaatgtcgtaacaactccgccccattgacgcaaatgggcggtaggcgtgtacggtgggaggtctatataagcagagctcgtttagtgaaccgtcagatcgcctggagacgccatccacgctgttttgacctccatagaagacaccgggaccgatccagcctccgcggattcgaatcccggccgggaacggtgcattggaacgcggattccccgtgccaagagtgacgtaagtaccgcctatagagtctataggcccacaaaaaatgctttcttcttttaatatacttttttgtttatcttatttctaatactttccctaatctctttctttcagggcaataatgatacaatgtatcatgcctctttgcaccattctaaagaataacagtgataatttctgggttaaggcaatagcaatatttctgcatataaatatttctgcatataaattgtaactgatgtaagaggtttcatattgctaatagcagctacaatccagctaccattctgcttttattttatggttgggataaggctggattattctgagtccaagctaggcccttttgctaatcatgttcatacctcttatcttcctcccacagctcctgggcaacgtgctggtctgtgtgctggcccatcactttggcaaagaattgggatCGTAACTATAACGGTCCTAAGGTAGCGAAATGAGCATCCAAGTCGAGCACCCCGCAGGCGGGTACAAGAAGTTATTTGAAACGGTAGAAGAGCTGTCGTCGCCTCTGACCGCTCATGTAACAGGACGGATACCTCTGTGGTTGACAGGTTCTTTATTACGCTGCGGACCCGGCCTGTTCGAAGTTGGCTCCGAGCCCTTTTACCACCTGTTCGACGGCCAAGCACTGCTCCACAAGTTCGACTTTAAAGAGGGCCACGTGACGTACCATAGAAGGTTCATCAGGACGGATGCTTACGTCCGCGCAATGACGGAAAAGCGGATCGTAATCACGGAGTTCGGGACATGTGCCTTCCCCGACCCCTGTAAGAACATCTTCTCCCGCTTCTTTAGTTACTTTCGGGGCGTGGAGGTTACTGACAATGCCCTGGTTAACGTATACCCTGTCGGGGAAGACTATTACGCCTGCACAGAGACCAACTTCATTACGAAGATCAATCCTGAGACGCTGGAGACCATCAAGCAAGTCGATCTGTGCAATTACGTCTCGGTGAATGGCGCCACCGCGCATCCACACATTGAAAACGACGGCACTGTGTATAATATCGGCAACTGCTTCGGCAAGAACTTCTCGATAGCATACAACATTGTGAAGATCCCACCGCTTCAGGCTGACAAGGAGGACCCCATCTCAAAGTCGGAAATAGTGGTCCAGTTCCCCTGCTCAGACAGGTTCAAACCTAGCTATGTCCACTCGTTTGGTCTGACCCCGAATTATATCGTTTTCGTGGAGACCCCGGTCAAGATTAACCTGTTCAAATTCCTCAGCTCATGGTCCCTCTGGGGCGCAAACTACATGGACTGCTTCGAGTCCAACGAAACAATGGGCGTATGGCTCCATATCGCCGACAAGAAGCGGAAAAAGTACCTGAACAACAAGTACCGCACCTCGCCCTTCAACCTCTTTCATCACATCAACACCTACGAGGACAACGGCTTCCTCATCGTAGACCTCTGCTGCTGGAAGGGCTTCGAGTTTGTCTACAACTACCTGTACCTGGCAAACCTGAGGGAAAACTGGGAAGAGGTCAAAAAGAACGCCCGTAAGGCACCACAACCCGAGGTGCGCCGGTACGTCCTGCCCCTTAACATAGACAAAGCAGACACAGGGAAGAACTTAGTGACTTTGCCTAACACAACCGCGACTGCGATCCTATGTTCCGACGAGACTATCTGGCTGGAGCCTGAGGTGTTATTTTCTGGCCCCAGACAGGCATTCGAGTTTCCCCAGATTAACTATCAGAAGTACTGCGGAAAGCCATACACGTATGCCTACGGTCTCGGCCTGAATCATTTCGTGCCTGACCGCCTGTGTAAGTTGAACGTAAAAACTAAAGAAACCTGGGTGTGGCAGGAGCCCGACTCATACCCTTCCGAGCCCATATTTGTCAGTCACCCTGATGCACTGGAAGAGGACGATGGAGTGGTGTTGTCTGTCGTCGTGAGCCCAGGGGCCGGTCAGAAGCCAGCCTACCTATTGATTCTCAACGCGAAGGACCTGTCTGAGGTCGCGCGGGCGGAGGTCGAAATCAATATCCCCGTTACGTTCCACGGCCTCTTTAAGAAGTCGTAGGGATAACAGGGTAATGTCGACAAGCTTGCTAGCACGGGTGGCATCCCTGTGACCCCTCCCCAGTGCCTCTCCTGGCCCTGGAAGTTGCCACTCCAGTGCCCACCAGCCTTGTCCTAATAAAATTAAGTTGCATCATTTTGTCTGACTAGGTGTCCTTCTATAATATTATGGGGTGGAGGGGGGTGGTATGGAGCAAGGGGCAAGTTGGGAAGACAACCTGTAGGGCCTGCGGGGTCTATTGGGAACCAAGCTGGAGTGCAGTGGCACAATCTTGGCTCACTGCAATCTCCGCCTCCTGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCCGAGTTGTTGGGATTCCAGGCATGCATGACCAGGCTCAGCTAATTTTTGTTTTTTTGGTAGAGACGGGGTTTCACCATATTGGCCAGGCTGGTCTCCAACTCCTAATCTCAGGTGATCTACCCACCTTGGCCTCCCAAATTGCTGGGATTACAGGCGTGAACCACTGCTCCCTTCCCTGTCCTTATGCATGGGCCCGTACGATCACTAGTGTACAGCGGCCGCAGGAACCCCTAGTGATGGAGTTGGCCACTCCCTCTCTGCGCGCTCGCTCGCTCACTGAGGCCGGGCGACCAAAGGTCGCCCGACGCCCGGGCTTTGCCCGGGCGGCCTCAGTGAGCGAGCGAGCGCGCAGCTGCCTGCAGGggcgcctgatgcggtattttctccttacgcatctgtgcggtatttcacaccgcatacgtcaaagcaaccatagtacgcgccctgtagcggcgcattaagcgcggcgggtgtggtggttacgcgcagcgtgaccgctacacttgccagcgccttagcgcccgctcctttcgctttcttcccttcctttctcgccacgttcgccggctttccccgtcaagctctaaatcgggggctccctttagggttccgatttagtgctttacggcacctcgaccccaaaaaacttgatttgggtgatggttcacgtagtgggccatcgccctgatagacggtttttcgccctttgacgttggagtccacgttctttaatagtggactcttgttccaaactggaacaacactcaactctatctcgggctattcttttgatttataagggattttgccgatttcggtctattggttaaaaaatgagctgatttaacaaaaatttaacgcgaattttaacaaaatattaacgtttacaattttatggtgcactctcagtacaatctgctctgatgccgcatagttaagccagccccgacacccgccaacacccgctgacgcgccctgacgggcttgtctgctcccggcatccgcttacagacaagctgtgaccgtctccgggagctgcatgtgtcagaggttttcaccgtcatcaccgaaacgcgcgagacgaaagggcctcgtgatacgcctatttttataggttaatgtcatgataataatggtttcttagacgtcaggtggcacttttcggggaaatgtgcgcggaacccctatttgtttatttttctaaatacattcaaatatgtatccgctcatgagacaataaccctgataaatgcttcaataatattgaaaaaggaagagtatgagtattcaacatttccgtgtcgcccttattcccttttttgcggcattttgccttcctgtttttgctcacccagaaacgctggtgaaagtaaaagatgctgaagatcagttgggtgcacgagtgggttacatcgaactggatctcaacagcggtaagatccttgagagttttcgccccgaagaacgttttccaatgatgagcacttttaaagttctgctatgtggcgcggtattatcccgtattgacgccgggcaagagcaactcggtcgccgcatacactattctcagaatgacttggttgagtactcaccagtcacagaaaagcatcttacggatggcatgacagtaagagaattatgcagtgctgccataaccatgagtgataacactgcggccaacttacttctgacaacgatcggaggaccgaaggagctaaccgcttttttgcacaacatgggggatcatgtaactcgccttgatcgttgggaaccggagctgaatgaagccataccaaacgacgagcgtgacaccacgatgcctgtagcaatggcaacaacgttgcgcaaactattaactggcgaactacttactctagcttcccggcaacaattaatagactggatggaggcggataaagttgcaggaccacttctgcgctcggcccttccggctggctggtttattgctgataaatctggagccggtgagcgtgggtctcgcggtatcattgcagcactggggccagatggtaagccctcccgtatcgtagttatctacacgacggggagtcaggcaactatggatgaacgaaatagacagatcgctgagataggtgcctcactgattaagcattggtaactgtcagaccaagtttactcatatatactttagattgatttaaaacttcatttttaatttaaaaggatctaggtgaagatcctttttgataatctcatgaccaaaatcccttaacgtgagttttcgttccactgagcgtcagaccccgtagaaaagatcaaaggatcttcttgagatcctttttttctgcgcgtaatctgctgcttgcaaacaaaaaaaccaccgctaccagcggtggtttgtttgccggatcaagagctaccaactctttttccgaaggtaactggcttcagcagagcgcagataccaaatactgttcttctagtgtagccgtagttaggccaccacttcaagaactctgtagcaccgcctacatacctcgctctgctaatcctgttaccagtggctgctgccagtggcgataagtcgtgtcttaccgggttggactcaagacgatagttaccggataaggcgcagcggtcgggctgaacggggggttcgtgcacacagcccagcttggagcgaacgacctacaccgaactgagatacctacagcgtgagctatgagaaagcgccacgcttcccgaagggagaaaggcggacaggtatccggtaagcggcagggtcggaacaggagagcgcacgagggagcttccagggggaaacgcctggtatctttatagtcctgtcgggtttcgccacctctgacttgagcgtcgatttttgtgatgctcgtcaggggggcggagcctatggaaaaacgccagcaacgcggcctttttacggttcctggccttttgctggccttttgctcacatgt"++dottedMeta :: Meta+dottedMeta = Meta { locus=Locus "pAAV-GFP-CellBio" 5374 "ds-DNA" (Just Circular) (Just "SYN") "15-AUG-2016"+                  , definition=Just $ "."+                  , accession=Just $ "."+                  , version=Just $ Version "." Nothing+                  , keywords=Just "."+                  , source=Just $ Source "." Nothing+                  , references=[ Reference "." Nothing Nothing Nothing Nothing+                               , Reference "." Nothing Nothing Nothing Nothing+                               ]+                  , comments=["."]+                  }
+ test/GBWriterSpec.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE OverloadedStrings #-}++module GBWriterSpec where++import           Bio.GB     (GenBankSequence (..), fromFile, fromText, toText)+import           Test.Hspec++gbWriterSpec :: Spec+gbWriterSpec = describe "GenBank format writer." $ do+      pAAVGFPSpecW "test/GB/pAAV-GFP-CellBioLab.gb"+      pAAVCMVSpecW "test/GB/pAAV_CMV_RPE65_PolyA_linkers.gb"+      dottedMetaSpecW "test/GB/pAAV-GFP-CellBioLab-dots.gb"++pAAVGFPSpecW :: FilePath -> Spec+pAAVGFPSpecW path = describe "pAAVGFP" $ do+    it "compares parsed structure with structure that is parsed from result of writing parsed structure" $ do+        st       <- fromFile path+        let text = toText st++        fromText text `shouldBe` Right st++pAAVCMVSpecW :: FilePath -> Spec+pAAVCMVSpecW path = describe "pAAVCMV" $ do+  it "compares parsed structure with structure that is parsed from result of writing parsed structure" $ do+      st       <- fromFile path+      let text = toText st++      fromText text `shouldBe` Right st++dottedMetaSpecW :: FilePath -> Spec+dottedMetaSpecW path = describe "Meta with dots." $ do+  it "compares parsed structure with structure that is parsed from result of writing parsed structure" $ do+      st       <- fromFile path+      let text = toText st++      meta <$> fromText text `shouldBe` Right (meta st)
+ test/MMTFSpec.hs view
@@ -0,0 +1,36 @@+module MMTFSpec where++import           Bio.MMTF+import           Bio.MMTF.Decode.Codec+import           Data.Array            ((!))+import           Data.Int              (Int8)+import           Test.Hspec++mmtfCodecSpec :: Spec+mmtfCodecSpec =+  describe "MMTF decoding" $ do+    it "unpacks by Run-length encoding" $ do+      let sample = [ 1, 10, 2, 1, 1, 4 ] :: [Int8]+      runLengthDec sample `shouldBe` ([ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1 ] :: [Int8])+    it "unpacks by Delta encoding" $ do+      let sample = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1 ] :: [Int8]+      deltaDec sample `shouldBe` ([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16 ] :: [Int8])+    it "unpacks by Recursive indexing encoding" $ do+      let sample = [ 127, 41, 34, 1, 0, -50, -128, 0, 7, 127, 0, 127, 127, 14 ] :: [Int8]+      recIndexDec sample `shouldBe` [ 168, 34, 1, 0, -50, -128, 7, 127, 268 ]+    it "unpacks by Integer encoding" $ do+      let sample = [ 100, 100, 100, 100, 50, 50 ] :: [Int8]+      integerDec 100 sample `shouldBe` [ 1.00, 1.00, 1.00, 1.00, 0.50, 0.50 ]++mmtfParserSpec :: Spec+mmtfParserSpec =+  describe "MMTF parser" $+  it "should parse 1FSD" $ do+    m <- fetch "1FSD"+    (structureId . structure) m `shouldBe` "1FSD"+    (numModels . structure) m `shouldBe` 41+    (length . bFactorList . atom) m `shouldBe` 20664+    ((! 0) . experimentalMethods . structure) m `shouldBe` "SOLUTION NMR"+    ((! 0) . xCoordList . atom) m `shouldBe` (-12.847)+    ((! 20663) . xCoordList . atom) m `shouldBe` 5.672+
+ test/SequenceSpec.hs view
@@ -0,0 +1,287 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++module SequenceSpec where++import           Bio.Sequence       (BareSequence, IsMarking, IsWeight (..),+                                     MarkedSequence, Sequence, WeightedSequence,+                                     addMarkings, bareSequence, createSequence,+                                     drop, getMarking, getRange, getWeight,+                                     markedSequence, mean, meanInRange, reverse,+                                     tail, take, toMarked, toWeighted,+                                     unsafeCreateSequence, unsafeMarkedSequence,+                                     unsafeWeightedSequence, weightedSequence)+import qualified Data.List.NonEmpty as NE (fromList)+import           Data.Text          (Text)+import           Prelude            hiding (drop, reverse, tail, take)+import           Test.Hspec++instance IsWeight Int where+  toDouble = fromIntegral++type TestWeightedSequence = WeightedSequence Int Char++weightedSequenceSpec :: Spec+weightedSequenceSpec =+  describe "Weighted sequence" $ do+    it "successful creation of weighted sequence" $ do+      let seqE = weightedSequence ['a', 'b', 'c', 'd'] [1, 2, 3, 4] :: Either Text TestWeightedSequence+      seqE `shouldBe` Right (unsafeWeightedSequence ['a', 'b', 'c', 'd'] [1, 2, 3, 4])++    it "unsuccessful creation of weighted sequence" $ do+      let seqErr  = Left "Bio.Sequence.Class: sequence and weights have different lengths."+      let seqErr1 = Left "Bio.Sequence.Class: weights are null for sequence."++      let seqE = weightedSequence ['a', 'b', 'c', 'd'] [1, 2, 4] :: Either Text TestWeightedSequence+      seqE `shouldBe` seqErr++      let seqE = weightedSequence ['a', 'b', 'c', 'd'] [] :: Either Text TestWeightedSequence+      seqE `shouldBe` seqErr1++      let seqE = weightedSequence [] [1] :: Either Text TestWeightedSequence+      seqE `shouldBe` seqErr++      let seqE = weightedSequence [] [] :: Either Text TestWeightedSequence+      seqE `shouldBe` seqErr1++newtype TestMarking = TestMarking Text+  deriving (Eq, Show, Ord)++instance IsMarking TestMarking++type TestMarkedSequence = MarkedSequence TestMarking Char++markedSequenceSpec :: Spec+markedSequenceSpec =+  describe "Marked sequence" $ do+    it "successful creation of marked sequence" $ do+      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence+      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))])++      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", (1, 5)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence+      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", (1, 5)), (TestMarking "a", (3, 5))])++      let seqE = markedSequence [] [] :: Either Text TestMarkedSequence+      seqE `shouldBe` Right (unsafeMarkedSequence [] [])++      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [] :: Either Text TestMarkedSequence+      seqE `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [])+    it "unsuccessful creation of marked sequence" $ do+      let seqErr = Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking."++      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (-1, 1))] :: Either Text TestMarkedSequence+      seqE `shouldBe` seqErr++      let seqE = markedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", (0, 6)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence+      seqE `shouldBe` seqErr++      let seqE = markedSequence ['a'] [(TestMarking "a", (0, 0))] :: Either Text TestMarkedSequence+      seqE `shouldBe` seqErr++      let seqE = markedSequence [] [(TestMarking "k", (0, 1))] :: Either Text TestMarkedSequence+      seqE `shouldBe` seqErr++type TestMarkedAndWeightedSequence = Sequence TestMarking Int Char++markedAndWeightedSequenceSpec :: Spec+markedAndWeightedSequenceSpec =+  describe "Marked and weighted sequence" $ do+    it "successful creation of marked and weighted sequence" $ do+      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` Right (unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5])++    it "unsuccessful creation of marked and weighted sequence" $ do+      let seqErr = Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking."++      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (-1, 1))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` seqErr++      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "bca", (0, 6)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` seqErr++      let seqE = createSequence ['a'] [(TestMarking "a", (0, 0))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` seqErr++      let seqE = createSequence [] [(TestMarking "k", (0, 1))] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` seqErr++      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2, 4] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` seqErr++      let seqE = createSequence ['a', 'b', 'c', 'a', 'a'] [] [1, 2.. 5] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` Right (unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [] [1, 2.. 5])++      let seqErr1 = Left "Bio.Sequence.Class: sequence and weights have different lengths."++      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 4))] [1, 2] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` seqErr1++      let seqErr2 = Left "Bio.Sequence.Class: weights are null for sequence."++      let seqE = createSequence ['a', 'b', 'c', 'd'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 4))] [] :: Either Text TestMarkedAndWeightedSequence+      seqE `shouldBe` seqErr2++functionsSpec :: Spec+functionsSpec =+  describe "Sequence functions" $ do+    -- common 'IsSequence' functions+    getRangeSpec+    reverseSpec+    dropSpec+    takeSpec+    tailSpec++    -- 'Marking functions+    getMarkingSpec+    toMarkedSpec+    addMarkingsSpec++    -- 'Weight' functions+    meanAndMeanInRangeSpec+    getWeightSpec+    toWeightedSpec++getRangeSpec :: Spec+getRangeSpec =+  describe "getRange" $ do+    let getRangeError = Left "Bio.Sequence.Functions.Sequence: invalid range in getRange."+    let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: TestMarkedAndWeightedSequence++    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (0, 1)" $ do+      getRange s (0, 1) `shouldBe` Right ['a']+    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (2, 5)" $ do+      getRange s (2, 5) `shouldBe` Right ['c', 'a', 'a']+    it "sequence: ['a', 'b', 'c', 'a', 'a', 'd', 'e']; range: (5, 7)" $ do+      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a', 'd', 'e'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 7] :: TestMarkedAndWeightedSequence+      getRange s (5, 7) `shouldBe` Right ['d', 'e']+    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (0, 0)" $ do+      getRange s (0, 0) `shouldBe` getRangeError+    it "sequence: ['a', 'b', 'c', 'a', 'a']; range: (3, 8)" $ do+      getRange s (3, 8) `shouldBe` getRangeError++reverseSpec :: Spec+reverseSpec =+  describe "reverse" $ do+    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; weights: [1, 2.. 5]" $ do+      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: TestMarkedAndWeightedSequence+      reverse s `shouldBe` unsafeCreateSequence ['a', 'a', 'c', 'b', 'a'] [(TestMarking "a", (4, 5)), (TestMarking "a", (0, 2))] [5, 4.. 1]+    it "sequence: ['a', 'b']; markings: []; weights: [1, 2]" $ do+      let s = unsafeWeightedSequence ['a', 'b'] [1, 2] :: TestWeightedSequence+      reverse s `shouldBe` unsafeWeightedSequence ['b', 'a'] [2, 1]+    it "sequence: ['a', 'b', 'c', 'd', 'e']; markings: [(abc, (0, 3)), (abcd, (0, 4)), (de, (3, 5)), (abcde, (0, 5))]; weights: []" $ do+      let s = unsafeMarkedSequence ['a', 'b', 'c', 'd', 'e'] [(TestMarking "abc", (0, 3)), (TestMarking "abcd", (0, 4)), (TestMarking "de", (3, 5)), (TestMarking "abcde", (0, 5))] :: TestMarkedSequence+      reverse s `shouldBe` unsafeMarkedSequence ['e', 'd', 'c', 'b', 'a'] [(TestMarking "abc", (2, 5)), (TestMarking "abcd", (1, 5)), (TestMarking "de", (0, 2)), (TestMarking "abcde", (0, 5))]++dropSpec :: Spec+dropSpec =+  describe "drop" $ do+    let s  = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence+    let sB = bareSequence ['a', 'b', 'c', 'a', 'a'] :: TestBareSequence++    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; drop: 2" $ do+      drop 2 s `shouldBe` unsafeWeightedSequence ['c', 'a', 'a'] [3.. 5]+    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; drop: 4" $ do+      drop 4 s `shouldBe` unsafeWeightedSequence ['a'] [5]+    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; drop: 4" $ do+      drop 0 s `shouldBe` s+    it "sequence: ['a', 'b', 'c', 'a', 'a']; drop: 2" $ do+      drop 2 sB `shouldBe` bareSequence ['c', 'a', 'a']++takeSpec :: Spec+takeSpec =+  describe "take" $ do+    let s = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence++    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; take: 2" $ do+      take 2 s `shouldBe` unsafeWeightedSequence ['a', 'b'] [1.. 2]+    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; take: 8" $ do+      take 8 s `shouldBe` s++tailSpec :: Spec+tailSpec =+  describe "tail" $ do+    let s = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence++    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]" $ do+      tail s `shouldBe` unsafeWeightedSequence ['b', 'c', 'a', 'a'] [2.. 5]+    it "sequence: ['b', 'c', 'a', 'a']; weights: [2.. 5]" $ do+      tail (tail s) `shouldBe` unsafeWeightedSequence ['c', 'a', 'a'] [3.. 5]+    it "sequence: [c', 'a', 'a']; weights: [3.. 5]" $ do+      tail (tail (tail s)) `shouldBe` unsafeWeightedSequence ['a', 'a'] [4.. 5]+    it "sequence: [a', 'a']; weights: [4.. 5]" $ do+      tail (tail (tail (tail s))) `shouldBe` unsafeWeightedSequence ['a'] [5]++getMarkingSpec :: Spec+getMarkingSpec =+  describe "getMarking" $ do+    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; get: a" $ do+      let s = unsafeCreateSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] [1, 2.. 5] :: TestMarkedAndWeightedSequence+      getMarking s (TestMarking "a") `shouldBe` Right (NE.fromList [['a'], ['a', 'a']])+    it "sequence: ['a', 'b', 'c', 'd', 'e']; markings: [(abc, (0, 3)), (abcd, (0, 4)), (de, (3, 5)), (abcde, (0, 5))]; get: abcde" $ do+      let s = unsafeMarkedSequence ['a', 'b', 'c', 'd', 'e'] [(TestMarking "abc", (0, 3)), (TestMarking "abcd", (0, 4)), (TestMarking "de", (3, 5)), (TestMarking "abcde", (0, 5))] :: TestMarkedSequence+      getMarking s (TestMarking "abcde") `shouldBe` Right (NE.fromList [['a', 'b', 'c', 'd', 'e']])++type TestBareSequence = BareSequence Char++toMarkedSpec :: Spec+toMarkedSpec =+  describe "toMarked" $ do+    let s = bareSequence ['a', 'b', 'c', 'a', 'a'] :: TestBareSequence++    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]" $ do+      (toMarked s [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence) `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))])+    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 6)), (a, (3, 5))]" $ do+      let rangesError = Left "Bio.Sequence.Class: invalid 'Range' found in sequence's marking."+      (toMarked s [(TestMarking "a", (0, 6)), (TestMarking "a", (3, 5))] :: Either Text TestMarkedSequence) `shouldBe` rangesError++addMarkingsSpec :: Spec+addMarkingsSpec =+  describe "addMarkings" $ do+    let s = unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5))] :: TestMarkedSequence+    let rangesError = Left "Bio.Sequence.Functions.Marking: can't add markings to Sequence, because some of them are out of range."++    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: [(b, (1, 2))]" $ do+      addMarkings s [(TestMarking "b", (1, 2))] `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5)), (TestMarking "b", (1, 2))])+    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: []" $ do+      addMarkings s [] `shouldBe` Right s+    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: [(b, (1, 2)), (c, (2, 3)), (abcaa, (0, 5))]" $ do+      addMarkings s [(TestMarking "b", (1, 2)), (TestMarking "c", (2, 3)), (TestMarking "abcaa", (0, 5))] `shouldBe` Right (unsafeMarkedSequence ['a', 'b', 'c', 'a', 'a'] [(TestMarking "a", (0, 1)), (TestMarking "a", (3, 5)), (TestMarking "b", (1, 2)), (TestMarking "c", (2, 3)), (TestMarking "abcaa", (0, 5))])+    it "sequence: ['a', 'b', 'c', 'a', 'a']; markings: [(a, (0, 1)), (a, (3, 5))]; add: [(b, (1, 2)), (c, (2, 3)), (abcaa, (0, 6))]" $ do+      addMarkings s [(TestMarking "b", (1, 2)), (TestMarking "c", (2, 3)), (TestMarking "abcaa", (0, 6))] `shouldBe` rangesError++meanAndMeanInRangeSpec :: Spec+meanAndMeanInRangeSpec =+  describe "mean and meanInRange" $ do+    let s = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence++    it "mean for sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]" $ do+      mean s `shouldBe` 3+    it "meanInRange for sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; range: (2, 4)" $ do+      meanInRange s (2, 4) `shouldBe` 4+    it "meanInRange for sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; range: (0, 5)" $ do+      meanInRange s (0, 5) `shouldBe` 3+    it "meanInRange for sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; range: (0, 0)" $ do+      meanInRange s (0, 0) `shouldBe` 1++getWeightSpec :: Spec+getWeightSpec =+  describe "getWeight" $ do+    let s = unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5] :: TestWeightedSequence++    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; ind: 2" $ do+      getWeight s 2 `shouldBe` Right 3+    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; ind: 4" $ do+      getWeight s 4 `shouldBe` Right 5+    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]; ind: 7" $ do+      getWeight s 7 `shouldBe` Left "Bio.Sequence.Functions.Weight: index out of range."++toWeightedSpec :: Spec+toWeightedSpec =+  describe "toWeighted" $ do+    let s = bareSequence ['a', 'b', 'c', 'a', 'a'] :: TestBareSequence++    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 5]" $ do+      (toWeighted s [1.. 5] :: Either Text TestWeightedSequence) `shouldBe` Right (unsafeWeightedSequence ['a', 'b', 'c', 'a', 'a'] [1.. 5])+    it "sequence: ['a', 'b', 'c', 'a', 'a']; weights: [1.. 3]" $ do+      let rangesError = Left "Bio.Sequence.Class: sequence and weights have different lengths."+      (toWeighted s [1.. 3] :: Either Text TestWeightedSequence) `shouldBe` rangesError
+ test/Spec.hs view
@@ -0,0 +1,37 @@+import           ABISpec+import           GBParserSpec+import           GBWriterSpec+import           MMTFSpec+import           SequenceSpec+import           System.IO+import           Test.Hspec+import           UniprotSpec+import           FastaParserSpec+import           FastaWriterSpec+import           FASTASpec++main :: IO ()+main = do+    hSetBuffering stdout NoBuffering+    hspec $ do+         -- MMTF+         mmtfCodecSpec+         mmtfParserSpec+         -- Sequence+         weightedSequenceSpec+         markedSequenceSpec+         markedAndWeightedSequenceSpec+         functionsSpec+         -- ABI+         abiExtractSpec+         abiCleanSpec+         -- Uniprot+         uniprotSectionSpec+         uniprotFullSpec+         -- GB+         gbParserSpec+         gbWriterSpec+         -- Fasta+         fastaParserSpec+         fastaSpec+         fastaWriterSpec
+ test/UniprotSpec.hs view
@@ -0,0 +1,983 @@+{-# LANGUAGE QuasiQuotes       #-}+module UniprotSpec where++import           Prelude       hiding (lines, unlines)++import           Data.Text            (Text)+import           Data.Attoparsec.Text (parseOnly, endOfLine, many')+import           NeatInterpolation    (text)+import           Test.Hspec++import          Bio.Uniprot.Type+import          Bio.Uniprot.Parser++idStr :: Text+idStr = "ID   PDCD1_HUMAN             Reviewed;         288 AA."++acStr :: Text+acStr = "AC   Q15116; O00517; Q8IX89;"++dtStr :: Text+dtStr = [text|+DT   01-NOV-1997, integrated into UniProtKB/Swiss-Prot.+DT   17-APR-2007, sequence version 3.+DT   28-FEB-2018, entry version 163.|]++deStr :: Text+deStr = [text|+DE   RecName: Full=Programmed cell death protein 1;+DE            Short=Protein PD-1;+DE            Short=hPD-1;+DE   AltName: CD_antigen=CD279;+DE   Flags: Precursor;|]++de2Str :: Text+de2Str = [text|+DE   RecName: Full=Arginine biosynthesis bifunctional protein argJ;+DE   Includes:+DE     RecName: Full=Glutamate N-acetyltransferase;+DE              EC=2.3.1.35;+DE     AltName: Full=Ornithine acetyltransferase;+DE              Short=OATase;+DE     AltName: Full=Ornithine transacetylase;+DE   Includes:+DE     RecName: Full=Amino-acid acetyltransferase;+DE              EC=2.3.1.1;+DE     AltName: Full=N-acetylglutamate synthase;+DE              Short=AGS;+DE   Contains:+DE     RecName: Full=Arginine biosynthesis bifunctional protein argJ alpha chain;+DE   Contains:+DE     RecName: Full=Arginine biosynthesis bifunctional protein argJ beta chain;|]+  +gnStr :: Text+gnStr = "GN   Name=PDCD1; Synonyms=PD1;"++osStr :: Text+osStr = "OS   Homo sapiens (Human)."++ogStr :: Text+ogStr = [text|+OG   Plasmid R6-5, Plasmid IncFII R100 (NR1), and+OG   Plasmid IncFII R1-19 (R1 drd-19).|]++ocStr :: Text+ocStr = [text|+OC   Eukaryota; Metazoa; Chordata; Craniata; Vertebrata; Euteleostomi;+OC   Mammalia; Eutheria; Euarchontoglires; Primates; Haplorrhini;+OC   Catarrhini; Hominidae; Homo.|]++oxStr :: Text+oxStr = "OX   NCBI_TaxID=9606;"++ohStr :: Text+ohStr = "OH   NCBI_TaxID=9536; Cercopithecus hamlyni (Owl-faced monkey) (Hamlyn's monkey)."++refStr :: Text+refStr = [text|+RN   [1]+RP   NUCLEOTIDE SEQUENCE [GENOMIC DNA].+RX   PubMed=7851902; DOI=10.1006/geno.1994.1562;+RA   Shinohara T., Taniwaki M., Ishida Y., Kawaich M., Honjo T.;+RT   "Structure and chromosomal localization of the human PD-1 gene+RT   (PDCD1).";+RL   Genomics 23:704-706(1994).+RN   [2]+RP   NUCLEOTIDE SEQUENCE [MRNA].+RX   PubMed=9332365; DOI=10.1016/S0378-1119(97)00260-6;+RA   Finger L.R., Pu J., Wasserman R., Vibhakar R., Louie E., Hardy R.R.,+RA   Burrows P.D., Billips L.D.;+RT   "The human PD-1 gene: complete cDNA, genomic organization, and+RT   developmentally regulated expression in B cell progenitors.";+RL   Gene 197:177-187(1997).+RN   [3]+RP   ERRATUM.+RA   Finger L.R., Pu J., Wasserman R., Vibhakar R., Louie E., Hardy R.R.,+RA   Burrows P.D., Billips L.D.;+RL   Gene 203:253-253(1997).+RN   [4]+RP   NUCLEOTIDE SEQUENCE [GENOMIC DNA], AND INVOLVEMENT IN SLEB2.+RX   PubMed=12402038; DOI=10.1038/ng1020;+RA   Prokunina L., Castillejo-Lopez C., Oberg F., Gunnarsson I., Berg L.,+RA   Magnusson V., Brookes A.J., Tentler D., Kristjansdottir H.,+RA   Grondal G., Bolstad A.I., Svenungsson E., Lundberg I., Sturfelt G.,+RA   Jonssen A., Truedsson L., Lima G., Alcocer-Varela J., Jonsson R.,+RA   Gyllensten U.B., Harley J.B., Alarcon-Segovia D., Steinsson K.,+RA   Alarcon-Riquelme M.E.;+RT   "A regulatory polymorphism in PDCD1 is associated with susceptibility+RT   to systemic lupus erythematosus in humans.";+RL   Nat. Genet. 32:666-669(2002).+RN   [5]+RP   NUCLEOTIDE SEQUENCE [MRNA].+RA   He X., Xu L., Liu Y., Zeng Y.;+RT   "Cloning of PD-1 cDNA from activated peripheral leukocytes.";+RL   Submitted (FEB-2003) to the EMBL/GenBank/DDBJ databases.+RN   [6]+RP   NUCLEOTIDE SEQUENCE [GENOMIC DNA].+RA   Livingston R.J., Shaffer T., McFarland I., Nguyen C.P., Stanaway I.B.,+RA   Rajkumar N., Johnson E.J., da Ponte S.H., Willa H., Ahearn M.O.,+RA   Bertucci C., Acklestad J., Carroll A., Swanson J., Gildersleeve H.I.,+RA   Nickerson D.A.;+RL   Submitted (OCT-2006) to the EMBL/GenBank/DDBJ databases.+RN   [7]+RP   NUCLEOTIDE SEQUENCE [LARGE SCALE MRNA].+RX   PubMed=14702039; DOI=10.1038/ng1285;+RA   Ota T., Suzuki Y., Nishikawa T., Otsuki T., Sugiyama T., Irie R.,+RA   Wakamatsu A., Hayashi K., Sato H., Nagai K., Kimura K., Makita H.,+RA   Sekine M., Obayashi M., Nishi T., Shibahara T., Tanaka T., Ishii S.,+RA   Yamamoto J., Saito K., Kawai Y., Isono Y., Nakamura Y., Nagahari K.,+RA   Murakami K., Yasuda T., Iwayanagi T., Wagatsuma M., Shiratori A.,+RA   Sudo H., Hosoiri T., Kaku Y., Kodaira H., Kondo H., Sugawara M.,+RA   Takahashi M., Kanda K., Yokoi T., Furuya T., Kikkawa E., Omura Y.,+RA   Abe K., Kamihara K., Katsuta N., Sato K., Tanikawa M., Yamazaki M.,+RA   Ninomiya K., Ishibashi T., Yamashita H., Murakawa K., Fujimori K.,+RA   Tanai H., Kimata M., Watanabe M., Hiraoka S., Chiba Y., Ishida S.,+RA   Ono Y., Takiguchi S., Watanabe S., Yosida M., Hotuta T., Kusano J.,+RA   Kanehori K., Takahashi-Fujii A., Hara H., Tanase T.-O., Nomura Y.,+RA   Togiya S., Komai F., Hara R., Takeuchi K., Arita M., Imose N.,+RA   Musashino K., Yuuki H., Oshima A., Sasaki N., Aotsuka S.,+RA   Yoshikawa Y., Matsunawa H., Ichihara T., Shiohata N., Sano S.,+RA   Moriya S., Momiyama H., Satoh N., Takami S., Terashima Y., Suzuki O.,+RA   Nakagawa S., Senoh A., Mizoguchi H., Goto Y., Shimizu F., Wakebe H.,+RA   Hishigaki H., Watanabe T., Sugiyama A., Takemoto M., Kawakami B.,+RA   Yamazaki M., Watanabe K., Kumagai A., Itakura S., Fukuzumi Y.,+RA   Fujimori Y., Komiyama M., Tashiro H., Tanigami A., Fujiwara T.,+RA   Ono T., Yamada K., Fujii Y., Ozaki K., Hirao M., Ohmori Y.,+RA   Kawabata A., Hikiji T., Kobatake N., Inagaki H., Ikema Y., Okamoto S.,+RA   Okitani R., Kawakami T., Noguchi S., Itoh T., Shigeta K., Senba T.,+RA   Matsumura K., Nakajima Y., Mizuno T., Morinaga M., Sasaki M.,+RA   Togashi T., Oyama M., Hata H., Watanabe M., Komatsu T.,+RA   Mizushima-Sugano J., Satoh T., Shirai Y., Takahashi Y., Nakagawa K.,+RA   Okumura K., Nagase T., Nomura N., Kikuchi H., Masuho Y., Yamashita R.,+RA   Nakai K., Yada T., Nakamura Y., Ohara O., Isogai T., Sugano S.;+RT   "Complete sequencing and characterization of 21,243 full-length human+RT   cDNAs.";+RL   Nat. Genet. 36:40-45(2004).+RN   [8]+RP   NUCLEOTIDE SEQUENCE [LARGE SCALE MRNA].+RX   PubMed=15489334; DOI=10.1101/gr.2596504;+RG   The MGC Project Team;+RT   "The status, quality, and expansion of the NIH full-length cDNA+RT   project: the Mammalian Gene Collection (MGC).";+RL   Genome Res. 14:2121-2127(2004).+RN   [9]+RP   NUCLEOTIDE SEQUENCE [LARGE SCALE GENOMIC DNA].+RA   Mural R.J., Istrail S., Sutton G., Florea L., Halpern A.L.,+RA   Mobarry C.M., Lippert R., Walenz B., Shatkay H., Dew I., Miller J.R.,+RA   Flanigan M.J., Edwards N.J., Bolanos R., Fasulo D., Halldorsson B.V.,+RA   Hannenhalli S., Turner R., Yooseph S., Lu F., Nusskern D.R.,+RA   Shue B.C., Zheng X.H., Zhong F., Delcher A.L., Huson D.H.,+RA   Kravitz S.A., Mouchard L., Reinert K., Remington K.A., Clark A.G.,+RA   Waterman M.S., Eichler E.E., Adams M.D., Hunkapiller M.W., Myers E.W.,+RA   Venter J.C.;+RL   Submitted (JUL-2005) to the EMBL/GenBank/DDBJ databases.+RN   [10]+RP   FUNCTION.+RX   PubMed=21276005; DOI=10.1111/j.1749-6632.2010.05919.x;+RA   Fife B.T., Pauken K.E.;+RT   "The role of the PD-1 pathway in autoimmunity and peripheral+RT   tolerance.";+RL   Ann. N. Y. Acad. Sci. 1217:45-59(2011).|]++ccStr :: Text+ccStr = [text|+CC   -!- FUNCTION: Inhibitory cell surface receptor involved in the+CC       regulation of T-cell function during immunity and tolerance. Upon+CC       ligand binding, inhibits T-cell effector functions in an antigen-+CC       specific manner. Possible cell death inducer, in association with+CC       other factors. {ECO:0000269|PubMed:21276005}.+CC   -!- SUBUNIT: Monomer. {ECO:0000250}.+CC   -!- INTERACTION:+CC       Q9NZQ7:CD274; NbExp=2; IntAct=EBI-4314328, EBI-4314282;+CC       Q9NZQ7-1:CD274; NbExp=2; IntAct=EBI-4314328, EBI-15686469;+CC       Q06124:PTPN11; NbExp=3; IntAct=EBI-4314328, EBI-297779;+CC   -!- SUBCELLULAR LOCATION: Membrane; Single-pass type I membrane+CC       protein.+CC   -!- DEVELOPMENTAL STAGE: Induced at programmed cell death.+CC   -!- DISEASE: Systemic lupus erythematosus 2 (SLEB2) [MIM:605218]: A+CC       chronic, relapsing, inflammatory, and often febrile multisystemic+CC       disorder of connective tissue, characterized principally by+CC       involvement of the skin, joints, kidneys and serosal membranes. It+CC       is of unknown etiology, but is thought to represent a failure of+CC       the regulatory mechanisms of the autoimmune system. The disease is+CC       marked by a wide range of system dysfunctions, an elevated+CC       erythrocyte sedimentation rate, and the formation of LE cells in+CC       the blood or bone marrow. {ECO:0000269|PubMed:12402038}.+CC       Note=Disease susceptibility is associated with variations+CC       affecting the gene represented in this entry.|]++peStr :: Text+peStr = "PE   1: Evidence at protein level;"++kwStr :: Text+kwStr = [text|+KW   3D-structure; Apoptosis; Complete proteome; Disulfide bond;+KW   Glycoprotein; Immunity; Immunoglobulin domain; Membrane; Polymorphism;+KW   Reference proteome; Signal; Systemic lupus erythematosus;+KW   Transmembrane; Transmembrane helix.|]++drStr :: Text+drStr = [text|+DR   EMBL; L27440; AAC41700.1; -; Genomic_DNA.+DR   EMBL; U64863; AAC51773.1; -; mRNA.+DR   EMBL; AF363458; AAN64003.1; -; Genomic_DNA.+DR   EMBL; AY238517; AAO63583.1; -; mRNA.+DR   EMBL; EF064716; ABK41899.1; -; Genomic_DNA.+DR   EMBL; AK313848; BAG36577.1; -; mRNA.+DR   EMBL; CH471063; EAW71298.1; -; Genomic_DNA.+DR   EMBL; BC074740; AAH74740.1; -; mRNA.+DR   CCDS; CCDS33428.1; -.+DR   PIR; A55737; A55737.+DR   RefSeq; NP_005009.2; NM_005018.2.+DR   UniGene; Hs.158297; -.+DR   PDB; 2M2D; NMR; -; A=34-150.+DR   PDB; 3RRQ; X-ray; 2.10 A; A=32-160.+DR   PDB; 4ZQK; X-ray; 2.45 A; B=33-150.+DR   PDB; 5B8C; X-ray; 2.15 A; C/F/I/L=32-160.+DR   PDB; 5GGR; X-ray; 3.30 A; Y/Z=26-150.+DR   PDB; 5GGS; X-ray; 2.00 A; Y/Z=26-148.+DR   PDB; 5IUS; X-ray; 2.89 A; A/B=26-146.+DR   PDB; 5JXE; X-ray; 2.90 A; A/B=33-146.+DR   PDB; 5WT9; X-ray; 2.40 A; G=1-167.+DR   PDBsum; 2M2D; -.+DR   PDBsum; 3RRQ; -.+DR   PDBsum; 4ZQK; -.+DR   PDBsum; 5B8C; -.+DR   PDBsum; 5GGR; -.+DR   PDBsum; 5GGS; -.+DR   PDBsum; 5IUS; -.+DR   PDBsum; 5JXE; -.+DR   PDBsum; 5WT9; -.+DR   ProteinModelPortal; Q15116; -.+DR   SMR; Q15116; -.+DR   BioGrid; 111160; 61.+DR   DIP; DIP-44126N; -.+DR   IntAct; Q15116; 5.+DR   MINT; Q15116; -.+DR   STRING; 9606.ENSP00000335062; -.+DR   ChEMBL; CHEMBL3307223; -.+DR   DrugBank; DB05916; CT-011.+DR   DrugBank; DB09035; Nivolumab.+DR   DrugBank; DB09037; Pembrolizumab.+DR   GuidetoPHARMACOLOGY; 2760; -.+DR   iPTMnet; Q15116; -.+DR   PhosphoSitePlus; Q15116; -.+DR   BioMuta; PDCD1; -.+DR   DMDM; 145559515; -.+DR   PaxDb; Q15116; -.+DR   PeptideAtlas; Q15116; -.+DR   PRIDE; Q15116; -.+DR   DNASU; 5133; -.+DR   Ensembl; ENST00000334409; ENSP00000335062; ENSG00000188389.+DR   Ensembl; ENST00000618185; ENSP00000480684; ENSG00000276977.+DR   GeneID; 5133; -.+DR   KEGG; hsa:5133; -.+DR   UCSC; uc002wcq.5; human.+DR   CTD; 5133; -.+DR   DisGeNET; 5133; -.+DR   EuPathDB; HostDB:ENSG00000188389.10; -.+DR   GeneCards; PDCD1; -.+DR   H-InvDB; HIX0030684; -.+DR   HGNC; HGNC:8760; PDCD1.+DR   HPA; CAB038418; -.+DR   HPA; HPA035981; -.+DR   MalaCards; PDCD1; -.+DR   MIM; 109100; phenotype.+DR   MIM; 600244; gene.+DR   MIM; 605218; phenotype.+DR   neXtProt; NX_Q15116; -.+DR   OpenTargets; ENSG00000188389; -.+DR   Orphanet; 802; Multiple sclerosis.+DR   Orphanet; 536; Systemic lupus erythematosus.+DR   PharmGKB; PA33110; -.+DR   eggNOG; ENOG410J26W; Eukaryota.+DR   eggNOG; ENOG41116U6; LUCA.+DR   GeneTree; ENSGT00390000013662; -.+DR   HOGENOM; HOG000253959; -.+DR   HOVERGEN; HBG053534; -.+DR   InParanoid; Q15116; -.+DR   KO; K06744; -.+DR   OMA; DFQWREK; -.+DR   OrthoDB; EOG091G0EE8; -.+DR   PhylomeDB; Q15116; -.+DR   TreeFam; TF336181; -.+DR   Reactome; R-HSA-389948; PD-1 signaling.+DR   SIGNOR; Q15116; -.+DR   ChiTaRS; PDCD1; human.+DR   GeneWiki; Programmed_cell_death_1; -.+DR   GenomeRNAi; 5133; -.+DR   PRO; PR:Q15116; -.+DR   Proteomes; UP000005640; Chromosome 2.+DR   Bgee; ENSG00000188389; -.+DR   CleanEx; HS_PDCD1; -.+DR   ExpressionAtlas; Q15116; baseline and differential.+DR   Genevisible; Q15116; HS.+DR   GO; GO:0009897; C:external side of plasma membrane; IEA:Ensembl.+DR   GO; GO:0016021; C:integral component of membrane; IEA:UniProtKB-KW.+DR   GO; GO:0005886; C:plasma membrane; TAS:Reactome.+DR   GO; GO:0004871; F:signal transducer activity; TAS:ProtInc.+DR   GO; GO:0006915; P:apoptotic process; TAS:ProtInc.+DR   GO; GO:0006959; P:humoral immune response; TAS:ProtInc.+DR   GO; GO:0007275; P:multicellular organism development; TAS:ProtInc.+DR   GO; GO:0043066; P:negative regulation of apoptotic process; IEA:Ensembl.+DR   GO; GO:0002644; P:negative regulation of tolerance induction; IEA:Ensembl.+DR   GO; GO:0070234; P:positive regulation of T cell apoptotic process; IDA:UniProtKB.+DR   GO; GO:0031295; P:T cell costimulation; TAS:Reactome.+DR   Gene3D; 2.60.40.10; -; 1.+DR   InterPro; IPR007110; Ig-like_dom.+DR   InterPro; IPR036179; Ig-like_dom_sf.+DR   InterPro; IPR013783; Ig-like_fold.+DR   InterPro; IPR003599; Ig_sub.+DR   InterPro; IPR013106; Ig_V-set.+DR   Pfam; PF07686; V-set; 1.+DR   SMART; SM00409; IG; 1.+DR   SMART; SM00406; IGv; 1.+DR   SUPFAM; SSF48726; SSF48726; 1.+DR   PROSITE; PS50835; IG_LIKE; 1.|]++ftStr :: Text+ftStr = [text|+FT   SIGNAL        1     20       {ECO:0000255}.+FT   CHAIN        21    288       Programmed cell death protein 1.+FT                                /FTId=PRO_0000014892.+FT   TOPO_DOM     21    170       Extracellular. {ECO:0000255}.+FT   TRANSMEM    171    191       Helical. {ECO:0000255}.+FT   TOPO_DOM    192    288       Cytoplasmic. {ECO:0000255}.+FT   DOMAIN       35    145       Ig-like V-type.+FT   CARBOHYD     49     49       N-linked (GlcNAc...) asparagine.+FT                                {ECO:0000255}.+FT   CARBOHYD     58     58       N-linked (GlcNAc...) asparagine.+FT                                {ECO:0000255}.+FT   CARBOHYD     74     74       N-linked (GlcNAc...) asparagine.+FT                                {ECO:0000255}.+FT   CARBOHYD    116    116       N-linked (GlcNAc...) asparagine.+FT                                {ECO:0000255}.+FT   DISULFID     54    123       {ECO:0000255|PROSITE-ProRule:PRU00114}.+FT   VARIANT     215    215       A -> V (in dbSNP:rs2227982).+FT                                /FTId=VAR_031685.+FT   CONFLICT     38     38       S -> F (in Ref. 2; AAC51773).+FT                                {ECO:0000305}.+FT   CONFLICT    162    162       P -> S (in Ref. 1; AAC41700).+FT                                {ECO:0000305}.+FT   STRAND       27     29       {ECO:0000244|PDB:5WT9}.+FT   STRAND       36     38       {ECO:0000244|PDB:5GGS}.+FT   STRAND       40     45       {ECO:0000244|PDB:5GGS}.+FT   STRAND       50     55       {ECO:0000244|PDB:5GGS}.+FT   STRAND       60     70       {ECO:0000244|PDB:5GGS}.+FT   STRAND       72     74       {ECO:0000244|PDB:4ZQK}.+FT   STRAND       76     83       {ECO:0000244|PDB:5GGS}.+FT   STRAND       95     99       {ECO:0000244|PDB:5GGS}.+FT   STRAND      103    112       {ECO:0000244|PDB:5GGS}.+FT   HELIX       115    117       {ECO:0000244|PDB:5GGS}.+FT   STRAND      119    131       {ECO:0000244|PDB:5GGS}.+FT   STRAND      134    136       {ECO:0000244|PDB:5GGS}.+FT   STRAND      140    145       {ECO:0000244|PDB:5GGS}.|]+  +sqStr :: Text+sqStr = [text|+SQ   SEQUENCE   288 AA;  31647 MW;  A5210FD40C304FB7 CRC64;+     MQIPQAPWPV VWAVLQLGWR PGWFLDSPDR PWNPPTFSPA LLVVTEGDNA TFTCSFSNTS+     ESFVLNWYRM SPSNQTDKLA AFPEDRSQPG QDCRFRVTQL PNGRDFHMSV VRARRNDSGT+     YLCGAISLAP KAQIKESLRA ELRVTERRAE VPTAHPSPSP RPAGQFQTLV VGVVGGLLGS+     LVLLVWVLAV ICSRAARGTI GARRTGQPLK EDPSAVPVFS VDYGELDFQW REKTPEPPVP+     CVPEQTEYAT IVFPSGMGTS SPARRGSADG PRSAQPLRPE DGHCSWPL|]++endStr :: Text+endStr = "//"++pd1Str :: Text+pd1Str = [text|+ID   PDCD1_HUMAN             Reviewed;         288 AA.+AC   Q15116; O00517; Q8IX89;+DT   01-NOV-1997, integrated into UniProtKB/Swiss-Prot.+DT   17-APR-2007, sequence version 3.+DT   28-FEB-2018, entry version 163.+DE   RecName: Full=Programmed cell death protein 1;+DE            Short=Protein PD-1;+DE            Short=hPD-1;+DE   AltName: CD_antigen=CD279;+DE   Flags: Precursor;+GN   Name=PDCD1; Synonyms=PD1;+OS   Homo sapiens (Human).+OC   Eukaryota; Metazoa; Chordata; Craniata; Vertebrata; Euteleostomi;+OC   Mammalia; Eutheria; Euarchontoglires; Primates; Haplorrhini;+OC   Catarrhini; Hominidae; Homo.+OX   NCBI_TaxID=9606;+RN   [1]+RP   NUCLEOTIDE SEQUENCE [GENOMIC DNA].+RX   PubMed=7851902; DOI=10.1006/geno.1994.1562;+RA   Shinohara T., Taniwaki M., Ishida Y., Kawaich M., Honjo T.;+RT   "Structure and chromosomal localization of the human PD-1 gene+RT   (PDCD1).";+RL   Genomics 23:704-706(1994).+RN   [2]+RP   NUCLEOTIDE SEQUENCE [MRNA].+RX   PubMed=9332365; DOI=10.1016/S0378-1119(97)00260-6;+RA   Finger L.R., Pu J., Wasserman R., Vibhakar R., Louie E., Hardy R.R.,+RA   Burrows P.D., Billips L.D.;+RT   "The human PD-1 gene: complete cDNA, genomic organization, and+RT   developmentally regulated expression in B cell progenitors.";+RL   Gene 197:177-187(1997).+RN   [3]+RP   ERRATUM.+RA   Finger L.R., Pu J., Wasserman R., Vibhakar R., Louie E., Hardy R.R.,+RA   Burrows P.D., Billips L.D.;+RL   Gene 203:253-253(1997).+RN   [4]+RP   NUCLEOTIDE SEQUENCE [GENOMIC DNA], AND INVOLVEMENT IN SLEB2.+RX   PubMed=12402038; DOI=10.1038/ng1020;+RA   Prokunina L., Castillejo-Lopez C., Oberg F., Gunnarsson I., Berg L.,+RA   Magnusson V., Brookes A.J., Tentler D., Kristjansdottir H.,+RA   Grondal G., Bolstad A.I., Svenungsson E., Lundberg I., Sturfelt G.,+RA   Jonssen A., Truedsson L., Lima G., Alcocer-Varela J., Jonsson R.,+RA   Gyllensten U.B., Harley J.B., Alarcon-Segovia D., Steinsson K.,+RA   Alarcon-Riquelme M.E.;+RT   "A regulatory polymorphism in PDCD1 is associated with susceptibility+RT   to systemic lupus erythematosus in humans.";+RL   Nat. Genet. 32:666-669(2002).+RN   [5]+RP   NUCLEOTIDE SEQUENCE [MRNA].+RA   He X., Xu L., Liu Y., Zeng Y.;+RT   "Cloning of PD-1 cDNA from activated peripheral leukocytes.";+RL   Submitted (FEB-2003) to the EMBL/GenBank/DDBJ databases.+RN   [6]+RP   NUCLEOTIDE SEQUENCE [GENOMIC DNA].+RA   Livingston R.J., Shaffer T., McFarland I., Nguyen C.P., Stanaway I.B.,+RA   Rajkumar N., Johnson E.J., da Ponte S.H., Willa H., Ahearn M.O.,+RA   Bertucci C., Acklestad J., Carroll A., Swanson J., Gildersleeve H.I.,+RA   Nickerson D.A.;+RL   Submitted (OCT-2006) to the EMBL/GenBank/DDBJ databases.+RN   [7]+RP   NUCLEOTIDE SEQUENCE [LARGE SCALE MRNA].+RX   PubMed=14702039; DOI=10.1038/ng1285;+RA   Ota T., Suzuki Y., Nishikawa T., Otsuki T., Sugiyama T., Irie R.,+RA   Wakamatsu A., Hayashi K., Sato H., Nagai K., Kimura K., Makita H.,+RA   Sekine M., Obayashi M., Nishi T., Shibahara T., Tanaka T., Ishii S.,+RA   Yamamoto J., Saito K., Kawai Y., Isono Y., Nakamura Y., Nagahari K.,+RA   Murakami K., Yasuda T., Iwayanagi T., Wagatsuma M., Shiratori A.,+RA   Sudo H., Hosoiri T., Kaku Y., Kodaira H., Kondo H., Sugawara M.,+RA   Takahashi M., Kanda K., Yokoi T., Furuya T., Kikkawa E., Omura Y.,+RA   Abe K., Kamihara K., Katsuta N., Sato K., Tanikawa M., Yamazaki M.,+RA   Ninomiya K., Ishibashi T., Yamashita H., Murakawa K., Fujimori K.,+RA   Tanai H., Kimata M., Watanabe M., Hiraoka S., Chiba Y., Ishida S.,+RA   Ono Y., Takiguchi S., Watanabe S., Yosida M., Hotuta T., Kusano J.,+RA   Kanehori K., Takahashi-Fujii A., Hara H., Tanase T.-O., Nomura Y.,+RA   Togiya S., Komai F., Hara R., Takeuchi K., Arita M., Imose N.,+RA   Musashino K., Yuuki H., Oshima A., Sasaki N., Aotsuka S.,+RA   Yoshikawa Y., Matsunawa H., Ichihara T., Shiohata N., Sano S.,+RA   Moriya S., Momiyama H., Satoh N., Takami S., Terashima Y., Suzuki O.,+RA   Nakagawa S., Senoh A., Mizoguchi H., Goto Y., Shimizu F., Wakebe H.,+RA   Hishigaki H., Watanabe T., Sugiyama A., Takemoto M., Kawakami B.,+RA   Yamazaki M., Watanabe K., Kumagai A., Itakura S., Fukuzumi Y.,+RA   Fujimori Y., Komiyama M., Tashiro H., Tanigami A., Fujiwara T.,+RA   Ono T., Yamada K., Fujii Y., Ozaki K., Hirao M., Ohmori Y.,+RA   Kawabata A., Hikiji T., Kobatake N., Inagaki H., Ikema Y., Okamoto S.,+RA   Okitani R., Kawakami T., Noguchi S., Itoh T., Shigeta K., Senba T.,+RA   Matsumura K., Nakajima Y., Mizuno T., Morinaga M., Sasaki M.,+RA   Togashi T., Oyama M., Hata H., Watanabe M., Komatsu T.,+RA   Mizushima-Sugano J., Satoh T., Shirai Y., Takahashi Y., Nakagawa K.,+RA   Okumura K., Nagase T., Nomura N., Kikuchi H., Masuho Y., Yamashita R.,+RA   Nakai K., Yada T., Nakamura Y., Ohara O., Isogai T., Sugano S.;+RT   "Complete sequencing and characterization of 21,243 full-length human+RT   cDNAs.";+RL   Nat. Genet. 36:40-45(2004).+RN   [8]+RP   NUCLEOTIDE SEQUENCE [LARGE SCALE MRNA].+RX   PubMed=15489334; DOI=10.1101/gr.2596504;+RG   The MGC Project Team;+RT   "The status, quality, and expansion of the NIH full-length cDNA+RT   project: the Mammalian Gene Collection (MGC).";+RL   Genome Res. 14:2121-2127(2004).+RN   [9]+RP   NUCLEOTIDE SEQUENCE [LARGE SCALE GENOMIC DNA].+RA   Mural R.J., Istrail S., Sutton G., Florea L., Halpern A.L.,+RA   Mobarry C.M., Lippert R., Walenz B., Shatkay H., Dew I., Miller J.R.,+RA   Flanigan M.J., Edwards N.J., Bolanos R., Fasulo D., Halldorsson B.V.,+RA   Hannenhalli S., Turner R., Yooseph S., Lu F., Nusskern D.R.,+RA   Shue B.C., Zheng X.H., Zhong F., Delcher A.L., Huson D.H.,+RA   Kravitz S.A., Mouchard L., Reinert K., Remington K.A., Clark A.G.,+RA   Waterman M.S., Eichler E.E., Adams M.D., Hunkapiller M.W., Myers E.W.,+RA   Venter J.C.;+RL   Submitted (JUL-2005) to the EMBL/GenBank/DDBJ databases.+RN   [10]+RP   FUNCTION.+RX   PubMed=21276005; DOI=10.1111/j.1749-6632.2010.05919.x;+RA   Fife B.T., Pauken K.E.;+RT   "The role of the PD-1 pathway in autoimmunity and peripheral+RT   tolerance.";+RL   Ann. N. Y. Acad. Sci. 1217:45-59(2011).+CC   -!- FUNCTION: Inhibitory cell surface receptor involved in the+CC       regulation of T-cell function during immunity and tolerance. Upon+CC       ligand binding, inhibits T-cell effector functions in an antigen-+CC       specific manner. Possible cell death inducer, in association with+CC       other factors. {ECO:0000269|PubMed:21276005}.+CC   -!- SUBUNIT: Monomer. {ECO:0000250}.+CC   -!- INTERACTION:+CC       Q9NZQ7:CD274; NbExp=2; IntAct=EBI-4314328, EBI-4314282;+CC       Q9NZQ7-1:CD274; NbExp=2; IntAct=EBI-4314328, EBI-15686469;+CC       Q06124:PTPN11; NbExp=3; IntAct=EBI-4314328, EBI-297779;+CC   -!- SUBCELLULAR LOCATION: Membrane; Single-pass type I membrane+CC       protein.+CC   -!- DEVELOPMENTAL STAGE: Induced at programmed cell death.+CC   -!- DISEASE: Systemic lupus erythematosus 2 (SLEB2) [MIM:605218]: A+CC       chronic, relapsing, inflammatory, and often febrile multisystemic+CC       disorder of connective tissue, characterized principally by+CC       involvement of the skin, joints, kidneys and serosal membranes. It+CC       is of unknown etiology, but is thought to represent a failure of+CC       the regulatory mechanisms of the autoimmune system. The disease is+CC       marked by a wide range of system dysfunctions, an elevated+CC       erythrocyte sedimentation rate, and the formation of LE cells in+CC       the blood or bone marrow. {ECO:0000269|PubMed:12402038}.+CC       Note=Disease susceptibility is associated with variations+CC       affecting the gene represented in this entry.+DR   EMBL; L27440; AAC41700.1; -; Genomic_DNA.+DR   EMBL; U64863; AAC51773.1; -; mRNA.+DR   EMBL; AF363458; AAN64003.1; -; Genomic_DNA.+DR   EMBL; AY238517; AAO63583.1; -; mRNA.+DR   EMBL; EF064716; ABK41899.1; -; Genomic_DNA.+DR   EMBL; AK313848; BAG36577.1; -; mRNA.+DR   EMBL; CH471063; EAW71298.1; -; Genomic_DNA.+DR   EMBL; BC074740; AAH74740.1; -; mRNA.+DR   CCDS; CCDS33428.1; -.+DR   PIR; A55737; A55737.+DR   RefSeq; NP_005009.2; NM_005018.2.+DR   UniGene; Hs.158297; -.+DR   PDB; 2M2D; NMR; -; A=34-150.+DR   PDB; 3RRQ; X-ray; 2.10 A; A=32-160.+DR   PDB; 4ZQK; X-ray; 2.45 A; B=33-150.+DR   PDB; 5B8C; X-ray; 2.15 A; C/F/I/L=32-160.+DR   PDB; 5GGR; X-ray; 3.30 A; Y/Z=26-150.+DR   PDB; 5GGS; X-ray; 2.00 A; Y/Z=26-148.+DR   PDB; 5IUS; X-ray; 2.89 A; A/B=26-146.+DR   PDB; 5JXE; X-ray; 2.90 A; A/B=33-146.+DR   PDB; 5WT9; X-ray; 2.40 A; G=1-167.+DR   PDBsum; 2M2D; -.+DR   PDBsum; 3RRQ; -.+DR   PDBsum; 4ZQK; -.+DR   PDBsum; 5B8C; -.+DR   PDBsum; 5GGR; -.+DR   PDBsum; 5GGS; -.+DR   PDBsum; 5IUS; -.+DR   PDBsum; 5JXE; -.+DR   PDBsum; 5WT9; -.+DR   ProteinModelPortal; Q15116; -.+DR   SMR; Q15116; -.+DR   BioGrid; 111160; 61.+DR   DIP; DIP-44126N; -.+DR   IntAct; Q15116; 5.+DR   MINT; Q15116; -.+DR   STRING; 9606.ENSP00000335062; -.+DR   ChEMBL; CHEMBL3307223; -.+DR   DrugBank; DB05916; CT-011.+DR   DrugBank; DB09035; Nivolumab.+DR   DrugBank; DB09037; Pembrolizumab.+DR   GuidetoPHARMACOLOGY; 2760; -.+DR   iPTMnet; Q15116; -.+DR   PhosphoSitePlus; Q15116; -.+DR   BioMuta; PDCD1; -.+DR   DMDM; 145559515; -.+DR   PaxDb; Q15116; -.+DR   PeptideAtlas; Q15116; -.+DR   PRIDE; Q15116; -.+DR   DNASU; 5133; -.+DR   Ensembl; ENST00000334409; ENSP00000335062; ENSG00000188389.+DR   Ensembl; ENST00000618185; ENSP00000480684; ENSG00000276977.+DR   GeneID; 5133; -.+DR   KEGG; hsa:5133; -.+DR   UCSC; uc002wcq.5; human.+DR   CTD; 5133; -.+DR   DisGeNET; 5133; -.+DR   EuPathDB; HostDB:ENSG00000188389.10; -.+DR   GeneCards; PDCD1; -.+DR   H-InvDB; HIX0030684; -.+DR   HGNC; HGNC:8760; PDCD1.+DR   HPA; CAB038418; -.+DR   HPA; HPA035981; -.+DR   MalaCards; PDCD1; -.+DR   MIM; 109100; phenotype.+DR   MIM; 600244; gene.+DR   MIM; 605218; phenotype.+DR   neXtProt; NX_Q15116; -.+DR   OpenTargets; ENSG00000188389; -.+DR   Orphanet; 802; Multiple sclerosis.+DR   Orphanet; 536; Systemic lupus erythematosus.+DR   PharmGKB; PA33110; -.+DR   eggNOG; ENOG410J26W; Eukaryota.+DR   eggNOG; ENOG41116U6; LUCA.+DR   GeneTree; ENSGT00390000013662; -.+DR   HOGENOM; HOG000253959; -.+DR   HOVERGEN; HBG053534; -.+DR   InParanoid; Q15116; -.+DR   KO; K06744; -.+DR   OMA; DFQWREK; -.+DR   OrthoDB; EOG091G0EE8; -.+DR   PhylomeDB; Q15116; -.+DR   TreeFam; TF336181; -.+DR   Reactome; R-HSA-389948; PD-1 signaling.+DR   SIGNOR; Q15116; -.+DR   ChiTaRS; PDCD1; human.+DR   GeneWiki; Programmed_cell_death_1; -.+DR   GenomeRNAi; 5133; -.+DR   PRO; PR:Q15116; -.+DR   Proteomes; UP000005640; Chromosome 2.+DR   Bgee; ENSG00000188389; -.+DR   CleanEx; HS_PDCD1; -.+DR   ExpressionAtlas; Q15116; baseline and differential.+DR   Genevisible; Q15116; HS.+DR   GO; GO:0009897; C:external side of plasma membrane; IEA:Ensembl.+DR   GO; GO:0016021; C:integral component of membrane; IEA:UniProtKB-KW.+DR   GO; GO:0005886; C:plasma membrane; TAS:Reactome.+DR   GO; GO:0004871; F:signal transducer activity; TAS:ProtInc.+DR   GO; GO:0006915; P:apoptotic process; TAS:ProtInc.+DR   GO; GO:0006959; P:humoral immune response; TAS:ProtInc.+DR   GO; GO:0007275; P:multicellular organism development; TAS:ProtInc.+DR   GO; GO:0043066; P:negative regulation of apoptotic process; IEA:Ensembl.+DR   GO; GO:0002644; P:negative regulation of tolerance induction; IEA:Ensembl.+DR   GO; GO:0070234; P:positive regulation of T cell apoptotic process; IDA:UniProtKB.+DR   GO; GO:0031295; P:T cell costimulation; TAS:Reactome.+DR   Gene3D; 2.60.40.10; -; 1.+DR   InterPro; IPR007110; Ig-like_dom.+DR   InterPro; IPR036179; Ig-like_dom_sf.+DR   InterPro; IPR013783; Ig-like_fold.+DR   InterPro; IPR003599; Ig_sub.+DR   InterPro; IPR013106; Ig_V-set.+DR   Pfam; PF07686; V-set; 1.+DR   SMART; SM00409; IG; 1.+DR   SMART; SM00406; IGv; 1.+DR   SUPFAM; SSF48726; SSF48726; 1.+DR   PROSITE; PS50835; IG_LIKE; 1.+PE   1: Evidence at protein level;+KW   3D-structure; Apoptosis; Complete proteome; Disulfide bond;+KW   Glycoprotein; Immunity; Immunoglobulin domain; Membrane; Polymorphism;+KW   Reference proteome; Signal; Systemic lupus erythematosus;+KW   Transmembrane; Transmembrane helix.+FT   SIGNAL        1     20       {ECO:0000255}.+FT   CHAIN        21    288       Programmed cell death protein 1.+FT                                /FTId=PRO_0000014892.+FT   TOPO_DOM     21    170       Extracellular. {ECO:0000255}.+FT   TRANSMEM    171    191       Helical. {ECO:0000255}.+FT   TOPO_DOM    192    288       Cytoplasmic. {ECO:0000255}.+FT   DOMAIN       35    145       Ig-like V-type.+FT   CARBOHYD     49     49       N-linked (GlcNAc...) asparagine.+FT                                {ECO:0000255}.+FT   CARBOHYD     58     58       N-linked (GlcNAc...) asparagine.+FT                                {ECO:0000255}.+FT   CARBOHYD     74     74       N-linked (GlcNAc...) asparagine.+FT                                {ECO:0000255}.+FT   CARBOHYD    116    116       N-linked (GlcNAc...) asparagine.+FT                                {ECO:0000255}.+FT   DISULFID     54    123       {ECO:0000255|PROSITE-ProRule:PRU00114}.+FT   VARIANT     215    215       A -> V (in dbSNP:rs2227982).+FT                                /FTId=VAR_031685.+FT   CONFLICT     38     38       S -> F (in Ref. 2; AAC51773).+FT                                {ECO:0000305}.+FT   CONFLICT    162    162       P -> S (in Ref. 1; AAC41700).+FT                                {ECO:0000305}.+FT   STRAND       27     29       {ECO:0000244|PDB:5WT9}.+FT   STRAND       36     38       {ECO:0000244|PDB:5GGS}.+FT   STRAND       40     45       {ECO:0000244|PDB:5GGS}.+FT   STRAND       50     55       {ECO:0000244|PDB:5GGS}.+FT   STRAND       60     70       {ECO:0000244|PDB:5GGS}.+FT   STRAND       72     74       {ECO:0000244|PDB:4ZQK}.+FT   STRAND       76     83       {ECO:0000244|PDB:5GGS}.+FT   STRAND       95     99       {ECO:0000244|PDB:5GGS}.+FT   STRAND      103    112       {ECO:0000244|PDB:5GGS}.+FT   HELIX       115    117       {ECO:0000244|PDB:5GGS}.+FT   STRAND      119    131       {ECO:0000244|PDB:5GGS}.+FT   STRAND      134    136       {ECO:0000244|PDB:5GGS}.+FT   STRAND      140    145       {ECO:0000244|PDB:5GGS}.+SQ   SEQUENCE   288 AA;  31647 MW;  A5210FD40C304FB7 CRC64;+     MQIPQAPWPV VWAVLQLGWR PGWFLDSPDR PWNPPTFSPA LLVVTEGDNA TFTCSFSNTS+     ESFVLNWYRM SPSNQTDKLA AFPEDRSQPG QDCRFRVTQL PNGRDFHMSV VRARRNDSGT+     YLCGAISLAP KAQIKESLRA ELRVTERRAE VPTAHPSPSP RPAGQFQTLV VGVVGGLLGS+     LVLLVWVLAV ICSRAARGTI GARRTGQPLK EDPSAVPVFS VDYGELDFQW REKTPEPPVP+     CVPEQTEYAT IVFPSGMGTS SPARRGSADG PRSAQPLRPE DGHCSWPL+//|]++idAns :: ID+idAns = ID "PDCD1_HUMAN" Reviewed 288++acAns :: AC+acAns = AC ["Q15116", "O00517", "Q8IX89"]++dtAns :: DT+dtAns = DT "01-NOV-1997" "Swiss-Prot" "17-APR-2007" 3 "28-FEB-2018" 163++deAns :: DE+deAns = DE (Just (Name "Programmed cell death protein 1" ["Protein PD-1", "hPD-1"] []))+           [CDAntigen "CD279"] [] [] [] [Precursor]++de2Ans :: DE+de2Ans = DE (Just (Name "Arginine biosynthesis bifunctional protein argJ" [] [])) [] []+            [DE (Just (Name "Glutamate N-acetyltransferase" [] ["2.3.1.35"]))+                [Simple (Name "Ornithine acetyltransferase" ["OATase"] []),+                 Simple (Name "Ornithine transacetylase" [] [])]+                [] [] [] [],+             DE (Just (Name "Amino-acid acetyltransferase" [] ["2.3.1.1"]))+                [Simple (Name "N-acetylglutamate synthase" ["AGS"] [])]+                [] [] [] []+            ]+            [DE (Just (Name "Arginine biosynthesis bifunctional protein argJ alpha chain" [] []))+                [] [] [] [] [],+             DE (Just (Name "Arginine biosynthesis bifunctional protein argJ beta chain" [] []))+                [] [] [] [] []]+            []++gnAns :: [GN]+gnAns = [GN (Just "PDCD1") ["PD1"] [] []]++osAns :: OS+osAns = OS "Homo sapiens (Human)"++ogAns :: OG+ogAns = Plasmid ["R6-5", "IncFII R100 (NR1)", "IncFII R1-19 (R1 drd-19)"]++ocAns :: OC+ocAns = OC ["Eukaryota", "Metazoa", "Chordata", "Craniata",+            "Vertebrata", "Euteleostomi", "Mammalia", "Eutheria",+            "Euarchontoglires", "Primates", "Haplorrhini", "Catarrhini",+            "Hominidae", "Homo"]++ohAns :: OH+ohAns = OH "9536" "Cercopithecus hamlyni (Owl-faced monkey) (Hamlyn's monkey)"++oxAns :: OX+oxAns = OX "NCBI_TaxID" "9606"++refAns :: [Reference]+refAns = [Reference 1 "NUCLEOTIDE SEQUENCE [GENOMIC DNA]" [] [(PubMed,"7851902"),(DOI,"10.1006/geno.1994.1562")] [] ["Shinohara T.","Taniwaki M.","Ishida Y.","Kawaich M.","Honjo T."] (Just "Structure and chromosomal localization of the human PD-1 gene (PDCD1).") "Genomics 23:704-706(1994)",+          Reference 2 "NUCLEOTIDE SEQUENCE [MRNA]" [] [(PubMed,"9332365"),(DOI,"10.1016/S0378-1119(97)00260-6")] [] ["Finger L.R.","Pu J.","Wasserman R.","Vibhakar R.","Louie E.","Hardy R.R.","Burrows P.D.","Billips L.D."] (Just "The human PD-1 gene: complete cDNA, genomic organization, and developmentally regulated expression in B cell progenitors.") "Gene 197:177-187(1997)",+          Reference 3 "ERRATUM" [] [] [] ["Finger L.R.","Pu J.","Wasserman R.","Vibhakar R.","Louie E.","Hardy R.R.","Burrows P.D.","Billips L.D."] Nothing "Gene 203:253-253(1997)",+          Reference 4 "NUCLEOTIDE SEQUENCE [GENOMIC DNA], AND INVOLVEMENT IN SLEB2" [] [(PubMed,"12402038"),(DOI,"10.1038/ng1020")] [] ["Prokunina L.","Castillejo-Lopez C.","Oberg F.","Gunnarsson I.","Berg L.","Magnusson V.","Brookes A.J.","Tentler D.","Kristjansdottir H.","Grondal G.","Bolstad A.I.","Svenungsson E.","Lundberg I.","Sturfelt G.","Jonssen A.","Truedsson L.","Lima G.","Alcocer-Varela J.","Jonsson R.","Gyllensten U.B.","Harley J.B.","Alarcon-Segovia D.","Steinsson K.","Alarcon-Riquelme M.E."] (Just "A regulatory polymorphism in PDCD1 is associated with susceptibility to systemic lupus erythematosus in humans.") "Nat. Genet. 32:666-669(2002)",+          Reference 5 "NUCLEOTIDE SEQUENCE [MRNA]" [] [] [] ["He X.","Xu L.","Liu Y.","Zeng Y."] (Just "Cloning of PD-1 cDNA from activated peripheral leukocytes.") "Submitted (FEB-2003) to the EMBL/GenBank/DDBJ databases",+          Reference 6 "NUCLEOTIDE SEQUENCE [GENOMIC DNA]" [] [] [] ["Livingston R.J.","Shaffer T.","McFarland I.","Nguyen C.P.","Stanaway I.B.","Rajkumar N.","Johnson E.J.","da Ponte S.H.","Willa H.","Ahearn M.O.","Bertucci C.","Acklestad J.","Carroll A.","Swanson J.","Gildersleeve H.I.","Nickerson D.A."] Nothing "Submitted (OCT-2006) to the EMBL/GenBank/DDBJ databases",+          Reference 7 "NUCLEOTIDE SEQUENCE [LARGE SCALE MRNA]" [] [(PubMed,"14702039"),(DOI,"10.1038/ng1285")] [] ["Ota T.","Suzuki Y.","Nishikawa T.","Otsuki T.","Sugiyama T.","Irie R.","Wakamatsu A.","Hayashi K.","Sato H.","Nagai K.","Kimura K.","Makita H.","Sekine M.","Obayashi M.","Nishi T.","Shibahara T.","Tanaka T.","Ishii S.","Yamamoto J.","Saito K.","Kawai Y.","Isono Y.","Nakamura Y.","Nagahari K.","Murakami K.","Yasuda T.","Iwayanagi T.","Wagatsuma M.","Shiratori A.","Sudo H.","Hosoiri T.","Kaku Y.","Kodaira H.","Kondo H.","Sugawara M.","Takahashi M.","Kanda K.","Yokoi T.","Furuya T.","Kikkawa E.","Omura Y.","Abe K.","Kamihara K.","Katsuta N.","Sato K.","Tanikawa M.","Yamazaki M.","Ninomiya K.","Ishibashi T.","Yamashita H.","Murakawa K.","Fujimori K.","Tanai H.","Kimata M.","Watanabe M.","Hiraoka S.","Chiba Y.","Ishida S.","Ono Y.","Takiguchi S.","Watanabe S.","Yosida M.","Hotuta T.","Kusano J.","Kanehori K.","Takahashi-Fujii A.","Hara H.","Tanase T.-O.","Nomura Y.","Togiya S.","Komai F.","Hara R.","Takeuchi K.","Arita M.","Imose N.","Musashino K.","Yuuki H.","Oshima A.","Sasaki N.","Aotsuka S.","Yoshikawa Y.","Matsunawa H.","Ichihara T.","Shiohata N.","Sano S.","Moriya S.","Momiyama H.","Satoh N.","Takami S.","Terashima Y.","Suzuki O.","Nakagawa S.","Senoh A.","Mizoguchi H.","Goto Y.","Shimizu F.","Wakebe H.","Hishigaki H.","Watanabe T.","Sugiyama A.","Takemoto M.","Kawakami B.","Yamazaki M.","Watanabe K.","Kumagai A.","Itakura S.","Fukuzumi Y.","Fujimori Y.","Komiyama M.","Tashiro H.","Tanigami A.","Fujiwara T.","Ono T.","Yamada K.","Fujii Y.","Ozaki K.","Hirao M.","Ohmori Y.","Kawabata A.","Hikiji T.","Kobatake N.","Inagaki H.","Ikema Y.","Okamoto S.","Okitani R.","Kawakami T.","Noguchi S.","Itoh T.","Shigeta K.","Senba T.","Matsumura K.","Nakajima Y.","Mizuno T.","Morinaga M.","Sasaki M.","Togashi T.","Oyama M.","Hata H.","Watanabe M.","Komatsu T.","Mizushima-Sugano J.","Satoh T.","Shirai Y.","Takahashi Y.","Nakagawa K.","Okumura K.","Nagase T.","Nomura N.","Kikuchi H.","Masuho Y.","Yamashita R.","Nakai K.","Yada T.","Nakamura Y.","Ohara O.","Isogai T.","Sugano S."] (Just "Complete sequencing and characterization of 21,243 full-length human cDNAs.") "Nat. Genet. 36:40-45(2004)",+          Reference 8 "NUCLEOTIDE SEQUENCE [LARGE SCALE MRNA]" [] [(PubMed,"15489334"),(DOI,"10.1101/gr.2596504")] ["The MGC Project Team;"] [] (Just "The status, quality, and expansion of the NIH full-length cDNA project: the Mammalian Gene Collection (MGC).") "Genome Res. 14:2121-2127(2004)",+          Reference 9 "NUCLEOTIDE SEQUENCE [LARGE SCALE GENOMIC DNA]" [] [] [] ["Mural R.J.","Istrail S.","Sutton G.","Florea L.","Halpern A.L.","Mobarry C.M.","Lippert R.","Walenz B.","Shatkay H.","Dew I.","Miller J.R.","Flanigan M.J.","Edwards N.J.","Bolanos R.","Fasulo D.","Halldorsson B.V.","Hannenhalli S.","Turner R.","Yooseph S.","Lu F.","Nusskern D.R.","Shue B.C.","Zheng X.H.","Zhong F.","Delcher A.L.","Huson D.H.","Kravitz S.A.","Mouchard L.","Reinert K.","Remington K.A.","Clark A.G.","Waterman M.S.","Eichler E.E.","Adams M.D.","Hunkapiller M.W.","Myers E.W.","Venter J.C."] Nothing "Submitted (JUL-2005) to the EMBL/GenBank/DDBJ databases",+          Reference 10 "FUNCTION" [] [(PubMed,"21276005"),(DOI,"10.1111/j.1749-6632.2010.05919.x")] [] ["Fife B.T.","Pauken K.E."] (Just "The role of the PD-1 pathway in autoimmunity and peripheral tolerance.") "Ann. N. Y. Acad. Sci. 1217:45-59(2011)"]++ccAns :: [CC]+ccAns = [CC "FUNCTION" "Inhibitory cell surface receptor involved in the regulation of T-cell function during immunity and tolerance. Upon ligand binding, inhibits T-cell effector functions in an antigen-specific manner. Possible cell death inducer, in association with other factors.",+         CC "SUBUNIT" "Monomer.",+         CC "INTERACTION" "Q9NZQ7:CD274; NbExp=2; IntAct=EBI-4314328, EBI-4314282; Q9NZQ7-1:CD274; NbExp=2; IntAct=EBI-4314328, EBI-15686469; Q06124:PTPN11; NbExp=3; IntAct=EBI-4314328, EBI-297779;",+         CC "SUBCELLULAR LOCATION" "Membrane; Single-pass type I membrane protein.",+         CC "DEVELOPMENTAL STAGE" "Induced at programmed cell death.",+         CC "DISEASE" "Systemic lupus erythematosus 2 (SLEB2) [MIM:605218]: A chronic, relapsing, inflammatory, and often febrile multisystemic disorder of connective tissue, characterized principally by involvement of the skin, joints, kidneys and serosal membranes. It is of unknown etiology, but is thought to represent a failure of the regulatory mechanisms of the autoimmune system. The disease is marked by a wide range of system dysfunctions, an elevated erythrocyte sedimentation rate, and the formation of LE cells in the blood or bone marrow."]++drAns :: [DR]+drAns = [DR "EMBL" "L27440" ["AAC41700.1","-","Genomic_DNA"],+         DR "EMBL" "U64863" ["AAC51773.1","-","mRNA"],+         DR "EMBL" "AF363458" ["AAN64003.1","-","Genomic_DNA"],+         DR "EMBL" "AY238517" ["AAO63583.1","-","mRNA"],+         DR "EMBL" "EF064716" ["ABK41899.1","-","Genomic_DNA"],+         DR "EMBL" "AK313848" ["BAG36577.1","-","mRNA"],+         DR "EMBL" "CH471063" ["EAW71298.1","-","Genomic_DNA"],+         DR "EMBL" "BC074740" ["AAH74740.1","-","mRNA"],+         DR "CCDS" "CCDS33428.1" ["-"],+         DR "PIR" "A55737" ["A55737"],+         DR "RefSeq" "NP_005009.2" ["NM_005018.2"],+         DR "UniGene" "Hs.158297" ["-"],+         DR "PDB" "2M2D" ["NMR","-","A=34-150"],+         DR "PDB" "3RRQ" ["X-ray","2.10 A","A=32-160"],+         DR "PDB" "4ZQK" ["X-ray","2.45 A","B=33-150"],+         DR "PDB" "5B8C" ["X-ray","2.15 A","C/F/I/L=32-160"],+         DR "PDB" "5GGR" ["X-ray","3.30 A","Y/Z=26-150"],+         DR "PDB" "5GGS" ["X-ray","2.00 A","Y/Z=26-148"],+         DR "PDB" "5IUS" ["X-ray","2.89 A","A/B=26-146"],+         DR "PDB" "5JXE" ["X-ray","2.90 A","A/B=33-146"],+         DR "PDB" "5WT9" ["X-ray","2.40 A","G=1-167"],+         DR "PDBsum" "2M2D" ["-"],+         DR "PDBsum" "3RRQ" ["-"],+         DR "PDBsum" "4ZQK" ["-"],+         DR "PDBsum" "5B8C" ["-"],+         DR "PDBsum" "5GGR" ["-"],+         DR "PDBsum" "5GGS" ["-"],+         DR "PDBsum" "5IUS" ["-"],+         DR "PDBsum" "5JXE" ["-"],+         DR "PDBsum" "5WT9" ["-"],+         DR "ProteinModelPortal" "Q15116" ["-"],+         DR "SMR" "Q15116" ["-"],+         DR "BioGrid" "111160" ["61"],+         DR "DIP" "DIP-44126N" ["-"],+         DR "IntAct" "Q15116" ["5"],+         DR "MINT" "Q15116" ["-"],+         DR "STRING" "9606.ENSP00000335062" ["-"],+         DR "ChEMBL" "CHEMBL3307223" ["-"],+         DR "DrugBank" "DB05916" ["CT-011"],+         DR "DrugBank" "DB09035" ["Nivolumab"],+         DR "DrugBank" "DB09037" ["Pembrolizumab"],+         DR "GuidetoPHARMACOLOGY" "2760" ["-"],+         DR "iPTMnet" "Q15116" ["-"],+         DR "PhosphoSitePlus" "Q15116" ["-"],+         DR "BioMuta" "PDCD1" ["-"],+         DR "DMDM" "145559515" ["-"],+         DR "PaxDb" "Q15116" ["-"],+         DR "PeptideAtlas" "Q15116" ["-"],+         DR "PRIDE" "Q15116" ["-"],+         DR "DNASU" "5133" ["-"],+         DR "Ensembl" "ENST00000334409" ["ENSP00000335062","ENSG00000188389"],+         DR "Ensembl" "ENST00000618185" ["ENSP00000480684","ENSG00000276977"],+         DR "GeneID" "5133" ["-"],+         DR "KEGG" "hsa:5133" ["-"],+         DR "UCSC" "uc002wcq.5" ["human"],+         DR "CTD" "5133" ["-"],+         DR "DisGeNET" "5133" ["-"],+         DR "EuPathDB" "HostDB:ENSG00000188389.10" ["-"],+         DR "GeneCards" "PDCD1" ["-"],+         DR "H-InvDB" "HIX0030684" ["-"],+         DR "HGNC" "HGNC:8760" ["PDCD1"],+         DR "HPA" "CAB038418" ["-"],+         DR "HPA" "HPA035981" ["-"],+         DR "MalaCards" "PDCD1" ["-"],+         DR "MIM" "109100" ["phenotype"],+         DR "MIM" "600244" ["gene"],+         DR "MIM" "605218" ["phenotype"],+         DR "neXtProt" "NX_Q15116" ["-"],+         DR "OpenTargets" "ENSG00000188389" ["-"],+         DR "Orphanet" "802" ["Multiple sclerosis"],+         DR "Orphanet" "536" ["Systemic lupus erythematosus"],+         DR "PharmGKB" "PA33110" ["-"],+         DR "eggNOG" "ENOG410J26W" ["Eukaryota"],+         DR "eggNOG" "ENOG41116U6" ["LUCA"],+         DR "GeneTree" "ENSGT00390000013662" ["-"],+         DR "HOGENOM" "HOG000253959" ["-"],+         DR "HOVERGEN" "HBG053534" ["-"],+         DR "InParanoid" "Q15116" ["-"],+         DR "KO" "K06744" ["-"],+         DR "OMA" "DFQWREK" ["-"],+         DR "OrthoDB" "EOG091G0EE8" ["-"],+         DR "PhylomeDB" "Q15116" ["-"],+         DR "TreeFam" "TF336181" ["-"],+         DR "Reactome" "R-HSA-389948" ["PD-1 signaling"],+         DR "SIGNOR" "Q15116" ["-"],+         DR "ChiTaRS" "PDCD1" ["human"],+         DR "GeneWiki" "Programmed_cell_death_1" ["-"],+         DR "GenomeRNAi" "5133" ["-"],+         DR "PRO" "PR:Q15116" ["-"],+         DR "Proteomes" "UP000005640" ["Chromosome 2"],+         DR "Bgee" "ENSG00000188389" ["-"],+         DR "CleanEx" "HS_PDCD1" ["-"],+         DR "ExpressionAtlas" "Q15116" ["baseline and differential"],+         DR "Genevisible" "Q15116" ["HS"],+         DR "GO" "GO:0009897" ["C:external side of plasma membrane","IEA:Ensembl"],+         DR "GO" "GO:0016021" ["C:integral component of membrane","IEA:UniProtKB-KW"],+         DR "GO" "GO:0005886" ["C:plasma membrane","TAS:Reactome"],+         DR "GO" "GO:0004871" ["F:signal transducer activity","TAS:ProtInc"],+         DR "GO" "GO:0006915" ["P:apoptotic process","TAS:ProtInc"],+         DR "GO" "GO:0006959" ["P:humoral immune response","TAS:ProtInc"],+         DR "GO" "GO:0007275" ["P:multicellular organism development","TAS:ProtInc"],+         DR "GO" "GO:0043066" ["P:negative regulation of apoptotic process","IEA:Ensembl"],+         DR "GO" "GO:0002644" ["P:negative regulation of tolerance induction","IEA:Ensembl"],+         DR "GO" "GO:0070234" ["P:positive regulation of T cell apoptotic process","IDA:UniProtKB"],+         DR "GO" "GO:0031295" ["P:T cell costimulation","TAS:Reactome"],+         DR "Gene3D" "2.60.40.10" ["-","1"],+         DR "InterPro" "IPR007110" ["Ig-like_dom"],+         DR "InterPro" "IPR036179" ["Ig-like_dom_sf"],+         DR "InterPro" "IPR013783" ["Ig-like_fold"],+         DR "InterPro" "IPR003599" ["Ig_sub"],+         DR "InterPro" "IPR013106" ["Ig_V-set"],+         DR "Pfam" "PF07686" ["V-set","1"],+         DR "SMART" "SM00409" ["IG","1"],+         DR "SMART" "SM00406" ["IGv","1"],+         DR "SUPFAM" "SSF48726" ["SSF48726","1"],+         DR "PROSITE" "PS50835" ["IG_LIKE","1"]]++peAns :: PE+peAns = EvidenceAtProteinLevel++kwAns :: KW+kwAns = KW ["3D-structure", "Apoptosis", "Complete proteome", "Disulfide bond",+            "Glycoprotein", "Immunity", "Immunoglobulin domain", "Membrane", "Polymorphism",+            "Reference proteome", "Signal", "Systemic lupus erythematosus",+            "Transmembrane", "Transmembrane helix"]++ftAns :: [FT]+ftAns = [FT "SIGNAL"   (ExactEP 1)   (ExactEP 20)  [],+         FT "CHAIN"    (ExactEP 21)  (ExactEP 288) ["Programmed cell death protein 1","/FTId=PRO_0000014892"],+         FT "TOPO_DOM" (ExactEP 21)  (ExactEP 170) ["Extracellular"],+         FT "TRANSMEM" (ExactEP 171) (ExactEP 191) ["Helical"],+         FT "TOPO_DOM" (ExactEP 192) (ExactEP 288) ["Cytoplasmic"],+         FT "DOMAIN"   (ExactEP 35)  (ExactEP 145) ["Ig-like V-type"],+         FT "CARBOHYD" (ExactEP 49)  (ExactEP 49)  ["N-linked (GlcNAc...) asparagine"],+         FT "CARBOHYD" (ExactEP 58)  (ExactEP 58)  ["N-linked (GlcNAc...) asparagine"],+         FT "CARBOHYD" (ExactEP 74)  (ExactEP 74)  ["N-linked (GlcNAc...) asparagine"],+         FT "CARBOHYD" (ExactEP 116) (ExactEP 116) ["N-linked (GlcNAc...) asparagine"],+         FT "DISULFID" (ExactEP 54)  (ExactEP 123) [],+         FT "VARIANT"  (ExactEP 215) (ExactEP 215) ["A -> V (in dbSNP:rs2227982)","/FTId=VAR_031685"],+         FT "CONFLICT" (ExactEP 38)  (ExactEP 38)  ["S -> F (in Ref. 2; AAC51773)"],+         FT "CONFLICT" (ExactEP 162) (ExactEP 162) ["P -> S (in Ref. 1; AAC41700)"],+         FT "STRAND"   (ExactEP 27)  (ExactEP 29)  [],+         FT "STRAND"   (ExactEP 36)  (ExactEP 38)  [],+         FT "STRAND"   (ExactEP 40)  (ExactEP 45)  [],+         FT "STRAND"   (ExactEP 50)  (ExactEP 55)  [],+         FT "STRAND"   (ExactEP 60)  (ExactEP 70)  [],+         FT "STRAND"   (ExactEP 72)  (ExactEP 74)  [],+         FT "STRAND"   (ExactEP 76)  (ExactEP 83)  [],+         FT "STRAND"   (ExactEP 95)  (ExactEP 99)  [],+         FT "STRAND"   (ExactEP 103) (ExactEP 112) [],+         FT "HELIX"    (ExactEP 115) (ExactEP 117) [],+         FT "STRAND"   (ExactEP 119) (ExactEP 131) [],+         FT "STRAND"   (ExactEP 134) (ExactEP 136) [],+         FT "STRAND"   (ExactEP 140) (ExactEP 145) []]++sqAns :: SQ+sqAns = SQ 288 31647 "A5210FD40C304FB7"+           "MQIPQAPWPVVWAVLQLGWRPGWFLDSPDRPWNPPTFSPALLVVTEGDNATFTCSFSNTSESFVLNWYRMSPSNQTDKLAAFPEDRSQPGQDCRFRVTQLPNGRDFHMSVVRARRNDSGTYLCGAISLAPKAQIKESLRAELRVTERRAEVPTAHPSPSPRPAGQFQTLVVGVVGGLLGSLVLLVWVLAVICSRAARGTIGARRTGQPLKEDPSAVPVFSVDYGELDFQWREKTPEPPVPCVPEQTEYATIVFPSGMGTSSPARRGSADGPRSAQPLRPEDGHCSWPL"++endAns :: ()+endAns = ()++uniprotSectionSpec :: Spec+uniprotSectionSpec = +  describe "Individual Uniprot sections parishioner" $ do+    it "parses ID lines" $+      parseOnly parseID idStr `shouldBe` Right idAns+    it "parses AC lines" $ +      parseOnly parseAC acStr `shouldBe` Right acAns+    it "parses DT lines" $+      parseOnly parseDT dtStr `shouldBe` Right dtAns+    it "parses DE lines" $ do+      parseOnly parseDE deStr `shouldBe` Right deAns+      parseOnly parseDE de2Str `shouldBe` Right de2Ans+    it "parses GN lines" $+      parseOnly parseGN gnStr `shouldBe` Right gnAns+    it "parses OS lines" $+      parseOnly parseOS osStr `shouldBe` Right osAns+    it "parses OG lines (non-PD1)" $+      parseOnly parseOG ogStr `shouldBe` Right ogAns+    it "parses OC lines" $+      parseOnly parseOC ocStr `shouldBe` Right ocAns+    it "parses OX lines (non-PD1)" $+      parseOnly parseOX oxStr `shouldBe` Right oxAns+    it "parses OH lines (non-PD1)" $+      parseOnly parseOH ohStr `shouldBe` Right ohAns+    it "parses REF lines" $ do+      let parseManyRef = (:) <$> parseRef <*> many' (endOfLine *> parseRef)+      parseOnly parseManyRef refStr `shouldBe` Right refAns+    it "parses CC lines" $ do+      let parseManyCC = (:) <$> parseCC <*> many' (endOfLine *> parseCC)+      parseOnly parseManyCC ccStr `shouldBe` Right ccAns+    it "parses DR lines" $ do+      let parseManyDR = (:) <$> parseDR <*> many' (endOfLine *> parseDR)+      parseOnly parseManyDR drStr `shouldBe` Right drAns+    it "parses PE lines" $+      parseOnly parsePE peStr `shouldBe` Right peAns+    it "parses KW lines" $+      parseOnly parseKW kwStr `shouldBe` Right kwAns+    it "parses FT lines" $ do+      let parseManyFT = (:) <$> parseFT <*> many' (endOfLine *> parseFT)+      parseOnly parseManyFT ftStr `shouldBe` Right ftAns+    it "parses SQ lines" $ do+      parseOnly parseSQ sqStr `shouldBe` Right sqAns+    it "parses End lines" $+      parseOnly parseEnd endStr `shouldBe` Right endAns++uniprotFullSpec :: Spec+uniprotFullSpec =+  describe "Full Uniprot record parser" $ do+    it "parses PD1 example" $ do+      let record = Record idAns acAns dtAns deAns+                          gnAns osAns [] ocAns+                          oxAns [] refAns ccAns+                          drAns peAns (Just kwAns) ftAns sqAns+      parseOnly parseRecord pd1Str `shouldBe` Right record