% Copyright 2007--today Alexander Grahn

% This material is subject to the LaTeX Project Public License. See
%   http://mirrors.ctan.org/help/Catalogue/licenses.lppl.html
% for the details of that license.

% Package for creating portable, JavaScript driven animations from sets of
% graphics files or inline graphics (e. g. LaTeX-picture, PSTricks,
% pgf/TikZ, ...)

% Supports LaTeX->dvips->ps2pdf, (Xe)LaTeX->(x)dvipdfmx, LuaLaTeX and
% pdfLaTeX workflows.

\NeedsTeXFormat{LaTeX2e}

\def\@anim@version{2016/02/15}
\ProvidesPackage{animate}
[\@anim@version\space PDF animations from files and inline graphics]

%test for e-TeX
\expandafter\ifx\csname eTeXversion\endcsname\relax
  \PackageError{animate}{%
    Missing support for e-TeX; aborting...%
  }{%
    Use a TeX compiler that supports e-TeX and enable e-TeX %
    in the format.%
  }
\fi

\RequirePackage{keyval}
\RequirePackage{ifthen}
\RequirePackage{ifpdf}
\RequirePackage{ifluatex}
\RequirePackage{ifdraft}
\RequirePackage{calc}
\RequirePackage{atenddvi}%to really get certain \specials into the dvi
\RequirePackage{animfp}
\RequirePackage{graphics}

\newboolean{@anim@powerdot} %to cope with some powerdot oddity
\setboolean{@anim@powerdot}{false}
\@ifclassloaded{powerdot}{\setboolean{@anim@powerdot}{true}}{}%

%driver options (the only package options we process immediately)
\newboolean{@anim@dvips}
\setboolean{@anim@dvips}{false}
\newboolean{@anim@dvipdfmx}
\setboolean{@anim@dvipdfmx}{false}
\ifpdf\else
  \setboolean{@anim@dvips}{true}% default dvi mode
  \setboolean{@anim@dvipdfmx}{false}
  \DeclareOption{dvips}{%
    \setboolean{@anim@dvips}{true}
    \setboolean{@anim@dvipdfmx}{false}
  }
  \DeclareOption{dvipdfmx}{%
    \setboolean{@anim@dvipdfmx}{true}
    \setboolean{@anim@dvips}{false}
    \PassOptionsToPackage{dvipdfmx}{ocgbase}
  }
  \DeclareOption{xetex}{%
    \setboolean{@anim@dvipdfmx}{true}
    \setboolean{@anim@dvips}{false}
    \PassOptionsToPackage{xetex}{ocgbase}
  }
\fi
\newboolean{@anim@xetex}
\setboolean{@anim@xetex}{false}
\expandafter\ifx\csname XeTeXrevision\endcsname\relax\else
  \setboolean{@anim@xetex}{true}
  \setboolean{@anim@dvipdfmx}{true}
  \setboolean{@anim@dvips}{false}
\fi

\DeclareOption*{}\ProcessOptions*\relax %allow anything as an option
%(remaining package options will be processed near end of this file)

\RequirePackage{ocgbase} %OCG generating and configuration macros

\ifpdf
  %test for correct pdfTeX version
  \ifluatex\else
    \ifnum\pdftexversion<120\relax
      \PackageError{animate}{%
        pdfTeX, version >= 1.20, required%
      }{%
        Install a newer version!%
      }
    \fi
  \fi
  %load MP to PDF converter
  \InputIfFileExists{supp-pdf.mkii}{}{%
  \InputIfFileExists{supp-pdf}{}{%
    \PackageWarningNoLine{animate}{%
      Neither of the files `supp-pdf.mkii' and `supp-pdf.tex',%
      \MessageBreak%
      which are part of ConTeXt, could be found.%
      \MessageBreak%
      Therefore, MetaPost generated PS files cannot%
      \MessageBreak%
      be embedded using pdfTeX%
    }
  }}
\else
  \if@anim@dvipdfmx\else % dvips
    %if geometry package is loaded, execute `\geometry{dvips}' right before
    %  `\begin{document}'; not sure whether needed at all any more
    \let\@anim@document\document
    \def\document{%
      \endgroup%
      \@ifpackageloaded{geometry}{\geometry{dvips}}{}%
      \begingroup%
      \@anim@document%
    }
    %define `?pdfmark' operator as in file hdvips.def from package `hyperref'
    \AtBeginDvi{%
      \expandafter\ifx\csname pdfmark\endcsname\relax%
        \special{!
          systemdict /pdfmark known%
          {%
            userdict /?pdfmark systemdict /exec get put%
          }{%
            userdict /?pdfmark systemdict /pop get put
            userdict /pdfmark systemdict /cleartomark get put%
          }%
          ifelse%
        }%
      \fi%
    }
    \AtEndDvi{\special{ps:\@anim@gsoldwarning}}%
  \fi
\fi

\begingroup
\catcode`\_=13 \let_\space
\xdef\@anim@dpiwarning{%
  {Resolution 1200 gt VResolution 1200 gt or product (Ghostscript)
  search {pop pop pop true}{pop false}ifelse and {%
  (\string\n%
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\string\n%
   @@____Warning:_DVI_resolution_greater_than_1200_dpi!_____@@\string\n%
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\string\n%
   @@_______________________________________________________@@\string\n%
   @@_Animation_frames_may_be_poorly_scaled,_clipped_or_____@@\string\n%
   @@_invisible.____________________________________________@@\string\n%
   @@_______________________________________________________@@\string\n%
   @@_Dvips_should_be_called_either_without_option_`-Ppdf':_@@\string\n%
   @@_______________________________________________________@@\string\n%
   @@___dvips_\jobname\string\n
   @@_______________________________________________________@@\string\n%
   @@_or_with_a_different_resolution_setting:_______________@@\string\n%
   @@_______________________________________________________@@\string\n%
   @@___dvips_-Ppdf_-D1200_\jobname\string\n
   @@_______________________________________________________@@\string\n%
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\string\n)
   print} if} ?pdfmark
}
\xdef\@anim@gsoldwarning{%
  {product (Ghostscript) search {pop pop pop true}{pop false}ifelse
   revision 915 lt and {%
  (\string\n%
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\string\n%
   @@____________Warning:_Ghostscript_too_old!______________@@\string\n%
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\string\n%
   @@_______________________________________________________@@\string\n%
   @@_Ghostscript_version_>=_9.15_required._________________@@\string\n%
   @@_Otherwise,_animations_will_not_work.__________________@@\string\n%
   @@_______________________________________________________@@\string\n%
   @@_Get_current_version_from______________________________@@\string\n%
   @@_http://www.ghostscript.com/download___________________@@\string\n%
   @@_______________________________________________________@@\string\n%
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\string\n)
   print} if} ?pdfmark
}
\endgroup

%\pdfmdfivesum is used for hashing object references of embedded files based
%on their MD5 digest (in order to avoid multiple inclusion); if it is not
%available, hashing will be based on the file name
\ifluatex
  \RequirePackage{pdftexcmds}
  \let\@anim@pdfmdfivesum\pdf@filemdfivesum
\else
  \ifcsname pdfmdfivesum\endcsname
    \def\@anim@pdfmdfivesum#1{\pdfmdfivesum file {#1}}
  \else
    \def\@anim@pdfmdfivesum#1{#1}
  \fi
\fi

%creating and using global definitions
\def\@anim@newkey#1#2{{\expandafter\xdef\csname#1\endcsname{#2}}}
\def\@anim@getkeyval#1{\ifcsname#1\endcsname\csname#1\endcsname\fi}

\def\@animate@rerunwarn{%
  \ifcsname @anim@rerunwarned\endcsname\else%
    \gdef\@anim@rerunwarned{}%
      \PackageWarningNoLine{animate}{%
      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak
      @@ Rerun to get internal references right! @@\MessageBreak
      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}%
  \fi%
}

%macro for writing global defs to external *.aux file
\def\@anim@keytoaux#1#2{%
  \@bsphack\protected@write\@mainaux{}{%
    \string\@anim@newkey{#1}{#2}%
  }\@esphack%
  \ifthenelse{\equal{\@anim@getkeyval{#1}}{#2}}{}{%
    \AtEndDocument{\@animate@rerunwarn}}%
}

\let\AtEndDvi@CheckImpl@Orig\AtEndDvi@CheckImpl%
\def\AtEndDvi@CheckImpl{%
  \AtEndDvi@CheckImpl@Orig%
  \@ifundefined{AtEndDvi@LastPage}{%
    \@animate@rerunwarn%
  }{%
    \ifnum\AtEndDvi@LastPage=\value{abspage}\else%
      \@animate@rerunwarn%
    \fi%
  }%
}

%missing package error message
\newcommand{\@anim@missing}[2][]{%
  \ifthenelse{\equal{#1}{}}{%
    \def\@anim@pkgopt{}%
  }{%
    \def\@anim@pkgopt{[#1]}%
  }%
  \PackageError{animate}{%
    Package `#2' has not been loaded yet.\MessageBreak%
    Put the line\MessageBreak%
    `\protect\usepackage\@anim@pkgopt{#2}'\MessageBreak%
    to the preamble of your document%
  }{}%
}

\newboolean{@anim@grxloaded}
\setboolean{@anim@grxloaded}{false}
\newboolean{@anim@pgfloaded}
\setboolean{@anim@pgfloaded}{false}
\AtBeginDocument{%
  \@ifpackageloaded{graphicx}{%
    \setboolean{@anim@grxloaded}{true}%
  }{}%
  \@ifpackageloaded{pgf}{%
    \setboolean{@anim@pgfloaded}{true}%
  }{}%
}

%macros for adding Appearances name tree / AcroForm dicts to PDF Catalog
\def\@anim@appearances{}
\ifdefined\@anim@fields\else\def\@anim@fields{}\fi %takes Field object refs
\ifpdf
  %Appearance name tree
  \AtEndDvi{%
    \ifx\empty\@anim@appearances\empty\else%
      \immediate\pdfobj{[\@anim@appearances]}%
      \pdfnames{%
        /AP <</Names \the\pdflastobj\space 0 R>>%
      }%
    \fi%
  }%
  %AcroForm dict
  \ifdefined\Acro@Form@added\else%
    \AtEndDvi{%
      \ifx\empty\@anim@fields\empty\else%
        \immediate\pdfobj{[\@anim@fields]}%
        \pdfcatalog{%
          /AcroForm <</Fields \the\pdflastobj\space 0 R /NeedAppearances false>>%
        }%
      \fi%
    }%
    \gdef\Acro@Form@added{}%
  \fi%
\else
  %counts inserted widget annots
  \newcount\@anim@fieldnum\@anim@fieldnum=\z@
  \if@anim@dvipdfmx
    \AtEndDvi{%
      \ifx\empty\@anim@appearances\empty\else%
        \special{pdf:obj @anim@appearances []}%
        \special{pdf:put @anim@appearances \@anim@appearances}%
        \special{pdf:put @names <</AP <</Names @anim@appearances>>>>}%
      \fi%
    }%
    \ifdefined\Acro@Form@added\else%
      \AtEndDvi{%
        \ifx\empty\@anim@fields\empty\else%
          %array which takes refs to all widget annotations
          \special{pdf:obj @anim@fields []}%
          \special{pdf:put @anim@fields \@anim@fields}%
          \special{pdf:put @catalog <<%
            /AcroForm <</Fields @anim@fields /NeedAppearances false>>>>}%
        \fi%
      }%
      \gdef\Acro@Form@added{}%
    \fi%
  \else
    \AtEndDvi{%
      \ifx\empty\@anim@appearances\empty\else%
        \special{ps:
          mark /_objdef {@anim@appearances} /type/array /OBJ pdfmark
          mark {@anim@appearances} 0 [\@anim@appearances] /PUTINTERVAL pdfmark
          mark {Catalog} <<%
            /Names <</AP <</Names {@anim@appearances}>> >>
          >> /PUT pdfmark
        }%
      \fi%
    }%
    \ifdefined\Acro@Form@added\else%
      \AtEndDvi{%
        \ifx\empty\@anim@fields\empty\else%
          \special{ps:
            mark /_objdef {@anim@fields} /type/array /OBJ pdfmark
            mark {@anim@fields} 0 [\@anim@fields] /PUTINTERVAL pdfmark
            mark {Catalog} <<%
              /AcroForm <</Fields {@anim@fields} /NeedAppearances false>>
            >> /PUT pdfmark
          }%
        \fi%
      }%
      \gdef\Acro@Form@added{}%
    \fi%
  \fi
\fi

% true if any of `autoplay' or `autoresume' options is set
\newboolean{@anim@autoplayorresume}
% true if any of `controls' or `palindrome' or `label' options is set
\newboolean{@anim@morejs}
\newboolean{@anim@timeline} %true if `timeline' option is set
\newboolean{@anim@multipage} % multipage document?

\newbox\@anim@box %stores animation frames
\newbox\@anim@measbox % for measuring purposes
\newdimen\@anim@tmpdima %length registers for occasional use
\newdimen\@anim@tmpdimb

%tests whether file is already known (and embedded), if so it returns identifier
%of xobj, otherwise returns `!'
\def\@anim@fileknown#1#2{%#1 file name, #2 page No. (multipage files)
  %identify file by md5sum
  \ifcsname file:\@anim@pdfmdfivesum{#1}.#2\endcsname%
    \@anim@getkeyval{file:\@anim@pdfmdfivesum{#1}.#2}\else!\fi%
}
\def\@anim@makefileknown#1#2#3{%
  %#1 file name, #2 page No. (multipage files), #3 Form XObj ID
  \@anim@newkey{file:\@anim@pdfmdfivesum{#1}.#2}{#3}%
}
%retrieve nat. dimensions from XObjects
\def\@anim@xobjnatwd#1{% #1 Form XObj ID
  \@anim@getkeyval{natwidth:#1}\p@%
}
\def\@anim@xobjnatht#1{% #1 Form XObj ID
  \@anim@getkeyval{natheight:#1}\p@%
}
\def\@anim@xobjnatdp#1{% #1 Form XObj ID
  \@anim@getkeyval{natdepth:#1}\p@%
}
\def\@anim@xobjnatdims#1#2#3#4{% Form XObj ID, wd, ht, dp
  \@anim@newkey{natwidth:#1}{#2}%
  \@anim@newkey{natheight:#1}{#3}%
  \@anim@newkey{natdepth:#1}{#4}%
}

%helper macro that typesets graphics file into savebox
\ifpdf
  \def\@anim@filebox#1#2{% #1 filename, #2 page No. for multipage files
    \ifx\@anim@gropts\@empty%
      \def\@anim@mps{.mps}%
      \ifx\@anim@ext\@anim@mps%
        \global\setbox\@anim@box=\hbox{\convertMPtoPDF{#1}{1}{1}}%
      \else%
        \pdfximage page #2 {#1}%
        \global\setbox\@anim@box=\hbox{\pdfrefximage\pdflastximage}%
      \fi%
    \else%
      \edef\@anim@curfile{[clip\@anim@gropts,page=#2]{#1}}%
      \global\setbox\@anim@box=\hbox{%
        \expandafter\includegraphics\@anim@curfile}%
    \fi%
  }
\else
  \if@anim@xetex
    \def\@anim@filebox#1#2{%
      \edef\@anim@curfile{[clip\@anim@gropts,page=#2]{#1}}%
      \global\setbox\@anim@box=\hbox{%
        \expandafter\includegraphics\@anim@curfile}%
    }
  \else
    \def\@anim@filebox#1#2{% #2 ignored
      \edef\@anim@curfile{[clip\@anim@gropts]{#1}}%
      \global\setbox\@anim@box=\hbox{%
        \expandafter\includegraphics\@anim@curfile}%
    }
  \fi
\fi

\def\@anim@checkboxsize#1#2{% #1: box number, #2: file
  \ifdim\wd#1=\z@%
    \PackageError{animate}{%
      Graphics to be used for first frame%
      \MessageBreak must not have zero width%
    }{%
      Check content of file #2%
    }%
  \fi%
  \ifdim\ht#1=\z@\ifdim\dp#1=\z@%
    \PackageError{animate}{%
      Graphics to be used for first frame%
      \MessageBreak must not have zero height%
    }{%
      Check content of file #2%
    }%
  \fi\fi%
}

%create Form XObject from graphics file
\def\@anim@ximage#1#2#3#4{%#1:@anim@num, #2:@anim@curframe@zb, #3:filename,
  %#4: page number of multipage file
  \ifthenelse{\equal{\@anim@fileknown{#3}{#4.\@anim@gropts}}{!}}{%
    \@anim@filebox{#3}{#4}% store file in a box
    \@anim@xinline{#1}{#2}{\@anim@box}{!}% delegate Form XObject creation
    \ifx\@anim@gropts\@empty\if@anim@multipage\message{<#4>}\fi\fi%
    \@anim@makefileknown{#3}{#4.\@anim@gropts}{\@anim@@lastxform}%
  }{% file known, re-use existing form xobject
    \setbox\@anim@box=%
      \hbox to \@anim@xobjnatwd{\@anim@fileknown{#3}{#4.\@anim@gropts}}{%
        \vrule width \z@
          height \@anim@xobjnatht{\@anim@fileknown{#3}{#4.\@anim@gropts}}
          depth \@anim@xobjnatdp{\@anim@fileknown{#3}{#4.\@anim@gropts}}%
          \hss%
      }%
    \@anim@xinline{#1}{#2}{%
      \@anim@box}{\@anim@fileknown{#3}{#4.\@anim@gropts}}%
  }%
}

%low level operations (driver level)
\ifpdf
  \def\@anim@dictobj#1{%
    \immediate\pdfobj{<<#1>>}%
    \xdef\@anim@lastobj{\the\pdflastobj\space 0 R}%
  }

  \def\@anim@streamobj#1#2{% #1: attrs, #2 content
    \immediate\pdfobj stream attr {#1}{#2}%
    \xdef\@anim@lastobj{\the\pdflastobj\space 0 R}%
  }

  \def\@anim@refobj#1{#1 0 R}

  \def\@anim@xform#1#2#3{%#1: not used, #2: not used, #3 boxnum
    \immediate\pdfxform resources {\the\pdfpageresources}#3%
    \xdef\@anim@lastxform{\the\pdflastxform}%
  }

  \def\@anim@refxform#1{% #1: xform obj ID
    \rlap{\vbox to \z@{\vss\pdfrefxform#1}}%
  }

  \def\@anim@pdfannot#1#2#3#4{%width, height, depth, dict
    \pdfannot width #1\p@ height #2\p@ depth #3\p@ {%
      #4%
    }%
    %since all annots are Widgets
    \xdef\@anim@fields{\@anim@fields\the\pdflastannot\space 0 R\space}%
  }

\else

  \newcount\@anim@objnum
  \if@anim@dvipdfmx
    \def\@anim@dictobj#1{%
      \special{pdf:obj @anm@obj\the\@anim@objnum <<#1>>}%
      \xdef\@anim@lastobj{@anm@obj\the\@anim@objnum}%
      \global\advance\@anim@objnum by \@ne%
    }

    \def\@anim@streamobj#1#2{% #1 attrs, #2 content
      \special{pdf:stream @anm@obj\the\@anim@objnum\space (#2) <<#1>>}%
      \xdef\@anim@lastobj{@anm@obj\the\@anim@objnum}%
      \global\advance\@anim@objnum by \@ne%
    }

    \def\@anim@refobj#1{#1}

    \def\@anim@xform#1#2#3{%#1 add. pgf resources ? 1:0, #2 not used, #3 boxnum
      \special{pdf:bxobj @anm@obj\the\@anim@objnum\space width \strip@pt\wd#3pt
        height \strip@pt\ht#3pt depth \strip@pt\dp#3pt}%
      \rlap{\vbox to \z@{\vss\box#3}}%
      \ifx1#1%
        \ifthenelse{\boolean{@anim@pgfloaded}}{%
          \def\@anim@resources{}%
          \ifthenelse{\boolean{pgf@sys@pdf@extgs@exists}}{%
            \def\@anim@resources{/ExtGState @pgfextgs}}{}%
          \ifthenelse{\boolean{pgf@sys@pdf@patterns@exists}}{%
            \edef\@anim@resources{\@anim@resources/Pattern @pgfpatterns}}{}%
          \ifthenelse{\boolean{pgf@sys@pdf@colorspaces@exists}}{%
            \edef\@anim@resources{%
              \@anim@resources/ColorSpace @pgfcolorspaces}}{}%
          \ifthenelse{%
            \boolean{pgf@sys@pdf@extgs@exists}%
            \OR\boolean{pgf@sys@pdf@patterns@exists}%
            \OR\boolean{pgf@sys@pdf@colorspaces@exists}%
          }{%
            \special{pdf:put @resources <<\@anim@resources>>}%
          }{}%
        }{}%
      \fi%
      \special{pdf:exobj}%
      \xdef\@anim@lastxform{@anm@obj\the\@anim@objnum}%
      \global\advance\@anim@objnum by \@ne%
    }
    \def\@anim@refxform#1{\special{pdf:uxobj #1}}% #1: xform obj ID

    \def\@anim@pdfannot#1#2#3#4{%width, height, depth, dict
      \special{pdf:annot @anm@obj\the\@anim@objnum\space
        width #1pt height #2pt
        depth #3pt <<%
          #4%
        >>}%
      \xdef\@anim@fields{\@anim@fields @anm@obj\the\@anim@objnum\space}%
      \global\advance\@anim@objnum by \@ne%
    }

  \else % dvips
    \def\@anim@dictobj#1{%
      \special{ps:
        mark /_objdef {@anm@obj\the\@anim@objnum} /type/dict /OBJ pdfmark
        mark {@anm@obj\the\@anim@objnum} <<#1>> /PUT pdfmark
      }%
      \xdef\@anim@lastobj{{@anm@obj\the\@anim@objnum}}%
      \global\advance\@anim@objnum by \@ne%
    }

    \def\@anim@streamobj#1#2{%
      \special{ps::[nobreak] %don't break long (strings) at embedded spaces
        mark /_objdef {@anm@obj\the\@anim@objnum} /type/stream /OBJ pdfmark
        mark {@anm@obj\the\@anim@objnum} (#2) /PUT pdfmark
        mark {@anm@obj\the\@anim@objnum} <<#1>> /PUT pdfmark
      }%
      \xdef\@anim@lastobj{{@anm@obj\the\@anim@objnum}}%
      \global\advance\@anim@objnum by \@ne%
    }

    \def\@anim@refobj#1{#1}

    \def\@anim@xform#1#2#3{%#1 not used, #2 used as appearance ? 1:0, #3 boxnum
      \ifnum\@anim@method=\z@\relax% icon based && dvips kill links in document
        \ifdefined\hypersetup%
          \ifdefined\@anim@icondvipswarned\else%
            \AtEndDocument{%
              \PackageWarningNoLine{animate}{\@anim@icondvipswarning}%
            }%
            \gdef\@anim@icondvipswarned{}%
          \fi%
        \fi%
      \fi%
      \ifnum\@anim@method<\tw@\relax% icon based && widget based
        \ifdefined\@anim@@dpiwarning\else%
          %determine DVI resolution and output warning message if too high
          \AtEndDvi{\special{ps:\@anim@dpiwarning}}%
          \gdef\@anim@@dpiwarning{}%
        \fi%
      \fi%
      \begingroup%
        \setlength{\unitlength}{1pt}%
        \begin{picture}(0,0)%
        %mark BBox of the graphics
        \put(0,-\strip@pt\dp#3){%
          \special{ps:
            currentpoint /frame@lly exch def /frame@llx exch def
          }%
        }%
        \put(\strip@pt\wd#3,\strip@pt\ht#3){%
          \special{ps:
            currentpoint /frame@ury exch def /frame@urx exch def
          }%
        }%
        %define some length values in current PS coordinate units
        \put(0,0){%
          \special{ps:
            currentpoint /origin@y exch def /origin@x exch def
          }%
        }%
        \put(72.27,72.27){%
          \special{ps:
            currentpoint origin@y exch sub /one@inch@y exch def
            origin@x sub /one@inch@x exch def
          }%
        }%
        \end{picture}%
      \endgroup%
      \@anim@newkey{origin:{@anm@obj\the\@anim@objnum}}{origin@\the\@anim@objnum}%
      \special{ps:
        gsave
        %keep a record of lower left corner coordinates
        true setglobal globaldict
        /origin@\the\@anim@objnum [currentpoint] cvx put false setglobal
        %translate graphics to upper left page corner
        \if@anim@powerdot\else%
        {%
          frame@llx neg frame@ury neg translate
          one@inch@x DVImag div neg one@inch@y DVImag div neg translate
        }?pdfmark
        \fi%
        %distill graphics into XObject
        mark
          /_objdef {@anm@obj\the\@anim@objnum}
          /BBox [frame@llx frame@lly frame@urx frame@ury]
        /BP pdfmark
        \ifx1#2% operations needed if used as annotation appearance
        {%
          isls{%landscape mode (powerdot, geometry /w landscape option)
            /frame@dxdy {%
              frame@urx frame@llx sub abs
              frame@ury frame@lly sub abs div%
            } bind def
            /frame@dydx {1 frame@dxdy div} bind def
            /frame@cx {frame@urx frame@llx add 2 div} bind def
            /frame@cy {frame@ury frame@lly add 2 div} bind def
            % graphics needs to be rescaled for some reason ...
            [frame@dxdy 0 0 frame@dydx 1 frame@dxdy sub frame@cx mul
              1 frame@dydx sub frame@cy mul] concat
            %... rotated by 270 degrees ...
            [0 -1 1 0 frame@cx frame@cy sub frame@cx frame@cy add] concat
            %... and flipped around vertical axis
            [-1 0 0 1 frame@llx frame@urx add 0] concat%
          }{% flip around horizontal axis in portrait mode
            [1 0 0 -1 0 frame@lly frame@ury add] concat%
          }ifelse
        }?pdfmark
        \fi%
      }%
      \rlap{\vbox to \z@{\vss\box#3}}%
      \special{ps:
        mark /EP pdfmark
        grestore%
      }%
      \xdef\@anim@lastxform{{@anm@obj\the\@anim@objnum}}%
      \global\advance\@anim@objnum by \@ne%
    }
    \def\@anim@refxform#1{% #1: xform obj ID
      \special{ps:
        gsave
        currentpoint pop \@anim@getkeyval{origin:#1} pop sub
        currentpoint exch pop \@anim@getkeyval{origin:#1} exch pop sub translate
        mark #1 /SP pdfmark
        grestore
      }%
    }

    \def\@anim@pdfannot#1#2#3#4{%width, height, depth, dict
      \begingroup%
        \setlength{\unitlength}{1pt}%
        \begin{picture}(0,0)% mark annotation rectangle
          \put(0,-#3){%
          \special{ps:
            currentpoint /wid@lly exch def /wid@llx exch def
          }%
        }%
        \put(#1,#2){%
          \special{ps:
            currentpoint /wid@ury exch def /wid@urx exch def
          }%
        }%
        \end{picture}%
      \endgroup%
      \special{ps:
        mark
          /_objdef {@anm@obj\the\@anim@objnum}%
          /Rect [wid@llx wid@lly wid@urx wid@ury]%
          #4%
        /ANN pdfmark
      }%
      \xdef\@anim@fields{\@anim@fields{@anm@obj\the\@anim@objnum}\space}%
      \global\advance\@anim@objnum by \@ne%
    }
  \fi
\fi

%creates Form XObject from box contents
\def\@anim@xinline#1#2#3#4{%
  \edef\@anim@curwd{\strip@pt\wd#3}%
  \edef\@anim@curht{\strip@pt\ht#3}%
  \edef\@anim@curdp{\strip@pt\dp#3}%
  \ifnum#2=\z@\relax%
    %nat. dims of zeroth frame
    \xdef\@anim@zframewd{\@anim@curwd}%
    \xdef\@anim@zframeht{\@anim@curht}%
    \xdef\@anim@zframedp{\@anim@curdp}%
    %determine size of animation widget
    \setbox\@anim@measbox=\hbox to \wd#3{%
      \vrule width \z@ height \ht#3 depth \dp#3\hss}%
    \@anim@scale{\@anim@measbox}%
  \else%
    \def\@anim@needresize{0}%
    \ifdim\wd#3=\@anim@zframewd\p@\else\def\@anim@needresize{1}\fi%
    \ifdim\ht#3=\@anim@zframeht\p@\else\def\@anim@needresize{1}\fi%
    \ifdim\dp#3=\@anim@zframedp\p@\else\def\@anim@needresize{1}\fi%
  \fi%
  %create form xobject from box argument
  \ifthenelse{\equal{#4}{!}}{% %%%% new graphics %%%%
    %put graphics into XObject
    \@anim@xform{1}{0}{#3}%
    \xdef\@anim@@lastxform{\@anim@lastxform}%
    \@anim@xobjnatdims{\@anim@lastxform}{%
      \@anim@curwd}{\@anim@curht}{\@anim@curdp}%
  }{%
    \xdef\@anim@lastxform{#4}%
  }%
  \ifnum#2>\z@\relax%
    %adjust size of current frame to zeroth frame's dims, if necessary
    \ifnum\@anim@needresize>\z@\relax%
      \global\setbox#3=\hbox to \@anim@curwd\p@{%
        \vrule width \z@ height \@anim@curht\p@ depth \@anim@curdp\p@%
        \@anim@refxform{\@anim@lastxform}%
        \hss%
      }%
      \global\setbox#3=\hbox{%
        \raisebox{-\@anim@zframedp\p@}{%
          \resizebox*{\@anim@zframewd\p@}{%
            \dimexpr\@anim@zframeht\p@+\@anim@zframedp\p@\relax%
          }{\raisebox{\depth}{\box#3}}%
        }%
      }%
      \@anim@xform{0}{0}{#3}%
    \fi%
  \fi%
  %keep a record of XObject number
  \@anim@newkey{img@#2}{\@anim@lastxform}%
  \if@anim@timeline\else%
    \@anim@newkey{frmcontent@#2}{%
      \@anim@refxform{\@anim@getkeyval{img@#2}}%
    }%
    \@anim@makeframe{#1}{#2}%
  \fi%
}

%creates OCG (ocgbase.sty)
\def\@anim@newocg#1#2{%#1:@anim@num, #2:@anim@curframe@zb
  \ocgbase@new@ocg{#1.#2}{}{1}%
  \xdef\@anim@curocg{\ocgbase@last@ocg}%
}

%inserts one animation frame into the output acc. to
% \ifcase\@anim@method as
% 0: Form XObject (not referenced in the page content stream)
% 1: non-interactive Widget annotation
% 2: referenced Form XObject in the page content, tagged as OC
% animation
\def\@anim@makeframe#1#2{%
  %container box
  \global\setbox\@anim@box=\hbox to \@anim@zframewd\p@{%
    \vrule width \z@ height \@anim@zframeht\p@ depth \@anim@zframedp\p@%
    \@anim@getkeyval{frmcontent@#2}%
    \hss%
  }%
  \ifcase\@anim@method% icon based
    \@anim@xform{0}{1}{\@anim@box}%
    %initial visibility
    \ifnum\@anim@poster>\@anim@mtwo\relax% insert poster frame
      \ifnum#2=\@anim@poster\relax%
        \edef\@anim@posterap{\@anim@lastxform}%
      \else%
        \ifnum\@anim@poster=\@anim@mone\relax% use last frame as poster
          \edef\@anim@posterap{\@anim@lastxform}%
        \fi%
      \fi%
    \fi%
    %build appearance name tree
    \xdef\@anim@appearances{%
      \@anim@appearances
      (\@anim@pad{1234}{#1}.\@anim@pad{1234}{#2})
      \@anim@refobj{\@anim@lastxform}%
    }%
  \or% widget based
    %initial visibility
    \def\@anim@annotflag{/F 2}% default: hidden
    \ifnum\@anim@poster>\@anim@mtwo\relax% insert poster frame
      \ifnum#2=\@anim@poster\relax%
        \def\@anim@annotflag{/F 4}% not hidden + print (4)
      \else%
        \ifnum\@anim@poster=\@anim@mone\relax% use last frame as poster
          \ifthenelse{%
            \NOT\equal{\@anim@getkeyval{a#1.poster}}{}\AND%
            #2=\@anim@getkeyval{a#1.poster}%
          }{%
            \def\@anim@annotflag{/F 4}%
          }{}%
        \fi%
      \fi%
    \fi%
    %frame insertion
    \@anim@xform{0}{1}{\@anim@box}%
    \@anim@pdfannot{\@anim@animwidth}{\@anim@animheight}{\@anim@animdepth}{%
      /Subtype/Widget%
      \@anim@annotflag%
      /FT/Btn/Ff 65537%
      /BS <</W 0>>%
      /AP <</N \@anim@refobj{\@anim@lastxform}>>%
      /MK <</TP 1/I \@anim@refobj{\@anim@lastxform}/IF<</S/A/FB true>>>>%
      /T (#1.#2)%
      \ifdefined\ocgxii@insert@OC\ocgxii@insert@OC\fi%
    }%
  \or% ocg based
    \@anim@newocg{#1}{#2}%
    %initial visibility
    \ifnum\@anim@poster=\@anim@mone\relax% use last frame as poster
      \ifthenelse{%
        \NOT\equal{\@anim@getkeyval{a#1.poster}}{}\AND%
        #2=\@anim@getkeyval{a#1.poster}%
      }{}{%
        \ocgbase@add@to@off@list{\@anim@curocg}%
      }%
    \else%
      \ifnum#2=\@anim@poster\relax\else%
        \ocgbase@add@to@off@list{\@anim@curocg}%
      \fi%
    \fi%
    \def\@anim@needresize{0}%
    \ifdim\@anim@animwidth\p@=\@anim@zframewd\p@\else%
      \def\@anim@needresize{1}\fi%
    \ifdim\@anim@animheight\p@=\@anim@zframeht\p@\else%
      \def\@anim@needresize{1}\fi%
    \ifdim\@anim@animdepth\p@=\@anim@zframedp\p@\else%
      \def\@anim@needresize{1}\fi%
    \ifnum\@anim@needresize>\z@\relax%
      \global\setbox\@anim@box=\hbox{%
        \raisebox{-\@anim@animdepth\p@}{%
          \resizebox*{\@anim@animwidth\p@}{%
            \dimexpr\@anim@animheight\p@+\@anim@animdepth\p@\relax%
          }{\raisebox{\depth}{\box\@anim@box}}%
        }%
      }%
    \fi%
    %frame insertion
    \@anim@xform{0}{0}{\@anim@box}%
    \ocgbase@oc@bdc{\@anim@curocg}%
    \@anim@refxform{\@anim@lastxform}%
    \ocgbase@oc@emc%
  \fi%
}

%create XObjects of all button faces
\if@anim@dvips
  %stroking commands
  \def\@anim@btnend{%
    \@anim@fg\space
    0.5 setlinewidth
    1 setlinecap
    1 setlinejoin
    6.5 1 moveto
    1 1 1 6.5 2 arct
    1 6.5 lineto
    1 14 6.5 14 2 arct
    6.5 14 lineto
    14 14 14 6.5 2 arct
    14 6.5 lineto
    14 1 6.5 1 2 arct
    closepath
    \ifx\empty\@anim@bg\empty\else
      gsave \@anim@bg\space fill grestore
    \fi
    stroke
    %
    1 setlinewidth
    4.5 4.7 moveto
    8.6 7.5 lineto
    4.5 10.3 lineto
    stroke
    0 setlinejoin
    10.0 4.7 moveto
    10.0 10.3 lineto
    stroke
  }
  \def\@anim@btnstep{%
    \@anim@fg\space
    0.5 setlinewidth
    1 setlinecap
    1 setlinejoin
    6.5 1 moveto
    1 1 1 6.5 2 arct
    1 6.5 lineto
    1 14 6.5 14 2 arct
    6.5 14 lineto
    14 14 14 6.5 2 arct
    14 6.5 lineto
    14 1 6.5 1 2 arct
    closepath
    \ifx\empty\@anim@bg\empty\else
      gsave \@anim@bg\space fill grestore
    \fi
    stroke
    %
    1 setlinewidth
    5.5 4.7 moveto
    9.6 7.5 lineto
    5.5 10.3 lineto
    stroke
  }
  \def\@anim@btnplay{%
    \@anim@fg\space
    0.5 setlinewidth
    1 setlinecap
    1 setlinejoin
    0 1 moveto
    14 1 14 6.5 2 arct
    14 6.5 lineto
    14 14 1 14 2 arct
    0 14 lineto
    \ifx\empty\@anim@bg\empty\else
      gsave closepath \@anim@bg\space fill grestore
    \fi
    stroke
    0.1 setlinewidth
    0 14 moveto
    0 1 lineto
    stroke
    %
    1 setlinewidth
    5 4 moveto
    5 11 lineto
    10 7.5 lineto
    closepath
    stroke
  }
  \def\@anim@btnpause{%
    \@anim@fg\space
    0.5 setlinewidth
    1 setlinecap
    1 setlinejoin
    0 1 moveto
    14 1 14 6.5 2 arct
    14 6.5 lineto
    14 14 1 14 2 arct
    0 14 lineto
    \ifx\empty\@anim@bg\empty\else
      gsave closepath \@anim@bg\space fill grestore
    \fi
    stroke
    %
    0 setlinecap
    2 setlinewidth
    2.2 4 moveto
    2.2 11 lineto
    stroke
  }
  \def\@anim@btnminus{%
    \@anim@fg\space
    0.5 setlinewidth
    1 setlinecap
    1 setlinejoin
    6.5 1 moveto
    1 1 1 6.5 2 arct
    1 6.5 lineto
    1 14 6.5 14 2 arct
    6.5 14 lineto
    14 14 14 6.5 2 arct
    14 6.5 lineto
    14 1 6.5 1 2 arct
    closepath
    \ifx\empty\@anim@bg\empty\else
      gsave \@anim@bg\space fill grestore
    \fi
    stroke
    %
    1.0 setlinewidth
    0 setlinecap
    4.7 7.5 moveto
    10.3 7.5 lineto
    stroke
  }
  \def\@anim@btnplus{%
    \@anim@fg\space
    0.5 setlinewidth
    1 setlinecap
    1 setlinejoin
    6.5 1 moveto
    1 1 1 6.5 2 arct
    1 6.5 lineto
    1 14 6.5 14 2 arct
    6.5 14 lineto
    14 14 14 6.5 2 arct
    14 6.5 lineto
    14 1 6.5 1 2 arct
    closepath
    \ifx\empty\@anim@bg\empty\else
      gsave \@anim@bg\space fill grestore
    \fi
    stroke
    %
    1.0 setlinewidth
    0 setlinecap
    4.7 7.5 moveto
    10.3 7.5 lineto
    7.5 4.7  moveto
    7.5 10.3 lineto
    stroke
  }
  \def\@anim@btnreset{%
    \@anim@fg\space
    0.5 setlinewidth
    1 setlinecap
    1 setlinejoin
    6.5 1 moveto
    1 1 1 6.5 2 arct
    1 6.5 lineto
    1 14 6.5 14 2 arct
    6.5 14 lineto
    14 14 14 6.5 2 arct
    14 6.5 lineto
    14 1 6.5 1 2 arct
    closepath
    \ifx\empty\@anim@bg\empty\else
      gsave \@anim@bg\space fill grestore
    \fi
    stroke
    %
    1 setlinewidth
    7.5 4.7 moveto
    7.5 10.3 lineto
    stroke
    0 setlinejoin
    3.5 5 moveto
    7 7.5 lineto
    3.5 10 lineto
    closepath
    fill
    11.5 5 moveto
    8 7.5 lineto
    11.5 10 lineto
    closepath
    fill
    1 setlinewidth
    2 setlinecap
    3 7.5 moveto
    3.5 7.5 lineto
    12 7.5 moveto
    11.5 7.5 lineto
    stroke
  }
  \def\@anim@makebuttons#1{% #1: @anim@num
    \@anim@xbutton{EndLeft}{[-1 0 0 1 15 0] concat \@anim@btnend}{#1}%
    \@anim@xbutton{EndRight}{\@anim@btnend}{#1}%
    \@anim@xbutton{Minus}{\@anim@btnminus}{#1}%
    \@anim@xbutton{PauseLeft}{[-1 0 0 1 15 0] concat \@anim@btnpause}{#1}%
    \@anim@xbutton{PauseRight}{\@anim@btnpause}{#1}%
    \@anim@xbutton{PlayLeft}{[-1 0 0 1 15 0] concat \@anim@btnplay}{#1}%
    \@anim@xbutton{PlayRight}{\@anim@btnplay}{#1}%
    \@anim@xbutton{Plus}{\@anim@btnplus}{#1}%
    \@anim@xbutton{Reset}{\@anim@btnreset}{#1}%
    \@anim@xbutton{StepLeft}{[-1 0 0 1 15 0] concat \@anim@btnstep}{#1}%
    \@anim@xbutton{StepRight}{\@anim@btnstep}{#1}%
  }
  \def\@anim@xbutton#1#2#3{% #1: name; #2: stroking commands, #3 @anim@num
    \special{ps:
      gsave [1 0 0 1 0 0] setmatrix
      mark
        /_objdef {@anm@obj\the\@anim@objnum}
        /BBox [0 0 15 15]
      /BP pdfmark
      {%
        %landscape mode (powerdot, geometry /w landscape option)
        isls{%
          [0 -1 1 0 0 15] concat % rotate by 270 degrees
          [-1 0 0 1 15 0] concat%  flip around vertical axis
        }if
        #2
      }?pdfmark mark /EP pdfmark
      grestore
    }%
    \xdef\@anim@lastobj{{@anm@obj\the\@anim@objnum}}%
    \global\advance\@anim@objnum by \@ne%
    \@anim@newkey{btn#1:#3}{\@anim@lastobj}%
  }
\else %pdftex/dvipdfmx/xetex
  %stroking commands
  \def\@anim@btnend{%
    5 w
    1 J
    1 j
    \@anim@fg\space
    65 10 m
    30 10 l
    18.957 10 10 18.957 10 30 c
    10 120 l
    10 131.043 18.957 140 30 140 c
    120 140 l
    131.043 140 140 131.043 140 120 c
    140 30 l
    140 18.957 131.043 10 120 10 c
    \ifx\empty\@anim@bg\empty s
    \else\@anim@bg\space b \fi
    %
    10 w
    45 47 m
    86 75 l
    45 103 l
    S
    0 j
    100 47 m
    100 103 l
    S
  }
  \def\@anim@btnstep{%
    5 w
    1 J
    1 j
    \@anim@fg\space
    65 10 m
    30 10 l
    18.957 10 10 18.957 10 30 c
    10 120 l
    10 131.043 18.957 140 30 140 c
    120 140 l
    131.043 140 140 131.043 140 120 c
    140 30 l
    140 18.957 131.043 10 120 10 c
    \ifx\empty\@anim@bg\empty s
    \else\@anim@bg\space b \fi
    %
    10 w
    55 47 m
    96 75 l
    55 103 l
    S
  }
  \def\@anim@btnplay{%
    5 w
    1 J
    1 j
    \@anim@fg\space
    0 10 m
    120 10 l
    131.043 10 140 18.957 140 30 c
    140 120 l
    140 131.043 131.043 140 120 140 c
    0 140 l
    \ifx\empty\@anim@bg\empty S
    \else\@anim@bg\space B \fi
    1 w
    0 140 m
    0 10 l
    S
    %
    10 w
    50 40 m
    50 110 l
    100 75 l
    s
  }
  \def\@anim@btnpause{%
    5 w
    1 J
    1 j
    \@anim@fg\space
    0 10 m
    120 10 l
    131.043 10 140 18.957 140 30 c
    140 120 l
    140 131.043 131.043 140 120 140 c
    0 140 l
    \ifx\empty\@anim@bg\empty S
    \else\@anim@bg\space B \fi
    %
    0 J
    20 w
    22 40 m
    22 110 l
    S
  }
  \def\@anim@btnminus{%
    5 w
    1 J
    1 j
    \@anim@fg\space
    65 10 m
    30 10 l
    18.957 10 10 18.957 10 30 c
    10 120 l
    10 131.043 18.957 140 30 140 c
    120 140 l
    131.043 140 140 131.043 140 120 c
    140 30 l
    140 18.957 131.043 10 120 10 c
    \ifx\empty\@anim@bg\empty s
    \else\@anim@bg\space b \fi
    %
    10 w
    0 J
    47 75 m
    103 75 l
    S
  }
  \def\@anim@btnplus{%
    5 w
    1 J
    1 j
    \@anim@fg\space
    65 10 m
    30 10 l
    18.957 10 10 18.957 10 30 c
    10 120 l
    10 131.043 18.957 140 30 140 c
    120 140 l
    131.043 140 140 131.043 140 120 c
    140 30 l
    140 18.957 131.043 10 120 10 c
    \ifx\empty\@anim@bg\empty s
    \else\@anim@bg\space b \fi
    %
    10 w
    0 J
    47 75 m
    103 75 l
    75 47 m
    75 103 l
    S
  }
  \def\@anim@btnreset{%
    5 w
    1 J
    1 j
    \@anim@fg\space
    65 10 m
    30 10 l
    18.957 10 10 18.957 10 30 c
    10 120 l
    10 131.043 18.957 140 30 140 c
    120 140 l
    131.043 140 140 131.043 140 120 c
    140 30 l
    140 18.957 131.043 10 120 10 c
    \ifx\empty\@anim@bg\empty s
    \else\@anim@bg\space b \fi
    %
    10 w
    75 47 m
    75 103 l
    S
    \@anim@@@fg\space
    35 50 m
    70 75 l
    35 100 l
    f
    115 50 m
    80 75 l
    115 100 l
    f
    2 J
    0 j
    30 75 m
    35 75 l
    120 75 m
    115 75 l
    S
  }
  \def\@anim@makebuttons#1{%
    \@anim@xbutton{EndLeft}{%
      q -0.1 0 0 0.1 15 0 cm
      \@anim@btnend\space Q%
    }{#1}%
    \@anim@xbutton{EndRight}{%
      q 0.1 0 0 0.1 0 0 cm
      \@anim@btnend\space Q%
    }{#1}%
    \@anim@xbutton{Minus}{%
      q 0.1 0 0 0.1 0 0 cm
      \@anim@btnminus\space Q%
    }{#1}%
    \@anim@xbutton{PauseLeft}{%
      q -0.1 0 0 0.1 15 0 cm
      \@anim@btnpause\space Q%
    }{#1}%
    \@anim@xbutton{PauseRight}{%
      q 0.1 0 0 0.1 0 0 cm
      \@anim@btnpause\space Q%
    }{#1}%
    \@anim@xbutton{PlayLeft}{%
      q -0.1 0 0 0.1 15 0 cm
      \@anim@btnplay\space Q%
    }{#1}%
    \@anim@xbutton{PlayRight}{%
      q 0.1 0 0 0.1 0 0 cm
      \@anim@btnplay\space Q%
    }{#1}%
    \@anim@xbutton{Plus}{%
      q 0.1 0 0 0.1 0 0 cm
      \@anim@btnplus\space Q%
    }{#1}%
    \@anim@xbutton{Reset}{%
      q 0.1 0 0 0.1 0 0 cm
      \@anim@btnreset\space Q%
    }{#1}%
    \@anim@xbutton{StepLeft}{%
      q -0.1 0 0 0.1 15 0 cm
      \@anim@btnstep\space Q%
    }{#1}%
    \@anim@xbutton{StepRight}{%
      q 0.1 0 0 0.1 0 0 cm
      \@anim@btnstep\space Q%
    }{#1}%
  }
  %XObject creation
  \def\@anim@xbutton#1#2#3{% #1 name, #2 stroking commands, #3 @anim@num
    \@anim@streamobj{/Type/XObject/Subtype/Form/BBox [0 0 15 15]}{#2}%
    \@anim@newkey{btn#1:#3}{\@anim@lastobj}%
  }
\fi

%determines file type of the sequence
\def\zap@finalspace#1 \@nil{#1}
\ifpdf
  \def\@anim@getpath#1#2{% #2: empty | user provided file extension
    \ifx\@empty#2\@empty%
      \gdef\@anim@ext{.pdf}% we start with `pdf'
      \IfFileExists{#1\@anim@ext}{}{%
      \gdef\@anim@ext{.mps}%
      \IfFileExists{#1\@anim@ext}{}{%
      \gdef\@anim@ext{.png}%
      \IfFileExists{#1\@anim@ext}{}{%
      \gdef\@anim@ext{.jpg}%
      \IfFileExists{#1\@anim@ext}{}{%
      \gdef\@anim@ext{.jpeg}%
      \IfFileExists{#1\@anim@ext}{}{%
      \gdef\@anim@ext{.jbig2}%
      \IfFileExists{#1\@anim@ext}{}{%
      \gdef\@anim@ext{.jb2}%
      \IfFileExists{#1\@anim@ext}{}{%
      \gdef\@anim@ext{.jp2}%
      \IfFileExists{#1\@anim@ext}{}{%
      \gdef\@anim@ext{.j2k}%
      \IfFileExists{#1\@anim@ext}{}{%
      \gdef\@anim@ext{.jpx}%
      \IfFileExists{#1\@anim@ext}{}{%
        \PackageError{animate}{%
          None of the files\MessageBreak%
          `#1.pdf',\MessageBreak%
          `#1.mps',\MessageBreak%
          `#1.png',\MessageBreak%
          `#1.jpg',\MessageBreak%
          `#1.jpeg',\MessageBreak%
          `#1.jbig2',\MessageBreak%
          `#1.jb2',\MessageBreak%
          `#1.jp2',\MessageBreak%
          `#1.j2k' or\MessageBreak%
          `#1.jpx',\MessageBreak%
          could be found.\MessageBreak%
          Wrong file type? Mis-spelled file name?%
        }{}%
      }}}}}}}}}}%
    \else%
      \gdef\@anim@ext{.#2}%
      \IfFileExists{#1\@anim@ext}{}{%
        \PackageError{animate}{%
          File `#1.#2' could not be found.\MessageBreak%
          Wrong file type? Mis-spelled file name?%
        }{}%
      }%
    \fi%
    \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}%
  }%
\else
  \if@anim@dvipdfmx %XeLaTeX, dvipdfmx
    \def\@anim@getpath#1#2{%
      \ifx\@empty#2\@empty%
        \gdef\@anim@ext{.pdf}% we start with `pdf'
        \IfFileExists{#1\@anim@ext}{}{%
        \gdef\@anim@ext{.mps}%
        \IfFileExists{#1\@anim@ext}{}{%
        \gdef\@anim@ext{.eps}%
        \IfFileExists{#1\@anim@ext}{}{%
        \gdef\@anim@ext{.ps}%
        \IfFileExists{#1\@anim@ext}{}{%
        \gdef\@anim@ext{.png}%
        \IfFileExists{#1\@anim@ext}{}{%
        \gdef\@anim@ext{.jpg}%
        \IfFileExists{#1\@anim@ext}{}{%
        \gdef\@anim@ext{.jpeg}%
        \IfFileExists{#1\@anim@ext}{}{%
        \gdef\@anim@ext{.bmp}%
        \IfFileExists{#1\@anim@ext}{}{%
          \PackageError{animate}{%
            None of the files\MessageBreak%
            `#1.pdf',\MessageBreak%
            `#1.mps',\MessageBreak%
            `#1.eps',\MessageBreak%
            `#1.ps',\MessageBreak%
            `#1.png',\MessageBreak%
            `#1.jpg',\MessageBreak%
            `#1.jpeg' or\MessageBreak%
            `#1.bmp'\MessageBreak%
            could be found.\MessageBreak%
            Wrong file type? Mis-spelled file name?%
          }{}%
        }}}}}}}}%
      \else%
        \gdef\@anim@ext{.#2}%
        \IfFileExists{#1\@anim@ext}{}{%
          \PackageError{animate}{%
            File `#1.#2' could not be found.\MessageBreak%
            Wrong file type? Mis-spelled file name?%
          }{}%
        }%
      \fi%
      \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}%
    }%
  \else %dvips
    \def\@anim@getpath#1#2{%
      \ifx\@empty#2\@empty%
        \gdef\@anim@ext{.eps}% we start with `eps'
        \IfFileExists{#1\@anim@ext}{}{%
        \gdef\@anim@ext{.mps}%
        \IfFileExists{#1\@anim@ext}{}{%
        \gdef\@anim@ext{.ps}%
        \IfFileExists{#1\@anim@ext}{}{%
          \PackageError{animate}{%
            None of the files\MessageBreak%
            `#1.eps',\MessageBreak%
            `#1.mps' or\MessageBreak%
            `#1.ps'\MessageBreak%
            could be found.\MessageBreak%
            Wrong file type? Mis-spelled file name?%
          }{}%
        }}}%
      \else%
        \gdef\@anim@ext{.#2}%
        \IfFileExists{#1\@anim@ext}{}{%
          \PackageError{animate}{%
            File `#1.#2' could not be found.\MessageBreak%
            Wrong file type? Mis-spelled file name?%
          }{}%
        }%
      \fi%
      \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}%
    }%
  \fi
\fi

%counts embedded animations
\newcount\@anim@num\@anim@num=\z@%

%current frame
\newcount\@anim@curframe
\newcount\@anim@curframe@zb %zero based

%draftbox
\def\@anim@draftbox{%
  \begingroup%
  \setlength{\unitlength}{1pt}%
  \vtop{% draw boxes
    \offinterlineskip%
    \hbox{%
      \raisebox{-\@anim@animdepth\p@}{%
        \begin{picture}(\@anim@animwidth,\@anim@animtotalheight)%
          \put(0,0){\framebox(\@anim@animwidth,\@anim@animtotalheight){}}%
        \end{picture}%
      }%
    }%
    \if@anim@controls%
      \setlength{\@anim@tmpdima}{\@anim@btnsize}%
      \vskip 0.1\@anim@tmpdima%
      \hbox to \@anim@animwidth\p@ {%
        \hss%
        \setlength{\@anim@tmpdimb}{2\@anim@tmpdima}%
        \begin{picture}(\strip@pt\@anim@tmpdimb,\strip@pt\@anim@tmpdima)%
          \put(0,0){\line(1,0){\strip@pt\@anim@tmpdimb}}%
          \put(0,\strip@pt\@anim@tmpdima){%
            \line(1,0){\strip@pt\@anim@tmpdimb}%
          }%
          \put(0,0){\line(0,1){\strip@pt\@anim@tmpdima}}%
        \end{picture}%
        \if@anim@step\else%
          \begin{picture}(\strip@pt\@anim@tmpdimb,\strip@pt\@anim@tmpdima)%
            \put(0,0){\line(1,0){\strip@pt\@anim@tmpdimb}}%
            \put(0,\strip@pt\@anim@tmpdima){%
              \line(1,0){\strip@pt\@anim@tmpdimb}%
            }%
          \end{picture}%
        \fi%
        \begin{picture}(\strip@pt\@anim@tmpdimb,\strip@pt\@anim@tmpdima)%
          \put(0,0){\line(1,0){\strip@pt\@anim@tmpdimb}}%
          \put(0,\strip@pt\@anim@tmpdima){%
            \line(1,0){\strip@pt\@anim@tmpdimb}%
          }%
          \put(\strip@pt\@anim@tmpdimb,0){%
            \line(0,1){\strip@pt\@anim@tmpdima}%
          }%
        \end{picture}%
        \if@anim@step\else%
          \hskip 0.3\@anim@tmpdima%
          \setlength{\@anim@tmpdimb}{3\@anim@tmpdima}%
          \begin{picture}(\strip@pt\@anim@tmpdimb,\strip@pt\@anim@tmpdima)%
            \put(0,0){\line(0,1){\strip@pt\@anim@tmpdima}}%
            \put(0,0){\line(1,0){\strip@pt\@anim@tmpdimb}}%
            \put(0,\strip@pt\@anim@tmpdima){%
              \line(1,0){\strip@pt\@anim@tmpdimb}%
            }%
            \put(\strip@pt\@anim@tmpdimb,0){%
              \line(0,1){\strip@pt\@anim@tmpdima}%
            }%
          \end{picture}%
        \fi%
        \hss%
      }%
    \fi%
  }%
  \endgroup%
}

\ifpdf
  %detects multipage PDF and corrects user supplied page range
  \def\@anim@checkmultipage#1#2{% #1: file base name, #2 user provided file ext
    \ifx\@empty#2\@empty%
      \IfFileExists{#1.pdf}{%
        \setboolean{@anim@multipage}{true}%
        \gdef\@anim@ext{.pdf}%
      }{%
        \IfFileExists{#1.jbig2}{%
          \setboolean{@anim@multipage}{true}%
          \gdef\@anim@ext{.jbig2}%
        }{%
          \IfFileExists{#1.jb2}{%
            \setboolean{@anim@multipage}{true}%
            \gdef\@anim@ext{.jb2}%
          }{}%
        }%
      }%
    \else%
      \IfFileExists{#1.#2}{%
        \setboolean{@anim@multipage}{true}%
        \gdef\@anim@ext{.#2}%
      }{}%
    \fi%
    \if@anim@multipage%
      \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}%
      \pdfximage page 1 {\@anim@pathtofile}%
      \@anim@curframe=\pdflastximagepages%
      \advance\@anim@curframe by -\@ne%since \pdfximagepages is 1-based
      \edef\@anim@lastpage{\the\@anim@curframe}%
      \ifx\@anim@first\@empty%
        \gdef\@anim@first{0}%
      \else%
        \ifnum\@anim@first<\z@\relax\gdef\@anim@first{0}\fi%
        \ifnum\@anim@first>\@anim@lastpage\relax%
          \xdef\@anim@first{\@anim@lastpage}%
        \fi%
      \fi%
      \ifx\@anim@last\@empty%
        \xdef\@anim@last{\@anim@lastpage}%
      \else%
        \ifnum\@anim@last<\z@\relax\gdef\@anim@last{0}\fi%
        \ifnum\@anim@last>\@anim@lastpage\relax%
          \xdef\@anim@last{\@anim@lastpage}%
        \fi%
      \fi%
      \@anim@curframe=\@anim@first%
      \advance\@anim@curframe by \@ne%
      \xdef\@anim@first{\the\@anim@curframe}%
      \@anim@curframe=\@anim@last%
      \advance\@anim@curframe by \@ne%
      \xdef\@anim@last{\the\@anim@curframe}%
    \fi%
  }%
\else
  \if@anim@xetex
    \def\@anim@checkmultipage#1#2{%
      \ifx\@empty#2\@empty%
        \IfFileExists{#1.pdf}{%
          \setboolean{@anim@multipage}{true}%
          \gdef\@anim@ext{.pdf}%
        }{}%
      \else%
        \IfFileExists{#1.#2}{%
          \setboolean{@anim@multipage}{true}%
          \gdef\@anim@ext{.#2}%
        }{}%
      \fi%
      \if@anim@multipage%
        \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}%
        \@anim@curframe=\XeTeXpdfpagecount "\@anim@pathtofile"%
        \advance\@anim@curframe by -\@ne%since XeTeXpdfpagecount is 1-based
        \edef\@anim@lastpage{\the\@anim@curframe}%
        \ifx\@anim@first\@empty%
          \gdef\@anim@first{0}%
        \else%
          \ifnum\@anim@first<\z@\relax\gdef\@anim@first{0}\fi%
          \ifnum\@anim@first>\@anim@lastpage\relax%
            \xdef\@anim@first{\@anim@lastpage}%
          \fi%
        \fi%
        \ifx\@anim@last\@empty%
          \xdef\@anim@last{\@anim@lastpage}%
        \else%
          \ifnum\@anim@last<\z@\relax\gdef\@anim@last{0}\fi%
          \ifnum\@anim@last>\@anim@lastpage\relax%
            \xdef\@anim@last{\@anim@lastpage}%
          \fi%
        \fi%
        \@anim@curframe=\@anim@first%
        \advance\@anim@curframe by \@ne%
        \xdef\@anim@first{\the\@anim@curframe}%
        \@anim@curframe=\@anim@last%
        \advance\@anim@curframe by \@ne%
        \xdef\@anim@last{\the\@anim@curframe}%
      \fi%
    }%
  \else
    %no multipage support in dvips and dvipdfmx
    \def\@anim@checkmultipage#1{\setboolean{@anim@multipage}{false}}%
  \fi
\fi

%user command for embedding animation sequence
% #1: options
% #2: frame rate (fps)
% #3: basename of graphics file sequence (without frame number and extension)
% #4: first frame (integer)
% #5: last frame (integer)
\newcommand{\animategraphics}[5][]{%
  \@anim@endsanitize%
  \leavevmode%
  \ifpdf\else%
    \if@anim@grxloaded%
      \if@anim@xetex%
        \DeclareGraphicsRule{.mps}{eps}{*}{}%
      \fi%
    \else%
      \if@anim@xetex%
        \@anim@missing[xetex]{graphicx}%
      \else%
        \if@anim@dvipdfmx%
          \@anim@missing[dvipdfmx]{graphicx}%
        \else%
          \@anim@missing{graphicx}%
        \fi%
      \fi%
    \fi%
  \fi%
  \@anim@reset% to default settings
  \begingroup% make use of graphic[xs] search path
  \ifcsname Ginput@path\endcsname%
    \let\input@path\Ginput@path%
  \fi%
  %
  \setkeys{anim@user}{#1}%
  \ifthenelse{\boolean{@anim@autoplay}\OR\boolean{@anim@autoresume}}{%
    \setboolean{@anim@autoplayorresume}{true}%
  }{}%
  \ifthenelse{\boolean{@anim@controls}\OR\boolean{@anim@palindrome}}{%
    \setboolean{@anim@morejs}{true}%
  }{}%
  \ifx\empty\@anim@label\empty\else%
    \setboolean{@anim@morejs}{true}%
  \fi%
  \ifthenelse{\NOT\boolean{@anim@controls}\AND\boolean{@anim@step}}{%
    \setboolean{@anim@loop}{true}%
  }{}%
  \def\@anim@base{#3}%
  \def\@anim@first{#4}%
  \def\@anim@last{#5}%
  %
  \@anim@checkmultipage{\@anim@base}{\@anim@ftype}%test for multipage file
  \if@anim@multipage\else% cope with wrong user input
    \ifthenelse{\equal{#4}{}\OR\equal{#5}{}}{%
      \PackageError{animate}{%
        Missing frame number in \protect\animategraphics\space command%
      }{}%
    }{}%
    \ifthenelse{\@anim@first<\z@\OR\@anim@last<\z@}{%
      \PackageError{animate}{%
        Negative frame numbers not allowed%
      }{}%
    }{}%
  \fi%
  \def\@anim@relop{>}%
  \edef\@anim@numtemplate{\@anim@first}%
  \ifnum\@anim@first>\@anim@last\relax%
    \edef\@anim@every{-\@anim@every}%
    \def\@anim@relop{<}%
    \edef\@anim@numtemplate{\@anim@last}%
  \fi%
  \global\@anim@curframe=\@anim@first%
  \global\@anim@curframe@zb=\z@%
  %
  \if@anim@draft%
    \if@anim@multipage%
      %store file in a box
      \@anim@filebox{\@anim@pathtofile}{\@anim@first}%
    \else%
      %get file name extension
      \@anim@getpath{\@anim@base\@anim@first}{\@anim@ftype}%
      \@anim@filebox{\@anim@pathtofile}{1}%
    \fi%
    \@anim@scale{\@anim@box}%
    %draw draftbox according to dimensions of the first frame
    \@anim@draftbox%
  \else%
    \if@anim@controls%
      %create button faces only once in the current colour combination
      \ifcsname
        btncol:\@anim@bgcolour:\@anim@fgcolour\endcsname\else%
        \@anim@makebuttons{\the\@anim@num}%
        \@anim@newkey{btncol:\@anim@bgcolour:\@anim@fgcolour}{\the\@anim@num}%
      \fi%
    \fi%
    \xdef\@anim@nfps{#2\space}% current frame rate
    \xdef\@anim@nfps{\expandafter\zap@space\@anim@nfps\@empty}%
    \ifdim\@anim@nfps\p@<\z@%
      \PackageError{animate}{%
        Negative frame rate `\@anim@nfps' is not allowed%
      }{}%
    \fi%
    \xdef\@anim@fps{\@anim@nfps}%
    %
    %read all frames of the sequence
    \loop\ifnum\@anim@curframe\@anim@relop\@anim@last\relax\else%
      \if@anim@multipage%
        %embed graphics
        \@anim@ximage{\the\@anim@num}{\the\@anim@curframe@zb}{%
          \@anim@pathtofile}{\the\@anim@curframe}%
      \else%
        %get path to current file end its extension
        \@anim@getpath{%
          \@anim@base\@anim@pad{\@anim@numtemplate}{\the\@anim@curframe}%
        }{\@anim@ftype}%
        %embed graphics
        \@anim@ximage{\the\@anim@num}{\the\@anim@curframe@zb}{%
          \@anim@pathtofile}{1}%
      \fi%
      \global\advance\@anim@curframe by \@anim@every%
      \global\advance\@anim@curframe@zb by \@ne%
    \repeat%
    \xdef\@anim@frames{\the\@anim@curframe@zb}% total number
    \global\@anim@tmpcnt=\@anim@frames%
    \global\advance\@anim@tmpcnt by -\@ne%
    \xdef\@anim@maxframe{\the\@anim@tmpcnt}% highest frame index
    %build timeline from optional timeline file
    \@anim@sanitizeJS%
    \if@anim@timeline\@anim@buildtmln{\the\@anim@num}\fi%
    % if last frame used as poster, write frame num to aux file
    \ifnum\@anim@poster=\@anim@mone\relax%
      \@anim@keytoaux{a\the\@anim@num.poster}{\@anim@maxframe}%
    \fi%
    %insert animation widget & controls
    \@anim@insertwidgets{\the\@anim@num}{%
      \@anim@getkeyval{btncol:\@anim@bgcolour:\@anim@fgcolour}}%
    \@anim@endsanitize%
  \fi%
  \endgroup%
  \global\advance\@anim@num by \@ne%
}%
%adjust catcode of `:' character within \animategraphics
\let\@anim@animategraphics\animategraphics
\def\animategraphics{\@anim@sanitizeColon\@anim@animategraphics}

%inserts animation and control button widgets
\def\@anim@insertwidgets#1#2{%#1:@anim@num, #2 existing btn colour combination
  \vtop{%
    \offinterlineskip%
    \hbox{\@anim@animwidget{#1}}%
    \if@anim@controls%
      \setlength{\@anim@tmpdima}{\@anim@btnsize}%
      \vskip 0.1\@anim@tmpdima%
      \hbox to \@anim@animwidth\p@ {%
        \hss%
        \def\@anim@tooltip{}%
        \@anim@buttonwidget{#1}{EndLeft}{EndLeft:#2}%
        \@anim@buttonwidget{#1}{StepLeft}{StepLeft:#2}%
        \if@anim@step\else%
          \@anim@buttonwidget{#1}{PauseLeft}{PauseLeft:#2}%
          \@anim@buttonwidget{#1}{PlayLeft}{PlayLeft:#2}%
          \@anim@buttonwidget{#1}{PlayPauseLeft}{}%
          \@anim@buttonwidget{#1}{PauseRight}{PauseRight:#2}%
          \@anim@buttonwidget{#1}{PlayRight}{PlayRight:#2}%
          \@anim@buttonwidget{#1}{PlayPauseRight}{}%
        \fi%
        \@anim@buttonwidget{#1}{StepRight}{StepRight:#2}%
        \@anim@buttonwidget{#1}{EndRight}{EndRight:#2}%
        \if@anim@step\else%
          \hskip 0.3\@anim@tmpdima%
          \def\@anim@tooltip{/TU (slower)}%
          \@anim@buttonwidget{#1}{Minus}{Minus:#2}%
          \def\@anim@tooltip{/TU (default speed)}%
          \@anim@buttonwidget{#1}{Reset}{Reset:#2}%
          \def\@anim@tooltip{/TU (faster)}%
          \@anim@buttonwidget{#1}{Plus}{Plus:#2}%
        \fi%
        \hss%
      }%
    \fi%
  }%
}

\newcount\@anim@resizeflags% resizing flags according to options given.
%
%set animation widget dimensions
\def\@anim@scale#1{% #1: box number
  \begingroup%
    %natural dimensions \width, \height, \depth, \totalheight
    \def\width{\wd#1}%
    \def\height{\ht#1}%
    \def\depth{\dp#1}%
    \let\totalheight\@anim@tmpdimb%
    \setlength{\totalheight}{\dimexpr\height+\depth\relax}%
    %evaluate resizing options
    \xdef\@anim@animwidth{\strip@pt\dimexpr\@anim@widtharg\relax}%
    \xdef\@anim@animheight{\strip@pt\dimexpr\@anim@heightarg\relax}%
    \xdef\@anim@animtotalheight{\strip@pt\dimexpr\@anim@totheightarg\relax}%
  \endgroup%
  %correct wrong option combination; totalheight overrides height
  \ifnum\@anim@resizeflags=3\relax% height+totalheight->totalheight
    \global\@anim@resizeflags=\@ne%
  \fi%
  \ifnum\@anim@resizeflags=7\relax% height+totalheight+width->totalheight+width
    \global\@anim@resizeflags=5%
  \fi%
  %now resize
  \ifcase\@anim@resizeflags% bit 2^2=width, 2^1=height, 2^0=totalhight given
  \or% 1
    \global\setbox#1=\hbox{\resizebox*{!}{\@anim@animtotalheight\p@}{\box#1}}%
  \or% 2
    \global\setbox#1=\hbox{\resizebox{!}{\@anim@animheight\p@}{\box#1}}%
  \or\or% 4
    \global\setbox#1=\hbox{\resizebox{\@anim@animwidth\p@}{!}{\box#1}}%
  \or% 5
    \if@anim@iso%
      \setlength{\@anim@tmpdima}{%
        \totalheightof{\usebox#1}*\ratio{\@anim@animwidth\p@}{\wd#1}}%
      \ifdim\@anim@tmpdima<\z@\@anim@tmpdima=-\@anim@tmpdima\fi%
      \setlength{\@anim@tmpdimb}{\@anim@animtotalheight\p@}%
      \ifdim\@anim@tmpdimb<\z@\@anim@tmpdimb=-\@anim@tmpdimb\fi%
      \ifdim\@anim@tmpdima<\@anim@tmpdimb%
        \global\setbox#1=\hbox{\resizebox*{\@anim@animwidth\p@}{!}{\box#1}}%
      \else%
        \global\setbox#1=\hbox{%
          \resizebox*{!}{\@anim@animtotalheight\p@}{\box#1}}%
      \fi%
    \else%
      \global\setbox#1=\hbox{%
        \resizebox*{\@anim@animwidth\p@}{\@anim@totheightarg}{\box#1}}%
    \fi%
  \or% 6
    \if@anim@iso%
      \setlength{\@anim@tmpdima}{\ht#1*\ratio{\@anim@animwidth\p@}{\wd#1}}%
      \ifdim\@anim@tmpdima<\z@\@anim@tmpdima=-\@anim@tmpdima\fi%
      \setlength{\@anim@tmpdimb}{\@anim@animheight\p@}%
      \ifdim\@anim@tmpdimb<\z@\@anim@tmpdimb=-\@anim@tmpdimb\fi%
      \ifdim\@anim@tmpdima<\@anim@tmpdimb%
        \global\setbox#1=\hbox{\resizebox{\@anim@animwidth\p@}{!}{\box#1}}%
      \else%
        \global\setbox#1=\hbox{\resizebox{!}{\@anim@animheight\p@}{\box#1}}%
      \fi%
    \else%
      \global\setbox#1=\hbox{%
        \resizebox{\@anim@animwidth\p@}{\@anim@animheight\p@}{\box#1}}%
    \fi%
  \fi%
  %apply scale
  \ifdim\@anim@boxscale\p@=\@ne\p@\else%
    \global\setbox#1=\hbox{\scalebox{\@anim@boxscale}{\box#1}}%
  \fi%
  %dimensions after resizing
  \xdef\@anim@animwidth{\strip@pt\wd#1}%
  \xdef\@anim@animheight{\strip@pt\ht#1}%
  \xdef\@anim@animdepth{\strip@pt\dp#1}%
  \xdef\@anim@animtotalheight{\strip@pt\dimexpr\ht#1+\dp#1\relax}%
}

%interactive Widget annotation serving as animation frame container / that is
%overlayed on the non-interactive frame Widgets or on the page content with
%frame OCGs
\def\@anim@animwidget#1{%
  \@anim@pojscript{#1}%
  \@anim@otherjscript{#1}%
  \def\@anim@annotflag{}%
  \ifnum\@anim@poster>\@anim@maxframe\relax%
    \PackageError{animate}{%
      Poster frame `\@anim@poster' is out-of-bounds\MessageBreak%
      on input line \the\inputlineno.\MessageBreak%
      Try option `poster=last'%
    }{}%
  \fi%
  \ifnum\@anim@method=\z@\relax%
    \def\@anim@annotflag{/F 4}% 4=allow printing
    \ifnum\@anim@poster=\@anim@mtwo\relax%
      \ifdefined\@anim@apdummy\else% empty appearance dummy
        \setbox\@anim@box=\hbox{\phantom{x}}%
        \@anim@xform{0}{0}{\@anim@box}%
        \xdef\@anim@apdummy{\@anim@lastxform}%
        \xdef\@anim@appearances{%
          (0000)
          \@anim@refobj{\@anim@lastxform}
          \@anim@appearances%
        }%
      \fi%
      \def\@anim@apmk{\@anim@refobj{\@anim@apdummy}}%
    \else%
      \def\@anim@apmk{\@anim@refobj{\@anim@posterap}}%
    \fi%
  \else%
    \ifdefined\@anim@apdummy\else% empty appearance dummy
      \setbox\@anim@box=\hbox{\phantom{x}}%
      \@anim@xform{0}{0}{\@anim@box}%
      \xdef\@anim@apdummy{\@anim@lastxform}%
    \fi%
    \def\@anim@apmk{\@anim@refobj{\@anim@apdummy}}%
  \fi%
  %With icon and ocg method, we put one dummy widget below; this seems to be
  %necessary for the OCG visibility referenced by the /OC entry to work as
  %expected (if we place the animation on a PDF layer using ocgx2.sty).
  \ifnum\@anim@method=\@ne\relax\else%
    \ifdefined\ocgxii@insert@OC%
      \ifthenelse{\equal{\ocgxii@insert@OC}{}}{}{%
        \@anim@pdfannot{\@anim@animwidth}{\@anim@animheight}{\@anim@animdepth}{%
          /Subtype/Widget/F 2%
        }%
      }%
    \fi%
  \fi%
  \@anim@pdfannot{\@anim@animwidth}{\@anim@animheight}{\@anim@animdepth}{%
    /Subtype/Widget%
    /FT/Btn/Ff \@anim@btnflag%
    \@anim@annotflag%
    /BS <</W 0>>%
    /H/N%
    /T (anm#1)%
    /Contents (animation by animate[\@anim@version])%
    /AA <<%
      /PV <</S/JavaScript/JS \@anim@pojscriptobj>>% PageVisible
      \@anim@otherjscriptkey%
    >>%
    /AP <</N \@anim@apmk>>%
    /MK <</TP 1/I \@anim@apmk/IF<</S/A/FB true>>>>%
    \ifdefined\ocgxii@insert@OC\ocgxii@insert@OC\fi%
  }%
  \hbox to \@anim@animwidth\p@ {%
    \vrule width 0pt height \@anim@animheight\p@ depth \@anim@animdepth\p@%
    \hss%
  }%
}

%creates control button widget
\newboolean{@anim@js}
\newboolean{@anim@mk}
\def\@anim@buttonwidget#1#2#3{%#1:@anim@num, #2:action, #3:button face XObject
  \def\@anim@annotflag{/F 0}% visible, but don't print
  \def\@anim@buttonname{#2}\@anim@jstrue\@anim@mktrue%
  \def\@anim@arg{PlayLeft}%
  \ifx\@anim@arg\@anim@buttonname\@anim@jsfalse\fi%                          _
  \def\@anim@arg{PauseLeft}%                             %hidden, don't print |
  \ifx\@anim@arg\@anim@buttonname\@anim@jsfalse\def\@anim@annotflag{/F 2}\fi%_|
  \def\@anim@arg{PlayRight}%
  \ifx\@anim@arg\@anim@buttonname\@anim@jsfalse\fi%
  \def\@anim@arg{PauseRight}%
  \ifx\@anim@arg\@anim@buttonname\@anim@jsfalse\def\@anim@annotflag{/F 2}\fi%
  \def\@anim@arg{PlayPauseLeft}%
  \ifx\@anim@arg\@anim@buttonname\@anim@mkfalse\fi%
  \def\@anim@arg{PlayPauseRight}%
  \ifx\@anim@arg\@anim@buttonname\@anim@mkfalse\fi%
  \if@anim@mk\else%
    \ifdefined\@anim@apdummy\else% empty appearance dummy
      \setbox\@anim@box=\hbox{\phantom{x}}%
      \@anim@xform{0}{0}{\@anim@box}%
      \xdef\@anim@apdummy{\@anim@lastxform}%
    \fi%
  \fi%
  \if@anim@js\@anim@upjscript{#1}{#2}\fi% JavaScript actions for ButtonUp events
  \setlength{\@anim@tmpdima}{\@anim@btnsize}%
  \ifdefined\ocgxii@insert@OC% put dummy widget below (for ocgx2 compatibility)
    \ifthenelse{\equal{\ocgxii@insert@OC}{}}{}{%
      \@anim@pdfannot{\strip@pt\@anim@tmpdima}{\strip@pt\@anim@tmpdima}{0}{%
        /Subtype/Widget/F 2%
      }%
    }%
  \fi%
  \@anim@pdfannot{\strip@pt\@anim@tmpdima}{\strip@pt\@anim@tmpdima}{0}{%
    /Subtype/Widget%
    \@anim@annotflag%
    /FT/Btn/Ff \if@anim@js 65536\else 65537\fi%
    /H\if@anim@js/I\else/N\fi%
    /BS <</W 0>>%
    \if@anim@mk%
      /AP <</N \@anim@getkeyval{btn#3}>>%
      /MK <</TP 1/I \@anim@getkeyval{btn#3}/IF<</S/A/FB true>>>>%
    \else%
      /AP <</N \@anim@refobj{\@anim@apdummy}>>%
      /MK <</TP 1/I \@anim@refobj{\@anim@apdummy}/IF<</S/A/FB true>>>>%
    \fi%
    /T (#1.#2)%
    \@anim@tooltip%
    \if@anim@js/A <</S/JavaScript/JS (\@anim@upjscriptstring)>>\fi%
    \ifdefined\ocgxii@insert@OC\ocgxii@insert@OC\fi%
  }%
  \if@anim@js%
    \hbox to \@anim@tmpdima {%
      \vrule width 0pt height \@anim@tmpdima depth 0pt%
      \hss%
    }%
  \fi%
}

\newboolean{@anim@pauseframes} % true if \newframe* is being used
\newboolean{@anim@chfps} % true if \newframe or \newframe* is being used
                         % with optional `new frame rate' argument
\newboolean{@anim@usrjs} % true if user JavaScript provided by user

\newcount\@anim@skipfram % counter for skipped frames

%user environment for animating inline graphics
% #1: options
% #2: frame rate (fps)
\newenvironment{animateinline}[2][]{%
  \@anim@endsanitize%
  \leavevmode%
  \@anim@reset% to default settings
  \begingroup%
  % make use of graphic[xs] search path
  \ifcsname Ginput@path\endcsname%
    \let\input@path\Ginput@path%
  \fi%
  \setkeys{anim@user}{#1}%
  \ifthenelse{\boolean{@anim@autoplay}\OR\boolean{@anim@autoresume}}{%
    \setboolean{@anim@autoplayorresume}{true}%
  }{}%
  \ifthenelse{\boolean{@anim@controls}\OR\boolean{@anim@palindrome}}{%
    \setboolean{@anim@morejs}{true}%
  }{}%
  \ifx\empty\@anim@label\empty\else%
    \setboolean{@anim@morejs}{true}%
  \fi%
  \ifthenelse{\NOT\boolean{@anim@controls}\AND\boolean{@anim@step}}{%
    \setboolean{@anim@loop}{true}%
  }{}%
  \global\@anim@curframe@zb=\z@%
  \global\@anim@skipfram=\z@%
  \if@anim@draft\else%
    %create button faces if necessary
    \if@anim@controls%
      \ifcsname
        btncol:\@anim@bgcolour:\@anim@fgcolour\endcsname\else%
        \@anim@makebuttons{\the\@anim@num}%
        \@anim@newkey{btncol:\@anim@bgcolour:\@anim@fgcolour}{\the\@anim@num}%
      \fi%
    \fi%
    \if@anim@step\else%
      \xdef\@anim@nfps{-1}%
      \@anim@processfpsarg{#2}%
    \fi%
  \fi%
  \ifdefined\NoHyper\NoHyper\fi% silently suppress any hyperref specials
  \let\newframe\@anim@@newframe%
  \let\multiframe\@anim@multiframe%
  \@anim@beginframe%
  \ignorespaces%
}{%
  \unskip%
  \@anim@endframe{\the\@anim@num}{\the\@anim@curframe@zb}%
  \ifdefined\endNoHyper\endNoHyper\fi%
  \global\advance\@anim@curframe@zb by \@ne%
  \if@anim@draft\else%
    \xdef\@anim@frames{\the\@anim@curframe@zb}% total number
    \global\@anim@tmpcnt=\@anim@frames%
    \global\advance\@anim@tmpcnt by -\@ne%
    \xdef\@anim@maxframe{\the\@anim@tmpcnt}% highest frame index
    %build timeline from optional timeline file
    \@anim@sanitizeJS%
    \if@anim@timeline\@anim@buildtmln{\the\@anim@num}\fi%
    %insert animation widget & controls
    \@anim@insertwidgets{\the\@anim@num}{%
      \@anim@getkeyval{btncol:\@anim@bgcolour:\@anim@fgcolour}}%
    \@anim@endsanitize%
    % if last frame used as poster, write frame num to aux file
    \ifnum\@anim@poster=\@anim@mone\relax%
      \@anim@keytoaux{a\the\@anim@num.poster}{\@anim@maxframe}%
    \fi%
  \fi%
  \endgroup%
  \global\advance\@anim@num by \@ne%
}
\let\@anim@animateinline\animateinline
\def\animateinline{\@anim@sanitizeColon\@anim@animateinline}

%usercommand for use within `animateinline' environment;
%terminates the current frame and starts a new one
\def\@anim@@newframe{% aliased to \newframe inside `animateinline'
  \unskip%
  \@anim@endframe{\the\@anim@num}{\the\@anim@curframe@zb}%
  \@ifstar\@anim@newframestar\@anim@newframe%
}
\def\@anim@processfpsarg#1{%
  %process frame rate argument
  \xdef\@anim@pfps{\@anim@nfps}%
  \xdef\@anim@nfps{#1\space}%
  \xdef\@anim@nfps{\expandafter\zap@space\@anim@nfps\@empty}%
  \ifx\@anim@nfps\@empty% no change of frame rate
    \xdef\@anim@nfps{\@anim@pfps}%
  \fi%
  \ifnum\@anim@curframe@zb=\z@\relax%
    \xdef\@anim@fps{\@anim@nfps}% default fps
    \xdef\@anim@nfpsat{\@anim@nfps}%
  \else%
    \xdef\@anim@nfpsat{\@anim@nfpsat,\@anim@nfps}%
  \fi%
  \ifdim\@anim@nfps\p@=\@anim@pfps\p@\else%
    \ifnum\@anim@curframe@zb=\z@\relax\else%
      \setboolean{@anim@chfps}{true}% change fps
    \fi%
  \fi%
  \ifdim\@anim@nfps\p@<\z@%
    \PackageError{animate}{%
      Negative frame rate `\@anim@nfps' is not allowed%
    }{}%
  \fi%
}%
\newcommand{\@anim@newframe}[1][]{% #1: new frame rate
  \ifnum\@anim@skipfram=\z@\relax%
    \global\advance\@anim@curframe@zb by \@ne%
    \if@anim@draft\else%
      \if@anim@step\else%
        \if@anim@timeline\else%
          %process frame rate argument
          \@anim@processfpsarg{#1}%
        \fi%
      \fi%
    \fi%
  \fi%
  \@anim@beginframe%
  \ignorespaces%
}
\newcommand{\@anim@newframestar}[1][]{% starred variant for pausing animation
  \ifnum\@anim@skipfram=\z@\relax%            #1: new frame rate
    \if@anim@draft\else%
      \if@anim@step\else%
        \if@anim@timeline\else%
          %build JavaScript commands to fill the `pauseAt' array
          \xdef\@anim@pauseat{%
            \@anim@pauseat%
            a\the\@anim@num.pauseAt[\the\@anim@curframe@zb]=1;%
          }%
          \setboolean{@anim@pauseframes}{true}%
        \fi%
      \fi%
    \fi%
    \global\advance\@anim@curframe@zb by \@ne%
    \if@anim@draft\else%
      \if@anim@step\else%
        \if@anim@timeline\else%
          %process frame rate argument
          \@anim@processfpsarg{#1}%
        \fi%
      \fi%
    \fi%
  \fi%
  \@anim@beginframe%
  \ignorespaces%
}

%starts new frame
\def\@anim@beginframe{%
  \begin{lrbox}{\@anim@box}% store graphics in a box
  \@anim@begin%
}

%terminates current frame
\def\@anim@endframe#1#2{%
  \@anim@end%
  \end{lrbox}%
  \ifnum\@anim@skipfram=\z@\relax%
    \ifnum#2=\z@\relax%
      \ifdim\wd\@anim@box=\z@%
        \PackageError{animate}{%
          Contents of first frame must not have zero width%
        }{%
          Possible reason: \protect\begin{animateinline}{...}
          immediately followed by \protect\newframe%
        }%
      \fi%
      \ifdim\ht\@anim@box=\z@\ifdim\dp\@anim@box=\z@%
          \PackageError{animate}{%
            Contents of first frame must not have zero height%
          }{}%
      \fi\fi%
      %draw draftbox according to dimensions of the first frame
      \if@anim@draft\@anim@scale{\@anim@box}\@anim@draftbox\fi%
    \else% remaining frames
      %deal with zero width or totalheight boxes
      \ifdim\wd\@anim@box=\z@\global\setbox\@anim@box=\hbox{\phantom{X}}\fi%
      \ifdim\ht\@anim@box=\z@\ifdim\dp\@anim@box=\z@%
        \global\setbox\@anim@box=\hbox{\phantom{X}}%
      \fi\fi%
    \fi%
    %now create Form XObject of box contents
    \if@anim@draft\else%
      \@anim@xinline{#1}{#2}{\@anim@box}{!}{}\message{<a#1,fr#2>}%
    \fi%
  \fi%
  \global\advance\@anim@skipfram by \@ne%
  \ifnum\@anim@skipfram=\@anim@every\relax%
    \global\@anim@skipfram=\z@%
  \fi%
}

%user command for building loops around parameterized frame content, somewhat
%like \multido (package multido) with embedded \newframe
\newcount\@anim@mulframecnt %takes current loop No. of \multiframe
\newboolean{@anim@insidemulti} % for checking whether we are inside \multiframe
\setboolean{@anim@insidemulti}{false}
\newcommand{\@anim@multiframe}[3]{%
  % aliased to \multiframe inside `animateinline'
  % #1: #repetitions, #2: vars, #3: frame content
  \unskip%
  \if@anim@insidemulti%
    \PackageError{animate}{\protect\multiframe\space cannot be nested}{}%
  \fi%
  \setboolean{@anim@insidemulti}{true}%
  %reset macro for updating variables
  \gdef\@anim@updatevars{}%
  %reset loop counter
  \global\@anim@mulframecnt=\z@%
  %remove spaces from variable declaration list (2nd arg)
  \xdef\@anim@vardecls{#2\space}%
  \xdef\@anim@vardecls{\expandafter\zap@space\@anim@vardecls\@empty}%
  \ifnum#1<\z@\relax%
    \PackageError{animate}{%
      \protect\multiframe: first argument must be greater than zero%
    }{}%
  \fi%
  %parse list of variable declarations and build macro for updating them
  \expandafter\@anim@parsevars\@anim@vardecls,\@nil%
  \whiledo{\@anim@mulframecnt<#1}{%
    \ifnum\@anim@mulframecnt>\z@\relax%
      \@anim@@newframe%
      \@anim@updatevars% update variables
    \fi%
    \global\advance\@anim@mulframecnt by \@ne%
    \ignorespaces%
    #3% execute loop body
    \unskip%
  }%
  \setboolean{@anim@insidemulti}{false}%
  \ignorespaces%
}

%splits list of variable declarations
\def\@anim@parsevars#1,#2\@nil{%
  \ifthenelse{\equal{#1}{}}{}{\@anim@parsedecl#1\@nil=+\@nil\relax}%
  \ifthenelse{\equal{#2}{}}{}{\@anim@parsevars#2\@nil}%
}
%parser for single variable declaration
\def\@anim@parsedecl#1=#2+#3\@nil#4\relax{%
  \ifx\@empty#4\@empty%
    \PackageError{animate}{\protect\multiframe: bad variable declaration}{}%
  \fi%
  \ifthenelse{\equal{#1}{}\OR\equal{#2}{}\OR\equal{#3}{}}{%
    \PackageError{animate}{\protect\multiframe: bad variable declaration}{}%
  }{}%
  \edef\@anim@vartype{\@anim@getvartype#1\@nil}%
  \ifthenelse{\equal{\@anim@vartype}{d}\OR\equal{\@anim@vartype}{D}}{%
    % dimensions, prefix d, D
    %initialize variable
    \setlength{\@anim@tmpdima}{#2}%
    \expandafter\edef\csname#1\endcsname{\number\@anim@tmpdima sp}%
    %global copy that saves current variable value between loops
    \expandafter\xdef\csname#1@old\endcsname{\number\@anim@tmpdima sp}%
    \setlength{\@anim@tmpdimb}{#3}%
    %global copy of increment
    \expandafter\xdef\csname#1@inc\endcsname{\number\@anim@tmpdimb sp}%
    %append script for updating variable to \@anim@updatevars macro
    \g@addto@macro\@anim@updatevars{%
      %new value
      \setlength{\@anim@tmpdima}{\csname#1@old\endcsname}%
      \addtolength{\@anim@tmpdima}{\csname#1@inc\endcsname}%
      \expandafter\edef\csname#1\endcsname{\number\@anim@tmpdima sp}%
      %global copy
      \expandafter\xdef\csname#1@old\endcsname{\number\@anim@tmpdima sp}%
    }%
  }{%
    \ifthenelse{%
      \equal{\@anim@vartype}{n}\OR\equal{\@anim@vartype}{N}%
      \OR\equal{\@anim@vartype}{r}\OR\equal{\@anim@vartype}{R}%
    }{% real numbers, prefix n, N, r, R
      %initialize variable
      \expandafter\@anim@add\csname#1\endcsname{#2}{0.0}%
      %global copy that saves current variable value between loops
      \expandafter\xdef\csname#1@old\endcsname{#2}%
      %append script for updating variable to \@anim@updatevars macro
      \g@addto@macro\@anim@updatevars{%
        %new value
        \expandafter\@anim@add\csname#1\endcsname{\csname#1@old\endcsname}{#3}%
        %global copy
        \expandafter\xdef\csname#1@old\endcsname{\csname#1\endcsname}%
      }%
    }{%
      \ifthenelse{\equal{\@anim@vartype}{i}\OR\equal{\@anim@vartype}{I}}{%
        % integers, prefix i, I
        %initialize variable
        \setcounter{@anim@ltxcnt}{#2}%
        \expandafter\edef\csname#1\endcsname{\the@anim@ltxcnt}%
        %global copy that saves current variable value between loops
        \expandafter\xdef\csname#1@old\endcsname{\the@anim@ltxcnt}%
        \setcounter{@anim@ltxcnt}{#3}%
        %global copy of increment
        \expandafter\xdef\csname#1@inc\endcsname{\the@anim@ltxcnt}%
        %append script for updating variable to \@anim@updatevars macro
        \g@addto@macro\@anim@updatevars{%
          %new value
          \expandafter\global\expandafter\@anim@tmpcnt\csname#1@old\endcsname%
          \global\advance\@anim@tmpcnt by \csname#1@inc\endcsname%
          \expandafter\edef\csname#1\endcsname{\the\@anim@tmpcnt}%
          %global copy
          \expandafter\xdef\csname#1@old\endcsname{\the\@anim@tmpcnt}%
        }%
      }{%
        \PackageError{animate}{%
          \protect\multiframe: wrong name prefix `\@anim@vartype' in%
          \MessageBreak variable `#1'.\MessageBreak%
          Use any of d, D (dimensions), i, I (integer numbers)\MessageBreak%
          or n, N, r, R (real numbers) as the first letter to\MessageBreak%
          specify the variable type%
        }{}%
      }%
    }%
  }%
}
%get initial letter from variable name (the variable type, as with \multido)
\def\@anim@getvartype#1#2\@nil{#1}%

%prints zero padded integers
% #1: arbitrary integer number as template specifying the
%     width, e. g. `987654' for a width of 6 digits
% #2: the number to be formatted
\def\@anim@pad#1#2{%
  \@anim@@pad{\@anim@template{0}{#1}}{#2}%
}
%low level macros used by \@anim@pad
\def\@anim@@pad#1#2{% #1: string of zeros specifying width, #2 number
  \ifnum1#2<1#1
    \@anim@@pad{#1}{0#2}%
  \else%
    #2%
  \fi%
}%
\def\@anim@template#1#2{% create template (string of zeros) from given num
  \ifnum10#1>1#2
    #1%
  \else%
    \@anim@template{0#1}{#2}%
  \fi%
}%

\begingroup\catcode`\_=13\let_\space
\xdef\@anim@nusewarning{%
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak%
  @_There_were_unused_animation_transparencies._______@\MessageBreak%
  @_See_the_transcript_file___________________________@\MessageBreak%
  @___``\jobname.log''\MessageBreak%
  @_for_additional_information!_______________________@\MessageBreak%
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%
}
\xdef\@anim@icondvipswarning{%
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak%
  @_Icon-based_animation_method_(`method=icon')_____@\MessageBreak%
  @_breaks_all_hyperref-inserted_links_in_the_final_@\MessageBreak%
  @_PDF_produced_via_the_Dvips_route!_______________@\MessageBreak%
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
}
\endgroup

%macros for sanitizing characters
\def\@anim@sanitize#1#2\@nil{%
  \catcode`#1=12%
  \ifx\@empty#2\@empty\else%
    \@anim@sanitize#2\@nil%
  \fi%
}
\def\@anim@sanitizeJS{% sanitize JS code while being read from timeline file
  \begingroup%
  \@anim@sanitize.:;?!/"'*+,->=<$\&@][)(^_`|~\#\@nil%
  \def\\{\string\\}%
  \def\{{\string\{}%
  \def\}{\string\}}%
  \def\%{\string\%}%
}
\def\@anim@sanitizeColon{% sanitize colon (`:') while reading the option list,
  \begingroup%             in particular the `buttonfg' and `buttonbg' options
  \@anim@sanitize:\@nil%  arguments
}
\let\@anim@endsanitize\endgroup

%building timeline from timeline file
\newread\@anim@@tmlnfile
\newboolean{@anim@eof}
\newcount\@anim@tmpcnt %scratch counter for different uses
\newcounter{@anim@ltxcnt} %scratch LaTeX counter for different uses
\newcount\@anim@curlayer %takes the number of the current layer being processed
\newcount\@anim@lineno %current input line No.
\newcount\@anim@curfield %current field of input line processed

\def\@anim@buildtmln#1{% #1:@anim@num
  \endlinechar=-1% suppress trailing space at input line end
  \global\@anim@curframe@zb=\z@%
  %read timeline file a first time to get number of lines (= number of frames)
  \openin\@anim@@tmlnfile=\@anim@tmlnfile%
  \read\@anim@@tmlnfile to \@anim@inputline%
  \edef\@anim@inputline{\@anim@inputline\space}%
  %remove all spaces from input line
  \edef\@anim@inputline{\expandafter\zap@space\@anim@inputline\@empty}%
  \ifeof\@anim@@tmlnfile\setboolean{@anim@eof}{true}\else%
    \setboolean{@anim@eof}{false}\fi%
  \whiledo{\NOT\boolean{@anim@eof}}{%
    \ifthenelse{\equal{\@anim@inputline}{}}{}{%
      %initialise contents & transparency lists for each frame
      \@anim@newkey{trlst@\the\@anim@curframe@zb}{}%
      \@anim@newkey{frmcontent@\the\@anim@curframe@zb}{}%
      \global\advance\@anim@curframe@zb by \@ne%
    }%
    \read\@anim@@tmlnfile to \@anim@inputline%
    \edef\@anim@inputline{\@anim@inputline\space}%
    \edef\@anim@inputline{\expandafter\zap@space\@anim@inputline\@empty}%
    \ifeof\@anim@@tmlnfile\setboolean{@anim@eof}{true}\else%
      \setboolean{@anim@eof}{false}\fi%
  }%
  \closein\@anim@@tmlnfile%
  \xdef\@anim@transp{\@anim@frames}% total number of transparencies
  \xdef\@anim@frames{\the\@anim@curframe@zb}%total number of actual frames
  \global\@anim@tmpcnt=\@anim@frames%
  \global\advance\@anim@tmpcnt by -\@ne%
  \xdef\@anim@maxframe{\the\@anim@tmpcnt}% highest frame index
  \global\@anim@curframe@zb=\z@%
  \gdef\@anim@maxlayer{0}% highest layer index
  %reopen timeline file and build timeline
  \openin\@anim@@tmlnfile=\@anim@tmlnfile%
  \global\@anim@lineno=\z@%
  \read\@anim@@tmlnfile to \@anim@inputline%
  \edef\@anim@inputlinenospc{\@anim@inputline\space}%
  \edef\@anim@inputlinenospc{%
    \expandafter\zap@space\@anim@inputlinenospc\@empty}%
  \ifeof\@anim@@tmlnfile\setboolean{@anim@eof}{true}\else%
    \setboolean{@anim@eof}{false}\fi%
  \message{<building timeline a#1 from file `\@anim@tmlnfile':}%
  \whiledo{\NOT\boolean{@anim@eof}}{%
    \global\advance\@anim@lineno by \@ne%
    \ifthenelse{\equal{\@anim@inputlinenospc}{}}{}{%
      %process input line
      \global\@anim@curfield=\z@%
      \expandafter\@anim@parseline\@anim@inputline:\@nil%
      %combine the layers of the current frame
      \global\@anim@curlayer=\z@%
      \loop\ifnum\@anim@curlayer>\@anim@maxlayer\relax\else%
        \@anim@newkey{frmcontent@\the\@anim@curframe@zb}{%
          \@anim@getkeyval{frmcontent@\the\@anim@curframe@zb}%
          \@anim@getkeyval{%
            layercontent@\the\@anim@curframe@zb.\the\@anim@curlayer}%
        }%
        \@anim@newkey{trlst@\the\@anim@curframe@zb}{%
          \@anim@getkeyval{trlst@\the\@anim@curframe@zb}%
          \@anim@getkeyval{%
            layertrlst@\the\@anim@curframe@zb.\the\@anim@curlayer}%
        }%
        \@anim@newkey{%
          layercontent@\the\@anim@curframe@zb.\the\@anim@curlayer}{}%
        \@anim@newkey{%
          layertrlst@\the\@anim@curframe@zb.\the\@anim@curlayer}{}%
        \global\advance\@anim@curlayer by \@ne%
      \repeat%
      %detect multiple inclusion of the same transp. in the current frame
      \edef\@anim@trlst{%
        \the\@anim@curframe@zb.\@anim@getkeyval{trlst@\the\@anim@curframe@zb}}%
      \expandafter\@anim@findmult\@anim@trlst,\@nil%
      %insert frame Widget
      \@anim@makeframe{#1}{\the\@anim@curframe@zb}%
      %clean-up
      \expandafter\@anim@resetmult\@anim@trlst,\@nil%
      \@anim@newkey{trlst@\the\@anim@curframe@zb}{}%
      \@anim@newkey{frmcontent@\the\@anim@curframe@zb}{}%
      \message{.}%
      \global\advance\@anim@curframe@zb by \@ne%
    }%
    \read\@anim@@tmlnfile to \@anim@inputline%
    \edef\@anim@inputlinenospc{\@anim@inputline\space}%
    \edef\@anim@inputlinenospc{%
      \expandafter\zap@space\@anim@inputlinenospc\@empty}%
    \ifeof\@anim@@tmlnfile\setboolean{@anim@eof}{true}\else%
      \setboolean{@anim@eof}{false}\fi%
  }%
  \message{\the\@anim@curframe@zb\space frames built}%
  \closein\@anim@@tmlnfile%
  %check for unused transparencies
  \global\@anim@tmpcnt=\z@%
  \loop\ifnum\@anim@transp>\@anim@tmpcnt\relax%
    \ifcsname u@tr\the\@anim@tmpcnt\endcsname%
      {\expandafter\global\expandafter\let\csname
         u@tr\the\@anim@tmpcnt\endcsname\@undefined}%
    \else%
      \PackageWarning{animate}{%
        Transparency \the\@anim@tmpcnt\space has never been used\MessageBreak%
        in the current animation.\MessageBreak%
        Timeline ``\@anim@tmlnfile'',\MessageBreak\jobname.tex%
      }%
      \ifcsname @anim@nusewarned\endcsname\else%
        \AtEndDocument{%
          \PackageWarningNoLine{animate}{\@anim@nusewarning}%
        }%
        \gdef\@anim@nusewarned{}%
      \fi%
    \fi%
    \global\advance\@anim@tmpcnt by \@ne%
  \repeat%
  \message{>}%
}

%reads one line of timeline file and splits into its colon separated parts
\def\@anim@parseline#1:#2\@nil{%
  \ifcase\@anim@curfield\relax%
    %first field: a star (pause frame)
    \if@anim@step\else%
      \edef\@anim@tmp{#1\space}%
      \edef\@anim@tmp{\expandafter\zap@space\@anim@tmp\@empty}%
      \ifthenelse{\equal{\@anim@tmp}{*}}{%
        \xdef\@anim@pauseat{%
          \@anim@pauseat%
          a\the\@anim@num.pauseAt[\the\@anim@curframe@zb]=1;%
        }%
        \setboolean{@anim@pauseframes}{true}%
      }{}%
    \fi%
    \global\advance\@anim@curfield by \@ne%
    \@anim@parseline#2\@nil%
  \or%
    \if@anim@step\else%
      %second field: new frame rate
      \@anim@processfpsarg{#1}%
    \fi%
    \global\advance\@anim@curfield by \@ne%
    \@anim@parseline#2\@nil%
  \or%
    %parse the third field (list of layer specifications)
    \global\@anim@curlayer=\z@%
    \edef\@anim@tmp{#1\space}%
    \edef\@anim@tmp{\expandafter\zap@space\@anim@tmp\@empty}%
    \expandafter\@anim@parsethird\@anim@tmp;\@nil%
    \edef\@anim@tmp{#2\space}%
    \edef\@anim@tmp{\expandafter\zap@space\@anim@tmp\@empty}%
    %fourth field: JavaScript provided by the user
    \ifx\@anim@tmp\empty\else\@anim@parseforth#2\@nil\fi%
  \fi%
}

%parses frame contents specification (semicolon separated list of layer
%specifications)
\def\@anim@parsethird#1;#2\@nil{%
  \ifthenelse{\equal{#1}{}}{}{\@anim@parselayer#1,\@nil}%process one layer spec
  \ifthenelse{\equal{#2}{}}{}{%
    \global\advance\@anim@curlayer by \@ne%
    \ifnum\@anim@curlayer>\@anim@maxlayer\relax%
      \xdef\@anim@maxlayer{\the\@anim@curlayer}%
    \fi%
    \@anim@parsethird#2\@nil%
  }%
}

%process JavaScript field
\def\@anim@parseforth#1:\@nil{%
  \edef\@anim@tmp{#1\space}%
  \edef\@anim@tmp{\expandafter\zap@space\@anim@tmp\@empty}%
  \ifx\@anim@tmp\@empty\else%
    \xdef\@anim@usrjsat{%
      \@anim@usrjsat%
      a\the\@anim@num.usrJSat[\the\@anim@curframe@zb]=function(){#1};%
    }%
    \setboolean{@anim@usrjs}{true}%
  \fi%
}

%parses contents of one layer specification (comma separated list of transp.
%specs)
\def\@anim@parselayer#1,#2\@nil{%
  \ifthenelse{\equal{#1}{}}{}{\@anim@process#1x\@nil}%process one transp spec
  \ifthenelse{\equal{#2}{}}{}{\@anim@parselayer#2\@nil}%
}

%process transparency spec, such as `123' or `456x78' or `9x0' or `c' (clear
%transparency stack)
\def\@anim@process#1x#2\@nil{%
  %determine number of repetitions of current transparency
  \ifthenelse{\equal{#2}{}}{%
    \gdef\@anim@repeats{1}%
  }{%
    \@anim@getrepetitions#2\@nil%
  }%
  \ifnum\@anim@repeats=\z@\relax% =0 means: repeat until end of timeline
    \edef\@anim@repeatuntil{\@anim@frames}%
  \else%
    \global\@anim@tmpcnt=\@anim@curframe@zb%
    \global\advance\@anim@tmpcnt by \@anim@repeats%
    \ifnum\@anim@frames<\@anim@tmpcnt\relax%
      \edef\@anim@repeatuntil{\@anim@frames}%
    \else%
      \edef\@anim@repeatuntil{\the\@anim@tmpcnt}%
    \fi%
  \fi%
  %test whether transparency stack of the current layer is to be cleared
  \ifthenelse{\equal{#1}{c}\OR\equal{#1}{C}}{%
    \global\@anim@tmpcnt=\@anim@curframe@zb%
    \loop\ifnum\@anim@frames>\@anim@tmpcnt\relax%
      %clear layer content
      \@anim@newkey{layercontent@\the\@anim@tmpcnt.\the\@anim@curlayer}{}%
      %clear list of transparencies used in the current layer
      \@anim@newkey{layertrlst@\the\@anim@tmpcnt.\the\@anim@curlayer}{}%
      \global\advance\@anim@tmpcnt by \@ne%
    \repeat%
  }{%
    %build contents of animation layer according to transparency specifications
    \ifnum\@anim@transp<#1\relax\else%   ignore non-existing
      \ifnum\@anim@transp=#1\relax\else% transparencies
        \global\@anim@tmpcnt=\@anim@curframe@zb%
        \loop\ifnum\@anim@repeatuntil>\@anim@tmpcnt\relax%
          %layer content
          \edef\@anim@tmpvar{\@anim@getkeyval{%
            layercontent@\the\@anim@tmpcnt.\the\@anim@curlayer}}%
          \@anim@newkey{layercontent@\the\@anim@tmpcnt.\the\@anim@curlayer}{%
            \@anim@tmpvar\@anim@refxform{\@anim@getkeyval{img@#1}}%
          }%
          %append transp. to list of transparencies used in the current layer
          \edef\@anim@tmpvar{\@anim@getkeyval{%
            layertrlst@\the\@anim@tmpcnt.\the\@anim@curlayer}}%
          \@anim@newkey{layertrlst@\the\@anim@tmpcnt.\the\@anim@curlayer}{%
            \@anim@tmpvar#1,}%
          \global\advance\@anim@tmpcnt by \@ne%
        \repeat%
      \fi%
    \fi%
  }%
}
%get number of repetitions of frame
\def\@anim@getrepetitions#1x\@nil{%
  \gdef\@anim@repeats{#1}%
}

\begingroup\catcode`\_=13\let_\space
\xdef\@anim@multwarning{%
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak%
  @_In_certain_animation_frames,_transparencies_were_@\MessageBreak%
  @_included_multiple_times._This_may_considerably___@\MessageBreak%
  @_slow_down_animation_speed._Revise_the_timeline___@\MessageBreak%
  @_file_of_the_corresponding_animation!_____________@\MessageBreak%
  @__________________________________________________@\MessageBreak%
  @_See_the_transcript_file__________________________@\MessageBreak%
  @___``\jobname.log''\MessageBreak%
  @_for_additional_information_about_which_anima-____@\MessageBreak%
  @_tion(s)_are_affected!____________________________@\MessageBreak%
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%
}%
\endgroup

%detects multiple inclusion of the same transparency
\def\@anim@findmult#1.#2,#3\@nil{%
  \ifthenelse{\equal{#2}{}}{}{%
    \@anim@newkey{u@tr#2}{}% mark current transp. as `used'
    \ifcsname m@tr#2\endcsname%
      \PackageWarning{animate}{%
        Transparency #2 more than once included in frame #1.%
        \MessageBreak%
        Timeline ``\@anim@tmlnfile'' on input line \the\@anim@lineno,%
        \MessageBreak\jobname.tex%
      }%
      \ifcsname @anim@multwarned\endcsname\else%
        \AtEndDocument{%
          \PackageWarningNoLine{animate}{\@anim@multwarning}%
        }%
        \gdef\@anim@multwarned{}%
      \fi%
    \else%
      {\expandafter\xdef\csname m@tr#2\endcsname{}}%
    \fi%
  }%
  \ifthenelse{\equal{#3}{}}{}{%
    \@anim@findmult#1.#3\@nil%
  }%
}
%reset transparency list
\def\@anim@resetmult#1.#2,#3\@nil{%
  \ifthenelse{\equal{#2}{}}{}{%
    {\expandafter\global\expandafter\let\csname m@tr#2\endcsname\@undefined}%
  }%
  \ifthenelse{\equal{#3}{}}{}{%
    \@anim@resetmult#1.#3\@nil%
  }%
}

%command options
\define@key{anim@user}{label}{%
  \gdef\@anim@label{#1}%
  \ifcsname @anim@#1\endcsname%
    \PackageWarning{animate}{Label #1 multiply defined}
    \ifdefined\@anim@multlabel\else
      \gdef\@anim@multlabel{}%
      \AtEndDocument{%
        \PackageWarningNoLine{animate}{%
        @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak
        @@ There were multiply-defined labels! @@\MessageBreak
        @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}%
      }%
    \fi%
  \fi%
  \expandafter\gdef\csname  @anim@#1\endcsname{}%
}
%setting the widget size
\define@key{anim@user}{width}{%
  \gdef\@anim@widtharg{#1}%
  \ifdefined\@anim@usrwd\else%
    \global\advance\@anim@resizeflags by 4%
    \def\@anim@usrwd{}%
  \fi%
}
\define@key{anim@user}{height}{%
  \gdef\@anim@heightarg{#1}%
  \ifdefined\@anim@usrht\else%
    \global\advance\@anim@resizeflags by 2%
    \def\@anim@usrht{}%
  \fi%
}
\define@key{anim@user}{totalheight}{%
  \gdef\@anim@totheightarg{#1}%
  \ifdefined\@anim@usrtht\else%
    \global\advance\@anim@resizeflags by \@ne%
    \def\@anim@usrtht{}%
  \fi%
}
\define@key{anim@user}{depth}{%
  \PackageWarning{animate}{Ignoring obsolete `depth' option.}%
}
\newboolean{@anim@iso}
\define@key{anim@user}{keepaspectratio}[true]{%
  \setboolean{@anim@iso}{#1}%
}
\define@key{anim@user}{scale}{%
  \gdef\@anim@boxscale{#1}%
}
\define@key{anim@user}{buttonsize}{%
  \gdef\@anim@btnsize{#1}%
}
\def\@anim@colours#1:#2\@nil{% helper macro to get number of colour components
  \xdef\@anim@colour{\@anim@colour\space #1}% and to replace : by ` ' in the arg
  \ifthenelse{\equal{#2}{}}{}{%
    \global\advance\@anim@tmpcnt by \@ne%
    \@anim@colours#2\@nil%
  }%
}
\define@key{anim@user}{buttonbg}{%background colour of buttons
  \global\@anim@tmpcnt=\@ne%
  \gdef\@anim@colour{}%
  \@anim@colours#1:\@nil%
  \xdef\@anim@bgcolour{\@anim@colour}%
  \if@anim@dvips
    \ifnum\@anim@tmpcnt=\@ne\relax%
      \xdef\@anim@bg{\@anim@colour\space setgray}%
    \else%
      \ifnum\@anim@tmpcnt=3\relax%
        \xdef\@anim@bg{\@anim@colour\space setrgbcolor}%
      \else%
        \ifnum\@anim@tmpcnt=4\relax%
          \xdef\@anim@bg{\@anim@colour\space setcmykcolor}%
        \fi%
      \fi%
    \fi%
  \else% pdftex and dvipdfmx
    \ifnum\@anim@tmpcnt=\@ne\relax%
      \xdef\@anim@bg{\@anim@colour\space g}%
    \else%
      \ifnum\@anim@tmpcnt=3\relax%
        \xdef\@anim@bg{\@anim@colour\space rg}%
      \else%
        \ifnum\@anim@tmpcnt=4\relax%
          \xdef\@anim@bg{\@anim@colour\space k}%
        \fi%
      \fi%
    \fi%
  \fi%
}
\define@key{anim@user}{buttonfg}{%stroking colour of buttons
  \global\@anim@tmpcnt=\@ne%
  \gdef\@anim@colour{}%
  \@anim@colours#1:\@nil%
  \xdef\@anim@fgcolour{\@anim@colour}%
  \if@anim@dvips
    \ifnum\@anim@tmpcnt=\@ne\relax%
      \xdef\@anim@fg{\@anim@colour\space setgray}%
    \else%
      \ifnum\@anim@tmpcnt=3\relax%
        \xdef\@anim@fg{\@anim@colour\space setrgbcolor}%
      \else%
        \ifnum\@anim@tmpcnt=4\relax%
          \xdef\@anim@fg{\@anim@colour\space setcmykcolor}%
        \fi%
      \fi%
    \fi%
  \else% pdftex and dvipdfmx
    \ifnum\@anim@tmpcnt=\@ne\relax%
      \xdef\@anim@fg{\@anim@colour\space G}%
      \xdef\@anim@@@fg{\@anim@colour\space g}%
    \else%
      \ifnum\@anim@tmpcnt=3\relax%
        \xdef\@anim@fg{\@anim@colour\space RG}%
        \xdef\@anim@@@fg{\@anim@colour\space rg}%
      \else%
        \ifnum\@anim@tmpcnt=4\relax%
          \xdef\@anim@fg{\@anim@colour\space K}%
          \xdef\@anim@@@fg{\@anim@colour\space k}%
        \fi%
      \fi%
    \fi%
  \fi%
}
\newboolean{@anim@controls}
\define@key{anim@user}{controls}[true]{%
  \setboolean{@anim@controls}{#1}%
}
\newboolean{@anim@loop}
\define@key{anim@user}{loop}[true]{%
  \setboolean{@anim@loop}{#1}%
}
\newboolean{@anim@autoplay}
\define@key{anim@user}{autoplay}[true]{%
  \setboolean{@anim@autoplay}{#1}%
  \if@anim@autoplay%
    \setboolean{@anim@autoresume}{false}%
  \fi%
}
\newboolean{@anim@autoresume}
\define@key{anim@user}{autoresume}[true]{%
  \setboolean{@anim@autoresume}{#1}%
  \if@anim@autoresume%
    \setboolean{@anim@autoplay}{false}%
  \fi%
}
\newboolean{@anim@autopause}
\define@key{anim@user}{autopause}[true]{%
  \setboolean{@anim@autopause}{#1}%
}
\newboolean{@anim@palindrome}
\define@key{anim@user}{palindrome}[true]{%
  \setboolean{@anim@palindrome}{#1}%
}
\def\@anim@mone{-1}\def\@anim@mtwo{-2}
\define@key{anim@user}{poster}[first]{% <num> | first | last | none
  \ifthenelse{%
    \equal{#1}{first}%
  }{%
    \gdef\@anim@poster{0}%
  }{%
    \ifthenelse{%
      \equal{#1}{last}%
    }{%
      \gdef\@anim@poster{-1}%
    }{%
      \ifthenelse{%
        \equal{#1}{none}%
      }{%
        \gdef\@anim@poster{-2}%
      }{%
        \ifnum#1<\z@\relax%
          \PackageError{animate}{%
            Poster frame `#1' is out-of-bounds on\MessageBreak%
            input line \the\inputlineno.\MessageBreak%
            Try one of `poster=first' or `poster=none'%
          }{}%
        \fi%
        \gdef\@anim@poster{#1}%
      }%
    }%
  }%
}
\newboolean{@anim@step}
\define@key{anim@user}{step}[true]{%
  \setboolean{@anim@step}{#1}%
}
\newboolean{@anim@draft}
\define@key{anim@user}{draft}[true]{%
  \setboolean{@anim@draft}{#1}%
}
\define@key{anim@user}{final}[true]{%
  \ifthenelse{\equal{#1}{true}}{%
    \setboolean{@anim@draft}{false}%
  }{%
    \setboolean{@anim@draft}{true}%
  }%
}
\define@key{anim@user}{nomouse}[true]{%
  \ifthenelse{\equal{#1}{true}}{%
    \gdef\@anim@btnflag{65537}%
  }{}%
}
\define@key{anim@user}{timeline}{%
  \IfFileExists{#1}{%
    \xdef\@anim@tmlnfile{\expandafter\zap@finalspace\@filef@und\@nil}%
    \setboolean{@anim@timeline}{true}%
  }{%
    \PackageError{animate}{timeline file `#1' cannot be opened for reading%
    }{%
      Make sure file `#1' exists and is readable!%
    }%
  }%
}
\define@key{anim@user}{begin}{%
  \gdef\@anim@begin{#1}%
}
\define@key{anim@user}{end}{%
  \gdef\@anim@end{#1}%
}
\define@key{anim@user}{every}{% embed every #1th frame
  \ifnum#1<\@ne\relax\gdef\@anim@every{1}\else\gdef\@anim@every{#1}\fi%
}
\define@key{anim@user}{bb}{%
  \if@anim@grxloaded\g@addto@macro\@anim@gropts{, bb=#1}%
  \else\@anim@missing{graphicx}\fi%
}
\define@key{anim@user}{viewport}{%
  \if@anim@grxloaded\g@addto@macro\@anim@gropts{, viewport=#1}%
  \else\@anim@missing{graphicx}\fi%
}
\define@key{anim@user}{trim}{%
  \if@anim@grxloaded\g@addto@macro\@anim@gropts{, trim=#1}%
  \else\@anim@missing{graphicx}\fi%
}
\define@key{anim@user}{angle}{%
  \if@anim@grxloaded\g@addto@macro\@anim@gropts{, angle=#1}%
  \else\@anim@missing{graphicx}\fi%
}
\newboolean{@anim@meas}
\define@key{anim@user}{measure}[true]{%
  \setboolean{@anim@meas}{#1}%
}
\define@key{anim@user}{method}{%
  \ifthenelse{\equal{#1}{icon}}{%
    \def\@anim@method{\z@}%
  }{%
    \ifthenelse{\equal{#1}{widget}}{%
      \def\@anim@method{\@ne}%
    }{%
      \ifthenelse{\equal{#1}{ocg}}{%
        \def\@anim@method{\tw@}%
      }{}%
    }%
  }%
}
\define@key{anim@user}{useocg}[]{%
  \PackageError{animate}{%
    Option `useocg' has been removed.\MessageBreak%
    Use `method=ocg' instead%
  }{}%
}

\define@key{anim@user}{type}{\gdef\@anim@ftype{#1}}%

%macro to reset macros and booleans
\def\@anim@reset{%
  \gdef\@anim@label{}%
  \xdef\@anim@boxscale{\@anim@@boxscale}%
  \global\let\if@anim@iso=\if@anim@@iso%
  \global\@anim@resizeflags\@anim@@resizeflags%
  \global\let\@anim@widtharg\@anim@@widtharg%
  \global\let\@anim@heightarg\@anim@@heightarg%
  \global\let\@anim@totheightarg\@anim@@totheightarg%
  \let\@anim@usrwd\@anim@pkgwd%
  \let\@anim@usrht\@anim@pkght%
  \let\@anim@usrtht\@anim@pkgtht%
  \xdef\@anim@bg{\@anim@@bg}%
  \xdef\@anim@fg{\@anim@@fg}%
  \xdef\@anim@@@fg{\@anim@@@@fg}%
  \xdef\@anim@bgcolour{\@anim@@bgcolour}% default button colours
  \xdef\@anim@fgcolour{\@anim@@fgcolour}%
  \xdef\@anim@btnsize{\@anim@@btnsize}%
  \xdef\@anim@poster{\@anim@@poster}%
  \global\let\if@anim@controls=\if@anim@@controls%
  \global\let\if@anim@loop=\if@anim@@loop%
  \global\let\if@anim@autoplay=\if@anim@@autoplay%
  \global\let\if@anim@autoresume=\if@anim@@autoresume%
  \global\let\if@anim@autopause=\if@anim@@autopause%
  \global\let\if@anim@palindrome=\if@anim@@palindrome%
  \global\let\if@anim@step=\if@anim@@step%
  \global\let\if@anim@draft=\if@anim@@draft%
  \xdef\@anim@method{\@anim@@method}%
  \global\let\@anim@btnflag=\@anim@@btnflag%
  \gdef\@anim@properties{}%
  \setboolean{@anim@pauseframes}{false}%
  \gdef\@anim@pauseat{}%
  \setboolean{@anim@chfps}{false}%
  \setboolean{@anim@usrjs}{false}%
  \gdef\@anim@nfpsat{}%
  \gdef\@anim@pfpsat{}%
  \gdef\@anim@usrjsat{}%
  \gdef\@anim@tmlnfile{}%
  \setboolean{@anim@timeline}{false}%
  \gdef\@anim@begin{}%
  \gdef\@anim@end{}%
  \gdef\@anim@every{1}% frames to be included
  \gdef\@anim@gropts{}%
  \setboolean{@anim@multipage}{false}%
  \setboolean{@anim@meas}{false}%
  \setboolean{@anim@autoplayorresume}{false}%
  \setboolean{@anim@morejs}{false}%
  \xdef\@anim@ftype{\@anim@@ftype}%
}

%package options
\define@key{anim@pkg}{dvips}[]{%
  \ifthenelse{\equal{#1}{}}{}{%
    \PackageError{animate}{%
      Package option `dvips' does not accept arguments%
    }{}%
  }%
}%
\define@key{anim@pkg}{dvipdfmx}[]{
  \ifthenelse{\equal{#1}{}}{}{%
    \PackageError{animate}{%
      Package option `dvipdfmx' does not accept arguments%
    }{}%
  }%
}%
\define@key{anim@pkg}{xetex}[]{
  \ifthenelse{\equal{#1}{}}{}{%
    \PackageError{animate}{%
      Package option `xetex' does not accept arguments%
    }{}%
  }%
}%
\def\@anim@@bg{}
\def\@anim@@bgcolour{}
\define@key{anim@pkg}{buttonbg}{%background colour of buttons
  \global\@anim@tmpcnt=\@ne%
  \gdef\@anim@colour{}%
  \@anim@colours#1:\@nil%
  \xdef\@anim@@bgcolour{\@anim@colour}%
  \if@anim@dvips
    \ifnum\@anim@tmpcnt=\@ne\relax%
      \xdef\@anim@@bg{\@anim@colour\space setgray}%
    \else%
      \ifnum\@anim@tmpcnt=3\relax%
        \xdef\@anim@@bg{\@anim@colour\space setrgbcolor}%
      \else%
        \ifnum\@anim@tmpcnt=4\relax%
          \xdef\@anim@@bg{\@anim@colour\space setcmykcolor}%
        \fi%
      \fi%
    \fi%
  \else% pdftex and dvipdfmx
    \ifnum\@anim@tmpcnt=\@ne\relax%
      \xdef\@anim@@bg{\@anim@colour\space g}%
    \else%
      \ifnum\@anim@tmpcnt=3\relax%
        \xdef\@anim@@bg{\@anim@colour\space rg}%
      \else%
        \ifnum\@anim@tmpcnt=4\relax%
          \xdef\@anim@@bg{\@anim@colour\space k}%
        \fi%
      \fi%
    \fi%
  \fi%
}
\if@anim@dvips
  \def\@anim@@fg{0 setgray}\def\@anim@@@@fg{}%
\else% pdftex and dvipdfmx
  \def\@anim@@fg{0 G}\def\@anim@@@@fg{0 g}%
\fi
\def\@anim@@fgcolour{}
\define@key{anim@pkg}{buttonfg}{%stroking colour of buttons
  \global\@anim@tmpcnt=\@ne%
  \gdef\@anim@colour{}%
  \@anim@colours#1:\@nil%
  \xdef\@anim@@fgcolour{\@anim@colour}%
  \if@anim@dvips%
    \ifnum\@anim@tmpcnt=\@ne\relax%
      \xdef\@anim@@fg{\@anim@colour\space setgray}%
    \else%
      \ifnum\@anim@tmpcnt=3\relax%
        \xdef\@anim@@fg{\@anim@colour\space setrgbcolor}%
      \else%
        \ifnum\@anim@tmpcnt=4\relax%
          \xdef\@anim@@fg{\@anim@colour\space setcmykcolor}%
        \fi%
      \fi%
    \fi%
  \else% pdftex and dvipdfmx
    \ifnum\@anim@tmpcnt=\@ne\relax%
      \xdef\@anim@@fg{\@anim@colour\space G}%
      \xdef\@anim@@@@fg{\@anim@colour\space g}%
    \else%
      \ifnum\@anim@tmpcnt=3\relax%
        \xdef\@anim@@fg{\@anim@colour\space RG}%
        \xdef\@anim@@@@fg{\@anim@colour\space rg}%
      \else%
        \ifnum\@anim@tmpcnt=4\relax%
          \xdef\@anim@@fg{\@anim@colour\space K}%
          \xdef\@anim@@@@fg{\@anim@colour\space k}%
        \fi%
      \fi%
    \fi%
  \fi%
}
\newcount\@anim@@resizeflags
\def\@anim@@widtharg{\width}%
\define@key{anim@pkg}{width}{%
  \def\@anim@@widtharg{#1}%
  \ifdefined\@anim@pkgwd\else%
    \advance\@anim@@resizeflags by 4%
    \def\@anim@pkgwd{}%
  \fi%
}
\def\@anim@@heightarg{\height}%
\define@key{anim@pkg}{height}{%
  \def\@anim@@heightarg{#1}%
  \ifdefined\@anim@pkght\else%
    \advance\@anim@@resizeflags by 2%
    \def\@anim@pkght{}%
  \fi%
}
\def\@anim@@totheightarg{\totalheight}%
\define@key{anim@pkg}{totalheight}{%
  \def\@anim@@totheightarg{#1}%
  \ifdefined\@anim@pkgtht\else%
    \advance\@anim@@resizeflags by \@ne%
    \def\@anim@pkgtht{}%
  \fi%
}
\newboolean{@anim@@iso}
\define@key{anim@pkg}{keepaspectratio}[true]{%
  \setboolean{@anim@@iso}{#1}%
}
\def\@anim@@boxscale{1}%
\define@key{anim@pkg}{scale}{%
  \def\@anim@@boxscale{#1}%
}
\def\@anim@@btnsize{1.44em}%
\define@key{anim@pkg}{buttonsize}{%
  \gdef\@anim@@btnsize{#1}%
}
\newboolean{@anim@@controls}
\setboolean{@anim@@controls}{false}%
\define@key{anim@pkg}{controls}[true]{%
  \setboolean{@anim@@controls}{#1}%
}
\newboolean{@anim@@loop}
\setboolean{@anim@@loop}{false}%
\define@key{anim@pkg}{loop}[true]{%
  \setboolean{@anim@@loop}{#1}%
}
\newboolean{@anim@@autoplay}
\setboolean{@anim@@autoplay}{false}
\define@key{anim@pkg}{autoplay}[true]{%
  \setboolean{@anim@@autoplay}{#1}%
  \if@anim@@autoplay\setboolean{@anim@@autoresume}{false}\fi%
}
\newboolean{@anim@@autoresume}
\setboolean{@anim@@autoresume}{false}
\define@key{anim@pkg}{autoresume}[true]{%
  \setboolean{@anim@@autoresume}{#1}%
  \if@anim@@autoresume\setboolean{@anim@@autoplay}{false}\fi%
}
\newboolean{@anim@@autopause}
\setboolean{@anim@@autopause}{false}
\define@key{anim@pkg}{autopause}[true]{%
  \setboolean{@anim@@autopause}{#1}%
}
\newboolean{@anim@@palindrome}
\setboolean{@anim@@palindrome}{false}
\define@key{anim@pkg}{palindrome}[true]{%
  \setboolean{@anim@@palindrome}{#1}%
}
\gdef\@anim@@poster{0}%
\define@key{anim@pkg}{poster}[first]{%
  \ifthenelse{%
    \equal{#1}{first}%
  }{%
    \gdef\@anim@@poster{0}%
  }{%
    \ifthenelse{%
      \equal{#1}{last}%
    }{%
      \gdef\@anim@@poster{-1}%
    }{%
      \ifthenelse{%
        \equal{#1}{none}%
      }{%
        \gdef\@anim@@poster{-2}%
      }{%
        \ifnum#1<\z@\relax%
          \PackageError{animate}{%
            Poster frame `#1' is out-of-bounds on\MessageBreak%
            input line \the\inputlineno.\MessageBreak%
            Try one of `poster=first' or `poster=none'%
          }{}%
        \fi%
        \gdef\@anim@@poster{#1}%
      }%
    }%
  }%
}
\newboolean{@anim@@step}
\setboolean{@anim@@step}{false}
\define@key{anim@pkg}{step}[true]{%
  \setboolean{@anim@@step}{#1}%
}
\newboolean{@anim@@draft}
\ifdraft{%globally set by document class
  \setboolean{@anim@@draft}{true}%
}{%
  \setboolean{@anim@@draft}{false}%
}%
\define@key{anim@pkg}{draft}[true]{%
  \setboolean{@anim@@draft}{#1}%
}
\define@key{anim@pkg}{final}[true]{%
  \ifthenelse{\equal{#1}{true}}{%
    \setboolean{@anim@@draft}{false}%
  }{%
    \setboolean{@anim@@draft}{true}%
  }%
}
\def\@anim@@btnflag{65536}%
\define@key{anim@pkg}{nomouse}[true]{%
  \ifthenelse{\equal{#1}{true}}{%
    \gdef\@anim@@btnflag{65537}%
  }{}%
}

%file type (extension) of graphics files  to be embedded
\def\@anim@@ftype{}%
\define@key{anim@pkg}{type}{\def\@anim@@ftype{#1}}%

% animation method: icon vs. widget vs. ocg based
\define@key{anim@pkg}{method}{%
  \ifthenelse{\equal{#1}{icon}}{%
    \def\@anim@@method{\z@}%
  }{%
    \ifthenelse{\equal{#1}{widget}}{%
      \def\@anim@@method{\@ne}%
    }{%
      \ifthenelse{\equal{#1}{ocg}}{%
        \def\@anim@@method{\tw@}%
      }{}% ignoring wrong input
    }%
  }%
}
\define@key{anim@pkg}{useocg}[]{%
  \PackageError{animate}{%
    Package option `useocg' has been removed.\MessageBreak%
    Use `method=ocg' instead%
  }{}%
}

%default animation method is Icon based, except for dvips
\def\@anim@@method{\z@}
\ifpdf\else\if@anim@dvipdfmx\else % dvips, by default, uses Widget based method
  \def\@anim@@method{\@ne}
\fi\fi

%process package options
\def\@anim@setpkgkeys#1{\setkeys{anim@pkg}{#1}}
\edef\@anim@pkgopts{{\@ptionlist{\@currname.\@currext}}}
\expandafter\@anim@setpkgkeys\@anim@pkgopts

%JavaScript objects
%animation widget's PageOpen event
\def\@anim@pojscript#1{%
  \@anim@streamobj{}{\@anim@@pojscript{#1}}%
  \xdef\@anim@pojscriptobj{\@anim@lastobj}%
}
\def\@anim@@pojscript#1{% #1: @anim@num
%  console.show();%
%  console.clear();%
  var curdoc=this;%
  var a#1,a#1_int;%
  if(typeof a#1==='undefined'){% initialize animation
    a#1=new Object();% animation object
    %takes references to frame ocgs/Field objects belonging to the current
    %animation
    a#1.fr=new Array();%
    %initialize fr properties
    \ifcase\@anim@method %icon based
      var spc=String.fromCharCode(32);%
      if(typeof this.getIcon==='undefined'){%
        app.alert('Icon-based'+spc+'animation'+spc+'is'+spc+'not'+spc+%
          'supported'+spc+'by'+spc+'this'+spc+'Reader.'+spc+'Try'+spc+%
          'one'+spc+'of'+spc+'"method=widget"'+spc+'or'+spc+%
          '"method=useocg"'+spc+'options.');%
      }%
      a#1.wid=this.getField('anm#1');%reference to interactive widget
      for(i=0;i<=\@anim@maxframe;i++){%
        a#1.fr[i]=this.getIcon(util.printf('\@anim@pad{1234}{#1}.\%04d',i));%
      }%
      \ifnum\@anim@poster=\@anim@mtwo
        if(typeof blnk==='undefined'){% blank poster
          blnk=this.getIcon('0000');%
        }%
      \fi%
    \or %widget based
      %get array of animation frames
      for(i=0;i<=\@anim@maxframe;i++){%
        a#1.fr[i]=this.getField('#1.'+i);%
      }%
    \or %ocg based
      %get array of ocgs of current page
      var ocg=this.getOCGs(this.pageNum);%
      for(var i in ocg){%
        var ocgName=ocg[i].name.split('.');%
        if(ocgName[0]==#1){%
          %get array of animation frames
          a#1.fr[ocgName[1]]=ocg[i];%
          %set basic frame state
          a#1.fr[ocgName[1]].state=ocg[i].initState;%
        }%
      }%
    \fi%
    \if@anim@controls\if@anim@step\else
      a#1.btnPauseLeft=this.getField('#1.PauseLeft');%
      a#1.btnPlayLeft=this.getField('#1.PlayLeft');%
      a#1.btnPauseRight=this.getField('#1.PauseRight');%
      a#1.btnPlayRight=this.getField('#1.PlayRight');%
    \fi\fi%
    %playing state and direction
    \if@anim@step
      \if@anim@palindrome a#1.playsRight=true;\fi%
    \else%
      \if@anim@morejs a#1.playsRight=true;\fi%
    \fi%
    a#1.isPaused=false;%
    \if@anim@step\else
      a#1.playing=false;%
      \if@anim@pauseframes
        %this array takes the frame numbers at which to pause playback
        a#1.pauseAt=new Array();%
        \@anim@pauseat%
      \fi%
      \if@anim@chfps
        %arrays that take frame numbers (array index) and fps values
        a#1.nFpsAt=new Array(\@anim@nfpsat);%
      \fi
      a#1.fps=\@anim@fps;a#1.sm=1;%
      a#1.setFps=function(f){%
        a#1.fps=f;%
        if(a#1.playing){%
          \if@anim@morejs
            if(a#1.playsRight){a#1.playRight();}else{a#1.playLeft();}%
          \else
            a#1.playRight();%
          \fi%
        }%
      };%
    \fi%
    \if@anim@usrjs
      %array to take frame numbers (array index) and user provided JavaScript
      a#1.usrJSat=new Array();%
      \@anim@usrjsat%
    \fi%
    %actions
    a#1.seekFrame=function(f){%
      \ifnum\@anim@poster=\@anim@mtwo
        if(f<-1){%
          \ifcase\@anim@method %icon based
            a#1.wid.buttonSetIcon(blnk);%
            curdoc.dirty=false;%
          \or %widget based
            a#1.on=0;%
            a#1.fr[0].display=display.hidden;%
            curdoc.dirty=false;%
          \or %ocg based
            a#1.on=0;%
            a#1.fr[0].state=false;%
          \fi
          a#1.idx=-1;%
        }%
      \fi
      if(f>\@anim@maxframe||f<0){return -1;}%
      a#1.idx=f;%
      \if@anim@usrjs
        if(a#1.usrJSat[f]){%
          var cmd='try{a#1.usrJSat['+f+']();}catch(e){console.println(e);}';%
          var ret=app.setTimeOut(cmd,1);%
        }%
      \fi%
      \ifcase\@anim@method %icon based
        a#1.wid.buttonSetIcon(a#1.fr[f]);%
        curdoc.dirty=false;%
      \or %widget based
        a#1.fr[a#1.on].display=display.hidden;%
        a#1.fr[f].display=display.visible;%
        a#1.on=f;%
        curdoc.dirty=false;%
      \or %ocg based
        a#1.fr[a#1.on].state=false;%
        a#1.fr[f].state=true;%
        a#1.on=f;%
      \fi
      \if@anim@step\else%
        \if@anim@chfps
          if(a#1.nFpsAt[f]!=a#1.fps){%
            a#1.setFps(a#1.nFpsAt[f]);%
          }%
        \fi%
      \fi%
      \if@anim@step\else\if@anim@meas a#1.frcnt++;\fi\fi%
      return 0;%
    };%
    a#1.stopFirst=function(){%
      \if@anim@step
        a#1.isPaused=false;% stop
      \else
        a#1.pause(true);% stop
      \fi
      a#1.seekFrame(0);%
    };%
    a#1.stopLast=function(){%
      \if@anim@step
        a#1.isPaused=false;% stop
      \else
        a#1.pause(true);% stop
      \fi
      a#1.seekFrame(\@anim@maxframe);%
    };%
    a#1.gotoNext=function(){%
      if(a#1.seekFrame(a#1.idx+1)<0){%
        \if@anim@step\else\if@anim@meas a#1.stopMeas();\fi\fi%
        \if@anim@palindrome%
          \if@anim@step
            a#1.stopLast();%
            a#1.playsRight=false;%
          \else
            if(a#1.playing){%
              a#1.seekFrame(a#1.idx-1);%
              a#1.playLeft();%
            }%
          \fi%
        \else%
          \if@anim@step
            a#1.stopLast();%
          \else%
            \if@anim@loop
              if(a#1.playing){%
                a#1.seekFrame(0);%
                a#1.setFps(\@anim@fps);%
              }else{a#1.stopLast();}%
            \else
              a#1.stopLast();%
            \fi%
          \fi%
        \fi
        return;%
      }%
      \if@anim@step\else%
        \if@anim@pauseframes
          if(a#1.playing&&a#1.pauseAt[a#1.idx]){a#1.pause();}%
        \fi%
      \fi%
    };%
    \if@anim@morejs
      a#1.gotoPrev=function(){%
        if(a#1.seekFrame(a#1.idx-1)<0){%
          \if@anim@step\else\if@anim@meas a#1.stopMeas();\fi\fi%
          \if@anim@palindrome%
            \if@anim@step
              a#1.stopFirst();%
              a#1.playsRight=true;%
            \else
              if(a#1.playing){%
                a#1.seekFrame(a#1.idx+1);%
                a#1.playRight();%
              }%
            \fi%
          \else%
            \if@anim@step
              a#1.stopFirst();%
            \else%
              \if@anim@loop
                if(a#1.playing){%
                  a#1.seekFrame(\@anim@maxframe);%
                }else{a#1.stopFirst();}%
              \else
                a#1.stopFirst();%
              \fi%
            \fi%
          \fi
          return;%
        }%
        \if@anim@step\else%
          \if@anim@pauseframes
            if(a#1.playing&&a#1.pauseAt[a#1.idx]){a#1.pause();}%
          \fi%
        \fi%
      };%
    \fi%
    \if@anim@step\else
      a#1.pause=function(stop){%
        try{app.clearInterval(a#1_int);}catch(e){}%
        a#1.playing=false;%
        a#1.isPaused=!stop;%
        \if@anim@controls
          a#1.btnPauseLeft.display=display.hidden;%
          a#1.btnPlayLeft.display=display.visible;%
          a#1.btnPauseRight.display=display.hidden;%
          a#1.btnPlayRight.display=display.visible;%
          curdoc.dirty=false;%
        \fi%
      };%
      a#1.playRight=function(){%
        try{app.clearInterval(a#1_int);}catch(e){}%
        \if@anim@morejs a#1.playsRight=true;\fi
        a#1.playing=true;%
        a#1.isPaused=false;%
        \if@anim@controls
          a#1.btnPauseLeft.display=display.visible;%
          a#1.btnPlayLeft.display=display.hidden;%
          a#1.btnPauseRight.display=display.visible;%
          a#1.btnPlayRight.display=display.hidden;%
          curdoc.dirty=false;%
        \fi%
        \if@anim@meas a#1.startMeas();\fi
        a#1_int=app.setInterval('a#1.gotoNext()',%
          1000/(1e-6+a#1.fps)/a#1.sm);%
      };%
      \if@anim@morejs
        a#1.playLeft=function(){%
          try{app.clearInterval(a#1_int);}catch(e){}%
          a#1.playsRight=false;%
          a#1.playing=true;%
          a#1.isPaused=false;%
          \if@anim@controls
            a#1.btnPauseLeft.display=display.visible;%
            a#1.btnPlayLeft.display=display.hidden;%
            a#1.btnPauseRight.display=display.visible;%
            a#1.btnPlayRight.display=display.hidden;%
            curdoc.dirty=false;%
          \fi%
          \if@anim@meas a#1.startMeas();\fi
          a#1_int=app.setInterval('a#1.gotoPrev()',%
          1000/(1e-6+a#1.fps)/a#1.sm);%
        };%
      \fi%
      \if@anim@controls
        a#1.fpsIncr=function(){% speed up animation
          a#1.sm*=1.1;%
          a#1.setFps(a#1.fps);%
        };%
        a#1.fpsDecr=function(){% slow down animation
          a#1.sm/=1.1;%
          a#1.setFps(a#1.fps);%
        };%
        a#1.fpsReset=function(){% reset to default speed
          a#1.sm=1;%
          a#1.setFps(a#1.fps);%
        };%
      \fi%
      \if@anim@meas
        var spc=String.fromCharCode(32);%
        a#1.frcnt=1;% frame counter for speed measurements
        a#1.msStart=0;% takes start time (in millisecs)
        a#1.msEnd=0;% takes end time (in millisecs)
        a#1.startMeas=function(){%
          a#1.frcnt=1;% reset frame counter
          a#1.msStart=(new Date()).getTime();%
        };%
        a#1.stopMeas=function(){%
          a#1.msEnd=(new Date()).getTime();%
          console.show();console.println(%
            'av.'+spc+'frame'+spc+'rate:'+spc+%
            1e3*a#1.frcnt/(a#1.msEnd-a#1.msStart)+spc+'fps'%
          );%
        };%
      \fi%
    \fi%
    \if@anim@morejs%
      \if@anim@step
        a#1.stepBwd=function(){%
          a#1.seekFrame(a#1.idx-1);%
          a#1.isPaused=true;%
        };%
        a#1.stepFwd=function(){%
          a#1.seekFrame(a#1.idx+1);%
          a#1.isPaused=true;%
        };%
      \else
        a#1.stepBwd=function(){if(!a#1.playing){%
          a#1.seekFrame(a#1.idx-1);%
          a#1.isPaused=true;%
        }};%
        a#1.stepFwd=function(){if(!a#1.playing){%
          a#1.seekFrame(a#1.idx+1);%
          a#1.isPaused=true;%
        }};%
        a#1.playBwd=function(){%
          if(a#1.idx==0||!a#1.isPaused){a#1.stopLast();}%
          a#1.playLeft();%
        };%
        a#1.playFwd=function(){%
          if(a#1.idx==\@anim@maxframe||!a#1.isPaused){a#1.stopFirst();}%
          a#1.playRight();%
        };%
      \fi%
    \fi%
    %animation API for labelled anims
    \ifx\empty\@anim@label\empty\else
      if(typeof anim==='undefined'){anim=new Array();}%
      if(typeof anim['\@anim@label']==='undefined'){%
        anim['\@anim@label']={%
          \if@anim@step\else
            playBwd:a#1.playBwd,%
            playFwd:a#1.playFwd,%
            pause:a#1.pause,%
            get isPlaying(){return a#1.playing;},%
            get fps(){return a#1.fps;},%
            set fps(f){%
              if(f<0||isNaN(f)){%
                throw new RangeError('Frame_rate_not_in_allowed_range');%
              }else{a#1.setFps(f);}%
            },%
            get dt(){return 1000/(1e-6+a#1.fps)/a#1.sm;},%
            get playsFwd(){return a#1.playsRight;},%
          \fi
          get numFrames(){return \@anim@frames;},%
          get frameNum(){return a#1.idx;},%
          set frameNum(f){%
            f=Math.floor(f);%
            if(f<0||f>\@anim@maxframe||isNaN(f)){%
              throw new RangeError('Frame_number_not_in_allowed_range');%
            }%
            \if@anim@step
              if(a#1.seekFrame(f)>-1)a#1.isPaused=true;%
            \else
              if(a#1.playing){%
                a#1.pause();a#1.seekFrame(f);%
                if(a#1.playsRight){a#1.playRight();}else{a#1.playLeft();}%
              }else{if(a#1.seekFrame(f)>-1)a#1.isPaused=true;}%
            \fi%
          },%
          stopFirst:a#1.stopFirst,%
          stopLast:a#1.stopLast%
        };%
      }%
    \fi%
    \ifnum\@anim@poster=\@anim@mtwo %poster=none
      a#1.idx=-1;\ifnum\@anim@method>\z@ a#1.on=0;\fi%
    \fi%
    \ifnum\@anim@poster>\@anim@mone %poster=<num>|first
      a#1.idx=\ifnum\@anim@method>\z@ a#1.on=\fi\@anim@poster;%
    \fi%
    \ifnum\@anim@poster=\@anim@mone %poster=last
      a#1.idx=\ifnum\@anim@method>\z@ a#1.on=\fi\@anim@maxframe;%
    \fi%
  }%
  \if@anim@step\else%
    \if@anim@autoplayorresume%
      \if@anim@autoresume
        if(a#1.isPaused){%
      \fi%
        \if@anim@morejs
          if(a#1.playsRight){a#1.playRight();}else{a#1.playLeft();}%
        \else
          a#1.playRight();%
        \fi%
      \if@anim@autoresume%
        }%
      \fi%
    \fi%
  \fi%
}

%other trigger events in the anim widget's AA dictionary
\def\@anim@otherjscript#1{%
  \xdef\@anim@otherjscriptkey{%
    /PC <</S/JavaScript/JS (% PageClose
      \if@anim@step%
        \if@anim@palindrome a#1.playsRight=true;\fi%
      \else
        if(a#1.playing){
          \if@anim@autopause
            a#1.pause();%
          \else
            a#1.pause(true);% stop
          \fi%
        }%
        \if@anim@morejs if(!a#1.isPaused)a#1.playsRight=true;\fi%
      \fi
      %re-display poster frame
      if(!a#1.isPaused){% i.e. if stopped
        \ifnum\@anim@poster=\@anim@mtwo %poster=none
          var ret=app.setTimeOut('a#1.seekFrame(-2)',1);%
        \fi%
        \ifnum\@anim@poster>\@anim@mone %poster=<num>|first
          var ret=app.setTimeOut('a#1.seekFrame(\@anim@poster)',1);%
        \fi%
        \ifnum\@anim@poster=\@anim@mone %poster=last
          var ret=app.setTimeOut('a#1.seekFrame(\@anim@maxframe)',1);%
        \fi%
      }%
    )>>%
    /D <</S/JavaScript/JS (%
      app.focusRect=false;% disable focus rectangle
      \if@anim@step\else % pause on MouseDown
        try{if(a#1.playing){a#1.pause();}}catch(e){}%
      \fi%
    )>>%
    /U <</S/JavaScript/JS (% play/resume on MouseUp
      try{%
        \if@anim@step%
          \if@anim@palindrome
            if(a#1.idx==\@anim@maxframe){%
              a#1.playsRight=false;%
            }else if(a#1.idx==0){%
              a#1.playsRight=true;%
            }%
            if(a#1.playsRight){%
              a#1.gotoNext();%
            }else{%
              a#1.gotoPrev();%
            }%
          \else
            if(a#1.idx==\@anim@maxframe){%
              a#1.stopFirst();%
            }else{%
              a#1.gotoNext();%
            }%
          \fi
          a#1.isPaused=true;%
        \else
          if(!a#1.isPaused)a#1.stopFirst();%
          \if@anim@morejs%
            \if@anim@palindrome
              if(a#1.idx==0)a#1.playsRight=true;%
              if(a#1.idx==\@anim@maxframe)a#1.playsRight=false;%
            \else
              if(a#1.idx==\@anim@maxframe&&a#1.playsRight)a#1.stopFirst();%
              if(a#1.idx==0&&!a#1.playsRight)a#1.stopLast();%
            \fi
            if(a#1.playsRight){%
              a#1.playRight();%
            }else{%
              a#1.playLeft();%
            }%
          \else%
            \if@anim@loop\else
              if(a#1.idx==\@anim@maxframe){a#1.stopFirst();}%
            \fi
            a#1.playRight();%
          \fi%
        \fi%
      }catch(e){}%
    )>>%
  }%
}
%actions for control buttons
\def\@anim@upjscript#1#2{%
  \def\@anim@action{#2}%
  \def\@anim@EndLeft{EndLeft}%
  \def\@anim@StepLeft{StepLeft}%
  \def\@anim@PlayPauseLeft{PlayPauseLeft}%
  \def\@anim@PlayPauseRight{PlayPauseRight}%
  \def\@anim@StepRight{StepRight}%
  \def\@anim@EndRight{EndRight}%
  \def\@anim@Minus{Minus}%
  \def\@anim@Reset{Reset}%
  \def\@anim@Plus{Plus}%
  \xdef\@anim@upjscriptstring{%
    app.focusRect=false;%
    \ifx\@anim@action\@anim@EndLeft
      a#1.stopFirst();%
    \else%
    \ifx\@anim@action\@anim@StepLeft
      a#1.stepBwd();%
    \else%
    \ifx\@anim@action\@anim@PlayPauseLeft
      if(a#1.playing){a#1.pause();}else{a#1.playBwd();}%
    \else%
    \ifx\@anim@action\@anim@PlayPauseRight
      if(a#1.playing){a#1.pause();}else{a#1.playFwd();}%
    \else%
    \ifx\@anim@action\@anim@StepRight
      a#1.stepFwd();%
    \else%
    \ifx\@anim@action\@anim@EndRight
      a#1.stopLast();%
    \else%
    \ifx\@anim@action\@anim@Minus
      a#1.fpsDecr();%
    \else%
    \ifx\@anim@action\@anim@Reset
      a#1.fpsReset();%
    \else%
    \ifx\@anim@action\@anim@Plus
      a#1.fpsIncr();%
    \fi\fi\fi\fi\fi\fi\fi\fi\fi%
  }%
}
