Fiat lux!

This commit is contained in:
Charlie 2024-12-03 17:39:52 -03:00
commit 976abf1a09
5 changed files with 1516 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
*.aux
*.log
*.out
*.pdf
*.fdb_latexmk
*.fls

12
Makefile Normal file
View file

@ -0,0 +1,12 @@
SHELL=/bin/sh
default: manual.pdf
livedoc:
echo manual.nw | python peat -C 'make manual.pdf'
manual.tex: manual.nw
any weave -delay -index manual.nw > manual.tex
manual.pdf: manual.tex
latexmk -pdf manual

285
manual.nw Normal file
View file

@ -0,0 +1,285 @@
% -*- mode: noweb; noweb-default-code-mode: lisp-mode; -*-
\documentclass[a4paper,11pt]{article}
\usepackage[text={6.75in,10in},centering]{geometry}
\usepackage{lipsum}
\usepackage{graphicx}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{csquotes}
\usepackage[brazil]{babel}
\usepackage{etoolbox}
\AtBeginEnvironment{quote}{\small}
\AtBeginEnvironment{verbatim}{\small}
%% \usepackage[backend=biber]{biblatex}
%% \addbibresource{refs.bib}
%% \renewcommand{\cite}{\parencite}
\usepackage[hyperref]{xcolor}
\usepackage[colorlinks=true,citecolor=]{hyperref} % linkcolor=red
\usepackage{amsmath,amsthm,amssymb}
\allowdisplaybreaks
\usepackage{lmodern}
\usepackage{noweb}
\noweboptions{brazil,longchunks,smallcode}
\DeclareMathOperator{\mdc}{mdc}
\DeclareMathOperator{\gcdext}{gcdext}
\DeclareMathOperator{\remainder}{remainder}
\DeclareMathOperator{\quotient}{quotient}
\DeclareMathOperator{\diff}{diff}
\def\nwendcode{\endtrivlist \endgroup}
\let\nwdocspar=\par
%% Popular names.
\newcommand{\lxxp}{{\em loop}}
\newcommand{\Lp}{{\tt LOOP}}
\newcommand{\lp}{\Lp}
\newcommand{\bug}{{\em bug}}
\newcommand{\symlink}{{\em symbolic link}}
\newcommand{\symlinks}{\symlink s}
\newcommand{\etc}{{\em et cetera}}
\newcommand{\til}{\textasciitilde}
\newcommand{\ezmlm}{{\tt ezmlm}}
\newcommand{\qmail}{{\tt qmail}}
\newcommand{\git}{{\tt git}}
\newcommand{\fg}{{\tt forgejo}}
\title{Manual da Antártida}
\date{Dezembro 2024}
\begin{document}
\fontfamily{cmr}\selectfont
\maketitle
\setlength{\parskip}{5pt}
%\setlength{\parindent}{0pt}
\section{Publicação de código-fonte}
Usamos o \fg\ como publicador web dos nossos
\href{https://git.antartida.xyz}{repositórios}. Pra você dirigir o
\fg, você precisa usar a conta \git, ou seja, peça {\tt su - git} ao
dono da casa, Charlie Root. Dizendo {\tt forgejo help}, você obtém
informação como
\begin{verbatim}
DEFAULT CONFIGURATION:
AppPath: /usr/local/sbin/forgejo
WorkPath: /usr/local/share/forgejo
CustomPath: /usr/local/etc/forgejo
ConfigFile: /usr/local/etc/forgejo/conf/app.ini
\end{verbatim}
\noindent{\bf Como customizar o site}? O \fg\ olha pra ver se existe algum
template customizado que substitua um dos templates padrão; se houver,
ele substitui; se não, não. Pra substituir {\em templates}, copie-os
do código-fonte pro {\tt CustomPath/templates}. Por exemplo, pra
alterar o código-fonte do template home.tmpl, copie o home.tmpl que
você encontra no código-fonte pra {\tt
CustomPath/templates/home.tmpl}. (Já fizemos isso, então você já
encontrará o {\tt home.tmpl} por lá.)
Fizemos uma customização que foi levar o usuário da página {\em home}
direto pra página {\tt explore/repos}. Em outras palavras, evitamos a
inútil página principal e levamos o visitante diretamente ao que temos
disponível. No modelo {\tt templates/base/head.tmpl} você encontra as
tags {\tt html, meta} {\em et cetera}.
%
\begin{verbatim}
{{if eq .TemplateName "home"}}
<meta http-equiv="refresh" content="0; url=https://git.antartida.xyz/explore/repos">
{{end}}
\end{verbatim}
%
A linguagem usada aí é {\em go templates}. O \fg\ é escrito em Go.
O ideal seria fazer o redirecionamento direto no cabeçalho HTTP, mas
não sei como reprogramar o \fg\ pra isso. Ah, na verdade a gente usa
o {\tt nginx} como {\em frontend} pro \fg, então só precisamos fazer o
redirecionamento no {\tt nginx} mesmo. Faz lá---tarefa pra você!
Fiz a tarefa. Não confie em mim quanto a falar a língua do {\tt
nginx}, mas me pareceu simples o construtor {\tt rewrite}. Infiro
que a expressão é comparada apenas contra o {\tt path} de uma URL e
não contra a URL toda. Por exemplo, a URL {\tt /?hello} também é
redirecionada pra {\tt /explore/repos}, como gostaríamos que fosse.
%
\begin{verbatim}
location / {
rewrite ^/$ /explore/repos redirect;
client_max_body_size 512M;
proxy_pass http://forgejo;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
\end{verbatim}
\noindent{\bf Onde encontrar o código-fonte}? Use o {\tt ports}. Vá
até {\tt /usr/ports/www/forgejo}. Diga {\tt make fetch} pra baixar o
código-fonte. Pronto. Agora navegue pelos novos arquivos que
apareceram e você se encontrará. Note que instalamos o \fg\ pelo {\tt
pkg} e não pelo {\tt ports}.
\undef\pib
\newcommand{\pib}{{\tt public-inbox}}
\newcommand{\ml}{{\em mailing list}}
\newcommand{\mls}{\ml{}{\em s}}
\undef\path\newcommand{\path}{{\em path}}
\section{Arquivos \pib}
O software \pib\ é um arquivador de \mls. A documentação disponível
sobre o \pib\ é essencialmente um conjunto de referências. Não há um
tutorial com passos para leigos---é a vida. Ele usa o git como base
de dados, ou seja, o arquivo da \ml\ em si é um repositório git.
Assim, você obtém o arquivo fazendo um clone. Por exemplo, clonemos a
\ml\ do próprio \pib.
\begin{verbatim}
%public-inbox-clone https://public-inbox.org/meta/
[...]
# /usr/local/bin/git clone --mirror https://public-inbox.org/meta meta
Cloning into bare repository 'meta'...
remote: Enumerating objects: 39480, done.
remote: Counting objects: 100% (1262/1262), done.
remote: Compressing objects: 100% (1262/1262), done.
remote: Total 39480 (delta 495), reused 0 (delta 0), pack-reused 38218
Receiving objects: 100% (39480/39480), 22.37 MiB | 817.00 KiB/s, done.
Resolving deltas: 100% (20326/20326), done.
[...]
# /usr/local/bin/git --git-dir=meta show-ref
# mirrored https://public-inbox.org/meta/ => meta
\end{verbatim}
Diga {\tt git log} em {\tt meta} e você verá cada messagem adiciona à
lista. Tem um {\tt Makefile} lá dentro que vale a pena ser lido. Ele
automatiza uma série de operações que estudaremos aqui. Por exemplo,
pra obter novas mensagens do repositório git que você clonou, basta
dizer {\tt make fetch}. Se você quiser de fato incorporar as novas
adições, você diz {\tt make update}. Leia o {\tt Makefile} pra ver
que comandos \pib\ executa em cada {\tt target}. Então agora você já
sabe como manter seu arquivo atualizado---peça ao {\tt cron} pra fazer
um {\em update} periódico.
É um jeito diferente de pensar em \mls. Em vez de você se inscrever
numa, você simplesmente copia o arquivo dela e lê o arquivo. Quando
quiser atualizar seu arquivo, atualiza e continua a leitura. É um
jeito mais inteligente. Inscrever-se numa \ml\ só faz sentido quando
você quer participar dela de forma bem completa---ler todas as
mensagens, responder cada uma com atenção \etc.
Note que o \pib\ tem evoluído. Existem agora duas versões de
arquivos, um chamado {\tt v1 public-inbox} e um mais novo chamado {\tt
v2}. Essa \ml\ que você acabou de clonar é {\tt v1}. Pra mais
informações, veja {\tt public-inbox-v1-format(5)}.
\noindent{\bf Como expor seu arquivo ao público via HTTP}? Antes de
pensar em expor, é preciso informá-lo ao \pib. Você vai criar um
arquivo de configuração em {\tt \til/.public-inbox/config}. Eis o meu
como exemplo, mas não crie esse arquivo de configuração, não---ele
pode deve ser criado pelo programa {\tt public-inbox-init}.
%
\begin{verbatim}
[publicinbox "meta"]
address = meta@public-inbox.org
url = https://public-inbox.org/meta
inboxdir = /usr/home/dbastos/inbox/meta
newsgroup = inbox.comp.mail.public-inbox.meta
\end{verbatim}
Eis o que disse a meu shell pra obter essa configuração:
%
\begin{verbatim}
public-inbox-init -V1 --ng inbox.comp.mail.public-inbox.meta \
meta ./meta https://public-inbox.org/meta \
meta@public-inbox.org
\end{verbatim}
Agora você já poderia executar o servidor web e assistir o arquivo na
web. Faça isso. Execute o {\tt public-inbox-httpd}, que vai ouvir na
porta 8080 por padrão, e você verá o arquivo se estendendo página web
agora no seu navegador. Vá até o fim da página e clique em {\tt
topics (new)}. Você receberá a mensagem ``[o]verview is not
available for this public-inbox''. Significa que você não tem um
índice pra navegar melhor por essa \ml. Crie o índice dizendo {\tt
public-inbox-index meta}, sendo {\tt meta} o diretório que contém
seu arquivo, ou seja, seu repositório git. Criar o índice leva um
tempo se a \ml\ é grande e a {\tt meta} não é muito pequena, além de
crescer com o tempo.
Criado o índice, diga {\tt public-inbox-httpd} a seu shell e observe o
servidor HTTP iniciar. Visite agora o endereço do seu computador com
\path\ {\tt /} na porta 8080---observe o shell pra obter a porta
correta---e use o protocolo HTTP e não HTTPS. Ele vai dizer ``{\tt no
inboxes, yet}''. Não sei por que ele não exibe uma lista de todas
as suas \mls. Mas ignora isso. Visite o \path\ {\tt /meta} e você
verá sua \ml, agora indexada. Parabéns. Você já sabe clonar e expor
seu arquivo para o mundo.
Seu próximo passo é aprender a construir uma \ml\ sua, uma original.
Pra isso você precisa saber construir \ml\ usando o \ezmlm. Como
exemplo, construi uma \ml\ chamada {\tt dbastos-testlist}. Cada
mensagem endereçada a {\tt dbastos-testlist@antartida.xyz} invoca os
programas programados em {\tt \til{}dbastos/.qmail-testlist}. Eis o
meu:
%
\begin{verbatim}
$ cat ~/.qmail-testlist
|/usr/local/bin/ezmlm/ezmlm-reject
|/usr/local/bin/ezmlm/ezmlm-send '/usr/home/dbastos/list/testlist'
|/usr/local/bin/ezmlm/ezmlm-warn '/usr/home/dbastos/list/testlist' || exit 0
|env ORIGINAL_RECIPIENT=dbastos-testlist@antartida.xyz \
/usr/local/bin/public-inbox-mda --no-precheck
\end{verbatim}
%
Em outras palavras, quando o qmail recebe uma mensagem pra {\tt
dbastos-testlist@antartida.xyz}, ele invoca cada um desses programas
aí. O último deles é o MDA do \pib. MDA significa {\em mail delivery
agent}. O {\tt public-inbox-mda} espera uma variável chamada {\tt
ORIGINAL\_RECIPIENT}. Servidores como Postfix já criam essa
variável, o que entrega o viés do autor do \pib\ pelo Postfix. Como
usamos o qmail, precisamos criar essa variável nós mesmo. Não sei
exatamente que conteúdo ela deveria ter---adivinhei que seria o
endereço da própria lista e fui em frente---com sucesso. Veja {\tt
public-inbox-mda(1)} pra mais informações.
\noindent{\bf Como expor seu arquivo ao público via NNTP}? Veja {\tt
public-inbox-nntpd}. Por exemplo:
%
\begin{verbatim}
$ public-inbox-nntpd -l nntp://0.0.0.0:1024
# bound nntp://0.0.0.0:1024
\end{verbatim}
%
Aí está seu servidor NNTP em ação. Em seguida, simule um cliente
usando {\tt telnet}:
\begin{verbatim}
$ telnet 0 1024
Trying 0.0.0.0...
Connected to 0.
Escape character is '^]'.
201 antartida.xyz ready - post via email
list
215 list of newsgroups follows
inbox.comp.mail.public-inbox.meta 9869 1 n
inbox.people.dbastos-testlist 5 1 n
.
quit
205 closing connection - goodbye!
Connection closed by foreign host.
\end{verbatim}
%
Aí estão seus arquivos servidos via NNTP. O \pib\ também é capaz de
servi-los via IMAP e POP3 se algum dia você desejá-los.
%% \section*{Index of chunks}
%% \nowebchunks
%%
%% \section*{Index of names}
%% \nowebindex
\end{document}

989
noweb.sty Normal file
View file

@ -0,0 +1,989 @@
% noweb.sty -- LaTeX support for noweb
% DON'T read or edit this file! Use ...noweb-source/tex/support.nw instead.
{\obeyspaces\AtBeginDocument{\global\let =\ }} % from texbook, p 381
\def\nwopt@nomargintag{\let\nwmargintag=\@gobble}
\def\nwopt@margintag{%
\def\nwmargintag##1{\leavevmode\llap{##1\kern\nwmarginglue\kern\codemargin}}}
\def\nwopt@margintag{%
\def\nwmargintag##1{\leavevmode\kern-\codemargin\nwthemargintag{##1}\kern\codemargin}}
\def\nwthemargintag#1{\llap{#1\kern\nwmarginglue}}
\nwopt@margintag
\newdimen\nwmarginglue
\nwmarginglue=0.3in
\def\nwtagstyle{\footnotesize\Rm}
% make \hsize in code sufficient for 88 columns
\setbox0=\hbox{\tt m}
\newdimen\codehsize
\codehsize=91\wd0 % 88 columns wasn't enough; I don't know why
\newdimen\codemargin
\codemargin=0pt
\newdimen\nwdefspace
\nwdefspace=\codehsize
% need to use \textwidth in {\LaTeX} to handle styles with
% non-standard margins (David Bruce). Don't know why we sometimes
% wanted \hsize. 27 August 1997.
%% \advance\nwdefspace by -\hsize\relax
\ifx\textwidth\undefined
\advance\nwdefspace by -\hsize\relax
\else
\advance\nwdefspace by -\textwidth\relax
\fi
\chardef\other=12
\def\setupcode{%
\chardef\\=`\\
\chardef\{=`\{
\chardef\}=`\}
\catcode`\$=\other
\catcode`\&=\other
\catcode`\#=\other
\catcode`\%=\other
\catcode`\~=\other
\catcode`\_=\other
\catcode`\^=\other
\catcode`\"=\other % fixes problem with german.sty
\obeyspaces\Tt
}
%\let\nwlbrace=\{
%\let\nwrbrace=\}
\def\nwendquote{\relax\ifhmode\spacefactor=1000 \fi}
{\catcode`\^^M=\active % make CR an active character
\gdef\newlines{\catcode`\^^M=\active % make CR an active character
\def^^M{\par\startline}}%
\gdef\eatline#1^^M{\relax}%
}
%%% DON'T \gdef^^M{\par\startline}}% in case ^^M appears in a \write
\def\startline{\noindent\hskip\parindent\ignorespaces}
\def\nwnewline{\ifvmode\else\hfil\break\leavevmode\hbox{}\fi}
\def\setupmodname{%
\catcode`\$=3
\catcode`\&=4
\catcode`\#=6
\catcode`\%=14
\catcode`\~=13
\catcode`\_=8
\catcode`\^=7
\catcode`\ =10
\catcode`\^^M=5
\let\nwlbrace\lbrace
\let\nwrbrace\rbrace
\let\{\nwlbrace
\let\}\nwrbrace
% bad news --- don't know what catcode to give "
\Rm}
\def\LA{\begingroup\maybehbox\bgroup\setupmodname\It$\langle$}
\def\RA{\/$\rangle$\egroup\endgroup}
\def\code{\leavevmode\begingroup\setupcode\newlines}
\def\edoc{\endgroup}
\let\maybehbox\relax
\newbox\equivbox
\setbox\equivbox=\hbox{$\equiv$}
\newbox\plusequivbox
\setbox\plusequivbox=\hbox{$\mathord{+}\mathord{\equiv}$}
% \moddef can't have an argument because there might be \code...\edoc
\def\moddef{\leavevmode\kern-\codemargin\LA}
\def\endmoddef{\RA\ifmmode\equiv\else\unhcopy\equivbox\fi
\nobreak\hfill\nobreak}
\def\plusendmoddef{\RA\ifmmode\mathord{+}\mathord{\equiv}\else\unhcopy\plusequivbox\fi
\nobreak\hfill\nobreak}
\def\chunklist{%
\errhelp{I changed \chunklist to \nowebchunks.
I'll try to avoid such incompatible changes in the future.}%
\errmessage{Use \string\nowebchunks\space instead of \string\chunklist}}
\def\nowebchunks{\message{<Warning: You need noweave -x to use \string\nowebchunks>}}
\def\nowebindex{\message{<Warning: You need noweave -index to use \string\nowebindex>}}
% here is support for the new-style (capitalized) font-changing commands
% thanks to Dave Love
\ifx\documentstyle\undefined
\let\Rm=\rm \let\It=\it \let\Tt=\tt % plain
\else\ifx\selectfont\undefined
\let\Rm=\rm \let\It=\it \let\Tt=\tt % LaTeX OFSS
\else % LaTeX NFSS
\def\Rm{\reset@font\rm}
\def\It{\reset@font\it}
\def\Tt{\reset@font\tt}
\def\Bf{\reset@font\bf}
\fi\fi
\ifx\reset@font\undefined \let\reset@font=\relax \fi
\def\noweboptions#1{%
\def\@nwoptionlist{#1}%
\@for\@nwoption:=\@nwoptionlist\do{%
\@ifundefined{nwopt@\@nwoption}{%
\@latexerr{There is no such noweb option as '\@nwoption'}\@eha}{%
\csname nwopt@\@nwoption\endcsname}}}
\codemargin=10pt
\advance\codehsize by \codemargin % make room for indentation of code
\advance\nwdefspace by \codemargin % and fix adjustment for def/use
\def\setcodemargin#1{%
\advance\codehsize by -\codemargin % make room for indentation of code
\advance\nwdefspace by -\codemargin % and fix adjustment for def/use
\codemargin=#1
\advance\codehsize by \codemargin % make room for indentation of code
\advance\nwdefspace by \codemargin % and fix adjustment for
% def/use
}
\def\nwopt@shift{%
\dimen@=-0.8in
\if@twoside % Values for two-sided printing:
\advance\evensidemargin by \dimen@
\else % Values for one-sided printing:
\advance\evensidemargin by \dimen@
\advance\oddsidemargin by \dimen@
\fi
% \advance \marginparwidth -\dimen@
}
\let\nwopt@noshift\@empty
\def\nwbegincode#1{%
\begingroup
\topsep \nwcodetopsep
\@beginparpenalty \@highpenalty
\@endparpenalty -\@highpenalty
\@begincode }
\def\nwendcode{\endtrivlist \endgroup \filbreak} % keeps code on 1 page
\newenvironment{webcode}{%
\@begincode
}{%
\endtrivlist}
\def\@begincode{%
\trivlist \item[]%
\leftskip\@totalleftmargin \advance\leftskip\codemargin
\rightskip\hsize \advance\rightskip -\codehsize
\parskip\z@ \parindent\z@ \parfillskip\@flushglue
\linewidth\codehsize
\@@par
\def\par{\leavevmode\null \@@par \penalty\nwcodepenalty}%
\obeylines
\@noligs \ifx\verbatim@nolig@list\undefined\else
\let\do=\nw@makeother \verbatim@nolig@list \do@noligs\`
\fi
\setupcode \frenchspacing \@vobeyspaces
\nowebsize \setupcode
\let\maybehbox\mbox }
\newskip\nwcodetopsep \nwcodetopsep = 3pt plus 1.2pt minus 1pt
\let\nowebsize=\normalsize
\def\nwopt@tinycode{\let\nowebsize=\tiny}
\def\nwopt@footnotesizecode{\let\nowebsize=\footnotesize}
\def\nwopt@scriptsizecode{\let\nowebsize=\scriptsize}
\def\nwopt@smallcode{\let\nowebsize=\small}
\def\nwopt@normalsizecode{\let\nowebsize=\normalsize}
\def\nwopt@largecode{\let\nowebsize=\large}
\def\nwopt@Largecode{\let\nowebsize=\Large}
\def\nwopt@LARGEcode{\let\nowebsize=\LARGE}
\def\nwopt@hugecode{\let\nowebsize=\huge}
\def\nwopt@Hugecode{\let\nowebsize=\Huge}
\newcount\nwcodepenalty \nwcodepenalty=\@highpenalty
\def\nw@makeother#1{\catcode`#1=12 }
\def\nwbegindocs#1{\ifvmode\noindent\fi}
\let\nwenddocs=\relax
\let\nwdocspar=\filbreak
\def\@nwsemifilbreak#1{\vskip0pt plus#1\penalty-200\vskip0pt plus -#1}
\newdimen\nwbreakcodespace
\nwbreakcodespace=0.2in % by default, leave no more than this on a page
\def\nwopt@breakcode{%
\def\nwdocspar{\@nwsemifilbreak{0.2in}}%
\def\nwendcode{\endtrivlist\endgroup} % ditches filbreak
}
\raggedbottom
\def\code{\leavevmode\begingroup\setupcode\@vobeyspaces\obeylines}
\let\edoc=\endgroup
\newdimen\@original@textwidth
\def\ps@noweb{%
\@original@textwidth=\textwidth
\let\@mkboth\@gobbletwo
\def\@oddfoot{}\def\@evenfoot{}% No feet.
\if@twoside % If two-sided printing.
\def\@evenhead{\hbox to \@original@textwidth{%
\Rm \thepage\qquad{\Tt\leftmark}\hfil\today}}% Left heading.
\def\@oddhead{\hbox to \@original@textwidth{%
\Rm \today\hfil{\Tt\leftmark}\qquad\thepage}}% Right heading.
\else % If one-sided printing.
\def\@oddhead{\hbox to \@original@textwidth{%
\Rm \today\hfil{\Tt\leftmark}\qquad\thepage}}% Right heading.
\let\@evenhead\@oddhead
\fi
\let\chaptermark\@gobble
\let\sectionmark\@gobble
\let\subsectionmark\@gobble
\let\subsubsectionmark\@gobble
\let\paragraphmark\@gobble
\let\subparagraphmark\@gobble
\def\nwfilename{\begingroup\let\do\@makeother\dospecials
\catcode`\{=1 \catcode`\}=2 \nw@filename}
\def\nw@filename##1{\endgroup\markboth{##1}{##1}\let\nw@filename=\nw@laterfilename}%
}
\def\nw@laterfilename#1{\endgroup\clearpage \markboth{#1}{#1}}
\let\nwfilename=\@gobble
\def\nwcodecomment#1{\@@par\penalty\nwcodepenalty
\if@firstnwcodecomment
\vskip\nwcodecommentsep\penalty\nwcodepenalty\@firstnwcodecommentfalse
\fi%
\hspace{-\codemargin}{%
\rightskip=0pt plus1in
\interlinepenalty\nwcodepenalty
\let\\\relax\footnotesize\Rm #1\@@par\penalty\nwcodepenalty}}
\def\@nwalsodefined#1{\nwcodecomment{\@nwlangdepdef\ \nwpageprep\ \@pagesl{#1}.}}
\def\@nwused#1{\nwcodecomment{\@nwlangdepcud\ \nwpageprep\ \@pagesl{#1}.}}
\def\@nwnotused#1{\nwcodecomment{\@nwlangdeprtc.}}
\def\nwoutput#1{\nwcodecomment{\@nwlangdepcwf\ {\Tt \@stripstar#1*\stripped}.}}
\def\@stripstar#1*#2\stripped{#1}
\newcommand{\nwprevdefptr}[1]{%
\mbox{$\mathord{\triangleleft}\,\mathord{\mbox{\subpageref{#1}}}$}}
\newcommand{\nwnextdefptr}[1]{%
\mbox{$\mathord{\mbox{\subpageref{#1}}}\,\mathord{\triangleright}$}}
\newcommand{\@nwprevnextdefs}[2]{%
{\nwtagstyle
\ifx\relax#1\else ~~\nwprevdefptr{#1}\fi
\ifx\relax#2\else ~~\nwnextdefptr{#2}\fi}}
\newcommand{\@nwusesondefline}[1]{{\nwtagstyle~~(\@pagenumsl{#1})}}
\newcommand{\@nwstartdeflinemarkup}{\nobreak\hskip 1.5em plus 1fill\nobreak}
\newcommand{\@nwenddeflinemarkup}{\nobreak\hskip \nwdefspace minus\nwdefspace\nobreak}
\def\nwopt@longxref{%
\let\nwalsodefined\@nwalsodefined
\let\nwused\@nwused
\let\nwnotused\@nwnotused
\let\nwprevnextdefs\@gobbletwo
\let\nwusesondefline\@gobble
\let\nwstartdeflinemarkup\relax
\let\nwenddeflinemarkup\relax
}
\def\nwopt@shortxref{%
\let\nwalsodefined\@gobble
\let\nwused\@gobble
\let\nwnotused\@gobble
\let\nwprevnextdefs\@nwprevnextdefs
\let\nwusesondefline\@nwusesondefline
\let\nwstartdeflinemarkup\@nwstartdeflinemarkup
\let\nwenddeflinemarkup\@nwenddeflinemarkup
}
\def\nwopt@noxref{%
\let\nwalsodefined\@gobble
\let\nwused\@gobble
\let\nwnotused\@gobble
\let\nwprevnextdefs\@gobbletwo
\let\nwusesondefline\@gobble
\let\nwstartdeflinemarkup\relax
\let\nwenddeflinemarkup\relax
}
\nwopt@shortxref % to hell with backward compatibility!
\newskip\nwcodecommentsep \nwcodecommentsep=3pt plus 1pt minus 1pt
\newif\if@firstnwcodecomment\@firstnwcodecommenttrue
\newcount\@nwlopage\newcount\@nwhipage % range lo..hi-1
\newcount\@nwlosub % subpage of lo
\newcount\@nwhisub % subpage of hi
\def\@nwfirstpage#1#2#3{% subpage page xref-tag
\@nwlopage=#2 \@nwlosub=#1
\def\@nwloxreftag{#3}%
\advance\@nwpagecount by \@ne
\@nwhipage=\@nwlopage\advance\@nwhipage by \@ne }
\def\@nwnextpage#1#2#3{% subpage page xref-tag
\ifnum\@nwhipage=#2
\advance\@nwhipage by \@ne
\advance\@nwpagecount by \@ne
\@nwhisub=#1
\def\@nwhixreftag{#3}\else
\ifnum#2<\@nwlopage \advance\@nwhipage by \m@ne
\ifnum\@nwhipage=\@nwlopage
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}}%
\else
\count@=\@nwhipage \advance\count@ by \m@ne
\ifnum\count@=\@nwlopage % consecutive pages
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}%
\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwhisub}{\number\@nwhipage}}
{\@nwhixreftag}}}%
\else \ifnum\@nwlopage<110 \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100 \multiply\count@ by 100
\ifnum\count@=\@nwlopage \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100
\@nwpagetemp=\@nwhipage \divide\@nwpagetemp by 100
\ifnum\count@=\@nwpagetemp % lo--least 2 digits of hi
\multiply\@nwpagetemp by 100
\advance \@nwhipage by -\@nwpagetemp
\edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\else \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\fi
\fi
\fi%
\fi
\fi%
\edef\@tempa{\noexpand\nwix@cons\noexpand\nw@pages{\@tempa}}\@tempa\@nwfirstpage{#1}{#2}{#3}\else
\ifnum#2>\@nwhipage \advance\@nwhipage by \m@ne
\ifnum\@nwhipage=\@nwlopage
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}}%
\else
\count@=\@nwhipage \advance\count@ by \m@ne
\ifnum\count@=\@nwlopage % consecutive pages
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}%
\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwhisub}{\number\@nwhipage}}
{\@nwhixreftag}}}%
\else \ifnum\@nwlopage<110 \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100 \multiply\count@ by 100
\ifnum\count@=\@nwlopage \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100
\@nwpagetemp=\@nwhipage \divide\@nwpagetemp by 100
\ifnum\count@=\@nwpagetemp % lo--least 2 digits of hi
\multiply\@nwpagetemp by 100
\advance \@nwhipage by -\@nwpagetemp
\edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\else \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\fi
\fi
\fi%
\fi
\fi%
\edef\@tempa{\noexpand\nwix@cons\noexpand\nw@pages{\@tempa}}\@tempa\@nwfirstpage{#1}{#2}{#3}\else
\@nwlosub=0 \@nwhisub=0
\fi\fi\fi
}
\newcount\@nwpagetemp
\newcount\@nwpagecount
\def\@nwfirstpagel#1{% label
\@ifundefined{r@#1}{\@warning{Reference `#1' on page \thepage \space undefined}%
\nwix@cons\nw@pages{\\{\bf ??}}}{%
\edef\@tempa{\noexpand\@nwfirstpage\subpagepair{#1}{#1}}\@tempa}}
\def\@nwnextpagel#1{% label
\@ifundefined{r@#1}{\@warning{Reference `#1' on page \thepage \space undefined}%
\nwix@cons\nw@pages{\\{\bf ??}}}{%
\edef\@tempa{\noexpand\@nwnextpage\subpagepair{#1}{#1}}\@tempa}}
\def\@pagesl#1{% list of labels
\gdef\nw@pages{}\@nwpagecount=0
\def\\##1{\@nwfirstpagel{##1}\let\\=\@nwnextpagel}#1%
\advance\@nwhipage by \m@ne
\ifnum\@nwhipage=\@nwlopage
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}}%
\else
\count@=\@nwhipage \advance\count@ by \m@ne
\ifnum\count@=\@nwlopage % consecutive pages
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}%
\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwhisub}{\number\@nwhipage}}
{\@nwhixreftag}}}%
\else \ifnum\@nwlopage<110 \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100 \multiply\count@ by 100
\ifnum\count@=\@nwlopage \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100
\@nwpagetemp=\@nwhipage \divide\@nwpagetemp by 100
\ifnum\count@=\@nwpagetemp % lo--least 2 digits of hi
\multiply\@nwpagetemp by 100
\advance \@nwhipage by -\@nwpagetemp
\edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\else \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\fi
\fi
\fi%
\fi
\fi%
\edef\@tempa{\noexpand\nwix@cons\noexpand\nw@pages{\@tempa}}\@tempa\def\\##1{\@nwhyperpagenum##1}%
\ifnum\@nwpagecount=1 \nwpageword \else \nwpagesword\fi~\commafy{\nw@pages}}
\def\@nwhyperpagenum#1#2{\nwhyperreference{#2}{#1}}
\def\@pagenumsl#1{% list of labels -- doesn't include word `pages', commas, or `and'
\gdef\nw@pages{}\@nwpagecount=0
\def\\##1{\@nwfirstpagel{##1}\let\\=\@nwnextpagel}#1%
\advance\@nwhipage by \m@ne
\ifnum\@nwhipage=\@nwlopage
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}}%
\else
\count@=\@nwhipage \advance\count@ by \m@ne
\ifnum\count@=\@nwlopage % consecutive pages
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}%
\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwhisub}{\number\@nwhipage}}
{\@nwhixreftag}}}%
\else \ifnum\@nwlopage<110 \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100 \multiply\count@ by 100
\ifnum\count@=\@nwlopage \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100
\@nwpagetemp=\@nwhipage \divide\@nwpagetemp by 100
\ifnum\count@=\@nwpagetemp % lo--least 2 digits of hi
\multiply\@nwpagetemp by 100
\advance \@nwhipage by -\@nwpagetemp
\edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\else \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\fi
\fi
\fi%
\fi
\fi%
\edef\@tempa{\noexpand\nwix@cons\noexpand\nw@pages{\@tempa}}\@tempa%
\def\\##1{\@nwhyperpagenum##1\let\\=\@nwpagenumslrest}\nw@pages}
\def\@nwpagenumslrest#1{~\@nwhyperpagenum#1}
\def\subpages#1{% list of {{subpage}{page}}
\gdef\nw@pages{}\@nwpagecount=0
\def\\##1{\edef\@tempa{\noexpand\@nwfirstpage##1{}}\@tempa
\def\\####1{\edef\@tempa{\noexpand\@nwnextpage####1}\@tempa}}#1%
\advance\@nwhipage by \m@ne
\ifnum\@nwhipage=\@nwlopage
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}}%
\else
\count@=\@nwhipage \advance\count@ by \m@ne
\ifnum\count@=\@nwlopage % consecutive pages
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}%
\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwhisub}{\number\@nwhipage}}
{\@nwhixreftag}}}%
\else \ifnum\@nwlopage<110 \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100 \multiply\count@ by 100
\ifnum\count@=\@nwlopage \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100
\@nwpagetemp=\@nwhipage \divide\@nwpagetemp by 100
\ifnum\count@=\@nwpagetemp % lo--least 2 digits of hi
\multiply\@nwpagetemp by 100
\advance \@nwhipage by -\@nwpagetemp
\edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\else \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\fi
\fi
\fi%
\fi
\fi%
\edef\@tempa{\noexpand\nwix@cons\noexpand\nw@pages{\@tempa}}\@tempa\def\\##1{\@firstoftwo##1}%
\ifnum\@nwpagecount=1 \nwpageword \else \nwpagesword\fi~\commafy{\nw@pages}}
\def\@nwaddrange{\advance\@nwhipage by \m@ne
\ifnum\@nwhipage=\@nwlopage
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}}%
\else
\count@=\@nwhipage \advance\count@ by \m@ne
\ifnum\count@=\@nwlopage % consecutive pages
\edef\@tempa{\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}%
{\@nwloxreftag}}%
\noexpand\noexpand\noexpand\\%
{{\nwthepagenum{\number\@nwhisub}{\number\@nwhipage}}
{\@nwhixreftag}}}%
\else \ifnum\@nwlopage<110 \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100 \multiply\count@ by 100
\ifnum\count@=\@nwlopage \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}\else
\count@=\@nwlopage \divide\count@ by 100
\@nwpagetemp=\@nwhipage \divide\@nwpagetemp by 100
\ifnum\count@=\@nwpagetemp % lo--least 2 digits of hi
\multiply\@nwpagetemp by 100
\advance \@nwhipage by -\@nwpagetemp
\edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\else \edef\@tempa{\noexpand\noexpand\noexpand\\{{\number\@nwlopage--\number\@nwhipage}{}}}%
\fi
\fi
\fi%
\fi
\fi%
\edef\@tempa{\noexpand\nwix@cons\noexpand\nw@pages{\@tempa}}\@tempa}
\def\nwpageword{\@nwlangdepchk} % chunk, was page
\def\nwpagesword{\@nwlangdepchks} % chunk, was page
\def\nwpageprep{\@nwlangdepin} % in, was on
\newcommand\nw@genericref[2]{% what to do, name of ref
\expandafter\nw@g@nericref\csname r@#2\endcsname#1{#2}}
\newcommand\nw@g@nericref[3]{% control sequence, what to do, name
\ifx#1\relax
\ref{#3}% trigger the standard `undefined ref' mechanisms
\else
\expandafter#2#1.\\%
\fi}
\def\nw@selectone#1#2#3\\{#1}
\def\nw@selecttwo#1#2#3\\{#2}
\def\nw@selectonetwo#1#2#3\\{{#1}{#2}}
\newcommand{\subpageref}[1]{%
\nwhyperreference{#1}{\nw@genericref\@subpageref{#1}}}
\def\@subpageref#1#2#3\\{%
\@ifundefined{2on#2}{#2}{\nwthepagenum{#1}{#2}}}
\newcommand{\subpagepair}[1]{% % produces {subpage}{page}
\@ifundefined{r@#1}%
{{0}{0}}%
{\nw@genericref\@subpagepair{#1}}}
\def\@subpagepair#1#2#3\\{%
\@ifundefined{2on#2}{{0}{#2}}{{#1}{#2}}}
\newcommand{\sublabel}[1]{%
\leavevmode % needed to make \@bsphack work
\@bsphack
\nwblindhyperanchor{#1}%
\if@filesw {\let\thepage\relax
\def\protect{\noexpand\noexpand\noexpand}%
\edef\@tempa{\write\@auxout{\string
\newsublabel{#1}{{}{\thepage}}}}%
\expandafter}\@tempa
\if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack}
\newcommand{\nosublabel}[1]{%
\@bsphack\if@filesw {\let\thepage\relax
\def\protect{\noexpand\noexpand\noexpand}%
\edef\@tempa{\write\@auxout{\string
\newlabel{#1}{{0}{\thepage}}}}%
\expandafter}\@tempa
\if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack}
\newcommand\newsublabel{%
\nw@settrailers
\global\let\newsublabel\@newsublabel
\@newsublabel}
\newcommand{\@newsublabel}[2]{%
\edef\this@page{\@cdr#2\@nil}%
\ifx\this@page\last@page\else
\sub@page=\z@
\fi
\edef\last@page{\this@page}
\advance\sub@page by \@ne
\ifnum\sub@page=\tw@
\global\@namedef{2on\this@page}{}%
\fi
\pendingsublabel{#1}%
\edef\@tempa##1{\noexpand\newlabel{##1}%
{{\number\sub@page}{\this@page}\nw@labeltrailers}}%
\pending@sublabels
\def\pending@sublabels{}}
\newcommand\nw@settrailers{% -- won't work on first run
\@ifpackageloaded{nameref}%
{\gdef\nw@labeltrailers{{}{}{}}}%
{\gdef\nw@labeltrailers{}}}
\renewcommand\nw@settrailers{%
\@ifundefined{@secondoffive}%
{\gdef\nw@labeltrailers{}}%
{\gdef\nw@labeltrailers{{}{}{}}}}
\newcommand{\nextchunklabel}[1]{%
\nwblindhyperanchor{#1}% % looks slightly bogus --- nr
\@bsphack\if@filesw {\let\thepage\relax
\edef\@tempa{\write\@auxout{\string\pendingsublabel{#1}}}%
\expandafter}\@tempa
\if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack}
\newcommand\pendingsublabel[1]{%
\def\@tempa{\noexpand\@tempa}%
\edef\pending@sublabels{\noexpand\@tempa{#1}\pending@sublabels}}
\def\pending@sublabels{}
\def\last@page{\relax}
\newcount\sub@page
\def\@alphasubpagenum#1#2{#2\ifnum#1=0 \else\@alph{#1}\fi}
\def\@nosubpagenum#1#2{#2}
\def\@numsubpagenum#1#2{#2\ifnum#1=0 \else.\@arabic{#1}\fi}
\def\nwopt@nosubpage{\let\nwthepagenum=\@nosubpagenum\nwopt@nomargintag}
\def\nwopt@numsubpage{\let\nwthepagenum=\@numsubpagenum}
\def\nwopt@alphasubpage{\let\nwthepagenum=\@alphasubpagenum}
\nwopt@alphasubpage
\newcount\@nwalph@n
\let\@nwalph@d\@tempcnta
\let\@nwalph@bound\@tempcntb
\def\@nwlongalph#1{{%
\@nwalph@n=#1\advance\@nwalph@n by-1
\@nwalph@bound=26
\loop\ifnum\@nwalph@n<\@nwalph@bound\else
\advance\@nwalph@n by -\@nwalph@bound
\multiply\@nwalph@bound by 26
\repeat
\loop\ifnum\@nwalph@bound>1
\divide\@nwalph@bound by 26
\@nwalph@d=\@nwalph@n\divide\@nwalph@d by \@nwalph@bound
% d := d * bound ; n -:= d; d := d / bound --- saves a temporary
\multiply\@nwalph@d by \@nwalph@bound
\advance\@nwalph@n by -\@nwalph@d
\divide\@nwalph@d by \@nwalph@bound
\advance\@nwalph@d by 1 \@alph{\@nwalph@d}%
\repeat
}}
\newcount\nw@chunkcount
\nw@chunkcount=\@ne
\newcommand{\weblabel}[1]{%
\@bsphack
\nwblindhyperanchor{#1}%
\if@filesw {\let\thepage\relax
\def\protect{\noexpand\noexpand\noexpand}%
\edef\@tempa{\write\@auxout{\string
\newsublabel{#1}{{}{\number\nw@chunkcount}}}}%
\expandafter}\@tempa
\global\advance\nw@chunkcount by \@ne
\if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack}
\def\nwopt@webnumbering{%
\let\sublabel=\weblabel
\def\nwpageword{chunk}\def\nwpagesword{chunks}%
\def\nwpageprep{in}}
% \nwindexdefn{printable name}{identifying label}{label of chunk}
% \nwindexuse{printable name}{identifying label}{label of chunk}
\def\nwindexdefn#1#2#3{\@auxix{\protect\nwixd}{#2}{#3}}
\def\nwindexuse#1#2#3{\@auxix{\protect\nwixu}{#2}{#3}}
\def\@auxix#1#2#3{% {marker}{id label}{subpage label}
\@bsphack\if@filesw {\let\nwixd\relax\let\nwixu\relax
\def\protect{\noexpand\noexpand\noexpand}%
\edef\@tempa{\write\@auxout{\string\nwixadd{#1}{#2}{#3}}}%
\expandafter}\@tempa
\if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack}
% \nwixadd{marker}{idlabel}{subpage label}
\def\nwixadd#1#2#3{%
\@ifundefined{nwixl@#2}%
{\global\@namedef{nwixl@#2}{#1{#3}}}%
{\expandafter\nwix@cons\csname nwixl@#2\endcsname{#1{#3}}}}
\def\@nwsubscriptident#1#2{\mbox{$\mbox{#1}_{\mathrm{\subpageref{#2}}}$}}
\def\@nwnosubscriptident#1#2{#1}
\def\@nwhyperident#1#2{\leavevmode\nwhyperreference{#2}{#1}}
\def\nwopt@subscriptidents{%
\let\nwlinkedidentq\@nwsubscriptident
\let\nwlinkedidentc\@nwsubscriptident
}
\def\nwopt@nosubscriptidents{%
\let\nwlinkedidentq\@nwnosubscriptident
\let\nwlinkedidentc\@nwnosubscriptident
}
\def\nwopt@hyperidents{%
\let\nwlinkedidentq\@nwhyperident
\let\nwlinkedidentc\@nwhyperident
}
\def\nwopt@nohyperidents{%
\let\nwlinkedidentq\@nwnosubscriptident
\let\nwlinkedidentc\@nwnosubscriptident
}
\def\nwopt@subscriptquotedidents{%
\let\nwlinkedidentq\@nwsubscriptident
}
\def\nwopt@nosubscriptquotedidents{%
\let\nwlinkedidentq\@nwnosubscriptident
}
\def\nwopt@hyperquotedidents{%
\let\nwlinkedidentq\@nwhyperident
}
\def\nwopt@nohyperquotedidents{%
\let\nwlinkedidentq\@nwnosubscriptident
}
\nwopt@hyperidents
\newcount\@commacount
\def\commafy#1{%
{\nwix@listcount{#1}\@commacount=\nwix@counter
\let\@comma@each=\\%
\ifcase\@commacount\let\\=\@comma@each\or\let\\=\@comma@each\or
\def\\{\def\\{ \@nwlangdepand\ \@comma@each}\@comma@each}\else
\def\\{\def\\{, %
\advance\@commacount by \m@ne
\ifnum\@commacount=1 \@nwlangdepand~\fi\@comma@each}\@comma@each}\fi
#1}}
\def\nwix@cons#1#2{% {list}{\marker{element}}
{\toks0=\expandafter{#1}\def\@tempa{#2}\toks2=\expandafter{\@tempa}%
\xdef#1{\the\toks0 \the\toks2 }}}
\def\nwix@uses#1{% {label}
\def\nwixu{\\}\let\nwixd\@gobble\@nameuse{nwixl@#1}}
\def\nwix@defs#1{% {label}
\def\nwixd{\\}\let\nwixu\@gobble\@nameuse{nwixl@#1}}
\newcount\nwix@counter
\def\nwix@listcount#1{% {list with \\}
{\count@=0
\def\\##1{\advance\count@ by \@ne }%
#1\global\nwix@counter=\count@ }}
\def\nwix@usecount#1{\nwix@listcount{\nwix@uses{#1}}}
\def\nwix@defcount#1{\nwix@listcount{\nwix@defs{#1}}}
\def\nwix@id@defs#1{% index pair
{{\Tt \@car#1\@nil}%
\def\\##1{\nwix@defs@space\subpageref{##1}}\nwix@defs{\@cdr#1\@nil}}}
% useful above to change ~ into something that can break
% this option is undocumented because I think breakdefs is always right
\def\nwopt@breakdefs{\def\nwix@defs@space{\penalty200\ }}
\def\nwopt@nobreakdefs{\def\nwix@defs@space{~}} % old code
\nwopt@breakdefs
\def\nwidentuses#1{% list of index pairs
\nwcodecomment{\@nwlangdepuss\ \let\\=\nwix@id@defs\commafy{#1}.}}
\def\nwix@totaluses#1{% list of index pairs
{\count@=0
\def\\##1{\nwix@usecount{\@cdr##1\@nil}\advance\count@ by\nwix@counter}%
#1\global\nwix@counter\count@ }}
\def\nwix@id@uses#1#2{% {ident}{label}
\nwix@usecount{#2}\ifnum\nwix@counter>0
{\advance\leftskip by \codemargin
\nwcodecomment{{\Tt #1}, \@nwlangdepusd\ \nwpageprep\ \@pagesl{\nwix@uses{#2}}.}}%
\else
\ifnw@hideunuseddefs\else
{\advance\leftskip by \codemargin \nwcodecomment{{\Tt #1}, \@nwlangdepnvu.}}%
\fi
\fi}
\def\nwidentdefs#1{% list of index pairs
\ifnw@hideunuseddefs\nwix@totaluses{#1}\else\nwix@listcount{#1}\fi
\ifnum\nwix@counter>0
\nwcodecomment{\@nwlangdepdfs:}%
{\def\\##1{\nwix@id@uses ##1}#1}%
\fi}
\newif\ifnw@hideunuseddefs\nw@hideunuseddefsfalse
\def\nwopt@hideunuseddefs{\nw@hideunuseddefstrue}
\def\nwopt@noidentxref{%
\let\nwidentdefs\@gobble
\let\nwidentuses\@gobble}
\def\nw@underlinedefs{% {list with \nwixd, \nwixu}
\let\\=\relax\def\nw@comma{, }
\def\nwixd##1{\\\underline{\subpageref{##1}}\let\\\nw@comma}%
\def\nwixu##1{\\\subpageref{##1}\let\\\nw@comma}}
\def\nw@indexline#1#2{%
{\indent {\Tt #1}: \nw@underlinedefs\@nameuse{nwixl@#2}\par}}
\newenvironment{thenowebindex}{\parindent=-10pt \parskip=\z@
\advance\leftskip by 10pt
\advance\rightskip by 0pt plus1in\par\@afterindenttrue
\def\\##1{\nw@indexline##1}}{}
\def\nowebindex{%
\@ifundefined{nwixs@i}%
{\@warning{The \string\nowebindex\space is empty}}%
{\begin{thenowebindex}\@nameuse{nwixs@i}\end{thenowebindex}}}
\def\nowebindex@external{%
{\let\nwixadds@c=\@gobble
\def\nwixadds@i##1{\nw@indexline##1}%
\def\nwixaddsx##1##2{\@nameuse{nwixadds@##1}{##2}}%
\begin{thenowebindex}\@input{\jobname.nwi}\end{thenowebindex}}}
\def\nwixlogsorted#1#2{% list data
\@bsphack\if@filesw
\toks0={#2}\immediate\write\@auxout{\string\nwixadds{#1}{\the\toks0}}
\if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack}
\def\nwixadds#1#2{%
\@ifundefined{nwixs@#1}%
{\global\@namedef{nwixs@#1}{\\{#2}}}%
{\expandafter\nwix@cons\csname nwixs@#1\endcsname{\\{#2}}}}
\let\nwixaddsx=\@gobbletwo
\def\nwopt@externalindex{%
\ifx\nwixadds\@gobbletwo % already called
\else
\let\nwixaddsx=\nwixadds \let\nwixadds=\@gobbletwo
\let\nowebindex=\nowebindex@external
\let\nowebchunks=\nowebchunks@external
\fi}
\def\nowebchunks{%
\@ifundefined{nwixs@c}%
{\@warning{The are no \string\nowebchunks}}%
{\begin{thenowebchunks}\@nameuse{nwixs@c}\end{thenowebchunks}}}
\def\nowebchunks@external{%
{\let\nwixadds@i=\@gobble
\def\nwixadds@c##1{\nw@onechunk##1}%
\def\nwixaddsx##1##2{\@nameuse{nwixadds@##1}{##2}}%
\begin{thenowebchunks}\@input{\jobname.nwi}\end{thenowebchunks}}}
\@namedef{r@nw@notdef}{{0}{(\@nwlangdepnvd)}}
\def\nw@chunkunderlinedefs{% {list of labels with \nwixd, \nwixu}
\let\\=\relax\def\nw@comma{, }
\def\nwixd##1{\\\underline{\subpageref{##1}}\let\\\nw@comma}%
\def\nwixu##1{\\\subpageref{##1}\let\\\nw@comma}}
\def\nw@onechunk#1#2#3{% {name}{label of first definition}{list with \nwixd, \nwixu}
\@ifundefined{r@#2}{}{%
\indent\LA #1~{\nwtagstyle\subpageref{#2}}\RA
\if@nwlongchunks{~\nw@chunkunderlinedefs#3}\fi\par}}
\newenvironment{thenowebchunks}{\vskip3pt
\parskip=\z@\parindent=-10pt \advance\leftskip by 10pt
\advance\rightskip by 0pt plus10pt \@afterindenttrue
\def\\##1{\nw@onechunk##1}}{}
\newif\if@nwlongchunks
\@nwlongchunksfalse
\let\nwopt@longchunks\@nwlongchunkstrue
\newcommand\@nw@hyper@ref{\hyperreference} % naras
\newcommand\@nw@hyper@anc{\blindhyperanchor} % naras
\newcommand\@nw@hyperref@ref[2]{\hyperlink{noweb.#1}{#2}} % nr
\newcommand\@nw@hyperref@anc[1]{\hypertarget{noweb.#1}{\relax}} % nr
%%\renewcommand\@nw@hyperref@ref[2]{{#2}} % nr
%%\renewcommand\@nw@hyperref@anc[1]{} % nr
\newcommand\nwhyperreference{%
\@ifundefined{hyperlink}
{\@ifundefined{hyperreference}
{\global\let\nwhyperreference\@gobble}
{\global\let\nwhyperreference\@nw@hyper@ref}}
{\global\let\nwhyperreference\@nw@hyperref@ref}%
\nwhyperreference
}
\newcommand\nwblindhyperanchor{%
\@ifundefined{hyperlink}
{\@ifundefined{hyperreference}
{\global\let\nwblindhyperanchor\@gobble}
{\global\let\nwblindhyperanchor\@nw@hyper@anc}}
{\global\let\nwblindhyperanchor\@nw@hyperref@anc}%
\nwblindhyperanchor
}
\newcommand\nwanchorto{%
\begingroup\let\do\@makeother\dospecials
\catcode`\{=1 \catcode`\}=2 \nw@anchorto}
\newcommand\nw@anchorto[1]{\endgroup\def\nw@next{#1}\nw@anchortofin}
\newcommand\nw@anchortofin[1]{#1\footnote{See URL \texttt{\nw@next}.}}
\let\nwanchorname\@gobble
\newif\ifhtml
\htmlfalse
\let\nwixident=\relax
\def\nwbackslash{\char92}
\def\nwlbrace{\char123}
\def\nwrbrace{\char125}
\def\nwopt@english{%
\def\@nwlangdepdef{This definition is continued}%
\def\@nwlangdepcud{This code is used}%
\def\@nwlangdeprtc{Root chunk (not used in this document)}%
\def\@nwlangdepcwf{This code is written to file}%
\def\@nwlangdepchk{chunk}%
\def\@nwlangdepchks{chunks}%
\def\@nwlangdepin{in}%
\def\@nwlangdepand{and}%
\def\@nwlangdepuss{Uses}%
\def\@nwlangdepusd{used}%
\def\@nwlangdepnvu{never used}%
\def\@nwlangdepdfs{Defines}%
\def\@nwlangdepnvd{never defined}%
}
\let\nwopt@american\nwopt@english
\def\nwopt@portuges{%
\def\@nwlangdepdef{Defini\c{c}\~ao continuada em}%
% This definition is continued
\def\@nwlangdepcud{C\'odigo usado em}%
% This code is used
\def\@nwlangdeprtc{Fragmento de topo (sem uso no documento)}%
% Root chunk (not used in this document)
\def\@nwlangdepcwf{Este c\'odigo foi escrito no ficheiro}%
% This code is written to file
\def\@nwlangdepchk{fragmento}%
% chunk
\def\@nwlangdepchks{fragmentos}%
% chunks
\def\@nwlangdepin{no(s)}%
% in
\def\@nwlangdepand{e}%
% and
\def\@nwlangdepuss{Usa}%
% Uses
\def\@nwlangdepusd{usado}%
% used
\def\@nwlangdepnvu{nunca usado}%
% never used
\def\@nwlangdepdfs{Define}%
% Defines
\def\@nwlangdepnvd{nunca definido}%
% never defined
}
\def\nwopt@brazil{%
\def\@nwlangdepdef{Defini\c{c}\~{a}o continua}%
% This definition is continued
\def\@nwlangdepcud{C\'odigo usado}%
% This code is used
\def\@nwlangdeprtc{Trecho raiz, isto é, este trecho come\c{c}a aqui}%
% Root chunk (not used in this document)
\def\@nwlangdepcwf{C\'odigo escrito no arquivo}%
% This code is written to file
\def\@nwlangdepchk{trecho}%
% chunk
\def\@nwlangdepchks{trechos}%
% chunks
\def\@nwlangdepin{@}%
% in
\def\@nwlangdepand{e}%
% and
\def\@nwlangdepuss{Usa}%
% Uses
\def\@nwlangdepusd{usado}%
% used
\def\@nwlangdepnvu{nunca usado}%
% never used
\def\@nwlangdepdfs{Define}%
% Defines
\def\@nwlangdepnvd{nunca definido}%
% never defined
}
\def\nwopt@frenchb{%
\def\@nwlangdepdef{Suite de la d\'efinition}%
% This definition is continued
\def\@nwlangdepcud{Ce code est employ\'e}%
% This code is used
\def\@nwlangdeprtc{Morceau racine (pas employ\'e dans ce document)}%
% Root chunk (not used in this document)
\def\@nwlangdepcwf{Ce code est \'ecrit dans le fichier}%
% This code is written to file
\def\@nwlangdepchk{le morceau}%
% chunk
\def\@nwlangdepchks{les morceaux}%
% chunks
\def\@nwlangdepin{dans}%
% in
\def\@nwlangdepand{et}%
% and
\def\@nwlangdepuss{Utilise}%
% Uses
\def\@nwlangdepusd{utilis\'{e}}%
% used
\def\@nwlangdepnvu{jamais employ\'{e}}%
% never used
\def\@nwlangdepdfs{D\'{e}finit}%
% Defines
% Cannot use the accent here: \def\@nwlangdepnvd{jamais d\'{e}fini}%
\def\@nwlangdepnvd{jamais defini}%
% never defined
}
\let\nwopt@french\nwopt@frenchb
\def\nwopt@german{%
\def\@nwlangdepdef{Diese Definition wird fortgesetzt}%
% This definition is continued
\def\@nwlangdepcud{Dieser Code wird benutzt}%
% This code is used
\def\@nwlangdeprtc{Hauptteil (nicht in diesem Dokument benutzt)}%
% Root chunk (not used in this document)
%\def\@nwlangdepcwf{Dieser Code schreibt man zum File}%
\def\@nwlangdepcwf{Dieser Code geht in Datei}%
% This code is written to file
\def\@nwlangdepchk{dem Teil}%
% chunk
%\def\@nwlangdepchks{Teils}%
\def\@nwlangdepchks{den Teilen}%
% chunks
\def\@nwlangdepin{in}%
% in
\def\@nwlangdepand{und}%
% and
\def\@nwlangdepuss{Benutzt}%
% Uses
\def\@nwlangdepusd{benutzt}%
% used
\def\@nwlangdepnvu{nicht benutzt}%
% never used
\def\@nwlangdepdfs{Definiert}%
% Defines
\def\@nwlangdepnvd{nicht definiert}%
% never defined
}
\def\nwopt@german{%
\def\@nwlangdepdef{Diese Definition wird fortgesetzt}%
% This definition is continued
\def\@nwlangdepcud{Dieser Code wird benutzt}%
% This code is used
\def\@nwlangdeprtc{Hauptteil (nicht in diesem Dokument benutzt)}%
% Root chunk (not used in this document)
\def\@nwlangdepcwf{Dieser Code schreibt man zum File}%
% This code is written to file
\def\@nwlangdepchk{Teil}%
% chunk
\def\@nwlangdepchks{Teils}%
% chunks
\def\@nwlangdepin{im}%
% in
\def\@nwlangdepand{und}%
% and
\def\@nwlangdepuss{Benutzt}%
% Uses
\def\@nwlangdepusd{benutzt}%
% used
\def\@nwlangdepnvu{nicht benutzt}%
% never used
\def\@nwlangdepdfs{Definiert}%
% Defines
\def\@nwlangdepnvd{nicht definiert}%
% never defined
}
\let\nwopt@ngerman\nwopt@german
\ifx\languagename\undefined % default is English
\noweboptions{english}
\else
\@ifundefined{nwopt@\languagename}
{\noweboptions{english}}
{\expandafter\noweboptions\expandafter{\languagename}}
\fi
\let\obeyedspace\@xobeysp

224
peat Normal file
View file

@ -0,0 +1,224 @@
#!/usr/bin/env python
# -*- coding: utf8 -*-
##############################
# ____ ___ ____ ______ #
# | \ / _] / T| T #
# | o )/ [_ Y o || | #
# | _/Y _]| |l_j l_j #
# | | | [_ | _ | | | #
# | | | T| | | | | #
# l__j l_____jl__j__j l__j #
# #
##### #####
# Repeat commands! #
##################
import errno, os, subprocess, sys, time
from optparse import OptionParser
interval = 1.0
command = 'true'
clear = True
get_paths = lambda: set()
verbose = True
dynamic = None
last_run = None
USAGE = r"""usage: %prog [options] COMMAND
COMMAND should be given as a single argument using a shell string.
A list of paths to watch should be piped in on standard input.
For example:
find . | peat './test.sh'
find . -name '*.py' | peat 'rm *.pyc'
find . -name '*.py' -print0 | peat -0 'rm *.pyc'
If --dynamic is used, the given command will be run each time to generate the
list of files to check:
peat --dynamic 'find .' './test.sh'
peat --dynamic 'find . -name '\''*.py'\''' 'rm *.pyc'
"""
def log(s):
if verbose:
print(s)
def die(s):
sys.stderr.write('ERROR: ' + s + '\n')
sys.exit(1)
def check(paths):
for p in paths:
try:
if os.stat(p).st_mtime >= last_run:
return True
except OSError as e:
# If the file has been deleted since we started watching, don't
# worry about it.
if e.errno == errno.ENOENT:
pass
else:
raise
return False
def run():
global last_run
last_run = time.time()
log("running: " + command)
subprocess.call(command, shell=True)
def build_option_parser():
p = OptionParser(USAGE)
# Main options
p.add_option('-i', '--interval', default=None,
help='interval between checks in milliseconds',
metavar='N')
p.add_option('-I', '--smart-interval', dest='interval',
action='store_const', const=None,
help='determine the interval based on number of files watched (default)')
p.add_option('-d', '--dynamic', default=None,
help='run COMMAND before each run to generate the list of files to check',
metavar='COMMAND')
p.add_option('-D', '--no-dynamic', dest='dynamic',
action='store_const', const=None,
help='take a list of files to watch on standard in (default)')
p.add_option('-c', '--clear', default=True,
action='store_true', dest='clear',
help='clear screen before runs (default)')
p.add_option('-C', '--no-clear',
action='store_false', dest='clear',
help="don't clear screen before runs")
p.add_option('-v', '--verbose', default=True,
action='store_true', dest='verbose',
help='show extra logging output (default)')
p.add_option('-q', '--quiet',
action='store_false', dest='verbose',
help="don't show extra logging output")
p.add_option('-w', '--whitespace', default=None,
action='store_const', dest='sep', const=None,
help="assume paths are separated by whitespace (default)")
p.add_option('-n', '--newlines',
action='store_const', dest='sep', const='\n',
help="assume paths are separated by newlines")
p.add_option('-s', '--spaces',
action='store_const', dest='sep', const=' ',
help="assume paths are separated by spaces")
p.add_option('-0', '--zero',
action='store_const', dest='sep', const='\0',
help="assume paths are separated by null bytes")
return p
def _main():
if dynamic:
log("Running the following command to generate watch list:")
log(' ' + dynamic)
log('')
log("Watching the following paths:")
for p in get_paths():
log(' ' + p)
log('')
log('Checking for changes every %d milliseconds.' % int(interval * 1000))
log('')
run()
while True:
time.sleep(interval)
if check(get_paths()):
if clear:
subprocess.check_call('clear')
run()
def smart_interval(count):
"""Return the smart interval to use in milliseconds."""
if count >= 50:
return 1000
else:
sq = lambda n: n * n
return int(1000 * (1 - (sq(50.0 - count) / sq(50))))
def _parse_interval(options):
global get_paths
if options.interval:
i = int(options.interval)
elif options.dynamic:
i = 1000
else:
i = smart_interval(len(get_paths()))
return i / 1000.0
def _parse_paths(sep, data):
if not sep:
paths = data.split()
else:
paths = data.split(sep)
paths = [p.rstrip('\n') for p in paths if p]
paths = map(os.path.abspath, paths)
paths = set(paths)
return paths
def main():
global interval, command, clear, get_paths, verbose, dynamic
(options, args) = build_option_parser().parse_args()
if len(args) != 1:
die("exactly one command must be given")
command = args[0]
clear = options.clear
verbose = options.verbose
sep = options.sep
dynamic = options.dynamic
if dynamic:
def _get_paths():
data = subprocess.check_output(dynamic, shell=True)
return _parse_paths(sep, data)
get_paths = _get_paths
else:
data = sys.stdin.read()
paths = _parse_paths(sep, data)
if not paths:
die("no paths to watch were given on standard input")
for path in paths:
if not os.path.exists(path):
die('path to watch does not exist: ' + repr(path))
get_paths = lambda: paths
interval = _parse_interval(options)
_main()
if __name__ == '__main__':
import signal
def sigint_handler(signal, frame):
sys.stdout.write('\n')
sys.exit(130)
signal.signal(signal.SIGINT, sigint_handler)
main()