%luacensor.sty
\def\luacensorversionnumber{1.1.0}
\ProvidesPackage{luacensor}
[2022/02/22 \luacensorversionnumber\
 Redact sensitive information using Lua]
% !TeX program = lualatex                                   
% !TeX encoding = utf8
% 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
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% option (we'll come back
% to this later
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newif\ifwarning
\warningfalse
\DeclareOption{warning}{\warningtrue}
\ProcessOptions*
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DEPENDENCIES
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage{luacode}
\RequirePackage{environ}% http://ctan.org/pkg/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 would be better for
%the environment with printing
%BUT I MADE MY CHOICE!
\RequirePackage{xcolor}
\RequirePackage{graphicx}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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
%WordSpace=0,
ItalicFont={Redacted},%
BoldItalicFont={Redacted},%
BoldFont={Redacted},%
SmallCapsFont={Redacted}]{Redacted}
\newcommand{\onething}{\cnsrfnt\ • }
\newcommand{\twothings}{\cnsrfnt\ • •}
\newcommand{\donothing}{\cnsrfnt\ }
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%The little spaces let justification happen
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% • 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}{ }
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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}

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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]{}%
%%%%%%%%%%%%%%%%%%%%%%%%%%%d
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The LUA MAGIC PART
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{luacode}
--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 = true
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{luacode}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% WARNING FUN YAY
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Definitely this whole section
%is there to be user modified, because 
% depending on language, jurisdiction
%type of document etc, everyone will need
%a specific warning style. So the important
% part of the code here is the 
% conditional and global [warning]
% option, because that's the magic value added
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% fonts for the warning:
%I chose default LaTeX fonts
% here to be changed as users wish
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newfontface\wrnstncl{QT Military}
\newcommand{\warnword}{WARNING}
\newfontface\smbl{Deja Vu Sans Bold}
\newcommand{\danger}{\smbl ⚠︎\normalfont}
\newcommand{\warnformat}{\sffamily\bfseries \color{red}}
\newcommand{\textwarn}{This document is {\underline{NOT}}  redacted. It contains private and confidential personal data, and may {\underline{NOT}} be distributed, published, or shown to those without the right to view such information.  The publication of the information in this document may constitute a contempt of court, punishable by a term of imprisonment.}
\newcommand{\textsafe}{This document has been altered to remove sensitive personal data.  It is cleared for publication and dissemination.
}
\definecolor{darkgreen}{rgb}{0.0, 0.2, 0.13}
\definecolor{darkspringgreen}{rgb}{0.09, 0.45, 0.27}
	\definecolor{forestgreen}{rgb}{0.13, 0.55, 0.13}
\newcommand{\dquad}{\danger\danger\danger\danger}
\newcommand{\dangersign}[1]{\scalebox{2}{\huge\danger}}
\newcommand{\dangerblock}{\scalebox{2}{\huge\danger\quad\danger\quad\danger}}
\newcommand{\warnblock}{{\Large\wrnstncl\warnword\quad\warnword\quad\warnword}}
\newcommand{\tworules}{\hrule width \hsize height .7pt\vskip2pt\hrule width \hsize height .7pt}
\newcommand{\allwarning}{\dangerblock\\\warnblock\\\normalfont\smallskip\warnformat\textwarn }
\newcommand{\confwarning}{%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The warning option
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\ifwarning
\ifcnsr 
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% a note saying document is redacted
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{center}
\color{forestgreen}
\tworules\vskip5pt
\normalsize\normalfont\sffamily\bfseries\textsafe
\vskip5pt\tworules
\end{center}
\else 
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The WARNING for un-redacted docs
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{center}\color{red}\tworules\vskip 5pt\allwarning
\vskip5pt\tworules%
\end{center}%
\fi%
\else\fi}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Allow \maketitle
% on same page 
% yay
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\ifwarning\let\oldmaketitle\maketitle\renewcommand{\maketitle}{{\let\newpage\relax\maketitle}}\else\fi
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% print the warning at the start of the document
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\AtBeginDocument{\confwarning}