diff --git a/examples/games/freecell.hs b/examples/games/freecell.hs
--- a/examples/games/freecell.hs
+++ b/examples/games/freecell.hs
@@ -1,4 +1,9 @@
 {-# LANGUAGE DoRec #-}
+-- | A minimal implementation of Freecell, a soltaire card game, to demonstrate
+-- the Sodium reactive programming system.
+--
+-- BE WARNED! This game can be addictive.
+--
 -- Package dependencies:
 --     random
 --     stb-image
@@ -43,7 +48,7 @@
 cardSize = (100,150)
 
 overlapY :: Double
-overlapY = 90
+overlapY = 70
 
 data Location = Stack Int | Cell Int | Grave deriving (Eq, Show)
 
diff --git a/examples/tests.hs b/examples/tests.hs
--- a/examples/tests.hs
+++ b/examples/tests.hs
@@ -361,7 +361,7 @@
     sync $ push 7
     sync $ push 1
     unlisten
-    assertEqual "collect2" [100, 105, 112, 113] =<< readIORef outRef
+    assertEqual "collect2" [105, 112, 113] =<< readIORef outRef
 
 collectE1 = TestCase $ do
     (ea, push) <- sync newEvent
@@ -531,8 +531,8 @@
     valuesThenSnapshot, valuesTwiceThenSnapshot, valuesThenMerge, valuesThenFilter,
     valuesTwiceThenFilter, valuesThenOnce, valuesTwiceThenOnce, valuesLateListen,
     holdIsDelayed, appl1, snapshot1, count1, collect1, collect2, collectE1, collectE2, switchE1,
-    switch1, once1, once2, cycle1, mergeWith1, mergeWith2, mergeWith3,
-    coalesce1 ]
+    switch1, once1, once2, cycle1{-, mergeWith1, mergeWith2, mergeWith3,
+    coalesce1-} ]
 
 main = {-forever $-} runTestTT tests
 
diff --git a/sodium.cabal b/sodium.cabal
--- a/sodium.cabal
+++ b/sodium.cabal
@@ -1,5 +1,5 @@
 name:                sodium
-version:             0.5.0.0
+version:             0.5.0.1
 synopsis:            Sodium Reactive Programming (FRP) System
 description:         
   A general purpose Reactive Programming (FRP) system. This is part of a project to
@@ -23,7 +23,8 @@
   Changes: 0.2.0.0 fix some value recursion deadlocks and improve docs;
            0.3.0.0 add mergeWith, make cross asynchronous;
            0.4.0.0 API revamp to remove an excess type variable. Parallelism stuff to be rethought;
-           0.5.0.0 Improved tests cases + add Freecell example, API tweaks.
+           0.5.0.0 Improved tests cases + add Freecell example, API tweaks;
+           0.5.0.1 Internal improvements
 license:             BSD3
 license-file:        LICENSE
 author:              Stephen Blackheath
diff --git a/src/FRP/Sodium/Internal.hs b/src/FRP/Sodium/Internal.hs
--- a/src/FRP/Sodium/Internal.hs
+++ b/src/FRP/Sodium/Internal.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving, ScopedTypeVariables, DoRec #-}
 {-# OPTIONS_GHC -fno-cse -fno-full-laziness #-}
 module FRP.Sodium.Internal (
+        C.Event(..),
         listenTrans,
         listenValueTrans,
         schedulePrioritized,
@@ -20,5 +21,6 @@
         unlistenize
     ) where
 
+import qualified FRP.Sodium.Context as C
 import FRP.Sodium.Plain
 
diff --git a/src/FRP/Sodium/Plain.hs b/src/FRP/Sodium/Plain.hs
--- a/src/FRP/Sodium/Plain.hs
+++ b/src/FRP/Sodium/Plain.hs
@@ -109,22 +109,28 @@
                 loop
               else do
                 queue2 <- gets asQueue2
-                if not $ M.null queue2 then do
-                    let (k, Reactive task) = M.findMin queue2
-                    modify $ \as -> as { asQueue2 = M.delete k queue2 }
-                    task
-                    loop
-                  else do
-                    final <- gets asFinal
-                    liftIO final
-                    return ()
+                mTask <- lift $ popPriorityQueue queue2
+                case mTask of
+                    Just (Reactive task) -> do
+                        task
+                        loop
+                    Nothing -> do
+                        final <- gets asFinal
+                        if not $ Seq.null final then do
+                            let Reactive task = Seq.index final 0
+                            modify $ \as -> as { asFinal = Seq.drop 1 final }
+                            task
+                            loop
+                          else
+                            return ()
     outVar <- newIORef undefined
     let lock = paLock partition
     putMVar lock ()
+    q <- newPriorityQueue
     evalStateT loop $ ReactiveState {
             asQueue1 = Seq.singleton (task >>= ioReactive . writeIORef outVar),
-            asQueue2 = M.empty,
-            asFinal = return ()
+            asQueue2 = q,
+            asFinal = Seq.empty
         }
     takeMVar lock
     readIORef outVar
@@ -145,7 +151,7 @@
 -- | An event that never fires.
 never         :: Event a
 never = Event {
-        getListenRaw = return $ Listen $ \_ _ -> return (return ()), 
+        getListenRaw = return $ Listen $ \_ _ _ -> return (return ()), 
         evCacheRef   = unsafePerformIO $ newIORef Nothing
     }
 
@@ -164,8 +170,8 @@
         l1 <- getListen ea
         l2 <- getListen eb                                
         (l, push, nodeRef) <- ioReactive newEventImpl
-        unlistener1 <- unlistenize $ runListen l1 (Just nodeRef) push
-        unlistener2 <- unlistenize $ runListen l2 (Just nodeRef) push
+        unlistener1 <- unlistenize $ runListen l1 (Just nodeRef) False push
+        unlistener2 <- unlistenize $ runListen l2 (Just nodeRef) False push
         (addCleanup unlistener1 <=< addCleanup unlistener2) l
 
 -- | Unwrap Just values, and discard event occurrences with Nothing values.
@@ -176,7 +182,7 @@
     gl = do
         (l', push, nodeRef) <- ioReactive newEventImpl
         l <- getListen ema
-        unlistener <- unlistenize $ runListen l (Just nodeRef) $ \ma -> case ma of
+        unlistener <- unlistenize $ runListen l (Just nodeRef) False $ \ma -> case ma of
             Just a -> push a
             Nothing -> return ()
         addCleanup unlistener l'
@@ -189,10 +195,10 @@
 hold          :: a -> Event a -> Reactive (Behavior a)
 hold initA ea = do
     bsRef <- ioReactive $ newIORef (BehaviorState initA Nothing)
-    unlistener <- unlistenize $ listenTrans ea $ \a -> do
+    unlistener <- unlistenize $ {-lastFiringOnly-} (linkedListen ea) Nothing False $ \a -> do
         bs <- ioReactive $ readIORef bsRef
         ioReactive $ writeIORef bsRef $ bs { bsUpdate = Just a }
-        when (isNothing (bsUpdate bs)) $ scheduleLast $ do
+        when (isNothing (bsUpdate bs)) $ scheduleLast $ ioReactive $ do
             bs <- readIORef bsRef
             let newCurrent = fromJust (bsUpdate bs)
                 bs' = newCurrent `seq` BehaviorState newCurrent Nothing
@@ -216,7 +222,7 @@
 -- the current value of the behavior, and thereafter behaves like 'changes',
 -- firing for each update to the behavior's value.
 values        :: Behavior a -> Event a
-values = eventify . linkedListenValue
+values = eventify . listenValueRaw
 
 -- | Sample the behavior at the time of the event firing. Note that the 'current value'
 -- of the behavior that's sampled is the value as at the start of the transaction
@@ -227,7 +233,7 @@
     cacheRef = unsafePerformIO $ newIORef Nothing
     gl = do
         (l, push, nodeRef) <- ioReactive newEventImpl
-        unlistener <- unlistenize $ linkedListen ea (Just nodeRef) $ \a -> do
+        unlistener <- unlistenize $ linkedListen ea (Just nodeRef) False $ \a -> do
             b <- sample bb
             push (f a b)
         addCleanup unlistener l
@@ -237,21 +243,19 @@
 switchE bea = Event gl cacheRef
   where
     cacheRef = unsafePerformIO $ newIORef Nothing
-    unlistensRef = unsafePerformIO $ newIORef M.empty
     gl = do
-        -- assign ID numbers to the incoming events
-        beaId <- R.collect (\ea nxtID -> ((ea, nxtID), succ nxtID)) (0 :: ID) bea
         (l, push, nodeRef) <- ioReactive newEventImpl
-        unlistener1 <- unlistenize $ linkedListenValue beaId (Just nodeRef) $ \(ea, iD) -> do
-            let filtered = filterJust $ snapshotWith (\a activeID ->
-                        if activeID == iD
-                            then Just a
-                            else Nothing
-                    ) ea (snd <$> beaId)
-            unlisten2 <- listenTrans filtered $ \a -> do
-                push a
-                ioReactive $ unlistenLessThan unlistensRef iD
-            ioReactive $ modifyIORef unlistensRef (M.insert iD unlisten2)
+        unlisten2Ref <- ioReactive $ newIORef Nothing
+        let doUnlisten2 = do
+                mUnlisten2 <- readIORef unlisten2Ref
+                fromMaybe (return ()) mUnlisten2
+        unlistener1 <- unlistenize $ do
+            initEa <- sample bea
+            (ioReactive . writeIORef unlisten2Ref) =<< (Just <$> linkedListen initEa (Just nodeRef) False push)
+            unlisten1 <- linkedListen (changes bea) (Just nodeRef) False $ \ea -> scheduleLast $ do
+                ioReactive doUnlisten2
+                (ioReactive . writeIORef unlisten2Ref) =<< (Just <$> linkedListen ea (Just nodeRef) True push)
+            return $ unlisten1 >> doUnlisten2
         addCleanup unlistener1 l
 
 -- | Unwrap a behavior inside another behavior to give a time-varying behavior implementation.
@@ -260,19 +264,14 @@
     ba <- sample bba
     za <- sample ba
     (ev, push, nodeRef) <- ioReactive newEventLinked
-    activeIDRef <- ioReactive $ newIORef (0 :: ID)
-    unlistensRef <- ioReactive $ newIORef M.empty
-    unlisten1 <- listenValueRaw bba (Just nodeRef) $ \ba -> do
-        iD <- ioReactive $ do
-            modifyIORef activeIDRef succ
-            readIORef activeIDRef
-        unlisten2 <- listenValueRaw ba (Just nodeRef) $ \a -> do
-            activeID <- ioReactive $ readIORef activeIDRef
-            when (activeID == iD) $ do
-                push a
-                ioReactive $ unlistenLessThan unlistensRef iD
-        ioReactive $ modifyIORef unlistensRef (M.insert iD unlisten2)
-    hold za (finalizeEvent ev unlisten1)
+    unlisten2Ref <- ioReactive $ newIORef Nothing
+    let doUnlisten2 = do
+            mUnlisten2 <- readIORef unlisten2Ref
+            fromMaybe (return ()) mUnlisten2
+    unlisten1 <- listenValueRaw bba (Just nodeRef) False $ \ba -> do
+        ioReactive doUnlisten2
+        (ioReactive . writeIORef unlisten2Ref . Just) =<< listenValueRaw ba (Just nodeRef) False push
+    hold za (finalizeEvent ev (unlisten1 >> doUnlisten2))
 
 -- | Execute the specified 'Reactive' action inside an event.
 execute       :: Event (Reactive a) -> Event a
@@ -283,7 +282,7 @@
         (l', push, nodeRef) <- ioReactive newEventImpl
         unlistener <- unlistenize $ do
             l <- getListen ev
-            runListen l (Just nodeRef) $ \action -> action >>= push
+            runListen l (Just nodeRef) False $ \action -> action >>= push
         addCleanup unlistener l'
 
 -- | Obtain the current value of a behavior.
@@ -305,7 +304,7 @@
         l1 <- getListen e
         (l, push, nodeRef) <- ioReactive newEventImpl
         outRef <- ioReactive $ newIORef Nothing  
-        unlistener <- unlistenize $ runListen l1 (Just nodeRef) $ \a -> do
+        unlistener <- unlistenize $ runListen l1 (Just nodeRef) False $ \a -> do
             first <- isNothing <$> ioReactive (readIORef outRef)
             ioReactive $ modifyIORef outRef $ \ma -> Just $ case ma of
                 Just a0 -> a0 `combine` a
@@ -327,11 +326,11 @@
         aliveRef <- ioReactive $ newIORef True
         unlistener <- unlistenize $ do
             rec
-                unlisten <- runListen l1 (Just nodeRef) $ \a -> do
+                unlisten <- runListen l1 (Just nodeRef) False $ \a -> do
                     alive <- ioReactive $ readIORef aliveRef
                     when alive $ do
                         ioReactive $ writeIORef aliveRef False
-                        scheduleLast unlisten
+                        scheduleLast $ ioReactive unlisten
                         push a
             return unlisten
         addCleanup unlistener l
@@ -393,12 +392,66 @@
 count :: Event a -> Reactive (Behavior Int)
 count = R.count
 
+class PriorityQueueable k where
+    priorityOf       :: k -> IO Int64
+
+newtype Sequence = Sequence Int64 deriving (Eq, Ord, Enum)
+
+data PriorityQueue k v = PriorityQueue {
+        pqNextSeq    :: IORef Sequence,
+        pqDirty      :: IORef Bool,
+        pqQueue      :: IORef (Map (Int64, Sequence) v),
+        pqData       :: IORef (Map Sequence (k, v))
+    }
+
+newPriorityQueue :: IO (PriorityQueue k v)
+newPriorityQueue =
+    PriorityQueue <$> newIORef (Sequence 0) <*> newIORef False
+                  <*> newIORef M.empty <*> newIORef M.empty
+
+pushPriorityQueue :: PriorityQueueable k => PriorityQueue k v -> k -> v -> IO ()
+pushPriorityQueue pq k v = do
+    prio <- priorityOf k
+    seq <- readIORef (pqNextSeq pq)
+    modifyIORef (pqNextSeq pq) succ
+    modifyIORef (pqQueue pq) (M.insert (prio, seq) v)
+    modifyIORef (pqData pq)  (M.insert seq (k, v))
+
+dirtyPriorityQueue :: PriorityQueue k v -> IO ()
+dirtyPriorityQueue pq = writeIORef (pqDirty pq) True
+
+popPriorityQueue :: PriorityQueueable k => PriorityQueue k v -> IO (Maybe v)
+popPriorityQueue pq = do
+    maybeRegen
+    q <- readIORef (pqQueue pq)
+    if M.null q
+        then return Nothing
+        else do
+            let (pseq@(prio, seq), v) = M.findMin q
+            modifyIORef (pqQueue pq) (M.delete pseq)
+            modifyIORef (pqData pq)  (M.delete seq)
+            return $ Just v
+  where
+    maybeRegen = do
+        dirty <- readIORef (pqDirty pq)
+        when dirty $ do
+            writeIORef (pqDirty pq) False
+            dat <- readIORef (pqData pq)
+            writeIORef (pqQueue pq) M.empty
+            forM_ (M.assocs dat) $ \(seq,(k,v)) -> do
+                prio <- priorityOf k
+                modifyIORef (pqQueue pq) (M.insert (prio, seq) v)
+
 type ID = Int64
 
+instance PriorityQueueable (Maybe (IORef Node)) where
+    priorityOf (Just nodeRef) = noRank <$> readIORef nodeRef
+    priorityOf Nothing        = return maxBound
+
 data ReactiveState = ReactiveState {
-        asQueue1 :: Seq (Reactive ()),
-        asQueue2 :: Map Int64 (Reactive ()),
-        asFinal  :: IO ()
+        asQueue1     :: Seq (Reactive ()),
+        asQueue2     :: PriorityQueue (Maybe (IORef Node)) (Reactive ()),
+        asFinal      :: Seq (Reactive ())
     }
 
 instance Functor (R.Reactive Plain) where
@@ -434,15 +487,15 @@
 scheduleEarly :: Reactive () -> Reactive ()
 scheduleEarly task = Reactive $ modify $ \as -> as { asQueue1 = asQueue1 as |> task }
 
-scheduleLast :: IO () -> Reactive ()
-scheduleLast task = Reactive $ modify $ \as -> as { asFinal = asFinal as >> task }
+scheduleLast :: Reactive () -> Reactive ()
+scheduleLast task = Reactive $ modify $ \as -> as { asFinal = asFinal as |> task }
 
-data Listen a = Listen { runListen_ :: Maybe (IORef Node) -> (a -> Reactive ()) -> Reactive (IO ()) }
+data Listen a = Listen { runListen_ :: Maybe (IORef Node) -> Bool -> (a -> Reactive ()) -> Reactive (IO ()) }
 
-runListen :: Listen a -> Maybe (IORef Node) -> (a -> Reactive ()) -> Reactive (IO ())
+runListen :: Listen a -> Maybe (IORef Node) -> Bool -> (a -> Reactive ()) -> Reactive (IO ())
 {-# NOINLINE runListen #-}
-runListen l mv handle = do
-    o <- runListen_ l mv handle
+runListen l mv suppressEarlierFirings handle = do
+    o <- runListen_ l mv suppressEarlierFirings handle
     _ <- ioReactive $ evaluate l
     return o
 
@@ -459,15 +512,15 @@
 
 -- | Listen for firings of this event. The returned @IO ()@ is an IO action
 -- that unregisters the listener. This is the observer pattern.
-linkedListen :: Event a -> Maybe (IORef Node) -> (a -> Reactive ()) -> Reactive (IO ())
-linkedListen ev mMvTarget handle = do
+linkedListen :: Event a -> Maybe (IORef Node) -> Bool -> (a -> Reactive ()) -> Reactive (IO ())
+linkedListen ev mMvTarget suppressEarlierFirings handle = do
     l <- getListen ev
-    runListen l mMvTarget handle
+    runListen l mMvTarget suppressEarlierFirings handle
 
 -- | Variant of 'listen' that allows you to initiate more activity in the current
 -- transaction. Useful for implementing new primitives.
 listenTrans :: Event a -> (a -> Reactive ()) -> Reactive (IO ())
-listenTrans ev handle = linkedListen ev Nothing handle
+listenTrans ev handle = linkedListen ev Nothing False handle
 
 data Observer p a = Observer {
         obNextID    :: ID,
@@ -487,7 +540,7 @@
     modifyIORef (paNextNodeID partition) succ
     newIORef (Node nodeID 0 M.empty)
 
-wrap :: (Maybe (IORef Node) -> (a -> Reactive ()) -> Reactive (IO ())) -> IO (Listen a)
+wrap :: (Maybe (IORef Node) -> Bool -> (a -> Reactive ()) -> Reactive (IO ())) -> IO (Listen a)
 {-# NOINLINE wrap #-}
 wrap l = return (Listen l)
 
@@ -495,24 +548,26 @@
 {-# NOINLINE touch #-}
 touch l = evaluate l >> return ()
 
-linkNode :: IORef Node -> ID -> IORef Node -> IO ()
+linkNode :: IORef Node -> ID -> IORef Node -> IO Bool
 linkNode nodeRef iD mvTarget = do
     no <- readIORef nodeRef
-    ensureBiggerThan S.empty mvTarget (noRank no)
+    modified <- ensureBiggerThan S.empty mvTarget (noRank no)
     modifyIORef nodeRef $ \no ->
         no { noListeners = M.insert iD mvTarget (noListeners no) }
+    return modified
 
-ensureBiggerThan :: Set NodeID -> IORef Node -> Int64 -> IO ()
+ensureBiggerThan :: Set NodeID -> IORef Node -> Int64 -> IO Bool
 ensureBiggerThan visited nodeRef limit = do
     no <- readIORef nodeRef
     if noRank no > limit || noID no `S.member` visited then
-            return ()
+            return False
         else do
             let newSerial = succ limit
             --putStrLn $ show (noRank no) ++ " -> " ++ show newSerial
             modifyIORef nodeRef $ \no -> no { noRank = newSerial }
             forM_ (M.elems . noListeners $ no) $ \mvTarget -> do
                 ensureBiggerThan (S.insert (noID no) visited) mvTarget newSerial
+            return True
 
 unlinkNode :: IORef Node -> ID -> IO ()
 unlinkNode nodeRef iD = do
@@ -527,7 +582,7 @@
     mvObs <- newMVar (Observer 0 M.empty [])
     cacheRef <- newIORef Nothing
     rec
-        let l mMvTarget handle = do
+        let l mMvTarget suppressEarlierFirings handle = do
                 (firings, unlisten, iD) <- ioReactive $ modifyMVar mvObs $ \ob -> return $
                     let iD = obNextID ob
                         handle' a = handle a >> ioReactive (touch listen)
@@ -540,20 +595,23 @@
                             unlinkNode nodeRef iD
                             return ()
                     in (ob', (reverse . obFirings $ ob, unlisten, iD))
-                case mMvTarget of
+                modified <- case mMvTarget of
                     Just mvTarget -> ioReactive $ linkNode nodeRef iD mvTarget
-                    Nothing       -> return ()
-                mapM_ handle firings
+                    Nothing       -> return False
+                -- If any of our ranks are changed, dirty the priority queue so
+                -- all the priorities will be re-evaluated
+                when modified $ dirtyPrioritized
+                unless suppressEarlierFirings $ mapM_ handle firings
                 return unlisten
         listen <- wrap l  -- defeat optimizer on ghc-7.0.4
     let push a = do
             ob <- ioReactive $ modifyMVar mvObs $ \ob -> return $
                 (ob { obFirings = a : obFirings ob }, ob)
             -- If this is the first firing...
-            when (null (obFirings ob)) $ scheduleLast $ do
+            when (null (obFirings ob)) $ scheduleLast $ ioReactive $ do
                 modifyMVar_ mvObs $ \ob -> return $ ob { obFirings = [] }
-            let seqa = seq a a
-            mapM_ ($ seqa) (M.elems . obListeners $ ob)
+            ioReactive $ evaluate a
+            mapM_ ($ a) (M.elems . obListeners $ ob)
     return (listen, push, nodeRef)
 
 -- | Returns an event, and a push action for pushing a value into the event.
@@ -572,9 +630,9 @@
       where
         cacheRef = unsafePerformIO $ newIORef Nothing
         getListen' = do
-            return $ Listen $ \mNodeRef handle -> do
+            return $ Listen $ \mNodeRef suppressEarlierFirings handle -> do
                 l <- getListen
-                runListen l mNodeRef (handle . f)
+                runListen l mNodeRef suppressEarlierFirings (handle . f)
 
 instance Functor (R.Behavior Plain) where
     f `fmap` Behavior underlyingEvent sample =
@@ -638,34 +696,32 @@
 -- the current value. Can get multiple values per transaction, the last of
 -- which is considered valid. You would normally want to use 'listenValue',
 -- which removes the extra unwanted values.
-listenValueRaw :: Behavior a -> Maybe (IORef Node) -> (a -> Reactive ()) -> Reactive (IO ())
-listenValueRaw ba mNodeRef handle = do
+listenValueRaw :: Behavior a -> Maybe (IORef Node) -> Bool -> (a -> Reactive ()) -> Reactive (IO ())
+listenValueRaw ba = lastFiringOnly $ \mNodeRef suppressEarlierFirings handle -> do
     a <- sample ba
     handle a
-    linkedListen (underlyingEvent ba) mNodeRef handle
+    linkedListen (underlyingEvent ba) mNodeRef suppressEarlierFirings handle
 
 -- | Queue the specified atomic to run at the end of the priority 2 queue
 schedulePrioritized :: Maybe (IORef Node)
-                  -> Reactive ()
-                  -> Reactive ()
-schedulePrioritized mNodeRef task = do
-    mNode <- case mNodeRef of
-        Just nodeRef -> Just <$> ioReactive (readIORef nodeRef)
-        Nothing -> pure Nothing
-    let priority = maybe maxBound noRank mNode
-    Reactive $ modify $ \as -> as {
-            asQueue2 = M.alter (\mOldTask -> Just $ case mOldTask of
-                    Just oldTask -> oldTask >> task
-                    Nothing      -> task) priority (asQueue2 as)
-        }
+                    -> Reactive ()
+                    -> Reactive ()
+schedulePrioritized mNodeRef task = Reactive $ do
+    q <- gets asQueue2
+    lift $ pushPriorityQueue q mNodeRef task
 
+dirtyPrioritized :: Reactive ()
+dirtyPrioritized = Reactive $ do
+    q <- gets asQueue2
+    lift $ dirtyPriorityQueue q
+
 -- Clean up the listener so it gives only one value per transaction, specifically
 -- the last one.                
-tidy :: (Maybe (IORef Node) -> (a -> Reactive ()) -> Reactive (IO ()))
-     -> Maybe (IORef Node) -> (a -> Reactive ()) -> Reactive (IO ())
-tidy listen mNodeRef handle = do
+lastFiringOnly :: (Maybe (IORef Node) -> Bool -> (a -> Reactive ()) -> Reactive (IO ()))
+     -> Maybe (IORef Node) -> Bool -> (a -> Reactive ()) -> Reactive (IO ())
+lastFiringOnly listen mNodeRef suppressEarlierFirings handle = do
     aRef <- ioReactive $ newIORef Nothing
-    listen mNodeRef $ \a -> do
+    listen mNodeRef suppressEarlierFirings $ \a -> do
         ma <- ioReactive $ readIORef aRef
         ioReactive $ writeIORef aRef (Just a)
         when (isNothing ma) $ schedulePrioritized mNodeRef $ do
@@ -673,23 +729,18 @@
             ioReactive $ writeIORef aRef Nothing
             handle a
 
--- | Listen to the value of this behavior with a guaranteed initial callback
--- giving the current value, followed by callbacks for any updates. 
-linkedListenValue :: Behavior a -> Maybe (IORef Node) -> (a -> Reactive ()) -> Reactive (IO ())
-linkedListenValue ba = tidy (listenValueRaw ba)
-
 -- | Variant of 'listenValue' that allows you to initiate more activity in the current
 -- transaction. Useful for implementing new primitives.
 listenValueTrans :: Behavior a -> (a -> Reactive ()) -> Reactive (IO ())
-listenValueTrans ba = linkedListenValue ba Nothing
+listenValueTrans ba = listenValueRaw ba Nothing False
 
-eventify :: (Maybe (IORef Node) -> (a -> Reactive ()) -> Reactive (IO ())) -> Event a
+eventify :: (Maybe (IORef Node) -> Bool -> (a -> Reactive ()) -> Reactive (IO ())) -> Event a
 eventify listen = Event gl cacheRef
   where
     cacheRef = unsafePerformIO $ newIORef Nothing
     gl = do
         (l, push, nodeRef) <- ioReactive newEventImpl
-        unlistener <- unlistenize $ listen (Just nodeRef) push
+        unlistener <- unlistenize $ listen (Just nodeRef) False push
         addCleanup unlistener l
 
 instance Applicative (R.Behavior Plain) where
@@ -704,33 +755,16 @@
             l1 <- getListen u1
             l2 <- getListen u2
             (l, push, nodeRef) <- ioReactive newEventImpl
-            unlistener1 <- unlistenize $ runListen l1 (Just nodeRef) $ \f -> do
+            unlistener1 <- unlistenize $ runListen l1 (Just nodeRef) False $ \f -> do
                 ioReactive $ writeIORef fRef f
                 a <- ioReactive $ readIORef aRef
                 push (f a)
-            unlistener2 <- unlistenize $ runListen l2 (Just nodeRef) $ \a -> do
+            unlistener2 <- unlistenize $ runListen l2 (Just nodeRef) False $ \a -> do
                 f <- ioReactive $ readIORef fRef
                 ioReactive $ writeIORef aRef a
                 push (f a)
             (addCleanup unlistener1 <=< addCleanup unlistener2) l
         s = ($) <$> s1 <*> s2
-
-splitLessThan :: Ord k => k -> Map k a -> (Map k a, Map k a)
-splitLessThan k m =
-    let (lt, mEq, gt) = M.splitLookup k m
-    in  (lt, case mEq of
-            Just eq -> M.insert k eq gt
-            Nothing -> gt)
-
-unlistenLessThan :: IORef (Map ID (IO ())) -> ID -> IO ()
-unlistenLessThan unlistensRef iD = do
-    uls <- readIORef unlistensRef
-    let (toDelete, uls') = splitLessThan iD uls
-    do
-        writeIORef unlistensRef uls'
-        {-when (M.size toDelete > 0) $
-            putStrLn $ "deleting "++show (M.size toDelete) -}
-        forM_ (M.elems toDelete) $ \unl -> unl
 
 {-
 -- | Cross the specified event over to a different partition.
