Package frege.prelude.PreludeMonad

Compiled: Wed Dec 05 00:00:02 PST 2012 from source file: frege/prelude/PreludeMonad.fr

Package Documentation

This package provides the Monad class and related classes and functions.

The class hierarchy is derived from the (Haskell) proposal /The Other Prelude/ but the traditional method names have been kept, except for Applicative.pure which is replaced by Applicative.return. This is because pure cannot be a function name in Frege due to being a keyword.

The functions in this library use the following naming conventions:

 filter ::               (a -> Bool) -  > [a] -> [a]
 filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
 sequence  :: Monad m => [m a] -> m [a]
 sequence_ :: Monad m => [m a] -> m ()
 sum :: Num a => [a] -> a
 msum :: MonadPlus m => [m a] -> m a

This package is /implementation specific/ insofar as the compiler may assume that certain items are defined here in a certain way. Changes may thus lead to compiler crashes or java code that will be rejected by the java compiler.

In particular, desugared do expressions will reference Monad, Monad.>>= and Monad.>>.

This package is implicitly imported and besides the additional stuff covers most of what one would get by importing Control.Monad in Hasekll.

Table of Content

Imports

Classes

class Applicative Functor p => p

A functor with application, providing operations to

A minimal complete definition must include implementations of these functions satisfying the following laws:

/identity/
return id <*> v = v
/composition/
return (•) <> u <> v <> w = u <> (v <*> w)
/homomorphism/
return f <*> return x = return (f x)
/interchange/
u <> return y = return ($ y) <> u

The other methods have the following default definitions, which may be overridden with equivalent specialized implementations:

  u *> v = return (const id)  <*> u <*> v
  u <* v = return const <*> u <*> v

As a consequence of these laws, the Functor instance for f will satisfy

 fmap f x = return f <*> x

If f is also a Monad, it should satisfy (<*>) = ap (which implies that Applicative.return and Applicative.<*> satisfy the applicative functor laws).

Minimal complete definition: Applicative.return and Applicative.<*>.

Known Instances

ST, State, [], Either

Member Functions

*> :: Applicative p => p a -> p b -> p b

Sequence actions, discarding the value of the first argument.

<* :: Applicative p => p a -> p b -> p a

Sequence actions, discarding the value of the second argument.

<*> :: Applicative p => p (a->b) -> p a -> p b

Sequential application.

return :: Applicative p => a -> p a

Lift a value

class Cloneable Freezable f => f

For a data type declared like

 data D s = native Javatype

where Javatype implements the java.lang.Cloneable interface, one can get implementations for Freezable.freeze and Freezable.thaw by just stating

 instance Cloneable D

The Freezable.freeze and Freezable.thaw operations are implemented in terms of Cloneable.clone.

Member Functions

clone :: Cloneable f => f a -> f b
pure native clone

clone v must be a native method that works like java.lang.Object#clone.

freeze :: Cloneable f => f s -> ST s (Frozen f)
thaw :: Cloneable f => Frozen f -> Mutable f s
class Freezable f

Type class for native values that may be used in a functional way. The Freezable.freeze operation is a ST action, but yields a result that can be returned from a ST thread.

To be implemented with care.

Member Functions

freeze :: Freezable f => f s -> ST s (Frozen f)

"Freeze" a mutable native value. The result is supposed to be immutable or at least not reachable from other parts of the code, especially from java code.

The most prominent way to freeze a value is by Cloneable.clone-ing it, if that is supported.

our :: Freezable f => f s -> ST s (Frozen f)
Usage
our v as last action in a do block that created mutable native value v
Purpose
Make a value that is identical to v but has Immutable as phantom type. This allows escape of mutable native values from ST actions. Yet, because these values are tagged Immutable, unsafe operations are impossible outside the ST monad as long as all impure native functions are correctly defined. One can pass the value to another ST action, which may Freezable.thaw it and apply impure native functions again.
Returns
a copy of v tagged as Immutable in the ST monad

This is intended for cases where we want to keep the native value and we know that there are no references to the native value other than the ones maintained in the current ST action. In those not so rare cases, it would be overkill to obtain a copy of a value by cloning it or serializing/deserializing it. Hence, an implementation of Freezable.our is allowed to cheat a bit and return just this.

The safety of Freezable operations is something the compiler cannot infer. It lies entirely in the responsibility of the programmer to ensure safety. Remember that violation of the informal contract of Freezable (see below) will be rewarded with exceptions thrown at runtime or with inexplicable, perhaps nondeterministic behaviour of the program.

An example where Freezable.our is employed is creation and initialization of arrays, as in IntArray.fromList. When the array is completely initialized, it is safe to let it escape as a read only value because no further write accesses are possible (unless one manages to pass the array to an impure function.)

This is the informal contract of Freezable and its operations. It is designed so that the type system will detect unsafe usage of mutable native values. The programmer should understand that such type errors are a strong signal to go back and rethink the code. Inventing "clever" workarounds in the form of creatively typed native functions or so is like loading a shotgun that points to ones foot.

  • All mutable native data types have a frege type with a phantom type as its last type argument. (i.e. data Date s = native java.util.Date)
  • All impure functions have the same type variable (say s) for the phantom type of mutable types that appear in their type and have a result of ST s /a/.
  • All object creation functions have a return type of ST s (M s) or Mutable M s where M is the type constructor of the native values frege type.
  • If the function relies on global state, alters global state or performs input or output, the return type must be ST RealWorld /a/. Consequently, all mutable types that appear in the type signature must have RealWorld as phantom type.
  • In pure functions, the mutable data types must appear as M Immutable. The return type is an ordinary type (no ST type).
  • If the type is an instance of Freezable, then the implmentations of Freezable.freeze and Freezable.thaw create fresh objects. This is true for instances of Cloneable and Serializable that use the default type class methods (i.e., do not supply own implementations).
  • Freezable.our is used only when there are no alien references to the value or if a fresh object is created.

The default implementation does the same as Freezable.freeze. A generic native method to implement a low cost Freezable.our is provided in the runtime as frege.RT.our. It just returns its argument.

thaw :: Freezable f => Frozen f -> Mutable f s

The inverse of Freezable.freeze creates a value (an object) which can be passed to impure functions without compromising the frozen object passed as argument.

One possibility to thaw an object properly is by cloning it.

If Freezable.thaw is not implemented correctly, bad things may happen.

withFrozen :: Freezable f => f s -> (Frozen f->a) -> ST s a
Usage
withFrozen v f where v is a mutable native value.
Purpose
Temporarily freeze v and pass it to a pure function f.
Return
the result of f v in the ST monad.
Requirements
f must not fork parallel computations that could access v after f has returned.

This function is needed to synchronize pure computations on a native value with manipulations of that same value inside ST actions. Consider the following code:

 do
    arr <- IntArray.new 100
    arr.[42 <- 1]
    let result = arr.elemAt 42   // actually a type error
    arr.[42 <- 2]
    return result

The placement of the let does not guarantee that result will be evaluated between the assignments to cell 42 of the array. To the contrary, the read access to the array will most probably not occur before the result of the state action is evaluated. Therefore, such constructs are forbidden through the type of IntArray.elemAt which requires a frozen array.

The let must be replaced by

    result <- withFrozen arr (flip IntArray.elemAt 42)

to sequence evaluation before the next write access to the array.

Because Freezable.withFrozen employs Freezable.our it can be as easily misused. In fact withFrozen v id is identical to our v.

class Functor f

The Functor class is used for types that can be mapped over. Instances of Functor should satisfy the following laws:

 fmap id == id
 fmap (f . g) ==
 fmap f . fmap g

Known Instances

ST, State, Either, (,,), (,), []

Member Functions

fmap :: Functor f => (a->b) -> f a -> f b

Map a function over a Functor

class Monad (Functor m, Applicative m) => m

The Monad class defines the basic operations over a monad, a concept from a branch of mathematics known as /category theory/. From the perspective of a Frege programmer, however, it is best to think of a monad as an /abstract datatype/ of actions.

Frege’s do expressions provide a convenient syntax for writing monadic expressions.

Minimal complete definition: Monad.>>= and Applicative.return.

Instances of Monad should satisfy the following laws:

 return a >>= k == k a
 m >>= return == m
 m >>= (\x -> k x >>= h) == (m >>= k) >>= h

Since instances of Monad are also instances of Functor, they additionally shall satisfy the law:

 fmap f xs == xs >>= return • f

which is also the default implementation of Functor.fmap.

The instances of Monad for lists, Maybe and ST defined in the Prelude satisfy these laws.

Known Instances

ST, State, [], Either

Member Functions

<*> :: Monad m => m (a->b) -> m a -> m b
>> :: Monad m => m a -> m b -> m b

Sequentially compose two actions, discarding any value produced by the first, this works like sequencing operators (such as the semicolon) in imperative languages.

>>= :: Monad m => m a -> (a->m b) -> m b

Sequentially compose two actions, passing any value produced by the first as an argument to the second.

fmap :: Monad m => (a->b) -> m a -> m b
join :: Monad m => m (m a) -> m a

The Monad.join function is the conventional monad join operator. It is used to remove one level of monadic structure, projecting its bound argument into the outer level.

class MonadFail (Functor m, Applicative m, Monad m) => m

The MonadFail class augments Monad by adding the MonadFail.fail operation. This operation is not part of the mathematical definition of a monad.

Known Instances

Either, []

Member Functions

fail :: MonadFail m => String -> m a

Fail with a message.

class MonadOr (Functor mo, Applicative mo, Monad mo, MonadZero mo) => mo

Member Functions

orElse :: MonadOr mo => mo a -> mo a -> mo a
class MonadPlus (Functor mp, Applicative mp, Monad mp, MonadZero mp) => mp

A Monad that also supports choice and failure and observes the following laws:

 mzero `mplus`  v = v
 v `mplus` mzero  = v
 (a `mplus` b) `mplus` c = a `mplus` (b `mplus` c)
 (a `mplus` b) >>= f = (a >>= f) `mplus` (b >>= f)

Known Instances

[]

Member Functions

mplus :: MonadPlus mp => mp a -> mp a -> mp a

an associative operation

class MonadZero (Functor mz, Applicative mz, Monad mz) => mz

A Monad with a left identity.

Known Instances

[]

Member Functions

mzero :: MonadZero mz => mz a

This value should satisfy /left zero/:

 mzero >>= f = mzero   
class Serializable Freezable f => f

For a data type declared like

 data D s = native Javatype

where Javatype implements the java.io.Serializable interface, one can get implementations for Freezable.freeze and Freezable.thaw by just stating

 instance Serializable D

The Freezable.freeze and Freezable.thaw operations are implemented in terms of copySerializable, which serializes its argument to a byte array and creates a new copy by deserializing it from the byte array.

Member Functions

copySerializable :: Serializable f => f a -> f b
pure native frege.RT.copySerializable

copySerializable v is supposed to be a native function that is implemented by frege.RT.copySerializable at the instantiated type.

freeze :: Serializable f => f s -> ST s (Frozen f)
thaw :: Serializable f => Frozen f -> Mutable f s

Instances

instance Functor (a)

Member Functions

fmap :: (γ->α) -> (β, γ) -> (β, α)
instance Functor (a, b)

Member Functions

fmap :: (δ->α) -> (γ, β, δ) -> (γ, β, α)
instance Functor []

Member Functions

fmap :: (α->β) -> [α] -> [β]
instance MonadFail Either String

Member Functions

fail :: String -> Either String α
instance MonadFail []

Member Functions

fail :: String -> [α]
instance MonadPlus []

Member Functions

mplus :: [α] -> [α] -> [α]
mzero :: [α]
instance Monad Either left

Member Functions

*> :: Either β γ -> Either β α -> Either β α

inherited from Applicative.*>

<* :: Either β γ -> Either β α -> Either β γ

inherited from Applicative.<*

<*> :: Either β (γ->α) -> Either β γ -> Either β α

inherited from Monad.<*>

>> :: Either β γ -> Either β α -> Either β α

inherited from Monad.>>

>>= :: Either β γ -> (γ->Either β α) -> Either β α
fmap :: (γ->α) -> Either β γ -> Either β α
join :: Either α (Either α β) -> Either α β

inherited from Monad.join

return :: α -> Either β α
instance Monad ST s

Member Functions

*> :: ST β γ -> ST β α -> ST β α

inherited from Applicative.*>

<* :: ST β γ -> ST β α -> ST β γ

inherited from Applicative.<*

<*> :: ST β (γ->α) -> ST β γ -> ST β α

inherited from Monad.<*>

>> :: ST β γ -> ST β α -> ST β α
>>= :: ST γ α -> (α->ST γ β) -> ST γ β
fmap :: (γ->α) -> ST β γ -> ST β α

inherited from Monad.fmap

join :: ST α (ST α β) -> ST α β

inherited from Monad.join

return :: α -> ST β α
instance Monad State s

Member Functions

*> :: State β γ -> State β α -> State β α

inherited from Applicative.*>

<* :: State β γ -> State β α -> State β γ

inherited from Applicative.<*

<*> :: State β (γ->α) -> State β γ -> State β α

inherited from Monad.<*>

>> :: State α γ -> State α β -> State α β
>>= :: State γ α -> (α->State γ β) -> State γ β

monadic bind for the State monad

fmap :: (γ->α) -> State β γ -> State β α

inherited from Monad.fmap

join :: State α (State α β) -> State α β

inherited from Monad.join

return :: α -> State β α

lift a value to the State monad

instance Monad []

Member Functions

*> :: [α] -> [β] -> [β]

inherited from Applicative.*>

<* :: [α] -> [β] -> [α]

inherited from Applicative.<*

<*> :: [α->β] -> [α] -> [β]

inherited from Monad.<*>

>> :: [α] -> [β] -> [β]

inherited from Monad.>>

>>= :: [α] -> (α->[β]) -> [β]
join :: [[α]] -> [α]

inherited from Monad.join

return :: α -> [α]

Functions and Values

<$> :: Functor f => (a->b) -> f a -> f b

An infix synonym for Functor.fmap. Left associative with precedence 4.

<=< :: Monad β => (α->β γ) -> (δ->β α) -> δ -> β γ

Right-to-left Kleisli composition of monads. (>=>), with the arguments flipped

=<< :: Monad γ => (α->γ β) -> γ α -> γ β

=<< is the same as Monad.>>= with the arguments flipped

>=> :: Monad α => (δ->α β) -> (β->α γ) -> δ -> α γ

left to right Kleisli composition of monads

ap :: Monad α => α (γ->β) -> α γ -> α β

In many situations, the liftM operations can be replaced by uses of ap, which promotes function application.

       return f `ap` x1 `ap` ... `ap` xn

is equivalent to

       liftMn f x1 x2 ... xn
apply :: Applicative p => p (a->b) -> p a -> p b
filterM :: (ListSource γ, Monad β) => (α->β Bool) -> γ α -> β [α]

filterM generalizes the list-based filter function.

foldM :: Monad β => (α->γ->β α) -> α -> [γ] -> β α

foldM f a xs folds a monadic function f over the list xs.

foldM_ :: Monad α => (β->γ->α β) -> β -> [γ] -> α ()

foldM_ is the same as foldM, but discards the result

forM :: Monad α => [γ] -> (γ->α β) -> α [β]

forM xs f = mapM_ f xs

forM_ :: Monad α => [γ] -> (γ->α β) -> α ()
forever :: Monad γ => γ α -> γ β

repeat action forever

guard :: MonadZero α => Bool -> α ()

guard b is return () if b is true, and MonadZero.mzero otherwise.

liftA :: Applicative f => (a->b) -> f a -> f b
liftA2 :: Applicative f => (a->b->c) -> f a -> f b -> f c
liftA3 :: Applicative f => (a->b->c->d) -> f a -> f b -> f c -> f d
liftA4 :: Applicative f => (a->b->c->d->e) -> f a -> f b -> f c -> f d -> f e
liftA5 :: Applicative f => (a->b->c->d->e->g) -> f a -> f b -> f c -> f d -> f e -> f g
liftM :: Monad m => (a->b) -> m a -> m b

Promote a function to a monad.

liftM2 :: Monad γ => (α->δ->β) -> γ α -> γ δ -> γ β

Promote a function to a monad, scanning the monadic arguments from left to right. For example,

    liftM2 (+) [0,1] [0,2] = [0,2,1,3]
    liftM2 (+) (Just 1) Nothing = Nothing   
liftM3 :: Monad β => (δ->α->ε->γ) -> β δ -> β α -> β ε -> β γ

Promote a function to a monad, scanning the monadic arguments from left to right (cf. liftM2).

liftM4 :: Monad β => (δ->α->ε->ζ->γ) -> β δ -> β α -> β ε -> β ζ -> β γ

Promote a function to a monad, scanning the monadic arguments from left to right (cf. liftM2).

liftM5 :: Monad β => (δ->α->ζ->ε->η->γ) -> β δ -> β α -> β ζ -> β ε -> β η -> β γ

Promote a function to a monad, scanning the monadic arguments from left to right (cf. liftM2).

mapAndUnzipM :: Monad β => (α->β (γ, δ)) -> [α] -> β ([γ], [δ])

The mapAndUnzipM function maps its first argument over a list, returning the result as a pair of lists. This function is mainly used with complicated data structures or a state-transforming monad.

mapM :: Monad α => (γ->α β) -> [γ] -> α [β]

mapM f is equivalent to sequence • map f

mapM_ :: Monad α => (γ->α β) -> [γ] -> α ()

mapM_ f is equivalent to sequence_ • map f

msum :: MonadPlus α => [α β] -> α β

msum generalizes the list-based concat function.

replicateM :: Monad m => Int -> m a -> m [a]

replicateM n act performs the action n times, gathering the results.

replicateM_ :: Monad m => Int -> m a -> m ()

Like replicateM, but discards the result.

sequence :: (Monad β, ListSource γ) => γ (β α) -> β [α]

Turn a list of monadic values [m a] into a monadic value with a list m [a]

 sequence [Just 1, Just 3, Just 2] = Just [1,2,3]

This version of sequence runs in constant stack space, but needs heap space proportional to the size of the input list.

sequence_ :: (Monad β, ListSource γ) => γ (β α) -> β ()

foldr (Monad.>>) over a list of monadic values for side effects

unless :: Applicative α => Bool -> α () -> α ()

opposite of when

void :: Functor α => α β -> α ()

discard or ignore result of evaluation, such as the return value of an IO action.

when :: Applicative α => Bool -> α () -> α ()

when condition monadic returns /action/ of type Monad m => m () if /condition/ is true, otherwise Applicative.return ().

zipWithM :: Monad β => (α->δ->β γ) -> [α] -> [δ] -> β [γ]

The zipWithM function generalizes zipWith to arbitrary monads.

zipWithM_ :: Monad β => (α->δ->β γ) -> [α] -> [δ] -> β ()

zipWithM_ is the extension of zipWithM which ignores the final result.

Functions and Values by Type

String -> Either String α

MonadFail_Either.fail

String -> [α]

MonadFail_[].fail

[[α]] -> [α]

Monad_[].join

[α] -> [α] -> [α]

MonadPlus_[].mplus

α -> [α]

Monad_[].return

Applicative α => Bool -> α () -> α ()

unless, when

MonadZero α => Bool -> α ()

guard

[α]

MonadPlus_[].mzero

(α->β) -> [α] -> [β]

Functor_[].fmap

Either α (Either α β) -> Either α β

Monad_Either.join

ST α (ST α β) -> ST α β

Monad_ST.join

State α (State α β) -> State α β

Monad_State.join

[α->β] -> [α] -> [β]

Monad_[].<*>

[α] -> (α->[β]) -> [β]

Monad_[].>>=

[α] -> [β] -> [α]

Monad_[].<*

[α] -> [β] -> [β]

Monad_[].*>, Monad_[].>>

α -> Either β α

Monad_Either.return

Applicative p => a -> p a

Applicative.return

Cloneable f => Frozen f -> Mutable f s

Cloneable.thaw

Cloneable f => f s -> ST s (Frozen f)

Cloneable.freeze

Freezable f => Frozen f -> Mutable f s

Freezable.thaw

Freezable f => f s -> ST s (Frozen f)

Freezable.our, Freezable.freeze

Functor α => α β -> α ()

void

Monad m => m (m a) -> m a

Monad.join

Monad m => Int -> m a -> m [a]

replicateM

Monad m => Int -> m a -> m ()

replicateM_

MonadFail m => String -> m a

MonadFail.fail

MonadOr mo => mo a -> mo a -> mo a

MonadOr.orElse

MonadPlus mp => mp a -> mp a -> mp a

MonadPlus.mplus

MonadPlus α => [α β] -> α β

msum

Serializable f => Frozen f -> Mutable f s

Serializable.thaw

Serializable f => f s -> ST s (Frozen f)

Serializable.freeze

MonadZero mz => mz a

MonadZero.mzero

(γ->α) -> (β, γ) -> (β, α)

Functor_(,).fmap

(γ->α) -> Either β γ -> Either β α

Monad_Either.fmap

(γ->α) -> ST β γ -> ST β α

Monad_ST.fmap

(γ->α) -> State β γ -> State β α

Monad_State.fmap

Either β (γ->α) -> Either β γ -> Either β α

Monad_Either.<*>

Either β γ -> (γ->Either β α) -> Either β α

Monad_Either.>>=

Either β γ -> Either β α -> Either β α

Monad_Either.>>, Monad_Either.*>

Either β γ -> Either β α -> Either β γ

Monad_Either.<*

ST β (γ->α) -> ST β γ -> ST β α

Monad_ST.<*>

ST β γ -> ST β α -> ST β α

Monad_ST.>>, Monad_ST.*>

ST β γ -> ST β α -> ST β γ

Monad_ST.<*

State β (γ->α) -> State β γ -> State β α

Monad_State.<*>

State β γ -> State β α -> State β α

Monad_State.*>

State β γ -> State β α -> State β γ

Monad_State.<*

(ListSource γ, Monad β) => (α->β Bool) -> γ α -> β [α]

filterM

Applicative f => (a->b) -> f a -> f b

liftA

Applicative p => p (a->b) -> p a -> p b

apply, Applicative.<*>

Applicative p => p a -> p b -> p a

Applicative.<*

Applicative p => p a -> p b -> p b

Applicative.*>

Cloneable f => f a -> f b

Cloneable.clone

Freezable f => f s -> (Frozen f->a) -> ST s a

Freezable.withFrozen

Functor f => (a->b) -> f a -> f b

<$>, Functor.fmap

Monad m => (a->b) -> m a -> m b

liftM, Monad.fmap

Monad m => m (a->b) -> m a -> m b

Monad.<*>

Monad m => m a -> (a->m b) -> m b

Monad.>>=

Monad m => m a -> m b -> m b

Monad.>>

Monad α => (β->γ->α β) -> β -> [γ] -> α ()

foldM_

Monad α => (γ->α β) -> [γ] -> α [β]

mapM

Monad α => (γ->α β) -> [γ] -> α ()

mapM_

Monad α => [γ] -> (γ->α β) -> α [β]

forM

Monad α => [γ] -> (γ->α β) -> α ()

forM_

Monad α => α (γ->β) -> α γ -> α β

ap

Monad β => (α->γ->β α) -> α -> [γ] -> β α

foldM

(Monad β, ListSource γ) => γ (β α) -> β [α]

sequence

(Monad β, ListSource γ) => γ (β α) -> β ()

sequence_

Monad γ => (α->γ β) -> γ α -> γ β

=<<

Monad γ => γ α -> γ β

forever

Serializable f => f a -> f b

Serializable.copySerializable

(δ->α) -> (γ, β, δ) -> (γ, β, α)

Functor_(,,).fmap

Applicative f => (a->b->c) -> f a -> f b -> f c

liftA2

Monad α => (δ->α β) -> (β->α γ) -> δ -> α γ

>=>

Monad β => (α->δ->β γ) -> [α] -> [δ] -> β [γ]

zipWithM

Monad β => (α->δ->β γ) -> [α] -> [δ] -> β ()

zipWithM_

Monad β => (α->β (γ, δ)) -> [α] -> β ([γ], [δ])

mapAndUnzipM

Monad β => (α->β γ) -> (δ->β α) -> δ -> β γ

<=<

Monad γ => (α->δ->β) -> γ α -> γ δ -> γ β

liftM2

Applicative f => (a->b->c->d) -> f a -> f b -> f c -> f d

liftA3

Monad β => (δ->α->ε->γ) -> β δ -> β α -> β ε -> β γ

liftM3

Applicative f => (a->b->c->d->e) -> f a -> f b -> f c -> f d -> f e

liftA4

Monad β => (δ->α->ε->ζ->γ) -> β δ -> β α -> β ε -> β ζ -> β γ

liftM4

Applicative f => (a->b->c->d->e->g) -> f a -> f b -> f c -> f d -> f e -> f g

liftA5

Monad β => (δ->α->ζ->ε->η->γ) -> β δ -> β α -> β ζ -> β ε -> β η -> β γ

liftM5

Valid HTML 4.01 Strict