texlive[57325] Master/texmf-dist: chickenize (4jan21)

commits+karl at tug.org commits+karl at tug.org
Mon Jan 4 22:58:54 CET 2021


Revision: 57325
          http://tug.org/svn/texlive?view=revision&revision=57325
Author:   karl
Date:     2021-01-04 22:58:54 +0100 (Mon, 04 Jan 2021)
Log Message:
-----------
chickenize (4jan21)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/luatex/chickenize/README.md
    trunk/Master/texmf-dist/doc/luatex/chickenize/chickenize.pdf
    trunk/Master/texmf-dist/source/luatex/chickenize/chickenize.dtx
    trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.lua
    trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.sty
    trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.tex

Modified: trunk/Master/texmf-dist/doc/luatex/chickenize/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/chickenize/README.md	2021-01-04 21:52:06 UTC (rev 57324)
+++ trunk/Master/texmf-dist/doc/luatex/chickenize/README.md	2021-01-04 21:58:54 UTC (rev 57325)
@@ -6,7 +6,7 @@
   chickenize.sty  (LaTeX user interface)
   chickenize.lua  (Lua package code) [does the actual work]
 
-You need an up-to-date TeX Live (2017, if possible) to use this package. Maybe a full MiKTeX will will also work. (Not tested!) Lua\TeX > 1.0.4 is required for some features since the corresponding syntax has changed!
+You need an up-to-date TeX Live (2020, if possible) to use this package. Maybe a full MiKTeX will also work. (Not tested!) Lua\TeX > 1.0.4 is required for some features since the corresponding syntax has changed; tested with Lua\TeX 1.12.0 (TeX Live 2020)
 
 For any comments or suggestions, contact me:
 arno dot trautmann at gmx dot de
@@ -13,7 +13,7 @@
 
 Hope you have fun with this package!
 
-This package is copyright © 2017 Arno L. Trautmann. It may be distributed and/or
+This package is copyright © 2021 Arno L. Trautmann. It may be distributed and/or
 modified under the conditions of the LaTeX Project Public License, either version 1.3c
 of this license or (at your option) any later version. This work has the LPPL mainten-
 ance status ‘maintained’.

Modified: trunk/Master/texmf-dist/doc/luatex/chickenize/chickenize.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/luatex/chickenize/chickenize.dtx
===================================================================
--- trunk/Master/texmf-dist/source/luatex/chickenize/chickenize.dtx	2021-01-04 21:52:06 UTC (rev 57324)
+++ trunk/Master/texmf-dist/source/luatex/chickenize/chickenize.dtx	2021-01-04 21:58:54 UTC (rev 57325)
@@ -12,7 +12,7 @@
   chickenize.sty  (LaTeX user interface)
   chickenize.lua  (Lua package code) [does the actual work]
 
-You need an up-to-date TeX Live (2017, if possible) to use this package. Maybe a full MiKTeX will will also work. (Not tested!) Lua\TeX > 1.0.4 is required for some features since the corresponding syntax has changed!
+You need an up-to-date TeX Live (2020, if possible) to use this package. Maybe a full MiKTeX will also work. (Not tested!) Lua\TeX > 1.0.4 is required for some features since the corresponding syntax has changed; tested with Lua\TeX 1.12.0 (TeX Live 2020)
 
 For any comments or suggestions, contact me:
 arno dot trautmann at gmx dot de
@@ -19,7 +19,7 @@
 
 Hope you have fun with this package!
 
-This package is copyright © 2017 Arno L. Trautmann. It may be distributed and/or
+This package is copyright © 2021 Arno L. Trautmann. It may be distributed and/or
 modified under the conditions of the LaTeX Project Public License, either version 1.3c
 of this license or (at your option) any later version. This work has the LPPL mainten-
 ance status ‘maintained’.
@@ -37,7 +37,7 @@
 
 EXPERIMENTAL CODE
 
-This package is copyright © 2017 Arno L. Trautmann. It may be distributed and/or
+This package is copyright © 2021 Arno L. Trautmann. It may be distributed and/or
 modified under the conditions of the LaTeX Project Public License, either version 1.3c
 of this license or (at your option) any later version. This work has the LPPL mainten-
 ance status ‘maintained’.
@@ -79,8 +79,9 @@
   hyperref,
   longtable,
   microtype,
-  scrpage2,
-  tabu
+  scrlayer-scrpage,
+  tabu,
+  xcolor
 }
 \hypersetup{
   colorlinks=true,
@@ -103,7 +104,7 @@
 }
 
 \begin{document}
-{\hspace*{-2cm}{\scalebox{.2}{\drawchicken}
+{\hspace*{-2cm}{\scalebox{.2}{\drawchicken\hspace*{20cm}\reflectbox{\chickenizesetup{drawwidth=5}\drawunicorn}}
 \hfill\hfill \parbox{6.3cm}{{\TGChorus{\Large »\,}\large The Monty Pythons, were they \TeX~users,\\\hspace*{.2em} could have written the chickenize macro.{\Large \textit «}}\\[1ex]
 \hspace*{4cm}\small Paul Isambert}\kern-2.5cm
 }
@@ -116,7 +117,7 @@
 
 \unrainbowcolor
 
-\centerline{v0.2.5}
+\centerline{v0.3}
 \centerline{\hspace*{2cm} Arno L. Trautmann {\Large \ALT}}
 \centerline{\href{mailto:arno.trautmann at gmx.de}{arno.trautmann at gmx.de}}
 
@@ -123,7 +124,7 @@
 \kern.5cm
 \textcolor{blue}{\Large How to read this document.}
 
-This is the documentation of the package |chickenize|. It allows manipulations of any Lua\TeX\ document\footnote{The code is based on pure Lua\TeX\ features, so don't even try to use it with any other \TeX\ flavour. The package is tested under  plain Lua\TeX\ and Lua\LaTeX. If you tried using it with Con\TeX t, please share your experience, I will gladly try to make it compatible!} exploiting the possibilities offered by the callbacks that influence line breaking (and some other stuff). Most of this package's content is just for fun and educational use, but there are also some functions that can be useful in a normal document.
+This is the documentation of the package |chickenize|. It allows manipulations of any Lua\TeX\ document\footnote{The code is based on pure Lua\TeX\ features, so don't even try to use it with any other \TeX\ flavour. The package is (partially) tested under  plain Lua\TeX\ and (fully) under Lua\LaTeX. If you tried using it with Con\TeX t, please share your experience, I will gladly try to make it compatible!} exploiting the possibilities offered by the callbacks that influence line breaking (and~some other stuff). Most of this package's content is just for fun and educational use, but there are also some functions that can be useful in a normal production document.
 
 The table on the next page shortly informs you about some of your possibilities and provides links to the (documented) Lua functions. The \TeX\ interface is presented \hyperlink{texinterface}{below}.
 
@@ -131,7 +132,7 @@
 
 For a better understanding of what's going on in the code of this package, there is a small \hyperlink{tutorial}{tutorial} below that explains shortly the most important features used here.
 
-\emph{Attention}: This package is under development and everything presented here might be subject to incompatible changes. If, by any reason, you decide to use this package for an important document, please make a local copy of the source code and use that. This package will not be considered stable until it reaches at least v0.5, which might never happen.
+\emph{Attention}: This package is under development and everything presented here might be subject to incompatible changes. If, by any reason, you decide to use this package for an important document, please make a local copy of the source code and use that. This package will only be considered stable and long-term compatible should it reach version 1.0.
 
 If you have any suggestions or comments, just drop me a mail, I’ll be happy to get any response! The latet source code is hosted on github: \url{https://github.com/alt/chickenize}. Feel free to comment or report bugs there, to fork, pull, etc.
 
@@ -139,7 +140,7 @@
 
 \small\noindent
 \fbox{\parbox{.97\textwidth}{
-This package is copyright © 2017 Arno L. Trautmann. It may be distributed and/or
+This package is copyright © 2021 Arno L. Trautmann. It may be distributed and/or
 modified under the conditions of the LaTeX Project Public License, either version 1.3c
 of this license or (at your option) any later version. This work has the LPPL maintenance status ‘maintained’.}}
 \vspace*{1cm}
@@ -149,7 +150,7 @@
 \section*{\rainbowcolor For the Impatient:}
 
 \unrainbowcolor
-A small and incomplete overview of the functionalities offered by this package. I try to keep this list as complete as possible.\footnote{If you notice that something is missing, please help me improving the documentation!} Of course, the label “complete nonsense” depends on what you are doing …\\[2ex]
+A small and incomplete overview of the functionalities offered by this package.\footnote{If you notice that something is missing, please help me improving the documentation!} Of course, the label “complete nonsense” depends on what you are doing … The links will take you to the source code, while a more complete list with explanations is given \hyperlink{texinterface}{further below}.
 
 \noindent
 \tabulinesep=.5ex
@@ -178,11 +179,16 @@
 \hbox to 0cm{\bfseries \hspace*{2cm} complete nonsense} \\
 \cmidrule(lr){1-2}
 \hyperref[sec:chickenize]{chickenize} & replaces every word with “chicken” (or user-adjustable words)\\
+\hyperref[sec:drawchicken]{drawchicken} & draws a nice chicken with random, “hand-sketch”-type lines\\
+\hyperref[sec:drawcov]{drawcov} & draws a corona virus\\
+\hyperref[sec:drawchicken]{drawhorse} & draws a horse\\
 \hyperref[sec:guttenbergenize]{guttenbergenize} & deletes every quote and footnotes\\
 \hyperref[sec:hammertime]{hammertime} & U can't touch this!\\
+\hyperref[sec:italianize]{italianize} & Mamma mia!! \\
+\hyperref[sec:italianizerandwords]{italianizerandwords} & Will put the word order in a sentence at random. (tbi)\\
 \hyperref[sec:kernmanipulate]{kernmanipulate} & manipulates the kerning (tbi)\\
 \hyperref[sec:matrixize]{matrixize} & replaces every glyph by its ASCII value in binary code\\
-\hyperref[sec:randomerror]{randomerror} & just throws random (La)\TeX\ errors at random times\\
+\hyperref[sec:randomerror]{randomerror} & just throws random (La)\TeX\ errors at random times (tbi)\\
 \hyperref[sec:randomfonts]{randomfonts} & changes the font randomly between every letter\\
 \hyperref[sec:randomchars]{randomchars} & randomizes the (letters of the) whole input\\
 \bottomrule
@@ -199,23 +205,26 @@
 
 \hypertarget{texinterface}{}
 \section{Commands – How You Can Use It}
-There are several ways to make use of the \emph{chickenize} package – you can either stay on the \TeX\ side or use the Lua functions directly. In fact, the \TeX\ macros are simple wrappers around the functions.
+There are several ways to make use of the \emph{chickenize} package – you can either stay on the \TeX\ side or use the Lua functions directly. In fact, the \TeX\ macros are in most cases simple wrappers around the functions.
 
 \subsection{\TeX\ Commands – Document Wide}
 You have a number of commands at your hand, each of which does some manipulation of the input or output. In fact, the code is simple and straightforward, but be careful, especially when combining things. Apply features step by step so your brain won't be damaged …
 
-The effect of the commands can be influenced, not with arguments, but only via the |\chickenizesetup| described \hyperlink{adjustment}{below}.
+The effect of the commands can be influenced, not with arguments, but only via the |\chickenizesetup| described \hyperlink{adjustment}{below}. The links provide here will bring you to the more relevant part of the implementation, i.\,e.~either the \TeX\ code or the Lua code, depending on what is doing the main job. Mostly it's the Lua part.
 
 \begin{description}
-\def\command#1{\item[\ttfamily \color{blue} \textbackslash#1]}
+\def\command#1{\item[{\hyperref[sec:#1]{\textbackslash #1}}]}
+
 \command{allownumberincommands} Normally, you cannot use numbers as part of a control sequence (or, command) name. This makes perfect sense and is good as it is. However, just to raise awareness to this, we provide a command here that changes the chategory codes of numbers 0–9 to 11, i.\,e.~normal character. So they \emph{can} be used in command names. However, this will break many packages, so do \emph{not} expect anything to work! At least use it \emph{after} all packages are loaded.
 \command{boustrophedon} Reverts every second line. This immitates archaic greek writings where one line was right-to-left, the next one left-to-right etc.\footnote{\url{en.wikipedia.org/wiki/Boustrophedon}} Interestingly, also every glyph was adaptet to the writing direction, so all glyphs are inverted in the right-to-left lines. Actually, there are two versions of this command that differ in their implementation: |\boustrophedon| rotates the whole line, while |\boustrophedonglyphs| changes the writing direction and reverses glyph-wise. The second one takes much more compilation time, but may be more reliable. A Rongorongo\footnote{\url{en.wikipedia.org/wiki/Rongorongo}} similar style boustrophedon is available with |\boustrophedoninverse| or |\rongorongonize|, where subsequent lines are rotated by 180° instead of mirrored.
 \command{countglyphs} \textcolor{blue}{\texttt{\textbackslash countwords}} Counts every printed character (or word, respectively) that appears in anything that is a paragraph. Which is quite everything, in fact, \emph{exept} math mode! The total number of glyphs/words will be printed at the end of the log file/console output. For glyphs, also the number of use for every letter is printed separately.
 \command{chickenize} Replaces every word of the input with the word “chicken”. Maybe sometime the replacement will be made configurable, but up to now, it's only chicken. To be a bit less static, about every 10\textsuperscript{th} chicken is uppercase. However, the beginning of a sentence is not recognized automatically.\footnote{If you have a nice implementation idea, I'd love to include this!}
+\command{drawchicken} Draws a chicken based on some low-level lua drawing code. Each stroke is parameterized with random numbers so the chicken will always look different.
 \command{colorstretch} Inspired by Paul Isambert's code, this command prints boxes instead of lines. The greyness of the first (left-hand) box corresponds to the badness of the line, i.\,e. it is a measure for how much the space between words has been extended to get proper paragraph justification. The second box on the right-hand side shows the amount of stretching/shrinking when font expansion is used. Together, the greyness of both boxes indicate how well the greyness is distributed over the typeset page.
 \command{dubstepize} wub wub wub wub wub BROOOOOAR WOBBBWOBBWOBB BZZZRRRRRRROOOOOOAAAAA … (inspired by   \url{http://www.youtube.com/watch?v=ZFQ5EpO7iHk} and \url{http://www.youtube.com/watch?v=nGxpSsbodnw})
 \command{dubstepenize} synomym for |\dubstepize| as I am not sure what is the better name. Both macros are just a special case of |chickenize| with a very special “zoo” … there is no |\undubstepize| – once you go dubstep, you cannot go back …
 \command{explainbackslashes} A small list that gives hints on how many |\| characters you actually need for a backslash. I's supposed to be funny. At least my head thinks it's funny. Inspired (and mostly copied from, actually) xkcd.
+\command{gameofchicken} This is a temptative implementation of Conway's classic Game of Life. This is actually a rather powerful code with some choices for you. The game itself is played on a matrix in Lua and can be output either on the console (for quick checks) or in a pdf. The latter case needs a LaTeX document, and the packages |geometry|, |placeat|, and |graphicx|. You can choose which \LaTeX\ code represents the cells or you take the pre-defined – a \kern-1.5em\raisebox{.75ex}{\scalebox{0.075}{\drawchicken}}\kern2.5em , of course! Additionally, there are |anticells| which is basically just a second set of cells. However, they can interact, and you have full control over the rules, i.\,e.~how many neighbors a cell or anticell may need to be born, die, or stay alive, and what happens if cell and anticell collide. See below for parameters; all of them start with GOC for clarity.
 \command{gameoflife} Try it.
 \command{hammertime} STOP! —— Hammertime!
 \command{leetspeak} Translates the input into 1337 speak. If you don't understand that, lern it, n00b.
@@ -227,6 +236,7 @@
 \command{randomfonts} Changes the font randomly for every character. If no parameters are given, all fonts that have been loaded are used, especially including math fonts.
 \command{randomcolor} Does what its name says.
 \command{rainbowcolor} Instead of random colors, this command causes the text color to change gradually according to the colors of a rainbow. Do not mix this with |randomcolor|, as that doesn't make any sense.
+\command{relationship} Draws the relationship. A ship made of relations.
 \command{pancakenize} This is a dummy command that does nothing. However, every time you use it, you owe a pancake to the package author. You can either send it via mail or bring it to some (local) \TeX\ user's group meeting.
 \command{substitutewords} You have to specify pairs of words by using |\addtosubstitutions{word1}{word2}|. Then call |\substitutewords| (or the other way round, doesn't matter) and each occurance of |word1| will be replaced by |word2|. You can add replacement pairs by repeated calls to |\addtosubstitutions|. Take care! This function works with the input stream directly, therefore it does \emph{not} work on text that is inserted by macros, but it \emph{will} work on macro names itself! This way, you may use it to change macros (or environments) at will. Bug or feature? I'm not sure right now …
 \command{suppressonecharbreak} \TeX~normally does not suppress a linebreak after words with only one character (“I“, “a” etc.) This command suppresses line breaks. It is very similar to the code provided by the |impnattypo| package and based on the same ideas. However, the code in |chickenize| has been written before the author knew |impnattypo|, and the code differs a bit, might even be a bit faster. Well, test it!
@@ -267,12 +277,15 @@
 \def\default#1{\textcolor{black}{\ttfamily #1}}
 \begin{description}
 \item[\opt{randomfontslower}, \opt{randomfontsupper} = \arg{int}] These two integer variables determine the span of fonts used for the font randomization. Just play around with them a bit to find out what they are doing.
-\item[\opt{chickenstring} = \arg{table}] The string that is printed when using |\chickenize|. In fact, |chickenstring| is a table which allows for some more random action. To specify the default string, say |chickenstring[1] = 'chicken'|. For more than one animal, just step the index: |chickenstring[2] = 'rabbit'|. All existing table entries will be used randomly. Remember that we are dealing with Lua strings here, so use |' '| to mark them. (|" "| can cause problems with |babel|.)
+\subsection{options for chickenization}
+\item[\opt{chickenstring} = \arg{table}] The string that is printed when using |\chickenize|. In fact, |chickenstring| is a table which allows for some more random action. To specify the default string, say |chickenstring[1] = 'chicken'|. For more than one animal, just step the index:\\
+ |chickenstring[2] = 'rabbit'|. All existing table entries will be used randomly. Remember that we are dealing with Lua strings here, so use |' '| to mark them. (|" "| can cause problems with |babel|.)
 \item[\opt{chickenizefraction} = \arg{float} \default{1}] Gives the fraction of words that get replaced by the |chickenstring|. The default means that every word is substituted. However, with a value of, say, |0.0001|, only one word in ten thousand will be |chickenstring|. |chickenizefraction| must be specified \emph{after} |\begin{document}|. No idea, why …
-\item[\opt{chickencount} = \arg{true}] Activates the counting of substituted words and prints the number at the end of the terminal output.
-\item[\opt{colorstretchnumbers} = \arg{true} \default{0}] If true, the amount of stretching or shrinking of each line is printed into the margin as a green, red or black number.
+\item[\opt{chickencount} = \arg{bool}  \default{true}] Activates the counting of substituted words and prints the number at the end of the terminal output.
+\item[\opt{colorstretchnumbers} = \arg{bool} \default{false}] If true, the amount of stretching or shrinking of each line is printed into the margin as a green, red or black number.
 \item[\opt{chickenkernamount} = \arg{int}] The amount the kerning is set to when using |\kernmanipulate|.
 \item[\opt{chickenkerninvert} = \arg{bool}] If set to true, the kerning is inverted (to be used with |\kernmanipulate|.
+\item[\opt{drawwidth} = \arg{float} \default{1}] Defines the widths of the sloppy drawings of chickens, horses, etc.
 \item[\opt{leettable} = \arg{table}] From this table, the substitution for 1337 is taken. If you want to add or change an entry, you have to provide the unicode numbers of the characters, e.\,g. |leettable[101] = 50| replaces every |e| (|101|) with the number |3| (|50|).
 \item[\opt{uclcratio} = \arg{float} \default{0.5}] Gives the fraction of uppercases to lowercases in the |\randomuclc| mode. A higher number (up to 1) gives more uppercase letters. Guess what a lower number does.
 \item[\opt{randomcolor\_grey} = \arg{bool} \default{false}] For a printer-friendly version, this offers a grey scale instead of an rgb value for |\randomcolor|.
@@ -282,6 +295,40 @@
 \item[\opt{colorexpansion} = \arg{bool} \default{true}] If |true|, two bars are shown of which the second one denotes the font expansion. Only useful if font expansion is used. (You \emph{do} use font expansion, don’t you?)
 \end{description}
 
+\subsection{Options for Game of Chicken}
+This deserves a separate section since there are some more options and they need some explanation. So here goes the parameters for the GOC:
+\begin{description}
+\item[\opt{GOCrule\_live} = \arg{\{int,int,...\}} \default{\{2,3\}}] This gives the number of neighbors for an existing cell to keep it alive. This is a list, so you can say |\chickenizesetup{GOCrule_live = {2,3,7}| or similar.
+\item[\opt{GOCrule\_spawn} = \arg{\{int,int,...\}} \default{\{3\}}] The number of neighbors to spawn a new cell.
+\item[\opt{GOCrule\_antilive} = \arg{int} \default{2,3}] The number of neighbors to keep an anticell alive.
+\item[\opt{GOCrule\_antispawn} = \arg{int} \default{3}] The number of neighbors to spawn a new anticell.
+\item[\opt{GOCcellcode} = \arg{string} \default {"\\scalebox\{0.03\}\{\\drawchicken\}"}] The \LaTeX\ code for graphical representation of a living cell. You can use basically any valid \LaTeX\ code in here. A chicken is the default, of course.
+\item[\opt{GOCanticellcode} = \arg{string} \default {"O"}] The \LaTeX\ code for graphical representation of a living anticell.
+\item[\opt{GOCx} = \arg{int} \default{100}] Grid size in |x| direction (vertical).
+\item[\opt{GOCy} = \arg{int} \default{100}] Grid size in |y| direction (horizontal).
+\item[\opt{GOCiter} = \arg{int} \default{150}] Number of iterations to run the game.
+\item[\opt{GOC\_console} = \arg{bool} \default{false}] Activate output on the console.
+\item[\opt{GOC\_pdf} = \arg{bool} \default{true}] Activate output in the pdf.
+\item[\opt{GOCsleep} = \arg{int} \default{0}] Wait after one cycle of the game. This helps especially on the console, or for debugging. By dafault no wait time is added.
+\item[\opt{GOCmakegif} = \arg{bool} \default{false}] Produce a gif. This requires the command line tool |convert| since I use it for the creation. If you have troubles with this feel free to contact me.
+\item[\opt{GOCdensity} = \arg{int} \default{100}] Defines the density of the gif export. 100 is quite dense and it might take quite some time to get your gif done.
+\end{description}
+I recommend to use the |\gameofchicken| with a code roughly like this:
+\begin{verbatim}
+\documentclass{scrartcl}
+\usepackage{chickenize}
+\usepackage[paperwidth=10cm,paperheight=10cm,margin=5mm]{geometry}
+\usepackage{graphicx}
+\usepackage{placeat}
+\placeatsetup{final}
+\begin{document}
+\gameofchicken{GOCiter=50}
+%\gameofchicken{GOCiter=50 GOCmakegif = true}
+% \directlua{  os.execute("gwenview test.gif")} % substitute your filename
+\end{document}
+\end{verbatim}
+Keep in mind that for convenience |\gameofchicken{}| has one argument which is equivalent to using |\chickenizesetup{}| and actually just executes the argument as Lua code …
+
 \clearpage
 \part[Tutorial]{Tutorial\hypertarget{tutorial}}
 I thought it might be helpful to add a small tutorial to this package as it is mainly written with instructional purposes in mind. However, the following is \emph{not} intended as a comprehensive guide to Lua\TeX\. It's just to get an idea how things work here. For a deeper understanding of Lua\TeX\ you should consult both the Lua\TeX\ manual and some introduction into Lua proper like “Programming in Lua“. (See the section \hyperref[sec:literature]{Literature} at the end of the manual.)
@@ -308,19 +355,19 @@
 
 Callbacks are employed at several stages of \TeX's work – e.\,g. for font loading, paragraph breaking, shipping out etc. In this package, we make heavy use of mostly two callbacks: The |pre_linebreak_filter| and the |post_linebreak| filter. These callbacks are called just before (or after, resp.) \TeX\ breaks a paragraph into lines. Normally, these callbacks are empty, so they are a great playground. In between these callbacks, the |linebreak_filter| takes care of \TeX's line breaking mechanism. We won't touch this as I have no idea of what's going on there ;)
 
-\subsection{How to use a callback}
+\section{How to use a callback}
 The normal way to use a callback is to “register” a function in it. This way, the function is called each time the callback is executed. Typically, the function takes a node list (see below) as an argument, does something with it, and returns it. So a basic use of the |post_linebreak_filter| would look like:
 
 \begin{verbatim}
-function my_new_filter(head)
+function my_filter(head)
   return head
 end
 
-callback.register("post_linebreak_filter",my_new_filter)
+callback.register("post_linebreak_filter",my_filter)
 \end{verbatim}
 The function |callback.register| takes the name of the callback and your new function. However, there are some reasons why we avoid this syntax here. Instead, we rely on the function |luatexbase.add_to_callback|. This is provided by the \LaTeX\ kernel table |luatexbase| which was initially a package by Manuel Pégourié-Gonnard and Élie Roux.\footnote{Since the late 2015 release of \LaTeX, the package has not to be loaded anymore since the functionality is absorbed by the kernel. Plain\TeX~users can load the |ltluatex| file which provides the needed functionality.} This function has a more extended syntax:
 \begin{verbatim}
-luatexbase.add_to_callback("post_linebreak_filter",my_new_filter,"a fancy new filter")
+luatexbase.add_to_callback("post_linebreak_filter",my_filter,"a fancy new filter")
 \end{verbatim}
 The third argument is a name you can (have to) give to your function in the callback. That is necessary because the package also allows for removing functions from callbacks, and then you need a unique identifier for the function:
 \begin{verbatim}
@@ -334,7 +381,7 @@
 \section{Nodes}
 Essentially everything that Lua\TeX\ deals with are nodes – letters, spaces, colors, rules etc. In this package, we make heavy use of different types of nodes, so an understanding of the concept is crucial for the functionality.
 
-A node is an object that has different properties, depending on its type which is stored in its |.id| field. For example, a node of type |glyph| has |id| 27 (up to Lua\TeX~0.80., it was 37) has a number |.char| that represents its unicode codepoint, a |.font| entry that determines the font used for this glyph, a |.height|, |.depth| and |.width| etc.
+A node is an object that has different properties, depending on its type which is stored in its |.id| field. For example, a node of type |glyph| has |id| 27 (up to Lua\TeX~0.80, it was 37) has a number |.char| that represents its unicode codepoint, a |.font| entry that determines the font used for this glyph, a |.height|, |.depth| and |.width| etc.
 
 Also, a node typically has a non-empty field |.next| and |.prev|. In a list, these point to the – guess it – next or previous node. Using this, one can walk over a list of nodes step by step and manipulate the list.
 
@@ -386,11 +433,13 @@
   \bgroup%
   \fontspec{Latin Modern Sans}%
   A%
-  \kern-.4em \raisebox{.65ex}{\scalebox{0.3}{L}}%
-  \kern-.0em \raisebox{-0.98ex}{T}%
+  \kern-.375em \raisebox{.65ex}{\scalebox{0.3}{L}}%
+  \kern.03em \raisebox{-.99ex}{T}%
   \egroup%
 }
-
+%    \end{macrocode}
+% \subsection{allownumberincommands}\label{sec:allownumberincommands}
+%    \begin{macrocode}
 \def\allownumberincommands{
   \catcode`\0=11
   \catcode`\1=11
@@ -538,10 +587,41 @@
 \textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash... the true name of Ba'al, the soul-eater}
 }
 
+\def\francize{
+  \directlua{luatexbase.add_to_callback("pre_linebreak_filter",francize,"francize")}}
+
+\def\unfrancize{
+  \directlua{luatexbase.remove_from_callback("pre_linebreak_filter",francize)}}
+
 \def\gameoflife{
   Your Life Is Tetris. Stop Playing It Like Chess.
 }
+%    \end{macrocode}
+% This is just the activation of the command, the typesetting is done in the Lua code/loop as explained below. Use this macro \emph{after} |\begin{document}|. Remember that |graphicx| and |placeat| are required!
+%    \begin{macrocode}
+\def\gameofchicken#1{\directlua{
+GOCrule_live = {2,3}
+GOCrule_spawn = {3}
+GOCrule_antilive = {2,3}
+GOCrule_antispawn = {3}
+GOCcellcode = "\\scalebox{0.03}{\\drawchicken}"
+GOCcellcode = "\\scalebox{0.03}{\\drawcov}"
+GOCx = 100
+GOCy = 100
+GOCiter = 150
+GOC_console = false
+GOC_pdf = true
+GOCsleep = 0
+GOCdensity = 100
+#1
+gameofchicken()
 
+if (GOCmakegif == true) then
+  luatexbase.add_to_callback("wrapup_run",make_a_gif,"makeagif")
+end
+}}
+\let\gameofchimken\gameofchicken % yeah, that had to be.
+
 \def\guttenbergenize{ %% makes only sense when using LaTeX
   \AtBeginDocument{
     \let\grqq\relax\let\glqq\relax
@@ -577,6 +657,16 @@
 \let\hendlnize\chickenize     % homage to Hendl/Chicken
 \let\unhendlnize\unchickenize % may the soldering strength always be with him
 
+\def\italianizerandwords{
+  \directlua{luatexbase.add_to_callback("pre_linebreak_filter",italianizerandwords,"italianizerandwords")}}
+\def\unitalianizerandwords{
+  \directlua{luatexbase.remove_from_callback("pre_linebreak_filter","italianizerandwords")}}
+  
+\def\italianize{
+  \directlua{luatexbase.add_to_callback("pre_linebreak_filter",italianize,"italianize")}}
+\def\unitalianize{
+  \directlua{luatexbase.remove_from_callback("pre_linebreak_filter","italianize")}}
+ 
 % \def\itsame{
 %   \directlua{drawmario}} %%% does not exist
 
@@ -671,6 +761,13 @@
 \def\unrandomuclc{
   \directlua{luatexbase.remove_from_callback("pre_linebreak_filter","randomuclc")}}
 
+\def\relationship{%
+  \directlua{luatexbase.add_to_callback("post_linebreak_filter",cutparagraph,"cut paragraph")
+    luatexbase.add_to_callback("stop_run",missingcharstext,"charsmissing")
+    relationship()
+  }
+}
+
 \let\rongorongonize\boustrophedoninverse
 \let\unrongorongonize\unboustrophedoninverse
 
@@ -777,7 +874,8 @@
 %    \begin{macrocode}
 \def\chickenizesetup#1{\directlua{#1}}
 %    \end{macrocode}
-% The following is the very first try of implementing a small drawing language in Lua. It draws a beautiful chicken.
+% \subsection{drawchicken}\label{sec:drawchicken}
+% The following is the very first try of implementing a small drawing language in Lua. It draws a beautiful (?) chicken. TODO: Make it scalable by giving relative sizes. Also: Allow it to look to the other side if wanted.
 %    \begin{macrocode}
 \long\def\luadraw#1#2{%
   \vbox to #1bp{%
@@ -817,6 +915,105 @@
   }
 }
 %    \end{macrocode}
+% \subsection{drawcov}\label{sec:drawcov}
+% This draws a corona virus since I had some time to work on this package due to the shutdown caused by COVID-19.
+%    \begin{macrocode}
+\long\def\drawcov{
+  \luadraw{90}{
+    covbody = {200,50}
+    covbody_rad = 50
+
+    covcrown_rad = 5
+    crownno = 13
+    for i=1,crownno do
+      crownpos = {covbody[1]+1.4*covbody_rad*math.sin(2*math.pi/crownno*i),covbody[2]+1.4*covbody_rad*math.cos(2*math.pi/crownno*i)}
+      crownconnect = {covbody[1]+covbody_rad*math.sin(2*math.pi/crownno*i),covbody[2]+covbody_rad*math.cos(2*math.pi/crownno*i)}
+     sloppycircle(crownpos,covcrown_rad)
+     sloppyline(crownpos,crownconnect)
+   end
+
+    covcrown_rad = 6
+    crownno = 8
+    for i=1,crownno do
+      crownpos = {covbody[1]+0.8*covbody_rad*math.sin(2*math.pi/crownno*i),covbody[2]+0.8*covbody_rad*math.cos(2*math.pi/crownno*i)}
+      crownconnect = {covbody[1]+0.5*covbody_rad*math.sin(2*math.pi/crownno*i),covbody[2]+0.5*covbody_rad*math.cos(2*math.pi/crownno*i)}
+      sloppycircle(crownpos,covcrown_rad)
+      sloppyline(crownpos,crownconnect)
+    end
+
+    covcrown_rad = 8
+    sloppycircle(covbody,covcrown_rad)
+    sloppycircle(covbody,covbody_rad)
+    sloppyline(covbody,covbody)
+  }
+}
+%    \end{macrocode}
+% \subsection{drawhorse}\label{sec:drawhorse}
+% Well … guess what this does.
+%    \begin{macrocode}
+\long\def\drawhorse{
+  \luadraw{90}{
+    horsebod = {100,-40}
+    sloppyellipsis(horsebod,50,20)
+    horsehead = {20,0}
+    sloppyellipsis(horsehead,25,15)
+    sloppyline({35,-10},{50,-40})
+    sloppyline({45,5},{80,-25})
+    sloppyline({60,-50},{60,-90})
+    sloppyline({70,-50},{70,-90})
+    sloppyline({130,-50},{130,-90})
+    sloppyline({140,-50},{140,-90})
+    sloppyline({150,-40},{160,-60})
+    sloppyline({150,-38},{160,-58})
+    sloppyline({150,-42},{160,-62})
+    sloppyline({-5,-10},{10,-5})
+    sloppyellipsis({30,5},5,2)  %% it's an eye, aye?
+    sloppyline({27,15},{34,25})
+    sloppyline({34,25},{37,13})    
+  }
+}
+%    \end{macrocode}
+% There's also a version with a bit more … meat to the bones:
+%    \begin{macrocode}
+\long\def\drawfathorse{
+  \luadraw{90}{
+    horsebod = {100,-40}
+    sloppyellipsis(horsebod,50,40)
+    horsehead = {20,0}
+    sloppyellipsis(horsehead,25,15)
+    sloppyline({35,-10},{50,-40})
+    sloppyline({45,5},{70,-15})
+    sloppyline({60,-70},{60,-90})
+    sloppyline({70,-70},{70,-90})
+    sloppyline({130,-70},{130,-90})
+    sloppyline({140,-70},{140,-90})
+    sloppyline({150,-40},{160,-60})
+    sloppyline({150,-38},{160,-58})
+    sloppyline({150,-42},{160,-62})
+    sloppyline({-5,-10},{10,-5})
+    sloppyellipsis({30,5},5,2)  %% it's an eye, aye?
+    sloppyline({27,15},{34,25})
+    sloppyline({34,25},{37,13})    
+  }
+}
+% intentioally not documented:
+\long\def\drawunicorn{
+\color{pink!90!black}
+  \drawhorse
+  \luadraw{0}{
+    sloppyline({15,20},{15,50})
+    sloppyline({15,50},{25,20})
+  }  
+}
+\long\def\drawfatunicorn{
+\color{pink!90!black}
+  \drawfathorse
+  \luadraw{0}{
+    sloppyline({15,20},{15,50})
+    sloppyline({15,50},{25,20})
+  }  
+}
+%    \end{macrocode}
 % \iffalse
 %</tex>
 %<*package>
@@ -827,12 +1024,12 @@
 % Some code might be implemented to manipulate figures for full chickenization. However, I will \emph{not} load any packages at this place, as loading of expl3 or TikZ or whatever takes too much time for such a tiny package like this one. If you require any of the features presented here, you have to load the packages on your own. Maybe this will change.
 %    \begin{macrocode}
 \ProvidesPackage{chickenize}%
-  [2017/08/19 v0.2.5 chickenize package]
+  [2021/01/03 v0.3 chickenize package]
 \input{chickenize}
 %    \end{macrocode}
 % \subsection{Free Compliments}
 %    \begin{macrocode}
-
+% 
 %    \end{macrocode}
 % \subsection{Definition of User-Level Macros}
 % Nothing done so far, just some minor ideas. If you want to implement some cool things, contact me! :)
@@ -855,7 +1052,7 @@
 %\fi
 % \section{Lua Module}
 % \label{sec:luamodule}
-% This file contains all the necessary functions and is the actual work horse of this package. The functions are sorted strictly alphabetically (or, they \emph{should} be …) and not by sense, functionality or anything.
+% This file contains all the necessary functions and is the actual work horse of this package. The functions are sorted alphabetically (or, they \emph{should} be …) and not by sense, functionality or anything.
 % 
 % First, we set up some constants that are used by many of the following functions. These are made global so the code can be manipulated at the document level, too.
 %    \begin{macrocode}
@@ -901,8 +1098,8 @@
 chickenstring = {}
 chickenstring[1] = "chicken" -- chickenstring is a table, please remeber this!
 
-chickenizefraction = 0.5
--- set this to a small value to fool somebody, or to see if your text has been read carefully. This is also a great way to lay easter eggs for your own class / package …
+chickenizefraction = 0.5 -- set this to a small value to fool somebody,
+-- or to see if your text has been read carefully. This is also a great way to lay easter eggs for your own class / package …
 chicken_substitutions = 0 -- value to count the substituted chickens. Makes sense for testing your proofreaders.
 
 local match = unicode.utf8.match
@@ -1129,7 +1326,7 @@
 %    \begin{macrocode}
 countwords = function(head)
   for glyph in nodetraverseid(GLYPH,head) do
-    if (glyph.next.id == 10) then
+    if (glyph.next.id == GLUE) then
       wordnumber = wordnumber + 1
     end
   end
@@ -1146,7 +1343,7 @@
 
 % \subsection{detectdoublewords}\label{sec:detectdoublewords}
 %    \begin{macrocode} %% FIXME: Does this work? …
-function detectdoublewords(head)
+detectdoublewords = function(head)
   prevlastword  = {}  -- array of numbers representing the glyphs
   prevfirstword = {}
   newlastword   = {}
@@ -1161,10 +1358,128 @@
   end
 end
 
-function printdoublewords()
+printdoublewords = function()
   texio.write_nl("finished")
 end
 %    \end{macrocode}
+% \subsection{francize}\label{sec:francize}
+% This function is intentionally undocumented. It randomizes all numbers digit by digit. Why? Because.
+%    \begin{macrocode}
+francize = function(head)
+  for n in nodetraverseid(GLYPH,head) do
+    if ((n.char > 47) and (n.char < 58)) then
+      n.char = math.random(48,57)
+    end
+  end
+  return head
+end
+%    \end{macrocode}
+% \subsection{gamofchicken}\label{sec:gamofchicken}
+% The |gameofchicken| is an implementation of the Game of Life by Conway. The standard cell here is a chicken, while there are also anticells. For both you can adapt the \LaTeX\ code to represent the cells.
+% 
+% I also kick in some code to convert the pdf into a gif after the pdf has been finalized and Lua\TeX\ is about to end. This uses a system call to |convert|; especially the latter one will change. For now this is a convenient implementation for me and maybe most Linux environments to get the gif by one-click-compiling the |tex| document. 
+%    \begin{macrocode}
+function gameofchicken()
+  GOC_lifetab = {}
+  GOC_spawntab = {}
+  GOC_antilifetab = {}
+  GOC_antispawntab = {}
+  -- translate the rules into an easily-manageable table
+  for i=1,#GOCrule_live do; GOC_lifetab[GOCrule_live[i]] = true end
+  for i=1,#GOCrule_spawn do; GOC_spawntab[GOCrule_spawn[i]] = true end
+  for i=1,#GOCrule_antilive do; GOC_antilifetab[GOCrule_antilive[i]] = true end
+  for i=1,#GOCrule_antispawn do; GOC_antispawntab[GOCrule_antispawn[i]] = true end
+%    \end{macrocode}
+% Initialize the arrays for cells and anticells with zeros.
+%    \begin{macrocode}
+-- initialize the arrays
+local life = {}
+local antilife = {}
+local newlife = {}
+local newantilife = {}
+for i = 0, GOCx do life[i] = {}; newlife[i] = {} for j = 0, GOCy do life[i][j] = 0 end end
+for i = 0, GOCx do antilife[i] = {}; newantilife[i] = {} for j = 0, GOCy do antilife[i][j] = 0 end end
+%    \end{macrocode}
+% These are the functions doing the actual work, checking the neighbors and applying the rules defined above.
+%    \begin{macrocode}
+function applyruleslife(neighbors, lifeij, antineighbors, antilifeij)
+  if GOC_spawntab[neighbors] then myret = 1 else -- new cell
+  if GOC_lifetab[neighbors] and (lifeij == 1) then myret = 1 else myret =  0 end end
+  if antineighbors > 1 then myret =  0 end
+  return myret
+end
+function applyrulesantilife(neighbors, lifeij, antineighbors, antilifeij)
+  if (antineighbors == 3) then myret = 1 else -- new cell or keep cell
+  if (((antineighbors > 1) and (antineighbors < 4)) and (lifeij == 1)) then myret = 1 else myret =  0 end end
+  if neighbors > 1 then myret =  0 end
+  return myret
+end
+%    \end{macrocode}
+% Preparing the initial state with a default pattern:
+%    \begin{macrocode}
+-- prepare some special patterns as starter
+life[53][26] = 1 life[53][25] = 1 life[54][25] = 1 life[55][25] = 1 life[54][24] = 1
+%    \end{macrocode}
+% And the main loop running from here:
+%    \begin{macrocode}
+  print("start");
+  for i = 1,GOCx do
+    for j = 1,GOCy do
+      if (life[i][j]==1) then texio.write("X") else if (antilife[i][j]==1) then texio.write("O") else texio.write("_") end end
+    end
+    texio.write_nl(" ");
+  end 
+  os.sleep(GOCsleep)
+
+  for i = 0, GOCx do
+    for j = 0, GOCy do
+        newlife[i][j] = 0 -- Fill the values from the start settings here
+        newantilife[i][j] = 0 -- Fill the values from the start settings here
+    end
+  end
+
+  for k = 1,GOCiter do -- iterate over the cycles
+    texio.write_nl(k);
+    for i = 1, GOCx-1 do -- iterate over lines
+      for j = 1, GOCy-1 do -- iterate over columns -- prevent edge effects
+        local neighbors = (life[i-1][j-1] + life[i-1][j] + life[i-1][j+1] + life[i][j-1] + life[i][j+1] +  life[i+1][j-1] + life[i+1][j] + life[i+1][j+1])
+        local antineighbors = (antilife[i-1][j-1] + antilife[i-1][j] + antilife[i-1][j+1] + antilife[i][j-1] + antilife[i][j+1] +  antilife[i+1][j-1] + antilife[i+1][j] + antilife[i+1][j+1])
+
+        newlife[i][j] = applyruleslife(neighbors, life[i][j],antineighbors, antilife[i][j])
+        newantilife[i][j] = applyrulesantilife(neighbors,life[i][j], antineighbors,antilife[i][j])
+      end
+    end
+
+    for i = 1, GOCx do
+      for j = 1, GOCy do
+        life[i][j] = newlife[i][j] -- copy the values
+        antilife[i][j] = newantilife[i][j] -- copy the values
+      end
+    end
+
+    for i = 1,GOCx do
+      for j = 1,GOCy do
+        if GOC_console then
+          if (life[i][j]==1) then texio.write("X") else if (antilife[i][j]==1) then texio.write("O") else texio.write("_") end end
+        end
+        if GOC_pdf then
+          if (life[i][j]==1) then tex.print("\\placeat("..(i/10)..","..(j/10).."){"..GOCcellcode.."}") end
+          if (antilife[i][j]==1) then tex.print("\\placeat("..(i/10)..","..(j/10).."){"..GOCanticellcode.."}") end
+        end
+      end
+    end 
+    tex.print(".\\newpage")
+    os.sleep(GOCsleep)
+  end
+end --end function gameofchicken
+%    \end{macrocode}
+% The following is a function calling some tool from your operating system. This requires of course that you have them present – that should be the case on a typical Linux distribution. Take care that |convert| normally does not allow for conversion from pdf, please check that this is allowed by the rules. So this is more an example code that can help you to add it to your game so you can enjoy your chickens developing as a gif.
+%    \begin{macrocode}
+function make_a_gif()
+  os.execute("convert -verbose -dispose previous -background white -alpha remove -alpha off -density "..GOCdensity.." "..tex.jobname ..".pdf " ..tex.jobname..".gif")
+  os.execute("gwenview "..tex.jobname..".gif")
+end
+%    \end{macrocode}
 % \subsection{guttenbergenize}\label{sec:guttenbergenize}
 % A function in honor of the German politician Guttenberg.\footnote{Thanks to Jasper for bringing me to this idea!} Please do \emph{not} confuse him with the grand master Gutenberg!
 % 
@@ -1185,7 +1500,7 @@
 % \subsubsection{guttenbergenize – the function}
 %    \begin{macrocode}
 guttenbergenize_rq = function(head)
-  for n in nodetraverseid(nodeid"glyph",head) do
+  for n in nodetraverseid(GLYPH,head) do
     local i = n.char
     if quotestrings[i] then
       noderemove(head,n)
@@ -1220,6 +1535,124 @@
   return head
 end
 %    \end{macrocode}
+% \subsection{italianize}\label{sec:italianize}
+% This is inspired by some of the more melodic pronounciations of the english language. The command will add randomly an |h| in front of every word starting with a vowel or remove |h| from words starting with one. Also, it will ad randomly an |e| to words ending in consonants. This is tricky and might fail – I'm happy to receive and try to solve ayn bug reports.
+%    \begin{macrocode}
+italianizefraction = 0.5 --%% gives the amount of italianization
+mynode = nodenew(GLYPH) -- prepare a dummy glyph
+
+italianize = function(head)
+  -- skip "h/H" randomly
+  for n in node.traverse_id(GLYPH,head) do -- go through all glyphs
+      if n.prev.id ~= GLYPH then -- check if it's a word start
+      if ((n.char == 72) or (n.char == 104)) and (tex.normal_rand() < italianizefraction) then -- if it's h/H, remove randomly
+        n.prev.next = n.next
+      end
+    end
+  end
+ 
+  -- add h or H in front of vowels
+  for n in nodetraverseid(GLYPH,head) do
+    if math.random() < italianizefraction then 
+    x = n.char 
+    if x == 97 or x == 101 or x == 105 or x == 111 or x == 117 or
+       x == 65 or x ==  69 or x ==  73 or x == 79 or x == 85 then
+      if (n.prev.id == GLUE) then
+        mynode.font = n.font
+        if x > 90 then  -- lower case 
+          mynode.char = 104
+        else
+          mynode.char = 72 -- upper case – convert into lower case
+          n.char = x + 32
+        end
+          node.insert_before(head,n,node.copy(mynode))
+        end
+      end
+    end
+  end
+
+  -- add e after words, but only after consonants
+  for n in node.traverse_id(GLUE,head) do
+    if n.prev.id == GLYPH then
+    x = n.prev.char
+    -- skip vowels and randomize
+    if not(x == 97 or x == 101 or x == 105 or x == 111 or x == 117 or x == 44 or x == 46) and math.random() > 0.2 then
+        mynode.char = 101           -- it's always a lower case e, no?
+        mynode.font = n.prev.font -- adapt the current font
+        node.insert_before(head,n,node.copy(mynode)) -- insert the e in the node list
+      end
+    end
+  end
+  
+  return head
+end
+%    \end{macrocode}
+% \subsection{italianizerandwords}\label{sec:italianizerandwords}
+% This is inspired by my dearest colleagues and their artistic interpretation of the english grammar. The command will cause LuaTeX to read a sentence (i.\,e.~text until the next full stop), then randomizes the words (i.\,e.~units separated by a space) in it and throws the result back to the typesetting. Useless? Very.
+%    \begin{macrocode}
+italianizerandwords = function(head)
+words = {}
+wordnumber = 0
+-- head.next.next is the very first word. However, let's try to get the first word after the first space correct.
+  for n in nodetraverseid(GLUE,head) do -- let's try to count words by their separators
+    wordnumber = wordnumber + 1
+    if n.next then
+      words[wordnumber] = {}
+      words[wordnumber][1] = node.copy(n.next)
+
+      glyphnumber = 1
+      myglyph = n.next
+      while myglyph.next do
+        node.tail(words[wordnumber][1]).next = node.copy(myglyph.next)
+        myglyph = myglyph.next
+      end
+    end
+  print(#words) 
+  if #words > 0 then 
+  print("lengs is: ")
+  print(#words[#words])
+  end
+  end
+--myinsertnode = head.next.next -- first letter
+--node.tail(words[1][1]).next = myinsertnode.next
+--myinsertnode.next = words[1][1]
+
+  return head
+end
+
+italianize_old = function(head)
+  local wordlist = {} -- here we will store the number of words of the sentence.
+  local words = {} -- here we will store the words of the sentence.  
+  local wordnumber = 0
+  -- let's first count all words in one sentence, howboutdat?
+  wordlist[wordnumber] = 1 -- let's save the word *length* in here …
+
+ 
+  for n in nodetraverseid(GLYPH,head) do
+    if (n.next.id == GLUE) then -- this is a space
+      wordnumber = wordnumber + 1
+      wordlist[wordnumber] = 1
+      words[wordnumber] = n.next.next
+    end
+    if (n.next.id == GLYPH) then  -- it's a glyph
+    if (n.next.char == 46) then -- this is a full stop.
+      wordnumber = wordnumber + 1
+      texio.write_nl("this sentence had "..wordnumber.."words.")
+      for i=0,wordnumber-1 do
+      texio.write_nl("word "..i.." had " .. wordlist[i] .. "glyphs")
+      end
+      texio.write_nl(" ")
+      wordnumber = -1 -- to compensate the fact that the next node will be a space, this would count one word too much.
+    else
+        
+      wordlist[wordnumber] = wordlist[wordnumber] + 1 -- the current word got 1 glyph longer
+      end
+    end
+  end
+  return head
+end
+%    \end{macrocode}
+
 % \subsection{itsame}\label{sec:itsame}
 % The (very first, very basic, very stupid) code to draw a small mario. You need to input luadraw.tex or do luadraw.lua for the rectangle function.
 %    \begin{macrocode}
@@ -1342,8 +1775,8 @@
 % Why the synonym |stealsheep|? Because of a comment of Paul on the |texhax| mailing list: \url{http://tug.org/pipermail/texhax/2011-October/018374.html}
 % \subsubsection{setup of variables}
 %    \begin{macrocode}
-local letterspace_glue   = nodenew(nodeid"glue")
-local letterspace_pen    = nodenew(nodeid"penalty")
+local letterspace_glue   = nodenew(GLUE)
+local letterspace_pen    = nodenew(PENALTY)
 
 letterspace_glue.width   = tex.sp"0pt"
 letterspace_glue.stretch = tex.sp"0.5pt"
@@ -1352,8 +1785,8 @@
 % \subsubsection{function implementation}
 %    \begin{macrocode}
 letterspaceadjust = function(head)
-  for glyph in nodetraverseid(nodeid"glyph", head) do
-    if glyph.prev and (glyph.prev.id == nodeid"glyph" or glyph.prev.id == nodeid"disc" or glyph.prev.id == nodeid"kern") then
+  for glyph in nodetraverseid(GLYPH, head) do
+    if glyph.prev and (glyph.prev.id == GLYPH or glyph.prev.id == DISC or glyph.prev.id == KERN) then
       local g = nodecopy(letterspace_glue)
       nodeinsertbefore(head, glyph, g)
       nodeinsertbefore(head, g, nodecopy(letterspace_pen))
@@ -1366,9 +1799,9 @@
 % The |\text...|-version of |letterspaceadjust|. Just works, without the need to call |\letterspaceadjust| globally or anything else. Just put the |\textletterspaceadjust| around the part of text you want the function to work on. Might have problems with surrounding spacing, take care!
 %    \begin{macrocode}
 textletterspaceadjust = function(head)
-  for glyph in nodetraverseid(nodeid"glyph", head) do
+  for glyph in nodetraverseid(GLYPH, head) do
     if node.has_attribute(glyph,luatexbase.attributes.letterspaceadjustattr) then
-      if glyph.prev and (glyph.prev.id == node.id"glyph" or glyph.prev.id == node.id"disc" or glyph.prev.id == nodeid"kern") then
+      if glyph.prev and (glyph.prev.id == node.id"glyph" or glyph.prev.id == node.id"disc" or glyph.prev.id == KERN) then
         local g = node.copy(letterspace_glue)
         nodeinsertbefore(head, glyph, g)
         nodeinsertbefore(head, g, nodecopy(letterspace_pen))
@@ -1384,8 +1817,8 @@
 %    \begin{macrocode}
 matrixize = function(head)
   x = {}
-  s = nodenew(nodeid"disc")
-  for n in nodetraverseid(nodeid"glyph",head) do
+  s = nodenew(DISC)
+  for n in nodetraverseid(GLYPH,head) do
     j = n.char
     for m = 0,7 do -- stay ASCII for now
       x[7-m] = nodecopy(n) -- to get the same font etc.
@@ -1470,8 +1903,8 @@
 end
 %    \end{macrocode}
 % \subsection{randomerror}\label{sec:randomerror}
+% Not yet implemented, sorry.
 
-
 % \subsection{randomfonts}\label{sec:randomfonts}
 % Traverses the output and substitutes fonts randomly. A check is done so that the font number is existing.
 % One day, the fonts should be easily given explicitly in terms of |\bf| etc.
@@ -1600,10 +2033,69 @@
   return head
 end
 %    \end{macrocode}
-% \subsection{randomerror}\label{sec:randomerror}
+% \subsection{relationship}\label{sec:relationship}
+% It literally is what is says: A ship made of relations. Or a boat, rather. There are four parameters, |sailheight|, |mastheight|, |hullheight|, and |relnumber| which you can adjust.
 %    \begin{macrocode}
-% 
+  sailheight = 12
+  mastheight = 4
+  hullheight = 5
+  relnumber = 402
+function relationship()
+--%% check if there's a problem with any character in the current font
+  f = font.getfont(font.current())
+  fullfont = 1
+  for i = 8756,8842 do
+    if not(f.characters[i]) then texio.write_nl((i).." not available") fullfont = 0 end
+  end
+--%% store the result of the check for later, then go on to construct the ship:
+  shipheight = sailheight + mastheight + hullheight
+  tex.print("\\parshape "..(shipheight)) --%% prepare the paragraph shape ...
+  for i =1,sailheight do
+    tex.print(" "..(4.5-i/3.8).."cm "..((i-0.5)/2.5).."cm ")
+   end
+  for i =1,mastheight do
+    tex.print(" "..(3.2).."cm "..(1).."cm ")
+  end
+  for i =1,hullheight do
+    tex.print(" "..((i-1)/2).."cm "..(10-i).."cm ")
+  end
+  tex.print("\\noindent") --%% ... up to here, then insert relations
+  for i=1,relnumber do
+    tex.print("\\ \\char"..math.random(8756,8842))
+  end
+  tex.print("\\break")
+end
 %    \end{macrocode}
+% And this is a helper function to prevent too many relations to be typeset. Problem: The relations are chosen randomly, and each might take different horizontial space. So we cannot make sure the same number of lines for each version. To catch this, we typeset more lines and just remove excess lines with a simple function in our beloved |post_linebreak_filter|.
+%    \begin{macrocode}
+function cutparagraph(head)
+  local parsum = 0
+  for n in nodetraverseid(HLIST,head) do
+    parsum = parsum + 1
+    if parsum > shipheight then
+      node.remove(head,n)
+    end
+  end
+  return head
+end
+%    \end{macrocode}
+% And finally a helper function to inform our dear users that they have to use a font that actually can display all the necessary symbols.
+%    \begin{macrocode}
+function missingcharstext()
+  if (fullfont == 0) then
+  local separator     = string.rep("=", 28)
+local texiowrite_nl = texio.write_nl
+  texiowrite_nl("Output written on "..tex.jobname..".pdf ("..status.total_pages.." chicken,".." eggs).")
+  texiowrite_nl(" ")
+  texiowrite_nl(separator)
+  texiowrite_nl("CAREFUL!!")
+  texiowrite_nl("\\relationship needs special characters (unicode points 8756 to 8842)")
+  texiowrite_nl("Your font does not support all of them!")
+  texiowrite_nl("consider using another one, e.g. the XITS font supplied with TeXlive.")
+  texiowrite_nl(separator .. "\n")
+  end
+end
+%    \end{macrocode}
 % \subsection{rickroll}\label{sec:rickroll}
 % Another tribute to pop culture. Either: substitute word-by-word as in pancake. OR: substitute each link to a youtube-rickroll …
 %    \begin{macrocode}
@@ -1651,9 +2143,9 @@
 tabularasa_onlytext = false
 
 tabularasa = function(head)
-  local s = nodenew(nodeid"kern")
-  for line in nodetraverseid(nodeid"hlist",head) do
-    for n in nodetraverseid(nodeid"glyph",line.head) do
+  local s = nodenew(KERN)
+  for line in nodetraverseid(HLIST,head) do
+    for n in nodetraverseid(GLYPH,line.head) do
       if not(tabularasa_onlytext) or node.has_attribute(n,luatexbase.attributes.tabularasaattr) then
         s.kern = n.width
         nodeinsertafter(line.list,n,nodecopy(s))
@@ -1667,7 +2159,7 @@
 % \subsection{tanjanize}\label{sec:tanjanize}
 %    \begin{macrocode}
 tanjanize = function(head)
-  local s = nodenew(nodeid"kern")
+  local s = nodenew(KERN)
   local m = nodenew(GLYPH,1)
   local use_letter_i = true
   scale = nodenew(WHAT,PDF_LITERAL)
@@ -1675,8 +2167,8 @@
   scale.data  = "0.5 0 0 0.5 0 0 cm"
   scale2.data = "2   0 0 2   0 0 cm"
 
-  for line in nodetraverseid(nodeid"hlist",head) do
-    for n in nodetraverseid(nodeid"glyph",line.head) do
+  for line in nodetraverseid(HLIST,head) do
+    for n in nodetraverseid(GLYPH,line.head) do
       mimicount = 0
       tmpwidth  = 0
       while ((n.next.id == GLYPH) or (n.next.id == 11) or (n.next.id == 7) or (n.next.id == 0)) do  --find end of a word
@@ -1780,11 +2272,18 @@
     local rule_bad = nodenew(RULE)
 
     if colorexpansion then  -- if also the font expansion should be shown
+--%% here use first_glyph function!!
       local g = line.head
+n = node.first_glyph(line.head.next)
+texio.write_nl(line.head.id)
+texio.write_nl(line.head.next.id)
+texio.write_nl(line.head.next.next.id)
+texio.write_nl(n.id)
       while not(g.id == GLYPH) and (g.next) do g = g.next end -- find first glyph on line. If line is empty, no glyph:
       if (g.id == GLYPH) then                                 -- read width only if g is a glyph!
-        exp_factor = g.width / f[g.char].width
-        exp_color = colorstretch_coloroffset + (1-exp_factor)*10 .. " g"
+        exp_factor = g.expansion_factor/10000 --%% neato, luatex now directly gives me this!!
+        exp_color = colorstretch_coloroffset + (exp_factor*0.1) .. " g"
+texio.write_nl(exp_factor)
         rule_bad.width = 0.5*line.width  -- we need two rules on each line!
       end
     else
@@ -1902,10 +2401,10 @@
 %    \begin{macrocode}
 function variantjustification(head)
   math.randomseed(1)
-  for line in nodetraverseid(nodeid"hhead",head) do
+  for line in nodetraverseid(Hhead,head) do
     if (line.glue_sign == 1 and line.glue_order == 0) then -- exclude the last line!
       substitutions_wide = {} -- we store all “expandable” letters of each line
-      for n in nodetraverseid(nodeid"glyph",line.head) do
+      for n in nodetraverseid(GLYPH,line.head) do
         if (substlist[n.char]) then
           substitutions_wide[#substitutions_wide+1] = n
         end
@@ -1946,12 +2445,12 @@
 %    \begin{macrocode}
 function zebranize(head)
   zebracolor = 1
-  for line in nodetraverseid(nodeid"hhead",head) do
+  for line in nodetraverseid(Hhead,head) do
     if zebracolor == #zebracolorarray then zebracolor = 0 end
     zebracolor = zebracolor + 1
     color_push.data = zebracolorarray[zebracolor]
     line.head =     nodeinsertbefore(line.head,line.head,nodecopy(color_push))
-    for n in nodetraverseid(nodeid"glyph",line.head) do
+    for n in nodetraverseid(GLYPH,line.head) do
       if n.next then else
         nodeinsertafter(line.head,n,nodecopy(color_pull))
       end
@@ -1979,6 +2478,7 @@
 % Well, it's not the whole story so far. I plan to test some drawing using only Lua code, writing directly to the pdf file. This section will grow and get better in parallel to my understandings of what's going on. I.e. it will be very slowly … Nothing here is to be taken as good and/or correct LuaTeXing, and most code is plain ugly. However, it kind of works already {\XITS ☺}
 % \section{Drawing}
 % A \emph{very} first, experimental implementation of a drawing of a chicken. The parameters should be consistent, easy to change and that monster should look more like a cute chicken. However, it is chicken, it is Lua, so it belongs into this package. So far, all numbers and positions are hard coded, this will of course change!
+% The parameters |sloppinessh| and |sloppinessv| give the amount of sloppiness, i.\,e.~how strongly the points are “wiggled” randomly to make the drawings more dynamically. You can set them at any time in the document
 %    \begin{macrocode}
 --
 function pdf_print (...)
@@ -1988,18 +2488,31 @@
   pdf.print("\n")
 end
 
-function move (p)
-  pdf_print(p[1],p[2],"m")
+function move (p1,p2)
+  if (p2) then
+    pdf_print(p1,p2,"m")
+  else
+    pdf_print(p1[1],p1[2],"m")
+  end
 end
 
-function line (p)
-  pdf_print(p[1],p[2],"l")
+function line(p1,p2)
+  if (p2) then
+    pdf_print(p1,p2,"l")
+  else
+    pdf_print(p1[1],p1[2],"l")
+  end
 end
 
-function curve(p1,p2,p3)
+function curve(p11,p12,p21,p22,p31,p32)
+  if (p22) then
+    p1,p2,p3 = {p11,p12},{p21,p22},{p31,p32}
+  else
+    p1,p2,p3 = p11,p12,p21
+  end
   pdf_print(p1[1], p1[2],
-            p2[1], p2[2],
-            p3[1], p3[2], "c")
+              p2[1], p2[2],
+              p3[1], p3[2], "c")
 end
 
 function close ()
@@ -2006,6 +2519,11 @@
   pdf_print("h")
 end
 
+%    \end{macrocode}
+% By setting |drawwidth| to something different than 1 you can adjust the thickness of the strokes. Any stroke done with the |sloppy| functions will by varied between |0.5 drawwidth| and |1.5 drawwidth|.
+%    \begin{macrocode}
+drawwidth = 1
+
 function linewidth (w)
   pdf_print(w,"w")
 end
@@ -2029,9 +2547,12 @@
 stroke()
 end
 
+sloppynessh = 5
+sloppynessv = 5
+
 function disturb_point(point)
-  return {point[1] + math.random()*5 - 2.5,
-          point[2] + math.random()*5 - 2.5}
+  return {point[1] + (math.random() - 1/2)*sloppynessh,
+          point[2] + (math.random() - 1/2)*sloppynessv}
 end
 
 function sloppycircle(center,radius)
@@ -2047,10 +2568,27 @@
   move (right)
   curve (rightbot, leftbot, left)
   curve (lefttop, righttop, right_end)
-  linewidth(math.random()+0.5)
+  linewidth(drawwidth*(math.random()+0.5))
   stroke()
 end
 
+function sloppyellipsis(center,radiusx,radiusy)
+  local left = disturb_point({center[1] - radiusx, center[2]})
+  local lefttop = disturb_point({left[1], left[2] + 1.45*radiusy})
+  local leftbot = {lefttop[1], lefttop[2] - 2.9*radiusy}
+  local right = disturb_point({center[1] + radiusx, center[2]})
+  local righttop = disturb_point({right[1], right[2] + 1.45*radiusy})
+  local rightbot = disturb_point({right[1], right[2] - 1.45*radiusy})
+
+  local right_end = disturb_point(right)
+
+  move (right)
+  curve (rightbot, leftbot, left)
+  curve (lefttop, righttop, right_end)
+  linewidth(drawwidth*(math.random()+0.5))
+  stroke()
+end
+
 function sloppyline(start,stop)
   local start_line = disturb_point(start)
   local stop_line = disturb_point(stop)
@@ -2057,7 +2595,7 @@
   start = disturb_point(start)
   stop = disturb_point(stop)
   move(start) curve(start_line,stop_line,stop)
-  linewidth(math.random()+0.5)
+  linewidth(drawwidth*(math.random()+0.5))
   stroke()
 end
 %    \end{macrocode}

Modified: trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.lua	2021-01-04 21:52:06 UTC (rev 57324)
+++ trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.lua	2021-01-04 21:58:54 UTC (rev 57325)
@@ -8,7 +8,7 @@
 --  
 --  EXPERIMENTAL CODE
 --  
---  This package is copyright © 2017 Arno L. Trautmann. It may be distributed and/or
+--  This package is copyright © 2021 Arno L. Trautmann. It may be distributed and/or
 --  modified under the conditions of the LaTeX Project Public License, either version 1.3c
 --  of this license or (at your option) any later version. This work has the LPPL mainten-
 --  ance status ‘maintained’.
@@ -47,8 +47,8 @@
 chickenstring = {}
 chickenstring[1] = "chicken" -- chickenstring is a table, please remeber this!
 
-chickenizefraction = 0.5
--- set this to a small value to fool somebody, or to see if your text has been read carefully. This is also a great way to lay easter eggs for your own class / package …
+chickenizefraction = 0.5 -- set this to a small value to fool somebody,
+-- or to see if your text has been read carefully. This is also a great way to lay easter eggs for your own class / package …
 chicken_substitutions = 0 -- value to count the substituted chickens. Makes sense for testing your proofreaders.
 
 local match = unicode.utf8.match
@@ -234,7 +234,7 @@
 end
 countwords = function(head)
   for glyph in nodetraverseid(GLYPH,head) do
-    if (glyph.next.id == 10) then
+    if (glyph.next.id == GLUE) then
       wordnumber = wordnumber + 1
     end
   end
@@ -245,7 +245,7 @@
   texiowrite_nl("\nNumber of words in this document: "..wordnumber)
 end
 
-function detectdoublewords(head)
+detectdoublewords = function(head)
   prevlastword  = {}  -- array of numbers representing the glyphs
   prevfirstword = {}
   newlastword   = {}
@@ -260,9 +260,102 @@
   end
 end
 
-function printdoublewords()
+printdoublewords = function()
   texio.write_nl("finished")
 end
+francize = function(head)
+  for n in nodetraverseid(GLYPH,head) do
+    if ((n.char > 47) and (n.char < 58)) then
+      n.char = math.random(48,57)
+    end
+  end
+  return head
+end
+function gameofchicken()
+  GOC_lifetab = {}
+  GOC_spawntab = {}
+  GOC_antilifetab = {}
+  GOC_antispawntab = {}
+  -- translate the rules into an easily-manageable table
+  for i=1,#GOCrule_live do; GOC_lifetab[GOCrule_live[i]] = true end
+  for i=1,#GOCrule_spawn do; GOC_spawntab[GOCrule_spawn[i]] = true end
+  for i=1,#GOCrule_antilive do; GOC_antilifetab[GOCrule_antilive[i]] = true end
+  for i=1,#GOCrule_antispawn do; GOC_antispawntab[GOCrule_antispawn[i]] = true end
+-- initialize the arrays
+local life = {}
+local antilife = {}
+local newlife = {}
+local newantilife = {}
+for i = 0, GOCx do life[i] = {}; newlife[i] = {} for j = 0, GOCy do life[i][j] = 0 end end
+for i = 0, GOCx do antilife[i] = {}; newantilife[i] = {} for j = 0, GOCy do antilife[i][j] = 0 end end
+function applyruleslife(neighbors, lifeij, antineighbors, antilifeij)
+  if GOC_spawntab[neighbors] then myret = 1 else -- new cell
+  if GOC_lifetab[neighbors] and (lifeij == 1) then myret = 1 else myret =  0 end end
+  if antineighbors > 1 then myret =  0 end
+  return myret
+end
+function applyrulesantilife(neighbors, lifeij, antineighbors, antilifeij)
+  if (antineighbors == 3) then myret = 1 else -- new cell or keep cell
+  if (((antineighbors > 1) and (antineighbors < 4)) and (lifeij == 1)) then myret = 1 else myret =  0 end end
+  if neighbors > 1 then myret =  0 end
+  return myret
+end
+-- prepare some special patterns as starter
+life[53][26] = 1 life[53][25] = 1 life[54][25] = 1 life[55][25] = 1 life[54][24] = 1
+  print("start");
+  for i = 1,GOCx do
+    for j = 1,GOCy do
+      if (life[i][j]==1) then texio.write("X") else if (antilife[i][j]==1) then texio.write("O") else texio.write("_") end end
+    end
+    texio.write_nl(" ");
+  end
+  os.sleep(GOCsleep)
+
+  for i = 0, GOCx do
+    for j = 0, GOCy do
+        newlife[i][j] = 0 -- Fill the values from the start settings here
+        newantilife[i][j] = 0 -- Fill the values from the start settings here
+    end
+  end
+
+  for k = 1,GOCiter do -- iterate over the cycles
+    texio.write_nl(k);
+    for i = 1, GOCx-1 do -- iterate over lines
+      for j = 1, GOCy-1 do -- iterate over columns -- prevent edge effects
+        local neighbors = (life[i-1][j-1] + life[i-1][j] + life[i-1][j+1] + life[i][j-1] + life[i][j+1] +  life[i+1][j-1] + life[i+1][j] + life[i+1][j+1])
+        local antineighbors = (antilife[i-1][j-1] + antilife[i-1][j] + antilife[i-1][j+1] + antilife[i][j-1] + antilife[i][j+1] +  antilife[i+1][j-1] + antilife[i+1][j] + antilife[i+1][j+1])
+
+        newlife[i][j] = applyruleslife(neighbors, life[i][j],antineighbors, antilife[i][j])
+        newantilife[i][j] = applyrulesantilife(neighbors,life[i][j], antineighbors,antilife[i][j])
+      end
+    end
+
+    for i = 1, GOCx do
+      for j = 1, GOCy do
+        life[i][j] = newlife[i][j] -- copy the values
+        antilife[i][j] = newantilife[i][j] -- copy the values
+      end
+    end
+
+    for i = 1,GOCx do
+      for j = 1,GOCy do
+        if GOC_console then
+          if (life[i][j]==1) then texio.write("X") else if (antilife[i][j]==1) then texio.write("O") else texio.write("_") end end
+        end
+        if GOC_pdf then
+          if (life[i][j]==1) then tex.print("\\placeat("..(i/10)..","..(j/10).."){"..GOCcellcode.."}") end
+          if (antilife[i][j]==1) then tex.print("\\placeat("..(i/10)..","..(j/10).."){"..GOCanticellcode.."}") end
+        end
+      end
+    end
+    tex.print(".\\newpage")
+    os.sleep(GOCsleep)
+  end
+end --end function gameofchicken
+function make_a_gif()
+  os.execute("convert -verbose -dispose previous -background white -alpha remove -alpha off -density "..GOCdensity.." "..tex.jobname ..".pdf " ..tex.jobname..".gif")
+  os.execute("gwenview "..tex.jobname..".gif")
+end
 local quotestrings = {
    [171] = true,  [172] = true,
   [8216] = true, [8217] = true, [8218] = true,
@@ -271,7 +364,7 @@
   [8248] = true, [8249] = true, [8250] = true,
 }
 guttenbergenize_rq = function(head)
-  for n in nodetraverseid(nodeid"glyph",head) do
+  for n in nodetraverseid(GLYPH,head) do
     local i = n.char
     if quotestrings[i] then
       noderemove(head,n)
@@ -301,6 +394,115 @@
   end
   return head
 end
+italianizefraction = 0.5 --%% gives the amount of italianization
+mynode = nodenew(GLYPH) -- prepare a dummy glyph
+
+italianize = function(head)
+  -- skip "h/H" randomly
+  for n in node.traverse_id(GLYPH,head) do -- go through all glyphs
+      if n.prev.id ~= GLYPH then -- check if it's a word start
+      if ((n.char == 72) or (n.char == 104)) and (tex.normal_rand() < italianizefraction) then -- if it's h/H, remove randomly
+        n.prev.next = n.next
+      end
+    end
+  end
+
+  -- add h or H in front of vowels
+  for n in nodetraverseid(GLYPH,head) do
+    if math.random() < italianizefraction then
+    x = n.char
+    if x == 97 or x == 101 or x == 105 or x == 111 or x == 117 or
+       x == 65 or x ==  69 or x ==  73 or x == 79 or x == 85 then
+      if (n.prev.id == GLUE) then
+        mynode.font = n.font
+        if x > 90 then  -- lower case
+          mynode.char = 104
+        else
+          mynode.char = 72 -- upper case – convert into lower case
+          n.char = x + 32
+        end
+          node.insert_before(head,n,node.copy(mynode))
+        end
+      end
+    end
+  end
+
+  -- add e after words, but only after consonants
+  for n in node.traverse_id(GLUE,head) do
+    if n.prev.id == GLYPH then
+    x = n.prev.char
+    -- skip vowels and randomize
+    if not(x == 97 or x == 101 or x == 105 or x == 111 or x == 117 or x == 44 or x == 46) and math.random() > 0.2 then
+        mynode.char = 101           -- it's always a lower case e, no?
+        mynode.font = n.prev.font -- adapt the current font
+        node.insert_before(head,n,node.copy(mynode)) -- insert the e in the node list
+      end
+    end
+  end
+
+  return head
+end
+italianizerandwords = function(head)
+words = {}
+wordnumber = 0
+-- head.next.next is the very first word. However, let's try to get the first word after the first space correct.
+  for n in nodetraverseid(GLUE,head) do -- let's try to count words by their separators
+    wordnumber = wordnumber + 1
+    if n.next then
+      words[wordnumber] = {}
+      words[wordnumber][1] = node.copy(n.next)
+
+      glyphnumber = 1
+      myglyph = n.next
+      while myglyph.next do
+        node.tail(words[wordnumber][1]).next = node.copy(myglyph.next)
+        myglyph = myglyph.next
+      end
+    end
+  print(#words)
+  if #words > 0 then
+  print("lengs is: ")
+  print(#words[#words])
+  end
+  end
+--myinsertnode = head.next.next -- first letter
+--node.tail(words[1][1]).next = myinsertnode.next
+--myinsertnode.next = words[1][1]
+
+  return head
+end
+
+italianize_old = function(head)
+  local wordlist = {} -- here we will store the number of words of the sentence.
+  local words = {} -- here we will store the words of the sentence.
+  local wordnumber = 0
+  -- let's first count all words in one sentence, howboutdat?
+  wordlist[wordnumber] = 1 -- let's save the word *length* in here …
+
+  for n in nodetraverseid(GLYPH,head) do
+    if (n.next.id == GLUE) then -- this is a space
+      wordnumber = wordnumber + 1
+      wordlist[wordnumber] = 1
+      words[wordnumber] = n.next.next
+    end
+    if (n.next.id == GLYPH) then  -- it's a glyph
+    if (n.next.char == 46) then -- this is a full stop.
+      wordnumber = wordnumber + 1
+      texio.write_nl("this sentence had "..wordnumber.."words.")
+      for i=0,wordnumber-1 do
+      texio.write_nl("word "..i.." had " .. wordlist[i] .. "glyphs")
+      end
+      texio.write_nl(" ")
+      wordnumber = -1 -- to compensate the fact that the next node will be a space, this would count one word too much.
+    else
+
+      wordlist[wordnumber] = wordlist[wordnumber] + 1 -- the current word got 1 glyph longer
+      end
+    end
+  end
+  return head
+end
+
 itsame = function()
 local mr = function(a,b) rectangle({a*10,b*-10},10,10) end
 color = "1 .6 0"
@@ -396,15 +598,15 @@
   end
   return head
 end
-local letterspace_glue   = nodenew(nodeid"glue")
-local letterspace_pen    = nodenew(nodeid"penalty")
+local letterspace_glue   = nodenew(GLUE)
+local letterspace_pen    = nodenew(PENALTY)
 
 letterspace_glue.width   = tex.sp"0pt"
 letterspace_glue.stretch = tex.sp"0.5pt"
 letterspace_pen.penalty  = 10000
 letterspaceadjust = function(head)
-  for glyph in nodetraverseid(nodeid"glyph", head) do
-    if glyph.prev and (glyph.prev.id == nodeid"glyph" or glyph.prev.id == nodeid"disc" or glyph.prev.id == nodeid"kern") then
+  for glyph in nodetraverseid(GLYPH, head) do
+    if glyph.prev and (glyph.prev.id == GLYPH or glyph.prev.id == DISC or glyph.prev.id == KERN) then
       local g = nodecopy(letterspace_glue)
       nodeinsertbefore(head, glyph, g)
       nodeinsertbefore(head, g, nodecopy(letterspace_pen))
@@ -413,9 +615,9 @@
   return head
 end
 textletterspaceadjust = function(head)
-  for glyph in nodetraverseid(nodeid"glyph", head) do
+  for glyph in nodetraverseid(GLYPH, head) do
     if node.has_attribute(glyph,luatexbase.attributes.letterspaceadjustattr) then
-      if glyph.prev and (glyph.prev.id == node.id"glyph" or glyph.prev.id == node.id"disc" or glyph.prev.id == nodeid"kern") then
+      if glyph.prev and (glyph.prev.id == node.id"glyph" or glyph.prev.id == node.id"disc" or glyph.prev.id == KERN) then
         local g = node.copy(letterspace_glue)
         nodeinsertbefore(head, glyph, g)
         nodeinsertbefore(head, g, nodecopy(letterspace_pen))
@@ -427,8 +629,8 @@
 end
 matrixize = function(head)
   x = {}
-  s = nodenew(nodeid"disc")
-  for n in nodetraverseid(nodeid"glyph",head) do
+  s = nodenew(DISC)
+  for n in nodetraverseid(GLYPH,head) do
     j = n.char
     for m = 0,7 do -- stay ASCII for now
       x[7-m] = nodecopy(n) -- to get the same font etc.
@@ -602,6 +804,59 @@
   end
   return head
 end
+  sailheight = 12
+  mastheight = 4
+  hullheight = 5
+  relnumber = 402
+function relationship()
+--%% check if there's a problem with any character in the current font
+  f = font.getfont(font.current())
+  fullfont = 1
+  for i = 8756,8842 do
+    if not(f.characters[i]) then texio.write_nl((i).." not available") fullfont = 0 end
+  end
+--%% store the result of the check for later, then go on to construct the ship:
+  shipheight = sailheight + mastheight + hullheight
+  tex.print("\\parshape "..(shipheight)) --%% prepare the paragraph shape ...
+  for i =1,sailheight do
+    tex.print(" "..(4.5-i/3.8).."cm "..((i-0.5)/2.5).."cm ")
+   end
+  for i =1,mastheight do
+    tex.print(" "..(3.2).."cm "..(1).."cm ")
+  end
+  for i =1,hullheight do
+    tex.print(" "..((i-1)/2).."cm "..(10-i).."cm ")
+  end
+  tex.print("\\noindent") --%% ... up to here, then insert relations
+  for i=1,relnumber do
+    tex.print("\\ \\char"..math.random(8756,8842))
+  end
+  tex.print("\\break")
+end
+function cutparagraph(head)
+  local parsum = 0
+  for n in nodetraverseid(HLIST,head) do
+    parsum = parsum + 1
+    if parsum > shipheight then
+      node.remove(head,n)
+    end
+  end
+  return head
+end
+function missingcharstext()
+  if (fullfont == 0) then
+  local separator     = string.rep("=", 28)
+local texiowrite_nl = texio.write_nl
+  texiowrite_nl("Output written on "..tex.jobname..".pdf ("..status.total_pages.." chicken,".." eggs).")
+  texiowrite_nl(" ")
+  texiowrite_nl(separator)
+  texiowrite_nl("CAREFUL!!")
+  texiowrite_nl("\\relationship needs special characters (unicode points 8756 to 8842)")
+  texiowrite_nl("Your font does not support all of them!")
+  texiowrite_nl("consider using another one, e.g. the XITS font supplied with TeXlive.")
+  texiowrite_nl(separator .. "\n")
+  end
+end
 substitutewords_strings = {}
 
 addtosubstitutions = function(input,output)
@@ -631,9 +886,9 @@
 tabularasa_onlytext = false
 
 tabularasa = function(head)
-  local s = nodenew(nodeid"kern")
-  for line in nodetraverseid(nodeid"hlist",head) do
-    for n in nodetraverseid(nodeid"glyph",line.head) do
+  local s = nodenew(KERN)
+  for line in nodetraverseid(HLIST,head) do
+    for n in nodetraverseid(GLYPH,line.head) do
       if not(tabularasa_onlytext) or node.has_attribute(n,luatexbase.attributes.tabularasaattr) then
         s.kern = n.width
         nodeinsertafter(line.list,n,nodecopy(s))
@@ -644,7 +899,7 @@
   return head
 end
 tanjanize = function(head)
-  local s = nodenew(nodeid"kern")
+  local s = nodenew(KERN)
   local m = nodenew(GLYPH,1)
   local use_letter_i = true
   scale = nodenew(WHAT,PDF_LITERAL)
@@ -652,8 +907,8 @@
   scale.data  = "0.5 0 0 0.5 0 0 cm"
   scale2.data = "2   0 0 2   0 0 cm"
 
-  for line in nodetraverseid(nodeid"hlist",head) do
-    for n in nodetraverseid(nodeid"glyph",line.head) do
+  for line in nodetraverseid(HLIST,head) do
+    for n in nodetraverseid(GLYPH,line.head) do
       mimicount = 0
       tmpwidth  = 0
       while ((n.next.id == GLYPH) or (n.next.id == 11) or (n.next.id == 7) or (n.next.id == 0)) do  --find end of a word
@@ -731,11 +986,18 @@
     local rule_bad = nodenew(RULE)
 
     if colorexpansion then  -- if also the font expansion should be shown
+--%% here use first_glyph function!!
       local g = line.head
+n = node.first_glyph(line.head.next)
+texio.write_nl(line.head.id)
+texio.write_nl(line.head.next.id)
+texio.write_nl(line.head.next.next.id)
+texio.write_nl(n.id)
       while not(g.id == GLYPH) and (g.next) do g = g.next end -- find first glyph on line. If line is empty, no glyph:
       if (g.id == GLYPH) then                                 -- read width only if g is a glyph!
-        exp_factor = g.width / f[g.char].width
-        exp_color = colorstretch_coloroffset + (1-exp_factor)*10 .. " g"
+        exp_factor = g.expansion_factor/10000 --%% neato, luatex now directly gives me this!!
+        exp_color = colorstretch_coloroffset + (exp_factor*0.1) .. " g"
+texio.write_nl(exp_factor)
         rule_bad.width = 0.5*line.width  -- we need two rules on each line!
       end
     else
@@ -823,10 +1085,10 @@
 substlist[1514] = 64296
 function variantjustification(head)
   math.randomseed(1)
-  for line in nodetraverseid(nodeid"hhead",head) do
+  for line in nodetraverseid(Hhead,head) do
     if (line.glue_sign == 1 and line.glue_order == 0) then -- exclude the last line!
       substitutions_wide = {} -- we store all “expandable” letters of each line
-      for n in nodetraverseid(nodeid"glyph",line.head) do
+      for n in nodetraverseid(GLYPH,line.head) do
         if (substlist[n.char]) then
           substitutions_wide[#substitutions_wide+1] = n
         end
@@ -854,12 +1116,12 @@
 zebracolorarray_bg[2] = "0.1 g"
 function zebranize(head)
   zebracolor = 1
-  for line in nodetraverseid(nodeid"hhead",head) do
+  for line in nodetraverseid(Hhead,head) do
     if zebracolor == #zebracolorarray then zebracolor = 0 end
     zebracolor = zebracolor + 1
     color_push.data = zebracolorarray[zebracolor]
     line.head =     nodeinsertbefore(line.head,line.head,nodecopy(color_push))
-    for n in nodetraverseid(nodeid"glyph",line.head) do
+    for n in nodetraverseid(GLYPH,line.head) do
       if n.next then else
         nodeinsertafter(line.head,n,nodecopy(color_pull))
       end
@@ -889,18 +1151,31 @@
   pdf.print("\n")
 end
 
-function move (p)
-  pdf_print(p[1],p[2],"m")
+function move (p1,p2)
+  if (p2) then
+    pdf_print(p1,p2,"m")
+  else
+    pdf_print(p1[1],p1[2],"m")
+  end
 end
 
-function line (p)
-  pdf_print(p[1],p[2],"l")
+function line(p1,p2)
+  if (p2) then
+    pdf_print(p1,p2,"l")
+  else
+    pdf_print(p1[1],p1[2],"l")
+  end
 end
 
-function curve(p1,p2,p3)
+function curve(p11,p12,p21,p22,p31,p32)
+  if (p22) then
+    p1,p2,p3 = {p11,p12},{p21,p22},{p31,p32}
+  else
+    p1,p2,p3 = p11,p12,p21
+  end
   pdf_print(p1[1], p1[2],
-            p2[1], p2[2],
-            p3[1], p3[2], "c")
+              p2[1], p2[2],
+              p3[1], p3[2], "c")
 end
 
 function close ()
@@ -907,6 +1182,8 @@
   pdf_print("h")
 end
 
+drawwidth = 1
+
 function linewidth (w)
   pdf_print(w,"w")
 end
@@ -930,9 +1207,12 @@
 stroke()
 end
 
+sloppynessh = 5
+sloppynessv = 5
+
 function disturb_point(point)
-  return {point[1] + math.random()*5 - 2.5,
-          point[2] + math.random()*5 - 2.5}
+  return {point[1] + (math.random() - 1/2)*sloppynessh,
+          point[2] + (math.random() - 1/2)*sloppynessv}
 end
 
 function sloppycircle(center,radius)
@@ -948,10 +1228,27 @@
   move (right)
   curve (rightbot, leftbot, left)
   curve (lefttop, righttop, right_end)
-  linewidth(math.random()+0.5)
+  linewidth(drawwidth*(math.random()+0.5))
   stroke()
 end
 
+function sloppyellipsis(center,radiusx,radiusy)
+  local left = disturb_point({center[1] - radiusx, center[2]})
+  local lefttop = disturb_point({left[1], left[2] + 1.45*radiusy})
+  local leftbot = {lefttop[1], lefttop[2] - 2.9*radiusy}
+  local right = disturb_point({center[1] + radiusx, center[2]})
+  local righttop = disturb_point({right[1], right[2] + 1.45*radiusy})
+  local rightbot = disturb_point({right[1], right[2] - 1.45*radiusy})
+
+  local right_end = disturb_point(right)
+
+  move (right)
+  curve (rightbot, leftbot, left)
+  curve (lefttop, righttop, right_end)
+  linewidth(drawwidth*(math.random()+0.5))
+  stroke()
+end
+
 function sloppyline(start,stop)
   local start_line = disturb_point(start)
   local stop_line = disturb_point(stop)
@@ -958,7 +1255,7 @@
   start = disturb_point(start)
   stop = disturb_point(stop)
   move(start) curve(start_line,stop_line,stop)
-  linewidth(math.random()+0.5)
+  linewidth(drawwidth*(math.random()+0.5))
   stroke()
 end
 -- 

Modified: trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.sty
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.sty	2021-01-04 21:52:06 UTC (rev 57324)
+++ trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.sty	2021-01-04 21:58:54 UTC (rev 57325)
@@ -8,14 +8,13 @@
 %% 
 %% EXPERIMENTAL CODE
 %% 
-%% This package is copyright © 2017 Arno L. Trautmann. It may be distributed and/or
+%% This package is copyright © 2021 Arno L. Trautmann. It may be distributed and/or
 %% modified under the conditions of the LaTeX Project Public License, either version 1.3c
 %% of this license or (at your option) any later version. This work has the LPPL mainten-
 %% ance status ‘maintained’.
 \ProvidesPackage{chickenize}%
-  [2017/08/19 v0.2.5 chickenize package]
+  [2021/01/03 v0.3 chickenize package]
 \input{chickenize}
-
 \iffalse
   \DeclareDocumentCommand\includegraphics{O{}m}{
      \fbox{Chicken}  %% actually, I'd love to draw an MP graph showing a chicken …

Modified: trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.tex
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.tex	2021-01-04 21:52:06 UTC (rev 57324)
+++ trunk/Master/texmf-dist/tex/luatex/chickenize/chickenize.tex	2021-01-04 21:58:54 UTC (rev 57325)
@@ -8,7 +8,7 @@
 %% 
 %% EXPERIMENTAL CODE
 %% 
-%% This package is copyright © 2017 Arno L. Trautmann. It may be distributed and/or
+%% This package is copyright © 2021 Arno L. Trautmann. It may be distributed and/or
 %% modified under the conditions of the LaTeX Project Public License, either version 1.3c
 %% of this license or (at your option) any later version. This work has the LPPL mainten-
 %% ance status ‘maintained’.
@@ -18,11 +18,10 @@
   \bgroup%
   \fontspec{Latin Modern Sans}%
   A%
-  \kern-.4em \raisebox{.65ex}{\scalebox{0.3}{L}}%
-  \kern-.0em \raisebox{-0.98ex}{T}%
+  \kern-.375em \raisebox{.65ex}{\scalebox{0.3}{L}}%
+  \kern.03em \raisebox{-.99ex}{T}%
   \egroup%
 }
-
 \def\allownumberincommands{
   \catcode`\0=11
   \catcode`\1=11
@@ -170,10 +169,38 @@
 \textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash\textbackslash... the true name of Ba'al, the soul-eater}
 }
 
+\def\francize{
+  \directlua{luatexbase.add_to_callback("pre_linebreak_filter",francize,"francize")}}
+
+\def\unfrancize{
+  \directlua{luatexbase.remove_from_callback("pre_linebreak_filter",francize)}}
+
 \def\gameoflife{
   Your Life Is Tetris. Stop Playing It Like Chess.
 }
+\def\gameofchicken#1{\directlua{
+GOCrule_live = {2,3}
+GOCrule_spawn = {3}
+GOCrule_antilive = {2,3}
+GOCrule_antispawn = {3}
+GOCcellcode = "\\scalebox{0.03}{\\drawchicken}"
+GOCcellcode = "\\scalebox{0.03}{\\drawcov}"
+GOCx = 100
+GOCy = 100
+GOCiter = 150
+GOC_console = false
+GOC_pdf = true
+GOCsleep = 0
+GOCdensity = 100
+#1
+gameofchicken()
 
+if (GOCmakegif == true) then
+  luatexbase.add_to_callback("wrapup_run",make_a_gif,"makeagif")
+end
+}}
+\let\gameofchimken\gameofchicken % yeah, that had to be.
+
 \def\guttenbergenize{ %% makes only sense when using LaTeX
   \AtBeginDocument{
     \let\grqq\relax\let\glqq\relax
@@ -208,7 +235,17 @@
 \let\hendlnize\chickenize     % homage to Hendl/Chicken
 \let\unhendlnize\unchickenize % may the soldering strength always be with him
 
+\def\italianizerandwords{
+  \directlua{luatexbase.add_to_callback("pre_linebreak_filter",italianizerandwords,"italianizerandwords")}}
+\def\unitalianizerandwords{
+  \directlua{luatexbase.remove_from_callback("pre_linebreak_filter","italianizerandwords")}}
 
+\def\italianize{
+  \directlua{luatexbase.add_to_callback("pre_linebreak_filter",italianize,"italianize")}}
+\def\unitalianize{
+  \directlua{luatexbase.remove_from_callback("pre_linebreak_filter","italianize")}}
+
+
 \def\kernmanipulate{
   \directlua{luatexbase.add_to_callback("pre_linebreak_filter",kernmanipulate,"kernmanipulate")}}
 \def\unkernmanipulate{
@@ -300,6 +337,13 @@
 \def\unrandomuclc{
   \directlua{luatexbase.remove_from_callback("pre_linebreak_filter","randomuclc")}}
 
+\def\relationship{%
+  \directlua{luatexbase.add_to_callback("post_linebreak_filter",cutparagraph,"cut paragraph")
+    luatexbase.add_to_callback("stop_run",missingcharstext,"charsmissing")
+    relationship()
+  }
+}
+
 \let\rongorongonize\boustrophedoninverse
 \let\unrongorongonize\unboustrophedoninverse
 
@@ -436,6 +480,93 @@
     sloppyline(wing_front,wing_bottom) sloppyline(wing_back,wing_bottom)
   }
 }
+\long\def\drawcov{
+  \luadraw{90}{
+    covbody = {200,50}
+    covbody_rad = 50
+
+    covcrown_rad = 5
+    crownno = 13
+    for i=1,crownno do
+      crownpos = {covbody[1]+1.4*covbody_rad*math.sin(2*math.pi/crownno*i),covbody[2]+1.4*covbody_rad*math.cos(2*math.pi/crownno*i)}
+      crownconnect = {covbody[1]+covbody_rad*math.sin(2*math.pi/crownno*i),covbody[2]+covbody_rad*math.cos(2*math.pi/crownno*i)}
+     sloppycircle(crownpos,covcrown_rad)
+     sloppyline(crownpos,crownconnect)
+   end
+
+    covcrown_rad = 6
+    crownno = 8
+    for i=1,crownno do
+      crownpos = {covbody[1]+0.8*covbody_rad*math.sin(2*math.pi/crownno*i),covbody[2]+0.8*covbody_rad*math.cos(2*math.pi/crownno*i)}
+      crownconnect = {covbody[1]+0.5*covbody_rad*math.sin(2*math.pi/crownno*i),covbody[2]+0.5*covbody_rad*math.cos(2*math.pi/crownno*i)}
+      sloppycircle(crownpos,covcrown_rad)
+      sloppyline(crownpos,crownconnect)
+    end
+
+    covcrown_rad = 8
+    sloppycircle(covbody,covcrown_rad)
+    sloppycircle(covbody,covbody_rad)
+    sloppyline(covbody,covbody)
+  }
+}
+\long\def\drawhorse{
+  \luadraw{90}{
+    horsebod = {100,-40}
+    sloppyellipsis(horsebod,50,20)
+    horsehead = {20,0}
+    sloppyellipsis(horsehead,25,15)
+    sloppyline({35,-10},{50,-40})
+    sloppyline({45,5},{80,-25})
+    sloppyline({60,-50},{60,-90})
+    sloppyline({70,-50},{70,-90})
+    sloppyline({130,-50},{130,-90})
+    sloppyline({140,-50},{140,-90})
+    sloppyline({150,-40},{160,-60})
+    sloppyline({150,-38},{160,-58})
+    sloppyline({150,-42},{160,-62})
+    sloppyline({-5,-10},{10,-5})
+    sloppyellipsis({30,5},5,2)  %% it's an eye, aye?
+    sloppyline({27,15},{34,25})
+    sloppyline({34,25},{37,13})
+  }
+}
+\long\def\drawfathorse{
+  \luadraw{90}{
+    horsebod = {100,-40}
+    sloppyellipsis(horsebod,50,40)
+    horsehead = {20,0}
+    sloppyellipsis(horsehead,25,15)
+    sloppyline({35,-10},{50,-40})
+    sloppyline({45,5},{70,-15})
+    sloppyline({60,-70},{60,-90})
+    sloppyline({70,-70},{70,-90})
+    sloppyline({130,-70},{130,-90})
+    sloppyline({140,-70},{140,-90})
+    sloppyline({150,-40},{160,-60})
+    sloppyline({150,-38},{160,-58})
+    sloppyline({150,-42},{160,-62})
+    sloppyline({-5,-10},{10,-5})
+    sloppyellipsis({30,5},5,2)  %% it's an eye, aye?
+    sloppyline({27,15},{34,25})
+    sloppyline({34,25},{37,13})
+  }
+}
+\long\def\drawunicorn{
+\color{pink!90!black}
+  \drawhorse
+  \luadraw{0}{
+    sloppyline({15,20},{15,50})
+    sloppyline({15,50},{25,20})
+  }
+}
+\long\def\drawfatunicorn{
+\color{pink!90!black}
+  \drawfathorse
+  \luadraw{0}{
+    sloppyline({15,20},{15,50})
+    sloppyline({15,50},{25,20})
+  }
+}
 %% 
 %%
 %% End of file `chickenize.tex'.



More information about the tex-live-commits mailing list.