diff --git a/changelog.markdown b/changelog.markdown
--- a/changelog.markdown
+++ b/changelog.markdown
@@ -1,3 +1,14 @@
+2009.4.50
+----------
+
+### Feature
+
+* xml helper, io helper
+
+### fix
+
+* unescape unicode parser use (try)
+
 2009.4.21
 ---------
 
diff --git a/mps.cabal b/mps.cabal
--- a/mps.cabal
+++ b/mps.cabal
@@ -1,5 +1,5 @@
 Name:                 mps
-Version:              2009.4.21
+Version:              2009.4.50
 Build-type:           Simple
 Synopsis:             message passing style helpers
 Description:          message passing style helpers
@@ -15,7 +15,7 @@
 
 library
   ghc-options: -Wall -fno-warn-missing-signatures -fno-warn-name-shadowing -fno-warn-orphans -fno-warn-type-defaults
-  build-depends: base, containers, array, parallel, fgl, QuickCheck, time, bytestring >= 0.9, pandoc, regexpr >= 0.3.4, parsec >= 2, utf8-string >= 0.3.3, directory, interpolatedstring-qq
+  build-depends: base, containers, array, parallel, fgl, QuickCheck, time, bytestring >= 0.9, pandoc, regexpr >= 0.3.4, parsec >= 2, utf8-string >= 0.3.3, directory, interpolatedstring-qq, base64-string, zlib, old-locale, unix, filepath, template
   hs-source-dirs: src/
   exposed-modules:  MPS, MPSUTF8
   other-modules:    MPS.UTF8, MPS.Snippets, MPS.Hack.Dot
diff --git a/src/MPS/Snippets.hs b/src/MPS/Snippets.hs
--- a/src/MPS/Snippets.hs
+++ b/src/MPS/Snippets.hs
@@ -1,36 +1,58 @@
 module MPS.Snippets where
 
+import MPS.Hack.Dot
+import Prelude hiding ((.), sum, product, maximum, minimum, 
+  foldl, foldr, foldl1, foldr1, concat, concatMap, and, or, any, all, elem, (^))
+import qualified Prelude as Prelude
+
 import Control.Arrow ((&&&), (>>>))
 import Control.Monad hiding (join)
 import Control.Parallel
+
 import Data.Char
 import Data.Maybe
-import Data.Time.Calendar
-import Numeric
-import MPS.Hack.Dot
-import Test.QuickCheck
-import Text.RegexPR
+import Data.Graph.Inductive (Gr, mkGraph)
+import Data.Foldable
+import Data.Time.Clock.POSIX
+import Data.Time
+import Data.List (transpose, sort, group, (\\), sortBy)
+
 import qualified Data.Array as A
 import qualified Data.List as L
 import qualified Data.Set as S
 import qualified Data.Graph as G
 import qualified Data.Map as M
-import Data.Graph.Inductive (Gr, mkGraph)
+import qualified Data.ByteString.Lazy.Char8 as B
+
+import System.Locale
+import System.Posix.Files
+import System.IO
+import System.Directory
 import qualified System.IO.Unsafe as Unsafe
-import qualified Text.ParserCombinators.Parsec as P
-import Data.Foldable
-import Debug.Trace
+
+
+import Test.QuickCheck
+import Text.RegexPR
 import Text.Pandoc
+import Text.Template
+import Text.InterpolatedString.QQ
+import Text.ParserCombinators.Parsec (many, char, many1, digit, (<|>), Parser, anyChar, try)
+import qualified Text.ParserCombinators.Parsec as P
+
+import Codec.Binary.Base64.String as C
 import qualified Codec.Binary.UTF8.String as Codec
-import System.Directory
-import Text.ParserCombinators.Parsec (many, char, many1, digit, (<|>), Parser, anyChar)
-import qualified Prelude as Prelude
+import qualified Codec.Compression.GZip as GZip
 
-import Prelude hiding ((.), sum, product, maximum, minimum, 
-  foldl, foldr, foldl1, foldr1, concat, concatMap, and, or, any, all, elem, (^))
-import Data.List (transpose, sort, group, (\\), sortBy)
-import Text.InterpolatedString.QQ
+import Debug.Trace
+import Numeric
 
+
+
+
+
+
+
+
 -- List
 join x xs              = L.intercalate x xs
 join' xs               = xs.concat
@@ -137,10 +159,6 @@
 -- Map
 to_h xs = xs.M.fromList
 
-
-
-
-
 -- QuickCheck
 quick_check prop = quickCheck prop
 qc prop          = quick_check prop
@@ -378,16 +396,57 @@
   return $ chr (read word)
 
 unescape_parser :: Parser String
-unescape_parser = many (unicode_char <|> anyChar)
+unescape_parser = many (try unicode_char <|> anyChar)
 
 unescape_unicode_xml s = parse unescape_parser s
 
+escape_unicode_xml :: String -> String
+escape_unicode_xml = concatMap fixChar
+    where
+      fixChar '<' = "<"
+      fixChar '>' = ">"
+      fixChar '&' = "&"
+      fixChar '"' = "\""
+      fixChar c | ord c < 0x80 = [c]
+      fixChar c = "&#" ++ show (ord c) ++ ";"
+
+
 -- IO
 ls s = getDirectoryContents s <.> (\\ [".", ".."])
 
+file_size :: String -> IO Integer
+file_size path = withFile (path.u2b) ReadMode hFileSize
+
+file_mtime :: String -> IO UTCTime
+file_mtime path = getFileStatus (path.u2b) 
+                  ^ modificationTime ^ realToFrac ^ posixSecondsToUTCTime
+
+read_binary_file :: String -> IO String
+read_binary_file path = path.u2b.B.readFile ^ B.unpack
+
+get_permissions :: String -> IO Permissions
+get_permissions path = getPermissions (path.u2b) 
+
+get_current_directory :: IO String
+get_current_directory = getCurrentDirectory ^ b2u
+
 -- Text
 filter_comment = lines >>> map strip >>> reject null >>> reject (head >>> (== '#')) >>> unlines
 
+interpolate :: String -> [(String, String)] -> String
+interpolate s params = B.unpack $ substitute (B.pack s) (context params)
+  where 
+    context = map packPair >>> to_h
+    packPair (x, y) = (B.pack x, B.pack y)
+    
+-- Time
+now :: IO UTCTime
+now = getCurrentTime
+
+format_time :: String -> UTCTime -> String
+format_time = formatTime defaultTimeLocale
+
+
 -- UTF8
 b2u = Codec.decodeString
 u2b = Codec.encodeString
@@ -395,3 +454,9 @@
 -- QQ
 
 here = istr
+
+-- compress
+
+zip64, unzip64 :: String -> String
+zip64 = B.pack >>> GZip.compress >>> B.unpack >>> C.encode
+unzip64 = C.decode >>> B.pack >>> GZip.decompress >>> B.unpack
