summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/lualatex/luacensor/luacensor.tex
blob: 9e2f1e14a0de1dacc086333f3df21b35e4d5e560 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
\documentclass{article}
\usepackage{xcolor}
\usepackage[hidelinks]{hyperref}
\usepackage[british]{babel}
\usepackage[useregional]{datetime2}
\DTMlangsetup[en-GB]{ord=omit}
\definecolor{LightGray}{gray}{0.9}
\usepackage{mathpazo}
\usepackage{luacensor}
\usepackage{fontspec}
\IfFontExistsTF{Palatine Parliamentary}{\setromanfont[RawFeature={+onum,+pnum}]{Palatine Parliamentary}
}{\setromanfont[RawFeature={+onum,+pnum}]{TeX Gyre PagellaX}}
\setmonofont[Scale=.9]{Deja Vu Sans Mono}
\usepackage{luacode}
%\usepackage[firstnumber=last]{fancyvrb}
\usepackage{minted}
\date{\today}
\author{Elijah Z Granet\thanks{e-mail: \href{mailto:ezg21@cantab.ac.uk}{ezg21@cantab.ac.uk}}}

\title{\texttt{LuaCensor}:\\A package for redacting sensitive information}

\begin{document}
\maketitle
\tableofcontents
\section{Very Quick Guide}
\subsection{Purpose}
This package redacts sensitive information using \texttt{Lua}, and adds accessibility support.
\subsection{Usage}
The package is called with:

\begin{minted}{latex}
\usepackage{luacensor}
\end{minted}

Sensitive information is enclosed within the command:

\begin{minted}{latex}
\cnsr{John Smith}
\end{minted}

When the outputted document is intended for authorised readers who are supposed to see sensitive information, no further action is needed.  When the outputted document is for general audiences, who are \textit{not} supposed to see sensitive information, add the following line to the preamble:

\begin{minted}{latex}
\cnsrtrue
\end{minted}

This activates the censoring globally.
\subsection{Requirements}
This package will \textbf{only} work in Lua\LaTeX. The package works out of the box with a standard \TeX\ distribution, but ideally, I would strongly suggest installing the free (\textit{libre} \& \textit{gratis}) `Redacted' font from Google Fonts, which gives a quite æsthetically pleasing black bar effect.\footnote{Available at: \url{https://fonts.google.com/specimen/Redacted}.}
\subsection{\color{red}Warning}
The package is completely effective at censoring text formatted with normal \LaTeX\ commands, by which I mean that it is impossible for someone to ascertain the original text (or even its precise length) from the outputted \MakeLowercase{\textsc{PDF}} when the \verb|\cnsrtrue| option has been activated. 

 However, math mode is used, it will censor numbers, but not operators or \TeX\ (as opposed to Unicode) operators.  This is probably fine for most instances, but unacceptable where security is of the highest priority, and I would not really recommend using this package to censor highly secret formulæ; the \texttt{censor} package in your \TeX\ distribution will do a better job of that.  The package is set to completely disappear the output (as opposed to black bar over) of the \texttt{math}, \texttt{align}, \texttt{equation}, \texttt{tabular}, and a few other environments, as disappearing these environments proved more secure than the piecemeal blacking out I saw.  It is probable that there are packages and macros that will break the \texttt{cnsr} macro, and therefore, care should be taken to always examine output before public distribution.
 \subsection{Demonstration}
 \begin{quote}
 \begin{minted}[fontsize=\footnotesize,
,breaklines]{latex}
%In the preamble: \usepackage{luacensor}
\begin{quote}
\cnsrtrue\footnotesize Whereas recognition of the \cnsr{inherent dignity and of the equal and inalienable rights of all members of the human family} is the foundation of freedom, justice and peace in the world,

\cnsr{Whereas disregard and contempt for human rights have resulted in barbarous acts which have outraged the conscience of mankind, and the advent of a world in which human beings shall enjoy freedom of speech and belief and freedom from fear and want has been proclaimed as the highest aspiration of the common people,}
 \end{minted}
 \end{quote}
 \begin{quote}
\cnsrtrue\footnotesize Whereas recognition of the \cnsr{inherent dignity and of the equal and inalienable rights of all members of the human family} is the foundation of freedom, justice and peace in the world,

\cnsr{Whereas disregard and contempt for human rights have resulted in barbarous acts which have outraged the conscience of mankind, and the advent of a world in which human beings shall enjoy freedom of speech and belief and freedom from fear and want has been proclaimed as the highest aspiration of the common people,}

 \end{quote}
 
 \clearpage



\section{More detailed information}
\subsection{Purpose}
This package is a relatively lightweight and aesthetically pleasing censorship solution which includes accessibility features to allow screen readers to be aware that content has been redacted.  
\subsection{The censoring mechanism}
The package uses Luas's \texttt{toks}  filter to replace all \textsc{utf8} characters with a single glyph (• in the case of Redacted, and a Unicode black rectangle in the fallback \TeX\ default font Source Sans Pro).  In both font options, these combine visually into a single line (though this can be deconstructed in a text editor).

  However, while changing all characters into a single character is effective in \textit{most} cases, this alone would not be sufficiently secure for reliable usage.  This is because knowing the length of a censored name could be combined with other information in, for example, a Family Court judgment, to allow for what lawyers call `jigsaw identification' (\textit{eg}, where there is only one person with an eight letter surname who meets the other details given in the judgment).  

Therefore, the package adds an extra layer of security by randomly changing the length of strings during the censorship phase; censored strings can thus be either longer or shorter by a few characters.  This means that while the area of the blacked out content will be \textit{approximately} similar to the length of the uncensored string (which means wireframing more or less works), it cannot be used to reverse engineer information about the censored content.  

\subsection{The accessibility feature}
One concern about document redaction is ensuring that visually impaired readers of your document, who use screen reading software to listen to your text, may encounter problems with censored content.  If the screen reading software skips over the censored text altogether, it will be a very confusing jump for the visually impaired user.  If the screen reading software reads the replacement characters, it will be very annoying for the visually impaired reader to hear, in a censored paragraph, the same character being read out \textit{ad nauseam} (\textit{eg}, `Asterisk, asterisk, asterisk…').

To overcome this limitation, the package uses the \texttt{accsup} package to add an `actual text' feature which will lead screen readers (and utilities like \texttt{pdftotext}) to replace the string of replacement characters with the two words `TEXT REDACTED'. This also will be encountered by naïve users who try to outdo the package by copying and pasting the black blocks from Adobe™ Acrobat or Reader.  (However, because other PDF readers, like Apple's Preview, do not implement accessibility features, this is \textbf{not} an additional security feature and is not on its own sufficient to work for redaction; if it were otherwise, the rest of the package would be unnecessary)



\subsection{Bugs and development}
All bugs, feature requests, or other technical points should be submitted to the package's official Github page.\footnote{\url{https://github.com/ezgranet/luacensor}}

\subsection{Licensing}
The software is free and open-sour ce software licensed under the Latex Public Project Licence.\footnote{\url{https://www.latex-project.org/lppl/}} 


\subsection{Some useful advice}
This package is really good at some things, but if you find it breaks down on censoring complex \LaTeX\ code, the existing \texttt{censor} package on \textsc{ctan} is excellent (albeit less good with accessibility), and works with non-\texttt{Lua} versions of \TeX. Incidentally, you can use both this package and \texttt{censor} in the same file without trouble; this (\textit{not} a penchant for annoying tech-speak) is why the main command in this package is \texttt{cnsr} without vowels.

\clearpage
\section{Implementation}
\begin{minted}[
frame=lines,
framesep=2mm,
baselinestretch=1.2,
bgcolor=LightGray,
fontsize=\footnotesize,
linenos,
breaklines,
firstnumber=last
]
{latex}
\ProvidesPackage{luacensor}
[2022/02/17
 Redact sensitive information using Lua]
% This work may be distributed and/or modified under the 
% conditions of the LaTeX Project Public License, either version 1.3 
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX 
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Elijah Z Granet
\end{minted}
\subsection{Dependencies}
\begin{minted}[
frame=lines,
framesep=2mm,
baselinestretch=1.2,
bgcolor=LightGray,
fontsize=\footnotesize,
linenos,
breaklines,
firstnumber=last
]{latex}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DEPENDENCIES
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage{luacode}
\RequirePackage{environ}
\RequirePackage{verbatim}
% ^ for the censoring
\RequirePackage{accsupp}
%^for accessibility
\RequirePackage{fontspec}
%^for black lines
%in theory, you could do 
%a lighter version of this
%package with just asterisks 
%or `[TEXT-REDACTED]'
%And perhaps that's better for
%the environment with printing
\end{minted}
\subsection{Fonts}
\begin{minted}[
frame=lines,
framesep=2mm,
baselinestretch=1.2,
bgcolor=LightGray,
fontsize=\footnotesize,
linenos,
breaklines,
firstnumber=last
]{latex}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FONTS
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% redacted is prettier and free to download
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Strongly recommended
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\IfFontExistsTF{Redacted}{%
\newfontface\cnsrfnt[%%%%%%
%the scale is arbitrary, but kind of works
Scale=1.1,
%%the below declarations are to prevent warnings about shapes not being available
ItalicFont=Redacted,%
BoldItalicFont=Redacted,%
BoldFont=Redacted,%
SmallCapsFont=Redacted]{Redacted}
\newcommand{\onething}{\cnsrfnt\ • }
\newcommand{\twothings}{\cnsrfnt\ • • }
\newcommand{\donothing}{}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%The little spaces let justification happen
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% x chosen as an arbitrary average width
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
}{
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This option works perfectly
%fine, it's just less pretty
%%but a good fallback because
% Source Sans is in TeX dists by default
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newfontface\cnsrfnt[Scale=1.01,%To allow for separate use of source sans in text
WordSpace=0,%To make it all one black line
%the below declarations are to prevent warnings about shapes not being available
ItalicFont={Source Sans Pro Black},BoldItalicFont={Source Sans Pro Black},BoldFont={Source Sans Pro Black},SmallCapsFont={Source Sans Pro Black}]{Source Sans Pro Black}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Bit of unicode magic below to make the black line effect
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\onething}{\cnsrfnt ▬ }
\newcommand{\twothings}{\cnsrfnt ▬ ▬ }
\newcommand{\donothing}{}
}
\end{minted}



\subsection{Eliminate pesky environments}
\begin{minted}[
frame=lines,
framesep=2mm,
baselinestretch=1.2,
bgcolor=LightGray,
fontsize=\footnotesize,
linenos,
breaklines,
firstnumber=last
]{latex}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% A neat fallback for disappearing things…
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FULL CREDIT
% and FULSOME THANKS
% TO TEX.SE USER
% Werner  for the code below
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatletter
\newcommand{\voidenvironment}[1]{%
  \expandafter\providecommand\csname env@#1@save@env\endcsname{}%
  \expandafter\providecommand\csname env@#1@process\endcsname{}%
  \@ifundefined{#1}{}{\RenewEnviron{#1}{}}%
}
\makeatother
\newcommand{\hddn}[1]{%
\ifcnsr{}\else%
#1\fi}
\newenvironment*{hidden}{\begin{@empty}
}{\end{@empty}}
\voidenvironment{hidden}

\end{minted}
\subsection{The \texttt{cnsr} command}
\begin{minted}[
frame=lines,
framesep=2mm,
baselinestretch=1.2,
bgcolor=LightGray,
fontsize=\footnotesize,
linenos,
breaklines,
firstnumber=last
]{latex}

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% the CENSOR COMMAND
%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newif\ifcnsr\cnsrfalse

\newcommand{\cnsr}[1]{%
  \ifcnsr{%
\voidenvironment{equation*}
\voidenvironment{equation}
\voidenvironment{table}
\voidenvironment{table*}
\voidenvironment{tabular}
\voidenvironment{tabular*}
\voidenvironment{}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% I don't know how many
% people use TEX native accent commands
% in LuaTEX given that using Unicode is more
%people's style.  But just in case, because these can lead to stray accent marks floating above censored letters.
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\renewcommand{\`}[1]{}
\renewcommand{\'}[1]{}
\renewcommand{\^}[1]{}
\renewcommand{\"}[1]{}
\renewcommand{\H}[1]{}
\renewcommand{\~}[1]{}
\renewcommand{\c}[1]{}
\renewcommand{\k}[1]{}
\renewcommand{\l}[1]{}
\renewcommand{\=}[1]{}
\renewcommand{\b}[1]{}
\renewcommand{\.}[1]{}
\renewcommand{\d}[1]{}
\renewcommand{\r}[1]{}
\renewcommand{\u}[1]{}
\renewcommand{\v}[1]{}
\renewcommand{\t}[1]{}
\renewcommand{\o}[1]{}
\renewcommand{\i}[1]{}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%TEX primitives can break the
%code because they don't have the good manners
%to put their arguments in brackets
%No offence, of course, to the 
%honoured Prof Knuth, who had
%magnificent genius reasons 
%for coding things that way
%it's just that i'm an idiot
%and therefore need things simple
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\renewcommand{\hskip}[1]{}
\renewcommand{\vskip}[1]{}
\renewcommand{\raise}[1]{}
\renewcommand{\lower}[1]{}
\renewcommand{\kern}[1]{}
% here we have the accsupp magic
% this operates by replacing the 'x's 
% or unicode black squares as the case
% may be with an alt text
% this serves a dual purpose of both making 
%pdftotext not break with huge strings of meaningless characters
%but more importantly
% it means screen readers don't subject
%. their users to the meaningless reading out of unicode black squares 50 times in a row!
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\BeginAccSupp{method=plain,ActualText={TEXT REDACTED}}%
\rndstring{#1}
\EndAccSupp{}%
}
  \else%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% if the conditional is off
% the command does absolutely nothing
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
#1%
\fi}
\end{minted}
\subsection{The Lua Magic}
\begin{minted}[
frame=lines,
framesep=2mm,
baselinestretch=1.2,
bgcolor=LightGray,
fontsize=\footnotesize,
linenos,
breaklines,
firstnumber=last
]{latex}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The LUA MAGIC PART
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{luacode}
\end{minted}
\begin{minted}[
frame=lines,
framesep=2mm,
baselinestretch=1.2,
bgcolor=LightGray,
fontsize=\footnotesize,
linenos,
breaklines,
firstnumber=last
]{lua}
--fulsome thanks to TeX.SE users Henri Menke and David Carlisle, without whom none of this would be possible 
local function rndstring()

    local toks = token.scan_toks(s)
        local on = tfrue
for n, t in ipairs(toks) do
    if t.csname == "begin" or t.csname == "end"  then
       on = false
-- The below is necessary as TeX primitives can break the code otherwise because they do not use brackets       
    end
   
   if not(on) and t.cmdname == "right_brace" then
     on = true
     -- This prevents needless errors about gibberish up commands
end
if on and t.csname ==  "&" then
  local letter = token.create'donothing'
 toks[n] = letter

elseif on and t.csname == "%" then
  local letter = token.create'donothing'
 toks[n] = letter

elseif on and t.csname == "$" then
  local letter = token.create'donothing'
 toks[n] = letter

elseif on and t.csname == "#" then
  local letter = token.create'donothing'
 toks[n] = letter

elseif on and t.csname == "_" then
  local letter = token.create'donothing'
 toks[n] = letter

elseif on and t.csname == "{" then
  local letter = token.create'donothing'
 toks[n] = letter

elseif on and t.csname == "}" then
  local letter = token.create'donothing'
 toks[n] = letter

elseif on and t.csname == "~" then
  local letter = token.create'donothing'
 toks[n] = letter

elseif on and t.csname == "^" then
  local letter = token.create'donothing'
 toks[n] = letter
elseif on and t.cmdname ==  "letter" then
-- The below is the randomness part of this, which I admit is fairly arbitrary, 
--but will more often  artificially shorten
--strings than lengthen them, as testing 
--found if lengthening was too frequent, it 
--led to really unsightly long strings. 

            local f = math.random (1,20)
            if f == 1 then
               local letter = token.create'donothing'
 toks[n] = letter

            	elseif f == 2 then
               local letter = token.create'donothing'
 toks[n] = letter
 elseif f == 3 then
   local letter = token.create'donothing'  toks[n] = letter
 elseif f == 4 then
               local letter = token.create'twothings'
  toks[n] = letter
   elseif f == 5 then
   local letter = token.create'donothing'  toks[n] = letter

   else 
               local letter = token.create'onething'
 toks[n] = letter
            	end
            	elseif
            on and t.cmdname == "spacer" then
            local f = math.random (1,20)
            	if f == 2 then
               local letter = token.create'donothing'
 toks[n] = letter
         		            elseif f == 3 then
                    
               local letter = token.create'donothing'  toks[n] = letter
 elseif f == 4 then
 local letter = token.create'donothing'
  toks[n] = letter
           		            elseif f == 5 then
                    

               local letter = token.create'twothings'  toks[n] = letter
 elseif f == 6 then
                    

               local letter = token.create'donothing'  toks[n] = letter
                  elseif f == 7 then
   local letter = token.create'donothing'  toks[n] = letter


   else 
               local letter = token.create'onething'
 toks[n] = letter
 
            	end

elseif on and t.cmdname == "other_char" then
            local f = math.random (1,20)

if f == 2 then local letter = token.create'donothing'
 toks[n] = letter

elseif f == 3 then
local letter = token.create'donothing'  toks[n] = letter
               
elseif f == 4 then
	local letter = token.create'donothing'
  	toks[n] = letter

elseif f == 5 then
	local letter = token.create'twothings' 
	toks[n] = letter
               
 elseif f == 6 then
local letter = token.create'donothing'  toks[n] = letter

elseif f == 7 then
local letter = token.create'donothing'  toks[n] = letter


else local letter = token.create'onething'
 toks[n] = letter
 
		end
			end
				end
 --Drop the token in and move on
        token.put_next(toks)
								end
	local lft = lua.get_functions_table()
--make a global command
lft[#lft + 1] = rndstring
token.set_lua("rndstring", #lft, "global")
\end{minted}
\begin{minted}[
frame=lines,
framesep=2mm,
baselinestretch=1.2,
bgcolor=LightGray,
fontsize=\footnotesize,
linenos,
breaklines, firstnumber=last
]{latex}
\end{luacode}
\end{minted}
\clearpage
\section{Version History}
\subsection{\texttt{1.00}}
\ttfamily 18 February 2022: Package creation

	
\end{document}