content: 
  import Uniplate.Type
  import Data.Char
  import Data.Ratio
  import qualified Data.Map as Map
  
  #ifndef SKIP_ZIPPER
  import Data.Generics.Uniplate.Zipper
  #endif
  
  
  benchmark :: Benchmark
  benchmark = Benchmark
      variables_ zeros_ simplify_
      rename_ symbols_ constFold_
      (increase_ 100) (incrone_ "" 100) bill_
  
  variables_ :: Expr -> [String]
  variables_ x = [y | Var y <- universe x]
  
  zeros_ :: Expr -> Int
  zeros_ x = length [() | Div _ (Val 0) <- universe x]
  
  simplify_ :: Expr -> Expr
  simplify_ = transform simp
      where
          simp (Sub x y)          = simp $ Add x (Neg y)
          simp (Add x y) | x == y = Mul (Val 2) x
          simp x                  = x
  
  rename_ :: Stm -> Stm
  rename_ = transformBi rename_op
      where rename_op (V x) = V ("_" ++ x)
  
  symbols_ :: Stm -> [(Var,Typ)]
  symbols_ x = [(v,t) | SDecl t v <- universeBi x]
  
  constFold_ :: Stm -> Stm
  constFold_ = transformBi const_op
      where
          const_op (EAdd (EInt n) (EInt m)) = EInt (n+m)
          const_op x = x
  
  increase_ :: Integer -> Company -> Company
  increase_ = increaseAny_
  
  increaseAny_ :: Biplate a Salary => Integer -> a -> a
  increaseAny_ k = transformBi (increase_op k)
      where increase_op k (S s) = S (s+k)
  
  incrone_ :: String -> Integer -> Company -> Company
  incrone_ name k = descendBi $ f name k
      where
          f name k a@(D n _ _) | name == n = increaseAny_ k a
                               | otherwise = descend (f name k) a
  
  bill_ :: Company -> Integer
  bill_ x = sum [x | S x <- universeBi x]
  
  
  test :: String -> IO ()
  test msg = do
      let a === b | a == b = return ()
                  | otherwise = error $ "Did not match in " ++ msg ++ ":\n" ++ show a ++ "\n" ++ show b
  
      let expr1 = Add (Val 1) (Neg (Val 2))
      universe expr1 === [expr1, Val 1, Neg (Val 2), Val 2]
      children expr1 === [Val 1, Neg (Val 2)]
      transform (\x -> case x of Val n -> Val (n+1) ; _ -> x) expr1 === Add (Val 2) (Neg (Val 3))
  
      let stmt11 = SAss (V "v") (EInt 1)
          stmt121 = SAss (V "x") (EInt 3)
          stmt12 = SReturn (EAdd (EInt 1) (EStm stmt121))
          stmt1 = SBlock [stmt11,stmt12]
      universe stmt1 === [stmt1,stmt11,stmt12,stmt121]
      children stmt1 === [stmt11,stmt12]
      childrenBi stmt1 === [EInt 1,EAdd (EInt 1) (EStm (SAss (V "x") (EInt 3)))]
      [i | EInt i <- universeBi stmt1] === [1,1,3]
      transformBi (const ([] :: [Stm])) stmt1 === SBlock []
      descend (const stmt121) stmt1 === SBlock [stmt121,stmt121]
  
      let str1 = "neil"
      universe str1 === ["neil","eil","il","l",""]
      children str1 === ["eil"]
      universeBi str1 === "neil"
      transformBi (reverse :: String -> String) str1 === "elin"
      descendBi toUpper str1 === "NEIL"
  
      let eith1 = Left str1 :: Either String Int
      universeBi eith1 === ([] :: [Int])
      childrenBi eith1 === str1
  
      let mp1 = map toMap [Map.singleton "neil" (1::Int), Map.fromList [("morz",3),("test",4)], Map.empty]
      universeBi mp1 === [1::Int,3,4]
      universeBi (transformBi (+(1::Int)) mp1) === [2::Int,4,5]
      let mp2 = map fromMap $ descendBi (reverse :: String -> String) mp1
      map Map.keys mp2 === [["lien"],["tset","zrom"],[]]
      map Map.valid mp2 === [True,True,True]
  
      let rat1 = 1 % 2 :: Rational
      universe rat1 === [rat1]
      universeBi rat1 === [1::Integer,2::Integer]
  
      let com1 = C [D "test" (E (P "fred" "bob") (S 12)) []]
      universeBi com1 === [S 12]
  
  #ifndef SKIP_ZIPPER
      let z = zipper expr1
      hole z === expr1
      fmap hole (down z) === Just (Val 1)
      fmap hole (left =<< down z) === Nothing
      fmap hole (right =<< down z) === Just (Neg (Val 2))
      fmap hole (right =<< right =<< down z) === Nothing
      fmap hole (left =<< right =<< down z) === Just (Val 1)
      fmap hole (up =<< down z) === Just expr1
      fmap (fromZipper . replaceHole (Val 3)) (right =<< down z) === Just (Add (Val 1) (Val 3))
      fmap hole (down =<< right =<< down z) === Just (Val 2)
      fmap hole (up z) === Nothing
  
      let zipChildren x = hole x : maybe [] zipChildren (right x)
      fmap zipChildren (down z) === Just (children expr1)
      maybe [] zipChildren (zipperBi stmt1) === (childrenBi stmt1 :: [Stm])
      maybe [] zipChildren (zipperBi stmt1) === (childrenBi stmt1 :: [Exp])
  #endif
  
      putChar '.'
  
  
  -- TO ADD
  -- Map/Set, check we go inside
  -- Ratio based test
  -- Strict fields
  -- Infinite type sizing, data Foo a = Foo Int | Bar (Foo (Foo a))
  
  -- should also rewrite PlateData:
  -- Info = IntMap (IntMap IntSet)
  
  -- a, b, then a set of those which are definate miss
  -- everything else is assumed to be follow
  -- then cache the two lookups inside the biplate instances (works even if biplate is missed)
  
  -- IntMap (IntSet, IntSet)
  
  -- The IntMap is indexed by "to"
  -- The first set is those "from" items that have been processed
  -- The second set is those which result in miss
  
  
  -- hitTest :: FromTypeRep -> ToTypeRep -> (FromTypeRep -> Bool)
  -- return True if it might be contained within
  