\documentclass[a4paper]{report}
\usepackage{amsmath}
\usepackage{color}

\begin{document}
\title{Mufasa PascalScript Handbook}
\author{Merlijn Wajer \and Raymond van Veneti\"{e}
        \and Benjamin J. Land \and Nielsie95}

\definecolor{typeGreen}{rgb}{0.0, 0.6, 0.0}
\definecolor{typeRed}{rgb}{0.6, 0.0, 0.0}

% Few defines to make methods easier.
% Most func/proc  definitions still don't use this...
\def\pproc{\textbf{procedure}}
\def\pfunc{\textbf{function}}
\newcommand{\pvtype}[1]{{\color{typeGreen}{#1}};}
\newcommand{\pvtypel}[1]{{\color{typeGreen}{#1}}}
\newcommand{\pvname}[1]{{\color{typeRed}{#1}}:}
\newcommand{\mname}[1]{{\color{blue}{#1}}}
\newcommand{\pvtotal}[2]{{\pvname{#1}} {\pvtype{#2}}} %this might be better?


\maketitle
\tableofcontents

\chapter{Foreword}

This document provides a simple but helpful explanation on every function that
the Mufasa macro library exports to it's Interpreter, PS\footnote{Pascal
Script}. For a real in depth explanation, the Mufasa Handbook would be a better
place to look.

\chapter{Exceptions}

\section{Motivation}
Mufasa takes debugging to a new level by using exceptions for error handling,
this allows you to even catch possible errors in your script, thus allowing
the script to continue it's exection. We strongly believe Exceptions are the
way to go. They were implemented for a reason.

\section{When do we throw Exceptions}

There are a lot of occasions where Mufasa may throw exceptions.

Consider the following program:

\begin{verbatim}
program new;
var
  bmp:integer;
  x, y:integer;
begin
  bmp:=bitmapfromstring(200, 200, '');
  x := -1;
  y := -1;
  fastsetpixel(bmp, x, y, clwhite);
end.
\end{verbatim}

Now, when we execute this with MML, we get this:

\begin{verbatim}
Error: Exception: You are accessing an invalid point, (-1,-1) at bitmap[0] at line 8
\end{verbatim}

Further expanding the example:
\begin{verbatim}
program new;
var
  bmp:integer;
  x, y:integer;
begin
  bmp:=bitmapfromstring(200, 200, '');
  x := -1;
  y := -1;
  try
  	fastsetpixel(bmp, x, y, clwhite);
  except
  	writeln('We failed to do a setpixel with x = ' + inttostr(x) + 
			', y = ' + inttostr(y));
  end;
end.

\end{verbatim}

Results in:

\begin{verbatim}
Compiled succesfully in 8 ms.
We failed to do a setpixel with x = .-1, y = -1
Succesfully executed
\end{verbatim}

\subsection{Going beyond script debugging}
Exceptions are even in the very core of Mufasa. This greatly improves
debugging in general, as we will also be able to easily spot errors in Mufasa.
When they occured, what the values of the variables were, et cetera.

Let's look at a function known as ReturnData(), which returns the client data.
It for example checks if the points that are passed are consistent.
If they are not, an Exception is thrown. If Mufasa does not catch that 
particular Exception\footnote{Which it doesn't, as a feature.}, then it will
be thrown in your script. This will indicate that somehow ReturnData got
invalid coordinates. Usually this Exception is not throw, as other functions
also check their input for sanity, and then it is possible to throw a more
detailed exception.

\subsection{How to Handle Exceptions}

An exception is handled with a \textbf{try} ... \textbf{except}
... \textbf{finally} statement.
See the example in the previous section for more details.

\chapter{Input}

\section{Mouse}

\subsection{Types}

A few variables are exported for working with Mufasa Mouse Functions.

TClickType, which defines the click type.
\begin{itemize}
	\item \textbf{mouse\_Right} = 0
	\item \textbf{mouse\_Left} = 1
	\item \textbf{mouse\_Middle} = 2
\end{itemize}

TMousePress, which defines if the mouse button is to be down or up.
\begin{itemize}
	\item \textbf{mouse\_Up}
	\item \textbf{mouse\_Down}
\end{itemize}

%  TClickType = (mouse_Left, mouse_Right, mouse_Middle);
%  TMousePress = (mouse_Down, mouse_Up);                

\subsection{MoveMouse}
\pproc \mname{MoveMouse}(\textbf{in } \pvname{x, y} \pvtypel{Integer});

MoveMouse moves the mouse pointer to the specified x and y coordinates.

\subsection{GetMousePos}
\pproc \mname{GetMousePos}(\textbf{out } \pvname{x, y} \pvtypel{Integer});

GetMousePos returns the current position of the mouse in \textbf{x} and
\textbf{y}.

\subsection{HoldMouse}
\pproc \mname{HoldMouse}(\pvname{x, y} \pvtype{Integer} \pvname{clickType}
\pvtypel{TClickType})

HoldMouse holds the given mouse button (clickType) down at the specified \textbf{x}, \textbf{y} 
coordinate. If the mouse if not at the given \textbf{x}, \textbf{y} yet, the mouse position
will be set to \textbf{x}, \textbf{y}.

\subsection{ReleaseMouse}
\pproc \mname{ReleaseMouse}(\pvname{x, y} \pvtype{Integer} \pvname{clickType} \pvtypel{TClickType});

ReleaseMouse releases the given mouse button (clickType) at the specified \textbf{x}, \textbf{y} 
coordinate. If the mouse if not at the given \textbf{x}, \textbf{y} yet, the mouse position
will be set to \textbf{x}, \textbf{y}.

\subsection{ClickMouse}
\pproc \mname{ClickMouse}(\pvname{x, y} \pvtype{Integer} \pvname{clickType}
\pvtypel{TClickType});

ClickMouse performs a click with the given mouse button (clickType) at the
specified x, y coordinate.

\section{Keyboard}

The Keyboard functions in Mufasa are listed here.
Most of them are quite basic and can use some improvement.

\subsection{Types}

Most of the low level Keyboard functions use Virtual Keys.

\subsection{Virtual Keys}

Virtual Keys originate from MS Windows, and we've added support for them.
Virtual Keys also work on non-Windows operating systems.

\begin{itemize}
\item   UNKNOWN: 0
\item   LBUTTON: 1
\item   RBUTTON: 2
\item   CANCEL: 3
\item   MBUTTON: 4
\item   XBUTTON1: 5
\item   XBUTTON2: 6
\item   BACK: 8
\item   TAB: 9
\item   CLEAR: 12
\item   RETURN: 13
\item   SHIFT: 16
\item   CONTROL: 17
\item   MENU: 18
\item   PAUSE: 19
\item   CAPITAL: 20
\item   KANA: 21
\item   HANGUL: 21
\item   JUNJA: 23
\item   FINAL: 24
\item   HANJA: 25
\item   KANJI: 25
\item   ESCAPE: 27
\item   CONVERT: 28
\item   NONCONVERT: 29
\item   ACCEPT: 30
\item   MODECHANGE: 31
\item   SPACE: 32
\item   PRIOR: 33
\item   NEXT: 34
\item   END: 35
\item   HOME: 36
\item   LEFT: 37
\item   UP: 38
\item   RIGHT: 39
\item   DOWN: 40
\item   SELECT: 41
\item   PRINT: 42
\item   EXECUTE: 43
\item   SNAPSHOT: 44
\item   INSERT: 45
\item   DELETE: 46
\item   HELP: 47
\item   0: \$30
\item   1: \$31
\item   2: \$32
\item   3: \$33
\item   4: \$34
\item   5: \$35
\item   6: \$36
\item   7: \$37
\item   8: \$38
\item   9: \$39
\item   A: \$41
\item   B: \$42
\item   C: \$43
\item   D: \$44
\item   E: \$45
\item   F: \$46
\item   G: \$47
\item   H: \$48
\item   I: \$49
\item   J: \$4A
\item   K: \$4B
\item   L: \$4C
\item   M: \$4D
\item   N: \$4E
\item   O: \$4F
\item   P: \$50
\item   Q: \$51
\item   R: \$52
\item   S: \$53
\item   T: \$54
\item   U: \$55
\item   V: \$56
\item   W: \$57
\item   X: \$58
\item   Y: \$59
\item   Z: \$5A
\item   LWIN: \$5B
\item   RWIN: \$5C
\item   APPS: \$5D
\item   SLEEP: \$5F
\item   NUMPAD0: 96
\item   NUMPAD1: 97
\item   NUMPAD2: 98
\item   NUMPAD3: 99
\item   NUMPAD4: 100
\item   NUMPAD5: 101
\item   NUMPAD6: 102
\item   NUMPAD7: 103
\item   NUMPAD8: 104
\item   NUMPAD9: 105
\item   MULTIPLY: 106
\item   ADD: 107
\item   SEPARATOR: 108
\item   SUBTRACT: 109
\item   DECIMAL: 110
\item   DIVIDE: 111
\item   F1: 112
\item   F2: 113
\item   F3: 114
\item   F4: 115
\item   F5: 116
\item   F6: 117
\item   F7: 118
\item   F8: 119
\item   F9: 120
\item   F10: 121
\item   F11: 122
\item   F12: 123
\item   F13: 124
\item   F14: 125
\item   F15: 126
\item   F16: 127
\item   F17: 128
\item   F18: 129
\item   F19: 130
\item   F20: 131
\item   F21: 132
\item   F22: 133
\item   F23: 134
\item   F24: 135
\item   NUMLOCK: \$90
\item   SCROLL: \$91
\item   LSHIFT: \$A0
\item   RSHIFT: \$A1
\item   LCONTROL: \$A2
\item   RCONTROL: \$A3
\item   LMENU: \$A4
\item   RMENU: \$A5
\item   BROWSER\_BACK: \$A6
\item   BROWSER\_FORWARD: \$A7
\item   BROWSER\_REFRESH: \$A8
\item   BROWSER\_STOP: \$A9
\item   BROWSER\_SEARCH: \$AA
\item   BROWSER\_FAVORITES: \$AB
\item   BROWSER\_HOME: \$AC
\item   VOLUME\_MUTE: \$AD
\item   VOLUME\_DOWN: \$AE
\item   VOLUME\_UP: \$AF
\item   MEDIA\_NEXT\_TRACK: \$B0
\item   MEDIA\_PREV\_TRACK: \$B1
\item   MEDIA\_STOP: \$B2
\item   MEDIA\_PLAY\_PAUSE: \$B3
\item   LAUNCH\_MAIL: \$B4
\item   LAUNCH\_MEDIA\_SELECT: \$B5
\item   LAUNCH\_APP1: \$B6
\item   LAUNCH\_APP2: \$B7
\item   OEM\_1: \$BA
\item   OEM\_PLUS: \$BB
\item   OEM\_COMMA: \$BC
\item   OEM\_MINUS: \$BD
\item   OEM\_PERIOD: \$BE
\item   OEM\_2: \$BF
\item   OEM\_3: \$C0
\item   OEM\_4: \$DB
\item   OEM\_5: \$DC
\item   OEM\_6: \$DD
\item   OEM\_7: \$DE
\item   OEM\_8: \$DF
\item   OEM\_102: \$E2
\item   PROCESSKEY: \$E7
\item   ATTN: \$F6
\item   CRSEL: \$F7
\item   EXSEL: \$F8
\item   EREOF: \$F9
\item   PLAY: \$FA
\item   ZOOM: \$FB
\item   NONAME: \$FC
\item   PA1: \$FD
\item   OEM\_CLEAR: \$FE
\item   HIGHESTVALUE: \$FE
\item   UNDEFINED: \$FF
\end{itemize}

\subsection{KeyDown}

\pproc \mname{KeyDown}(\pvname{key} \pvtypel{Word});

KeyDown sends a request to the Operating System to ``fake'' an event that
causes the Key to be ``down''.
\textbf{key} can be any Virtual Key\footnote{See the section on Virtual Keys}.

\subsubsection{Common pitfalls}

Don't forget that certain keys may require that shift, or another key,
is down as well.

\subsection{KeyUp}
\pproc \mname{KeyUp}(\pvname{key} \pvtypel{Word});

KeyUp sends a request to the Operating System to ``fake'' an event that
causes the Key to be ``up''.
\textbf{key} can be any Virtual Key.

\subsection{PressKey}

\pproc \mname{PressKey}(\pvname{key} \pvtypel{Word});

PressKey combines KeyDown and KeyUp, to fake a key press.

\subsection{SendKeys}

\pproc \mname{SendKeys}(\pvname{s} \pvtypel{String});

SendKeys takes a string \textbf{s}, and attempts to send it's complete contents to
the client. It currently only accepts characters ranging from ``A..z''.

\subsection{IsKeyDown}
\pfunc \mname{PressKey}(\pvname{key} \pvtypel{Word}): \pvtype{Boolean}

IsKeyDown returns true if the given VK key is ``down''.

\subsection{Notes}

There is no IsKeyUp, because this can easily be generated by inverting the
result of IsKeyDown:
\begin{verbatim}
    not IsKeyDown (x)
\end{verbatim}


\chapter{Finding Routines}

\section{Colours}

\subsection{FindColor}

\pfunc \mname{FindColor} (\textbf{out} \pvname{x, y} \pvtype{Integer} \pvname{col, x1, y1, x2, y2} 
\pvtypel{Integer}): \pvtype{Boolean}

FindColor returns true if the exact color given (col) is found in the box defined by x1, y1, x2, y2.
The point is returned in x and y. It searches from the top left to the bottom right and will stop
after matching a point.

\subsection{FindColorTolerance}

\pfunc \mname{FindColorTolerance}(\textbf{out} \pvname{x, y: } \pvtype{Integer} 
\pvname{col, x1, y1, x2, y2, tol: }\pvtypel{Integer}): \pvtype{Boolean}

FindColorTolerance returns true if a colour within the given tolerance range (tol) of the given color (col)
is found in the box defined by x1, y1, x2, y2. Only the first point is returned in x and y.
Whether or not a color is within the tolerance range is determined by the CTS mode.
It searches from the top left to the bottom right and will stop after matching a point.

\subsection{FindColorsTolerance}

\pfunc \mname{FindColorsTolerance}( \textbf{out }\pvname{pts} \pvtype{TPointArray} \pvname
{col, x1, y1, x2, y2, tol} \pvtypel{Integer}): \pvtype{Boolean}

FindColorsTolerance returns true if at least one point was found. A point is found if it is within the
given tolerance range (tol) of the given color (col) and inside the box defined by x1, y1, x2, y2.
Whether or not a color is within the tolerance range is determined by the CTS mode.
It searches from the top left to the bottom right and will find all matching points in the area.

\section{Bitmaps}

% Dit doe je zelf maar

\section{DTMs}

Deformable Template Models are a special approach to finding
objects. One can specify several points, colours and tolerances
for these points.

\subsection{Types}

Mufasa's DTM type:

\begin{verbatim}
  pDTM = packed record
    l: Integer; // length
    p: TPointArray; // points
    c, t, asz, ash: TIntegerArray; // colours, tolerance, areasize/shape
    bp: Array Of Boolean; // Bad Point ( = Not Point )
    n: String; // Name
  end;              
\end{verbatim}

Deprecated DTM type:

\begin{verbatim}
  TDTMPointDef = record
    x, y, Color, Tolerance, AreaSize, AreaShape: integer;
  end;

  TDTMPointDefArray = Array Of TDTMPointDef;

  TDTM = record
    MainPoint: TDTMPointDef;
    SubPoints: TDTMPointDefArray;
  end;    
\end{verbatim}

\subsection{FindDTM}


\pfunc \mname{FindDTM}(\pvname{DTM}\pvtype{Integer} \textbf{out}
\pvname{x, y} \pvtype{Integer} \pvname{x1, y1, x2, y2} \pvtypel{Integer}):
\pvtype{Boolean}

FindDTM is the most basic DTM finding function. It takes a box to search in,
defined by x1, y1, x2, y2; and if the DTM is found, it will set \textbf{x} and 
\textbf{y} to the coordinate the DTM was found at and it will also return true. 
Else, it returns false. Once a DTM is found, it will stop searching. In other words; it always returns
the first found DTM.

\subsection{FindDTMs}

\pfunc \mname{FindDTMs}(\pvname{DTM}\pvtype{Integer} \textbf{out} \pvname{Points}
\pvtype{TPointArray} \pvname{x1, y1, x2, y2} \pvtypel{Integer}):
\pvtype{Boolean}

FindDTMs is like FindDTM, but it returns an array of \textbf{x} and \textbf{y}, as the
\textbf{TPointArray} type.

\subsection{FindDTMRotatedSE}
\pfunc \mname{FindDTMRotatedSE}(\pvname{DTM}\pvtype{Integer} \textbf{out }
\pvname{x, y} \pvtype{Integer} \pvname{x1, y1, x2, y2} \pvtype{Integer}
\pvname{sAngle, eAngle, aStep} \pvtype{Extended} \textbf{out}
\pvname{aFound} \pvtypel{Extended}): \pvtype{Boolean}

FindDTMRotatedSE is behaves like FindDTM. Only, it will rotate the DTM between 
sAngle and eAngle by aStep each time. It will also return the angle which the
DTM was found at. Start rotating at StartAngle.

\subsection{FindDTMRotatedAlternating}
\pfunc \mname{FindDTMRotatedAlternating}(\pvname{DTM}\pvtype{Integer}
\textbf{out }
\pvname{x, y} \pvtype{Integer} \pvname{x1, y1, x2, y2} \pvtype{Integer}
\pvname{sAngle, eAngle, aStep} \pvtype{Extended} \textbf{out}
\pvname{aFound} \pvtypel{Extended}): \pvtype{Boolean}

FindDTMRotated is behaves like FindDTM. Only, it will rotate the DTM between 
sAngle and eAngle by aStep each time. It will also return the angle which the
DTM was found at. Starts at 0 degrees and alternatives between - and + aStep to search for the DTM.

\subsection{FindDTMsRotatedSE}
\pfunc \mname{FindDTMsRotatedSE}(\pvname{DTM}\pvtype{Integer} \textbf{var}
\pvname{Points} \pvtype{TPointArray} \pvname{x1, y1, x2, y2} \pvtype{Integer}
\pvname{sAngle, eAngle, aStep} \pvtype{Extended} \textbf{out}
\pvname{aFound} \pvtypel{T2DExtendedArray}): \pvtype{Boolean}

FindDTMsRotatedSE behaves like FindRotatedDTMSE, but finds all DTM occurances.
Since one point can be found on several angles, aFound is a 2d array.

\subsection{FindDTMsRotatedAlternating}
\pfunc \mname{FindDTMsRotatedAlternating}(\pvname{DTM}\pvtype{Integer} \textbf{var}
\pvname{Points} \pvtype{TPointArray} \pvname{x1, y1, x2, y2} \pvtype{Integer}
\pvname{sAngle, eAngle, aStep} \pvtype{Extended} \textbf{out}
\pvname{aFound} \pvtypel{T2DExtendedArray}): \pvtype{Boolean}

FindDTMsRotatedAlternating behaves like FindRotatedDTMAlternating,
but finds all DTM occurances.
Since one point can be found on several angles, aFound is a 2d array.

\subsection{DTMFromString}

DTMFromString creates a DTM from a string. The string must represent a dtm,
in a compressed state. Use tools like the DTM Editor or simply DTMToString to
turn your dtm into a string.

\subsection{DTMToString}

Turns the given DTM into a compressed string.

\subsection{AddDTM}

\subsection{FreeDTM}
\pproc ps\_FreeDTM(\pvname{DTM}\pvtype{Integer})

FreeDTM frees a DTM with the given index \textbf{DTM}. If it does not exist, an
exception is raised.

\subsection{GetDTM}

\subsection{tDTMtopDTM}

Convert a TDTM to a pDTM.

\subsection{pDTMtopDTM}

Convert a pDTM to a TDTM.

\chapter{OCR}

\section{Finding text}

\section{Identifying text}

\subsection{BitmapFromText}
\subsection{MaskFromText}
\subsection{TPAFromText}

\subsection{rs\_GetUpText}

rs\_GetUpText is a Runescape(tm)\footnote{http://www.runescape.com} specific function. It reads the text called
``uptext'' from the client, and returns the read string.

\subsection{rs\_GetUpTextAt}

rs\_GetUpTextAt is similar to rs\_GetUpText in all but one way, it allows you to
specify where to search for the ``uptext''.

\subsection{GetTextAt}

GetTextAt returns the text at the given X, Y.
minvspacing and maxvspacing define the minimum and maximum vertical spacing
between characters in the font, hspacing is the minimal space to split
characters on. If it is, for example, 0, and ``i'' will be split into two
characters.


%TODO: colours
\begin{verbatim}
function GetTextAt(atX, atY, minvspacing, maxvspacing, hspacing, color, tol, len: integer; font: string): string;  
\end{verbatim}

\chapter{Clients}

\section{Window}
Simba can target running applicationsa/applets on your computer. 
You simply use the crosshair to select the client, and it will then read and
send all its data from and to that application. Simba has also split up its
``Key and Mouse'' input and its ``Data Target``, which means you can send
mouse events to one window, while reading data from another.

\section{Bitmaps and other Raw Data}

Simba can also target data that is loaded in memory. Arrays, bitmaps and data
pointers. Obviously if you load any of these with Simba any mouse and key
events will not be send to that target, as it has no means of communicating
with your devices. Most likely mouse and key events will still be send to the
previous target.

% Complete TODO.
\section{Functions provided}

\subsection{GetClientDimensions}

GetClientDimensions returns the width and height of the current target.

\subsection{ActivateClient}

This functies tries to bring the current target to the front.
This will only work if the target is a System Window. When a bitmap is set as a
target, or a pointer to data, then it will not work.

\subsection{IsTargetValid}

Returns if the target is valid. For example, a window that does not\footnote{or
no longer} exists, is invalid. A bitmap that is still loaded and set as target,
or a window that still exists is valid.

\subsection{SetTargetBitmap}

Set the Target for all finding operations to this bitmap.

\subsection{SetImageTarget}

Set the target for all the finding.

\subsection{SetTargetArray}

Set a target array which is to be used as data for finding.

\subsection{SetEIOSTarget}

\subsection{SetKeyMouseTarget}

Set the target Window (Bitmaps and Arrays don't handle user input) to use for
all the input functions.

\subsection{GetImageTarget}

Returnsthe currently set target for finding.

\subsection{GetKeyMouseTarget}

Returs the currently set target for input operations.

\subsection{FreeTarget}

Free the passed target.

\section{Freeze and Unfreeze}

\subsection{Concept}

Freeze is an interesting concept. If one calls Freeze, the data that is
\textbf{currently} in the finder target is stored, and the finder target is set
to this data. This basically implies that while unfreeze is not called, you will
be looking at the client data the way it was when you called freeze. This
notably speeds up finding functions, as retreival of the data is instantly
(Simba owns the data). So if you plan to do a lot of finding functions and want
to analyse an exact frame, you should check out this functionality.

\subsection{Freeze}

Freeze the current client data. For more information see Concept.

\subsection{Unfreeze} 

Unfreeze the stored finder data. The finder target used before Freeze was called
will be restored, and used again as finder target. So calling
\begin{verbatim}
Freeze;
<stuff here>
Unfreeze;
\end{verbatim}
will not affect your finder target outside \textbf{<stuff here>}

% Files
\chapter{Files and Web}

\section{Files}

Files are used to load and save data to the hard drive.
Simba provides several functions to access files - that is, read
from them and write to them.

\subsection{CreateFile}

CreateFile creates a file. It will only create
the file if ti doesn't already exist.

Events called:
\begin{itemize}
\item WriteFileEvent
\end{itemize}

\subsection{OpenFile}

Opens a file for reading.

Events called:
\begin{itemize}
\item ReadFileEvent
\end{itemize}
\subsection{RewriteFile}

Rewrite files opens a file for reading and writing, but will remove all the
contents of a file. To open a file for appending, use AppendFile.

Events called:
\begin{itemize}
\item WriteFileEvent
\end{itemize}
\subsection{AppendFile}
AppendFile opens a file for reading and writing, and will not remove the
contents of the file.

Events called:
\begin{itemize}
\item WriteFileEvent
\end{itemize}
\subsection{CloseFile}

CloseFile closes the given file.

\subsection{EndOfFile}

EndOfFile returns true if the character pointer in the file has reached the end
of the file.

\subsection{FileSize}

FileSize returns the length of the file in bytes.

\subsection{ReadFileString}

ReadFileString reads a string from a file.

\subsection{WriteFileString}

WriteFileString writes a string to a file

\subsection{SetFileCharPointer}

Set the char pointer to a specific position.

\subsection{FilePointerPos}

Get the position of the char pointer.

\subsection{DirectoryExists}

Returns true if the directory exists.

\subsection{FileExists}

Returns true if the file exists.

\subsection{WriteINI}
\subsection{ReadINI}
\subsection{DeleteINI}

\section{Web}

\subsection{OpenWebPage}

\chapter{Point Sorting and Math}
\section{Sorting functions}
Wizzyplugin stuff

\section{Math}

\chapter{Easter Eggs}
\section{Easter egg 1}
Nothing here! Do you really think we document Easter eggs?
????

HakunaMatata!




\end{document}
