10

My .tex file starts with the following directives.

% arara: lualatex
% arara: biber
% arara: makeglossaries
% arara: makeindex
% arara: lualatex
% arara: lualatex

How can I instruct Arara to skip a step if the output files from this step already exist and the input files necessary for the completion of this step have not changed, which implies that the output files will not change as a result of this step, and therefore the step is redundant?


MINIMAL EXAMPLE

Here is a minimal example, comprising three files.

File #1: Test.tex

% arara: lualatex
% arara: biber
% arara: makeglossaries
% arara: makeindex
% arara: lualatex
% arara: lualatex
\documentclass[Bibliography=totoc,index=totoc]{scrbook}
\usepackage{biblatex}
\addbibresource{TestBibliography.bib}
\usepackage{imakeidx}
\makeindex
\usepackage[automake,sort=def]{glossaries-extra}
\makeglossaries
\input{TestGlossary}
\newtheorem{definition}{Definition}[chapter]
\title{Title}
\date{}
\begin{document}

\maketitle
\tableofcontents

\chapter{Chapter}
\section{Section}
\begin{definition}[Natural Numbers](\cite{Nat})\label{d:natural}\index{natural numbers}\glsadd{natural} The set of non-negative whole numbers shall be denoted by $\{0,1,2,\dots\}$. This is the set of \emph{natural numbers}.
\end{definition}

Natural numbers (see~\ref{d:natural}) are the best!

\printglossary[title={Notation Glossary}]
\printindex

\printbibliography[heading=bibintoc]
\end{document}

File #2: TestBibliography.bib

@Book{Nat,
author = {Poo, Winnie},
title = {Natural Numbers},
edition={3rd},
publisher = {Ex Libris},
year = {2019}}

File #3: TestGlossary.tex

\newglossaryentry{natural}{name={\ensuremath{\{0,1,2,\dots\}}},description={the natural numbers}}
Evan Aad
  • 11,066
  • 2
    There are missing, changed, unchanged, exists methods that can be used in rules, see around page 61 of the manual. – Marijn May 07 '19 at 08:32
  • @Marijn: Thanks. Can you please give a detailed answer to my specific question? I imagine I'm not the only one interested in cutting down Arara's run-time, and such an answer will be helpful to spare each such user from having to "reinvent the wheel". Also: it requires a bit of expertise not only in Arara syntax and semantics but also in what files are produced by the various TeX programs. – Evan Aad May 07 '19 at 08:37
  • I'd be happy to post an answer. Maybe you can facilitate the answering process a bit by providing an MWE with filecontents etc. that uses Biber, glossaries, makeindex? Otherwise I (or other answerers) have to do all that just to be able to write and test a couple of arara rules. – Marijn May 07 '19 at 08:53
  • @Marijn: I've added a minimal example. – Evan Aad May 07 '19 at 09:31
  • 2
    I'll leave this to our local Arara authority, as he probably knows better, but this is what I used for my dissertation project: % arara: lualatex: { draft: yes, shell: yes } % arara: biber if found ('log', 'Please \\(re\\)run Biber') % arara: --> || changed (toFile('biblio.bib')) % arara: lualatex until !found('log', '\\(?(R|r)e\\)?run (to get|LaTeX)'). It will run biber only if necessary and run lualatex until everything is sorted out. Explanation here. I didn't use makeglossaries though, but it should follow the same principle. – Phelype Oleinik May 07 '19 at 11:50
  • @PhelypeOleinik: What does the --> in the 3rd directive mean? – Evan Aad May 07 '19 at 13:38
  • 1
    @EvanAad It's a line continuation. It means that what follows the --> belongs to the previous line. It's used just for clarity of the code. It's documented in page 20 of the manual. – Phelype Oleinik May 07 '19 at 13:40
  • @PhelypeOleinik: Thanks. And why are some of the parentheses that are inside a pair of apostrophes preceded by \\\, but not all of them? – Evan Aad May 07 '19 at 13:45
  • 1
    @EvanAad In short, the escaped parentheses \\( and \\) are literal parentheses to be found in the .log file, and un-escaped ones are part of the regular expression. In not-so-short, see my answer ;) – Phelype Oleinik May 07 '19 at 15:14

4 Answers4

11

Here's my proposal:

% arara: lualatex: { draft: yes, shell: yes }
% arara: biber if changed (toFile('TestBibliography.bib'))
% arara: --> || found ('log', 'Please \\(re\\)run Biber')
% arara: makeglossaries if changed ('glo') || missing ('gls')
% arara: makeindex if changed ('idx') || missing ('ind')
% arara: lualatex until !found('log', '\\(?(R|r)e\\)?run (to get|LaTeX)')

Let's go one by one.

% arara: lualatex: { draft: yes, shell: yes }

This one will run LuaLaTeX in draft mode with -shell-escape enabled. The draft mode makes LuaLaTeX not generate the .pdf file, thus it won't include graphics. This run of LuaLaTeX just generates auxiliary files which are needed for the other programs. This saves a couple of seconds in compilation time. The -shell-escape is optional; I needed it, but if you aren't using any package that requires it you can remove that (I was using for externalisation of TikZ pictures).

% arara: biber if changed (toFile('TestBibliography.bib'))
% arara: --> || found ('log', 'Please \\(re\\)run Biber')

This directive will run Biber only if the .log file says so. BibLaTeX tells you when you need to (re)run Biber, so you can rely on that to know when. What BibLaTeX can't tell is when you change the .bib file, so I added an alternative condition, which is if I changed my .bib file (since the name isn't the same as the master .tex file, I needed to make it into a file reference with toFile('TestBibliography.bib')).

A couple of observations here: The % arara: --> line is a continuation line. It means that what follows the --> belongs to the previous line. It's used just for clarity of the code. It's documented in page 20 of the manual. Thus, the directive above could be written:

% arara: biber if changed (toFile('TestBibliography.bib')) || found ('log', 'Please \\(re\\)run Biber')

without change in meaning.

The syntax for found (an other commands like that) is:

found(<string extension or file reference>,<regular expression>)

The <string extension> in this case is 'log', and the <regular expression> is 'Please \\(re\\)run Biber'. In regular expressions, a pair of parentheses form a group, so (re)run does not match the literal string (re)run in the .log file, so you have to escape the parentheses with backslashes (\(re\)) so that they mean literal parentheses. However in Java (in which language Arara is written) a \\ translates to a single \1, so you need to escape the backslash as well. So, in a directive \\(re\\)run will be read by Arara as \(re\)run (first escaping level), and then will be passed to the regular expression engine which will understand \(re\)run as the literal string (re)run in the log file. Phew :)

[1]: The literal string "\\" is a single backslash. In regular expressions, the backslash is also an escape character. The regular expression "\\" matches a single backslash. This regular expression as a Java string, becomes "\\\\".

% arara: makeglossaries if changed ('glo') || missing ('gls')
% arara: makeindex if changed ('idx') || missing ('ind')

This directive will run makeglossaries and makeindex only if the input files .glo and .idx, respectively, changed (which already evaluates to true if the file didn't exist before, which is the case of the first run), or if the output file for these tools, .gls and .ind, did't exist before, which covers the situations where you'd need to run these tools.

% arara: lualatex until !found('log', '\\(?(R|r)e\\)?run (to get|LaTeX)')

Finally, this directive will run LuaLaTeX as many times as necessary until there are no messages in the .log file saying either of these strings:

Rerun LaTeX
rerun LaTeX
(Re)run LaTeX
(re)run LaTeX
Rerun to get
rerun to get
(Re)run to get
(re)run to get

which cover most of the messages I could find in my .log file. If you add another package which requires multiple runs and uses a different message you'd need to adapt it. For instance, if the package said (in the .log) “Execute LaTeX again” (which does not match any of the patterns above), then you could change that directive to:

% arara: lualatex until !found('log', '\\(?(R|r)e\\)?run (to get|LaTeX)')
% arara: --> && !found('log','Execute LaTeX again')

or something like that. It's virtually impossible to consider all the cases form all LaTeX packages, so you need to tailor the directive according to your document, but the rerun LaTeX one is pretty generic.

Remarks on this one: Again, '\\(?(R|r)e\\)?run (to get|LaTeX)' is a regular expression (if you know these, you can skip this part). Remember, Arara eats one level of escaping, so the above translates to '\(?(R|r)e\)?run (to get|LaTeX)'. This regular expression matches:

\(?                            | A (optional) literal '('
   (R|r)                       | One of 'R' or 'r'
        e                      | The letter 'e'
         \)?                   | A (optional) literal ')'
            run                | The string 'run ' (note the trailing space)
                (to get|LaTeX) | Either 'to get' or 'LaTeX'

which translates to the cases listed above.


With your sample document, the first run of arara test.tex yields:

phelype@phelype ~/testing> arara test.tex
  __ _ _ __ __ _ _ __ __ _ 
 / _` | '__/ _` | '__/ _` |
| (_| | | | (_| | | | (_| |
 \__,_|_|  \__,_|_|  \__,_|

Processing 'test.tex' (size: 30 KB, last modified: 05/07/2019
12:05:44), please wait.

(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS
(Biber) The Biber reference management software ......... SUCCESS
(MakeGlossaries) The MakeGlossaries software ............ SUCCESS
(MakeIndex) The MakeIndex software ...................... SUCCESS
(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS
(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS

Total: 6.75 seconds

and further runs (with no modification of the sources) yield:

phelype@phelype ~/testing> arara test.tex
  __ _ _ __ __ _ _ __ __ _ 
 / _` | '__/ _` | '__/ _` |
| (_| | | | (_| | | | (_| |
 \__,_|_|  \__,_|_|  \__,_|

Processing 'test.tex' (size: 30 KB, last modified: 05/07/2019
12:05:44), please wait.

(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS
(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS

Total: 2.69 seconds

From the second run on, you get the first run of LuaLaTeX in draft mode to read the input .tex file and generate the files for Biber, Makeglossaries, and Makeindex (which are the same, so these tools aren't run), and a second run to produce the .pdf file.

  • Thanks. Regarding the draft: yes option. If this option causes the resulting compilation to exclude graphics, then any reference to a page number (e.g. in the index and glossary) might be off, potentially significantly off, no? – Evan Aad May 07 '19 at 20:29
  • @EvanAad No, the engine still reads the image and computes its size when doing the page-breaking. What does make the references be slightly off is the missing citations and references in the first run, usually requiring you to run the engine more than once (after running auxiliary tools). – Phelype Oleinik May 07 '19 at 20:45
  • I see. But then shouldn't you also run makeindex and makeglossaries more than once, in fact as many times as you run lualatex? – Evan Aad May 07 '19 at 20:47
  • @EvanAad Hm... Good point. You might need, yes. You would probably need to run the makeglossaries, makeindex, and lualatex rules in a loop until everything settles down. Of course, I seriously doubt that more than two iterations will be necessary, so running Arara twice (or repeating the last three directives) will make sure everything is OK. – Phelype Oleinik May 07 '19 at 20:52
  • Your answer is very enlightening. However, I've decided to accept birdie's answer because even though it's not optimal, it's so much less headache and there is virtually no way of getting it wrong. – Evan Aad May 07 '19 at 21:00
  • @EvanAad Then drop Arara and use latexmk directly ¯\(ツ) – Phelype Oleinik May 07 '19 at 21:02
  • On second thought, I've decided to un-accept birdie's answer, since after trying it out on my real document rather than the minimal example listed in my question, I got a mysterious failure. – Evan Aad May 07 '19 at 21:07
  • @EvanAad Perhaps ask a new question about the failure, then :) – Phelype Oleinik May 07 '19 at 21:09
  • Marijn was the first to reply to my question with a correct and helpful answer, so I've accepted their answer. – Evan Aad May 08 '19 at 17:25
  • How should one modify the 2-line directive % arara: biber if changed (toFile('TestBibliography.bib')) % arara: --> || found ('log', 'Please \\(re\\)run Biber') if one is using two different .bib files (as I am, with my memoir document)? – murray Aug 24 '19 at 14:38
  • @murray (just for future reference): https://tex.stackexchange.com/questions/505335/how-get-multiple-indexes-with-arara/505349?noredirect=1#comment1277213_505349 – Phelype Oleinik Aug 24 '19 at 16:42
  • IMHO, the last line should be lualatex if found not until !found since I need to check before running lualatex not after. Furthermore, I found it is better to be % arara: --> if found('log', '\\(?(R|r)e\\)?run (to get|LaTeX)') % arara: --> || found('log', 'No file ') || found('log', 'undefined references') % arara: --> || found('log', 'Rerun required') % arara: --> || found('log', 'Rerun to get cross-references') % arara: --> || found('log', 'Rerun to get citations') – Diaa Jan 04 '20 at 12:38
  • Also, I found out that missing('gls') should be present to get the proper output. – Diaa Jan 04 '20 at 12:55
  • @Diaa Thanks for your comment! Indeed, missing('gls') is necessary; I updated my answer. As for your other comment, I'm not completely sure, but I think it's not completely correct. If you use lualatex if found, then LuaLaTeX runs once if found, but sometimes you need it to run multiple times until cross references settle, thus I used until !found, which will run it multiple times. – Phelype Oleinik Jan 04 '20 at 14:15
  • @Diaa Also, the regular expression \\(?(R|r)e\\)?run (to get|LaTeX) already covers the cases of Rerun to get cross-references and Rerun to get citations, thus these two are redundant. Also, if you add a ? at the end of that regex, Rerun required is also covered (which package prints "Rerun required"?). Finally, I think that No file and undefined references show up when you have some input file missing or missing references in your .bib file, so running LuaLaTeX again won't solve the problem... (again, I haven't put much thought into it, sorry if I said something stupid :-) – Phelype Oleinik Jan 04 '20 at 14:20
  • You are right about \\(?(R|r)e\\)?run (to get|LaTeX) since I didn't go through your answer :). However, for until !found, it tells lualatex to run first then check for not finding what you are looking for. On the other hand, if found is the condition of running lualatex in the first place. So, in order to make my argument completely true, your last line should be replaced with two instances of % arara: lualatex if found('log', '\\(?(R|r)e\\)?run (to get|LaTeX)'). In this way, you will get the two extra runs when needed, and no runs at all when everythng is fine. – Diaa Jan 04 '20 at 15:24
  • I am not sure, but maybe required is needed in % arara: lualatex if found('log', '\\(?(R|r)e\\)?run (to get|LaTeX|required)'). I am a long time latex user but I am lazy to learn its core basics :) – Diaa Jan 04 '20 at 15:37
  • @Diaa Indeed, according to the manual, until is an a posteriori test, so it runs LuaTeX first. What about using while, which should be the a priori version of until... I'm still not sure about checking then running, because the logs (which Arara will read when doing the while test for the first time) are from the draft run at the beginning... As for the required thing, maybe it's necessary, depending on the packages you use. I don't know a package which prints Rerun required, so I didn't add that (see the Execute LaTeX again thing in my answer). Which package is it? – Phelype Oleinik Jan 04 '20 at 18:57
  • natbib says Rerun required. Regardingwhile, you are right; I tested it and I found that it checks the condition before running, which is needed. I have a question if you don't mind: what is the difference that ? makes between \\(re\\) and \\(?re\\)? ? Another question, what log file is being searched: <main file>.log , arara.log or both? – Diaa Jan 04 '20 at 20:38
  • @Diaa A ? is a regex quantifier which matches the previous item (in this case \\( and \\)) zero or one time. It essentially means that the parentheses are optional, so the regex \\(?re\\)? matches all of re, (re), (re, and re) (of couse the last two are not likely to happen), while the regex \\(re\\) matches only (re). The .log searched is the <main file>.log. – Phelype Oleinik Jan 04 '20 at 20:44
  • Many thanks for your help. Out of curiosity, if I want to additionally check for run along with (re)run, is this the right way to do so: Please (\\(re\\)|)run ? – Diaa Jan 04 '20 at 20:51
  • @Diaa Yes, that regex will match both Please run and Please (re)run (though not Please rerun). Still, I'd use Please (\\(re\\))?run instead (that is, use the quantifier ? instead of an empty match after |). If you want to match Please rerun as well, you need ? after the \\( and \\). Here's an online tool to test regexes which might be of interest to you: https://regex101.com/r/1bQt3a/1 (note that Arara requires you to double all the \, so a regex \( becomes \\( in Arara). – Phelype Oleinik Jan 04 '20 at 21:07
  • @Diaa Hello! I've been testing the until vs. while thing, and I think while is a wrong choice here. I got to this conclusion fixing typos in my thesis: a typo fix hardly changes a line—let alone a page—break, so LaTeX won't write the "rerun" message to the log, therefore the a priori while test will not run LaTeX again and the PDF will not update. However, if one removes the draft: yes option from the first LaTeX run, then the PDF is updated in the first run, and then while is the right choice... I'll investigate which is faster and update my answer (eventually). – Phelype Oleinik Jan 06 '20 at 00:43
  • while is the correct choice in my opinion, and I think you might overlook the first run of lualatex that should check for changes in your main file or subfiles. For example, this code gets my job done by only running lualatex when detecting any changes in some files of my own preference. While further lines are not executed unless major changes take place. – Diaa Jan 06 '20 at 07:37
9

In arara rules can be executed conditionally using checks on the various files. These checks are described in the current manual (version 4.0) Section 6.1 - Files.

Some useful methods are missing and changed, which check if files are missing or changed (unsurprisingly). The methods can be used in two ways: by providing a file extension, in which case the name of the main file is prepended to the extension, or by providing a full filename using the syntax toFile('yourfile.ext'). Another useful method is found, which does a string search in the provided file and returns true if the string is found. This can be used to search the main log file, or any other file if necessary, for messages indicating that a rerun is needed.

For the document in the question the following rules can be used for example:

% arara: lualatex
% arara: biber if missing('bbl') || found('log', 'Citation')
% arara: makeglossaries if missing('gls') || changed('glo') || changed(toFile('TestGlossary.tex'))
% arara: makeindex if changed('idx')
% arara: lualatex if found('log', 'No file ') || found('log', 'undefined references') || found('log', 'Rerun required') || found('log', 'Rerun to get cross-references')
% arara: lualatex

The biber rule now means run Biber if there is no bbl file (which is the file that contains the compiled bibliography) or if there are messages about citations in the log (indicating new references that are not yet included in the compiled bibliography). Note that the first syntax variant is used here, so for Test.tex the command missing('bbl') is expanded to check if Test.bbl is missing and similary log is expanded to Test.log.

The makeglossaries rule checks if the gls file exists (the output of the makeglossaries command or if the glo file is changed (written by lualatex when a glsadd command is encountered) or if the input file with the glossaries is changed. This last check is actually not really useful because the file can change without new glossary items being added to the main text and new entries can be added without changing the file, but it serves as a demonstration of the toFile() construct.

The makeindex rule checks for changes in the idx file that contains index entries.

The second lualatex rule checks for various phrases in the log file that indicate that a rerun is needed. Note that string matching on the log file is an indirect method for checking the need for reruns which may result in necessary reruns being missed or in redundant reruns being performed. The packages and tools may write different information in the log in different situations, or after updates etc., and the strings may be present in the log file for completely unrelated reasons, for example in \typeout commands. Arara itself does not seem to provide functionality for robust rerun checking - there are some examples in the manual but these all use log matching.

The rules above result in the following three runs:

run 1

  __ _ _ __ __ _ _ __ __ _ 
 / _` | '__/ _` | '__/ _` |
| (_| | | | (_| | | | (_| |
 \__,_|_|  \__,_|_|  \__,_|

Processing 'archange.tex' (size: 1 KB, last modified: 05/07/2019
13:29:24), please wait.

(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS
(Biber) The Biber reference management software ......... SUCCESS
(MakeGlossaries) The MakeGlossaries software ............ SUCCESS
(MakeIndex) The MakeIndex software ...................... SUCCESS
(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS
(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS

Total: 4.53 seconds

run 2

(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS
(MakeGlossaries) The MakeGlossaries software ............ SUCCESS
(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS

Total: 2.73 seconds

run 3

(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS
(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS

Total: 2.62 seconds
Marijn
  • 37,699
  • Thanks! Why does the MakeGlossaries appear in run 2? – Evan Aad May 07 '19 at 13:20
  • 1
    I think it appears because in the first run the .glo file is not tested by arara, the .gls file is missing at that point so the conditional can stop there. This means that the .glo file is not added to the arara file hash table (arara.xml). In the second run the gls file does exist, so changed('glo') is executed, which appears new/changed to arara (the semantics of changed is entry does not exist in hash table OR entry exists and hash is different OR entry exists but file does not exist, see page 62 of the manual). – Marijn May 07 '19 at 14:41
2

Instead of reinventing the wheel (even though it can be entertaining: https://www.youtube.com/watch?v=QF7odK55gkI), I would use

% arara: latexmk

latexmk will then automatically determine which tools have to be run.

  • 2
    Personally, I find the current design of the wheel pretty much boring ;) – Phelype Oleinik May 07 '19 at 15:42
  • 1
    @PhelypeOleinik A square would be much more interesting! https://www.youtube.com/watch?v=QF7odK55gkI –  May 07 '19 at 15:43
  • Nice answer. However there's one big downside to using the latexmk directive over "reinventing the wheel" (in your words), and that is: it can take significantly longer to process a file with latexmk. And after all the whole point of this question is to cut down on the run time of the compilation process. Still, latexmk performs better, especially on 2nd and later runs, than the naive arara script given in the question. – Evan Aad May 07 '19 at 20:07
  • @EvanAad Do you have the current version of latexmk? I agree that it used to be slow in the past, but last year or so the author made some optimisations and since then it is really fast for me. –  May 07 '19 at 20:14
  • Last time I updated my TeX distribution was 3 months ago. – Evan Aad May 07 '19 at 20:25
  • @EvanAad This should be new enough. In this case I don't know what might cause the speed problems. –  May 07 '19 at 20:28
  • 2
    This is definitely an easy solution - but in this case, would it not be even easier to just use latexmk on the command line and not to use arara at all? – Marijn May 07 '19 at 21:07
  • In order to comply with my question, you should change your answer to % arara: latexmk: { engine: lualatex }, since I specified the LuaLaTeX engine. – Evan Aad May 07 '19 at 21:17
  • 1
    Also: latexmk doesn't create the glossary on my minimal example. – Evan Aad May 08 '19 at 17:24
2
% arara: halt if
% arara: --> (unchanged('tex')                  &&
% arara: -->  unchanged('TestBibliography.bib') &&
% arara: -->  unchanged('TestGlossary.tex')     &&
% arara: -->  exists('log'))
% arara: --> ||
% arara: --> (changed('TestBibliography.bib') && false) ||
% arara: --> (changed('TestGlossary.tex')     && false) ||
% arara: --> (changed('bbl') && false)                  ||
% arara: --> (changed('gls') && false)                  ||
% arara: --> (changed('ind') && false)
% arara: lualatex
% arara: biber
% arara: makeglossaries
% arara: halt if (changed('glo') && false) ||
% arara: -->     (changed('log') && false)
% arara: lualatex if
% arara: --> (changed('bbl') || changed('gls') || changed('ind')) &&
% arara: --> (changed('gls') || changed('ind') || true) &&
% arara: --> (changed('ind') || true)
% arara: makeglossaries if changed('glo')
% arara: lualatex if
% arara: --> (changed('gls') || changed('ind')) &&
% arara: --> (changed('ind') || true)
% arara: makeglossaries if changed('glo')
% arara: lualatex if changed('gls') || changed('ind')

First run

  __ _ _ __ __ _ _ __ __ _ 
 / _` | '__/ _` | '__/ _` |
| (_| | | | (_| | | | (_| |
 \__,_|_|  \__,_|_|  \__,_|

Processing 'Test.tex' (size: 1 KB, last modified: 05/09/2019
23:18:43), please wait.

(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS
(Biber) The Biber reference management software ......... SUCCESS
(MakeGlossaries) The MakeGlossaries software ............ SUCCESS
(LuaLaTeX) LuaLaTeX engine .............................. SUCCESS

Total: 30.52 seconds

Second Run

  __ _ _ __ __ _ _ __ __ _ 
 / _` | '__/ _` | '__/ _` |
| (_| | | | (_| | | | (_| |
 \__,_|_|  \__,_|_|  \__,_|

Processing 'Test.tex' (size: 1 KB, last modified: 05/09/2019
23:18:43), please wait.

(Halt) The halt trigger ................................. SUCCESS

Total: 0.36 seconds
Evan Aad
  • 11,066