packages feed

manatee-imageviewer 0.0.8 → 0.1.0

raw patch · 8 files changed

+238/−82 lines, 8 filesdep +binarydep +derivedep −gtk-serialized-eventdep ~manatee-coresetup-changedbinary-added

Dependencies added: binary, derive

Dependencies removed: gtk-serialized-event

Dependency ranges changed: manatee-core

Files

Main.hs view
@@ -1,7 +1,7 @@ -- Author:     Andy Stewart <lazycat.manatee@gmail.com> -- Maintainer: Andy Stewart <lazycat.manatee@gmail.com> -- --- Copyright (C) 2010 Andy Stewart, all rights reserved.+-- Copyright (C) 2010 ~ 2011 Andy Stewart, all rights reserved. --  -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by
Manatee/Extension/ImageViewer.hs view
@@ -1,7 +1,7 @@ -- Author:     Andy Stewart <lazycat.manatee@gmail.com> -- Maintainer: Andy Stewart <lazycat.manatee@gmail.com> -- --- Copyright (C) 2010 Andy Stewart, all rights reserved.+-- Copyright (C) 2010 ~ 2011 Andy Stewart, all rights reserved. --  -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by
Manatee/Extension/ImageViewer/ImageBuffer.hs view
@@ -1,7 +1,7 @@ -- Author:     Andy Stewart <lazycat.manatee@gmail.com> -- Maintainer: Andy Stewart <lazycat.manatee@gmail.com> -- --- Copyright (C) 2010 Andy Stewart, all rights reserved.+-- Copyright (C) 2010 ~ 2011 Andy Stewart, all rights reserved. --  -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by@@ -18,15 +18,19 @@  {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TemplateHaskell #-} module Manatee.Extension.ImageViewer.ImageBuffer where  import Control.Applicative import Control.Concurrent import Control.Concurrent.STM  import DBus.Client hiding (Signal)+import Data.Binary import Data.ByteString.UTF8+import Data.DeriveTH import Data.List import Data.Typeable+import Manatee.Core.Config import Manatee.Core.DBus import Manatee.Core.Types import Manatee.Extension.ImageViewer.PageMode@@ -45,9 +49,29 @@                 ,imageBufferFiles               :: TVar [FilePath]                 ,imageBufferBroadcastChannel    :: TChan String                 ,imageBufferSlideShowHanlderId  :: TVar (Maybe HandlerId)+                ,imageBufferState               :: TVar ImageState                 }      deriving Typeable +data ImageState =+    ImageState {imageStateDirection             :: ImageDirection+               ,imageStateZoom                  :: Maybe Double+               ,imageStateScrolledPosition      :: (Double, Double)}++data ImageDirection = DirectionUp+                    | DirectionDown+                    | DirectionLeft+                    | DirectionRight++data RotateAction = RotateCounterclockwise+                  | RotateClockwise+                  | RotateMirror++-- | Init state.+imageInitState :: ImageState+imageInitState =+    ImageState DirectionUp Nothing (0, 0)+ -- | New image buffer. imageBufferNew :: String -> [String] -> Client -> PageId -> CustomizeWrap -> IO ImageBuffer imageBufferNew path _ client pageId _ = do@@ -59,6 +83,7 @@                         <*> newTVarIO []                         <*> (newTChanIO :: IO (TChan String))                         <*> newTVarIO Nothing+                        <*> newTVarIO imageInitState    -- Scan image files under current directory.   forkIO $ imageBufferScanFiles buffer@@ -122,3 +147,19 @@   -- Scan...   scan enum             +-- | Write state.+imageBufferWriteState :: ImageBuffer -> FilePath -> IO ()+imageBufferWriteState buffer path = do+  state <- readTVarIO $ imageBufferState buffer+  writeConfigPath path state++-- | Read state.+imageBufferReadState :: ImageBuffer -> FilePath -> IO ()  +imageBufferReadState buffer path = do+  state <- readConfigPath path imageInitState+  writeTVarIO (imageBufferState buffer) state+  +$(derive makeBinary ''ImageDirection)+$(derive makeBinary ''RotateAction)+$(derive makeBinary ''ImageState)+
Manatee/Extension/ImageViewer/ImageView.hs view
@@ -1,7 +1,7 @@ -- Author:     Andy Stewart <lazycat.manatee@gmail.com> -- Maintainer: Andy Stewart <lazycat.manatee@gmail.com> -- --- Copyright (C) 2010 Andy Stewart, all rights reserved.+-- Copyright (C) 2010 ~ 2011 Andy Stewart, all rights reserved. --  -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by@@ -23,25 +23,25 @@ import Control.Applicative import Control.Concurrent.STM  import Control.Monad+import Data.ByteString.UTF8 hiding (length) import Data.List import Data.Map (Map)-import Data.ByteString.UTF8 hiding (length) import Data.Text.Lazy (Text) import Data.Typeable import Graphics.UI.Gtk hiding (Statusbar, statusbarNew, get)-import Graphics.UI.Gtk.Gdk.SerializedEvent+import Manatee.Core.Config import Manatee.Core.PageFrame import Manatee.Core.PageView import Manatee.Core.Types import Manatee.Extension.ImageViewer.ImageBuffer import Manatee.Toolkit.GConf.GConf+import Manatee.Toolkit.General.List import Manatee.Toolkit.General.Maybe import Manatee.Toolkit.General.Misc-import Manatee.Toolkit.General.List import Manatee.Toolkit.General.STM-import Manatee.Toolkit.Gtk.Concurrent-import Manatee.Toolkit.Gtk.Gtk import Manatee.Toolkit.Gio.Gio+import Manatee.Toolkit.Gtk.Concurrent+import Manatee.Toolkit.Gtk.ScrolledWindow import Paths_manatee_imageviewer import System.FilePath @@ -53,6 +53,7 @@               ,imageViewFrame           :: PageFrame               ,imageViewView            :: I.ImageView               ,imageViewBuffer          :: ImageBuffer+              ,imageViewDirection       :: TVar ImageDirection               ,imageViewBroadcastChannel:: ViewChannel String}     deriving Typeable @@ -65,12 +66,17 @@   pageBufferPackageName _       = fmap takeFileName getDataDir  instance PageView ImageView where-    pageViewBuffer              = PageBufferWrap . imageViewBuffer-    pageViewPlugId              = imageViewPlugId-    pageViewBox                 = pageFrameBox . imageViewFrame-    pageViewScrolledWindow      = imageViewScrolledWindow-    pageViewFocus               = widgetGrabFocus . imageViewView-    pageViewHandleKeyAction     = imageViewHandleKeyAction+    pageViewBuffer               = PageBufferWrap . imageViewBuffer+    pageViewPlugId               = imageViewPlugId+    pageViewFrame                = imageViewFrame+    pageViewLocalKeymap _        = imageViewLocalKeymap+    pageViewLocalCommandMap _    = imageViewLocalCommandMap+    pageViewFocus                = widgetGrabFocus . imageViewView+    pageViewPropagateWidget      = castToWidget . imageViewView+    pageViewSaveState view       = imageViewSaveState view Nothing+    pageViewRestoreState view    = imageViewRestoreState view Nothing+    pageViewWriteState view path = imageViewSaveState view (Just path)+    pageViewReadState view path  = imageViewRestoreState view (Just path)  -- | The intervals of slide show (ms). imageViewSlideShowInterval :: Int@@ -89,31 +95,36 @@   view <- I.imageViewNew   pageFrameAddChild pFrame view +  -- Init direction.+  direction <- newTVarIO DirectionUp+   -- Duplicate broadcast channel.   channel <- createViewChannel (imageBufferBroadcastChannel buffer) view    -- Build image view.-  let imageView = ImageView pId pFrame view buffer channel+  let imageView = ImageView pId pFrame view buffer direction channel    -- Listen broadcast channel.   imageViewListenChannel imageView -  -- Draw.-  imageViewDraw imageView-   -- Update zoom status.   view `on` I.zoomChanged $ imageViewUpdateZoomStatus imageView    return imageView  -- | Draw image view.-imageViewDraw :: ImageView -> IO ()-imageViewDraw view = do-  -- TODO: Need find a way free old pixbuf in GtkImageView after use new pixbuf.-  -- Otherwise cause memory leak. +imageViewDraw :: ImageView -> ImageDirection -> IO ()+imageViewDraw view direction = do   path <- readTVarIO $ imageBufferPath $ imageViewBuffer view-  pixbuf <- pixbufNewFromFile (filepathGetDisplayName (fromString path))-  I.imageViewSetPixbuf (imageViewView view) (Just pixbuf) True+  oldPixbuf <- pixbufNewFromFile (filepathGetDisplayName (fromString path))+  newPixbuf <- +      case direction of+        DirectionUp     -> return oldPixbuf+        DirectionRight  -> pixbufRotateSimple oldPixbuf PixbufRotateClockwise+        DirectionLeft   -> pixbufRotateSimple oldPixbuf PixbufRotateCounterclockwise+        DirectionDown   -> pixbufRotateSimple oldPixbuf PixbufRotateUpsidedown+  writeTVarIO (imageViewDirection view) direction+  I.imageViewSetPixbuf (imageViewView view) (Just newPixbuf) True  -- | Browse. imageViewBrowse :: ImageView -> FilePath -> IO ()@@ -128,14 +139,7 @@ imageViewListenChannel :: ImageView -> IO () imageViewListenChannel view =    listenViewChannel (imageViewBroadcastChannel view) $ \_ ->-      imageViewDraw view---- | Handle key action.-imageViewHandleKeyAction :: ImageView -> Text -> SerializedEvent -> IO ()  -imageViewHandleKeyAction view keystoke sEvent = -  case M.lookup keystoke imageViewKeymap of-    Just action -> action view-    Nothing -> widgetPropagateEvent (imageViewView view) sEvent+      imageViewDraw view DirectionUp  -- | Zoom out image. imageViewZoomOut :: ImageView -> IO ()@@ -178,13 +182,45 @@   files <- readTVarIO $ imageBufferFiles $ imageViewBuffer view   getLast files ?>= \ file -> imageViewBrowse view file +-- | Update direction.+imageViewUpdateDirection :: ImageView -> RotateAction -> IO ()  +imageViewUpdateDirection ImageView {imageViewDirection = directionTVar}+                         action = do+  -- Get old direction.+  direction <- readTVarIO directionTVar+  +  -- Get new direction.+  let newDirection = +          case action of+            RotateCounterclockwise ->+                case direction of+                  DirectionUp    -> DirectionLeft+                  DirectionRight -> DirectionUp+                  DirectionDown  -> DirectionRight+                  DirectionLeft  -> DirectionDown+            RotateClockwise ->+                case direction of+                  DirectionUp    -> DirectionRight+                  DirectionRight -> DirectionDown+                  DirectionDown  -> DirectionLeft+                  DirectionLeft  -> DirectionUp+            RotateMirror ->+                case direction of+                  DirectionUp    -> DirectionDown+                  DirectionRight -> DirectionLeft+                  DirectionDown  -> DirectionUp+                  DirectionLeft  -> DirectionRight++  -- Update direction.+  writeTVarIO directionTVar newDirection+ -- | Rotate clockwise imageViewRotateClockwise :: ImageView -> IO () imageViewRotateClockwise view = do   oldPixbuf <- I.imageViewGetPixbuf $ imageViewView view   newPixbuf <- pixbufRotateSimple oldPixbuf PixbufRotateClockwise   I.imageViewSetPixbuf (imageViewView view) (Just newPixbuf) True-+  imageViewUpdateDirection view RotateClockwise    -- | Rotate counterclockwise. imageViewRotateCounterclockwise :: ImageView -> IO ()@@ -192,6 +228,7 @@   oldPixbuf <- I.imageViewGetPixbuf $ imageViewView view   newPixbuf <- pixbufRotateSimple oldPixbuf PixbufRotateCounterclockwise   I.imageViewSetPixbuf (imageViewView view) (Just newPixbuf) True+  imageViewUpdateDirection view RotateCounterclockwise    -- | Rotate mirror. imageViewRotateMirror :: ImageView -> IO ()@@ -199,12 +236,13 @@   oldPixbuf <- I.imageViewGetPixbuf $ imageViewView view   newPixbuf <- pixbufRotateSimple oldPixbuf PixbufRotateUpsidedown   I.imageViewSetPixbuf (imageViewView view) (Just newPixbuf) True+  imageViewUpdateDirection view RotateMirror  -- | Update zoom status. imageViewUpdateZoomStatus :: ImageView -> IO () imageViewUpdateZoomStatus view = do   zoom <- liftM (\x -> floor $ formatFloatN x 2 * 100) $ I.imageViewGetZoom $ imageViewView view-  pageFrameUpdateStatusbar (imageViewFrame view) "Zoom" (" Zoom (" ++ show zoom ++ "%)")+  pageViewUpdateStatusbar view "Zoom" (" Zoom (" ++ show zoom ++ "%)")  -- | Find next image file under current directory. imageViewGetNextFile :: FilePath -> [FilePath] -> Maybe FilePath@@ -242,12 +280,12 @@   case sId of     -- Stop slide show.     Just id -> do-      pageFrameUpdateStatusbar (imageViewFrame view) "SlideShow" " SlideShow (off)"+      pageViewUpdateStatusbar view "SlideShow" " SlideShow (off)"       timeoutRemove id       writeTVarIO slideShowId Nothing     -- Start slide show.     Nothing -> do-      pageFrameUpdateStatusbar (imageViewFrame view) "SlideShow" " SlideShow (on)"+      pageViewUpdateStatusbar view "SlideShow" " SlideShow (on)"       handlerId <- timeoutAdd (imageViewBrowseNext view >> return True) imageViewSlideShowInterval       writeTVarIO slideShowId (Just handlerId) @@ -259,44 +297,109 @@   path <- readTVarIO bufferPath   setDesktopBackground path 100 Zoom +-- | Keymap.+imageViewLocalKeymap :: Map Text Text+imageViewLocalKeymap = +    M.fromList [("j",           "Scroll step up")+               ,("k",           "Scroll step down")+               ,("Down",        "Scroll step up")+               ,("Up",          "Scroll step down")+               ,("h",           "Scroll step right")+               ,("l",           "Scroll step left")+               ,("Right",       "Scroll step right")+               ,("Left",        "Scroll step left")+               ,(" ",           "Scroll page up")+               ,("b",           "Scroll page down")+               ,("PageDown",    "Scroll page up")+               ,("PageUp",      "Scroll page down")+               ,("J",           "Scroll to bottom")+               ,("K",           "Scroll to top")+               ,("End",         "Scroll to bottom")+               ,("Home",        "Scroll to top")+               ,(",",           "Zoom out")+               ,(".",           "Zoom in")+               ,("-",           "Zoom out")+               ,("=",           "Zoom in")+               ,("m",           "Fit size")+               ,("n",           "Browse next")+               ,("Return",      "Browse previous")+               ,("p",           "Browse previous")+               ,("N",           "Browse last")+               ,("P",           "Browse first")+               ,("<",           "Rotate counterclockwise")+               ,(">",           "Rotate clockwise")+               ,("/",           "Rotate mirror")+               ,("s",           "Slide show")+               ,("B",           "Set as background")+               ]++-- | Keymap.+imageViewLocalCommandMap :: Map Text (ImageView -> IO ())+imageViewLocalCommandMap = +    M.fromList [("Scroll step up",              pageViewScrollStepUp)+               ,("Scroll step down",            pageViewScrollStepDown)+               ,("Scroll step right",           pageViewScrollStepRight)+               ,("Scroll step left",            pageViewScrollStepLeft)+               ,("Scroll page up",              pageViewScrollPageUp)+               ,("Scroll page down",            pageViewScrollPageDown)+               ,("Scroll to bottom",            pageViewScrollToBottom)+               ,("Scroll to top",               pageViewScrollToTop)+               ,("Zoom out",                    imageViewZoomOut)+               ,("Zoom in",                     imageViewZoomIn)+               ,("Fit size",                    imageViewFit)+               ,("Browse next",                 imageViewBrowseNext)+               ,("Browse previous",             imageViewBrowsePrev)+               ,("Browse last",                 imageViewBrowseLast)+               ,("Browse first",                imageViewBrowseFirst)+               ,("Rotate counterclockwise",     imageViewRotateCounterclockwise)+               ,("Rotate clockwise",            imageViewRotateClockwise)+               ,("Rotate mirror",               imageViewRotateMirror)+               ,("Slide show",                  imageViewSlideShow)+               ,("Set as background",           imageViewSetAsBackground)+               ]+ -- | Scrolled window.-imageViewScrolledWindow :: ImageView -> ScrolledWindow  +imageViewScrolledWindow :: ImageView -> ScrolledWindow imageViewScrolledWindow =   pageFrameScrolledWindow . imageViewFrame --- | Keymap.-imageViewKeymap :: Map Text (ImageView -> IO ())-imageViewKeymap = -    M.fromList [("j",           pageViewScrollStepUp)-               ,("k",           pageViewScrollStepDown)-               ,("Down",        pageViewScrollStepUp)-               ,("Up",          pageViewScrollStepDown)-               ,("h",           pageViewScrollStepRight)-               ,("l",           pageViewScrollStepLeft)-               ,("Right",       pageViewScrollStepRight)-               ,("Left",        pageViewScrollStepLeft)-               ,(" ",           pageViewScrollPageUp)-               ,("b",           pageViewScrollPageDown)-               ,("PageDown",    pageViewScrollPageUp)-               ,("PageUp",      pageViewScrollPageDown)-               ,("J",           pageViewScrollToBottom)-               ,("K",           pageViewScrollToTop)-               ,("End",         pageViewScrollToBottom)-               ,("Home",        pageViewScrollToTop)-               ,(",",           imageViewZoomOut)-               ,(".",           imageViewZoomIn)-               ,("-",           imageViewZoomOut)-               ,("=",           imageViewZoomIn)-               ,("m",           imageViewFit)-               ,("n",           imageViewBrowseNext)-               ,("Return",      imageViewBrowseNext)-               ,("p",           imageViewBrowsePrev)-               ,("N",           imageViewBrowseLast)-               ,("P",           imageViewBrowseFirst)-               ,("<",           imageViewRotateCounterclockwise)-               ,(">",           imageViewRotateClockwise)-               ,("/",           imageViewRotateMirror)-               ,("s",           imageViewSlideShow)-               ,("B",           imageViewSetAsBackground)-               ]+-- | Save state.+imageViewSaveState :: ImageView -> Maybe FilePath -> IO ()+imageViewSaveState view@(ImageView {imageViewBuffer     = buffer+                                   ,imageViewView       = imageView+                                   ,imageViewDirection  = directionTVar}) +                   statePath = do+  -- Get direction.+  direction <- readTVarIO directionTVar +  -- Get zoom level.+  zoom <- I.imageViewGetZoom imageView++  -- Get scroll position.+  scrolledWindowPosition <- scrolledWindowGetValue (imageViewScrolledWindow view)++  -- Save state.+  let state = ImageState direction (Just zoom) scrolledWindowPosition+  case statePath of+    Nothing   -> writeTVarIO (imageBufferState buffer) state+    Just path -> writeConfigPath path state++-- | Restore state.+imageViewRestoreState :: ImageView -> Maybe FilePath -> IO ()+imageViewRestoreState view@(ImageView {imageViewBuffer  = buffer+                                      ,imageViewView    = imageView})+                      statePath = do+  bufferState <- readTVarIO (imageBufferState buffer)+  (ImageState direction zoom scrolledWindowPosition) <- +      case statePath of+        Just path -> readConfigPath path bufferState+        Nothing   -> return bufferState++  -- Restore direction.+  imageViewDraw view direction++  -- Restore zoom level.+  zoom ?>= (I.imageViewSetZoom imageView)++  -- Restore scroll position.+  scrolledWindowSetValue (imageViewScrolledWindow view) scrolledWindowPosition
Manatee/Extension/ImageViewer/PageMode.hs view
@@ -1,7 +1,7 @@ -- Author:     Andy Stewart <lazycat.manatee@gmail.com> -- Maintainer: Andy Stewart <lazycat.manatee@gmail.com> -- --- Copyright (C) 2010 Andy Stewart, all rights reserved.+-- Copyright (C) 2010 ~ 2011 Andy Stewart, all rights reserved. --  -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by
Setup.hs view
@@ -1,7 +1,7 @@ -- Author:     Andy Stewart <lazycat.manatee@gmail.com> -- Maintainer: Andy Stewart <lazycat.manatee@gmail.com> -- --- Copyright (C) 2010 Andy Stewart, all rights reserved.+-- Copyright (C) 2010 ~ 2011 Andy Stewart, all rights reserved. --  -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by@@ -19,6 +19,7 @@ import Distribution.Simple import Manatee.Core.Config import Manatee.Core.Types+import Manatee.Toolkit.Cabal.Utils import Manatee.Toolkit.General.List import Manatee.Toolkit.General.Map import Manatee.Extension.ImageViewer.PageMode@@ -28,7 +29,7 @@ main = defaultMainWithHooks         simpleUserHooks {          -- Update PageTypeRule after install successful.-         postInst = \ _ _ _ _ -> do+         postInst = \ _ _ pack_des lbi -> do              (PageTypeRule rule) <- readConfig pageTypeRulePath (PageTypeRule M.empty)              writeConfig pageTypeRulePath (PageTypeRule (M.insert "PageImage" "manatee-imageviewer" rule))              -- Update FileOpenRule.@@ -45,4 +46,12 @@              (PageModeRule modeRule) <- readConfig pageModeRulePath (PageModeRule M.empty)              writeConfig pageModeRulePath (PageModeRule                                                  (M.insert "PageImage" (Left $ pageModeName imageMode) modeRule))+             -- Update Application info.+             let snapshotPath = getDataFilePath pack_des lbi "data/welcome/snapshot.png"+             (WelcomeApplication apps) <- readConfig welcomeApplicationPath (WelcomeApplication M.empty)+             writeConfig welcomeApplicationPath (WelcomeApplication +                                                 (M.insert +                                                   ("Image Viewer", snapshotPath)+                                                   ("PageImage", snapshotPath, [])+                                                   apps))        }
+ data/welcome/snapshot.png view

binary file changed (absent → 1394575 bytes)

manatee-imageviewer.cabal view
@@ -1,13 +1,13 @@ name:			manatee-imageviewer-version:		0.0.8+version:		0.1.0 Cabal-Version:	>= 1.6 license:		GPL-3 license-file:	LICENSE-copyright:		(c) 2009 ~ 2010 Andy Stewart+copyright:		(c) 2010 ~ 2011 Andy Stewart synopsis:		Image viewer extension for Manatee. description:    manatee-imageviewer is image viewer extension for Manatee (Haskell/Gtk+ Integrated Live Environment)  .- Video at (Select 720p HD) at : <http://www.youtube.com/watch?v=weS6zys3U8k> <http://www.youtube.com/watch?v=A3DgKDVkyeM> <http://v.youku.com/v_show/id_XMjI2MDMzODI4.html>+ Video (Select 720p HD) at : <http://www.youtube.com/watch?v=weS6zys3U8k> <http://www.youtube.com/watch?v=A3DgKDVkyeM> <http://v.youku.com/v_show/id_XMjI2MDMzODI4.html>  .  Screenshots at : <http://goo.gl/MkVw>  .@@ -22,16 +22,19 @@ stability:		provisional category:		Manatee, Image Viewer, Image -tested-with:	GHC==6.12.3+tested-with:	GHC==7.0.2 build-type:		Custom +data-dir: ""+data-files: data/welcome/snapshot.png+ Source-Repository head   type:         darcs   location:     http://patch-tag.com/r/AndyStewart/manatee-imageviewer    Library-     build-depends: base >= 4 && < 5, manatee-core >= 0.0.8, dbus-client >= 0.3 && < 0.4, stm >= 2.1.2.0,-                    containers >= 0.3.0.0, gtk-serialized-event >= 0.12.0, gtk >= 0.12.0, glib >= 0.12.0,+     build-depends: base >= 4 && < 5, manatee-core >= 0.1.0, dbus-client >= 0.3 && < 0.4, stm >= 2.1.2.0,+                    containers >= 0.3.0.0, gtk >= 0.12.0, glib >= 0.12.0, derive, binary,                     gio >= 0.12.0, gtkimageview >= 0.12.0, text >= 0.7.1.0,                      regex-tdfa >= 1.1.2, filepath >= 1.1.0.3, utf8-string      exposed-modules: