diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,3 +1,7 @@
+0.0.2
+
+* Fix modules in cabal file.
+
 0.0.1
 
 * Initial version.
diff --git a/foscam-sort.cabal b/foscam-sort.cabal
--- a/foscam-sort.cabal
+++ b/foscam-sort.cabal
@@ -1,5 +1,5 @@
 name:               foscam-sort
-version:            0.0.1
+version:            0.0.2
 license:            BSD3
 license-file:       LICENSE
 author:             Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ> <dibblego>
@@ -23,6 +23,32 @@
 flag                small_base
   description:      Choose the new, split-up base package.
 
+library
+  default-language:
+                    Haskell2010
+
+  build-depends:
+                        base             >= 4     && < 5
+                    , lens             >= 4.0   && < 5
+                    , digit            >= 0.1.2 && < 0.2
+                    , filepath, directory, unix
+                    , foscam-filename  == 0.0.4
+                    , foscam-directory == 0.0.7
+
+  ghc-options:
+                    -Wall
+
+  default-extensions:
+                    NoImplicitPrelude
+
+  hs-source-dirs:
+                    src
+
+  exposed-modules:
+                    Data.Foscam.Sort
+                    Data.Foscam.Sort.FilenamePath
+
+
 executable foscam-sort
   main-is:
                     Main.hs
@@ -36,7 +62,7 @@
                     , digit            >= 0.1.2 && < 0.2
                     , filepath, directory, unix
                     , foscam-filename  == 0.0.4
-                    , foscam-directory == 0.0.6
+                    , foscam-directory == 0.0.7
 
   ghc-options:
                     -Wall
diff --git a/src/Data/Foscam/Sort.hs b/src/Data/Foscam/Sort.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Foscam/Sort.hs
@@ -0,0 +1,82 @@
+module Data.Foscam.Sort(
+  foscamsort
+) where
+
+import Control.Category(id, (.))
+import Control.Lens((^.), (^?), _2)
+import Control.Monad((>>=), when, unless)
+import Data.Bool(Bool(True))
+import Data.Either(either)
+import Data.Foldable(Foldable, mapM_)
+import Data.Foscam.Directory(getFoscamDirectoryContents, FoscamDirectoryFile, _FoscamDirectory, _FoscamFilename, _Is)
+import Data.Foscam.File(getFilename)
+import Data.Foscam.Sort.FilenamePath(FilenamePath, yyyy, mm, dd, hh, nn, deviceIdpath, aliaspath, (/<>/), (~/>))
+import Data.Maybe(maybe)
+import Data.Monoid((<>))
+import System.Directory(doesFileExist, getPermissions, readable, renameFile, doesFileExist, createDirectoryIfMissing)
+import System.Environment(getArgs, getProgName)
+import System.FilePath(FilePath, (</>))
+import System.IO(IO, hPutStrLn, stderr)
+import System.Posix.Files(createSymbolicLink)
+
+foscamsort ::
+  IO ()
+foscamsort = 
+  do a <- getArgs
+     case a of
+       (i:o:_) ->
+         getFoscamDirectoryContents i >>=
+         mapM_ (move o (yyyy <> mm <> dd)
+          [
+            yyyy <> mm
+          , yyyy <> mm <> dd
+          , yyyy <> mm <> dd <> hh
+          , yyyy <> mm <> dd <> hh <> mm
+          , yyyy /<>/ mm /<>/ dd
+          , yyyy /<>/ mm /<>/ dd /<>/ hh
+          , yyyy /<>/ mm /<>/ dd /<>/ hh /<>/ nn
+          , deviceIdpath /<>/ yyyy /<>/ mm /<>/ dd
+          , deviceIdpath /<>/ yyyy /<>/ mm /<>/ dd /<>/ hh
+          , aliaspath /<>/ yyyy /<>/ mm /<>/ dd
+          , aliaspath /<>/ yyyy /<>/ mm /<>/ dd /<>/ hh
+          ]) 
+       _ ->
+         do p <- getProgName
+            hPutStrLn stderr ("Usage: " <> p <> " <foscam-files-directory> <sort-output-directory>")
+
+move ::
+  Foldable t =>
+  FilePath
+  -> FilenamePath
+  -> t FilenamePath
+  -> FoscamDirectoryFile
+  -> IO ()
+move base mvpath lnpaths q =
+  let fname = q ^? _Is . _2
+      name = either id getFilename (q ^. _FoscamFilename)
+      mv = base </> "move" </> maybe "unknown" (\n -> "date" </> mvpath ~/> n) fname
+      mvto = mv </> name
+  in do createDirectoryIfMissing True mv
+        moveFile (q ^. _FoscamDirectory </> name) mvto
+        mapM_ (\n -> mapM_
+                (\k -> 
+                  let out = base </> "link" </> k ~/> n
+                  in do createDirectoryIfMissing True out
+                        createSymbolicLinkIfMissing mvto (out </> name)) lnpaths) fname
+     
+moveFile ::
+  FilePath
+  -> FilePath
+  -> IO ()
+moveFile f t =
+  do e <- doesFileExist f
+     when e (do p <- getPermissions f
+                when (readable p) (renameFile f t))
+
+createSymbolicLinkIfMissing ::
+  FilePath
+  -> FilePath
+  -> IO ()
+createSymbolicLinkIfMissing file1 file2 =
+        do s <- doesFileExist file2
+           unless s (createSymbolicLink file1 file2)
diff --git a/src/Data/Foscam/Sort/FilenamePath.hs b/src/Data/Foscam/Sort/FilenamePath.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Foscam/Sort/FilenamePath.hs
@@ -0,0 +1,81 @@
+module Data.Foscam.Sort.FilenamePath(
+  FilenamePath(FilenamePath, (~/>))
+, (/<>/)
+, deviceIdpath
+, aliaspath
+, yyyy
+, mm
+, dd
+, hh
+, nn
+, ss
+) where
+
+import Data.Monoid
+import Data.Digit(digitC)
+import Data.Foscam.File(Filename(Filename), Date(Date), Time(Time), AsAlias(_Alias), AsDeviceId(_DeviceId))
+import Data.Functor((<$>))
+import Data.List((++))
+import Control.Lens(( # ))
+import System.FilePath(FilePath, (</>))
+
+-- move to own module
+newtype FilenamePath =
+  FilenamePath { 
+    (~/>) ::
+      Filename
+      -> FilePath
+  }
+
+instance Monoid FilenamePath where
+  mempty =
+    FilenamePath (\_ -> "")
+  FilenamePath x `mappend` FilenamePath y =
+    FilenamePath (\n -> x n ++ y n)
+
+(/<>/) ::
+  FilenamePath
+  -> FilenamePath
+  -> FilenamePath
+FilenamePath a /<>/ FilenamePath b =
+  FilenamePath (\n -> a n </> b n)
+
+deviceIdpath ::
+  FilenamePath
+deviceIdpath =
+  FilenamePath (\(Filename i _ _ _ _ _) -> _DeviceId # i)
+
+aliaspath ::
+  FilenamePath
+aliaspath =
+  FilenamePath (\(Filename _ a _ _ _ _) -> _Alias # a)
+
+yyyy ::
+  FilenamePath
+yyyy =
+  FilenamePath (\(Filename _ _ _ (Date y1 y2 y3 y4 _ _ _ _) _ _) -> (digitC #) <$> [y1, y2, y3, y4])
+
+mm ::
+  FilenamePath
+mm =
+  FilenamePath (\(Filename _ _ _ (Date _ _ _ _ m1 m2 _ _) _ _) -> (digitC #) <$> [m1, m2])
+
+dd ::
+  FilenamePath
+dd =
+  FilenamePath (\(Filename _ _ _ (Date _ _ _ _ _ _ d1 d2) _ _) -> (digitC #) <$> [d1, d2])
+
+hh ::
+  FilenamePath
+hh =
+  FilenamePath (\(Filename _ _ _ _ (Time h1 h2 _ _ _ _) _) -> (digitC #) <$> [h1, h2])
+
+nn ::
+  FilenamePath
+nn =
+  FilenamePath (\(Filename _ _ _ _ (Time _ _ n1 n2 _ _) _) -> (digitC #) <$> [n1, n2])
+
+ss ::
+  FilenamePath
+ss =
+  FilenamePath (\(Filename _ _ _ _ (Time _ _ _ _ s1 s2) _) -> (digitC #) <$> [s1, s2])
