From 976abf1a09ee4a7d1a8d7880f55a434049332193 Mon Sep 17 00:00:00 2001 From: Charlie Date: Tue, 3 Dec 2024 17:39:52 -0300 Subject: [PATCH] Fiat lux! --- .gitignore | 6 + Makefile | 12 + manual.nw | 285 +++++++++++++++ noweb.sty | 989 +++++++++++++++++++++++++++++++++++++++++++++++++++++ peat | 224 ++++++++++++ 5 files changed, 1516 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 manual.nw create mode 100644 noweb.sty create mode 100644 peat diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b7dea41 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.aux +*.log +*.out +*.pdf +*.fdb_latexmk +*.fls diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0266d8f --- /dev/null +++ b/Makefile @@ -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 diff --git a/manual.nw b/manual.nw new file mode 100644 index 0000000..8ee9884 --- /dev/null +++ b/manual.nw @@ -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"}} + + {{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} diff --git a/noweb.sty b/noweb.sty new file mode 100644 index 0000000..1ea980b --- /dev/null +++ b/noweb.sty @@ -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{}} +\def\nowebindex{\message{}} +% 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 diff --git a/peat b/peat new file mode 100644 index 0000000..5078c80 --- /dev/null +++ b/peat @@ -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() +