diff --git a/library/Rattletrap/Header.hs b/library/Rattletrap/Header.hs
--- a/library/Rattletrap/Header.hs
+++ b/library/Rattletrap/Header.hs
@@ -1,7 +1,9 @@
 module Rattletrap.Header where
 
 import Rattletrap.Dictionary
+import Rattletrap.Int32
 import Rattletrap.Property
+import Rattletrap.PropertyValue
 import Rattletrap.Text
 import Rattletrap.Word32
 
@@ -34,3 +36,33 @@
   putWord32 (headerLicenseeVersion header)
   putText (headerLabel header)
   putDictionary putProperty (headerProperties header)
+
+getVersion
+  :: (Integral a, Integral b)
+  => Header -> (a, b)
+getVersion header =
+  let major = getMajorVersion header
+      minor = getMinorVersion header
+  in (major, minor)
+
+getMajorVersion
+  :: (Integral a)
+  => Header -> a
+getMajorVersion header = fromIntegral (word32Value (headerEngineVersion header))
+
+getMinorVersion
+  :: (Integral a)
+  => Header -> a
+getMinorVersion header =
+  fromIntegral (word32Value (headerLicenseeVersion header))
+
+getNumFrames
+  :: (Integral a)
+  => Header -> a
+getNumFrames header =
+  let key = stringToText "NumFrames"
+      properties = dictionaryValue (headerProperties header)
+  in case lookup key properties of
+       Just (Just (Property _ _ (IntProperty numFrames))) ->
+         fromIntegral (int32Value numFrames)
+       _ -> 0
diff --git a/library/Rattletrap/Replay.hs b/library/Rattletrap/Replay.hs
--- a/library/Rattletrap/Replay.hs
+++ b/library/Rattletrap/Replay.hs
@@ -2,12 +2,7 @@
 
 import Rattletrap.Content
 import Rattletrap.Crc
-import Rattletrap.Dictionary
 import Rattletrap.Header
-import Rattletrap.Int32
-import Rattletrap.Property
-import Rattletrap.PropertyValue
-import Rattletrap.Text
 import Rattletrap.Word32
 
 import qualified Data.Binary as Binary
@@ -26,16 +21,8 @@
   header <- getHeader
   _contentSize <- getWord32
   _contentCrc <- getWord32
-  let majorVersion = fromIntegral (word32Value (headerEngineVersion header))
-  let minorVersion = fromIntegral (word32Value (headerLicenseeVersion header))
-  let version = (majorVersion, minorVersion)
-  let numFrames =
-        case lookup
-               (stringToText "NumFrames")
-               (dictionaryValue (headerProperties header)) of
-          Just (Just (Property _ _ (IntProperty int32))) ->
-            fromIntegral (int32Value int32)
-          _ -> 0
+  let version = getVersion header
+  let numFrames = getNumFrames header
   content <- getContent version numFrames
   pure Replay {replayHeader = header, replayContent = content}
 
diff --git a/rattletrap.cabal b/rattletrap.cabal
--- a/rattletrap.cabal
+++ b/rattletrap.cabal
@@ -1,153 +1,162 @@
-name: rattletrap
-version: 0.1.4
-cabal-version: >=1.10
-build-type: Simple
-license: MIT
-license-file: LICENSE.markdown
-maintainer: Taylor Fausak
-homepage: https://github.com/tfausak/rattletrap#readme
-bug-reports: https://github.com/tfausak/rattletrap/issues
-synopsis: Parse and generate Rocket League replays.
-description:
-    Rattletrap parses and generates Rocket League replays.
-category: Game
+-- This file has been generated from package.yaml by hpack version 0.14.0.
+--
+-- see: https://github.com/sol/hpack
+
+name:           rattletrap
+version:        0.1.5
+synopsis:       Parse and generate Rocket League replays.
+description:    Rattletrap parses and generates Rocket League replays.
+category:       Game
+homepage:       https://github.com/tfausak/rattletrap#readme
+bug-reports:    https://github.com/tfausak/rattletrap/issues
+maintainer:     Taylor Fausak
+license:        MIT
+license-file:   LICENSE.markdown
+build-type:     Simple
+cabal-version:  >= 1.10
+
 extra-source-files:
     HLint.hs
     README.markdown
 
 source-repository head
-    type: git
-    location: https://github.com/tfausak/rattletrap
+  type: git
+  location: https://github.com/tfausak/rattletrap
 
 library
-    exposed-modules:
-        Rattletrap
-        Rattletrap.ActorMap
-        Rattletrap.Attribute
-        Rattletrap.AttributeMapping
-        Rattletrap.AttributeValue
-        Rattletrap.AttributeValue.Boolean
-        Rattletrap.AttributeValue.Byte
-        Rattletrap.AttributeValue.CamSettings
-        Rattletrap.AttributeValue.Demolish
-        Rattletrap.AttributeValue.Enum
-        Rattletrap.AttributeValue.Explosion
-        Rattletrap.AttributeValue.FlaggedInt
-        Rattletrap.AttributeValue.Float
-        Rattletrap.AttributeValue.GameMode
-        Rattletrap.AttributeValue.Int
-        Rattletrap.AttributeValue.Loadout
-        Rattletrap.AttributeValue.LoadoutOnline
-        Rattletrap.AttributeValue.Loadouts
-        Rattletrap.AttributeValue.LoadoutsOnline
-        Rattletrap.AttributeValue.Location
-        Rattletrap.AttributeValue.MusicStinger
-        Rattletrap.AttributeValue.PartyLeader
-        Rattletrap.AttributeValue.Pickup
-        Rattletrap.AttributeValue.PrivateMatchSettings
-        Rattletrap.AttributeValue.QWord
-        Rattletrap.AttributeValue.Reservation
-        Rattletrap.AttributeValue.RigidBodyState
-        Rattletrap.AttributeValue.String
-        Rattletrap.AttributeValue.TeamPaint
-        Rattletrap.AttributeValue.UniqueId
-        Rattletrap.AttributeValue.WeldedInfo
-        Rattletrap.AttributeValueType
-        Rattletrap.Cache
-        Rattletrap.ClassAttributeMap
-        Rattletrap.ClassMapping
-        Rattletrap.CompressedWord
-        Rattletrap.CompressedWordVector
-        Rattletrap.Content
-        Rattletrap.Crc
-        Rattletrap.Data
-        Rattletrap.Dictionary
-        Rattletrap.Float32
-        Rattletrap.Frame
-        Rattletrap.Header
-        Rattletrap.Initialization
-        Rattletrap.Int32
-        Rattletrap.Int8
-        Rattletrap.Int8Vector
-        Rattletrap.KeyFrame
-        Rattletrap.List
-        Rattletrap.Mark
-        Rattletrap.Message
-        Rattletrap.Property
-        Rattletrap.PropertyValue
-        Rattletrap.RemoteId
-        Rattletrap.Replay
-        Rattletrap.Replication
-        Rattletrap.ReplicationValue
-        Rattletrap.ReplicationValue.Destroyed
-        Rattletrap.ReplicationValue.Spawned
-        Rattletrap.ReplicationValue.Updated
-        Rattletrap.Text
-        Rattletrap.Utility
-        Rattletrap.Vector
-        Rattletrap.Version
-        Rattletrap.Word32
-        Rattletrap.Word64
-        Rattletrap.Word8
-    build-depends:
-        base >=4.9.0.0 && <4.10,
-        bimap >=0.3.2 && <0.4,
-        binary >=0.8.3.0 && <0.9,
-        binary-bits ==0.5.*,
-        bytestring >=0.10.8.1 && <0.11,
-        containers >=0.5.7.1 && <0.6,
-        data-binary-ieee754 >=0.4.4 && <0.5,
-        regex-compat >=0.95.1 && <0.96,
-        text >=1.2.2.1 && <1.3,
-        vector >=0.11.0.0 && <0.12
-    default-language: Haskell2010
-    default-extensions: Strict
-    hs-source-dirs: library
-    other-modules:
-        Paths_rattletrap
-    ghc-options: -Wall
+  hs-source-dirs:
+      library
+  default-extensions: Strict
+  ghc-options: -Wall
+  build-depends:
+      base >=4.9 && <4.10
+    , bimap >=0.3 && <0.4
+    , binary >=0.8 && <0.9
+    , binary-bits >=0.5 && <0.6
+    , bytestring >=0.10 && <0.11
+    , containers >=0.5 && <0.6
+    , data-binary-ieee754 >=0.4 && <0.5
+    , regex-compat >=0.95 && <0.96
+    , text >=1.2 && <1.3
+    , vector >=0.11 && <0.12
+  exposed-modules:
+      Rattletrap
+      Rattletrap.ActorMap
+      Rattletrap.Attribute
+      Rattletrap.AttributeMapping
+      Rattletrap.AttributeValue
+      Rattletrap.AttributeValue.Boolean
+      Rattletrap.AttributeValue.Byte
+      Rattletrap.AttributeValue.CamSettings
+      Rattletrap.AttributeValue.Demolish
+      Rattletrap.AttributeValue.Enum
+      Rattletrap.AttributeValue.Explosion
+      Rattletrap.AttributeValue.FlaggedInt
+      Rattletrap.AttributeValue.Float
+      Rattletrap.AttributeValue.GameMode
+      Rattletrap.AttributeValue.Int
+      Rattletrap.AttributeValue.Loadout
+      Rattletrap.AttributeValue.LoadoutOnline
+      Rattletrap.AttributeValue.Loadouts
+      Rattletrap.AttributeValue.LoadoutsOnline
+      Rattletrap.AttributeValue.Location
+      Rattletrap.AttributeValue.MusicStinger
+      Rattletrap.AttributeValue.PartyLeader
+      Rattletrap.AttributeValue.Pickup
+      Rattletrap.AttributeValue.PrivateMatchSettings
+      Rattletrap.AttributeValue.QWord
+      Rattletrap.AttributeValue.Reservation
+      Rattletrap.AttributeValue.RigidBodyState
+      Rattletrap.AttributeValue.String
+      Rattletrap.AttributeValue.TeamPaint
+      Rattletrap.AttributeValue.UniqueId
+      Rattletrap.AttributeValue.WeldedInfo
+      Rattletrap.AttributeValueType
+      Rattletrap.Cache
+      Rattletrap.ClassAttributeMap
+      Rattletrap.ClassMapping
+      Rattletrap.CompressedWord
+      Rattletrap.CompressedWordVector
+      Rattletrap.Content
+      Rattletrap.Crc
+      Rattletrap.Data
+      Rattletrap.Dictionary
+      Rattletrap.Float32
+      Rattletrap.Frame
+      Rattletrap.Header
+      Rattletrap.Initialization
+      Rattletrap.Int32
+      Rattletrap.Int8
+      Rattletrap.Int8Vector
+      Rattletrap.KeyFrame
+      Rattletrap.List
+      Rattletrap.Mark
+      Rattletrap.Message
+      Rattletrap.Property
+      Rattletrap.PropertyValue
+      Rattletrap.RemoteId
+      Rattletrap.Replay
+      Rattletrap.Replication
+      Rattletrap.ReplicationValue
+      Rattletrap.ReplicationValue.Destroyed
+      Rattletrap.ReplicationValue.Spawned
+      Rattletrap.ReplicationValue.Updated
+      Rattletrap.Text
+      Rattletrap.Utility
+      Rattletrap.Vector
+      Rattletrap.Version
+      Rattletrap.Word32
+      Rattletrap.Word64
+      Rattletrap.Word8
+  other-modules:
+      Paths_rattletrap
+  default-language: Haskell2010
 
 executable rattletrap
-    main-is: Main.hs
-    build-depends:
-        aeson >=0.11.2.1 && <0.12,
-        aeson-casing >=0.1.0.5 && <0.2,
-        base >=4.9.0.0 && <4.10,
-        binary >=0.8.3.0 && <0.9,
-        bytestring >=0.10.8.1 && <0.11,
-        rattletrap >=0.1.4 && <0.2,
-        template-haskell >=2.11.0.0 && <2.12
-    default-language: Haskell2010
-    default-extensions: Strict
-    hs-source-dirs: executable
-    ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N
+  main-is: Main.hs
+  hs-source-dirs:
+      executable
+  default-extensions: Strict
+  ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N
+  build-depends:
+      aeson >=0.11 && <1.1
+    , aeson-casing >=0.1 && <0.2
+    , base
+    , binary
+    , bytestring
+    , rattletrap
+    , template-haskell >=2.11 && <2.12
+  default-language: Haskell2010
 
 test-suite lint
-    type: exitcode-stdio-1.0
-    main-is: Lint.hs
-    build-depends:
-        base >=4.9.0.0 && <4.10,
-        hlint >=1.9.35 && <1.10
-    default-language: Haskell2010
-    default-extensions: Strict
-    hs-source-dirs: test
-    other-modules:
-        Test
-    ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N
+  type: exitcode-stdio-1.0
+  main-is: Lint.hs
+  hs-source-dirs:
+      test
+  default-extensions: Strict
+  ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N
+  build-depends:
+      base
+    , hlint >=1.9 && <1.10
+  other-modules:
+      Test
+  default-language: Haskell2010
+
 test-suite test
-    type: exitcode-stdio-1.0
-    main-is: Test.hs
-    build-depends:
-        base >=4.9.0.0 && <4.10,
-        binary >=0.8.3.0 && <0.9,
-        bytestring >=0.10.8.1 && <0.11,
-        filepath >=1.4.1.0 && <1.5,
-        rattletrap >=0.1.4 && <0.2,
-        tasty >=0.11.0.4 && <0.12,
-        tasty-hspec >=1.1.3 && <1.2
-    default-language: Haskell2010
-    default-extensions: Strict
-    hs-source-dirs: test
-    other-modules:
-        Lint
-    ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N
+  type: exitcode-stdio-1.0
+  main-is: Test.hs
+  hs-source-dirs:
+      test
+  default-extensions: Strict
+  ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N
+  build-depends:
+      base
+    , binary
+    , bytestring
+    , filepath >=1.4 && <1.5
+    , rattletrap
+    , tasty >=0.11 && <0.12
+    , tasty-hspec >=1.1 && <1.2
+  other-modules:
+      Lint
+  default-language: Haskell2010
