texlive[48720] Master/texmf-dist: ducksay (21sep18)

commits+karl at tug.org commits+karl at tug.org
Fri Sep 21 23:06:09 CEST 2018


Revision: 48720
          http://tug.org/svn/texlive?view=revision&revision=48720
Author:   karl
Date:     2018-09-21 23:06:08 +0200 (Fri, 21 Sep 2018)
Log Message:
-----------
ducksay (21sep18)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/ducksay/README.md
    trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.pdf
    trunk/Master/texmf-dist/tex/latex/ducksay/ducksay.sty

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.animals.tex
    trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v1.tex
    trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v2.tex
    trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.hd
    trunk/Master/texmf-dist/source/latex/ducksay/
    trunk/Master/texmf-dist/source/latex/ducksay/ducksay.dtx

Removed Paths:
-------------
    trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.tex

Modified: trunk/Master/texmf-dist/doc/latex/ducksay/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/ducksay/README.md	2018-09-21 00:23:48 UTC (rev 48719)
+++ trunk/Master/texmf-dist/doc/latex/ducksay/README.md	2018-09-21 21:06:08 UTC (rev 48720)
@@ -3,7 +3,7 @@
 This package is distributed under the terms of GPLv3 or later, or the LPPL 1.3c
 or later, which ever license fits your needs the best.
 
-Copyright (C) 2017 by Jonathan P. Spratte
+Copyright (C) 2017-2018 by Jonathan P. Spratte
 
 The package draws ASCII art of animals saying a specified message. The following
 macros are available:
@@ -17,4 +17,5 @@
 `<ascii-art>` should be delimited either by matching braces or by the same
 symbol and is read verbatim.
 
-Multi-line messages are supported but need to be manually created using `\\`.
+Multi-line messages are now fully supported. The package comes with two
+versions, choosable with the `version` key.

Added: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.animals.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.animals.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.animals.tex	2018-09-21 21:06:08 UTC (rev 48720)
@@ -0,0 +1,309 @@
+%%
+%% This is file `ducksay.animals.tex',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% ducksay.dtx  (with options: `animals')
+%% 
+%% --------------------------------------------------------------
+%% ducksay -- cowsay for LaTeX
+%% E-mail: jspratte at yahoo.de
+%% Released under the LaTeX Project Public License v1.3c or later
+%% See http://www.latex-project.org/lppl.txt
+%% --------------------------------------------------------------
+%% 
+%% Copyright (C) 2017-2018 Jonathan P. Spratte
+%% 
+%% This  work may be  distributed and/or  modified under  the conditions  of the
+%% LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
+%% (at your option) any later version.  The latest version of this license is in
+%% the file:
+%% 
+%%   http://www.latex-project.org/lppl.txt
+%% 
+%% Alternatively you can use this work under the terms of the GNU General Public
+%% Licensce (GPL), version 3 or later, except that you might not redistribute it
+%% under the same  name if you change  its functionality.  Choose which of these
+%% licenses fits your needs the best.
+%% 
+%% This work is "maintained" (as per LPPL maintenance status) by
+%%   Jonathan P. Spratte.
+%% 
+%% This work consists of the file  ducksay.dtx
+%% and the derived files           ducksay.pdf
+%%                                 ducksay.sty
+%%                                 ducksay.code.v1.tex
+%%                                 ducksay.code.v2.tex and
+%%                                 ducksay.animals.tex.
+%% 
+\AddAnimal{duck}%>>>
+{  \
+    \   __
+      >(' )
+        )/
+       /(
+      /  `----/
+      \  ~=- /
+    ~^~^~^~^~^~^~^}%<<<
+\AddAnimal{small-duck}%>>>
+{  \
+    \
+      >()_
+       (__)__ _}%<<<
+\AddAnimal{duck-family}%>>>
+{  \
+    \   __
+      >(' )
+        )/
+       /(
+      /  `----/  -()_  >()_
+    __\__~=-_/__ _(__)__(__)__ _}%<<<
+\AddAnimal{cow}%>>>
+{  \  ^__^
+    \ (oo)\_______
+      (__)\       )\/\
+          ||----w |
+          ||     ||}%<<<
+\AddAnimal{head-in}%>>>
+{  \
+    \ ^__^         /
+      (oo)\_______/  ________
+      (__)\       )=(  ___|_ \____
+          ||----w |  \ \    \____ |
+          ||     ||   ||         ||}%<<<
+\AddAnimal{sodomized}%>>>
+{  \             _
+    \           (_)
+      ^__^       / \
+      (oo)\_____/_\ \
+      (__)\       ) /
+          ||----w ((
+          ||     ||>>}%<<<
+\AddAnimal{tux}%>>>
+{  \
+    \  .--.
+      |o_o |
+      |\_/ |
+     //   \ \
+    (|     | )
+   /'\_   _/`\
+   \___)=(___/}%<<<
+\AddAnimal{pig}%>>>
++  \     _//| .-~~~-.
+    \ _/oo  }        }-@
+     ('')_  }        |
+      `--'| { }--{  }
+           //_/  /_/+%<<<
+\AddAnimal{frog}%>>>
+{   \
+     \ (.)_(.)
+    _ (   _   ) _
+   / \/`-----'\/ \
+ __\ ( (     ) ) /__
+ )   /\ \._./ /\   (
+  )_/ /|\   /|\ \_(}%<<<
+\AddAnimal{snowman}%>>>
+{  \
+    \_[_]_
+      (")
+   >-( : )-<
+    (__:__)}%<<<
+\AddAnimal{hedgehog}%>>>
+{  \    .\|//||\||.
+    \  |/\/||/|//|/|
+      /. `|/\\|/||/||
+     o__,_|//|/||\||'}%<<<
+\AddAnimal{kangaroo}%>>>
+{  \
+    \ _,'   ___
+     <__\__/   \
+        \_  /  _\
+          \,\ / \\
+            //   \\
+          ,/'     `\_,}%<<<
+\AddAnimal{rabbit}%>>>
+{ \     / \`\         __
+   \   |  \ `\      /`/ \
+    \  \_/`\  \-"-/` /\  \
+            |       |  \  |
+            (d     b)   \_/
+            /       \
+        ,".|.'.\_/.'.|.",
+       /   /\' _|_ '/\   \
+       |  /  '-`"`-'  \  |
+       | |             | |
+       | \    \   /    / |
+        \ \    \ /    / /
+         `"`\   :   /'"`
+             `""`""`}%<<<
+\AddAnimal{bunny}%>>>
+{ \
+   \      /
+      /\ /
+       ( )
+     .( o ).}%<<<
+\AddAnimal{small-rabbit}%>>>
+{  \
+    \ _//
+     (')---.
+      _/-_( )o}%<<<
+\AddAnimal{dragon}%>>>
+{     \                    / \  //\
+       \    |\___/|      /   \//  \\
+        \   /0  0  \__  /    //  | \ \
+           /     /  \/_/    //   |  \  \
+           @_^_@'/   \/_   //    |   \   \
+           //_^_/     \/_ //     |    \    \
+        ( //) |        \///      |     \     \
+      ( / /) _|_ /   )  //       |      \     _\
+    ( // /) '/,_ _ _/  ( ; -.    |    _ _\.-~        .-~~~^-.
+  (( / / )) ,-{        _      `-.|.-~-.           .~         `.
+ (( // / ))  '/\      /                 ~-. _ .-~      .-~^-.  \
+ (( /// ))      `.   {            }                   /      \  \
+  (( / ))     .----~-.\        \-'                 .~         \  `. \^-.
+             ///.----..>        \             _ -~             `.  ^-`  ^-_
+               ///-._ _ _ _ _ _ _}^ - - - - ~                     ~-- ,.-~
+                                                                  /.-~}%<<<
+\AddAnimal{dog}%>>>
+{  \     __
+    \ .-'\/\
+       "\   '------.
+     ___/       (  .'_____
+    '-----'"""'------"""""'}%<<<
+\AddAnimal{squirrel}%>>>
+{  \           ,;:;;,
+    \    ,    ;;;;;
+      .=',    ;:;;:,
+     /_', "=. ';:;:;
+     @=:__,  \,;:;:'
+       _(\.=  ;:;;'
+      `"_(  _/="`
+       `"'``}%<<<
+\AddAnimal{snail}%>>>
+{  \
+    \          .-""-.
+      oo      ; .-.  :
+       \\__..-: '.__.')._
+        "-._.._'.__.-'_.."}%<<<
+\AddAnimal{unicorn}%>>>
+{   \
+     \       /((((((\\\\
+     ---====((((((((((\\\\\
+          ((           \\\\\\\
+          ( (*    _/      \\\\\\\
+            \    /  \      \\\\\\_         __,,__
+             |  |   |       </    "------""     ((\\\\
+             o_|   /        /                      \ \\\\    \\\\\\\
+                  |  ._    (                        \ \\\\\\\\\\\\\\\\
+                  | /                       /       /    \\\\\\\     \\
+          .______/\/     /                 /       /         \\\
+         / __.____/    _/          ___----(       /\
+        / / / ________/:______,---'        \     /  \_
+       / /  \ \                             \   \ \_  \
+      ( <    \ \                             >  /    \ \
+       \/      \\_                          / /       > )
+                \_|                        / /       / /
+                                         _//       _//
+                                       /_|       /_|}%<<<
+\AddAnimal{whale}%>>>
+{  \                |-.
+    \    .-""-._     \ \.--|
+     \  /       `-..__)  ,-'
+       |     .          /
+        \--.__,   .__.,'
+         `-.___'._\_.'}%<<<
+\AddAnimal{yoda}%>>>
+{   \
+     \             ____
+      \         _.' :  `._
+            .-.'`.  ;   .'`.-.
+   __      / : ___\ ;  /___ ; \      __
+ ,'_ ""--.:__;".-.";: :".-.":__;.--"" _`,
+ :' `.t""--.. '<@.`;_  ',@>` ..--""j.' `;
+      `:-.._J '-.-'L__ `-- ' L_..-;'
+        "-.__ ;  .-"  "-.  : __.-"
+            L ' /.------.\ ' J
+             "-.   "--"   .-"
+            __.l"-:_JL_;-";.__
+         .-j/'.;  ;""""  / .'\"-.
+       .' /:`. :  :     /.".'';  `.
+    .-"  / ;`.".  :    ."."   :    "-.
+ .+"-.  : :   ".".". ."."      ;-._   \
+ ; \  `.; ; .   "."-"."        : : "+. ;
+ :  ;   ; ;  .   ."."    ;     : ;  : \:
+ ;  :   ; :     / /     /  ,   ;:   ;  :
+: \  ;  :  ;   ; /     :  ,   : ;  /  ::
+;  ; :   ; :  ; ;      ;      ;   :   ;:
+:  :  ;  :  ;. ;      '      : :  ;  : ;
+;\    :   ; : .          ,   ; ;     ; ;
+: `."-;   :  ;      .   ;   :  ;    /  ;
+ ;    -:   ; :      ,  ,    ;  : .-"   :
+ :\     \  :  ;    ,       : \.-"      :
+  ;`.    \  ; :   .   ,    ;.'_..--  / ;
+  :  "-.  "-:  ;     ,    :/."      .'  :
+   \         \ :    :     ;/  __        :
+    \       .-`.\        /t-""  ":-+.   :
+     `.  .-"    `l    __/ /`. :  ; ; \  ;
+       \   .-" .-"-.-"  .' .'j \  /   ;/
+        \ / .-"   /.     .'.' ;_:'    ;
+         :-""-.`./-.'     /    `.___.'
+               \ `t  ._  /
+                "-.t-._:'}%<<<
+\AddAnimal{yoda-head}%>>>
+{   \
+     \             ____
+      \         _.' :  `._
+            .-.'`.  ;   .'`.-.
+   __      / : ___\ ;  /___ ; \      __
+ ,'_ ""--.:__;".-.";: :".-.":__;.--"" _`,
+ :' `.t""--.. '<@.`;_  ',@>` ..--""j.' `;
+      `:-.._J '-.-'L__ `-- ' L_..-;'
+        "-.__ ;  .-"  "-.  : __.-"
+            L ' /.------.\ ' J
+             "-.   "--"   .-"
+            __.l"-:_JL_;-";.__
+         .-j/'.;  ;""""  / .'\"-.
+       .' /:`. :  :     /.".'';  `.
+    .-"  / ;`.".  :    ."."   :    "-.
+ .+"-.  : :   ".".". ."."      ;-._   \}%<<<
+\AddAnimal{small-yoda}%>>>
+{  \
+    \
+    __.-._
+    '-._"7'
+     /'.-c
+     |  /T
+    _)_/LI}%<<<
+\AddAnimal{r2d2}%>>>
+{  \
+    \ ,-----.
+    ,'_/_|_\_`.
+   /<<::8[O]::>\
+  _|-----------|_
+ |  | ====-=- |  |
+ |  | -=-==== |  |
+ \  | ::::|()||  /
+  | | ....|()|| |
+  | |_________| |
+  | |\_______/| |
+ /   \ /   \ /   \
+ `---' `---' `---'}%<<<
+\AddAnimal{vader}%>>>
+{  \     _.-'~~~~~~`-._
+    \   /      ||      \
+       /       ||       \
+      |        ||        |
+      | _______||_______ |
+      |/ ----- \/ ----- \|
+     /  (     )  (     )  \
+    / \  ----- () -----  / \
+   /   \      /||\      /   \
+  /     \    /||||\    /     \
+ /       \  /||||||\  /       \
+/_        \O========O/        _\
+  `--...__|`-._  _.-'|__...--'
+          |    `'    |}%<<<
+%% 
+%%
+%% End of file `ducksay.animals.tex'.


Property changes on: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.animals.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v1.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v1.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v1.tex	2018-09-21 21:06:08 UTC (rev 48720)
@@ -0,0 +1,159 @@
+%%
+%% This is file `ducksay.code.v1.tex',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% ducksay.dtx  (with options: `code.v1')
+%% 
+%% --------------------------------------------------------------
+%% ducksay -- cowsay for LaTeX
+%% E-mail: jspratte at yahoo.de
+%% Released under the LaTeX Project Public License v1.3c or later
+%% See http://www.latex-project.org/lppl.txt
+%% --------------------------------------------------------------
+%% 
+%% Copyright (C) 2017-2018 Jonathan P. Spratte
+%% 
+%% This  work may be  distributed and/or  modified under  the conditions  of the
+%% LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
+%% (at your option) any later version.  The latest version of this license is in
+%% the file:
+%% 
+%%   http://www.latex-project.org/lppl.txt
+%% 
+%% Alternatively you can use this work under the terms of the GNU General Public
+%% Licensce (GPL), version 3 or later, except that you might not redistribute it
+%% under the same  name if you change  its functionality.  Choose which of these
+%% licenses fits your needs the best.
+%% 
+%% This work is "maintained" (as per LPPL maintenance status) by
+%%   Jonathan P. Spratte.
+%% 
+%% This work consists of the file  ducksay.dtx
+%% and the derived files           ducksay.pdf
+%%                                 ducksay.sty
+%%                                 ducksay.code.v1.tex
+%%                                 ducksay.code.v2.tex and
+%%                                 ducksay.animals.tex.
+%% 
+\cs_new:Npn \ducksay_longest_line:n #1
+  {
+    \int_incr:N \l_ducksay_msg_height_int
+    \exp_args:NNx \tl_set:Nn \l_ducksay_tmpa_tl { #1 }
+    \regex_replace_all:nnN { \s } { \c { space } } \l_ducksay_tmpa_tl
+    \int_set:Nn \l_ducksay_msg_width_int
+      {
+        \int_max:nn
+          { \l_ducksay_msg_width_int } { \tl_count:N \l_ducksay_tmpa_tl }
+      }
+  }
+\cs_new:Npn \ducksay_open_bubble:
+  {
+    \begin{tabular}{@{}l@{}}
+      \null\\
+      \int_compare:nNnTF { \l_ducksay_msg_height_int } = { 1 } { ( }
+        {
+          /
+          \int_step_inline:nnn
+            { 3 } { \l_ducksay_msg_height_int } { \\\kern-0.2em| }
+          \\\detokenize{\ }
+        }
+      \\[-1ex]\null
+    \end{tabular}
+    \begin{tabular}{@{}l@{}}
+      _\\
+      \int_step_inline:nnn { 2 } { \l_ducksay_msg_height_int } { \\ } \\[-1ex]
+      \mbox { - }
+    \end{tabular}
+  }
+\cs_new:Npn \ducksay_close_bubble:
+  {
+    \begin{tabular}{@{}l@{}}
+      _\\
+      \int_step_inline:nnn { 2 } { \l_ducksay_msg_height_int } { \\ } \\[-1ex]
+      { - }
+    \end{tabular}
+    \begin{tabular}{@{}r@{}}
+      \null\\
+      \int_compare:nNnTF { \l_ducksay_msg_height_int } = { 1 }
+        { ) }
+        {
+          \detokenize {\ }
+          \int_step_inline:nnn
+            { 3 } { \l_ducksay_msg_height_int } { \\|\kern-0.2em }
+          \\/
+        }
+      \\[-1ex]\null
+    \end{tabular}
+  }
+\cs_new:Npn \ducksay_print_msg:nn #1 #2
+  {
+    \begin{tabular}{@{} #2 @{}}
+      \int_step_inline:nn { \l_ducksay_msg_width_int } { _ } \\
+      #1\\[-1ex]
+      \int_step_inline:nn { \l_ducksay_msg_width_int } { { - } }
+    \end{tabular}
+  }
+\cs_generate_variant:Nn \ducksay_print_msg:nn { nV }
+\cs_new:Npn \ducksay_print:nn #1 #2
+  {
+    \int_compare:nNnTF { \l_ducksay_msg_width_int } < { 0 }
+      {
+        \int_zero:N \l_ducksay_msg_height_int
+        \seq_set_split:Nnn \l_ducksay_msg_lines_seq { \\ } { #1 }
+        \seq_map_function:NN \l_ducksay_msg_lines_seq \ducksay_longest_line:n
+      }
+      {
+        \int_compare:nNnT { \l_ducksay_msg_height_int } < { 0 }
+          {
+            \regex_count:nnN { \c { \\ } } { #1 } \l_ducksay_msg_height_int
+            \int_incr:N \l_ducksay_msg_height_int
+          }
+      }
+    \group_begin:
+      \frenchspacing
+      \verbatim at font
+      \@noligs
+      \begin{tabular}[\l_ducksay_align_tl]{@{}#2@{}}
+        \l_ducksay_bubble_tl
+        \begin{tabular}{@{}l@{}}
+          \ducksay_open_bubble:
+          \ducksay_print_msg:nV { #1 } \l_ducksay_msg_align_tl
+          \ducksay_close_bubble:
+        \end{tabular}\\
+        \l_ducksay_body_tl
+        \begin{tabular}{@{}l@{}}
+          \l_ducksay_animal_tl
+        \end{tabular}
+      \end{tabular}
+    \group_end:
+  }
+\cs_generate_variant:Nn \ducksay_print:nn { nV }
+\cs_new:Npn \ducksay_prepare_say_and_think:n #1
+  {
+    \int_set:Nn \l_ducksay_msg_width_int  { -\c_max_int }
+    \int_set:Nn \l_ducksay_msg_height_int { -\c_max_int }
+    \keys_set:nn { ducksay } { #1 }
+    \tl_if_empty:NT \l_ducksay_animal_tl
+      { \keys_set:nn { ducksay } { default_animal } }
+  }
+\NewDocumentCommand \ducksay { O{} m }
+  {
+    \group_begin:
+      \tl_set:Nn \l_ducksay_say_or_think_tl { say }
+      \ducksay_prepare_say_and_think:n { #1 }
+      \ducksay_print:nV { #2 } \l_ducksay_rel_align_tl
+    \group_end:
+  }
+\NewDocumentCommand \duckthink { O{} m }
+  {
+    \group_begin:
+      \tl_set:Nn \l_ducksay_say_or_think_tl { think }
+      \ducksay_prepare_say_and_think:n { #1 }
+      \ducksay_print:nV { #2 } \l_ducksay_rel_align_tl
+    \group_end:
+  }
+%% 
+%%
+%% End of file `ducksay.code.v1.tex'.


Property changes on: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v1.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v2.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v2.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v2.tex	2018-09-21 21:06:08 UTC (rev 48720)
@@ -0,0 +1,509 @@
+%%
+%% This is file `ducksay.code.v2.tex',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% ducksay.dtx  (with options: `code.v2')
+%% 
+%% --------------------------------------------------------------
+%% ducksay -- cowsay for LaTeX
+%% E-mail: jspratte at yahoo.de
+%% Released under the LaTeX Project Public License v1.3c or later
+%% See http://www.latex-project.org/lppl.txt
+%% --------------------------------------------------------------
+%% 
+%% Copyright (C) 2017-2018 Jonathan P. Spratte
+%% 
+%% This  work may be  distributed and/or  modified under  the conditions  of the
+%% LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
+%% (at your option) any later version.  The latest version of this license is in
+%% the file:
+%% 
+%%   http://www.latex-project.org/lppl.txt
+%% 
+%% Alternatively you can use this work under the terms of the GNU General Public
+%% Licensce (GPL), version 3 or later, except that you might not redistribute it
+%% under the same  name if you change  its functionality.  Choose which of these
+%% licenses fits your needs the best.
+%% 
+%% This work is "maintained" (as per LPPL maintenance status) by
+%%   Jonathan P. Spratte.
+%% 
+%% This work consists of the file  ducksay.dtx
+%% and the derived files           ducksay.pdf
+%%                                 ducksay.sty
+%%                                 ducksay.code.v1.tex
+%%                                 ducksay.code.v2.tex and
+%%                                 ducksay.animals.tex.
+%% 
+\RequirePackage{array}
+\msg_new:nnn { ducksay } { justify~unavailable }
+  {
+    Justified~content~is~not~available~for~tabular~argument~mode~without~fixed~
+    width.~`l`~column~is~used~instead.
+  }
+\msg_new:nnn { ducksay } { unknown~message~alignment }
+  {
+    The~specified~message~alignment~`\exp_not:n { #1 }`~is~unknown.~
+    `l`~is~used~as~fallback.
+  }
+\tl_new:N \l_ducksay_msg_align_vbox_tl
+\box_new:N \l_ducksay_msg_box
+\bool_new:N \l_ducksay_eat_arg_box_bool
+\bool_new:N \l_ducksay_eat_arg_tab_verb_bool
+\bool_new:N \l_ducksay_mirrored_body_bool
+\coffin_new:N \l_ducksay_body_coffin
+\coffin_new:N \l_ducksay_bubble_close_coffin
+\coffin_new:N \l_ducksay_bubble_open_coffin
+\coffin_new:N \l_ducksay_bubble_top_coffin
+\coffin_new:N \l_ducksay_msg_coffin
+\dim_new:N \l_ducksay_hpad_dim
+\dim_new:N \l_ducksay_bubble_bottom_kern_dim
+\dim_new:N \l_ducksay_bubble_top_kern_dim
+\dim_new:N \l_ducksay_msg_width_dim
+\keys_define:nn { ducksay }
+  {
+    ,arg .choice:
+    ,arg / box  .code:n = \bool_set_true:N  \l_ducksay_eat_arg_box_bool
+    ,arg / tab  .code:n =
+      {
+        \bool_set_false:N \l_ducksay_eat_arg_box_bool
+        \bool_set_false:N \l_ducksay_eat_arg_tab_verb_bool
+      }
+    ,arg / tab* .code:n =
+      {
+        \bool_set_false:N \l_ducksay_eat_arg_box_bool
+        \bool_set_true:N  \l_ducksay_eat_arg_tab_verb_bool
+      }
+    ,arg .initial:n = tab
+    ,wd* .dim_set:N = \l_ducksay_msg_width_dim
+    ,wd* .initial:n = -\c_max_dim
+    ,wd* .value_required:n = true
+    ,none          .bool_set:N = \l_ducksay_no_body_bool
+    ,body-mirrored .bool_set:N = \l_ducksay_mirrored_body_bool
+    ,ignore-body   .bool_set:N = \l_ducksay_ignored_body_bool
+    ,body-x      .dim_set:N = \l_ducksay_body_x_offset_dim
+    ,body-x      .value_required:n = true
+    ,body-y      .dim_set:N = \l_ducksay_body_y_offset_dim
+    ,body-y      .value_required:n = true
+    ,body-to-msg .tl_set:N  = \l_ducksay_body_to_msg_align_body_tl
+    ,msg-to-body .tl_set:N  = \l_ducksay_body_to_msg_align_msg_tl
+    ,body-align .choice:
+    ,body-align / l .meta:n = { body-to-msg = l , msg-to-body = l }
+    ,body-align / c .meta:n = { body-to-msg = hc , msg-to-body = hc }
+    ,body-align / r .meta:n = { body-to-msg = r , msg-to-body = r }
+    ,body-align .initial:n = l
+    ,msg-align   .choice:
+    ,msg-align  / l .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { l } }
+    ,msg-align  / c .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { c } }
+    ,msg-align  / r .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { r } }
+    ,msg-align  / j .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { j } }
+    ,msg-align-l .tl_set:N  = \l_ducksay_msg_align_l_tl
+    ,msg-align-l .initial:n = \raggedright
+    ,msg-align-c .tl_set:N  = \l_ducksay_msg_align_c_tl
+    ,msg-align-c .initial:n = \centering
+    ,msg-align-r .tl_set:N  = \l_ducksay_msg_align_r_tl
+    ,msg-align-r .initial:n = \raggedleft
+    ,msg-align-j .tl_set:N  = \l_ducksay_msg_align_j_tl
+    ,msg-align-j .initial:n = {}
+    ,out-h   .tl_set:N  = \l_ducksay_output_h_pole_tl
+    ,out-h   .initial:n = l
+    ,out-v   .tl_set:N  = \l_ducksay_output_v_pole_tl
+    ,out-v   .initial:n = vc
+    ,out-x   .dim_set:N = \l_ducksay_output_x_offset_dim
+    ,out-x   .value_required:n = true
+    ,out-y   .dim_set:N = \l_ducksay_output_y_offset_dim
+    ,out-y   .value_required:n = true
+    ,t       .meta:n    = { out-v = t }
+    ,c       .meta:n    = { out-v = vc }
+    ,b       .meta:n    = { out-v = b }
+    ,body*   .tl_set:N  = \l_ducksay_body_fount_tl
+    ,msg*    .tl_set:N  = \l_ducksay_msg_fount_tl
+    ,bubble* .tl_set:N  = \l_ducksay_bubble_fount_tl
+    ,body*   .initial:n = \verbatim at font
+    ,msg*    .initial:n = \verbatim at font
+    ,bubble* .initial:n = \verbatim at font
+    ,body    .code:n    = \tl_put_right:Nn \l_ducksay_body_fount_tl   { #1 }
+    ,msg     .code:n    = \tl_put_right:Nn \l_ducksay_msg_fount_tl    { #1 }
+    ,bubble  .code:n    = \tl_put_right:Nn \l_ducksay_bubble_fount_tl { #1 }
+    ,MSG     .meta:n    = { msg  = #1 , bubble  = #1 }
+    ,MSG*    .meta:n    = { msg* = #1 , bubble* = #1 }
+    ,hpad    .int_set:N = \l_ducksay_hpad_int
+    ,hpad    .initial:n = 2
+    ,hpad    .value_required:n = true
+    ,vpad    .int_set:N = \l_ducksay_vpad_int
+    ,vpad    .value_required:n = true
+    ,col     .tl_set:N  = \l_ducksay_msg_tabular_column_tl
+    ,bubble-top-kern  .tl_set:N  = \l_ducksay_bubble_top_kern_tl
+    ,bubble-top-kern  .initial:n = { -.5ex }
+    ,bubble-top-kern  .value_required:n = true
+    ,bubble-bot-kern  .tl_set:N  = \l_ducksay_bubble_bottom_kern_tl
+    ,bubble-bot-kern  .initial:n = { .2ex }
+    ,bubble-bot-kern  .value_required:n = true
+    ,bubble-side-kern .tl_set:N  = \l_ducksay_bubble_side_kern_tl
+    ,bubble-side-kern .initial:n = { 0.2em }
+    ,bubble-side-kern .value_required:n = true
+    ,bubble-delim-top     .tl_set:N  = \l_ducksay_bubble_delim_top_tl
+    ,bubble-delim-left-1  .tl_set:N  = \l_ducksay_bubble_delim_left_a_tl
+    ,bubble-delim-left-2  .tl_set:N  = \l_ducksay_bubble_delim_left_b_tl
+    ,bubble-delim-left-3  .tl_set:N  = \l_ducksay_bubble_delim_left_c_tl
+    ,bubble-delim-left-4  .tl_set:N  = \l_ducksay_bubble_delim_left_d_tl
+    ,bubble-delim-right-1 .tl_set:N  = \l_ducksay_bubble_delim_right_a_tl
+    ,bubble-delim-right-2 .tl_set:N  = \l_ducksay_bubble_delim_right_b_tl
+    ,bubble-delim-right-3 .tl_set:N  = \l_ducksay_bubble_delim_right_c_tl
+    ,bubble-delim-right-4 .tl_set:N  = \l_ducksay_bubble_delim_right_d_tl
+    ,bubble-delim-top     .initial:n = { { - } }
+    ,bubble-delim-left-1  .initial:n = (
+    ,bubble-delim-left-2  .initial:n = /
+    ,bubble-delim-left-3  .initial:n = |
+    ,bubble-delim-left-4  .initial:n = \c_backslash_str
+    ,bubble-delim-right-1 .initial:n = )
+    ,bubble-delim-right-2 .initial:n = \c_backslash_str
+    ,bubble-delim-right-3 .initial:n = |
+    ,bubble-delim-right-4 .initial:n = /
+  }
+\cs_new:Npn \ducksay_evaluate_message_alignment_fixed_width_tabular:
+  {
+    \tl_if_empty:NT \l_ducksay_msg_tabular_column_tl
+      {
+        \tl_set:Nx \l_ducksay_msg_tabular_column_tl
+          {
+            >
+            {
+              \str_case:Vn \l_ducksay_msg_align_tl
+                {
+                  { l } { \exp_not:N \l_ducksay_msg_align_l_tl }
+                  { c } { \exp_not:N \l_ducksay_msg_align_c_tl }
+                  { r } { \exp_not:N \l_ducksay_msg_align_r_tl }
+                  { j } { \exp_not:N \l_ducksay_msg_align_j_tl }
+                }
+              \exp_not:N \arraybackslash
+            }
+            p { \exp_not:N \l_ducksay_msg_width_dim }
+          }
+      }
+  }
+\cs_new:Npn \ducksay_evaluate_message_alignment_fixed_width_vbox:
+  {
+    \tl_set:Nx \l_ducksay_msg_align_vbox_tl
+      {
+        \str_case:Vn \l_ducksay_msg_align_tl
+          {
+            { l } { \exp_not:N \l_ducksay_msg_align_l_tl }
+            { c } { \exp_not:N \l_ducksay_msg_align_c_tl }
+            { r } { \exp_not:N \l_ducksay_msg_align_r_tl }
+            { j } { \exp_not:N \l_ducksay_msg_align_j_tl }
+          }
+      }
+  }
+\cs_new:Npn \ducksay_calculate_msg_width_from_int:
+  {
+    \hbox_set:Nn \l_ducksay_tmpa_box { \l_ducksay_msg_fount_tl M }
+    \dim_set:Nn \l_ducksay_msg_width_dim
+      { \l_ducksay_msg_width_int \box_wd:N \l_ducksay_tmpa_box }
+  }
+\cs_new:Npn \ducksay_msg_tabular_begin:
+  {
+    \ducksay_msg_tabular_begin_inner:V \l_ducksay_msg_tabular_column_tl
+  }
+\cs_new:Npn \ducksay_msg_tabular_begin_inner:n #1
+  {
+    \begin { tabular } { @{} #1 @{} }
+  }
+\cs_generate_variant:Nn \ducksay_msg_tabular_begin_inner:n { V }
+\cs_new:Npn \ducksay_msg_tabular_end:
+  {
+    \end { tabular }
+  }
+\cs_new:Npn \ducksay_digest_options:n #1
+  {
+    \keys_set:nn { ducksay } { #1 }
+    \tl_if_empty:NT \l_ducksay_animal_tl
+      { \keys_set:nn { ducksay } { default_animal } }
+    \bool_if:NTF \l_ducksay_eat_arg_box_bool
+      {
+        \dim_compare:nNnTF { \l_ducksay_msg_width_dim } < { \c_zero_dim }
+          {
+            \int_compare:nNnTF { \l_ducksay_msg_width_int } < { \c_zero_int }
+              {
+                \cs_set_eq:NN
+                  \ducksay_eat_argument:w \ducksay_eat_argument_hbox:w
+              }
+              {
+                \cs_set_eq:NN
+                  \ducksay_eat_argument:w \ducksay_eat_argument_vbox:w
+                \ducksay_calculate_msg_width_from_int:
+              }
+          }
+          {
+            \cs_set_eq:NN \ducksay_eat_argument:w \ducksay_eat_argument_vbox:w
+          }
+      }
+      {
+        \dim_compare:nNnTF { \l_ducksay_msg_width_dim } < { \c_zero_dim }
+          {
+            \int_compare:nNnTF { \l_ducksay_msg_width_int } < { \c_zero_int }
+              {
+                \tl_if_empty:NT \l_ducksay_msg_tabular_column_tl
+                  {
+                    \str_case:Vn \l_ducksay_msg_align_tl
+                      {
+                        { l }
+                          { \tl_set:Nn \l_ducksay_msg_tabular_column_tl { l } }
+                        { c }
+                          { \tl_set:Nn \l_ducksay_msg_tabular_column_tl { c } }
+                        { r }
+                          { \tl_set:Nn \l_ducksay_msg_tabular_column_tl { r } }
+                        { j } {
+                          \msg_error:nn { ducksay } { justify~unavailable }
+                          \tl_set:Nn \l_ducksay_msg_tabular_column_tl { l }
+                        }
+                      }
+                  }
+              }
+              {
+                \ducksay_calculate_msg_width_from_int:
+                \ducksay_evaluate_message_alignment_fixed_width_tabular:
+              }
+          }
+          {
+            \ducksay_evaluate_message_alignment_fixed_width_tabular:
+          }
+        \cs_set_eq:NN \ducksay_eat_argument:w \ducksay_eat_argument_tabular:w
+      }
+  }
+\cs_new:Npn \ducksay_set_bubble_top_kern:
+  {
+    \group_begin:
+    \l_ducksay_bubble_fount_tl
+    \exp_args:NNNx
+    \group_end:
+    \dim_set:Nn \l_ducksay_bubble_top_kern_dim
+      { \dim_eval:n { \l_ducksay_bubble_top_kern_tl } }
+  }
+\cs_new:Npn \ducksay_set_bubble_bottom_kern:
+  {
+    \group_begin:
+    \l_ducksay_bubble_fount_tl
+    \exp_args:NNNx
+    \group_end:
+    \dim_set:Nn \l_ducksay_bubble_bottom_kern_dim
+      { \dim_eval:n { \l_ducksay_bubble_bottom_kern_tl } }
+  }
+\cs_new_protected:Npn \ducksay_shipout:
+  {
+    \hbox_set:Nn \l_ducksay_tmpa_box
+      { \l_ducksay_bubble_fount_tl \l_ducksay_bubble_delim_top_tl }
+    \int_set:Nn \l_ducksay_msg_width_int
+      {
+        \fp_eval:n
+          {
+            ceil
+              ( \box_wd:N \l_ducksay_msg_box / \box_wd:N \l_ducksay_tmpa_box )
+          }
+      }
+    \group_begin:
+    \l_ducksay_bubble_fount_tl
+    \exp_args:NNNx
+    \group_end:
+    \int_set:Nn \l_ducksay_msg_height_int
+      {
+        \int_max:nn
+          {
+            \fp_eval:n
+              {
+                ceil
+                  (
+                    (
+                      \box_ht:N \l_ducksay_msg_box
+                      + \box_dp:N \l_ducksay_msg_box
+                    )
+                    / ( \arraystretch * \baselineskip )
+                  )
+              }
+            + \l_ducksay_vpad_int
+          }
+          { \l_ducksay_msg_height_int }
+      }
+    \hcoffin_set:Nn \l_ducksay_bubble_open_coffin
+      {
+        \l_ducksay_bubble_fount_tl
+        \begin{tabular}{@{}l@{}}
+          \int_compare:nNnTF { \l_ducksay_msg_height_int } = { \c_one_int }
+            {
+              \l_ducksay_bubble_delim_left_a_tl
+            }
+            {
+              \l_ducksay_bubble_delim_left_b_tl\\
+              \int_step_inline:nnn
+                { 3 } { \l_ducksay_msg_height_int }
+                {
+                  \kern-\l_ducksay_bubble_side_kern_tl
+                  \l_ducksay_bubble_delim_left_c_tl
+                  \\
+                }
+              \l_ducksay_bubble_delim_left_d_tl
+            }
+        \end{tabular}
+      }
+    \hcoffin_set:Nn \l_ducksay_bubble_close_coffin
+      {
+        \l_ducksay_bubble_fount_tl
+        \begin{tabular}{@{}r@{}}
+          \int_compare:nNnTF { \l_ducksay_msg_height_int } = { \c_one_int }
+            {
+              \l_ducksay_bubble_delim_right_a_tl
+            }
+            {
+              \l_ducksay_bubble_delim_right_b_tl \\
+              \int_step_inline:nnn
+                { 3 } { \l_ducksay_msg_height_int }
+                {
+                  \l_ducksay_bubble_delim_right_c_tl
+                  \kern-\l_ducksay_bubble_side_kern_tl
+                  \\
+                }
+              \l_ducksay_bubble_delim_right_d_tl
+            }
+        \end{tabular}
+      }
+    \hcoffin_set:Nn \l_ducksay_bubble_top_coffin
+      {
+        \l_ducksay_bubble_fount_tl
+        \int_step_inline:nn { \l_ducksay_msg_width_int + \l_ducksay_hpad_int }
+          { \l_ducksay_bubble_delim_top_tl }
+      }
+    \hcoffin_set:Nn \l_ducksay_msg_coffin { \box_use:N \l_ducksay_msg_box }
+    \bool_if:NF \l_ducksay_no_body_bool
+      {
+        \hcoffin_set:Nn \l_ducksay_body_coffin
+          {
+            \frenchspacing
+            \l_ducksay_body_fount_tl
+            \begin{tabular} { @{} l @{} }
+              \l_ducksay_animal_tl
+            \end{tabular}
+          }
+        \bool_if:NT \l_ducksay_mirrored_body_bool
+          {
+            \coffin_scale:Nnn \l_ducksay_body_coffin
+              { -\c_one_int } { \c_one_int }
+            \str_case:Vn \l_ducksay_body_to_msg_align_body_tl
+              {
+                { l } { \tl_set:Nn \l_ducksay_body_to_msg_align_body_tl { r } }
+                { r } { \tl_set:Nn \l_ducksay_body_to_msg_align_body_tl { l } }
+              }
+          }
+      }
+    \dim_set:Nn \l_ducksay_hpad_dim
+      {
+        (
+          \coffin_wd:N \l_ducksay_bubble_top_coffin
+          - \coffin_wd:N \l_ducksay_msg_coffin
+        ) / 2
+      }
+    \coffin_join:NnnNnnnn
+      \l_ducksay_msg_coffin         { l } { vc }
+      \l_ducksay_bubble_open_coffin { r } { vc }
+      { - \l_ducksay_hpad_dim } { \c_zero_dim }
+    \coffin_join:NnnNnnnn
+      \l_ducksay_msg_coffin          { r } { vc }
+      \l_ducksay_bubble_close_coffin { l } { vc }
+      { \l_ducksay_hpad_dim } { \c_zero_dim }
+    \ducksay_set_bubble_top_kern:
+    \ducksay_set_bubble_bottom_kern:
+    \coffin_join:NnnNnnnn
+      \l_ducksay_msg_coffin        { hc } { t }
+      \l_ducksay_bubble_top_coffin { hc } { b }
+      { \c_zero_dim } { \l_ducksay_bubble_top_kern_dim }
+    \coffin_join:NnnNnnnn
+      \l_ducksay_msg_coffin        { hc } { b }
+      \l_ducksay_bubble_top_coffin { hc } { t }
+      { \c_zero_dim } { \l_ducksay_bubble_bottom_kern_dim }
+    \bool_if:NF \l_ducksay_no_body_bool
+      {
+        \bool_if:NTF \l_ducksay_ignored_body_bool
+          { \coffin_attach:NVnNVnnn }
+          { \coffin_join:NVnNVnnn   }
+          \l_ducksay_msg_coffin  \l_ducksay_body_to_msg_align_msg_tl  { b }
+          \l_ducksay_body_coffin \l_ducksay_body_to_msg_align_body_tl { t }
+          { \l_ducksay_body_x_offset_dim } { \l_ducksay_body_y_offset_dim }
+      }
+    \coffin_typeset:NVVnn \l_ducksay_msg_coffin
+      \l_ducksay_output_h_pole_tl \l_ducksay_output_v_pole_tl
+      { \l_ducksay_output_x_offset_dim } { \l_ducksay_output_y_offset_dim }
+    \group_end:
+  }
+\cs_new:Npn \ducksay_eat_argument_tabular:w
+  {
+    \bool_if:NTF \l_ducksay_eat_arg_tab_verb_bool
+      { \ducksay_eat_argument_tabular_verb:w }
+      { \ducksay_eat_argument_tabular_normal:w }
+  }
+\cs_new:Npn \ducksay_eat_argument_tabular_inner:w #1
+  {
+    \hbox_set:Nn \l_ducksay_msg_box
+      {
+        \l_ducksay_msg_fount_tl
+        \ducksay_msg_tabular_begin:
+          #1
+        \ducksay_msg_tabular_end:
+      }
+    \ducksay_shipout:
+  }
+\NewDocumentCommand \ducksay_eat_argument_tabular_verb:w
+  { >{ \ducksay_process_verb_newline:nnn { ~ } { ~ \par } } +v }
+  { \ducksay_eat_argument_tabular_inner:w { \scantokens { #1 } } }
+\NewDocumentCommand \ducksay_eat_argument_tabular_normal:w { +m }
+  { \ducksay_eat_argument_tabular_inner:w { #1 } }
+\cs_new_protected_nopar:Npn \ducksay_eat_argument_hbox:w
+  {
+    \afterassignment \ducksay_eat_argument_hbox_inner:w
+    \let \l_ducksay_nothing =
+  }
+\cs_new_protected_nopar:Npn \ducksay_eat_argument_hbox_inner:w
+  {
+    \setbox \l_ducksay_msg_box \hbox \c_group_begin_token
+      \group_insert_after:N \ducksay_shipout:
+      \l_ducksay_msg_fount_tl
+  }
+\cs_new_protected_nopar:Npn \ducksay_eat_argument_vbox:w
+  {
+    \ducksay_evaluate_message_alignment_fixed_width_vbox:
+    \afterassignment \ducksay_eat_argument_vbox_inner:w
+    \let \l_ducksay_nothing =
+  }
+\cs_new_protected_nopar:Npn \ducksay_eat_argument_vbox_inner:w
+  {
+    \setbox \l_ducksay_msg_box \vbox \c_group_begin_token
+      \hsize \l_ducksay_msg_width_dim
+      \group_insert_after:N \ducksay_shipout:
+      \l_ducksay_msg_fount_tl
+      \l_ducksay_msg_align_vbox_tl
+      \@afterindentfalse
+      \@afterheading
+  }
+\cs_generate_variant:Nn \coffin_join:NnnNnnnn { NVnNVnnn }
+\cs_generate_variant:Nn \coffin_attach:NnnNnnnn { NVnNVnnn }
+\cs_generate_variant:Nn \coffin_typeset:Nnnnn { NVVnn }
+\cs_generate_variant:Nn \tl_if_eq:nnT { VnT }
+\cs_generate_variant:Nn \str_case:nn { Vn }
+\cs_generate_variant:Nn \regex_replace_all:NnN { Nnc }
+\NewDocumentCommand \ducksay { O{} }
+  {
+    \group_begin:
+      \tl_set:Nn \l_ducksay_say_or_think_tl { say }
+      \ducksay_digest_options:n { #1 }
+      \ducksay_eat_argument:w
+  }
+\NewDocumentCommand \duckthink { O{} }
+  {
+    \group_begin:
+      \tl_set:Nn \l_ducksay_say_or_think_tl { think }
+      \ducksay_digest_options:n { #1 }
+      \ducksay_eat_argument:w
+  }
+%% 
+%%
+%% End of file `ducksay.code.v2.tex'.


Property changes on: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.code.v2.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.hd
===================================================================
--- trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.hd	2018-09-21 00:23:48 UTC (rev 48719)
+++ trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.hd	2018-09-21 21:06:08 UTC (rev 48720)

Property changes on: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.hd
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.pdf
===================================================================
(Binary files differ)

Deleted: trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.tex	2018-09-21 00:23:48 UTC (rev 48719)
+++ trunk/Master/texmf-dist/doc/latex/ducksay/ducksay.tex	2018-09-21 21:06:08 UTC (rev 48720)
@@ -1,240 +0,0 @@
-%% This package is distributed under the terms of the GPLv3 or later, or the
-%% LPPL 1.3c or later, which ever license fits your needs the best.
-%%
-%% Copyright (C) 2017 by Jonathan P. Spratte
-%%
-%% This file is for documentation only
-\documentclass[a4paper,10pt]{article}
-
-%\usepackage[utf8]{inputenc}
-%\usepackage[T1]{fontenc}
-\usepackage[ligatures]{ducksay}
-\usepackage{multicol}
-\usepackage[colorlinks]{hyperref}
-\usepackage{lmodern}
-
-\makeatletter
-\newcommand*{\availableAnimal}[1]{\@for\cs:=#1\do{%
-  \ifx\cs\@empty\else%
-    \rlap{\expandafter\ducksay\expandafter[\cs]{\cs}}\hfill\mbox{}\\[1ex]%
-  \fi%
-}}
-\makeatother
-\newcommand*{\anml}{\texttt{<animal>}}
-\newcommand*{\msg}{\texttt{<message>}}
-\newenvironment{codedescription}{%
-  \parindent=-3em%
-  \parskip=1em%
-  \par%
-}{}
-
-\begin{document}
-\begin{titlepage}%>>>
-  \makeatletter
-  \centering
-  %\mbox{}\vfill
-  \Large
-    \ducksay[duck,bubble=\huge,msg-align=c,wd=8]{This is\\ducksay!}\\
-  \vfill
-  \normalsize
-  \hspace*{-2cm}
-    \ducksay[cow,bubble=\large]{\ducksay at version}\\
-  \small
-  \vspace*{-5cm}\hspace*{5cm}
-    \ducksay[small-duck,bubble=\normalsize]{But which Version?}
-  \mbox{}\hfil
-  \vspace{2cm}
-  \vfill
-  \vfill
-  \hspace*{-0cm}
-  \large
-  \smash{%
-    \ducksay[r2d2,bubble=\large]{by Jonathan P. Spratte}}
-  \small
-    \ducksay[hedgehog,bubble=\normalsize]{Today is \ducksay at date}
-  \makeatother
-\end{titlepage}%<<<
-\tableofcontents
-\section{Macros}%>>>
-\marginpar{%
-  \rlap{%
-    \tiny\ducksay[yoda,bubble=\footnotesize,align=t]{Use those, you might}}}
-The following macros are available:
-
-\begin{codedescription}
-\verb|\ducksay[<options>]{<message>}|\\
-  options might include any of the options described in
-  \autoref{sec:options}. Prints an \anml\ saying \msg. \msg\ is not read in
-  verbatim. Multi-line \msg s are possible using \verb|\\|. \verb|\\| should not
-  be inside a macro but at toplevel. Else use the option \texttt{ht}.
-
-\verb|\duckthink[<options>]{<message>}|\\
-  options might include any of the options described in
-  \autoref{sec:options}. Prints an \anml\ thinking \msg. \msg\ is not read in
-  verbatim. It is implemented using regular expressions replacing a \verb|\|
-  which is only preceded by \verb|\s*| in the first three lines with \verb|O|
-  and \verb|o|. It is therefore slower than \verb|\ducksay|. Multi-line \msg s
-  are possible using \verb|\\|. \verb|\\| should not be inside a macro but at
-  toplevel. Else use the option \texttt{ht}.
-
-\verb|\DefaultAnimal{<animal>}|\\
-  use the \anml\ if none is given in the optional argument to \verb|\ducksay| or
-  \verb|\duckthink|. Package default is \texttt{duck}.
-
-\verb|\DucksayOptions{<options>}|\\
-  set the defaults to the keys described in \autoref{sec:options}. Don't use an
-  \anml\ here, it has no effect.
-
-\verb|\AddAnimal(*){<animal>}<ascii-art>|\\
-  adds \anml\ to the known animals. \texttt{<ascii-art>} is multi-line verbatim
-  and therefore should be delimited either by matching braces or by anything
-  that works for \verb|\verb|. If the star is given \anml\ is the new default.
-  One space is added to the begin of \anml\ (compensating the opening symbol).
-  For example, snowman is added with:\\[1ex]
-  \begin{minipage}{\linewidth}
-\begin{verbatim}
-\AddAnimal{snowman}
-{  \
-    \_[_]_
-      (")
-   >-( : )-<
-    (__:__)}
-\end{verbatim}
-  \end{minipage}
-\end{codedescription}
-%<<<
-\section{Options}\label{sec:options}%>>>
-{\reversemarginpar\marginpar{%
-  \vspace*{-2em}\hspace*{-4em}%
-  \tiny%
-  \ducksay[hedgehog,bubble=\footnotesize,align=t]{Everyone likes\\options}}}
-The following options are available to \verb|\ducksay|, \verb|\duckthink|, and
-\verb|\DucksayOptions| and if not otherwise specified also as package options:
-
-\begin{codedescription}
-\anml\\
-  One of the animals listed in \autoref{sec:animals} or any of the ones added
-  with \verb|\AddAnimal|. Not useable as package option.
-
-\texttt{animal=\anml}\\
-  a longer alternative to the use of \anml\ if used in \verb|\ducksay| or
-  \verb|\duckthink|. If it is used as a package option or in
-  \verb|\DucksayOptions| it changes the default animal to \anml.
-
-\texttt{bubble=\#1}\\
-  use \texttt{\#1} in a group right before the bubble (for font switches). Might
-  be used as a package option but not all control sequences work out of the box
-  there.
-
-\texttt{body=\#1}\\
-  use \texttt{\#1} in a group right before the body (meaning the \anml). Might
-  be used as a package option but not all control sequences work out of the box
-  there. E.g., to right-align the \anml\ to the bubble, use \verb|body=\hfill|.
-
-\texttt{align=\#1}\\
-  use \texttt{\#1} as the vertical alignment specifier given to the
-  \texttt{tabular} which is around the contents of \verb|\ducksay| and
-  \verb|\duckthink|.
-
-\texttt{msg-align=\#1}\\
-  use \texttt{\#1} for alignment of the rows of multi-line \msg s. It should
-  match a \texttt{tabular} column specifier. Default is \texttt{l}. It only
-  affects the contents of the speech bubble not the bubble.
-
-\texttt{wd=\#1}\\
-  in order to detect the width the \msg\ is expanded. This might not work out
-  for some commands (e.g. \verb|\url| from \texttt{hyperref}). If you specify
-  the width using \texttt{wd} the \msg\ is not expanded and therefore the
-  command \emph{might} work out. \texttt{\#1} should be the character count.
-
-\texttt{ht=\#1}\\
-  you might explicitly set the height (the row count) of the \msg. This only has
-  an effect if you also specify \texttt{wd}.
-
-\texttt{ligatures=\#1}\\
-  this is a \LaTeX3 regular expression which should match every character you
-  don't want to form ligatures during \verb|\AddAnimal|. The default expression
-  is \verb|[\-<>`]|. Giving no argument (or an empty one) disables the
-  replacement, which enhances compilation speed. The formation of ligatures was
-  only observed in combination with \verb|\usepackage[T1]{fontenc}| by the
-  author of this package. Therefore giving the option \texttt{ligatures} without
-  an argument might enhance the compilation speed for you without any
-  drawbacks.
-\end{codedescription}
-  %<<<
-\section{Defects}%>>>
-{\reversemarginpar\marginpar{%
-  \tiny\rlap{\ducksay[frog,bubble=\footnotesize,align=t]{Ohh, no!}}}}
-\begin{itemize}
-  \item no automatic line wrapping
-\end{itemize}
-%<<<
-\section{Dependencies}%>>>
-\marginpar{%
-  \tiny\rlap{\ducksay[kangaroo,bubble=\footnotesize,align=t]{We rely on you}}}
-The package depends on the two packages \texttt{xparse} and \texttt{l3keys2e}
-and all of their dependencies.
-%<<<
-%\clearpage
-\section{Available Animals}\label{sec:animals}%>>>
-The following animals are provided by this package. I did not create them (but
-altered some), they belong to their original creators.
-\bgroup
-\footnotesize
-\begin{multicols}{2}
-\availableAnimal{%>>>
-  ,duck%
-  ,small-duck%
-  ,duck-family%
-  ,small-rabbit%
-  ,squirrel%
-  ,cow%
-  ,tux%
-  ,head-in%
-  ,pig%
-  ,frog%
-  ,snowman%
-  ,bunny%
-  ,dragon%
-  ,sodomized%
-  ,hedgehog%
-  ,kangaroo%
-  ,dog%
-  ,rabbit%
-  ,unicorn%
-}\end{multicols}\begin{multicols}{2}
-\availableAnimal{%
-  ,r2d2%
-  ,vader%
-  ,yoda-head%
-  ,small-yoda%
-  ,yoda%
-}%<<<
-\end{multicols}
-\egroup
-%<<<
-\section{Miscellaneous}%>>>
-\marginpar{%
-  \rlap{\tiny\ducksay[squirrel,bubble=\footnotesize,align=t]{I'd choose WTFPL}}}
-This package is distributed under the terms of the GPLv3 or later, or the LPPL
-1.3c or later, choose which ever license fits your needs the best.
-
-The package is hosted on \url{https://github.com/Skillmon/ltx_ducksay}, you
-might report bugs there.
-%<<<
-\clearpage
-% closing page>>>
-\thispagestyle{empty}
-\bgroup
-\Huge
-\mbox{}\vfill
-\centering
-\makebox[0pt]{\duckthink{Who's gonna use it anyway?}}
-\vfill
-\hfill\smash{\footnotesize\ducksay[small-yoda,wd=49]{hosted at
-  \url{https://github.com/Skillmon/ltx_ducksay}}}
-\egroup
-%<<<
-\end{document}
-
-% vim: fdm=marker foldmarker=>>>,<<<

Added: trunk/Master/texmf-dist/source/latex/ducksay/ducksay.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/ducksay/ducksay.dtx	                        (rev 0)
+++ trunk/Master/texmf-dist/source/latex/ducksay/ducksay.dtx	2018-09-21 21:06:08 UTC (rev 48720)
@@ -0,0 +1,2291 @@
+% \iffalse meta-comment
+%
+% File: ducksay.dtx Copyright (C) 2017-2018 Jonathan P. Spratte
+%
+% This work  may be  distributed and/or  modified under  the conditions  of the
+% LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
+% (at your option) any later version.  The latest version of this license is in
+% the file:
+%
+%   http://www.latex-project.org/lppl.txt
+%
+% Alternatively you can use this work under the terms of the GNU General Public
+% Licensce (GPL), version 3 or later, except that you might not redistribute it
+% under the same  name if you change  its functionality.  Choose which of these
+% licenses fits your needs the best.
+%
+% ------------------------------------------------------------------------------
+%
+%<*driver>^^A>>>
+\def\nameofplainTeX{plain}
+\ifx\fmtname\nameofplainTeX\else
+  \expandafter\begingroup
+\fi
+\input l3docstrip.tex
+\askforoverwritefalse
+\preamble
+
+--------------------------------------------------------------
+ducksay -- cowsay for LaTeX
+E-mail: jspratte at yahoo.de
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+--------------------------------------------------------------
+
+Copyright (C) 2017-2018 Jonathan P. Spratte
+
+This  work may be  distributed and/or  modified under  the conditions  of the
+LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
+(at your option) any later version.  The latest version of this license is in
+the file:
+
+  http://www.latex-project.org/lppl.txt
+
+Alternatively you can use this work under the terms of the GNU General Public
+Licensce (GPL), version 3 or later, except that you might not redistribute it
+under the same  name if you change  its functionality.  Choose which of these
+licenses fits your needs the best.
+
+This work is "maintained" (as per LPPL maintenance status) by
+  Jonathan P. Spratte.
+
+This work consists of the file  ducksay.dtx
+and the derived files           ducksay.pdf
+                                ducksay.sty
+                                ducksay.code.v1.tex
+                                ducksay.code.v2.tex and
+                                ducksay.animals.tex.
+
+\endpreamble
+% stop docstrip adding \endinput
+\postamble
+\endpostamble
+\generate{\file{ducksay.sty}{\from{ducksay.dtx}{pkg}}}
+\generate{\file{ducksay.code.v1.tex}{\from{ducksay.dtx}{code.v1}}}
+\generate{\file{ducksay.code.v2.tex}{\from{ducksay.dtx}{code.v2}}}
+\generate{\file{ducksay.animals.tex}{\from{ducksay.dtx}{animals}}}
+\ifx\fmtname\nameofplainTeX
+  \expandafter\endbatchfile
+\else
+  \expandafter\endgroup
+\fi
+%
+\ProvidesFile{ducksay.dtx}
+  [\csname ducksay at date\endcsname\ cowsay for LaTeX]
+\documentclass{l3doc}
+\usepackage[version=2]{ducksay}
+\let\metaORIG\meta
+\protected\def\meta #1{\texttt{\metaORIG{#1}}}
+\DucksayOptions{arg=tab,msg-align=l,vpad=1}
+\renewcommand*\thefootnote{\fnsymbol{footnote}}
+\newcommand*\anml{\meta{animal}}
+\newcommand*\msg{\meta{message}}
+\newcommand*\PolesInfo
+  {%
+    \href{https://ctan.org/pkg/l3kernel}{\file{interface3.pdf}} and the
+    documentation of \href{https://ctan.org/pkg/xcoffins}{\pkg{xcoffins}} for
+    information about coffin poles.%
+  }
+\usepackage{enumitem}
+\newenvironment{options}[1][]
+  {%
+    \begin{description}
+      [
+        style=nextline
+        ,font=\normalfont\ttfamily
+        ,labelindent=-.5\marginparwidth
+        ,labelwidth=\dimexpr.5\marginparwidth-5pt\relax
+        ,labelsep*=5pt
+        ,leftmargin=!
+        ,#1
+      ]%
+    \renewenvironment{options}[1][]
+      {%
+        \begin{description}
+          [
+            style=nextline
+            ,font=\normalfont\ttfamily
+            ,#1
+          ]%
+      }
+      {\end{description}}%
+  }
+  {\end{description}}
+\makeatletter
+\newcommand*\availableAnimal[1]
+  {%
+    \@for\cs:=#1\do
+      {%
+        \ifx\cs\@empty\else
+          \rlap{\expandafter\ducksay\expandafter[\cs]{\cs}}\hfill\null\par%
+        \fi
+      }%
+  }
+\def\@oddfoot
+  {%
+    \null\hfil
+    \makebox[0pt][c]
+      {%
+        \smash
+          {%
+            \ducksay
+              [dog,body=\tiny,wd=3,msg-align=c,out-v=T,MSG=\normalsize,vpad=0]
+              {\thepage}%
+          }%
+      }%
+    \hfil\null
+  }
+\let\@evenfoot\@oddfoot
+\def\@oddhead
+  {%
+    \null\hfill\firstmark
+  }
+\let\@evenhead\@oddhead
+\newcommand\DocImp{}
+\newcommand\SetVersion[1]
+  {%
+    \clearpage
+    \if\relax\detokenize{#1}\relax
+      \markboth{}{}%
+    \else
+      \markboth{}{\DocImp\ of Version #1}%
+    \fi
+  }
+\makeatother
+\setcounter{secnumdepth}{5}
+\setcounter{tocdepth}{5}
+\NewDocumentCommand \tocmsg {}
+  {%
+    \marginpar
+      {%
+        \tiny
+        \hfil
+        \makebox[.\marginparwidth][l]
+          {%
+            \ducksay[head-in,MSG=\footnotesize,msg-align=c,align=t]
+              {It's always\\good to\\keep the\\overview!}%
+          }%
+      }%
+    \unskip
+  }
+\addtocontents{toc}{\protect\tocmsg\vspace*{-\baselineskip}}
+\newcommand*\closingpage%>>>
+  {%
+    \clearpage
+    \thispagestyle{empty}
+    \bgroup
+    \Huge
+    \null\vfill
+    \centering
+    \makebox[0pt]{\duckthink{Who's gonna use it anyway?}}
+    \vfill
+    \hfill
+    \smash
+      {%
+        \footnotesize
+        \ducksay[small-yoda,wd=39,ht=3,msg-align=c,rel-align=r]
+          {Hosted at\\\url{https://github.com/Skillmon/ltx_ducksay}\\it is.}%
+      }
+    \egroup
+    \clearpage
+  }%<<<
+\begin{document}
+  \DocInput{ducksay.dtx}
+\end{document}
+%</driver>^^A<<<
+%<*pkg>^^A>>>
+\NeedsTeXFormat{LaTeX2e}
+\RequirePackage{xparse,l3keys2e}
+
+\def\ducksay at version{2.0}
+\def\ducksay at date{2018/09/21}
+
+\ProvidesExplPackage
+  {ducksay}           {\ducksay at date}
+  {\ducksay at version}  {cowsay for LaTeX}
+
+%</pkg>
+%^^A<<<
+% \fi
+%
+% \begin{titlepage}^^A>>>
+%   \DucksayOptions{vpad=0}%
+%   \makeatletter
+%   \centering
+%   \Large
+%     \ducksay[duck,MSG=\huge,msg-align=c]{This is\\\pkg{ducksay}!}\\
+%   \vfill
+%   \normalsize
+%   \hspace*{-2cm}
+%     \ducksay[cow,MSG=\large,body-mirrored,body-align=r,msg-to-body=hc,out-h=r]
+%       {v\ducksay at version}\\
+%   \small
+%   \vspace*{-5cm}\hspace*{5cm}
+%     \ducksay[small-duck,MSG=\normalsize]{But which Version?}
+%   \null\hfil
+%   \vspace{2cm}
+%   \vfill
+%   \vfill
+%   \hspace*{-0cm}
+%   \large
+%   \smash{%
+%     \ducksay[r2d2,MSG=\large,body-mirrored,msg-to-body=hc,body-to-msg=r]
+%       {by Jonathan P. Spratte}}
+%   \small
+%     \ducksay[hedgehog,MSG=\normalsize]{Today is \ducksay at date}
+%   \makeatother
+% \end{titlepage}^^A<<<
+% \tableofcontents
+%
+% \begin{documentation}^^A>>>
+%
+% \section{Documentation}\def\DocImp{Documentation}%
+%
+% \subsection{Downward Compatibility Issues}
+% \marginpar^^A>>>
+%   {
+%     \tiny
+%     \ducksay[snail,MSG=\footnotesize,align=t]{Yep, I screwed up!}
+%   }^^A<<<
+%
+% \begin{itemize}
+%   \item Versions prior to v2.0 did use a regular expression for the option
+%     |ligatures|, see \autoref{sec:options} for more on this issue. With v2.0
+%     I do refer to the package's version, not the code variant which can be
+%     selected with the |version| option.
+%   \item In a document created with package versions prior to v2.0 you'll have
+%     to specify the option |version=1| in newer versions to make those old
+%     documents behave like they used to. 
+% \end{itemize}
+%
+% \subsection{Shared between versions}
+%
+% \subsubsection{Macros}^^A>>>
+% \marginpar^^A>>>
+%   {
+%     \tiny
+%     \hfill
+%     \ducksay[bunny,MSG=\footnotesize,align=t,body-mirrored]
+%       {Macros for everyone!}
+%   }^^A<<<
+%
+% A careful reader might notice that in the below list of macros there is no
+% \cs{ducksay} and no \cs{duckthink} contained. This is due to differences
+% between the two usable code variants (see the |version| key in
+% \autoref{sec:options} for the code variants, \autoref{sec:macros1} and
+% \autoref{sec:macros2} for descriptions of the two macros).
+%
+% \begin{function}{\DefaultAnimal}^^A>>>
+%   \begin{syntax}
+%     \cs{DefaultAnimal}\marg{animal}
+%   \end{syntax}
+%   use the \anml\ if none is given in the optional argument to \cs{ducksay}
+%   or \cs{duckthink}. Package default is |duck|.
+% \end{function}^^A<<<
+%
+% \begin{function}{\DucksayOptions}^^A>>>
+%   \begin{syntax}
+%     \cs{DucksayOptions}\marg{options}
+%   \end{syntax}
+%   set the defaults to the keys described in \autoref{sec:options},
+%   \autoref{sec:options1} and \autoref{sec:options2}. Don't use an \anml\ here,
+%   it has no effect.
+% \end{function}^^A<<<
+%
+% \begin{function}{\AddAnimal}^^A>>>
+%   \begin{syntax}
+%     \cs{AddAnimal}\meta{*}\marg{animal}\meta{ascii-art}
+%   \end{syntax}
+%   adds \anml\ to the known animals. \meta{ascii-art} is multi-line verbatim
+%   and therefore should be delimited either by matching braces or by anything
+%   that works for \cs{verb}. If the star is given \anml\ is the new default.
+%   One space is added to the begin of \anml\ (compensating the opening symbol).
+%   For example, |snowman| is added with:\\[1ex]
+%   \begin{minipage}{\linewidth}
+%\begin{verbatim}
+% \AddAnimal{snowman}
+% {  \
+%     \ _[_]_
+%        (")
+%     >-( : )-<
+%      (__:__)}
+%\end{verbatim}
+%   \end{minipage}
+%   It is not checked whether the animal already exists, you could therefore
+%   redefine existing animals with this macro.\\
+%   The symbols signalizing the speech (in the |snowman| example above the two
+%   backslashes) should at most be used in the first three lines, as they get
+%   replaced by |O| and |o| for \cs{duckthink}. They also shouldn't be preceded
+%   by anything other than a space in that line.
+% \end{function}^^A<<<
+%
+% \begin{function}{\AddColoredAnimal}^^A>>>
+%   \begin{syntax}
+%     \cs{AddColoredAnimal}\meta{*}\marg{animal}\meta{ascii-art}
+%   \end{syntax}
+%   It does the same as \cs{AddAnimal} but allows three different colouring
+%   syntaxes. You can use \cs{textcolor} in the \meta{ascii-art} with the syntax
+%   \texttt{\cs{textcolor}\marg{color}\marg{text}}. Note that you can't
+%   use braces in the arguments of \cs{textcolor}.\\
+%   You can also use a delimited \cs{color} of the form
+%   \texttt{\cs{bgroup}\cs{color}\marg{color}\meta{text}\cs{egroup}}, a space
+%   after that |\egroup| will be considered a space in the output, you don't
+%   have to leave a space after the |\egroup| (so
+%   |\bgroup\color{red}RedText\egroupOtherText| is valid syntax). You can't nest
+%   delimited \cs{color}s.\\
+%   Also you can use an undelimited \cs{color}. It affects anything until the
+%   end of the current line (or, if used inside of the \meta{text} of an
+%   delimited \cs{color}, anything until the end of that delimited \cs{color}'s
+%   \meta{text}). The syntax would be \cs{color}\marg{color}.\\
+%   The package doesn't load anything providing those colouring commands for you
+%   and it doesn't provide any coloured animals. The parsing is done using
+%   regular expressions provided by \LaTeX3. It is therefore slower than the
+%   normal \cs{AddAnimal}.
+% \end{function}^^A<<<
+%
+%^^A<<<
+%
+% \subsubsection{Options}\label{sec:options}^^A>>>
+% \marginpar
+%   {%
+%     \vspace*{-2em}\tiny
+%     \ducksay[pig,MSG=\footnotesize,align=t]{Options.\\For every occasion}%
+%   }
+% The following options are available independent on the used code variant (the
+% value of the |version| key). They might be used as package options -- unless
+% otherwise specified -- or used in the macros \cs{DucksayOptions}, \cs{ducksay}
+% and \cs{duckthink} -- again unless otherwise specified. Some options might be
+% accessible in both code variants but do slightly different things. If that's
+% the case they will be explained in \autoref{sec:options1} and
+% \autoref{sec:options2} for |version| 1 and 2, respectively.
+% \begin{options}
+%   \item[version=\meta{number}]
+%     With this you can choose the code variant to be used. Currently |1| and
+%     |2| are available. This can be set only during package load time. For a
+%     dedicated description of each version look into \autoref{sec:v1} and
+%     \autoref{sec:v2}. The package author would choose |version=2|, the other
+%     version is mostly for legacy reasons. The default is |2|.
+%   \item[\anml] 
+%     One of the animals listed in \autoref{sec:animals} or any of the ones
+%     added with \cs{AddAnimal}. Not useable as package option. Also don't use
+%     it in \cs{DucksayOptions}, it'll break the default animal selection.
+%   \item[animal=\anml]
+%     Locally sets the default animal. Note that \cs{ducksay} and \cs{duckthink}
+%     do digest their options inside of a group, so it just results in
+%     a longer alternative to the use of \anml\ if used in their options.
+%   \item[ligatures=\meta{token list}]
+%     each token you don't want to form ligatures during \cs{AddAnimal} should
+%     be contained in this list. All of them get enclosed by grouping |{| and
+%     |}| so that they can't form ligatures. Giving no argument (or an empty
+%     one) might enhance compilation speed by disabling this replacement. The
+%     formation of ligatures was only observed in combination with
+%     \verb|\usepackage[T1]{fontenc}| by the author of this package. Therefore
+%     giving the option |ligatures| without an argument might enhance the
+%     compilation speed for you without any drawbacks. Initially this is set to
+%     \texttt{\csuse{\detokenize{l_ducksay_ligatures_tl}}}.\\
+%     \textbf{Note:} In earlier releases this option's expected argument was a
+%     regular expression. This means that this option is not fully
+%     downward compatible with older versions. The speed gain however seems
+%     worth it (and I hope the affected documents are few).
+%   \item[add-think=\meta{bool}]
+%     by default the animals for \cs{duckthink} are not created during package
+%     load time, but only when they are really used -- but then they are created
+%     globally so it just has to be done once. This is done because they rely on
+%     a rather slow regular expression. If you set this key to |true| each
+%     \cs{AddAnimal} will also create the corresponding \cs{duckthink} variant
+%     immediately.
+% \end{options}
+%^^A<<<
+%
+% \SetVersion{1}%
+% \subsection{Version 1}\label{sec:v1}
+%
+% \subsubsection{Introduction}
+%
+% This version is included for legacy support (old documents should behave the
+% same without any change to them -- except the usage of |version=1| as an
+% option. For the bleeding edge version of \pkg{ducksay} skip this subsection
+% and read \autoref{sec:v2}.
+%
+% \subsubsection{Macros}\label{sec:macros1}^^A>>>
+% \marginpar
+%   {%
+%     \rlap
+%       {%
+%         \tiny
+%         \ducksay[yoda,MSG=\footnotesize,align=t]{Use those, you might}%
+%       }%
+%   }
+% The following is the description of macros which differ in behaviour from
+% those of version 2.
+%
+% \begin{function}{\ducksay}^^A>>>
+%   \begin{syntax}
+%     \cs{ducksay}\oarg{options}\marg{message}
+%   \end{syntax}
+%   options might include any of the options described in \autoref{sec:options}
+%   and \autoref{sec:options1} if not otherwise specified. Prints an \anml\
+%   saying \msg. \msg\ is not read in verbatim. Multi-line \msg s are possible
+%   using |\\|. |\\| should not be contained in a macro definition but at
+%   toplevel. Else use the option |ht|.
+% \end{function}^^A<<<
+%
+% \begin{function}{\duckthink}^^A>>>
+%   \begin{syntax}
+%     \cs{duckthink}\oarg{options}\marg{message}
+%   \end{syntax}
+%   options might include any of the options described in \autoref{sec:options}
+%   and \autoref{sec:options1} if not otherwise specified. Prints an \anml\
+%   thinking \msg. \msg\ is not read in verbatim. It is implemented using
+%   regular expressions replacing a |\| which is only preceded by |\s*| in the
+%   first three lines with |O| and |o|. It is therefore slower than
+%   \cs{ducksay}. Multi-line \msg s are possible using |\\|. |\\| should not be
+%   contained in a macro definition but at toplevel. Else use the option |ht|.
+% \end{function}^^A<<<
+%^^A<<<
+%
+% \subsubsection{Options}\label{sec:options1}^^A>>>
+% \marginpar
+%   {%
+%     \vspace*{-2em}\tiny
+%     \hfill
+%     \ducksay[hedgehog,MSG=\footnotesize,align=t]{Everyone likes\\options}%
+%   }
+% The following options are available to \cs{ducksay}, \cs{duckthink}, and
+% \cs{DucksayOptions} and if not otherwise specified also as package options:
+% \begin{options}
+%   \item[bubble=\meta{code}]
+%     use \meta{code} in a group right before the bubble (for font switches).
+%     Might be used as a package option but not all control sequences work out
+%     of the box there.
+%   \item[body=\meta{code}]
+%     use \meta{code} in a group right before the body (meaning the \anml).
+%     Might be used as a package option but not all control sequences work out
+%     of the box there. E.g.\@ to right-align the \anml\ to the bubble, use
+%     \verb|body=\hfill|.
+%   \item[align=\meta{valign}]
+%     use \meta{valign} as the vertical alignment specifier given to the
+%     \env{tabular} which is around the contents of \cs{ducksay} and
+%     \cs{duckthink}.
+%   \item[msg-align=\meta{halign}]
+%     use \meta{halign} for alignment of the rows of multi-line \msg s. It
+%     should match a \texttt{tabular} column specifier. Default is |l|. It only
+%     affects the contents of the speech bubble not the bubble.
+%   \item[rel-align=\meta{column}]
+%     use \meta{column} for alignment of the bubble and the body. It should
+%     match a \env{tabular} column specifier. Default is |l|.
+%   \item[wd=\meta{count}]
+%     in order to detect the width the \msg\ is expanded. This might not work
+%     out for some commands (e.g.\@ \cs{url} from \pkg{hyperref}). If you
+%     specify the width using |wd| the \msg\ is not expanded and
+%     therefore the command \emph{might} work out. \meta{count} should be the
+%     character count.
+%   \item[ht=\meta{count}]
+%     you might explicitly set the height (the row count) of the \msg. This only
+%     has an effect if you also specify |wd|.
+% \end{options}
+%^^A<<<
+%
+% \subsubsection{Defects}^^A>>>
+% \begingroup
+%   \reversemarginpar
+%   \marginpar
+%     {\tiny\hfill\ducksay[frog,MSG=\footnotesize,align=t]{Ohh, no!}}
+% \endgroup
+% \begin{itemize}
+%   \item no automatic line wrapping
+% \end{itemize}^^A<<<
+%
+% \SetVersion{2}%
+% \subsection{Version 2}\label{sec:v2}
+% \marginpar^^A>>>
+%   {
+%     \fontsize{3.5pt}{3.5pt}\selectfont
+%     \ducksay[unicorn,MSG=\footnotesize,align=t]{Here's all the good stuff!}
+%   }^^A<<<
+%
+% \subsubsection{Introduction}^^A>>>
+%
+% Version 2 is the current version of \pkg{ducksay}. It features automatic line
+% wrapping (if you specify a fixed width) and in general more options (with some
+% nasty argument parsing).
+%
+% If you're already used to version 1 you should note one important thing: You
+% should only specify the |version|, the |ligatures| and |add-think| during
+% package load time as arguments to \cs{usepackage}. The other keys might not
+% work or do unintended things and only don't throw errors or warnings because
+% of the legacy support of version 1.
+%
+%^^A<<<
+%
+% \subsubsection{Macros}\label{sec:macros2}^^A>>>
+% \marginpar^^A>>>
+%   {
+%     \tiny
+%     \ducksay[duck-family,MSG=\footnotesize,align=t,body-mirrored]
+%       {Look at those, kids!}
+%   }^^A<<<
+%
+% The following is the description of macros which differ in behaviour from
+% those of version 1.
+%
+% \begin{function}{\ducksay}^^A>>>
+%   \begin{syntax}
+%     \cs{ducksay}\oarg{options}\marg{message}
+%   \end{syntax}
+%   options might include any of the options described in \autoref{sec:options}
+%   and \autoref{sec:options2} if not otherwise specified. Prints an \anml\
+%   saying \msg.\\
+%   The \msg\ can be read in in four different ways. For an explanation of the
+%   \msg\ reading see the description of the |arg| key in
+%   \autoref{sec:options2}.\\
+%   The height and width of the message is determined by measuring its
+%   dimensions and the bubble will be set accordingly. The box surrounding the
+%   message will be placed both horizontally and vertically centred inside of
+%   the bubble. The output utilizes \LaTeX3's coffin mechanism described in
+%   \href{https://ctan.org/pkg/l3kernel}{\file{interface3.pdf}} and the
+%   documentation of \href{https://ctan.org/pkg/xcoffins}{\pkg{xcoffins}}.
+% \end{function}^^A<<<
+%
+% \begin{function}{\duckthink}^^A>>>
+%   \begin{syntax}
+%     \cs{duckthink}\oarg{options}\marg{message}
+%   \end{syntax}
+%   The only difference to \cs{ducksay} is that in \cs{duckthink} the \anml s
+%   think the \msg\ and don't say it.\\
+%   It is implemented using regular expressions replacing a |\| which is only
+%   preceded by |\s*| (any number of space tokens) in the first three lines with
+%   |O| and |o|. It's first use per \anml\ might therefore be slower than
+%   \cs{ducksay} depending on the |add-think| key (see its description in
+%   \autoref{sec:options}).
+% \end{function}^^A<<<
+%
+%^^A<<<
+%
+% \subsubsection{Options}\label{sec:options2}^^A>>>
+% \marginpar^^A>>>
+%   {
+%     \tiny
+%     \hfill\ducksay[small-rabbit,MSG=\footnotesize,align=t]
+%       {Fast, use options!}
+%   }^^A<<<
+% In version 2 the following options are available. Keep in mind that you
+% shouldn't use them during package load time but in the arguments of
+% \cs{ducksay}, \cs{duckthink} or \cs{DucksayOptions}.
+% \begin{options}
+%   \item[arg=\meta{choice}]
+%     specifies how the \msg\ argument of \cs{ducksay} and \cs{duckthink} should
+%     be read in. Available options are |box|, |tab| and |tab*|:
+%     \begin{options}
+%       \item[box]
+%         the argument is read in either as a \cs{hbox} or a \cs{vbox} (the
+%         latter if a fixed width is specified with either |wd| or |wd*|). Note
+%         that in this mode any arguments relying on category code changes like
+%         e.g.\@ \cs{verb} will work (provided that you don't use \cs{ducksay} or
+%         \cs{duckthink} inside of an argument of another macro of course).
+%       \item[tab]
+%         the argument is read in as the contents of a \env{tabular}. Note that
+%         in this mode any arguments relying on category code changes like
+%         e.g.\@ \cs{verb} will \emph{not} work. This mode comes closest to the
+%         behaviour of version 1 of \pkg{ducksay}.
+%       \item[tab*]
+%         the argument is read in as the contents of a \env{tabular}. However it
+%         is read in verbatim and uses \cs{scantokens} to rescan the argument.
+%         Note that in this mode any arguments relying on category code changes
+%         like e.g.\@ \cs{verb} will work. You can't use \cs{ducksay} or
+%         \cs{duckthink} as an argument to another macro in this mode however.
+%     \end{options}
+%   \item[b]
+%     shortcut for |out-v=b|.
+%   \item[body=\meta{font}]
+%     add \meta{font} to the font definitions in use to typeset the \anml's
+%     body.
+%   \item[body*=\meta{font}]
+%     clear any definitions previously made (including the package default) and
+%     set the font definitions in use to typeset the \anml's body to
+%     \meta{font}. The package default is \cs{verbatim at font}. In addition
+%     \cs{frenchspacing} will always be used prior to the defined \meta{font}.
+%   \item[body-align=\meta{choice}]
+%     sets the relative alignment of the \anml\ to the \msg. Possible choices
+%     are |l|, |c| and |r|. For |l| the \anml\ is flushed to the left of the
+%     \msg, for |c| it is centred and for |r| it is flushed right. More fine
+%     grained control over the alignment can be obtained with the keys
+%     |msg-to-body|, |body-to-msg|, |body-x| and |body-y|. Package default is
+%     |l|.
+%   \item[body-mirrored=\meta{bool}]
+%     if set true the \anml\ will be mirrored along its vertical centre axis.
+%     Package default is |false|. If you set it |true| you'll most likely need
+%     to manually adjust the alignment of the body with one or more of the
+%     keys |body-align|, |body-to-msg|, |msg-to-body|, |body-x| and |body-y|.
+%   \item[body-to-msg=\meta{pole}]
+%     defines the horizontal coffin \meta{pole} to be used for the placement of
+%     the \anml\ beneath the \msg. See \PolesInfo.
+%   \item[body-x=\meta{dimen}]
+%     defines a horizontal offset of \meta{dimen} length of the \anml\ from its
+%     placement beneath the \msg.
+%   \item[body-y=\meta{dimen}]
+%     defines a vertical offset of \meta{dimen} length of the \anml\ from its
+%     placement beneath the \msg.
+%   \item[bubble=\meta{font}]
+%     add \meta{font} to the font definitions in use to typeset the bubble. This
+%     does not affect the \msg\ only the bubble put around it.
+%   \item[bubble*=\meta{font}]
+%     clear any definitions previously made (including the package default) and
+%     set the font definitions in use to typeset the bubble to \meta{font}. This
+%     does not affect the \msg\ only the bubble put around it. The package
+%     default is \cs{verbatim at font}.
+%   \item[bubble-bot-kern=\meta{dimen}]
+%     specifies a vertical offset of the placement of the lower border of the
+%     bubble from the bottom of the left and right borders.
+%   \item[bubble-delim-left-1=\meta{token list}]
+%     the left delimiter used if only one line of delimiters is needed. Package
+%     default is |(|.
+%   \item[bubble-delim-left-2=\meta{token list}]
+%     the upper most left delimiter used if more than one line of delimiters is
+%     needed. Package default is |/|.
+%   \item[bubble-delim-left-3=\meta{token list}]
+%     the left delimiters used to fill the gap if more than two lines of
+%     delimiters are needed. Package default is \verb+|+.
+%   \item[bubble-delim-left-4=\meta{token list}]
+%     the lower most left delimiters used if more than one line of delimiters is
+%     needed. Package default is |\|.
+%   \item[bubble-delim-right-1=\meta{token list}]
+%     the right delimiter used if only one line of delimiters is needed. Package
+%     default is |)|.
+%   \item[bubble-delim-right-2=\meta{token list}]
+%     the upper most right delimiter used if more than one line of delimiters is
+%     needed. Package default is |\|.
+%   \item[bubble-delim-right-3=\meta{token list}]
+%     the right delimiters used to fill the gap if more than two lines of
+%     delimiters are needed. Package default is \verb+|+.
+%   \item[bubble-delim-right-4=\meta{token list}]
+%     the lower most right delimiters used if more than one line of delimiters
+%     is needed. Package default is |/|.
+%   \item[bubble-delim-top=\meta{token list}]
+%     the delimiter used to create the top and bottom border of the bubble. The
+%     package default is |{-}| (the braces are important to suppress ligatures
+%     here).
+%   \item[bubble-side-kern=\meta{dimen}]
+%     specifies the kerning used to move the sideways delimiters added to fill
+%     the gap for more than two lines of bubble height. (the left one is moved
+%     to the left, the right one to the right)
+%   \item[bubble-top-kern=\meta{dimen}]
+%     specifies a vertical offset of the placement of the upper border of the
+%     bubble from the top of the left and right borders.
+%   \item[c]
+%     shortcut for |out-v=vc|.
+%   \item[col=\meta{column}]
+%     specifies the used column specifier used for the \msg\ enclosing
+%     \env{tabular} for |arg=tab| and |arg=tab*|. Has precedence over
+%     |msg-align|. You can also use more than one column this way:
+%     |\ducksay[arg=tab,col=cc]{ You & can \\ do & it }| would be valid syntax.
+%   \item[hpad=\meta{count}]
+%     Add \meta{count} times more |bubble-delim-top| instances than necassary to
+%     the upper and lower border of the bubble. Package default is 2.
+%   \item[ht=\meta{count}]
+%     specifies a minimum height (in lines) of the \msg. The lines' count is
+%     that of the needed lines of the horizontal bubble delimiters. If the
+%     count of the actually needed lines is smaller than the specified
+%     \meta{count}, \meta{count} lines will be used. Else the required lines
+%     will be used.
+%   \item[ignore-body=\meta{bool}]
+%     If set |true| the \anml's body will be added to the output but it will not
+%     contribute to the bounding box (so will not take up any space).
+%   \item[msg=\meta{font}]
+%     add \meta{font} to the font definitions in use to typeset the \msg.
+%   \item[msg*=\meta{font}]
+%     clear any definitions previously made (including the package default) and
+%     set the font definitions in use to typeset the \msg\ to \meta{font}. The
+%     package default is \cs{verbatim at font}.
+%   \item[MSG=\meta{font}]
+%     same as \texttt{msg=\meta{font}, bubble=\meta{font}}.
+%   \item[MSG*=\meta{font}]
+%     same as \texttt{msg*=\meta{font}, bubble*=\meta{font}}.
+%   \item[msg-align=\meta{choice}]
+%     specifies the alignment of the \msg. Possible values are |l| for flushed
+%     left, |c| for centred, |r| for flushed right and |j| for justified. If
+%     |arg=tab| or |arg=tab*| the |j| choice is only available for fixed width
+%     contents. Package default is |l|.
+%   \item[msg-align-c=\meta{token list}]
+%     set the \meta{token list} which is responsible to typeset the message
+%     centred if the option |msg-align=c| is used. It is used independent of the
+%     |arg| key. For |arg=tab| and |arg=tab*| the macro \cs{arraybackslash}
+%     provided by \pkg{array} is used afterwards. The package default is
+%     |\centering|. It might be useful if you want to use \pkg{ragged2e}'s
+%     \cs{Centering} for example.
+%   \item[msg-align-j=\meta{token list}]
+%     set the \meta{token list} which is responsible to typeset the message
+%     justified if the option |msg-align=j| is used. It is used independent of
+%     the |arg| key. For |arg=tab| and |arg=tab*| the macro \cs{arraybackslash}
+%     provided by \pkg{array} is used afterwards. The package default is
+%     empty as justification is the default behaviour of contents of a |p|
+%     column and of a \cs{vbox}. It might be useful if you want to use
+%     \pkg{ragged2e}'s \cs{justifying} for example.
+%   \item[msg-align-l=\meta{token list}]
+%     set the \meta{token list} which is responsible to typeset the message
+%     flushed left if the option |msg-align=l| is used. It is used independent
+%     of the |arg| key. For |arg=tab| and |arg=tab*| the macro
+%     \cs{arraybackslash} provided by \pkg{array} is used afterwards. The
+%     package default is |\raggedright|. It might be useful if you want to use
+%     \pkg{ragged2e}'s \cs{RaggedRight} for example.
+%   \item[msg-align-r=\meta{token list}]
+%     set the \meta{token list} which is responsible to typeset the message
+%     flushed right if the option |msg-align=r| is used. It is used independent
+%     of the |arg| key. For |arg=tab| and |arg=tab*| the macro
+%     \cs{arraybackslash} provided by \pkg{array} is used afterwards. The
+%     package default is |\raggedleft|. It might be useful if you want to use
+%     \pkg{ragged2e}'s \cs{RaggedLeft} for example.
+%   \item[msg-to-bubble=\meta{pole}]
+%     defines the horizontal coffin \meta{pole} to be used as the reference
+%     point for the placement of the \anml\ beneath the \msg. See \PolesInfo.
+%   \item[none=\meta{bool}]
+%     One could say this is a special animal. If |true| no animal body will be
+%     used (resulting in just the speech bubble). Package default is of course
+%     |false|.
+%   \item[out-h=\meta{pole}]
+%     defines the horizontal coffin \meta{pole} to be used as the anchor point
+%     for the print out of the complete result of \cs{ducksay} and
+%     \cs{duckthink}. See \PolesInfo.
+%   \item[out-v=\meta{pole}]
+%     defines the vertical coffin \meta{pole} to be used as the anchor point for
+%     the print out of the complete result of \cs{ducksay} and \cs{duckthink}.
+%     See \PolesInfo.
+%   \item[out-x=\meta{dimen}]
+%     specifies an additional horizontal offset of the print out of the complete
+%     result of \cs{ducksay} and \cs{duckthink}.
+%   \item[out-y=\meta{dimen}]
+%     specifies an additional vertical offset of the print out of the complete
+%     result of \cs{ducksay} and \cs{duckthink}
+%   \item[t]
+%     shortcut for |out-v=t|.
+%   \item[vpad=\meta{count}]
+%     add \meta{count} to the lines used for the bubble, resulting in
+%     \meta{count} more lines than necessary to enclose the \msg\ inside of the
+%     bubble.
+%   \item[wd=\meta{count}]
+%     specifies the width of the \msg\ to be fixed to \meta{count} times the
+%     width of an upper case M in the \msg's font declaration. A value smaller
+%     than 0 is considered deactivated, else the width is considered as fixed.
+%     For a fixed width the argument of \cs{ducksay} and \cs{duckthink} is read
+%     in as a \cs{vbox} for |arg=box| and the column definition uses a |p|-type
+%     column for |arg=tab| and |arg=tab*|. If both |wd| is not smaller than 0
+%     and |wd*| is not smaller than 0pt, |wd*| will take precedence.
+%   \item[wd*=\meta{dimen}]
+%     specifies the width of the \msg\ to be fixed to \meta{dimen}. A value
+%     smaller than 0pt is considered deactivated, else the width is considered
+%     as fixed. For a fixed width the argument of \cs{ducksay} and
+%     \cs{duckthink} is read in as a \cs{vbox} for |arg=box| and the column
+%     definition uses a |p|-type column for |arg=tab| and |arg=tab*|. If both
+%     |wd| is not smaller than 0 and |wd*| is not smaller than 0pt, |wd*| will
+%     take precedence.
+% \end{options}
+%
+%^^A<<<
+%
+% \SetVersion{}%
+% \subsection{Dependencies}^^A>>>
+% \marginpar
+%   {%
+%     \tiny
+%     \rlap
+%       {%
+%         \ducksay
+%           [
+%             kangaroo,MSG=\footnotesize,align=t
+%             ,body-mirrored,body-to-msg=r,msg-to-body=hc
+%           ]
+%           {We rely on you}%
+%       }%
+%   }
+% The package depends on the two packages \pkg{xparse} and \pkg{l3keys2e}
+% and all of their dependencies. Version 2 additionally depends on \pkg{array}.
+%^^A<<<
+%
+% \subsection{Available Animals}\label{sec:animals}^^A>>>
+% \marginpar
+%   {%
+%     \tiny
+%     \hfill
+%     \makebox[8em][r]
+%       {%
+%         \ducksay[whale,MSG=\footnotesize,align=t]
+%           {I'm the\\new one.}%
+%       }%
+%   }
+% The following animals are provided by this package. I did not create them (but
+% altered some), they belong to their original creators.
+% \bgroup
+% \fontsize{6pt}{6pt}\selectfont
+% \parindent=0pt
+% \DucksayOptions{MSG=\footnotesize,vpad=0,arg=tab}
+% \begin{multicols}{2}
+% \availableAnimal{^^A>>>
+%   ,duck^^A
+%   ,small-duck^^A
+%   ,duck-family^^A
+%   ,small-rabbit^^A
+%   ,squirrel^^A
+%   ,cow^^A
+%   ,tux^^A
+%   ,head-in^^A
+%   ,pig^^A
+%   ,frog^^A
+%   ,snowman^^A
+%   ,bunny^^A
+%   ,dragon^^A
+%   ,sodomized^^A
+%   ,hedgehog^^A
+%   ,kangaroo^^A
+%   ,dog^^A
+%   ,rabbit^^A
+%   ,snail^^A
+%   ,whale^^A
+%   ,unicorn^^A
+% }\end{multicols}\begin{multicols}{2}
+% \availableAnimal{^^A
+%   ,r2d2^^A
+%   ,vader^^A
+%   ,yoda-head^^A
+%   ,small-yoda^^A
+%   ,yoda^^A
+% }^^A<<<
+% \end{multicols}
+% \egroup
+%^^A<<<
+%
+% \subsection{Miscellaneous}^^A>>>
+% \marginpar
+%   {%
+%     \rlap
+%       {%
+%         \tiny
+%         \ducksay[squirrel,MSG=\footnotesize,align=t]{I'd choose WTFPL}%
+%       }%
+%   }
+% This package is distributed under the terms of the GPLv3 or later, or the LPPL
+% 1.3c or later, choose which ever license fits your needs the best.
+%
+% The package is hosted on \url{https://github.com/Skillmon/ltx_ducksay}, you
+% might report bugs there.
+%^^A<<<
+%
+% \end{documentation}^^A<<<
+%
+% \begin{implementation}^^A>>>
+%
+% \clearpage
+%
+% \SetVersion{}\def\DocImp{Implementation}%
+% \section{Implementation}^^A>>>
+% \marginpar
+%   {%
+%     \smash
+%       {%
+%         \tiny
+%         \ducksay
+%           [vader,MSG=\footnotesize,align=t,arg=tab,msg-align=c]
+%           {%
+%             Only rebel scum reads\\documentation!\\
+%             Join the dark side,\\read the implementation.%
+%           }%
+%       }%
+%   }
+%
+%^^A main file >>>
+%    \begin{macrocode}
+%<*pkg>
+%    \end{macrocode}
+%
+% \subsection{Shared between versions}^^A>>>
+%
+% \subsubsection{Variables}^^A>>>
+% \paragraph{Integers}
+%    \begin{macrocode}
+\int_new:N \l_ducksay_msg_width_int
+\int_new:N \l_ducksay_msg_height_int
+%    \end{macrocode}
+% \paragraph{Sequences}
+%    \begin{macrocode}
+\seq_new:N \l_ducksay_msg_lines_seq
+%    \end{macrocode}
+% \paragraph{Token lists}
+%    \begin{macrocode}
+\tl_new:N \l_ducksay_say_or_think_tl
+\tl_new:N \l_ducksay_align_tl
+\tl_new:N \l_ducksay_msg_align_tl
+\tl_new:N \l_ducksay_animal_tl
+\tl_new:N \l_ducksay_body_tl
+\tl_new:N \l_ducksay_bubble_tl
+\tl_new:N \l_ducksay_tmpa_tl
+%    \end{macrocode}
+% \paragraph{Boolean}
+%    \begin{macrocode}
+\bool_new:N \l_ducksay_also_add_think_bool
+\bool_new:N \l_ducksay_version_one_bool
+\bool_new:N \l_ducksay_version_two_bool
+%    \end{macrocode}
+% \paragraph{Boxes}
+%    \begin{macrocode}
+\box_new:N \l_ducksay_tmpa_box
+%    \end{macrocode}
+%
+%^^A<<<
+%
+% \subsubsection{Regular Expressions}^^A>>>
+% Regular expressions for \cs{duckthink}
+%    \begin{macrocode}
+\regex_const:Nn \c_ducksay_first_regex  { \A(.\s*)\\ }
+\regex_const:Nn \c_ducksay_second_regex { \A(.[^\c{null}]*\c{null}\s*)\\ }
+\regex_const:Nn \c_ducksay_third_regex  {
+  \A(.[^\c{null}]*\c{null}[^\c{null}]*\c{null}\s*)\\ }
+\regex_const:Nn \c_ducksay_textcolor_regex
+  { \cO(?:\\textcolor\{(.*?)\}\{(.*?)\}) }
+\regex_const:Nn \c_ducksay_color_delim_regex
+  { \cO(?:\\bgroup\\color\{(.*?)\}(.*)\\egroup) }
+\regex_const:Nn \c_ducksay_color_regex
+  { \cO(?:\\color\{(.*?)\}) }
+%    \end{macrocode}
+%^^A<<<
+%
+% \subsubsection{Messages}^^A>>>
+%    \begin{macrocode}
+\msg_new:nnn { ducksay } { load-time-only }
+  { The~`#1`~key~is~to~be~used~only~during~package~load~time. }
+%    \end{macrocode}
+%^^A<<<
+%
+% \subsubsection{Key-value setup}^^A>>>
+%    \begin{macrocode}
+\keys_define:nn { ducksay }
+  {
+    ,bubble .tl_set:N      = \l_ducksay_bubble_tl
+    ,body   .tl_set:N      = \l_ducksay_body_tl
+    ,align  .tl_set:N      = \l_ducksay_align_tl
+    ,align  .value_required:n = true
+    ,wd     .int_set:N     = \l_ducksay_msg_width_int
+    ,wd     .initial:n     = -\c_max_int
+    ,wd     .value_required:n = true
+    ,ht     .int_set:N     = \l_ducksay_msg_height_int
+    ,ht     .initial:n     = -\c_max_int
+    ,ht     .value_required:n = true
+    ,animal .code:n        =
+      { \keys_define:nn { ducksay } { default_animal .meta:n = { #1 } } }
+    ,animal .initial:n     = duck
+    ,msg-align .tl_set:N   = \l_ducksay_msg_align_tl
+    ,msg-align .initial:n  = l
+    ,msg-align .value_required:n = true
+    ,rel-align .tl_set:N   = \l_ducksay_rel_align_tl
+    ,rel-align .initial:n  = l
+    ,rel-align .value_required:n = true
+    ,ligatures .tl_set:N   = \l_ducksay_ligatures_tl
+    ,ligatures .initial:n  = { `<>,'- }
+    ,add-think .bool_set:N = \l_ducksay_also_add_think_bool
+    ,version   .choice:
+    ,version / 1 .code:n   = 
+      {
+        \bool_set_false:N \l_ducksay_version_two_bool
+        \bool_set_true:N  \l_ducksay_version_one_bool
+      }
+    ,version / 2 .code:n   =
+      {
+        \bool_set_false:N \l_ducksay_version_one_bool
+        \bool_set_true:N  \l_ducksay_version_two_bool
+      }
+    ,version   .initial:n  = 2
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\ProcessKeysOptions { ducksay }
+%    \end{macrocode}
+%
+% Undefine the load-time-only keys
+%    \begin{macrocode}
+\keys_define:nn { ducksay }
+  {
+    version .code:n = \msg_error:nnn { ducksay } { load-time-only } { version }
+  }
+%    \end{macrocode}
+%
+%^^A<<<
+%
+% \subsubsection{Functions}^^A>>>
+%
+% \paragraph{Generating Variants of External Functions}^^A>>>
+%
+%    \begin{macrocode}
+\cs_generate_variant:Nn \tl_if_eq:nnT { VnT }
+%    \end{macrocode}
+%^^A<<<
+%
+% \paragraph{Internal}^^A>>>
+%
+% \begin{macro}{\ducksay_create_think_animal:n}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected:Npn \ducksay_create_think_animal:n #1
+  {
+    \group_begin:
+      \tl_set_eq:Nc \l_ducksay_tmpa_tl { g_ducksay_animal_say_#1_tl }
+      \regex_replace_once:NnN \c_ducksay_first_regex  { \1O } \l_ducksay_tmpa_tl
+      \regex_replace_once:NnN \c_ducksay_second_regex { \1o } \l_ducksay_tmpa_tl
+      \regex_replace_once:NnN \c_ducksay_third_regex  { \1o } \l_ducksay_tmpa_tl
+      \tl_gset_eq:cN { g_ducksay_animal_think_#1_tl } \l_ducksay_tmpa_tl
+    \group_end:
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_replace_verb_newline:Nn}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected:Npx \ducksay_replace_verb_newline:Nn #1 #2
+  {
+    \tl_replace_all:Nnn #1 { \char_generate:nn { 13 } { 12 } } { #2 }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_replace_verb_newline_newline:Nn}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected:Npx \ducksay_replace_verb_newline_newline:Nn #1 #2
+  {
+    \tl_replace_all:Nnn #1
+      { \char_generate:nn { 13 } { 12 } \char_generate:nn { 13 } { 12 } } { #2 }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_process_verb_newline:nnn}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected:Npn \ducksay_process_verb_newline:nnn #1 #2 #3
+  {
+    \tl_set:Nn \ProcessedArgument { #3 }
+    \ducksay_replace_verb_newline_newline:Nn \ProcessedArgument { #2 }
+    \ducksay_replace_verb_newline:Nn \ProcessedArgument { #1 }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_add_animal_inner:nn}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected:Npn \ducksay_add_animal_inner:nn #1 #2
+  {
+    \tl_set:Nn \l_ducksay_tmpa_tl { \ #2 }
+    \tl_map_inline:Nn \l_ducksay_ligatures_tl
+      { \tl_replace_all:Nnn \l_ducksay_tmpa_tl { ##1 } { { ##1 } } }
+    \ducksay_replace_verb_newline:Nn \l_ducksay_tmpa_tl { \tabularnewline\null }
+    \tl_gset_eq:cN { g_ducksay_animal_say_#1_tl } \l_ducksay_tmpa_tl
+    \keys_define:nn { ducksay }
+      {
+        #1 .code:n =
+          {
+            \tl_if_exist:cF
+              { g_ducksay_animal_ \l_ducksay_say_or_think_tl _#1_tl }
+              { \ducksay_create_think_animal:n { #1 } }
+            \tl_set_eq:Nc \l_ducksay_animal_tl
+              { g_ducksay_animal_ \l_ducksay_say_or_think_tl _#1_tl }
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+%^^A<<<
+%
+% \paragraph{Document level}^^A>>>
+%
+% \begin{macro}{\DefaultAnimal}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \DefaultAnimal { m }
+  {
+    \keys_define:nn { ducksay } { default_animal .meta:n = { #1 } }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\DucksayOptions}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \DucksayOptions { m }
+  {
+    \keys_set:nn { ducksay } { #1 }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\AddAnimal}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \AddAnimal { s m +v }
+  {
+    \ducksay_add_animal_inner:nn { #2 } { #3 }
+    \bool_if:NT \l_ducksay_also_add_think_bool
+      { \ducksay_create_think_animal:n { #2 } }
+    \IfBooleanT{#1}
+      { \keys_define:nn { ducksay } { default_animal .meta:n = { #2 } } }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\AddColoredAnimal}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \AddColoredAnimal { s m +v }
+  {
+    \ducksay_add_animal_inner:nn { #2 } { #3 }
+    \regex_replace_all:Nnc \c_ducksay_color_delim_regex
+      { \c{bgroup}\c{color}\cB\{\1\cE\}\2\c{egroup} }
+      { g_ducksay_animal_say_#2_tl }
+    \regex_replace_all:Nnc \c_ducksay_color_regex
+      { \c{color}\cB\{\1\cE\} }
+      { g_ducksay_animal_say_#2_tl }
+    \regex_replace_all:Nnc \c_ducksay_textcolor_regex
+      { \c{textcolor}\cB\{\1\cE\}\cB\{\2\cE\} }
+      { g_ducksay_animal_say_#2_tl }
+    \bool_if:NT \l_ducksay_also_add_think_bool
+      { \ducksay_create_think_animal:n { #2 } }
+    \IfBooleanT{#1}
+      { \keys_define:nn { ducksay } { default_animal .meta:n = { #2 } } }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+%^^A<<<
+%
+%^^A<<<
+%
+% \subsubsection{Load the Correct Version and the Animals}^^A>>>
+%    \begin{macrocode}
+\bool_if:NT \l_ducksay_version_one_bool
+  { \file_input:n { ducksay.code.v1.tex } }
+\bool_if:NT \l_ducksay_version_two_bool
+  { \file_input:n { ducksay.code.v2.tex } }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\ExplSyntaxOff
+\input{ducksay.animals.tex}
+%    \end{macrocode}
+%^^A<<<
+%
+%^^A<<<
+%
+%    \begin{macrocode}
+%</pkg>
+%    \end{macrocode}
+%^^A<<<
+%
+% \SetVersion{1}%
+% \subsection{Version 1}^^A>>>
+%    \begin{macrocode}
+%<*code.v1>
+%    \end{macrocode}
+%
+% \subsubsection{Functions}^^A>>>
+%
+% \paragraph{Internal}^^A>>>
+%
+% \begin{macro}{\ducksay_longest_line:n}^^A>>>
+%   Calculate the length of the longest line
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_longest_line:n #1
+  {
+    \int_incr:N \l_ducksay_msg_height_int
+    \exp_args:NNx \tl_set:Nn \l_ducksay_tmpa_tl { #1 }
+    \regex_replace_all:nnN { \s } { \c { space } } \l_ducksay_tmpa_tl
+    \int_set:Nn \l_ducksay_msg_width_int
+      {
+        \int_max:nn
+          { \l_ducksay_msg_width_int } { \tl_count:N \l_ducksay_tmpa_tl }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_open_bubble:}^^A>>>
+%   Draw the opening bracket of the bubble
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_open_bubble:
+  {
+    \begin{tabular}{@{}l@{}}
+      \null\\
+      \int_compare:nNnTF { \l_ducksay_msg_height_int } = { 1 } { ( }
+        {
+          /
+          \int_step_inline:nnn
+            { 3 } { \l_ducksay_msg_height_int } { \\\kern-0.2em| }
+          \\\detokenize{\ }
+        }
+      \\[-1ex]\null
+    \end{tabular}
+    \begin{tabular}{@{}l@{}}
+      _\\
+      \int_step_inline:nnn { 2 } { \l_ducksay_msg_height_int } { \\ } \\[-1ex]
+      \mbox { - }
+    \end{tabular}
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_close_bubble:}^^A>>>
+%   Draw the closing bracket of the bubble
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_close_bubble:
+  {
+    \begin{tabular}{@{}l@{}}
+      _\\
+      \int_step_inline:nnn { 2 } { \l_ducksay_msg_height_int } { \\ } \\[-1ex]
+      { - }
+    \end{tabular}
+    \begin{tabular}{@{}r@{}}
+      \null\\
+      \int_compare:nNnTF { \l_ducksay_msg_height_int } = { 1 }
+        { ) }
+        {
+          \detokenize {\ }
+          \int_step_inline:nnn
+            { 3 } { \l_ducksay_msg_height_int } { \\|\kern-0.2em }
+          \\/
+        }
+      \\[-1ex]\null
+    \end{tabular}
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_print_msg:nn}^^A>>>
+%   Print out the message
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_print_msg:nn #1 #2
+  {
+    \begin{tabular}{@{} #2 @{}}
+      \int_step_inline:nn { \l_ducksay_msg_width_int } { _ } \\
+      #1\\[-1ex]
+      \int_step_inline:nn { \l_ducksay_msg_width_int } { { - } }
+    \end{tabular}
+  }
+\cs_generate_variant:Nn \ducksay_print_msg:nn { nV }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_print:nn}^^A>>>
+%   Print out the whole thing
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_print:nn #1 #2
+  {
+    \int_compare:nNnTF { \l_ducksay_msg_width_int } < { 0 }
+      {
+        \int_zero:N \l_ducksay_msg_height_int
+        \seq_set_split:Nnn \l_ducksay_msg_lines_seq { \\ } { #1 }
+        \seq_map_function:NN \l_ducksay_msg_lines_seq \ducksay_longest_line:n
+      }
+      {
+        \int_compare:nNnT { \l_ducksay_msg_height_int } < { 0 }
+          {
+            \regex_count:nnN { \c { \\ } } { #1 } \l_ducksay_msg_height_int
+            \int_incr:N \l_ducksay_msg_height_int
+          }
+      }
+    \group_begin:
+      \frenchspacing
+      \verbatim at font
+      \@noligs
+      \begin{tabular}[\l_ducksay_align_tl]{@{}#2@{}}
+        \l_ducksay_bubble_tl
+        \begin{tabular}{@{}l@{}}
+          \ducksay_open_bubble:
+          \ducksay_print_msg:nV { #1 } \l_ducksay_msg_align_tl
+          \ducksay_close_bubble:
+        \end{tabular}\\
+        \l_ducksay_body_tl
+        \begin{tabular}{@{}l@{}}
+          \l_ducksay_animal_tl
+        \end{tabular}
+      \end{tabular}
+    \group_end:
+  }
+\cs_generate_variant:Nn \ducksay_print:nn { nV }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_prepare_say_and_think:n}^^A>>>
+%   Reset some variables
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_prepare_say_and_think:n #1
+  {
+    \int_set:Nn \l_ducksay_msg_width_int  { -\c_max_int }
+    \int_set:Nn \l_ducksay_msg_height_int { -\c_max_int }
+    \keys_set:nn { ducksay } { #1 }
+    \tl_if_empty:NT \l_ducksay_animal_tl
+      { \keys_set:nn { ducksay } { default_animal } }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%^^A<<<
+%
+% \paragraph{Document level}^^A>>>
+%
+% \begin{macro}{\ducksay}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \ducksay { O{} m }
+  {
+    \group_begin:
+      \tl_set:Nn \l_ducksay_say_or_think_tl { say }
+      \ducksay_prepare_say_and_think:n { #1 }
+      \ducksay_print:nV { #2 } \l_ducksay_rel_align_tl
+    \group_end:
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\duckthink}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \duckthink { O{} m }
+  {
+    \group_begin:
+      \tl_set:Nn \l_ducksay_say_or_think_tl { think }
+      \ducksay_prepare_say_and_think:n { #1 }
+      \ducksay_print:nV { #2 } \l_ducksay_rel_align_tl
+    \group_end:
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%^^A<<<
+%
+%^^A<<<
+%
+%    \begin{macrocode}
+%</code.v1>
+%    \end{macrocode}^^A<<<
+%
+% \SetVersion{2}%
+% \subsection{Version 2}^^A>>>
+%    \begin{macrocode}
+%<*code.v2>
+%    \end{macrocode}
+%
+% Load the additional dependencies of version 2.
+%    \begin{macrocode}
+\RequirePackage{array}
+%    \end{macrocode}
+%
+% \subsubsection{Messages}^^A>>>
+%    \begin{macrocode}
+\msg_new:nnn { ducksay } { justify~unavailable }
+  {
+    Justified~content~is~not~available~for~tabular~argument~mode~without~fixed~
+    width.~`l`~column~is~used~instead.
+  }
+\msg_new:nnn { ducksay } { unknown~message~alignment }
+  {
+    The~specified~message~alignment~`\exp_not:n { #1 }`~is~unknown.~
+    `l`~is~used~as~fallback.
+  }
+%    \end{macrocode}
+%^^A<<<
+%
+% \subsubsection{Variables}^^A>>>
+%
+% \paragraph{Token Lists}
+%    \begin{macrocode}
+\tl_new:N \l_ducksay_msg_align_vbox_tl
+%    \end{macrocode}
+%
+% \paragraph{Boxes}
+%    \begin{macrocode}
+\box_new:N \l_ducksay_msg_box
+%    \end{macrocode}
+%
+% \paragraph{Bools}
+%    \begin{macrocode}
+\bool_new:N \l_ducksay_eat_arg_box_bool
+\bool_new:N \l_ducksay_eat_arg_tab_verb_bool
+\bool_new:N \l_ducksay_mirrored_body_bool
+%    \end{macrocode}
+%
+% \paragraph{Coffins}
+%    \begin{macrocode}
+\coffin_new:N \l_ducksay_body_coffin
+\coffin_new:N \l_ducksay_bubble_close_coffin
+\coffin_new:N \l_ducksay_bubble_open_coffin
+\coffin_new:N \l_ducksay_bubble_top_coffin
+\coffin_new:N \l_ducksay_msg_coffin
+%    \end{macrocode}
+%
+% \paragraph{Dimensions}
+%    \begin{macrocode}
+\dim_new:N \l_ducksay_hpad_dim
+\dim_new:N \l_ducksay_bubble_bottom_kern_dim
+\dim_new:N \l_ducksay_bubble_top_kern_dim
+\dim_new:N \l_ducksay_msg_width_dim
+%    \end{macrocode}
+%
+%^^A<<<
+%
+% \subsubsection{Options}^^A>>>
+%
+%    \begin{macrocode}
+\keys_define:nn { ducksay }
+  {
+    ,arg .choice:
+    ,arg / box  .code:n = \bool_set_true:N  \l_ducksay_eat_arg_box_bool
+    ,arg / tab  .code:n =
+      {
+        \bool_set_false:N \l_ducksay_eat_arg_box_bool
+        \bool_set_false:N \l_ducksay_eat_arg_tab_verb_bool
+      }
+    ,arg / tab* .code:n =
+      {
+        \bool_set_false:N \l_ducksay_eat_arg_box_bool
+        \bool_set_true:N  \l_ducksay_eat_arg_tab_verb_bool
+      }
+    ,arg .initial:n = tab
+    ,wd* .dim_set:N = \l_ducksay_msg_width_dim
+    ,wd* .initial:n = -\c_max_dim
+    ,wd* .value_required:n = true
+    ,none          .bool_set:N = \l_ducksay_no_body_bool
+    ,body-mirrored .bool_set:N = \l_ducksay_mirrored_body_bool
+    ,ignore-body   .bool_set:N = \l_ducksay_ignored_body_bool
+    ,body-x      .dim_set:N = \l_ducksay_body_x_offset_dim
+    ,body-x      .value_required:n = true
+    ,body-y      .dim_set:N = \l_ducksay_body_y_offset_dim
+    ,body-y      .value_required:n = true
+    ,body-to-msg .tl_set:N  = \l_ducksay_body_to_msg_align_body_tl
+    ,msg-to-body .tl_set:N  = \l_ducksay_body_to_msg_align_msg_tl
+    ,body-align .choice:
+    ,body-align / l .meta:n = { body-to-msg = l , msg-to-body = l }
+    ,body-align / c .meta:n = { body-to-msg = hc , msg-to-body = hc }
+    ,body-align / r .meta:n = { body-to-msg = r , msg-to-body = r }
+    ,body-align .initial:n = l
+    ,msg-align   .choice:
+    ,msg-align  / l .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { l } }
+    ,msg-align  / c .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { c } }
+    ,msg-align  / r .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { r } }
+    ,msg-align  / j .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { j } }
+    ,msg-align-l .tl_set:N  = \l_ducksay_msg_align_l_tl
+    ,msg-align-l .initial:n = \raggedright
+    ,msg-align-c .tl_set:N  = \l_ducksay_msg_align_c_tl
+    ,msg-align-c .initial:n = \centering
+    ,msg-align-r .tl_set:N  = \l_ducksay_msg_align_r_tl
+    ,msg-align-r .initial:n = \raggedleft
+    ,msg-align-j .tl_set:N  = \l_ducksay_msg_align_j_tl
+    ,msg-align-j .initial:n = {}
+    ,out-h   .tl_set:N  = \l_ducksay_output_h_pole_tl
+    ,out-h   .initial:n = l
+    ,out-v   .tl_set:N  = \l_ducksay_output_v_pole_tl
+    ,out-v   .initial:n = vc
+    ,out-x   .dim_set:N = \l_ducksay_output_x_offset_dim
+    ,out-x   .value_required:n = true
+    ,out-y   .dim_set:N = \l_ducksay_output_y_offset_dim
+    ,out-y   .value_required:n = true
+    ,t       .meta:n    = { out-v = t }
+    ,c       .meta:n    = { out-v = vc }
+    ,b       .meta:n    = { out-v = b }
+    ,body*   .tl_set:N  = \l_ducksay_body_fount_tl
+    ,msg*    .tl_set:N  = \l_ducksay_msg_fount_tl
+    ,bubble* .tl_set:N  = \l_ducksay_bubble_fount_tl
+    ,body*   .initial:n = \verbatim at font
+    ,msg*    .initial:n = \verbatim at font
+    ,bubble* .initial:n = \verbatim at font
+    ,body    .code:n    = \tl_put_right:Nn \l_ducksay_body_fount_tl   { #1 }
+    ,msg     .code:n    = \tl_put_right:Nn \l_ducksay_msg_fount_tl    { #1 }
+    ,bubble  .code:n    = \tl_put_right:Nn \l_ducksay_bubble_fount_tl { #1 }
+    ,MSG     .meta:n    = { msg  = #1 , bubble  = #1 }
+    ,MSG*    .meta:n    = { msg* = #1 , bubble* = #1 }
+    ,hpad    .int_set:N = \l_ducksay_hpad_int
+    ,hpad    .initial:n = 2
+    ,hpad    .value_required:n = true
+    ,vpad    .int_set:N = \l_ducksay_vpad_int
+    ,vpad    .value_required:n = true
+    ,col     .tl_set:N  = \l_ducksay_msg_tabular_column_tl
+    ,bubble-top-kern  .tl_set:N  = \l_ducksay_bubble_top_kern_tl
+    ,bubble-top-kern  .initial:n = { -.5ex }
+    ,bubble-top-kern  .value_required:n = true
+    ,bubble-bot-kern  .tl_set:N  = \l_ducksay_bubble_bottom_kern_tl
+    ,bubble-bot-kern  .initial:n = { .2ex }
+    ,bubble-bot-kern  .value_required:n = true
+    ,bubble-side-kern .tl_set:N  = \l_ducksay_bubble_side_kern_tl
+    ,bubble-side-kern .initial:n = { 0.2em }
+    ,bubble-side-kern .value_required:n = true
+    ,bubble-delim-top     .tl_set:N  = \l_ducksay_bubble_delim_top_tl
+    ,bubble-delim-left-1  .tl_set:N  = \l_ducksay_bubble_delim_left_a_tl
+    ,bubble-delim-left-2  .tl_set:N  = \l_ducksay_bubble_delim_left_b_tl
+    ,bubble-delim-left-3  .tl_set:N  = \l_ducksay_bubble_delim_left_c_tl
+    ,bubble-delim-left-4  .tl_set:N  = \l_ducksay_bubble_delim_left_d_tl
+    ,bubble-delim-right-1 .tl_set:N  = \l_ducksay_bubble_delim_right_a_tl
+    ,bubble-delim-right-2 .tl_set:N  = \l_ducksay_bubble_delim_right_b_tl
+    ,bubble-delim-right-3 .tl_set:N  = \l_ducksay_bubble_delim_right_c_tl
+    ,bubble-delim-right-4 .tl_set:N  = \l_ducksay_bubble_delim_right_d_tl
+    ,bubble-delim-top     .initial:n = { { - } }
+    ,bubble-delim-left-1  .initial:n = (
+    ,bubble-delim-left-2  .initial:n = /
+    ,bubble-delim-left-3  .initial:n = |
+    ,bubble-delim-left-4  .initial:n = \c_backslash_str
+    ,bubble-delim-right-1 .initial:n = )
+    ,bubble-delim-right-2 .initial:n = \c_backslash_str
+    ,bubble-delim-right-3 .initial:n = |
+    ,bubble-delim-right-4 .initial:n = /
+  }
+%    \end{macrocode}
+%
+%^^A<<<
+%
+% \subsubsection{Functions}^^A>>>
+%
+% \paragraph{Internal}^^A>>>
+%
+% \begin{macro}{\ducksay_evaluate_message_alignment_fixed_width_tabular:}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_evaluate_message_alignment_fixed_width_tabular:
+  {
+    \tl_if_empty:NT \l_ducksay_msg_tabular_column_tl
+      {
+        \tl_set:Nx \l_ducksay_msg_tabular_column_tl
+          {
+            >
+            {
+              \str_case:Vn \l_ducksay_msg_align_tl
+                {
+                  { l } { \exp_not:N \l_ducksay_msg_align_l_tl }
+                  { c } { \exp_not:N \l_ducksay_msg_align_c_tl }
+                  { r } { \exp_not:N \l_ducksay_msg_align_r_tl }
+                  { j } { \exp_not:N \l_ducksay_msg_align_j_tl }
+                }
+              \exp_not:N \arraybackslash
+            }
+            p { \exp_not:N \l_ducksay_msg_width_dim }
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_evaluate_message_alignment_fixed_width_vbox:}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_evaluate_message_alignment_fixed_width_vbox:
+  {
+    \tl_set:Nx \l_ducksay_msg_align_vbox_tl
+      {
+        \str_case:Vn \l_ducksay_msg_align_tl
+          {
+            { l } { \exp_not:N \l_ducksay_msg_align_l_tl }
+            { c } { \exp_not:N \l_ducksay_msg_align_c_tl }
+            { r } { \exp_not:N \l_ducksay_msg_align_r_tl }
+            { j } { \exp_not:N \l_ducksay_msg_align_j_tl }
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_calculate_msg_width_from_int:}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_calculate_msg_width_from_int:
+  {
+    \hbox_set:Nn \l_ducksay_tmpa_box { \l_ducksay_msg_fount_tl M }
+    \dim_set:Nn \l_ducksay_msg_width_dim 
+      { \l_ducksay_msg_width_int \box_wd:N \l_ducksay_tmpa_box }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_msg_tabular_begin:}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_msg_tabular_begin:
+  {
+    \ducksay_msg_tabular_begin_inner:V \l_ducksay_msg_tabular_column_tl
+  }
+\cs_new:Npn \ducksay_msg_tabular_begin_inner:n #1
+  {
+    \begin { tabular } { @{} #1 @{} }
+  }
+\cs_generate_variant:Nn \ducksay_msg_tabular_begin_inner:n { V }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_msg_tabular_end:}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_msg_tabular_end:
+  {
+    \end { tabular }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_digest_options:n}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_digest_options:n #1
+  {
+    \keys_set:nn { ducksay } { #1 }
+    \tl_if_empty:NT \l_ducksay_animal_tl
+      { \keys_set:nn { ducksay } { default_animal } }
+    \bool_if:NTF \l_ducksay_eat_arg_box_bool
+      {
+        \dim_compare:nNnTF { \l_ducksay_msg_width_dim } < { \c_zero_dim }
+          {
+            \int_compare:nNnTF { \l_ducksay_msg_width_int } < { \c_zero_int }
+              {
+                \cs_set_eq:NN
+                  \ducksay_eat_argument:w \ducksay_eat_argument_hbox:w
+              }
+              {
+                \cs_set_eq:NN
+                  \ducksay_eat_argument:w \ducksay_eat_argument_vbox:w
+                \ducksay_calculate_msg_width_from_int:
+              }
+          }
+          {
+            \cs_set_eq:NN \ducksay_eat_argument:w \ducksay_eat_argument_vbox:w
+          }
+      }
+      {
+        \dim_compare:nNnTF { \l_ducksay_msg_width_dim } < { \c_zero_dim }
+          {
+            \int_compare:nNnTF { \l_ducksay_msg_width_int } < { \c_zero_int }
+              {
+                \tl_if_empty:NT \l_ducksay_msg_tabular_column_tl
+                  {
+                    \str_case:Vn \l_ducksay_msg_align_tl
+                      {
+                        { l }
+                          { \tl_set:Nn \l_ducksay_msg_tabular_column_tl { l } }
+                        { c }
+                          { \tl_set:Nn \l_ducksay_msg_tabular_column_tl { c } }
+                        { r }
+                          { \tl_set:Nn \l_ducksay_msg_tabular_column_tl { r } }
+                        { j } {
+                          \msg_error:nn { ducksay } { justify~unavailable }
+                          \tl_set:Nn \l_ducksay_msg_tabular_column_tl { l }
+                        }
+                      }
+                  }
+              }
+              {
+                \ducksay_calculate_msg_width_from_int:
+                \ducksay_evaluate_message_alignment_fixed_width_tabular:
+              }
+          }
+          {
+            \ducksay_evaluate_message_alignment_fixed_width_tabular:
+          }
+        \cs_set_eq:NN \ducksay_eat_argument:w \ducksay_eat_argument_tabular:w
+      }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_set_bubble_top_kern:}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_set_bubble_top_kern:
+  {
+    \group_begin:
+    \l_ducksay_bubble_fount_tl
+    \exp_args:NNNx
+    \group_end:
+    \dim_set:Nn \l_ducksay_bubble_top_kern_dim
+      { \dim_eval:n { \l_ducksay_bubble_top_kern_tl } }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_set_bubble_bottom_kern:}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_set_bubble_bottom_kern:
+  {
+    \group_begin:
+    \l_ducksay_bubble_fount_tl
+    \exp_args:NNNx
+    \group_end:
+    \dim_set:Nn \l_ducksay_bubble_bottom_kern_dim
+      { \dim_eval:n { \l_ducksay_bubble_bottom_kern_tl } }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_shipout:}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected:Npn \ducksay_shipout:
+  {
+    \hbox_set:Nn \l_ducksay_tmpa_box
+      { \l_ducksay_bubble_fount_tl \l_ducksay_bubble_delim_top_tl }
+    \int_set:Nn \l_ducksay_msg_width_int
+      {
+        \fp_eval:n
+          {
+            ceil 
+              ( \box_wd:N \l_ducksay_msg_box / \box_wd:N \l_ducksay_tmpa_box )
+          }
+      }
+    \group_begin:
+    \l_ducksay_bubble_fount_tl
+    \exp_args:NNNx
+    \group_end:
+    \int_set:Nn \l_ducksay_msg_height_int
+      {
+        \int_max:nn
+          {
+            \fp_eval:n
+              {
+                ceil
+                  (
+                    (
+                      \box_ht:N \l_ducksay_msg_box
+                      + \box_dp:N \l_ducksay_msg_box
+                    )
+                    / ( \arraystretch * \baselineskip )
+                  )
+              }
+            + \l_ducksay_vpad_int
+          }
+          { \l_ducksay_msg_height_int }
+      }
+    \hcoffin_set:Nn \l_ducksay_bubble_open_coffin
+      {
+        \l_ducksay_bubble_fount_tl
+        \begin{tabular}{@{}l@{}}
+          \int_compare:nNnTF { \l_ducksay_msg_height_int } = { \c_one_int }
+            {
+              \l_ducksay_bubble_delim_left_a_tl
+            }
+            {
+              \l_ducksay_bubble_delim_left_b_tl\\
+              \int_step_inline:nnn
+                { 3 } { \l_ducksay_msg_height_int }
+                {
+                  \kern-\l_ducksay_bubble_side_kern_tl
+                  \l_ducksay_bubble_delim_left_c_tl
+                  \\
+                }
+              \l_ducksay_bubble_delim_left_d_tl
+            }
+        \end{tabular}
+      }
+    \hcoffin_set:Nn \l_ducksay_bubble_close_coffin
+      {
+        \l_ducksay_bubble_fount_tl
+        \begin{tabular}{@{}r@{}}
+          \int_compare:nNnTF { \l_ducksay_msg_height_int } = { \c_one_int }
+            {
+              \l_ducksay_bubble_delim_right_a_tl
+            }
+            {
+              \l_ducksay_bubble_delim_right_b_tl \\
+              \int_step_inline:nnn
+                { 3 } { \l_ducksay_msg_height_int }
+                {
+                  \l_ducksay_bubble_delim_right_c_tl
+                  \kern-\l_ducksay_bubble_side_kern_tl
+                  \\
+                }
+              \l_ducksay_bubble_delim_right_d_tl
+            }
+        \end{tabular}
+      }
+    \hcoffin_set:Nn \l_ducksay_bubble_top_coffin
+      {
+        \l_ducksay_bubble_fount_tl
+        \int_step_inline:nn { \l_ducksay_msg_width_int + \l_ducksay_hpad_int }
+          { \l_ducksay_bubble_delim_top_tl }
+      }
+    \hcoffin_set:Nn \l_ducksay_msg_coffin { \box_use:N \l_ducksay_msg_box }
+    \bool_if:NF \l_ducksay_no_body_bool
+      {
+        \hcoffin_set:Nn \l_ducksay_body_coffin
+          {
+            \frenchspacing
+            \l_ducksay_body_fount_tl
+            \begin{tabular} { @{} l @{} }
+              \l_ducksay_animal_tl
+            \end{tabular}
+          }
+        \bool_if:NT \l_ducksay_mirrored_body_bool
+          {
+            \coffin_scale:Nnn \l_ducksay_body_coffin
+              { -\c_one_int } { \c_one_int }
+            \str_case:Vn \l_ducksay_body_to_msg_align_body_tl
+              {
+                { l } { \tl_set:Nn \l_ducksay_body_to_msg_align_body_tl { r } }
+                { r } { \tl_set:Nn \l_ducksay_body_to_msg_align_body_tl { l } }
+              }
+          }
+      }
+    \dim_set:Nn \l_ducksay_hpad_dim
+      {
+        (
+          \coffin_wd:N \l_ducksay_bubble_top_coffin
+          - \coffin_wd:N \l_ducksay_msg_coffin
+        ) / 2
+      }
+    \coffin_join:NnnNnnnn
+      \l_ducksay_msg_coffin         { l } { vc }
+      \l_ducksay_bubble_open_coffin { r } { vc }
+      { - \l_ducksay_hpad_dim } { \c_zero_dim }
+    \coffin_join:NnnNnnnn
+      \l_ducksay_msg_coffin          { r } { vc }
+      \l_ducksay_bubble_close_coffin { l } { vc }
+      { \l_ducksay_hpad_dim } { \c_zero_dim }
+    \ducksay_set_bubble_top_kern:
+    \ducksay_set_bubble_bottom_kern:
+    \coffin_join:NnnNnnnn
+      \l_ducksay_msg_coffin        { hc } { t }
+      \l_ducksay_bubble_top_coffin { hc } { b }
+      { \c_zero_dim } { \l_ducksay_bubble_top_kern_dim }
+    \coffin_join:NnnNnnnn
+      \l_ducksay_msg_coffin        { hc } { b }
+      \l_ducksay_bubble_top_coffin { hc } { t }
+      { \c_zero_dim } { \l_ducksay_bubble_bottom_kern_dim }
+    \bool_if:NF \l_ducksay_no_body_bool
+      {
+        \bool_if:NTF \l_ducksay_ignored_body_bool
+          { \coffin_attach:NVnNVnnn }
+          { \coffin_join:NVnNVnnn   }
+          \l_ducksay_msg_coffin  \l_ducksay_body_to_msg_align_msg_tl  { b }
+          \l_ducksay_body_coffin \l_ducksay_body_to_msg_align_body_tl { t }
+          { \l_ducksay_body_x_offset_dim } { \l_ducksay_body_y_offset_dim }
+      }
+    \coffin_typeset:NVVnn \l_ducksay_msg_coffin
+      \l_ducksay_output_h_pole_tl \l_ducksay_output_v_pole_tl
+      { \l_ducksay_output_x_offset_dim } { \l_ducksay_output_y_offset_dim }
+    \group_end:
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% ^^A\subparagraph{Questionable Syntax Introducing Functions (Hacks)}^^A>>>
+%
+%^^A<<<
+%
+% \subparagraph{Message Reading Functions}^^A>>>
+%
+% Version 2 has different ways of reading the message argument of \cs{ducksay}
+% and \cs{duckthink}. They all should allow almost arbitrary content and the
+% height and width are set based on the dimensions.
+%
+% \begin{macro}{\ducksay_eat_argument_tabular:w}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_eat_argument_tabular:w
+  {
+    \bool_if:NTF \l_ducksay_eat_arg_tab_verb_bool
+      { \ducksay_eat_argument_tabular_verb:w }
+      { \ducksay_eat_argument_tabular_normal:w }
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_eat_argument_tabular_inner:w}^^A>>>
+%    \begin{macrocode}
+\cs_new:Npn \ducksay_eat_argument_tabular_inner:w #1
+  {
+    \hbox_set:Nn \l_ducksay_msg_box
+      {
+        \l_ducksay_msg_fount_tl
+        \ducksay_msg_tabular_begin:
+          #1
+        \ducksay_msg_tabular_end:
+      }
+    \ducksay_shipout:
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_eat_argument_tabular_verb:w}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \ducksay_eat_argument_tabular_verb:w
+  { >{ \ducksay_process_verb_newline:nnn { ~ } { ~ \par } } +v }
+  { \ducksay_eat_argument_tabular_inner:w { \scantokens { #1 } } }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_eat_argument_tabular_normal:w}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \ducksay_eat_argument_tabular_normal:w { +m }
+  { \ducksay_eat_argument_tabular_inner:w { #1 } }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_eat_argument_hbox:w}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \ducksay_eat_argument_hbox:w
+  {
+    \afterassignment \ducksay_eat_argument_hbox_inner:w
+    \let \l_ducksay_nothing =
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_eat_argument_hbox_inner:w}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \ducksay_eat_argument_hbox_inner:w
+  {
+    \setbox \l_ducksay_msg_box \hbox \c_group_begin_token
+      \group_insert_after:N \ducksay_shipout:
+      \l_ducksay_msg_fount_tl
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_eat_argument_vbox:w}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \ducksay_eat_argument_vbox:w
+  {
+    \ducksay_evaluate_message_alignment_fixed_width_vbox:
+    \afterassignment \ducksay_eat_argument_vbox_inner:w
+    \let \l_ducksay_nothing =
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\ducksay_eat_argument_vbox_inner:w}^^A>>>
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \ducksay_eat_argument_vbox_inner:w
+  {
+    \setbox \l_ducksay_msg_box \vbox \c_group_begin_token
+      \hsize \l_ducksay_msg_width_dim
+      \group_insert_after:N \ducksay_shipout:
+      \l_ducksay_msg_fount_tl
+      \l_ducksay_msg_align_vbox_tl
+      \@afterindentfalse
+      \@afterheading
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+%^^A<<<
+%
+% \subparagraph{Generating Variants of External Functions}^^A>>>
+%
+%    \begin{macrocode}
+\cs_generate_variant:Nn \coffin_join:NnnNnnnn { NVnNVnnn }
+\cs_generate_variant:Nn \coffin_attach:NnnNnnnn { NVnNVnnn }
+\cs_generate_variant:Nn \coffin_typeset:Nnnnn { NVVnn }
+\cs_generate_variant:Nn \tl_if_eq:nnT { VnT }
+\cs_generate_variant:Nn \str_case:nn { Vn }
+\cs_generate_variant:Nn \regex_replace_all:NnN { Nnc }
+%    \end{macrocode}
+%
+%^^A<<<
+%
+%^^A<<<
+%
+% \paragraph{Document level}^^A>>>
+%
+% \begin{macro}{\ducksay}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \ducksay { O{} }
+  {
+    \group_begin:
+      \tl_set:Nn \l_ducksay_say_or_think_tl { say }
+      \ducksay_digest_options:n { #1 }
+      \ducksay_eat_argument:w
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+% \begin{macro}{\duckthink}^^A>>>
+%    \begin{macrocode}
+\NewDocumentCommand \duckthink { O{} }
+  {
+    \group_begin:
+      \tl_set:Nn \l_ducksay_say_or_think_tl { think }
+      \ducksay_digest_options:n { #1 }
+      \ducksay_eat_argument:w
+  }
+%    \end{macrocode}
+% \end{macro}^^A<<<
+%
+%^^A<<<
+%
+%^^A<<<
+%
+%    \begin{macrocode}
+%</code.v2>
+%    \end{macrocode}^^A<<<
+%
+% \SetVersion{}%
+% \subsection{Definition of the Animals}^^A>>>
+%
+%    \begin{macrocode}
+%<*animals>
+%^^A some of the below are from http://ascii.co.uk/art/kangaroo
+\AddAnimal{duck}%>>>
+{  \
+    \   __
+      >(' )
+        )/
+       /(
+      /  `----/
+      \  ~=- /
+    ~^~^~^~^~^~^~^}%<<<
+\AddAnimal{small-duck}%>>>
+{  \
+    \
+      >()_
+       (__)__ _}%<<<
+\AddAnimal{duck-family}%>>>
+{  \
+    \   __
+      >(' )
+        )/
+       /(
+      /  `----/  -()_  >()_
+    __\__~=-_/__ _(__)__(__)__ _}%<<<
+\AddAnimal{cow}%>>>
+{  \  ^__^
+    \ (oo)\_______
+      (__)\       )\/\
+          ||----w |
+          ||     ||}%<<<
+\AddAnimal{head-in}%>>>
+{  \  
+    \ ^__^         /
+      (oo)\_______/  ________
+      (__)\       )=(  ___|_ \____
+          ||----w |  \ \    \____ |
+          ||     ||   ||         ||}%<<<
+\AddAnimal{sodomized}%>>>
+{  \             _
+    \           (_)
+      ^__^       / \
+      (oo)\_____/_\ \
+      (__)\       ) /
+          ||----w ((
+          ||     ||>>}%<<<
+\AddAnimal{tux}%>>>
+{  \
+    \  .--. 
+      |o_o |
+      |\_/ |
+     //   \ \
+    (|     | )
+   /'\_   _/`\
+   \___)=(___/}%<<<
+\AddAnimal{pig}%>>>
++  \     _//| .-~~~-.
+    \ _/oo  }        }-@
+     ('')_  }        |
+      `--'| { }--{  }
+           //_/  /_/+%<<<
+\AddAnimal{frog}%>>>
+{   \
+     \ (.)_(.)
+    _ (   _   ) _
+   / \/`-----'\/ \
+ __\ ( (     ) ) /__
+ )   /\ \._./ /\   (
+  )_/ /|\   /|\ \_(}%<<<
+\AddAnimal{snowman}%>>>
+{  \
+    \_[_]_
+      (")
+   >-( : )-<
+    (__:__)}%<<<
+\AddAnimal{hedgehog}%>>>
+{  \    .\|//||\||.
+    \  |/\/||/|//|/|
+      /. `|/\\|/||/||
+     o__,_|//|/||\||'}%<<<
+\AddAnimal{kangaroo}%>>>
+{  \
+    \ _,'   ___
+     <__\__/   \
+        \_  /  _\
+          \,\ / \\
+            //   \\
+          ,/'     `\_,}%<<<
+%^^A http://chris.com/ascii/index.php?art=animals/rabbits
+\AddAnimal{rabbit}%>>>
+{ \     / \`\         __
+   \   |  \ `\      /`/ \
+    \  \_/`\  \-"-/` /\  \
+            |       |  \  |
+            (d     b)   \_/
+            /       \
+        ,".|.'.\_/.'.|.",
+       /   /\' _|_ '/\   \
+       |  /  '-`"`-'  \  |
+       | |             | |
+       | \    \   /    / |
+        \ \    \ /    / /
+         `"`\   :   /'"`
+             `""`""`}%<<<
+\AddAnimal{bunny}%>>>
+{ \
+   \      /
+      /\ /
+       ( )
+     .( o ).}%<<<
+\AddAnimal{small-rabbit}%>>>
+{  \
+    \ _//
+     (')---.
+      _/-_( )o}%<<<
+\AddAnimal{dragon}%>>>
+{     \                    / \  //\
+       \    |\___/|      /   \//  \\
+        \   /0  0  \__  /    //  | \ \    
+           /     /  \/_/    //   |  \  \  
+           @_^_@'/   \/_   //    |   \   \ 
+           //_^_/     \/_ //     |    \    \
+        ( //) |        \///      |     \     \
+      ( / /) _|_ /   )  //       |      \     _\
+    ( // /) '/,_ _ _/  ( ; -.    |    _ _\.-~        .-~~~^-.
+  (( / / )) ,-{        _      `-.|.-~-.           .~         `.
+ (( // / ))  '/\      /                 ~-. _ .-~      .-~^-.  \
+ (( /// ))      `.   {            }                   /      \  \
+  (( / ))     .----~-.\        \-'                 .~         \  `. \^-.
+             ///.----..>        \             _ -~             `.  ^-`  ^-_
+               ///-._ _ _ _ _ _ _}^ - - - - ~                     ~-- ,.-~
+                                                                  /.-~}%<<<
+%^^A http://www.ascii-art.de/ascii/def/dogs.txt
+\AddAnimal{dog}%>>>
+{  \     __
+    \ .-'\/\
+       "\   '------.
+     ___/       (  .'_____
+    '-----'"""'------"""""'}%<<<
+%^^A http://ascii.co.uk/art/squirrel
+\AddAnimal{squirrel}%>>>
+{  \           ,;:;;,
+    \    ,    ;;;;;
+      .=',    ;:;;:,
+     /_', "=. ';:;:;
+     @=:__,  \,;:;:'
+       _(\.=  ;:;;'
+      `"_(  _/="`
+       `"'``}%<<<
+\AddAnimal{snail}%>>>
+{  \
+    \          .-""-.
+      oo      ; .-.  :
+       \\__..-: '.__.')._
+        "-._.._'.__.-'_.."}%<<<
+%^^A http://www.ascii-art.de/ascii/uvw/unicorn.txt
+\AddAnimal{unicorn}%>>>
+{   \
+     \       /((((((\\\\
+     ---====((((((((((\\\\\
+          ((           \\\\\\\
+          ( (*    _/      \\\\\\\
+            \    /  \      \\\\\\_         __,,__
+             |  |   |       </    "------""     ((\\\\
+             o_|   /        /                      \ \\\\    \\\\\\\
+                  |  ._    (                        \ \\\\\\\\\\\\\\\\
+                  | /                       /       /    \\\\\\\     \\
+          .______/\/     /                 /       /         \\\
+         / __.____/    _/          ___----(       /\
+        / / / ________/:______,---'        \     /  \_
+       / /  \ \                             \   \ \_  \
+      ( <    \ \                             >  /    \ \
+       \/      \\_                          / /       > )
+                \_|                        / /       / /
+                                         _//       _//
+                                       /_|       /_|}%<<<
+%^^A https://asciiart.website//index.php?art=animals/other%20(water)
+\AddAnimal{whale}%>>>
+{  \                |-.
+    \    .-""-._     \ \.--|
+     \  /       `-..__)  ,-'
+       |     .          /
+        \--.__,   .__.,'
+         `-.___'._\_.'}%<<<
+%^^A from http://www.ascii-art.de/ascii/s/starwars.txt :
+\AddAnimal{yoda}%>>>
+{   \
+     \             ____
+      \         _.' :  `._
+            .-.'`.  ;   .'`.-.
+   __      / : ___\ ;  /___ ; \      __
+ ,'_ ""--.:__;".-.";: :".-.":__;.--"" _`,
+ :' `.t""--.. '<@.`;_  ',@>` ..--""j.' `;
+      `:-.._J '-.-'L__ `-- ' L_..-;'
+        "-.__ ;  .-"  "-.  : __.-"
+            L ' /.------.\ ' J
+             "-.   "--"   .-"
+            __.l"-:_JL_;-";.__
+         .-j/'.;  ;""""  / .'\"-.
+       .' /:`. :  :     /.".'';  `.
+    .-"  / ;`.".  :    ."."   :    "-.
+ .+"-.  : :   ".".". ."."      ;-._   \
+ ; \  `.; ; .   "."-"."        : : "+. ;
+ :  ;   ; ;  .   ."."    ;     : ;  : \:
+ ;  :   ; :     / /     /  ,   ;:   ;  :
+: \  ;  :  ;   ; /     :  ,   : ;  /  ::
+;  ; :   ; :  ; ;      ;      ;   :   ;:
+:  :  ;  :  ;. ;      '      : :  ;  : ;
+;\    :   ; : .          ,   ; ;     ; ;
+: `."-;   :  ;      .   ;   :  ;    /  ;
+ ;    -:   ; :      ,  ,    ;  : .-"   :
+ :\     \  :  ;    ,       : \.-"      :
+  ;`.    \  ; :   .   ,    ;.'_..--  / ;
+  :  "-.  "-:  ;     ,    :/."      .'  :
+   \         \ :    :     ;/  __        :
+    \       .-`.\        /t-""  ":-+.   :
+     `.  .-"    `l    __/ /`. :  ; ; \  ;
+       \   .-" .-"-.-"  .' .'j \  /   ;/
+        \ / .-"   /.     .'.' ;_:'    ;
+         :-""-.`./-.'     /    `.___.'
+               \ `t  ._  /
+                "-.t-._:'}%<<<
+\AddAnimal{yoda-head}%>>>
+{   \
+     \             ____
+      \         _.' :  `._
+            .-.'`.  ;   .'`.-.
+   __      / : ___\ ;  /___ ; \      __
+ ,'_ ""--.:__;".-.";: :".-.":__;.--"" _`,
+ :' `.t""--.. '<@.`;_  ',@>` ..--""j.' `;
+      `:-.._J '-.-'L__ `-- ' L_..-;'
+        "-.__ ;  .-"  "-.  : __.-"
+            L ' /.------.\ ' J
+             "-.   "--"   .-"
+            __.l"-:_JL_;-";.__
+         .-j/'.;  ;""""  / .'\"-.
+       .' /:`. :  :     /.".'';  `.
+    .-"  / ;`.".  :    ."."   :    "-.
+ .+"-.  : :   ".".". ."."      ;-._   \}%<<<
+%^^A from https://www.ascii-code.com/ascii-art/movies/star-wars.php
+\AddAnimal{small-yoda}%>>>
+{  \
+    \
+    __.-._
+    '-._"7'
+     /'.-c
+     |  /T
+    _)_/LI}%<<<
+\AddAnimal{r2d2}%>>>
+{  \
+    \ ,-----.
+    ,'_/_|_\_`.
+   /<<::8[O]::>\
+  _|-----------|_
+ |  | ====-=- |  |
+ |  | -=-==== |  |
+ \  | ::::|()||  /
+  | | ....|()|| |
+  | |_________| |
+  | |\_______/| |
+ /   \ /   \ /   \
+ `---' `---' `---'}%<<<
+\AddAnimal{vader}%>>>
+{  \     _.-'~~~~~~`-._
+    \   /      ||      \
+       /       ||       \
+      |        ||        |
+      | _______||_______ |
+      |/ ----- \/ ----- \|
+     /  (     )  (     )  \
+    / \  ----- () -----  / \
+   /   \      /||\      /   \
+  /     \    /||||\    /     \
+ /       \  /||||||\  /       \
+/_        \O========O/        _\
+  `--...__|`-._  _.-'|__...--'
+          |    `'    |}%<<<
+%</animals>
+%    \end{macrocode}^^A<<<
+%
+%^^A<<<
+%
+% \end{implementation}^^A<<<
+%
+% \closingpage
+%
+\endinput
+%
+^^A vim: ft=tex fdm=marker fmr=>>>,<<<


Property changes on: trunk/Master/texmf-dist/source/latex/ducksay/ducksay.dtx
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/tex/latex/ducksay/ducksay.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/ducksay/ducksay.sty	2018-09-21 00:23:48 UTC (rev 48719)
+++ trunk/Master/texmf-dist/tex/latex/ducksay/ducksay.sty	2018-09-21 21:06:08 UTC (rev 48720)
@@ -1,471 +1,204 @@
-%% This package is distributed under the terms of the GPLv3 or later, or the
-%% LPPL 1.3c or later, which ever license fits your needs the best.
 %%
-%% Copyright (C) 2017 by Jonathan P. Spratte
+%% This is file `ducksay.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% ducksay.dtx  (with options: `pkg')
+%% 
+%% --------------------------------------------------------------
+%% ducksay -- cowsay for LaTeX
+%% E-mail: jspratte at yahoo.de
+%% Released under the LaTeX Project Public License v1.3c or later
+%% See http://www.latex-project.org/lppl.txt
+%% --------------------------------------------------------------
+%% 
+%% Copyright (C) 2017-2018 Jonathan P. Spratte
+%% 
+%% This  work may be  distributed and/or  modified under  the conditions  of the
+%% LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
+%% (at your option) any later version.  The latest version of this license is in
+%% the file:
+%% 
+%%   http://www.latex-project.org/lppl.txt
+%% 
+%% Alternatively you can use this work under the terms of the GNU General Public
+%% Licensce (GPL), version 3 or later, except that you might not redistribute it
+%% under the same  name if you change  its functionality.  Choose which of these
+%% licenses fits your needs the best.
+%% 
+%% This work is "maintained" (as per LPPL maintenance status) by
+%%   Jonathan P. Spratte.
+%% 
+%% This work consists of the file  ducksay.dtx
+%% and the derived files           ducksay.pdf
+%%                                 ducksay.sty
+%%                                 ducksay.code.v1.tex
+%%                                 ducksay.code.v2.tex and
+%%                                 ducksay.animals.tex.
+%% 
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{xparse,l3keys2e}
 
-\def\ducksay at version{v1.2}
-\def\ducksay at date{2017/10/30}
+\def\ducksay at version{2.0}
+\def\ducksay at date{2018/09/21}
 
 \ProvidesExplPackage
   {ducksay}           {\ducksay at date}
   {\ducksay at version}  {cowsay for LaTeX}
 
-\ExplSyntaxOn
-
-% variables>>>
-\int_new:N \l_ducksay_strlen_int
-\int_new:N \l_ducksay_lines_int
+\int_new:N \l_ducksay_msg_width_int
+\int_new:N \l_ducksay_msg_height_int
 \seq_new:N \l_ducksay_msg_lines_seq
+\tl_new:N \l_ducksay_say_or_think_tl
 \tl_new:N \l_ducksay_align_tl
 \tl_new:N \l_ducksay_msg_align_tl
 \tl_new:N \l_ducksay_animal_tl
-\bool_new:N \l_ducksay_empty_ligatures_bool
-\cs_new:Nn \ducksay_bubble: {}
-\cs_new:Nn \ducksay_body: {}
-\regex_new:N \l_ducksay_ligatures_regex
-%<<<
-
-% predefined regexes>>>
-% regexes for \duckthink >>>
+\tl_new:N \l_ducksay_body_tl
+\tl_new:N \l_ducksay_bubble_tl
+\tl_new:N \l_ducksay_tmpa_tl
+\bool_new:N \l_ducksay_also_add_think_bool
+\bool_new:N \l_ducksay_version_one_bool
+\bool_new:N \l_ducksay_version_two_bool
+\box_new:N \l_ducksay_tmpa_box
 \regex_const:Nn \c_ducksay_first_regex  { \A(.\s*)\\ }
 \regex_const:Nn \c_ducksay_second_regex { \A(.[^\c{null}]*\c{null}\s*)\\ }
 \regex_const:Nn \c_ducksay_third_regex  {
   \A(.[^\c{null}]*\c{null}[^\c{null}]*\c{null}\s*)\\ }
-%<<<
-% regexes for \AddAnimal >>>
-\regex_const:Nn \c_ducksay_newline_regex { \r }
-\regex_set:Nn \l_ducksay_ligatures_regex { [\-<>`] }
-%<<<
-%<<<
-
-\keys_define:nn { ducksay } {%>>>
-  ,bubble .code:n       = \cs_set:Nn \ducksay_bubble: {#1}
-  ,body   .code:n       = \cs_set:Nn \ducksay_body: {#1}
-  ,align  .tl_set:N     = \l_ducksay_align_tl
-  ,align  .value_required:n = true
-  ,wd     .int_set:N    = \l_ducksay_strlen_int
-  ,wd     .value_required:n = true
-  ,ht     .int_set:N    = \l_ducksay_lines_int
-  ,ht     .value_required:n = true
-  ,animal .code:n       = {
-    \keys_define:nn { ducksay } { default_animal .meta:n = {#1} }}
-  ,animal .initial:n    = duck
-  ,msg-align .tl_set:N  = \l_ducksay_msg_align_tl
-  ,msg-align .initial:n = l
-  ,msg-align .value_required:n = true
-  ,ligatures .code:n    = {
-    \tl_if_empty:nTF { #1 }
-      { \bool_set_true:N \l_ducksay_empty_ligatures_bool }
-      { \regex_set:Nn \l_ducksay_ligatures_regex { #1 } }
+\regex_const:Nn \c_ducksay_textcolor_regex
+  { \cO(?:\\textcolor\{(.*?)\}\{(.*?)\}) }
+\regex_const:Nn \c_ducksay_color_delim_regex
+  { \cO(?:\\bgroup\\color\{(.*?)\}(.*)\\egroup) }
+\regex_const:Nn \c_ducksay_color_regex
+  { \cO(?:\\color\{(.*?)\}) }
+\msg_new:nnn { ducksay } { load-time-only }
+  { The~`#1`~key~is~to~be~used~only~during~package~load~time. }
+\keys_define:nn { ducksay }
+  {
+    ,bubble .tl_set:N      = \l_ducksay_bubble_tl
+    ,body   .tl_set:N      = \l_ducksay_body_tl
+    ,align  .tl_set:N      = \l_ducksay_align_tl
+    ,align  .value_required:n = true
+    ,wd     .int_set:N     = \l_ducksay_msg_width_int
+    ,wd     .initial:n     = -\c_max_int
+    ,wd     .value_required:n = true
+    ,ht     .int_set:N     = \l_ducksay_msg_height_int
+    ,ht     .initial:n     = -\c_max_int
+    ,ht     .value_required:n = true
+    ,animal .code:n        =
+      { \keys_define:nn { ducksay } { default_animal .meta:n = { #1 } } }
+    ,animal .initial:n     = duck
+    ,msg-align .tl_set:N   = \l_ducksay_msg_align_tl
+    ,msg-align .initial:n  = l
+    ,msg-align .value_required:n = true
+    ,rel-align .tl_set:N   = \l_ducksay_rel_align_tl
+    ,rel-align .initial:n  = l
+    ,rel-align .value_required:n = true
+    ,ligatures .tl_set:N   = \l_ducksay_ligatures_tl
+    ,ligatures .initial:n  = { `<>,'- }
+    ,add-think .bool_set:N = \l_ducksay_also_add_think_bool
+    ,version   .choice:
+    ,version / 1 .code:n   =
+      {
+        \bool_set_false:N \l_ducksay_version_two_bool
+        \bool_set_true:N  \l_ducksay_version_one_bool
+      }
+    ,version / 2 .code:n   =
+      {
+        \bool_set_false:N \l_ducksay_version_one_bool
+        \bool_set_true:N  \l_ducksay_version_two_bool
+      }
+    ,version   .initial:n  = 2
   }
-}%<<<
-
 \ProcessKeysOptions { ducksay }
-
-\cs_new:Nn \ducksay_longest_line:n {%>>>
-  \int_incr:N \l_ducksay_lines_int
-  \exp_args:NNx \tl_set:Nn \l_tmpa_tl { #1 }
-  \regex_replace_all:nnN { \s } { \c{space} } \l_tmpa_tl
-  \int_set:Nn \l_ducksay_strlen_int {
-    \int_max:nn { \l_ducksay_strlen_int } { \tl_count:N \l_tmpa_tl } }
-}%<<<
-
-\cs_new:Nn \ducksay_open_bubble: {%>>>
-  \begin{tabular}{@{}l@{}}
-    \mbox{}\\
-    \int_compare:nNnTF {\l_ducksay_lines_int} = {1} {
-      (
-    }{
-      /
-      \int_step_inline:nnnn {3}{1} {\l_ducksay_lines_int} {\\\kern-0.5ex|}
-      \\\detokenize{\ }
-    }
-    \\[-1ex]\mbox{}
-  \end{tabular}
-  \begin{tabular}{@{}l@{}}
-    _\\
-    \int_step_inline:nnnn{2}{1}{\l_ducksay_lines_int}{\\}\\[-1ex]
-    \mbox{-}
-  \end{tabular}
-}%<<<
-
-\cs_new:Nn \ducksay_close_bubble: {%>>>
-  \begin{tabular}{@{}l@{}}
-    _\\
-    \int_step_inline:nnnn{2}{1}{\l_ducksay_lines_int}{\\}\\[-1ex]
-    {-}
-  \end{tabular}
-  \begin{tabular}{@{}r@{}}
-    \mbox{}\\
-    \int_compare:nNnTF {\l_ducksay_lines_int} = {1} {
-      )
-    }{
-      \detokenize{\ }
-      \int_step_inline:nnnn {3}{1}{\l_ducksay_lines_int} {\\|\kern-0.5ex}
-      \\/
-    }
-    \\[-1ex]\mbox{}
-  \end{tabular}
-}%<<<
-
-\cs_new:Nn \ducksay_print_msg:nn {%>>>
-  \begin{tabular}{@{} #2 @{}}
-    \int_step_inline:nnnn{1}{1}{\l_ducksay_strlen_int}{_}\\
-    #1\\[-1ex]
-    \int_step_inline:nnnn{1}{1}{\l_ducksay_strlen_int}{{-}}
-  \end{tabular}
-}%<<<
-
-\cs_generate_variant:Nn \ducksay_print_msg:nn { nV }
-
-\cs_new:Nn \ducksay_print:n {%>>>
-  \int_case:nnF { \l_ducksay_strlen_int }
-    { { 0 } {
-      \seq_set_split:Nnn \l_ducksay_msg_lines_seq {\\} { #1 }
-      \seq_map_function:NN \l_ducksay_msg_lines_seq \ducksay_longest_line:n
-    }}
-    {
-      \int_case:nn { \l_ducksay_lines_int }
-        { { 0 } {
-          \regex_count:nnN {\c{\\}} {#1} \l_ducksay_lines_int
-          \int_incr:N \l_ducksay_lines_int
-        }}
-    }
-  \group_begin:
-    \frenchspacing
-    \ttfamily
-    \verbatim at font
-    \@noligs
-    \begin{tabular}[\l_ducksay_align_tl]{@{}l@{}}
-      \ducksay_bubble:
-      \begin{tabular}{@{}l@{}}
-        \ducksay_open_bubble:
-        \ducksay_print_msg:nV {#1} \l_ducksay_msg_align_tl
-        \ducksay_close_bubble:
-      \end{tabular}\\
-      \ducksay_body:
-      \begin{tabular}{@{}l@{}}
-        \l_ducksay_animal_tl
-      \end{tabular}
-    \end{tabular}
-  \group_end:
-}%<<<
-
-\cs_new:Nn \ducksay_prepare_say_and_think:n {%>>>
-  \int_zero:N \l_ducksay_strlen_int
-  \int_zero:N \l_ducksay_lines_int
-  \keys_define:nn { ducksay } { animal .meta:n = { ##1 } }
-  \keys_set:nn { ducksay } { default_animal,#1 }
-}%<<<
-
-\cs_new:Nn \ducksay_to_duckthink: {%>>>
-  \regex_replace_once:NnN \c_ducksay_first_regex  { \1O } \l_ducksay_animal_tl
-  \regex_replace_once:NnN \c_ducksay_second_regex { \1o } \l_ducksay_animal_tl
-  \regex_replace_once:NnN \c_ducksay_third_regex  { \1o } \l_ducksay_animal_tl
-}%<<<
-
-\NewDocumentCommand{\ducksay}{ O{} m }{%>>>
-  \group_begin:
-    \ducksay_prepare_say_and_think:n { #1 }
-    \ducksay_print:n { #2 }
-  \group_end:
-}%<<<
-
-\NewDocumentCommand{\duckthink}{ O{} m }{%>>>
-  \group_begin:
-    \ducksay_prepare_say_and_think:n { #1 }
-    \ducksay_to_duckthink:
-    \ducksay_print:n { #2 }
-  \group_end:
-}%<<<
-
-\NewDocumentCommand{\DefaultAnimal}{ m }{%>>>
-  \keys_define:nn { ducksay } { default_animal .meta:n = {#1} }}%<<<
-
-\NewDocumentCommand{\DucksayOptions}{ m }{%>>>
-  \keys_set:nn { ducksay } { #1 }}%<<<
-
-\NewDocumentCommand{\AddAnimal}{ s m +v }{%>>>
-  \tl_set:Nn \l_tmpa_tl { \ #3 }
-  \bool_if:NF \l_ducksay_empty_ligatures_bool {
-    \regex_replace_all:NnN \l_ducksay_ligatures_regex { \c{mbox}\0 } \l_tmpa_tl 
+\keys_define:nn { ducksay }
+  {
+    version .code:n = \msg_error:nnn { ducksay } { load-time-only } { version }
   }
-  \regex_replace_all:NnN \c_ducksay_newline_regex { \c{tabularnewline}\c{null} }
-    \l_tmpa_tl
-  \tl_gset_eq:cN { g_ducksay_animal_#2_tl } \l_tmpa_tl
-  \keys_define:nn { ducksay } {
-    #2 .code:n = \tl_set_eq:Nc \l_ducksay_animal_tl { g_ducksay_animal_#2_tl }
+\cs_generate_variant:Nn \tl_if_eq:nnT { VnT }
+\cs_new_protected:Npn \ducksay_create_think_animal:n #1
+  {
+    \group_begin:
+      \tl_set_eq:Nc \l_ducksay_tmpa_tl { g_ducksay_animal_say_#1_tl }
+      \regex_replace_once:NnN \c_ducksay_first_regex  { \1O } \l_ducksay_tmpa_tl
+      \regex_replace_once:NnN \c_ducksay_second_regex { \1o } \l_ducksay_tmpa_tl
+      \regex_replace_once:NnN \c_ducksay_third_regex  { \1o } \l_ducksay_tmpa_tl
+      \tl_gset_eq:cN { g_ducksay_animal_think_#1_tl } \l_ducksay_tmpa_tl
+    \group_end:
   }
-  \IfBooleanT{#1}{
-    \keys_define:nn { ducksay } {
-      default_animal .meta:n = {#2} }}
-}%<<<
-
+\cs_new_protected:Npx \ducksay_replace_verb_newline:Nn #1 #2
+  {
+    \tl_replace_all:Nnn #1 { \char_generate:nn { 13 } { 12 } } { #2 }
+  }
+\cs_new_protected:Npx \ducksay_replace_verb_newline_newline:Nn #1 #2
+  {
+    \tl_replace_all:Nnn #1
+      { \char_generate:nn { 13 } { 12 } \char_generate:nn { 13 } { 12 } } { #2 }
+  }
+\cs_new_protected:Npn \ducksay_process_verb_newline:nnn #1 #2 #3
+  {
+    \tl_set:Nn \ProcessedArgument { #3 }
+    \ducksay_replace_verb_newline_newline:Nn \ProcessedArgument { #2 }
+    \ducksay_replace_verb_newline:Nn \ProcessedArgument { #1 }
+  }
+\cs_new_protected:Npn \ducksay_add_animal_inner:nn #1 #2
+  {
+    \tl_set:Nn \l_ducksay_tmpa_tl { \ #2 }
+    \tl_map_inline:Nn \l_ducksay_ligatures_tl
+      { \tl_replace_all:Nnn \l_ducksay_tmpa_tl { ##1 } { { ##1 } } }
+    \ducksay_replace_verb_newline:Nn \l_ducksay_tmpa_tl { \tabularnewline\null }
+    \tl_gset_eq:cN { g_ducksay_animal_say_#1_tl } \l_ducksay_tmpa_tl
+    \keys_define:nn { ducksay }
+      {
+        #1 .code:n =
+          {
+            \tl_if_exist:cF
+              { g_ducksay_animal_ \l_ducksay_say_or_think_tl _#1_tl }
+              { \ducksay_create_think_animal:n { #1 } }
+            \tl_set_eq:Nc \l_ducksay_animal_tl
+              { g_ducksay_animal_ \l_ducksay_say_or_think_tl _#1_tl }
+          }
+      }
+  }
+\NewDocumentCommand \DefaultAnimal { m }
+  {
+    \keys_define:nn { ducksay } { default_animal .meta:n = { #1 } }
+  }
+\NewDocumentCommand \DucksayOptions { m }
+  {
+    \keys_set:nn { ducksay } { #1 }
+  }
+\NewDocumentCommand \AddAnimal { s m +v }
+  {
+    \ducksay_add_animal_inner:nn { #2 } { #3 }
+    \bool_if:NT \l_ducksay_also_add_think_bool
+      { \ducksay_create_think_animal:n { #2 } }
+    \IfBooleanT{#1}
+      { \keys_define:nn { ducksay } { default_animal .meta:n = { #2 } } }
+  }
+\NewDocumentCommand \AddColoredAnimal { s m +v }
+  {
+    \ducksay_add_animal_inner:nn { #2 } { #3 }
+    \regex_replace_all:Nnc \c_ducksay_color_delim_regex
+      { \c{bgroup}\c{color}\cB\{\1\cE\}\2\c{egroup} }
+      { g_ducksay_animal_say_#2_tl }
+    \regex_replace_all:Nnc \c_ducksay_color_regex
+      { \c{color}\cB\{\1\cE\} }
+      { g_ducksay_animal_say_#2_tl }
+    \regex_replace_all:Nnc \c_ducksay_textcolor_regex
+      { \c{textcolor}\cB\{\1\cE\}\cB\{\2\cE\} }
+      { g_ducksay_animal_say_#2_tl }
+    \bool_if:NT \l_ducksay_also_add_think_bool
+      { \ducksay_create_think_animal:n { #2 } }
+    \IfBooleanT{#1}
+      { \keys_define:nn { ducksay } { default_animal .meta:n = { #2 } } }
+  }
+\bool_if:NT \l_ducksay_version_one_bool
+  { \file_input:n { ducksay.code.v1.tex } }
+\bool_if:NT \l_ducksay_version_two_bool
+  { \file_input:n { ducksay.code.v2.tex } }
 \ExplSyntaxOff
-
-% Animals:>>>
-% some of the below are from http://ascii.co.uk/art/kangaroo
-\AddAnimal{duck}%>>>
-{  \
-    \   __
-      >(' )
-        )/
-       /(
-      /  `----/
-      \  ~=- /
-    ~^~^~^~^~^~^~^}%<<<
-\AddAnimal{small-duck}%>>>
-{  \
-    \
-      >()_
-       (__)__ _}%<<<
-\AddAnimal{duck-family}%>>>
-{  \
-    \   __
-      >(' )
-        )/
-       /(
-      /  `----/  -()_  >()_
-    __\__~=-_/__ _(__)__(__)__ _}%<<<
-\AddAnimal{cow}%>>>
-{  \  ^__^
-    \ (oo)\_______
-      (__)\       )\/\
-          ||----w |
-          ||     ||}%<<<
-\AddAnimal{head-in}%>>>
-{  \  
-    \ ^__^         /
-      (oo)\_______/  ________
-      (__)\       )=(  ___|_ \____
-          ||----w |  \ \    \____ |
-          ||     ||   ||         ||}%<<<
-\AddAnimal{sodomized}%>>>
-{  \             _
-    \           (_)
-      ^__^       / \
-      (oo)\_____/_\ \
-      (__)\       ) /
-          ||----w ((
-          ||     ||>>}%<<<
-\AddAnimal{tux}%>>>
-{  \
-    \  .--. 
-      |o_o |
-      |\_/ |
-     //   \ \
-    (|     | )
-   /'\_   _/`\
-   \___)=(___/}%<<<
-\AddAnimal{pig}%>>>
-+  \     _//| .-~~~-.
-    \ _/oo  }        }-@
-     ('')_  }        |
-      `--'| { }--{  }
-           //_/  /_/+%<<<
-\AddAnimal{frog}%>>>
-{   \
-     \ (.)_(.)
-    _ (   _   ) _
-   / \/`-----'\/ \
- __\ ( (     ) ) /__
- )   /\ \._./ /\   (
-  )_/ /|\   /|\ \_(}%<<<
-\AddAnimal{snowman}%>>>
-{  \
-    \_[_]_
-      (")
-   >-( : )-<
-    (__:__)}%<<<
-\AddAnimal{hedgehog}%>>>
-{  \    .\|//||\||.
-    \  |/\/||/|//|/|
-      /. `|/\\|/||/||
-     o__,_|//|/||\||'}%<<<
-\AddAnimal{kangaroo}%>>>
-{  \
-    \ _,'   ___
-     <__\__/   \
-        \_  /  _\
-          \,\ / \\
-            //   \\
-          ,/'     `\_,}%<<<
-\AddAnimal{rabbit}%>>> http://chris.com/ascii/index.php?art=animals/rabbits
-{ \     / \`\         __
-   \   |  \ `\      /`/ \
-    \  \_/`\  \-"-/` /\  \
-            |       |  \  |
-            (d     b)   \_/
-            /       \
-        ,".|.'.\_/.'.|.",
-       /   /\' _|_ '/\   \
-       |  /  '-`"`-'  \  |
-       | |             | |
-       | \    \   /    / |
-        \ \    \ /    / /
-         `"`\   :   /'"`
-             `""`""`}%<<<
-\AddAnimal{bunny}%>>>
-{ \
-   \      /
-      /\ /
-       ( )
-     .( o ).}%<<<
-\AddAnimal{small-rabbit}%>>>
-{  \
-    \ _//
-     (')---.
-      _/-_( )o}%<<<
-\AddAnimal{dragon}%>>>
-{     \                    / \  //\
-       \    |\___/|      /   \//  \\
-        \   /0  0  \__  /    //  | \ \    
-           /     /  \/_/    //   |  \  \  
-           @_^_@'/   \/_   //    |   \   \ 
-           //_^_/     \/_ //     |    \    \
-        ( //) |        \///      |     \     \
-      ( / /) _|_ /   )  //       |      \     _\
-    ( // /) '/,_ _ _/  ( ; -.    |    _ _\.-~        .-~~~^-.
-  (( / / )) ,-{        _      `-.|.-~-.           .~         `.
- (( // / ))  '/\      /                 ~-. _ .-~      .-~^-.  \
- (( /// ))      `.   {            }                   /      \  \
-  (( / ))     .----~-.\        \-'                 .~         \  `. \^-.
-             ///.----..>        \             _ -~             `.  ^-`  ^-_
-               ///-._ _ _ _ _ _ _}^ - - - - ~                     ~-- ,.-~
-                                                                  /.-~}%<<<
-\AddAnimal{dog}%>>> http://www.ascii-art.de/ascii/def/dogs.txt
-{  \     __
-    \ .-'\/\
-       "\   '------.
-     ___/       (  .'_____
-    '-----'"""'------"""""'}%<<<
-\AddAnimal{squirrel}%>>> http://ascii.co.uk/art/squirrel
-{  \           ,;:;;,
-    \         ;;;;;
-      .=',    ;:;;:,
-     /_', "=. ';:;:;
-     @=:__,  \,;:;:'
-       _(\.=  ;:;;'
-      `"_(  _/="`
-       `"'``}%<<<
-% from http://www.ascii-art.de/ascii/uvw/unicorn.txt
-\AddAnimal{unicorn}
-{   \
-     \       /((((((\\\\
-     ---====((((((((((\\\\\
-          ((           \\\\\\\
-          ( (*    _/      \\\\\\\
-            \    /  \      \\\\\\_         __,,__
-             |  |   |       </    "------""     ((\\\\
-             o_|   /        /                      \ \\\\    \\\\\\\
-                  |  ._    (                        \ \\\\\\\\\\\\\\\\
-                  | /                       /       /    \\\\\\\     \\
-          .______/\/     /                 /       /         \\\
-         / __.____/    _/          ___----(       /\
-        / / / ________/:______,---'        \     /  \_
-       / /  \ \                             \   \ \_  \
-      ( <    \ \                             >  /    \ \
-       \/      \\_                          / /       > )
-                \_|                        / /       / /
-                                         _//       _//
-                                       /_|       /_|}
-
-% from http://www.ascii-art.de/ascii/s/starwars.txt :
-\AddAnimal{yoda}%>>>
-{   \
-     \             ____
-      \         _.' :  `._
-            .-.'`.  ;   .'`.-.
-   __      / : ___\ ;  /___ ; \      __
- ,'_ ""--.:__;".-.";: :".-.":__;.--"" _`,
- :' `.t""--.. '<@.`;_  ',@>` ..--""j.' `;
-      `:-.._J '-.-'L__ `-- ' L_..-;'
-        "-.__ ;  .-"  "-.  : __.-"
-            L ' /.------.\ ' J
-             "-.   "--"   .-"
-            __.l"-:_JL_;-";.__
-         .-j/'.;  ;""""  / .'\"-.
-       .' /:`. :  :     /.".'';  `.
-    .-"  / ;`.".  :    ."."   :    "-.
- .+"-.  : :   ".".". ."."      ;-._   \
- ; \  `.; ; .   "."-"."        : : "+. ;
- :  ;   ; ;  .   ."."    ;     : ;  : \:
- ;  :   ; :     / /     /  ,   ;:   ;  :
-: \  ;  :  ;   ; /     :  ,   : ;  /  ::
-;  ; :   ; :  ; ;      ;      ;   :   ;:
-:  :  ;  :  ;. ;      '      : :  ;  : ;
-;\    :   ; : .          ,   ; ;     ; ;
-: `."-;   :  ;      .   ;   :  ;    /  ;
- ;    -:   ; :      ,  ,    ;  : .-"   :
- :\     \  :  ;    ,       : \.-"      :
-  ;`.    \  ; :   .   ,    ;.'_..--  / ;
-  :  "-.  "-:  ;     ,    :/."      .'  :
-   \         \ :    :     ;/  __        :
-    \       .-`.\        /t-""  ":-+.   :
-     `.  .-"    `l    __/ /`. :  ; ; \  ;
-       \   .-" .-"-.-"  .' .'j \  /   ;/
-        \ / .-"   /.     .'.' ;_:'    ;
-         :-""-.`./-.'     /    `.___.'
-               \ `t  ._  /
-                "-.t-._:'}%<<<
-\AddAnimal{yoda-head}%>>>
-{   \
-     \             ____
-      \         _.' :  `._
-            .-.'`.  ;   .'`.-.
-   __      / : ___\ ;  /___ ; \      __
- ,'_ ""--.:__;".-.";: :".-.":__;.--"" _`,
- :' `.t""--.. '<@.`;_  ',@>` ..--""j.' `;
-      `:-.._J '-.-'L__ `-- ' L_..-;'
-        "-.__ ;  .-"  "-.  : __.-"
-            L ' /.------.\ ' J
-             "-.   "--"   .-"
-            __.l"-:_JL_;-";.__
-         .-j/'.;  ;""""  / .'\"-.
-       .' /:`. :  :     /.".'';  `.
-    .-"  / ;`.".  :    ."."   :    "-.
- .+"-.  : :   ".".". ."."      ;-._   \}%<<<
-% from https://www.ascii-code.com/ascii-art/movies/star-wars.php
-\AddAnimal{small-yoda}%>>>
-{  \
-    \
-    __.-._
-    '-._"7'
-     /'.-c
-     |  /T
-    _)_/LI}%<<<
-\AddAnimal{r2d2}%>>>
-{  \
-    \ ,-----.
-    ,'_/_|_\_`.
-   /<<::8[O]::>\
-  _|-----------|_
- |  | ====-=- |  |
- |  | -=-==== |  |
- \  | ::::|()||  /
-  | | ....|()|| |
-  | |_________| |
-  | |\_______/| |
- /   \ /   \ /   \
- `---' `---' `---'}%<<<
-\AddAnimal{vader}%>>>
-{  \     _.-'~~~~~~`-._
-    \   /      ||      \
-       /       ||       \
-      |        ||        |
-      | _______||_______ |
-      |/ ----- \/ ----- \|
-     /  (     )  (     )  \
-    / \  ----- () -----  / \
-   /   \      /||\      /   \
-  /     \    /||||\    /     \
- /       \  /||||||\  /       \
-/_        \O========O/        _\
-  `--...__|`-._  _.-'|__...--'
-          |    `'    |}%<<<
-%<<<
-
-\endinput
-% vim: fdm=marker foldmarker=>>>,<<<
+\input{ducksay.animals.tex}
+%% 
+%%
+%% End of file `ducksay.sty'.



More information about the tex-live-commits mailing list