summaryrefslogtreecommitdiff
path: root/macros/generic/boxedeps/boxedeps.tex
diff options
context:
space:
mode:
Diffstat (limited to 'macros/generic/boxedeps/boxedeps.tex')
-rw-r--r--macros/generic/boxedeps/boxedeps.tex1042
1 files changed, 1042 insertions, 0 deletions
diff --git a/macros/generic/boxedeps/boxedeps.tex b/macros/generic/boxedeps/boxedeps.tex
new file mode 100644
index 0000000000..038a7257f6
--- /dev/null
+++ b/macros/generic/boxedeps/boxedeps.tex
@@ -0,0 +1,1042 @@
+ %%
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%
+ %%%%% boxedeps.tex
+ %%%%% MACROS FOR FIGURE INSERTS OF EPSF NORM %%%%%
+ %%%%% (EPSF = Encapsulated PostScript File)
+ %%
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%
+ %%% AUTHOR: Laurent Siebenmann
+ %% lcs@topo.math.u-psud.fr
+ %%
+ %%% VERSIONS: Feb 1991 -- Nov 1995
+ %% Revisions bi-annual approx.
+ %%
+ %%% SOMMAIRE: boxedeps.tex d\'efinit des macro-commandes
+ %% qui permettent d'int\'egrer dans un document TeX des
+ %% objets graphiques d\'ecrits par fichier de norme EPSF,
+ %% tout en accordant a chacun le statut d'une bo\^ite TeX ayant
+ %% les bonnes dimensions. La (seule!) contribution unique
+ %% de ce fichier est de faire cela d'une fa{\c}con universelle.
+ %% C'est a dire de fa{\c}con \`a pouvoir commod\'ement
+ %% servir avec tout pilote d'imprimante de norme
+ %% PostScript --- malgr\'e l'absence d'une norme
+ %% pour \special.
+ %%
+ %%%% ACTIVATION:
+ %% by a driver-by-driver protocol
+ %% see \SetTexturesEPSFSpecial
+ %% and its companions below.
+ %%
+ %%%% DOCUMENTATION:
+ %% --- see boxedeps.doc
+ %% The complete utility is called BoxedEPSF but for
+ %% portability the nickname boxedeps is useful.
+ %%
+ %%%% POSTINGS: anonymous ftp
+ %% --- ftp matups.math.u-psud.fr [192.54.146.4]
+ %% is the master copy in 1995.
+ %% --- ftp.uni-stuttgart.de
+ %% --- ftp ftp.TeX.AC.UK
+ %% --- ftp ftp.SHSU.edu
+ %% Locate the full package on these three
+ %% "CTAN" servers by using (while connected) the command
+ %% QUOTE SITE INDEX boxedeps
+
+ %%%% RECENT ADDITIONS: \SetepsfEPSFSpecial simultaneously serves
+ %% dvips, the Y&Y drivers, DirectTeX, CMacTeX, OzTeX>=1.7
+ %% \SetOldOzTeXEPSFSpecial %% OzTeX 1.42--1.6x
+
+
+ \chardef\EPSFCatAt\the\catcode`\@
+ \catcode`\@=11
+
+ \chardef\C@tColon\the\catcode`\:
+ \chardef\C@tSemicolon\the\catcode`\;
+ \chardef\C@tQmark\the\catcode`\?
+ \chardef\C@tEmark\the\catcode`\!
+ \chardef\C@tDqt\the\catcode`\"
+
+ \def\PunctOther@{\catcode`\:=12
+ \catcode`\;=12 \catcode`\?=12 \catcode`\!=12 \catcode`\"=12}
+ \PunctOther@
+
+ %%%% MESSAGES (separate macro best for Europe)
+ %%
+ \def\ms@g{\immediate\write16}
+
+ %%%% Prevent double input
+ \let\EX@\expandafter
+
+ \ifx\BoxedArtundefined\relax
+ \ms@g{}\ms@g{ !!! Bad news.
+ \noexpand\BoxedEPSF or \noexpand\BoxedArt macros already input.}%
+ \ms@g{ !!! Hit RETURN to exit, or c and RETURN to forge bravely on.}%
+ {\endlinechar=-1\gdef\Temp{c}%
+ \global\read16 to \temp}%
+ \ifx\temp\Temp
+ \else
+ \EX@\EX@\EX@\end
+ \fi
+ \else
+ \global\let\BoxedArtundefined\relax
+ \fi
+
+
+
+ %%temporarily suppress Plain's logging of allocations
+ \let\wlog@ld\wlog
+ \def\wlog#1{\relax}
+
+ %% New for TOOLS
+ %\newif\ifIN@
+ \newdimen\XShift@ \newdimen\YShift@
+ \newtoks\Realtoks
+
+ %%% New for BoxedEPSF
+ %
+ \newdimen\Wd@ \newdimen\Ht@
+ \newdimen\Wd@@ \newdimen\Ht@@
+ %
+ \newdimen\TT@
+ \newdimen\LT@
+ \newdimen\BT@
+ \newdimen\RT@
+ %
+ \newdimen\XSlide@ \newdimen\YSlide@
+ %
+ \newdimen\TheScale %% secretly scale in mils: 1pt= 1mil
+ \newdimen\FigScale %% secretly scale in mils: 1pt= 1mil
+ %
+ \newdimen\ForcedDim@@
+
+ \newtoks\EPSFDirectorytoks@
+ \newtoks\EPSFNametoks@
+ \newtoks\BdBoxtoks@
+ \newtoks\LLXtoks@ %% useful info for Oz
+ \newtoks\LLYtoks@
+ \newtoks\URXtoks@ %% useful for epsf.tex syntax
+ \newtoks\URYtoks@
+
+
+ \newif\ifRepeat@
+ \newif\ifNotIn@
+ \newif\ifForcedDim@
+ \newif\ifForceOn@
+ \newif\ifForcedHeight@
+ \newif\ifPSOrigin
+ \newif\ifPCfmt@
+ \newif\ifPCfmtOK@
+
+
+ \newread\EPSFile@
+ \newwrite \epsf@log
+ \def\WrLog@{\immediate\write\epsf@log}
+
+ \gdef\InitLog@{%
+ \def\epsf@log@name{epsf.lst}%
+ \count255=\time\divide\count255 by 60
+ \edef\temp@{\the\count255}%
+ \multiply\count255 by -60\relax
+ \advance\count255 by \time
+ \immediate\openout\epsf@log \epsf@log@name
+ \WrLog@{ \pct@@\space boxedeps.tex log, date
+ \the\day-\the\month-\the\year,
+ time \temp@:\the\count255.}\WrLog@{}%
+ \ms@g{}\ms@g{ **** See file \epsf@log@name\space
+ for list of EPSFs integrated by boxedeps.tex}%
+ \global\let\InitLog@\relax}
+
+ \def\noArtList{\global\let\InitLog@\relax}
+ \let\noEPSFList\noArtList
+ \def\noArtReports{\global\let\ReportEPSF@\relax}
+ \let\noEPSFReports\noArtReports
+
+ %%%% WORD-PROCESSING MACROS
+ %%
+ %%% \IN@0#1@#2@ : Is 1st exp of #1 in 1st exp of #2 ??
+ %% Answer in \ifIN@
+ \newif\ifIN@\def\IN@{\EX@\INN@\EX@}
+ \long\def\INN@0#1@#2@{\long\def\NI@##1#1##2##3\ENDNI@
+ {\ifx\m@rker##2\IN@false\else\IN@true\fi}%
+ \EX@\NI@#2@@#1\m@rker\ENDNI@}
+ \def\m@rker{\m@@rker}
+
+ %%% \SPLIT@0#1@#2@ : Split 1st exp of #2 at 1st exp of #1
+ %% \Initialtoks@ , \Terminaltoks@ will contain pieces
+ \newtoks\Initialtoks@ \newtoks\Terminaltoks@
+ \def\SPLIT@{\EX@\SPLITT@\EX@}
+ \def\SPLITT@0#1@#2@{\def\TTILPS@##1#1##2@{%
+ \Initialtoks@{##1}\Terminaltoks@{##2}}\EX@\TTILPS@#2@}
+
+ %%%% MACROS TO TRIM \ForeTrim@0#1@ and \Trim@0#1@
+ %% result appears in \Trimtoks@
+ %% LIMITATION: assume no multiple spaces to trim
+
+ \newtoks\Trimtoks@
+
+ %%% \ForeTrim@0#1@ trims initial space of first erpansion of #1
+ %% #1 of form \the\toks0 or \mymacro
+ \def\ForeTrim@{\EX@\ForeTrim@@\EX@}
+ \def\ForePrim@0 #1@{\Trimtoks@{#1}}
+ \def\ForeTrim@@0#1@{\IN@0\m@rker. @\m@rker.#1@%
+ \ifIN@\ForePrim@0#1@%
+ \else\Trimtoks@\EX@{#1}\fi}
+ %%\m@rker expands here to \m@@rker since spot initial,
+ %% so no confusuion with \m@rker
+
+ %%% \Trim@0#1@ trims init and terminal spaces
+ %% Same syntax.
+ %% Warns if internal spaces found.
+ %%
+ \def\Trim@0#1@{%
+ \ForeTrim@0#1@%
+ \IN@0 @\the\Trimtoks@ @%
+ \ifIN@
+ \SPLIT@0 @\the\Trimtoks@ @\Trimtoks@\Initialtoks@
+ \IN@0\the\Terminaltoks@ @ @%
+ \ifIN@ \else \Trimtoks@{FigNameWithSpace}\fi
+ \fi }
+
+
+ %%%% MATH MACROS (provisional)
+ %% use dimen registers for reals; unit 1pt
+ %% (numerical dimension arguments OK unless contrary noted)
+
+ %%%% One needs the point token seq (pt with cat 12) USES dimen 0
+ \newtoks\pt@ks
+ \def\getpt@ks 0.0#1@{\pt@ks{#1}}
+ \dimen0=0pt\relax\EX@\getpt@ks\the\dimen0@
+
+ %%% Convert dimen to "decimal multiplier"% USES dimens 0,2
+ %\newtoks\Realtoks% the output!
+ \def\Real#1{%
+ \dimen2=#1%
+ \SPLIT@0\the\pt@ks @\the\dimen2@%% lop off the points
+ \Realtoks=\Initialtoks@ %\showthe\Realtoks
+ }
+
+ %%% Multiplication
+ % USES dimens 0,2,4,6; preserves args; output \Product
+ \newdimen\Product
+ \def\Mult#1#2{%
+ \dimen4=#1\relax
+ \dimen6=#2%
+ \Real{\dimen4}%
+ \Product=\the\Realtoks\dimen6%
+ }
+
+ %%% Inverse
+ % USES dimens 0; preserves arg; output \Inverse
+ \newdimen\Inverse
+ \newdimen\hmxdim@ \hmxdim@=8192pt%halfmaxdimen
+ \def\Invert#1{%
+ \Inverse=\hmxdim@
+ \dimen0=#1%
+ \divide\Inverse \dimen0%
+ \multiply\Inverse 8}
+
+ %%% \Rescale#1#2#3 % USES dimens 0,2,4,6
+ %% alters dimen register #1 by ratio #2/#3
+ %% where #2,#3 can be raw dimensions OR dimen registers
+ \def\Rescale#1#2#3{% Adequate accuracy. Can improve.
+ \divide #1 by 100\relax
+ \dimen2=#3\divide\dimen2 by 100 \Invert{\dimen2}%
+ \Mult{#1}{#2}%
+ \Mult\Product\Inverse
+ #1=\Product}
+
+ %%% \Scale#1 scales dimen register #1
+ %% by dimen register real \TheScale; USES dimen 0
+ \def\Scale#1{\dimen0=\TheScale
+ \divide #1 by 1280 %% 1280*5120*10=1000*2^16
+ \divide \dimen0 by 5120
+ \multiply#1 by \dimen0
+ \divide#1 by 10 %% max size of #1 about 32000/10 pt
+ }
+
+ %%% SCRUNCHING BOXES AND SHIFTING CONTENTS
+ %% TeX has to do this in general
+ %% since some drivers do not let
+ %% one do it readily using Postscript
+
+ \newbox\scrunchbox
+
+ %%% \Scrunched#1 puts #1 in an hbox
+ %% then in effect zeros the dimensions of this box
+ \def\Scrunched#1{{\setbox\scrunchbox\hbox{#1}%
+ \wd\scrunchbox=0pt
+ \ht\scrunchbox=0pt
+ \dp\scrunchbox=0pt
+ \box\scrunchbox}}
+
+ %%% \Shifted@#1 puts #1 in \hbox
+ %% then locates basepoint to bottom left corner
+ %% then translates ink only by \XShift@,\YShift@
+ %% with Postscript convention
+ %% For simplicity use only on scrunched boxes
+ %\newdimen\XShift@
+ %\newdimen\YShift@
+ \def\Shifted@#1{%
+ \vbox {\kern-\YShift@
+ \hbox {\kern\XShift@\hbox{#1}\kern-\XShift@}%
+ \kern\YShift@}}
+
+ %%% \cBoxedEPSF#1 the main macro
+ %% component macros are explained in order below
+
+ \def\cBoxedEPSF#1{{\leavevmode
+ %% double brace for amstex \allign, \alligned, ...
+ \ReadNameAndScale@{#1}%
+ \SetEPSFSpec@
+ \InitLog@
+ \ReadEPSFile@ \ReadBdB@x
+ %% Calculations
+ \TrimFigDims@
+ \CalculateFigScale@
+ \ScaleFigDims@
+ \SetInkShift@
+ \hbox{$\mathsurround=0pt\relax
+ \vcenter{\hbox{%
+ \FrameSpider{\hskip-.4pt\vrule}%
+ \vbox to \Ht@{\offinterlineskip\parindent=\z@%
+ \FrameSpider{\vskip-.4pt\hrule}\vfil
+ \hbox to \Wd@{\hfil}%
+ \vfil
+ \InkShift@{\EPSFSpecial{\EPSFSpec@}{\FigSc@leReal}}%
+ \FrameSpider{\hrule\vskip-.4pt}}%
+ \FrameSpider{\vrule\hskip-.4pt}}}%
+ $\relax}%
+ \CleanRegisters@
+ \ReportEPSF@
+ }}
+
+ \def\tBoxedEPSF#1{\setbox4\hbox{\cBoxedEPSF{#1}}%
+ \setbox4\hbox{\raise -\ht4 \hbox{\box4}}%
+ \box4
+ }
+
+ \def\bBoxedEPSF#1{\setbox4\hbox{\cBoxedEPSF{#1}}%
+ \setbox4\hbox{\raise \dp4 \hbox{\box4}}%
+ \box4
+ }
+
+ \let\BoxedEPSF\cBoxedEPSF% default setting
+
+ %% Some compatibility with BoxedArt.tex
+ %
+ \let\BoxedArt\BoxedEPSF
+
+ %% Some compatibility with Sweet-teX
+ %
+ \def\gLinefigure[#1scaled#2]_#3{%
+ \BoxedEPSF{#3 scaled #2}}
+
+ %% Some compatibility with Rokicki's dvips
+ %
+ \let\EPSFbox\bBoxedEPSF \let\EPSFfile\bBoxedEPSF
+
+ \def\EPSFxsize{\afterassignment\ForceW@\ForcedDim@@}
+ \def\ForceW@{\ForcedDim@true\ForcedHeight@false}
+
+ \def\EPSFysize{\afterassignment\ForceH@\ForcedDim@@}
+ \def\ForceH@{\ForcedDim@true\ForcedHeight@true}
+
+ \def\EmulateRokicki{%
+ \let\epsfbox\bBoxedEPSF \let\epsffile\bBoxedEPSF
+ \let\epsfxsize\EPSFxsize \let\epsfysize\EPSFysize}
+
+ %%% \ReadNameAndScale@#1
+ %
+ \def\ReadNameAndScale@#1{\IN@0 scaled@#1@% DOUBLE BARRELED
+ \ifIN@\ReadNameAndScale@@0#1@%
+ \else \ReadNameAndScale@@0#1 scaled\DefaultMilScale @%
+ \fi}
+
+ \def\ReadNameAndScale@@0#1scaled#2@{% HELPER MACRO
+ \let\OldBackslash@\\%
+ \def\\{\OtherB@ckslash}%
+ \edef\temp@{#1}%
+ \Trim@0\temp@ @%
+ \EPSFNametoks@\EX@{\the\Trimtoks@ }%
+ \FigScale=#2 pt%
+ \let\\\OldBackslash@
+ }
+
+ \def\SetDefaultEPSFScale#1{%
+ \global\def\DefaultMilScale{#1}}
+
+ \SetDefaultEPSFScale{1000}
+
+
+ %%% \ReadEPSFile@
+ %
+ \def \SetBogusBbox@{%
+ \global\BdBoxtoks@{ BoundingBox:0 0 100 100 }%
+ \global\def\BdBoxLine@{ BoundingBox:0 0 100 100 }%
+ \ms@g{ !!! Will use placeholder !!!}%
+ }
+
+ {\catcode`\%=12\relax\gdef\P@S@{%!}\gdef\pct@@{%%}}
+ %% %! min sign of PS file
+
+ %%% Opening and closing
+ \def\ReadEPSFile@{%\show\EPSFSpec@%
+ \openin\EPSFile@\EPSFSpec@
+ \relax %necessary to prevent precocious expansion of \ifeof
+ \ifeof\EPSFile@
+ \ms@g{}%
+ \ms@g{ !!! EPS FILE \the\EPSFDirectorytoks@
+ \the\EPSFNametoks@\space WAS NOT FOUND !!!}%
+ \SetBogusBbox@
+ \else
+ \ReadEPSFile@@
+ \fi
+ \closein\EPSFile@
+ }
+
+ %% \AdvanceLcnt@ for PC EPSF case only
+ \global\let\AdvanceLcnt@\relax %% initialize
+ \def\AdvanceLcnt@@{%
+ \advance\count255 1 \ifnum \count255>50 \Lcnt@ms@g \fi}
+
+ \def\Lcnt@ms@g{\ms@g{}%
+ \ms@g{ !!! PC binary EPS preview probably before BoundingBox.}%
+ \ms@g{ !!! To accellerate, use utility to move all previews after \pct@@ EOF.}%
+ \global\let\AdvanceLcnt@\relax
+ \global\let\AdvanceLcnt@@\relax %% in all, one test, one complaint
+ }
+
+ %%% Header tests
+ \def\ReadEPSFile@@{%
+ \begingroup%%
+ \chardef\other=12 \chardef\cmt=14 \catcode"0C=9 \catcode"7F=\cmt
+ \def\do##1{\catcode`##1=\other}\dospecials \catcode`\ =10
+ \catcode"00=\cmt \catcode`\\=\cmt \catcode`\!=12 \catcode`\:=12
+ %% next to recognize PC-type header
+ \global\PCfmt@false%% initialize
+ \catcode"C5=\other \catcode"D0=\other \catcode"D3=\other \catcode"C6=\cmt
+ \global\read\EPSFile@ to \HdLine@
+ \IN@0\P@S@ @\HdLine@ @%
+ \ifIN@ %% %! accepted as %!PS so do BdBox search loop!!
+ %\message{*********}%
+ %\showthe\catcode`\%
+ %\showthe\catcode`\!
+ %\show\HdLine@
+ %\show\P@S@
+ \let\temp@\ReadEPSFile@@@
+ \else
+ \def\temp@@{^^c5^^d0^^d3}%
+ \ifx\temp@@\HdLine@ %% sign of PC binary PostScript file header
+ \global\PCfmt@true
+ \count255=0 %% will be line counter
+ \let\AdvanceLcnt@\AdvanceLcnt@@
+ \let\temp@\ReadEPSFile@@@
+ \ifPCfmtOK@\else %%
+ \ms@g{}%
+ \ms@g{ !!! PC binary EPS file header encountered. Designated }%
+ \ms@g{ !!! driver may not accept this and similar EPS files.}%
+ \relax\global\PCfmtOK@true %% just one warning
+ \fi
+ \else
+ \ms@g{}%
+ \ms@g{ !!! \the\EPSFNametoks@\space is not PostScript.}%
+ \ms@g{ !!! It should begin with the "\P@S@" or PC binary header.}%
+ \SetBogusBbox@
+ \fi
+ \fi
+ \temp@
+ \endgroup%\relax
+ }
+
+ %%% BoundingBox search loop
+ \def\ReadEPSFile@@@{\Repeat@true
+ \loop
+ \ifeof\EPSFile@\relax\Repeat@false
+ \ms@g{}%
+ \ms@g{ !!! BoundingBox NOT FOUND IN %
+ \the\EPSFDirectorytoks@\the\EPSFNametoks@\space!!! }%
+ \SetBogusBbox@
+ \else
+ \ReadEPSFile@@@@
+ \fi
+ \ifRepeat@
+ \AdvanceLcnt@ %% is \relax unless PC EPSF; >50 => complaint
+ \repeat
+ \global\BdBoxtoks@\expandafter{\BdBoxLine@}%
+ }
+
+ %%% BoundingBox or HiResBoundingBox
+ %% HiRes normally on line following if present at all
+ \def\ReadEPSFile@@@@{%
+ \global\read\EPSFile@ to \BdBoxLine@
+ %\BdBoxtoks@\EX@{\BdBoxLine@}\ms@g{}\ms@g{ * \the\BdBoxtoks@}%%%%
+ \IN@0BoundingBox@\BdBoxLine@ @%
+ \ifIN@
+ %\ms@g{}\ms@g{ * SCORE!!}
+ \Repeat@false
+ \read\EPSFile@ to \temp@
+ \IN@0HiResBoundingBox:@\temp@ @%
+ \ifIN@
+ \global\let\BdBoxLine@\temp@
+ \fi
+ \fi}
+
+ %%% \ReadBdB@x
+ % Rmk For simplicity 0 not used in syntax
+ % of \ReadBdB@x@, \ReadBdB@x@@
+ \def\ReadBdB@x{% PART 0
+ \EX@\ReadBdB@x@\the\BdBoxtoks@ @}
+
+ \def\ReadBdB@x@#1BoundingBox:#2@{% PART 1
+ \ForeTrim@0#2@%
+ \IN@0atend@\the\Trimtoks@ @%
+ \ifIN@ \Trimtoks@={0 0 100 100 }%
+ \ms@g{}%
+ \ms@g{ !!! BoundingBox not found in %
+ \the\EPSFDirectorytoks@\the\EPSFNametoks@\space !!!}%
+ \ms@g{ !!! It must not be at end of EPSF !!!}%
+ \ms@g{ !!! Will use placeholder !!!}%
+ \fi%% cf \SetBogusBbox@
+ \EX@\ReadBdB@x@@\the\Trimtoks@ @%
+ }
+
+ \def\ReadBdB@x@@#1 #2 #3 #4@{% PART 2
+ \Wd@=#3bp\advance\Wd@ by -#1bp%
+ \Ht@=#4bp\advance\Ht@ by-#2bp%
+ \Wd@@=\Wd@ \Ht@@=\Ht@ %% useful info for Clark
+ \LLXtoks@={#1}\LLYtoks@={#2}%% useful for Oz
+ \URXtoks@={#3}\URYtoks@={#4}%% useful for epsf.tex
+ \ifPSOrigin\XShift@=-#1bp\YShift@=-#2bp\fi
+ }
+
+ %%% \SetEPSFDirectory
+ %
+ \def\G@bbl@#1{}
+ \bgroup
+ \global\edef\OtherB@ckslash{\EX@\G@bbl@\string\\}
+ \egroup
+
+ \def\SetEPSFDirectory{% Part 1
+ \bgroup\PunctOther@\relax
+ \let\\\OtherB@ckslash
+ \SetEPSFDirectory@}
+
+ \def\SetEPSFDirectory@#1{% Part 2
+ \edef\temp@{#1}%
+ \Trim@0\temp@ @% result in \Trimtoks@
+ \global\toks1\EX@{\the\Trimtoks@ }\relax
+ \egroup
+ \EPSFDirectorytoks@=\toks1
+ }
+
+ \def\SetEPSFSpec@{%
+ \bgroup
+ \let\\=\OtherB@ckslash
+ \global\edef\EPSFSpec@{%
+ \the\EPSFDirectorytoks@\the\EPSFNametoks@}%
+ \global\edef\EPSFSpec@{\EPSFSpec@}%
+ \egroup}
+
+ %%% Is trimming done percentage-wise??
+ \newif\ifPCT@
+
+ \def\PCTtrueErrTst@{}%
+ \def\PCTfalseErrTst@{}%
+
+ %%%% Trimming figure dimensions (source)
+ %%
+ %%% \TrimSide@
+ %% #1 is one of \TT@,...,\RT@; #2 is arg of \TrimTop,...
+ \def\TrimSide@#1#2{%
+ \IN@0pct@#2@%
+ \ifIN@
+ \PCT@true\PCTtrueErrTst@
+ \SPLIT@0pct@#2@%
+ \advance#1 by \the\Initialtoks@ pt
+ \else
+ \PCTfalseErrTst@
+ \advance#1 by #2
+ \fi}
+
+ \def\TrimTop#1{\TrimSide@{\TT@}{#1}}%
+ \def\TrimLeft#1{\TrimSide@{\LT@}{#1}}%
+ \def\TrimBottom#1{\TrimSide@{\BT@}{#1}}%
+ \def\TrimRight#1{\TrimSide@{\RT@}{#1}}%
+
+ \def\TrimBoundingBox#1{%
+ \TrimTop{#1}%
+ \TrimLeft{#1}%
+ \TrimBottom{#1}%
+ \TrimRight{#1}%
+ }
+
+ %%% Convert percentage trim to dimension trim on source (if nec)
+ %% #1 is percent trim (pt is unit); #2 is source width or height
+ \def\PCTtoSideTrimDims@{%
+ \ifPCT@
+ \Rescale\LT@\Wd@{100pt}%\showthe\LT@
+ \Rescale\RT@\Wd@{100pt}%
+ \Rescale\TT@\Ht@{100pt}%
+ \Rescale\BT@\Ht@{100pt}%
+ \fi}
+
+ \def\TrimFigDims@{%
+ \PCTtoSideTrimDims@
+ \advance\Wd@ by -\LT@
+ \advance\Wd@ by -\RT@ \RT@=\z@
+ \advance\Ht@ by -\TT@ \TT@=\z@
+ \advance\Ht@ by -\BT@
+ }
+
+
+ %%% \CalculateFigScale@
+ %
+ \def\ForceWidth#1{\ForcedDim@true
+ \ForcedDim@@#1\ForcedHeight@false}
+
+ \def\ForceHeight#1{\ForcedDim@true
+ \ForcedDim@@=#1\ForcedHeight@true}
+
+ \def\ForceOn{\ForceOn@true}
+ \def\ForceOff{\ForceOn@false\ForcedDim@false}
+
+ \def\CalculateFigScale@{%
+ %Have default \FigScale or read \FigScale
+ \ifForcedDim@\FigScale=1000pt% %% start afresh
+ \ifForcedHeight@
+ \Rescale\FigScale\ForcedDim@@\Ht@
+ \else
+ \Rescale\FigScale\ForcedDim@@\Wd@
+ \fi
+ \fi
+ \Real{\FigScale}%
+ \edef\FigSc@leReal{\the\Realtoks}%
+ }
+
+ \def\ScaleFigDims@{\TheScale=\FigScale
+ \ifForcedDim@
+ \ifForcedHeight@ \Ht@=\ForcedDim@@ \Scale\Wd@
+ \else \Wd@=\ForcedDim@@ \Scale\Ht@
+ \fi
+ \else \Scale\Wd@\Scale\Ht@
+ \fi
+ \ifForceOn@\relax\else\global\ForcedDim@false\fi
+ \Scale\LT@\Scale\BT@ %%%\Scale\Wd@\Scale\Ht@
+ \Scale\XShift@\Scale\YShift@
+ }
+
+ %%% \ShowDisplacementBoxes
+ %% shows (prints) corrected scaled and positioned
+ %% bounding boxes; for diagnostics
+ %%% \HideDisplacementBoxes makes them invisible again
+ %%
+ \def\HideDisplacementBoxes{\global\def\FrameSpider##1{\null}}
+ \def\ShowDisplacementBoxes{\global\def\FrameSpider##1{##1}}
+ \let\HideFigureFrames\HideDisplacementBoxes %% some synonyms
+ \let\ShowFigureFrames\ShowDisplacementBoxes
+ \ShowDisplacementBoxes
+
+ %%% \hSlide#1, \vSlide#1
+ %%
+ \def\hSlide#1{\advance\XSlide@ by #1}
+ \def\vSlide#1{\advance\YSlide@ by #1}
+
+ %%% \SetInkShift@, \InkShift@#1
+ %%
+ \def\SetInkShift@{%
+ \advance\XShift@ by -\LT@
+ \advance\XShift@ by \XSlide@
+ \advance\YShift@ by -\BT@
+ \advance\YShift@ by -\YSlide@
+ }
+ %
+ \def\InkShift@#1{\Shifted@{\Scrunched{#1}}}
+
+ %%% \CleanRegisters@
+ %
+ \def\CleanRegisters@{%
+ \globaldefs=1\relax
+ \XShift@=\z@\YShift@=\z@\XSlide@=\z@\YSlide@=\z@
+ \TT@=\z@\LT@=\z@\BT@=\z@\RT@=\z@
+ \globaldefs=0
+ \global\PCT@false}
+
+ \def\ReportEPSF@{%
+ \ms@g{ *** Box composed for the EPS file \the\EPSFNametoks@}%
+ \edef\temp@{\the\EPSFDirectorytoks@}%
+ \ifx\temp@\LastEPSFDirectory@\else
+ \WrLog@{--- change EPSF directory ==> \temp@}%
+ \global\let\LastEPSFDirectory@\temp@
+ \fi
+ \def\temp@{}%
+ \ifPCfmt@ \edef\temp@{\space \pct@@\space EPSP binary}%
+ \fi
+ %\show\temp@
+ \WrLog@\EX@{\the\EPSFNametoks@\temp@}%
+ }
+
+ \gdef\LastEPSFDirectory@{}%% initialize
+
+ %%% Special syntax for several drivers. The macros
+ %% \SetTexturesEPSFSpecial %% Textures
+ %% \SetUnixCoopEPSFSpecial %% dvi2ps early unix
+ %% \SetNiponUnixEPSFSpecial %% dvi2ps j-version
+ %% \SetBechtolsheimDVI2PSEPSFSpecial and
+ %% \SetBechtolsheimDVITPSEPSFSpecial %% by S.P.Bechtolsheim
+ %% \SetLisEPSFSpecial %% dvi2ps by Tony Lis
+ %% \SetepsfEPSFSpecial %% ******* will work for many:
+ %% ----- dvips, the Y&Y drivers, DirectTeX, CMacTeX, OzTeX>=1.7
+ %% \SetRokickiEPSFSpecial %% dvips by Tom Rokicki
+ %% \SetDVIPSoneEPSFSpecial %% DVIPSONE of Y&Y same as
+ %% \SetDVIWindowEPSFSpecial %% DVIWindow of Y&Y
+ %% \SetDirectTeXEPSFSpecial %% DirectTeX by Wilfried Ricken
+ %% \SetCMacTeXEPSFSpecial %% CMacTeX by Tom Kiffe
+ %% \SetOzTeXEPSFSpecial %% OzTeX (>=1.7) by Andrew Trevorrow
+ %% -----
+ %% \SetOldOzTeXEPSFSpecial %% OzTeX 1.42--1.6x
+ %% \SetPSprintEPSFSpecial %% PSprint by Andrew Trevorrow
+ %% --- also for OzTeX versions <= 1.41 !!
+ %% \SetArborEPSFSpecial %% ArborTeX DVILASER/PS
+ %% \SetClarkEPSFSpecial %% dvitops by James Clark
+ %% \SetBeebeEPSFSpecial %% DVIALW by N. Beebe
+ %% \SetNorthlakeEPSFSpecial %% Northlake Software
+ %% \SetStandardEPSFSpecial %% Nonexistant: Placebo used
+ %%
+ %% These many drivers are supported roughly
+ %% by (re-)defining the macro \EPSFSpecial#1#2, where
+ %% #1 = EPS file pathname (use \\ for the letter backslash)
+ %% #2 = scale in mils
+ %% Be wary of using strange characters in pathnames!
+
+ %% Textures, Blue Sky Research, Barry Smith
+ \def\SetTexturesEPSFSpecial{\PSOriginfalse%\PSOrigintrue
+ \gdef\EPSFSpecial##1##2{\relax
+ \edef\specialtemp{##2}%
+ \SPLIT@0.@\specialtemp.@\relax
+ \special{illustration ##1 scaled
+ \the\Initialtoks@}}}
+
+ %% Unix : dvi2ps by: Mark Senn, Stephan Bechtolsheim,
+ % Bob Brown, Richard, Furuta, James Schaad, Robert Wells,
+ % Norm Hutchinson, Neal Holt, Scott Jones, Howard Trickey.
+ % Introduced by B. Horn <bkph@ai.mit.edu>
+ \def\SetUnixCoopEPSFSpecial{\PSOrigintrue % Please test!
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt% convert real to dimen
+ \divide\dimen4 by 1000\relax
+ \Real{\dimen4}%dimens 0,2 used here
+ \edef\Aux@{\the\Realtoks}%
+ %%convert dimen to real
+ \special{psfile=##1\space
+ hscale=\Aux@\space
+ vscale=\Aux@}}}
+
+ %% Unix : dvi2ps j-version 1.91j
+ % Introduced by Takashi Matsushita matsu@tmuds1.phys.metro-u.ac.jp
+ % Takafumi Sakurai, sakurai@math.s.chiba-u.ac.jp
+ % Kazuhiro Kazama, kazama@square.ntt.jp
+ \def\SetNiponUnixEPSFSpecial{\PSOriginfalse % Please test!
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt% convert real to dimen
+ \divide\dimen4 by 1000\relax
+ \Real{\dimen4}%dimens 0,2 used here
+ \edef\Aux@{\the\Realtoks}%
+ %%convert dimen to real
+ \special{epsfile=##1\space
+ hscale=\Aux@\space
+ vscale=\Aux@}}}
+
+ %% Unix : dvi2ps j-version 1.91j
+ % Introduced by Takashi Matsushita matsu@tmuds1.phys.metro-u.ac.jp
+ % Takafumi Sakurai, sakurai@math.s.chiba-u.ac.jp
+ % Kazuhiro Kazama, kazama@square.ntt.jp
+ \def\SetNiponUnixEPSFSpecial{\PSOriginfalse % Please test!
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt% convert real to dimen
+ \divide\dimen4 by 1000\relax
+ \Real{\dimen4}%dimens 0,2 used here
+ \edef\Aux@{\the\Realtoks}%
+ %%convert dimen to real
+ {\dimen6=\the\URYtoks@ pt %
+ \advance\dimen6 by -\the\LLYtoks@ pt %
+ \dimen6=\Aux@\dimen6
+ \Real{\dimen6}%
+ \XShift@=0bp\YShift@=\the\Realtoks bp
+ \Shifted@{\special{epsfile=##1\space
+ hscale=\Aux@\space
+ vscale=\Aux@}}}}}
+%%% \Shifted@{\special{illustration ##1}}}}}
+
+
+
+ %% dvi2ps and dvitps by S.P. Bechtolsheim,
+ % Introduced by B. Horn <bkph@ai.mit.edu> and Carl.M.Jones,
+ % testing by R. Evans <Robert@cm.cardiff.ac.uk>
+ % and George Denk <denk@mathematik.tu-muenchen.de>
+ % Note that a prolog file psfig.pro
+ % specific to the driver should be available.
+ \def\SetBechtolsheimEPSFSpecial@{%% tool macro only
+ \PSOrigintrue
+ \special{\DriverTag@ Include0 "psfig.pro"}%
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt %% convert real to dimen
+ \divide\dimen4 by 1000\relax
+ \Real{\dimen4} %% dimens 0,2 used here
+ \edef\Aux@{\the\Realtoks}%% convert dimen to real
+ \special{\DriverTag@ Literal "10 10 0 0 10 10 startTexFig
+ \the\mag\space 1000 div
+ dup 3.25 neg mul 1 index .25 neg mul translate %% correction line
+ \Aux@\space mul dup scale "}%
+ \special{\DriverTag@ Include1 "##1"}%
+ \special{\DriverTag@ Literal "endTexFig "}%
+ }}
+
+ \def\SetBechtolsheimDVITPSEPSFSpecial{\def\DriverTag@{dvitps: }%
+ \SetBechtolsheimEPSFSpecial@}
+
+ \def\SetBechtolsheimDVI2PSEPSFSSpecial{\def\DriverTag@{DVI2PS: }%
+ \SetBechtolsheimEPSFSpecial@}
+
+ %% dvi2ps by Tony Lis,
+ % implantations? ; dates?; availability?
+ % Introduced by B. Horn <bkph@ai.mit.edu>
+ \def\SetLisEPSFSpecial{\PSOrigintrue
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt% convert real to dimen
+ \divide\dimen4 by 1000\relax
+ \Real{\dimen4}% dimens 0,2 used here
+ \edef\Aux@{\the\Realtoks}%
+ %%convert dimen to real
+ \special{pstext="10 10 0 0 10 10 startTexFig\space
+ \the\mag\space 1000 div \Aux@\space mul
+ \the\mag\space 1000 div \Aux@\space mul scale"}%
+ \special{psfile=##1}%
+ \special{pstext=endTexFig}%
+ }}
+
+ %% dvips by Tom Rokicki; free driver in portable C
+ % Introduced by W.D. Neumann <neumann@mps.ohio-state.edu>
+ \def\SetRokickiEPSFSpecial{\PSOrigintrue
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt% convert real to dimen
+ \divide\dimen4 by 10\relax
+ \Real{\dimen4}% dimens 0,2 used here
+ \edef\Aux@{\the\Realtoks}%
+ %%convert dimen to real
+ \special{psfile="##1"\space
+ hscale=\Aux@\space
+ vscale=\Aux@}}}
+
+ \def\SetInlineRokickiEPSFSpecial{\PSOrigintrue
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt% convert real to dimen
+ \divide\dimen4 by 1000\relax
+ \Real{\dimen4}% dimens 0,2 used here
+ \edef\Aux@{\the\Realtoks}%
+ %%convert dimen to real
+ \special{ps::[begin] 10 10 0 0 10 10 startTexFig\space
+ \the\mag\space 1000 div \Aux@\space mul
+ \the\mag\space 1000 div \Aux@\space mul scale}%
+ \special{ps: plotfile ##1}%
+ \special{ps::[end] endTexFig}%
+ }}
+
+ %%% Rokicki's epsf.tex syntax.
+ %% Is followed by DirectTeX (W. Ricken)
+ %% CMacTeX (Tom Kiffe), Y&Y's drivers, and OzTeX >= 1.7
+ \def\SetepsfEPSFSpecial{\PSOriginfalse
+ \gdef\epsfclipstring{}%
+ %% make { clip} if you want to clip (non-portably)
+ %% down to the PostScript bounding box. (OzTeX refuses this)
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt %% convert mil scale to dimen
+ \divide\dimen4 by 100 %% 1000ths to 10ths
+ \Real{\dimen4}%% dimens 0,2 used here
+ \edef\theScaleholder@{\the\Realtoks}%
+ \dimen6=\the\URXtoks@ pt %% not bp!!!!!
+ \advance\dimen6 by -\the\LLXtoks@ pt
+ %% \dimen6 now (bbox width) * points
+ \dimen6=\theScaleholder@\dimen6 \Real{\dimen6}%% dimens 0,2 used here
+ \edef\Temp{\the\Realtoks}%
+ %% \Temp now holds decimal real no
+ %% 10 times desired "real width" (rwi) in bp
+ \dimen6=\the\URYtoks@ pt %
+ \advance\dimen6 by -\the\LLYtoks@ pt %
+ \dimen6=\theScaleholder@\dimen6 \Real{\dimen6}%
+ \special{PSfile=##1\space
+ llx=\the\LLXtoks@\space lly=\the\LLYtoks@\space
+ urx=\the\URXtoks@\space ury=\the\URYtoks@\space
+ rwi=\Temp\space rhi=\the\Realtoks
+ \epsfclipstring}%
+ }}
+ %% Rmk: Under epsf.tex only multiples of (1/10) bp available widths
+ %% but considerably more accuracy available here.
+
+ \let\SetDirectTeXEPSFSpecial=\SetepsfEPSFSpecial
+ \let\SetCMacTeXEPSFSpecial=\SetepsfEPSFSpecial
+ \let\SetOzTeXEPSFSpecial=\SetepsfEPSFSpecial
+ %%% \SetOzTeXEPSFSpecial only for OzTeX in versions 1.7 and later
+
+ %%% Old OzTeX versions (1.42 to 1.6), by Andrew Trevorrow.
+ %%% For versions <= 1.41 use \SetPSprintEPSFSpecial below.
+ %% Nota: Version 1.42--1.5 may give
+ %% spurious "offpage" error notices on printing.
+ \def\SetOldOzTeXEPSFSpecial{\PSOrigintrue
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt%% convert real to dimen
+ \divide\dimen4 by 1000\relax
+ \Real{\dimen4}%% dimens 0,2 used here
+ \edef\Aux@{\the\Realtoks}%% convert dimen to real
+ \special{epsf=\string"##1\string"\space scale=\Aux@}%
+ }}
+
+ %% PSprint, by AndrewTrevorrow for VaX VMS
+ %% and OzTeX versions <= 1.41
+ % tested 2-91 by Max Calviani <ISICA@ASTRPD.infn.it>
+ \def\SetPSprintEPSFSpecial{\PSOriginfalse % artifice; see below
+ \gdef\EPSFSpecial##1##2{%note order
+ \special{##1\space
+ ##2 1000 div \the\mag\space 1000 div mul
+ ##2 1000 div \the\mag\space 1000 div mul scale
+ \the\LLXtoks@\space neg \the\LLYtoks@\space neg translate
+ }}}
+
+ %% DVILASER/PS driver originally written by David Fuchs
+ % marketed and supported by ArborTeXt 535 W. William St.
+ % Suite 300, Ann Arbor, MI 48103, U.S.A
+ % (313) 996-3566 (313) 996-3573
+ % help@arbortext.com, Andrew Dobrowolski
+ \def\SetArborEPSFSpecial{\PSOriginfalse % check!
+ \gdef\EPSFSpecial##1##2{%
+ \edef\specialthis{##2}%
+ \SPLIT@0.@\specialthis.@\relax % suppress decimals (nec!)
+ \special{ps: epsfile ##1\space \the\Initialtoks@}}}
+
+ %% dvitops, (c) James Clark <jjc@jclark.uucp>
+ % public domain; distributed by UK TeX Archive
+ % computers: unix, msdos, vms, primos and vm/cms,
+ % introduced by S. Ratz <spqr@uk.ac.southampton.ecs>
+ \def\SetClarkEPSFSpecial{\PSOriginfalse % please test!
+ \gdef\EPSFSpecial##1##2{%
+ \Rescale {\Wd@@}{##2pt}{1000pt}%
+ \Rescale {\Ht@@}{##2pt}{1000pt}%
+ \special{dvitops: import
+ ##1\space\the\Wd@@\space\the\Ht@@}}}
+
+ %% DVIPSONE, for PC compatibles
+ % Y&Y, 106 Indian Hill, Carlisle MA 01741, USA
+ % (508) 371-3286
+ % (introduced by B. Horn <bkph@ai.mit.edu>)
+ \let\SetDVIPSONEEPSFSpecial\SetepsfEPSFSpecial
+ \let\SetDVIPSoneEPSFSpecial\SetepsfEPSFSpecial
+ \let\SetDVIWindowEPSFSpecial\SetepsfEPSFSpecial
+
+ %% DVIALW by N. Beebe, public domain
+ % DVI Driver Distribution, Center for Scientific Computing,
+ % Department of Mathematics, 220 South Physics Building,
+ % University of Utah, Salt Lake City, UT 84112, USA
+ % (introduced by B. Horn <bkph@ai.mit.edu>)
+ % Proposed standard; see TUGboat article 1993.
+ \def\SetBeebeEPSFSpecial{%please test!
+ \PSOriginfalse%
+ \gdef\EPSFSpecial##1##2{\relax
+ \special{language "PS",
+ literal "##2 1000 div ##2 1000 div scale",
+ position = "bottom left",
+ include "##1"}}}
+ \let\SetDVIALWEPSFSpecial\SetBeebeEPSFSpecial
+
+ %% Northlake software
+ \def\SetNorthlakeEPSFSpecial{\PSOrigintrue
+ \gdef\EPSFSpecial##1##2{%
+ \edef\specialthis{##2}%
+ \SPLIT@0.@\specialthis.@\relax % suppress decimals (nec!)
+ \special{insert ##1,magnification=\the\Initialtoks@}}}
+
+ %%% MultiSpecial for Textures PLUS drivers supporting epsf.tex
+ %%% syntax of Rokicki (one of many dvips syntaxes)
+ %% *experimental* 2-95
+ \def\SetEPSFMultiSpecial{\PSOriginfalse
+ \csname newwrite\endcsname \EPSFile@@
+ \immediate\openout\EPSFile@@ illustration
+ \immediate\write\EPSFile@@ {\P@S@}%
+ \immediate\write\EPSFile@@ {\pct@@ Remark: Tranquilizer for OzTeX...}%
+ \immediate\closeout\EPSFile@@
+ \gdef\EPSFSpecial##1##2{%
+ \dimen4=##2pt %% convert mil scale to dimen
+ \divide\dimen4 by 100 %% 1000ths to 10ths
+ \Real{\dimen4}%% dimens 0,2 used here
+ \edef\theScaleholder@{\the\Realtoks}%
+ \dimen6=\the\URXtoks@ pt %% not bp!!!!!
+ \advance\dimen6 by -\the\LLXtoks@ pt
+ %% \dimen6 now (bbox width) * points
+ \dimen6=\theScaleholder@\dimen6 \Real{\dimen6}%% dimens 0,2 used here
+ \edef\Temp{\the\Realtoks}%
+ %% \Temp now holds decimal real no
+ %% 10 times desired "real width" (rwi) in bp
+ \dimen6=\the\URYtoks@ pt %
+ \advance\dimen6 by -\the\LLYtoks@ pt %
+ \dimen6=\theScaleholder@\dimen6 \Real{\dimen6}%
+ \special{PSfile=##1\space
+ llx=\the\LLXtoks@\space lly=\the\LLYtoks@\space
+ urx=\the\URXtoks@\space ury=\the\URYtoks@\space
+ rwi=\Temp\space rhi=\the\Realtoks}%
+ \edef\specialtemp{##2}%
+ \SPLIT@0.@\specialtemp.@\relax
+ \special{illustration ##1 scaled \the\Initialtoks@}%
+ }}
+
+ \def\SetStandardEPSFSpecial{%
+ \gdef\EPSFSpecial##1##2{%
+ \ms@g{}
+ \ms@g{%
+ !!! Sorry! There is still no standard for \noexpand
+ \special EPSF integration !!!}%
+ \ms@g{%
+ --- So you will have to identify your driver using a command}%
+ \ms@g{%
+ --- of the form \string\Set...EPSFSpecial, in order to get}%
+ \ms@g{%
+ --- your graphics to print.}%
+ \ms@g{%
+ Update your BoxedEPSF and read the documentation.}%
+ \ms@g{}
+ \gdef\EPSFSpecial####1####2{}
+ }}
+
+ \SetStandardEPSFSpecial %% currently gives warning
+
+ \let\wlog\wlog@ld %%restore logging
+
+ \catcode`\:=\C@tColon
+ \catcode`\;=\C@tSemicolon
+ \catcode`\?=\C@tQmark
+ \catcode`\!=\C@tEmark
+ \catcode`\"=\C@tDqt
+
+ \catcode`\@=\EPSFCatAt
+
+ \endinput
+
+%%%%%%%%%%%% ASCII Character test
+ %
+ % Upper case letters: ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ % Lower case letters: abcdefghijklmnopqrstuvwxyz
+ % Digits: 0123456789
+ % Square, curly, angle braces, parentheses: [] {} <> ()
+ % Backslash, slash, vertical bar: \ / |
+ % Punctuation: . ? ! , : ;
+ % Underscore, hyphen, equals sign: _ - =
+ % Quotes--right left double: ' ` "
+ %"at", "number" "dollar", "percent", "and": @ # $ % &
+ % "hat", "star", "plus", "tilde": ^ * + ~
+ %
+ %%%%%%%%%%%%%%%%%%%%%%%%
+ %
+ % Une seule erreur de transmission peut empoisoner un programme!
+ %
+ % A single transmission error can poison a whole program.
+ %
+ %%%%%%%%%%%%%%%%%%%%%%%%