diff --git a/Channel.hs b/Channel.hs
--- a/Channel.hs
+++ b/Channel.hs
@@ -35,26 +35,6 @@
     chan <- Ch.newChan
     return $ Channel (Ch.writeChan chan) (Ch.readChan chan) []
     
-{-newInternalChan :: String -> String -> Integer -> IO Channel
-newInternalChan hostName hostPort cp = do
-    currentHost <- getHostName
-    let ex = makeExtra ["host","clientPort"] [currentHost ++ ":" ++ hostPort,show cp]
-    return $ Channel s r True ex
-    where
-       r   = N.withSocketsDo $ do
-            sock <- N.listenOn $ N.PortNumber $ fromIntegral cp
-            (inHandle,_,_) <- N.accept sock
-            msg <- unlines <$> emptyHandle inHandle
-            putStrLn $ "got: " ++ msg
-            N.sClose sock
-            return msg
-       s v = N.withSocketsDo $ do
-            _ <- forkIO $ do
-                outHandle <- waitForConnect hostName $ N.PortNumber $ port hostPort
-                putStrLn $ "sending: " ++ v
-                hPutStr outHandle v
-            return ()-}
-
 newChanServer :: Integer -> IO Channel
 newChanServer cp = N.withSocketsDo $ do
     hanVar <- newEmptyMVar
@@ -72,9 +52,8 @@
     _ <- forkIO $ do
         serverHandle <- waitForConnect hostName $ N.PortNumber $ fromIntegral hostPort
         putMVar hanVar serverHandle
+    let ex = makeExtra [hostSig, portSig] [hostName,  show hostPort]
     return $ Channel (send' hanVar) (receive' hanVar) ex
-    where
-       ex = makeExtra [hostSig, portSig] [hostName,  show hostPort]
 
 waitForConnect :: N.HostName -> N.PortID -> IO Handle
 waitForConnect h p = N.connectTo h p `catchIOError`
diff --git a/Parser.hs b/Parser.hs
--- a/Parser.hs
+++ b/Parser.hs
@@ -200,11 +200,11 @@
 parseType :: Parser Type
 parseType =  try (str HttpRequest)
          <|> try (str HttpResponse)
-         <|> try (str Header)
-         <|> parseListType
+         -- <|> try (str Header)
+         -- <|> parseListType
          where
          str t = string (show t) >> return t
-         parseListType = string "List" >> many1 space >> fmap List parseType 
+         --parseListType = string "List" >> many1 space >> fmap List parseType 
         
 
 bracketed :: Parser a -> Parser a
@@ -222,6 +222,4 @@
 readProcesses = readOrThrow parseProcesses "multiple-processes"
 
 readTerm :: String -> ThrowsError Term 
-readTerm str = case parse parseTerm "term" str of
-                Left  err -> throwError $ Parser err
-                Right val -> return val 
+readTerm = readOrThrow parseTerm "term"
diff --git a/PatternMatching.hs b/PatternMatching.hs
--- a/PatternMatching.hs
+++ b/PatternMatching.hs
@@ -1,4 +1,4 @@
-module PatternMatching (match, matchTest) where            
+module PatternMatching (match) where            
             
 import Control.Arrow (second) 
 import Control.Monad (liftM,liftM2)
@@ -7,18 +7,19 @@
 import Parser (readTerm)
 import Network.HTTP.Base 
 
-match :: Term -> Term -> ThrowsError [(String,Value)]
+match :: Term -> Term -> ThrowsError [(Name,Value)]
 match a b = liftM (map (second Term)) $ match' a b
 
-match' :: Term -> Term -> ThrowsError [(String,Term)]
+match' :: Term -> Term -> ThrowsError [(Name,Term)]
 match' (TVar name _) term = case name of
                                 '_':_ -> return []
                                 _     -> return [(name,term)]
 match' (TPair (m1, m2)) (TPair (t1,t2)) = liftM2 (++) (match' m1 t1)  (match' m2 t2)
 match' (TList (m:ms)) (TList (t:ts)) = do
                 bind <- match' m t
-                rest <- case ms of
-                    [v] -> match' v $ TList ts
+                rest   <- case (ms,ts) of
+                    ([v],[t']) -> match' v t'
+                    ([v], _ ) -> match' v $ TList ts
                     _   -> match' (TList ms) (TList ts)
                 return $ bind ++ rest
 match' l@(TList _) (TData d) = match' l $ dataToList d
diff --git a/PiCalculus.hs b/PiCalculus.hs
--- a/PiCalculus.hs
+++ b/PiCalculus.hs
@@ -7,7 +7,6 @@
 import Control.Monad.Trans (liftIO)
 import Control.Monad.Trans.Except (catchE, runExceptT, throwE)
 import Data.IORef (newIORef, readIORef,writeIORef)
-import Data.Maybe (isJust)
 import Network.HTTP.Base (Request(..),Response(..), parseResponseHead, parseRequestHead)
 import System.Environment (getArgs, getProgName)
 import System.IO (hFlush, stderr, stdin, stdout)
@@ -25,32 +24,16 @@
 nullEnv :: IO Env
 nullEnv = newIORef Map.empty
 
-isBound :: Env -> String -> IO Bool
-isBound envRef var = liftM (isJust . Map.lookup var) $ readIORef envRef
-
 getVar :: Env -> String -> IOThrowsError Value 
 getVar envRef var = do env <- liftIO $ readIORef envRef
                        maybe (throwE $ UnboundVar "Getting an unbound variable" var)
                              return
                              (Map.lookup var env)
-
-setVar :: Env -> String -> Value -> IOThrowsError Value
-setVar _ "_" _ = return $ Term $ TVar "_" Nothing -- to allow wildcard matching
-setVar envRef var val = do env <- liftIO $ readIORef envRef
-                           maybe (throwE $ UnboundVar "Setting an unbound variable" var)
-                                 (return $ liftIO $ writeIORef envRef $ Map.insert var val env)
-                                 (Map.lookup var env)
-                           return val
                            
-defineVar :: Env -> String -> Value -> IOThrowsError Value
-defineVar envRef var val = do
-    alreadyDefined <- liftIO $ isBound envRef var
-    if alreadyDefined
-        then setVar envRef var val >> return val
-        else liftIO $ do
-            env      <- readIORef envRef
-            writeIORef envRef $ Map.insert var val env
-            return val
+defineVar :: Env -> String -> Value -> IOThrowsError ()
+defineVar envRef var val = liftIO $ do
+         env      <- readIORef envRef
+         writeIORef envRef $ Map.insert var val env
 
 bindVars :: Env -> [(String , Value)] -> IO Env
 bindVars envRef bindings = do
@@ -85,7 +68,7 @@
         pilude <- getDataFileName "pilude.pi"
         case args of
             []  -> runRepl coreBindings
-            [x] -> liftM (("&load("++pilude++");")++) (readFile x) >>= runProcess coreBindings 
+            [x] -> readFile x >>= runProcess coreBindings 
             _   -> do
                     putStrLn           "Use:"
                     putStrLn $ name ++ " -- Enter the REPL"
@@ -103,10 +86,11 @@
 
 evalTerm :: Env -> Term -> IOThrowsError Value
 evalTerm env (TVar name _) = getVar env name
-evalTerm _   (TNum num) = return $ Term $ TNum num
-evalTerm _   (TStr str) = return $ Term $ TStr str
-evalTerm _   (TBool b ) = return $ Term $ TBool b
-evalTerm _   (TData d ) = return $ Term $ TData d
+evalTerm _   t@(TNum  _ ) = return $ Term t
+evalTerm _   t@(TStr  _ ) = return $ Term t
+evalTerm _   t@(TBool _ ) = return $ Term t
+evalTerm _   t@(TBS   _ ) = return $ Term t
+evalTerm _   t@(TData _ ) = return $ Term t
 evalTerm env   (TList ls) = do
     vs <- mapM (evalTerm env) ls
     ts <- extractTerms vs
@@ -163,7 +147,7 @@
 assignFreePort :: Env -> IOThrowsError Integer
 assignFreePort env = do
             Term (TNum port) <- getVar env counterRef
-            _ <- setVar env counterRef $ Term $ TNum $ port + 1
+            defineVar env counterRef $ Term $ TNum $ port + 1
             if port == 2 ^ (16 :: Integer)
                 then error "HOW MANY CHANNELS DO YOU WANT?!" 
                 else return port
@@ -240,7 +224,7 @@
 eval env (p1 `Seq` p2) = do
                 eval env p1
                 eval env p2
-eval env (New var@(TVar name _)) = void $ defineVar env name $ Term var
+eval env (New var@(TVar name _)) = defineVar env name $ Term var
 eval env (If b p1 p2) = do
                 cond <- evalCond env b
                 eval env (if cond then p1 else p2)
@@ -250,14 +234,11 @@
                 eval newEnv p
 eval env (Let (TVar name _) (Term t2) Nothing) = do
                 val <- evalTerm env t2
-                _ <- defineVar env name val
-                return ()
+                defineVar env name val
 eval env (Let (TVar name _) proc@(Proc _) (Just p)) = do
                 newEnv <- liftIO $ bindVars env [(name,proc)]
                 eval newEnv p
-eval env (Let (TVar name _) proc@(Proc _) Nothing) = do
-                _ <- defineVar env name proc
-                return ()
+eval env (Let (TVar name _) proc@(Proc _) Nothing) = defineVar env name proc
 eval env (Let (TFun name args) t2 (Just p)) = 
             defineLocalFun env name args t2 p
 eval env (Let (TFun name args) t2 Nothing)  = 
@@ -293,7 +274,7 @@
 eval _ _ = throwE $ Default "undefined action"
 
 defineGlobalFun :: Env -> String -> [Term] -> Value -> IOThrowsError ()
-defineGlobalFun env name args term = void $ defineVar env name $ makeFun args term env
+defineGlobalFun env name args term = defineVar env name $ makeFun args term env
 
 defineLocalFun :: Env -> String -> [Term] -> Value -> PiProcess -> IOThrowsError ()
 defineLocalFun env name args term p = do
diff --git a/Primitives.hs b/Primitives.hs
--- a/Primitives.hs
+++ b/Primitives.hs
@@ -2,6 +2,9 @@
 
 import Control.Applicative ((<$>))
 import Control.Monad.Error (throwError)
+import qualified Crypto.Hash as Crypto
+import Data.Byteable (toBytes)
+import qualified Data.ByteString.Char8 as C8
 import Network.HTTP.Base (Request(..), Response(..), RequestMethod(..), mkRequest)
 import Network.HTTP.Cookie (Cookie, cookiesToHeader)
 import Network.HTTP.Headers (HasHeaders(..), Header, HeaderName(..), hdrName, hdrValue, findHeader, parseHeader, replaceHeader, setHeaders)
@@ -9,41 +12,43 @@
 
 import TypDefs
 
-primitives :: [(String      , TermFun)]
-primitives = [ ("fst"       , first)
-             , ("snd"       , secnd)
-             , ("hash"      , unaryId "hash")
-             , ("pk"        , unaryId "pk")
-             , ("httpReq"   , httpReq)
-             , ("httpResp"  , httpResp)
-             , ("getmsg"    , getmsg)
-             , ("pair"      , binaryId "pair")
-             , ("sdec"      , sdec)
-             , ("senc"      , binaryId "senc")
-             , ("adec"      , adec)
-             , ("aenc"      , binaryId "aenc")
-             , ("sign"      , binaryId "sign")
-             , ("checksign" , checksign)
-             , ("mac"       , binaryId "mac")
-             , ("headers"   , listId)
-             , ("header"    , header)
-             , ("cookies"   , listId)
-             , ("httpGet"   , constId "httpGet")
-             , ("httpHead"  , constId "httpHead")
-             , ("httpPost"  , constId "httpPost")
-             , ("getHeaders", getHeadersFromData)
-             , ("setHeader" , setHeader)
-             , ("getHeader" , getHeader)
-             , ("getCookie" , getCookie)
-             , ("setCookie" , setCookie)
-             , ("uri"       , makeUri)
-             , ("rspCode"   , responseCode)
-             , ("add"       , add)
-             , ("cons"      , cons)
-             , ("head"      , head')
-             , ("tail"      , tail')
+primitives :: [(Name          , TermFun)]
+primitives = [ ("fst"         , first)
+             , ("snd"         , secnd)
+             , ("hash"        , hash)
+             , ("pk"          , unaryId "pk")
+             , ("httpReq"     , httpReq)
+             , ("httpResp"    , httpResp)
+             , ("getmsg"      , getmsg)
+             , ("sdec"        , sdec)
+             , ("senc"        , binaryId "senc")
+             , ("adec"        , adec)
+             , ("aenc"        , binaryId "aenc")
+             , ("sign"        , binaryId "sign")
+             , ("checksign"   , checksign)
+             , ("mac"         , mac)
+             , ("headers"     , listId)
+             , ("header"      , header)
+             , ("cookies"     , listId)
+             , ("httpGet"     , constId "httpGet")
+             , ("httpHead"    , constId "httpHead")
+             , ("httpPost"    , constId "httpPost")
+             , ("getHeaders"  , getHeadersFromData)
+             , ("insertHeader", insertHeader)
+             , ("getHeader"   , getHeader)
+             , ("getCookie"   , getCookie)
+             , ("setCookie"   , setCookie)
+             , ("uri"         , makeUri)
+             , ("rspCode"     , responseCode)
+             , ("add"         , add)
+             , ("cons"        , cons)
+             , ("head"        , head')
+             , ("tail"        , tail')
+             , ("append"      , append)
              ]
 
+
+
 constId :: String -> TermFun
 constId name [] = return $ TFun name []
 constId name e  = throwError $ NumArgs name 0 (map Term e)
@@ -87,6 +92,7 @@
 checksign [TFun "pk" [k1], TFun "sign" [k2,_] ] = return $ TBool (k1 == k2)
 checksign e = throwError $ TypeMismatch "(pk(var),sign(var,var))" $ map Term e
 
+
 httpReq :: TermFun
 httpReq [TStr url, TList hs , reqMethod] = do
     uri <- case parseURI http' of 
@@ -149,14 +155,14 @@
             _       -> throwError $ Default $ headr ++ " not in " ++ show d
 getHeader e = throwError $ TypeMismatch "httpData" $ map Term e
 
-setHeader :: TermFun
-setHeader [h@(TStr _), TData d] = do 
+insertHeader :: TermFun
+insertHeader [h@(TStr _), TData d] = do 
                       headr <- makeHeader h
                       let name = hdrName headr
                       let val  = hdrValue headr
                       return $ TData $ replaceHeader name val d 
-setHeader [h@(TStr _), TList hs] = return $ TList $ h : hs  
-setHeader e = throwError $ TypeMismatch "(header,httpData|headers)" $ map Term e
+insertHeader [h@(TStr _), TList hs] = return $ TList $ h : hs  
+insertHeader e = throwError $ TypeMismatch "(header,httpData|headers)" $ map Term e
 
 getCookie :: TermFun
 getCookie [TData d] = 
@@ -166,7 +172,7 @@
 getCookie e = throwError $ TypeMismatch "httpData" $ map Term e
     
 setCookie :: TermFun
-setCookie [TData d, c] = do
+setCookie [c, TData d] = do
     cookie <- makeCookie c
     let cookieHeader = cookiesToHeader [cookie]
     let n = hdrName cookieHeader
@@ -204,3 +210,17 @@
 tail' [TList []] = throwError $ Default "tail of empty list" 
 tail' [TList x] = return $ TList $ tail x
 tail' e = throwError $ TypeMismatch "list" $ map Term e
+
+hash :: TermFun
+hash [TBS msg]  = return $ TBS $ toBytes (Crypto.hash msg :: Crypto.Digest Crypto.MD5)
+hash [TStr msg] = let mBS = C8.pack msg in return $ TBS $ toBytes (Crypto.hash mBS :: Crypto.Digest Crypto.MD5)
+hash e = throwError $ TypeMismatch "bytestring" $ map Term e
+        
+mac :: TermFun
+mac [TBS key,TBS msg]  = return $ TBS $ toBytes $ Crypto.hmacGetDigest $ Crypto.hmacAlg Crypto.MD5 key msg
+mac [TBS key,TStr msg] = let mBS = C8.pack msg in return $ TBS $ toBytes $ Crypto.hmacGetDigest $ Crypto.hmacAlg Crypto.MD5 key mBS
+mac e = throwError $ TypeMismatch "(bytestring,bytestring)" $ map Term e
+
+append :: TermFun
+append [TList x, TList y] = return $ TList $ x ++ y 
+append e = throwError $ TypeMismatch "(list,list)" $ map Term e
diff --git a/TypDefs.hs b/TypDefs.hs
--- a/TypDefs.hs
+++ b/TypDefs.hs
@@ -17,6 +17,7 @@
 
 import Control.Monad.Trans.Except(ExceptT(..))
 import Data.Char (toLower)
+import Data.ByteString (ByteString)
 import Data.IORef (IORef)
 import Data.List (intercalate)
 import Data.Map (Map)
@@ -43,6 +44,7 @@
           | TBool Bool
           | TPair (Term, Term)
           | TList [Term]
+          | TBS ByteString
           | TData HttpData
           | TFun Name [Term]
             deriving (Eq)
@@ -50,22 +52,13 @@
 data HttpData = Resp (Response String)
               | Req  (Request String)
 
-instance Eq HttpData where (==) = eqHttpData
-instance Show HttpData where show = showHttpData
-
 instance HasHeaders HttpData where
     getHeaders (Resp r) = getHeaders r
     getHeaders (Req r)  = getHeaders r
     setHeaders (Resp r) = Resp . setHeaders r
     setHeaders (Req r)  = Req . setHeaders r
 
-showHttpData :: HttpData -> String
-showHttpData (Resp r) = show r
-showHttpData (Req r)  = show r 
 
-eqHttpData :: HttpData -> HttpData -> Bool
-eqHttpData _ _ = False
-
 type TermFun = [Term] -> ThrowsError Term
 
 type Name      = String
@@ -93,27 +86,9 @@
 
 data Type = HttpRequest
           | HttpResponse
-          | Header
-          | List Type
           deriving (Eq, Read, Show)
 
-instance Show PiError where show = showError
-
-showError :: PiError -> String
-showError (UnboundVar message var)      = message ++ ": " ++ var
-showError (NotFunction message fun)     = message ++ ": " ++ fun
-showError (NotChannel chan)             = "Not a channel: " ++ chan 
-showError (NotProcess proc)             = "Not a Process: " ++ proc
-showError (NotTerm name var)            = "Expecting " ++ name ++ " to be a Term, found: " ++ show var
-showError (NumArgs name expected found) = "Expected " ++ show name ++ show expected ++ " args; found values "
-                                          ++ unwordsList found
-showError (TypeMismatch expected found) = "Invalid type: expected " ++ expected ++ ", found "
-                                          ++ show found
-showError (Parser parseErr)             = "Parse error at " ++ show parseErr
-showError (PatternMatch t1 t2)          = "Pattern match failure: cannot match " ++ show t1 ++ " and \n" ++ show t2
-showError (Default msg)                 = msg
-
-type Env = IORef (Map String Value)
+type Env = IORef (Map Name Value)
 
 data Channel = Channel {
                send         :: String -> IO ()
@@ -125,22 +100,12 @@
                | Connect
                  deriving (Eq, Show, Read)
 
-showValue :: Value -> String
-showValue (Proc p)  = show p
-showValue (Term t)  = show t
-showValue (Chan c)  = show $ convert c
-    where 
-        convert ch = TFun "<chan>" (map TStr ex) 
-            where ex = extra ch
-showValue (PrimitiveFunc _)  = "<primitive>" 
-showValue (Func {})          = "<user function>"  
-
-eqvVal :: Value -> Value -> Bool
-eqvVal (Proc p1)  (Proc p2) = p1 == p2
-eqvVal (Term t1)  (Term t2) = t1 == t2
-eqvVal _ _ = False
-
-instance Eq Value where (==) = eqvVal
+instance Show PiProcess where show = showPi
+instance Show Term      where show = showTerm
+instance Show Value     where show = showValue
+instance Show Condition where show = showCond
+instance Show PiError where show = showError
+instance Show HttpData where show = showHttpData
 
 showPi :: PiProcess -> String
 showPi Null = "0"
@@ -166,15 +131,51 @@
 showTerm (TList ls) = "list(" ++ intercalate "," (map show ls) ++ ")"
 showTerm (TPair (a,b)) = "pair("++ show a ++ ","++ show b ++ ")"
 showTerm (TData d) = show d
+showTerm (TBS bs)  = show bs
 showTerm (TFun n ts) = n ++ "(" ++ intercalate "," (map show ts) ++ ")"
 
+showValue :: Value -> String
+showValue (Proc p)  = show p
+showValue (Term t)  = show t
+showValue (Chan c)  = show $ convert c
+    where 
+        convert ch = TFun "<chan>" (map TStr ex) 
+            where ex = extra ch
+showValue (PrimitiveFunc _)  = "<primitive>" 
+showValue (Func {})          = "<user function>"  
+
 showCond :: Condition -> String
 showCond (t1 `Equals` t2) = show t1 ++ " == " ++ show t2
 
-instance Show PiProcess where show = showPi
-instance Show Term      where show = showTerm
-instance Show Condition where show = showCond
-instance Show Value     where show = showValue
+showError :: PiError -> String
+showError (UnboundVar message var)      = message ++ ": " ++ var
+showError (NotFunction message fun)     = message ++ ": " ++ fun
+showError (NotChannel chan)             = "Not a channel: " ++ chan 
+showError (NotProcess proc)             = "Not a Process: " ++ proc
+showError (NotTerm name var)            = "Expecting " ++ name ++ " to be a Term, found: " ++ show var
+showError (NumArgs name expected found) = "Expected " ++ show name ++ show expected ++ " args; found values "
+                                          ++ unwordsList found
+showError (TypeMismatch expected found) = "Invalid type: expected " ++ expected ++ ", found "
+                                          ++ show found
+showError (Parser parseErr)             = "Parse error at " ++ show parseErr
+showError (PatternMatch t1 t2)          = "Pattern match failure: cannot match " ++ show t1 ++ " and \n" ++ show t2
+showError (Default msg)                 = msg
+
+showHttpData :: HttpData -> String
+showHttpData (Resp r) = show r
+showHttpData (Req r)  = show r 
+
+instance Eq Value where (==) = eqvVal
+instance Eq HttpData where (==) = eqHttpData
+
+eqHttpData :: HttpData -> HttpData -> Bool
+eqHttpData _ _ = False
+
+eqvVal :: Value -> Value -> Bool
+eqvVal (Proc p1)  (Proc p2) = p1 == p2
+eqvVal (Term t1)  (Term t2) = t1 == t2
+eqvVal _ _ = False
+
 
 unwordsList :: [Value] -> String
 unwordsList = unwords . map show
diff --git a/changes.md b/changes.md
new file mode 100644
--- /dev/null
+++ b/changes.md
@@ -0,0 +1,10 @@
+Version 0.0.5:
+--------------
+
+Changelog!
+
+- Fixed an issue with pattern matching on lists. Lists of the same length pattern match exactly: i.e.
+let list(a,b,c) = list(1,2,3) => a = 1 , b = 2, c = 3 . 
+
+- Added the primitive append(list(a..),list(b..)) => list(a..,b..)
+
diff --git a/pi-calculus.cabal b/pi-calculus.cabal
--- a/pi-calculus.cabal
+++ b/pi-calculus.cabal
@@ -2,9 +2,9 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                pi-calculus
-version:             0.0.4
-synopsis:            Applied pi-calculus compiler
-description:         Phi - A compiler for the applied pi-calculus. Very rough around the edges.
+version:             0.0.5
+synopsis:            Applied pi-calculus interpreter
+description:         Phi -  an interpreter for the applied pi-calculus. Very rough around the edges.
 license:             GPL-3
 license-file:        LICENSE
 author:              Will de Renzy-Martin
@@ -15,8 +15,9 @@
 build-type:          Simple
 cabal-version:       >=1.8
 data-files:          testing/*.pi, pilude.pi
+extra-source-files:  changes.md
 
 executable phi
   main-is:           PiCalculus.hs
   other-modules:     Channel, Parser, PatternMatching, Primitives, TypDefs, Paths_pi_calculus
-  build-depends:       base >=4.5 && <=4.8, mtl ==2.2.*, parsec ==3.1.*, containers ==0.5.*, transformers ==0.4.*, network ==2.5.*, HTTP >=2.15, bytestring >= 0.10, io-streams ==1.1.*
+  build-depends:       base >=4.5 && <=4.8, mtl ==2.2.*, parsec ==3.1.*, containers ==0.5.*, transformers ==0.4.*, network ==2.5.*, HTTP >=2.15, bytestring >=0.10, io-streams ==1.1.*, cryptohash ==0.11.*, byteable ==0.1.*, binary ==0.7.2.*, AES ==0.2.*, RSA ==1.2.2.*
diff --git a/pilude.pi b/pilude.pi
--- a/pilude.pi
+++ b/pilude.pi
@@ -2,4 +2,9 @@
 let print(msg) = out(stdout,msg)
 let error(msg) = out(stderr,msg)
 let dbgOut(c, msg) = out(c,msg);out(stdout,msg)
-let forever(process) = &process;&forever(process)
+let fetch_out(c) = in(stdin,msg);out(c,msg)
+let in_print(c)  = in(c,msg);out(stdout,msg)
+let forever(p) = &p;&forever(p)
+let getLocation(data) = getHeader("location",data)
+let in_and_out(c) = &in_print(c);&fetch_out(c)
+let out_and_in(c) = &fetch_out(c);&in_print(c) 
diff --git a/testing/client.pi b/testing/client.pi
--- a/testing/client.pi
+++ b/testing/client.pi
@@ -1,6 +1,6 @@
-out(stdout,"Enter host:"); in(stdin,host);
-out(stdout,"Enter port:"); in(stdin,port);
-let ch = chan(host,port) in
-    let sch = {} in
-        out(stdout,sch);out(ch,sch);in(sch,msg);out(stdout,msg)
-
+&load("pilude.pi");
+out(stdout,"Enter Host"); in(stdin,host);
+out(stdout,"Enter Port"); in(stdin,port);
+    let ch = chan(host,port) in
+        let proc = out_and_in(ch) in
+            &forever(proc)
diff --git a/testing/follow.pi b/testing/follow.pi
--- a/testing/follow.pi
+++ b/testing/follow.pi
@@ -1,5 +1,5 @@
 let follow(ch,r) = (out(ch,r);in(ch,resp:HttpResponse);
-    let list(c,_,h,_) = resp in
+    let list(c,_,h,b) = resp in
         if c = 302 
             then let req = httpReq(getHeader("location",resp),headers(),httpGet()) in &follow(ch,req) 
-            else out(stdout,h)) 
+            else &print(b)) 
diff --git a/testing/get.pi b/testing/get.pi
new file mode 100644
--- /dev/null
+++ b/testing/get.pi
@@ -0,0 +1,6 @@
+&load("pilude.pi");
+&load("follow.pi");
+&print("Host:");in(stdin,site);
+&print("Resource:");in(stdin,res);
+let siteChan = httpChan(site) in
+    let req = httpReq(uri(site,res),headers(),httpGet()) in &follow(siteChan,req)
diff --git a/testing/index.pi b/testing/index.pi
deleted file mode 100644
--- a/testing/index.pi
+++ /dev/null
@@ -1,4 +0,0 @@
-&load("follow.pi");
-out(stdout,"Host:");in(stdin,site);
-let siteChan = httpChan(site) in
-let req = httpReq(uri(site,"index.html"),headers(),httpGet()) in &follow(siteChan,req)
diff --git a/testing/p_chan_client.pi b/testing/p_chan_client.pi
new file mode 100644
--- /dev/null
+++ b/testing/p_chan_client.pi
@@ -0,0 +1,6 @@
+out(stdout,"Enter host:"); in(stdin,host);
+out(stdout,"Enter port:"); in(stdin,port);
+let ch = chan(host,port) in
+    let sch = {} in
+        out(ch,sch);in(sch,msg);out(stdout,msg)
+
diff --git a/testing/p_chan_server.pi b/testing/p_chan_server.pi
new file mode 100644
--- /dev/null
+++ b/testing/p_chan_server.pi
@@ -0,0 +1,3 @@
+out(stdout,"Enter port:"); in(stdin,port);
+let ch = {port} in 
+    in(ch,sch);in(stdin,msg);out(sch,msg)
diff --git a/testing/server.pi b/testing/server.pi
--- a/testing/server.pi
+++ b/testing/server.pi
@@ -1,3 +1,5 @@
-out(stdout,"Enter port:"); in(stdin,port);
-let ch = {port} in 
-    in(ch,sch);out(stdout,sch);in(stdin,msg);out(sch,msg)
+&load("pilude.pi");
+out(stdout,"Enter Port");
+in(stdin,port);
+    let ch = {port} in
+        &in_and_out(ch)
