.\" .\" Copyright (c) 2014 Ingo Schwarze .\" .\" Permission to use, copy, modify, and distribute this presentation for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE PRESENTATION IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL .\" WARRANTIES WITH REGARD TO THIS PRESENTATION INCLUDING ALL IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE .\" AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL .\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA .\" OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER .\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS PRESENTATION. .\" .\" These slides use the mm and gpresent groff macros. .\" For example, on OpenBSD, install these ports: .\" groff, gpresent, ghostscript. .\" .\" Build instructions: .\" groff -mm -mpresent NewTrendsInMandoc.roff > NewTrendsInMandoc.pps .\" presentps -l NewTrendsInMandoc.pps > NewTrendsInMandoc.ps .\" ps2pdf NewTrendsInMandoc.ps .\" .\" === preamble ======================================================= .\" --- global mm configuration settings ------------------------------- .nr Pi 3 .\" --- global gpresent configuration settings ------------------------- .DEFCOLOR Kea1 0 0.8 0.48 .DEFCOLOR Kea2 0 0.5 0.3 .TITLECOLOR Kea1 .SUBTITLEFORMAT C .SUBTITLECOLOR Kea2 .FOOTERSIZE 2 .\" --- gpresent header setup ------------------------------------------ .\" We don't want a header line for the title page, .\" so we have to start it before setting up headers. .TITLE New trends in mandoc: .nr gpe_page_tot 1 .nr gpe_page_sec 0 .af gpe_page_sec I .nr gpe_time_tsec 60 .nr gpe_time_min 1 .nr gpe_time_sec 0 .af gpe_time_sec 02 . .de GPE_SECTION .ds gpe_title_sec \\$1 .nr gpe_page_sec 0 .. .de HEADER .nr gpe_page_tot +1 .nr gpe_page_sec +1 .sp 0.5v .tl 'Ingo Schwarze: new trends in mandoc'\ page \\n[gpe_page_tot]: \\*[gpe_title_sec] \\n[gpe_page_sec]'\ BSDCan 2014, May 17, Ottawa' .sp -0.5v \l'\\n(.lu'\h'-\\n(.lu' .br .. .\" --- define some gpresent extension macros -------------------------- .de GPE_MULB .nr gpe_colwr \\n(.l-\\$1-1n .ie \\n[.$]>1 .ds gpe_vsp \\$2 .el .ds gpe_vsp 0.5v .sp -\\*[gpe_vsp] .MULB \\$1 1n \\n[gpe_colwr]u .sp \\*[gpe_vsp] .. .de GPE_EM .COLOR red \\$1 .COLOR P .. .de GPE_SM .S -4 \\$1 .S P .. .de GPE_SMEM .ce 3 .GPE_SM "\\$1 \m[red]\\$2\m[] \\$3" .. .\" --- title page ----------------------------------------------------- .TITLE Enhancing the modern toolbox .sp -2v .TITLE for the classic documentation formats .SUBTITLE "Ingo Schwarze " .sp -1.5v .SUBTITLE "BSDCan 2014, May 17, Ottawa" .PSPIC Images/BrentBarrettKea.eps 13c .ce .GPE_SM "Kea juvenile (Nestor notabilis) exploring new horizons \ (c) 2007 Brent Barrett @flickr (CC)" .GPE_SECTION INTRO .SK .\" --- gpresent footer setup ------------------------------------------ .\" We dont want a footer line for the title page, .\" so we have to set it up after completing the title page. .de GPE_NEXT .nr gpe_time_tsec +\\$1 .nr gpe_time_min \\n[gpe_time_tsec]/60 .nr gpe_time_sec \\n[gpe_time_tsec]%60 .ds gpe_next \\$2 .SK .. .de FOOTER .ps 18 .vs 20 .sp -2v \l'\\n(.lu'\h'-\\n(.lu' .br .tl '\s-6\\n[gpe_time_min]:\s-2\\n[gpe_time_sec]\s+8'\ '\\m[Kea2]\\*[gpe_next]\ \ \(->\\m[]' .ps .vs .. .\" ==================================================================== .GPE_SMEM "Enhancing the modern" toolbox\ "for the classic documentation formats:" .TITLE "Tools for handling manual pages" .BVL 1c .LI "Manual viewer: man(1)" .BL .LI Find manuals in the file system. .LI Call a formatter and a pager on them. .LI Not the topic of this talk... .LE .sp 0.5v .LI "Manual formatter: \fBmandoc(1)\fP" .BL .LI .GPE_EM "Read source code written in markup languages." .LI Write formatted text for the user. .LI Classical tool for this task: nroff(1). .LE .sp 0.5v .LI "Manual page search tool: \fBapropos(1)\fP = \f(CWman \-k\fP" .BL .LI Do database lookups. .LE .sp 0.5v .LI "Manual page database tool: \fBmakewhatis(8)\fP" .BL .LI Build databases. .LE .LE .\" -------------------------------------------------------------------- .GPE_NEXT 60 "How do the markup languages look like?" .GPE_SMEM "Enhancing the modern toolbox for the" classic\ "documentation formats:" .TITLE "Classic roff markup syntax" .ce Classic = literally half a century of history! .sp 1.5v .GPE_MULB 10c The concept of text and macro lines: .P .GPE_EM "RUNOFF (later became \(lqroff\(rq)" .P by Jerome H. Saltzer, MIT, 1964 .P in MAD for CTSS on the IBM 7094 .P .GPE_SM "inspired by Memo, Modify, and Ditto" .br .GPE_SM "by Lowry/Corbato/Steinberg 1963." .P Requests still in use today: .VERBON 2 16 \&.ad .ce .fi .in .ll .nf \&.br .sp .VERBOFF .MULN .PSPIC Images/ColumbiaIBM7094.eps .GPE_SM "IBM 7094 (c) 1965 Columbia Univ. Archives (Courtesy)" .MULE .sp 1.5v Macro lines contain a period (\(oq.\(cq), a macro name, and optional arguments. .P All other lines are text lines. .\" -------------------------------------------------------------------- .GPE_NEXT 100 "Why do we still use that syntax 50 years later?" .TITLE "Sample roff(7) source code" .VERBON 1 14 .TITLE "Advantages of the roff macro syntax" .S +2 .BL .LI Can easily be hand-edited with minimal typing overhead. .LI Looks unobtrusive, does not muddle the actual text. .LI Harmonizes very well with diff(1). .LI Allows high quality output in multiple output formats, .br in particular for terminal output and typesetting. .LI Works with simple, fast, portable, readily available tools. .LI Does not need any heavyweight or cumbersome toolchains, .br in particular, does not require XML. .LE .sp 2v .ce 2 \&... or to say it in one word: .sp 2v .S +4 .GPE_EM "KISS!" .S -6 .GPE_NEXT 50 "Application to software manuals?" .VERBOFF .\" -------------------------------------------------------------------- .GPE_NEXT 40 "OK, try again:\ \ Why do we still use that syntax 50 years later?" \& .br .TITLE "Advantages of the roff macro syntax" .S +2 .BL .LI Can easily be hand-edited with minimal typing overhead. .LI Looks unobtrusive, does not muddle the actual text. .LI Harmonizes very well with diff(1). .LI Allows high quality output in multiple output formats, .br in particular for terminal output and typesetting. .LI Works with simple, fast, portable, readily available tools. .LI Does not need any heavyweight or cumbersome toolchains, .br in particular, does not require XML. .LE .sp 2v .ce 2 \&... or say it in one word: .sp 2v .S +4 .GPE_EM "KISS!" .S -6 .\" -------------------------------------------------------------------- .GPE_NEXT 80 "Application to software manuals?" .GPE_SMEM "Enhancing the modern toolbox for the classic"\ documentation formats: .TITLE "Origin of the basic manual structure" .GPE_MULB 4i .GPE_EM "AT&T Version 1 UNIX manual" .P formatted with roff .P by Ken Thompson .br and Dennis M. Ritchie, .br Bell Labs, 1971 .P written in assembler .br for UNIX on the DEC PDP-11 .P .GPE_SM "inspired by the CTSS manuals" .P Section headers in use since v1: .br NAME, SYNOPSIS, DESCRIPTION, FILES, SEE ALSO, DIAGNOSTICS, BUGS .MULN .PSPIC Images/BellPDP11.eps (u;\n(.l-\n(.i)u .ce 2 .GPE_SM "Ritchie, Thompson, PDP-11 (c) 1971 Bell Labs" .GPE_SM "Reprinted with permission of Alcatel-Lucent USA Inc." .MULE .P Precursors to man(7) and mdoc(7) macros, used in v4\(env6 (1973-1975): .P \f(CW.th\fP (\(-> .TH/.Dt)\ \ \ \f(CW.sh\fP (\(-> .SH/.Sh)\ \ \ \ \f(CW.bd\fP (\(-> .B/.Sy)\ \ \ \f(CW.it\fP (\(-> .I/.Em) .P .GPE_EM "The man(7) language first appeared in Version 7 AT&T UNIX (1979)." .\" -------------------------------------------------------------------- .GPE_NEXT 60 "Was there any progress during the last 35 years?" .GPE_SMEM "Enhancing the" modern\ "toolbox for the \m[red]classic\m[] documentation formats: .TITLE "Origin of semantic markup in manuals" .GPE_MULB 18c 2v .BL .LI The mdoc(7) semantic markup macro language. .LI First in 4.3BSD-Reno by Cynthia Livingston, USENIX, 1990. .LI Formatted with Brian Kernighan's device independent troff, .LI written in K&R C, running on BSD UNIX on DEC VAX. .LE .SUBTITLE "Advantages of the mdoc(7) language" .MULN .PSPIC Images/BSDBeastie.eps .GPE_SM "4.2BSD Beastie" .MULE .BL .LI Considerable expressive power for semantic markup \(em .br while man(7) is a presentation level language only. .LI Works in practice as a standalone language \(em .br while man(7) regularly requires resorting to low-level roff features. .LI Consequently, more uniform appearance, easier to read and write than man(7). .LI Portability is no longer an issue: for legacy systems still not having mdoc(7), mandoc(1) can be used to convert to man(7) \(em see this talk. .LI .GPE_EM "Facilitates semantic searching \(em see this talk." .LE .\" -------------------------------------------------------------------- .GPE_NEXT 100 "How does mdoc(7) code look like?" .TITLE "Sample mdoc(7) source code" .VERBON 1 14 .Dd $Mdocdate: May 17 2014 $ .Dt MDOC 7 .Os .Sh NAME .Nm mdoc .Nd semantic markup language for formatting manual pages .Sh DESCRIPTION The .Nm mdoc language supports authoring of manual pages for the .Xr man 1 utility by allowing semantic annotations of words, phrases, page sections and complete manual pages. Such annotations are used by formatting tools to achieve a uniform presentation across all manuals written in .Nm , and to support hyperlinking if supported by the output medium. .Pp This reference document describes the structure of manual pages and the syntax and usage of the .Nm language. The reference implementation of a parsing and formatting tool is .Xr mandoc 1 ; the .Sx COMPATIBILITY section describes compatibility with other implementations. .VERBOFF .\" -------------------------------------------------------------------- .GPE_NEXT 30 "Classic documentation formats (summary)" .TITLE "Classic documentation formats (summary)" .BL .LI The roff(7) input syntax, .LI the mdoc(7) semantic markup, .LI and the man(1) presentation format .LE .sp 0.5v .ce .GPE_EM "have proven timeless by their simplicity and efficiency:" .sp -0.5v .BL .LI Nobody has come up with a better basic concept yet, .LI even though many have tried, .LI and regarding the formats, there is indeed little one could wish. .LE .PSPIC Images/AndrewRockWren.eps 10c .ce .GPE_SM "Rock Wren / Hurupounamu (Xenicus gilviventris)\ (c) 2006 57Andrew@flickr (CC)" .\" -------------------------------------------------------------------- .GPE_NEXT 30 "So we need modern tools for all this!" .GPE_SMEM Enhancing "the modern toolbox"\ "for the classic documentation formats:" .TITLE "Advantages of mandoc(1)" .BL .LI Functional \(em all in one binary: .BL .LI ASCII, UTF-8, HTML, XHTML, PostScript, PDF output .LI mdoc(7) to man(7) conversion .LI makewhatis(8)/apropos(1) .LE .LI Free \(em ISC/BSD-licensed, no GPL code. .LI Lightweight \(em ANSI C, POSIX, no C++ code. .LI Portable \(em includes compat_*.c files for missing functions on older systems. .LI Small \(em source tarball (uncompressed) is 8% of groff, executable binary 50%. .LI Fast \(em for mdoc(7), typically 5 times faster than groff, typically about a hundred times faster than an AsciiDoc/DocBook toolchain. .LE .sp 2v .ce .GPE_EM "Basic functionality already presented during BSDCan 2011." .\" -------------------------------------------------------------------- .GPE_NEXT 90 "So, let's finally use our strengths!\ \ New functionality..." .TITLE "Table of contents" .GPE_MULB 12c .AL .LI Introduction: .br Classic documentation formats .LI Searching for manual pages .BL .LI Markup-sensitive search .LI Complex search queries .LI Flexible output format .LI Database implementation .LI Search algorithm .LI Optimization and performance .LI Consistency checking .LE .LI Adoption of mandoc .LI Handling manual pages in ports .LI Manual pages for portable software: .br The mdoc(7) to man(7) converter .LI Conclusion and future directions .LI Acknowledgements .LE .MULN .PSPIC Images/NZDOCKakapoChicks.eps .ce 2 .GPE_SM "Kakapo chicks (Strigops habroptilus)" .GPE_SM "(c) 2009 NZ DOC @flickr (CC)" .MULE .\" ==================================================================== .GPE_SECTION APROPOS .GPE_NEXT 50 "How does searching work?" .TITLE "Searching for manual pages" .sp -1.5v .SUBTITLE "Traditional functionality is preserved" .\" XXX kristaps@ started makewhatis/apropos on April 2, 2011 .\" XXX rewrite for SQLite3 since June 8, 2012 .sp -0.5v .BVL 1c .\" XXX working since October 19, 2013 .LI "apropos \fIkeywords\fP ..." Search case-insensitively for substrings in names and descriptions. .LI "man \-k \fIarguments\fP" As before, an alias for: apropos \fIarguments\fP .br But now also supports new-style arguments, see below. .LI "apropos [\fB\-C \fIfile\fR] [\fB\-M \fIpath\fR] [\fB\-m \fIpath\fR] \ [\fB\-S \fIarch\fR] [\fB\-s \fIsection\fR] \fIkeywords\fR ..." Traditional options are all supported. .LE .GPE_MULB 12c .BVL 1c .LI "whatis \fIkeywords\fP ..." Search case-insensitively for complete .br words in page names only. .LI "makewhatis" Rebuild all configured databases. .\" XXX working since June 3, 2013 .LI "makewhatis \-d \fIdirectory files ...\fP Update entries for the given \fIfiles\fP .br in one database. .LE .P .ce .GPE_EM "backward compatible" .sp -2v .MULN .PSPIC Images/GlenFergusKiwi.eps .ce 2 .GPE_SM "Southern Kiwi / Tokoeka (Apteryx australis)" .GPE_SM "(c) 2008 Glen Fergus @wikimedia (CC)" .sp -2v .MULE .\" -------------------------------------------------------------------- .GPE_NEXT 60 "New functionality" .TITLE "Markup-sensitive search" .sp -1v .VERBON 0 12 $ apropos Ev=USER Mail, mail, mailx(1) \(en send and receive mail csh(1) \(en a shell (command interpreter) with Clike syntax login(1) \(en log into the computer logname(1) \(en display user's login name slogin, ssh(1) \(en OpenSSH SSH client (remote login program) su(1) \(en substitute user identity [...] .VERBOFF .sp 0.2v Macro keys that can be searched for (examples, ordered by frequency): .GPE_MULB 5i .S -4 .VL 2c 0c 1 .LI Nm manual page names .LI Nd manual page descriptions .LI sec manual section numbers .LI arch machine architectures .LI Xr cross references .LI Ar command argument names .LI Fa function argument types and names .LI Dv preprocessor constants .LI Pa file system paths .LI Cd kernel configuration directives .LI Va variable names .LI Ft function return types .LI Er error constants .LI Ev environment variables .LI In include file names .LI St references to standards documents .LI An author names .LI ... and so on ... .LE .S +4 .MULN .PSPIC Images/JJHarrisonSilvereye.eps (u;\n(.l-\n(.i)u .ce 2 .GPE_SM "Silvereye / Tauhou (Zosterops lateralis)" .GPE_SM "(c) 2008 J. J. Harrison @wikimedia (CC)" .MULE .\" -------------------------------------------------------------------- .GPE_NEXT 60 "Intermediate new search features" .TITLE "Markup-sensitive search features" Search keys can be OR'ed: .VERBON 6 12 $ apropos \m[red]Fa,Ft,Va,Vt=\m[]timespec EV_SET, kevent, kqueue(2) \(en kernel event notification mechanism clock_getres, clock_gettime, clock_settime(2) \(en get/set/calibrate date and time futimens, futimes, utimensat, utimes(2) \(en set file access and modification times nanosleep(2) \(en high resolution sleep parse_time(3) \(en parse and unparse time intervals poll, ppoll(2) \(en synchronous I/O multiplexing pselect, \m[red]select(2)\m[], FD_CLR, FD_ISSET, FD_SET, \ \m[red]FD_ZERO(3)\m[]\ \(en synchronous I/O multiplexing sem_timedwait, sem_trywait, sem_wait(3) \(en decrement (lock) a semaphore tstohz, tvtohz(9) \(en translate time period to timeout delay [...] .VERBOFF Searching across all keys is possible: .VERBON 6 12 $ apropos \m[red]any=\m[]ulimit ksh, rksh(1) \(en public domain Korn shell sh(1) \(en public domain Bourne shell getrlimit, setrlimit(2) \(en control maximum system resource consumption .VERBOFF Regular expressions are supported (\(oq~\(cq instead of \(oq=\(cq) since October 19, 2013: .VERBON 6 12 $ apropos "Nm~^[gs]et.*gid" endgrent, getgrent, getgrgid, getgrgid_r, getgrnam, getgrnam_r, setgrent, setgrfile, setgroupent(3) \(en group database operations getegid, getgid(2) \(en get group process identification getpgid, getpgrp(2) \(en get process group getresgid, getresuid, setresgid, setresuid(2) \(en get or set real, effective and saved user or group ID setegid, seteuid, setgid, setuid(2) \(en set user and group ID setpgid, setpgrp(2) \(en set process group setregid(2) \(en set real and effective group IDs [...] .VERBOFF .\" -------------------------------------------------------------------- .GPE_NEXT 50 "Advanced new search features" .TITLE "Complex search queries" By default, multiple search terms are joined with OR, .br but the .B \-s and .B \-S options attach to the rest of the search expression with AND: .VERBON 6 12 $ apropos \-s 1 tbl Nm=eqn deroff(1) \(en remove nroff/troff, eqn, pic and tbl constructs eqn(1) \(en format equations for troff or MathML eqn2graph(1) \(en convert an EQN equation into a cropped image neqn(1) \(en format equations for ascii output tbl(1) \(en format tables for troff .VERBOFF .sp 1v .GPE_MULB 15.5c Explicit logical AND and OR are supported: .VERBON 6 12 $ apropos Nd=gigabit \m[red]\-a\m[] Cd=sbus gem(4) \(en GEM 10/100/Gigabit Ethernet device ti(4) \(en Alteon Networks Tigon I and II Gigabit Ethernet device .VERBOFF Precedence can be changed with parantheses: .VERBON 6 12 $ apropos \-s 1 terminal \m[red]\-a\ \e(\m[] At~[1\-6] \m[red]\-o\m[] Bx~^[12] \m[red]\e)\m[] clear, tput(1) \(en terminal capability interface lock(1) \(en reserve a terminal reset, tset(1) \(en terminal initialization script(1) \(en make typescript of terminal session stty(1) \(en set the options for a terminal device interface tty(1) \(en return user's terminal name .VERBOFF .sp 1v Complex search queries are working since January 4, 2014. .MULN .PSPIC Images/AvicedaMorepork.eps .ce 3 .GPE_SM "Morepork / Ruru (c) 2005" .GPE_SM "(Ninox novaeseelandiae)" .GPE_SM "Aviceda@wikimedia (CC)" .MULE .\" -------------------------------------------------------------------- .GPE_NEXT 50 "New output features" .TITLE "Flexible output format" .sp -1v .BL .LI The names, section numbers, and architectures of the search results are always shown because these are needed to access the results with man(1). .LI By default, apropos(1) also shows the one-line descriptions. .LE .sp 0.5v With the .B \-O option, any other macro key can be shown instead: .VERBON 6 12 $ apropos \-O Cd wireless acx(4) \(en acx* at pci? # acx* at cardbus? an(4) \(en an* at isapnp? # an* at pcmcia? # an* at pci? ath(4) \(en ath* at pci? dev ? function ? # ath* at cardbus? dev ? function ? # gpio* at ath? athn(4) \(en athn* at cardbus? # athn* at uhub? port ? # athn* at pci? atu(4) \(en atu* at uhub? port ? atw(4) \(en atw* at pci? # atw* at cardbus? .VERBOFF The .B \-O option is available since December 31, 2013. .PSPIC Images/SidMosdellBellbird.eps 8c .ce .GPE_SM "Bellbird / Korimako (Anthornis melanura)\ (c) 2012 Sid Mosdell @flickr (CC)" .\" -------------------------------------------------------------------- .GPE_NEXT 50 "How is this implemented?" .TITLE "Database implementation" .GPE_MULB 13c .BL .LI The old \f(CWwhatis.db\fR was a plain text file. .LI Now we need a structured database. .LI But a client-server model would be overkill and merely a hindrance. .LI So SQLite was the logical choice. .LE .MULN .PSPIC Images/SQLite.eps .MULE .BL .sp 0.5v .LI Four tables. They contain, respectively, one record ... .VL 2.5c 0c 1 .LI \fBmpages\fP \&... per physical page, containing the description .LI \fBmlinks\fP \&... per file system entry, containing section, architecture, filename .LI \fBnames\fP \&... per page name; for all manual page names, not just file names .LI \fBkeys\fP \&... per key=value pair .LE .sp 0.5v .LI The mlinks table has full support for: .BL .LI hard links since December 27, 2013 .LI symbolic links since April 18, 2014 .LI redirections using the roff .so request since March 19, 2014 .br (used by X.org) .LE .LE .\" -------------------------------------------------------------------- .GPE_NEXT 70 "How does the search algorithm work?" .TITLE "Search algorithm" Two or three queries: .AL .LI \f(CWSELECT FROM mpages\fP .br to find the pages to be displayed .BL .LI Conveniently, searching for descriptions is fastest \(em .br in the first step, access one single table only, finding the \f(CWpageid\fR. .LI Searching for names is the second in speed \(em .br it requires only a simple JOIN to a small table. .LE .LI \f(CWSELECT FROM names\fP .br to find the page names to be displayed .br This is very fast because it is just a simple SELECT .br in a small table using the indexed \f(CWpageid\fR. .LI \f(CWSELECT FROM keys\fP .br to find the values to be displayed .BL .LI Only needed when .B \-O is given. .br Otherwise, we already have the description from search step 1. .LI Very fast, too, just another simple SELECT indexed by \f(CWpageid\fR. .LE .LE .\" -------------------------------------------------------------------- .GPE_NEXT 110 "What has been optimized?" .GPE_MULB 10.5c \& .br .TITLE "Optimization" As usual, optimization is not a well-defined task in the mathematical sense. .sp 1v We want high speed and small size: .sp 1v .BL .LI a small database .LI a short database build time .LI low apropos memory consumption .LI short search times .LE .sp 1v Of course, these optimization goals conflict. .sp 2v The gprof(1) profiler was used a lot. .MULN .PSPIC Images/Py1jtpFalcon.eps .ce 2 .GPE_SM "Falcon / Karearea (Falco novaeseelandiae)" .GPE_SM "(c) 2008 Py1jtp@wikimedia (CC)" .sp -2v .MULE .\" -------------------------------------------------------------------- .GPE_NEXT 40 "What about search speed?" .TITLE "Search speed optimization" .BL .LI \" April 9, 2014 Moving the \m[red]descriptions\m[] from the keys table directly into the mpages table gained roughly a \fBfactor 4\fP in speed for searches by description \(em at no cost, the database shrank, too, due to reduced pageid overhead. .LI \" April 9, 2014 The dedicated \m[red]names\m[] table gained roughly a \fBfactor 4\fP in speed for searches by name \(em at almost no cost. .LI \" April 16, 2014 Adding an index to the \m[red]mlinks\m[] table sped up the second step in the algorithm, name retrieval, by about a factor of 20, which resulted in an overall \fB30% economy\fP for simple searches, and more for searches returning many results. The cost was a 10% growth of the database. .LI Adding an index to the \m[red]keys\m[] table sped up the third step in the algorithm, .B \-O value retrieval, which is dominant in .B \-O searches, resulting roughly in a \fBfactor 4\fP speedup of such searches. The cost was another 10% grow of the database. .LI \" April 11, 2014 By providing an SQLITE_CONFIG_PAGECACHE with mmap(3) MAP_ANON, execution time decreased by 20\-25% for simple (Nd and/or Nm) queries, 10\-20% for non-NAME queries, and even apropos(1) resident memory size decreased by 20% for simple and by 60% for non-NAME queries. Cache size is a compromize to provide nearly optimal speed gain for all queries while limiting additional memory consumption to about 15%. .LE .\" -------------------------------------------------------------------- .GPE_NEXT 120 "What about database build time?" .TITLE "Database build time optimization" This is relevant because \f(CWmandoc.db\fP is built during regular base system and Xenocara snapshots builds on all architectures, and we don't want to slow down developers during development and testing. .BL .LI \" January 5, 2014 Quick mode: \m[red]Abort parsing after the NAME section:\m[] factor 2 in speed and factor 4 in size. In the following, all speedups refer to quick mode. .LI \" January 6, 2014 Do not sync to disk after each individual manual page, only sync to disk one single time when all data is ready: 87%. .LI \" January 6, 2014 In quick mode, do not clear user-defined macros clashing with mdoc(7) or man(7) standard macros when parsing .Dd or .TH: 25%. .LI \" January 6, 2014 In quick mode, do not validate and normalize the date format: 18%. .LI \" January 6, 2014 Do not copy predefined strings into the dynamic string table: 10%. .LI \" January 7, 2014 Cache uname(3) result: 3%. .LI \" January 18, 2014 Do not index the keys in the keys table: 12% (and 42% size reduction). .LI \" January 18, 2014 No primary keys in the mlinks and keys table: 15% (and 3% size). .LI \" March 19, 2014 Properly handling .so redirections reduced Xenocara database build time by 40% and database size by nearly 50%. .LE .\" -------------------------------------------------------------------- .GPE_NEXT 90 "What about database size?" .TITLE "Database size optimizations" All size reductions refer to quick mode. .BL .LI \" January 5, 2014 Do not store the descriptions twice, once for searching and once for display, at the expense of somewhat more complicated, but not slower search code: 9%. .LI \" January 5, 2014 Remove the redundant "file" column from the mlinks table: 9%. .LI \" January 18, 2014 Sort macro keys by frequency: 11%. .LI \" January 19, 2014 Always store the arch in lower-case only: 1.5%. .LE .PSPIC -C Images/DigitaltrailsRifleman.eps 10c .ce .GPE_SM "Rifleman / Titipounamo (Acanthisitta chloris),\ NZ's smallest bird (c) 2008 digitaltrails@flickr (CC)" .\" -------------------------------------------------------------------- .GPE_NEXT 60 "Performance summary" .TITLE "Search and database performance summary" .BL .LI With the old, plain text apropos(1), a simple search took about 10 milliseconds on my notebook. .LI With the new, SQLite apropos(1), it is unavoidably slower due to the SQL overhead and because the names are now separated from the descriptions. It now takes about 40 milliseconds. .LI However, the difference is of no practical relevance even on moderately old hardware (like this notebook). .LE .sp 1v .GPE_MULB 10c 0v .BL .LI Base system database size grows from 250 kB to 900 kB (quick mode) or about 3800 kB (fully featured more). That is not a practical problem for any of our architectures. .LI During system builds, database build times are \m[red]reduced by roughly a factor 3\m[] with respect to the old Perl makewhatis(8). .LE .MULN .PSPIC Images/AvenueSpottedShag.eps .ce 2 .GPE_SM "Spotted Shag / Parekareka (Phalacrocorax punctatus)" .GPE_SM "(c) 2010 Avenue@wikimedia (CC)" .MULE .\" -------------------------------------------------------------------- .GPE_NEXT 80 "Are there any useful by-products?" .GPE_MULB 12c 0v .TITLE "Consistency checking" .BL .LI Mismatch of the section number .br given in the manual page with .br the directory the page is stored in. .LI Mismatch of the architecture name .br given in the manual page with .br the directory the page is stored in. .LI \" April 4, 2014 File name does not appear .br as a name in the NAME section. .sp 1v .LI Besides, direct inspection of the database .br has been used to catch markup errors. .LI More can be done later, .br all this is \m[red]just a start\m[]. .LE .MULN .PSPIC Images/AugustusHamiltonMoa.eps .ce 2 .GPE_SM "Moa hunt in the Dunedin Public Gardens" .GPE_SM "(c) 1906 Augustus Hamilton (PD)" .MULE Already checked by the old makewhatis(8): .BL .LI Missing NAME section, missing name(s) and/or missing description. .LI \" April 4, 2014 A name in the name section does not appear as an MLINK in the file system. .LE .\" ==================================================================== .GPE_SECTION ADOPTION .GPE_NEXT 90 "Adoption of mandoc(1)" .TITLE "Status in OpenBSD" .GPE_MULB 17c 2v .BL 3n 1 .LI Kristaps@ developed mandoc(1) since November 22, 2008. .LI Source code in the base repo since April 6, 2009. .LI Schwarze@ maintaining it since June 14, 2009. .LI Actively maintained regression suite since October 27, 2009. .LE .MULN .PSPIC Images/OpenBSD.eps .MULE .BL 3n 1 .LI mandoc(1) installed with OpenBSD-current since April 2, 2010. .LI Base system manuals built with mandoc(1) since April 3, 2010. .LI USE_GROFF framework for ports by espie@ since April 5, 2010. .LI Releases fully rely on mandoc(1) since OpenBSD 4.8, November 1, 2010. .LI Groff disconnected from base build since October 18, 2010: .br .\" topic (quoted) .GPE_EM "mandoc(1) is the only documentation formatter in base for three years." .LI Groff removed from the source tree since March 12, 2011. .LI Groff 1.21/1.22 available from the ports tree since March 19, 2011. .LI No stable releases contain groff since OpenBSD 4.9, May 1, 2011. .sp .LI SQLite-based code in the source tree since December 30, 2013. .LI .GPE_EM "makewhatis(8)/apropos(1) using mandoc" since April 18, 2014. .LI All will be released with OpenBSD 5.6 on November 1, 2014. .LE .\" -------------------------------------------------------------------- .GPE_NEXT 80 "NetBSD" .TITLE "Status in NetBSD" .GPE_MULB 15c .BL .LI A pkgsrc mdocml port by J\(:org Sonnenberger .br exists since March 1, 2009 \(-> .br continued support for \fImany\fP platforms. .LI The first code patch was sent upstream .br by J\(:org Sonnenberger on June 11, 2009. .LI Source code in the base repo and installed by default .br in NetBSD-current since October 21, 2009. .LE .MULN .PSPIC Images/NetBSD.eps .MULE .SUBTITLE "Big changes in NetBSD on February 7, 2012" .BL .LI .\" src/share/mk/bsd.own.mk#rev1.695 Install source manuals, no longer install preformatted manuals. .LI Use mandoc(1) as the default run-time manual formatter instead of groff. .LI Use makemandb(8) by Abhinav Upadhyay instead of makewhatis(8) .br together with versions of apropos(1) and whatis(1) based on it, .br featuring full text search, but not semantic search. .LE .P .GPE_EM "All this was first released with NetBSD 6.0 on October 17, 2012." .P Semantic searching is not yet supported, not even as an option. .\" -------------------------------------------------------------------- .GPE_NEXT 90 "FreeBSD and DragonFly" .TITLE "Status in FreeBSD" .GPE_MULB 17.5c 3v .BL .LI An mdocml port by Ulrich Sp\(:orlein exists since March 9, 2009. .LI First code patch sent in by Ulrich Sp\(:orlein on July 18, 2009. .LE .MULN .PSPIC Images/FreeBSD.eps .MULE .BL .LI Source code in the base repo and installed by default since October 19, 2012. .LI .GPE_EM "First released with FreeBSD 10.0 on January 20, 2014." .LE .TITLE "Status in DragonFly BSD" .GPE_MULB 17.5c 2v .BL .LI Source code in the base repo and installed by default .br since October 27, 2009 (Sascha Wildner) .LI .GPE_EM "First released with DragonFly BSD 3.6.0 on March 28, 2010." .LE .MULN .PSPIC Images/DragonFly.eps .MULE .sp -1v .BL .LI First code patch sent in by Franco Fichtner on November 25, 2013. .LE .SUBTITLE "In both:" .BL .LI mandoc(1) is installed, but not used. .LI Semantic searching is not yet supported, not even as an option. .LE .\" -------------------------------------------------------------------- .GPE_NEXT 120 "Non-BSD systems" .SUBTITLE "Status in non-BSD systems" .sp -1.5v .BVL 1c .LI "Minix 3" .BL .LI Source code in the base repo since June 26, 2010 (Ben Gras). .LI Somewhat apathetic, still using a version that is more than three years old. .LE .LE .GPE_MULB 12c .BVL 1c .LI "Alpine Linux" .BL .LI A testing aport exists since .br July 6, 2010 (Natanael Copa). .LI The aport moved from testing to main .br on June 12, 2011 (Natanael Copa). .LI Continuously maintained. .LE .LI "Arch Linux" .BL .LI An mdocml package exists since .br October 3, 2010 (Markus M. May). .LI Updated to 1.12.3 on April 17, 2014 .br (new maintainer Jesse Adams). .LE .LE .MULN .sp 1v .PSPIC Images/FlagstaffBluePenguin.eps (u;\n(.l-\n(.i)u .ce 4 .GPE_SM "Little Blue Penguin / Korora" .GPE_SM "(Eudyptula minor)" .GPE_SM "(c) 2009 Fir0002/Flagstaffotos" .GPE_SM "@wikimedia (CC)" .MULE .sp -0.5v .BVL 1c .LI "Debian GNU/Linux" .BL .LI An unofficial mdocml package exists since April 19, 2014 (Jesse Adams). .LE .LI "Solaris, MacOS X" .BL .LI Tested using pkgsrc. .LE .LE .\" -------------------------------------------------------------------- .GPE_NEXT 90 "Adoption (summary)" .TITLE "Adoption status (summary)" .BVL 3c .LI "OpenBSD" Only documentation formatter in base for three years, .br and now also enabled as the manual page search system. .LI "NetBSD" Default manual formatter for two years. .LI "FreeBSD, DragonFly" Part of the base system, and both consider switching to it. .LE .sp 0.5v .GPE_MULB 12c .BVL 3c .LI "Minix 3" Part of the base system. .LI "Linux, Solaris, MacOS" Tested. .LI "pkgsrc" Provides packages .br for additional systems. .LE .sp 2v .GPE_EM "A lot of traction in all BSDs and beyond." .MULN .PSPIC Images/PhillipCapperBlueDuck.eps (u;\n(.l-\n(.i)u .ce 3 .GPE_SM "Blue Duck / Whio in Sussex, England" .GPE_SM "(Hymenolaimus malacorhynchos)" .GPE_SM "(c) 2005 Philipp Capper @flickr (CC)" .MULE .\" ==================================================================== .GPE_SECTION PORTS .GPE_NEXT 60 "Rest of the talk: Topics of porting and portability" .TITLE "Handling manual pages in ports" .SUBTITLE "The problem" .BVL 1c .LI "The Law of Feature Creep" If a software offers some feature, sooner or later somebody will use it. .LI "Porting corollary" For every feature of the roff language (and for every groff extension), no matter how arcane and how obviously irrelevant for manual pages, sooner or later somebody will want to port a third-party software abusing that feature to format its manual pages. .LI "mandoc(1) is not a complete nroff implementation" and who knows whether it will ever be... .LI "Not a problem in the base system:" Given a finite set of manuals, implement in mandoc(1) what is needed, or patch away the worst abuse in the handful of manuals affected. .LI "\m[red]But in ports, \(lqmandoc or nothing\(rq is not a viable\ strategy:\m[]" That would inevitably leave you with some seriously misformatted manuals, and in some cases with no usable manuals at all. .LE .\" -------------------------------------------------------------------- .GPE_NEXT 100 "How can this be solved?" .TITLE "The OpenBSD solution for manual pages in ports" .sp -1v .BL .LI Make sure that no port tries to preformat manuals during the build target. .LI Let every port install manual page sources during the fake install target. .LI For the majority of ports, mandoc(1) can handle all manuals: .br That's it, you are done with respect to these. .LI For the remaining minority of ports: Set a special boolean make(1) variable in the port Makefile, in OpenBSD called USE_GROFF. .LI That variable implies a build dependency on the groff port. .LI .GPE_EM "When building the package, the ports framework runs groff on the\ fly and packages the preformatted pages instead of the source pages." .LI After installing the packages, this will work just fine at run time: The preformatted pages will be diplayed directly by man(1), and man(1) will format the source pages with mandoc(1), with no dedicated configuration. .LI .\" main topic (quoted) Example of OpenBSD: 7952 ports, 1217 still USE_GROFF (15%). .br Some of these probably don't really need it, but there is no hurry. .br Removing USE_GROFF needs a manual check \(em which was already done for about 3000 ports during the last three years. .LI This concept has been designed and implemented by Marc Espie, and it has proven very sturdy and very easy to use. .LE .\" -------------------------------------------------------------------- .GPE_NEXT 140 "makewhatis(8) in ports" .TITLE "makewhatis(8) in ports" .BL .LI Base and X manual databases are essentially static. .LI But packages get installed and deinstalled. .LI You could wait for the periodic weekly(8) makewhatis(1) rebuild. .LI Better idea: .br During pkg_add, run \f(CWmakewhatis -d /usr/local/man files ...\fP .br During pkg_delete, run \f(CWmakewhatis -u /usr/local/man files ...\fP .LI Done routinely on OpenBSD, works seamlessly with the new makewhatis. .LI .GPE_EM "So, right after pkg_add(1), you call apropos(1),\ and it finds the freshly installed manual pages." .LE .GPE_MULB 14.5c 1.5v .SUBTITLE "Features that help, in particular for ports" .BL .LI Handle preformatted manuals (since Nov. 27, 2011). .LI Natively support gzip(1)'ed manual pages .br (since March 26, 2014). .LI During makewhatis -d/-u, automatically rebuild .br missing or corrupt databases (since April 18, 2014). .LE .MULN .PSPIC Images/SidMosdellKakariki.eps .ce 3 .GPE_SM "Red-crested parakeet / Kakariki" .GPE_SM "(Cyanoramphus novaezelandiae)" .GPE_SM "(c) 2010 Sid Mosdell @flickr (CC)" .MULE .\" ==================================================================== .GPE_SECTION \-Tman .GPE_NEXT 160 "What about the reverse perspective?" .TITLE "Manual pages for portable software" .SUBTITLE "The problem" .BL .LI .\" topic Consider portable software packages like sudo(8), OpenSSH, OpenSMTPd, ... .LI Which markup language should be chosen for the manual pages? .LI Use mdoc(7) and some legacy systems lose that still don't have mdoc(7) after it has been freely available for more than 20 years (hello, Solaris). .LI Use man(7) and everybody loses \(em that would be a very bad idea indeed. .LE .SUBTITLE "mandoc(1) to the rescue!" .BL .LI .GPE_EM "Write the manual pages using mdoc(7)." .LI Use mandoc -Tman to convert them to man(7) format. .LI Include both the mdoc(7) and man(7) versions into distribution tarballs. .LI Let \f(CW./configure\fP decide: .LI On systems supporting mdoc(7), install the mdoc(7) versions. .LI Otherwise, install the man(7) versions. .LE .\" -------------------------------------------------------------------- .GPE_NEXT 110 "Let's look at an example" .TITLE "Case study: the sudo(8) manuals" .SUBTITLE "Build system for the distribution tarball" .GPE_MULB 17c 1.5v Simplified code from the Makefile: .sp 0.5v .VERBON 6 16 sudo.man: sudo.mdoc mandoc -Tman sudo.mdoc > sudo.man sudo.cat: sudo.mdoc mandoc sudo.mdoc > sudo.cat .VERBOFF .MULN .PSPIC Images/sudo.eps .MULE .SUBTITLE "Installation system" .BL .LI If \f(CW./configure\fP finds mandoc(1), install the *.mdoc pages .LI If \f(CW./configure\fP does not find nroff(1), install the *.cat pages .LI If \f(CW./configure\fP successfully tests \f(CWnroff -mdoc\fP, install the *.mdoc pages .LI Otherwise, install the *.man pages. .LI To override this autodetection logic, provide \f(CW--with-mdoc\fP or \f(CW--with-man\fP options to \f(CW./configure\fP. .LE .\" -------------------------------------------------------------------- .GPE_NEXT 180 "How is this implemented?" .TITLE "Implementation of the mdoc to man converter" .BL .LI First run the mdoc(7) parser, constructing exactly the same abstract syntax tree in memory as when running -Tascii, -Thtml, or -Tps. .LI Then run the mdoc(7)-to-man(7) output module, structured similarly as the mdoc(7)-to-ASCII output module, but sharing no code. .LI One file, 1600 lines of very straightforward C source code. .LI One macro lookup table containing pre- and post-node action functions and pre- and post-node output strings for each mdoc(7) macro type. .LI The module \m[red]iterates the syntax tree and calls the appropriate action functions\m[] for each mdoc(7) node. .LE .GPE_MULB 15c .BL .LI An alternative, slightly more flexible approach would have been to first translate the mdoc(7) syntax tree to a man(7) syntax tree, then provide a non-translating man(7) output module. .LI That would have allowed man(7)-to-man(7) code normalization as a by-product. .LI However, the direct approach was simpler and has so far proven sufficient for all practical needs. .LE .MULN .PSPIC Images/MarkJoblingTomtit.eps .ce 4 .GPE_SM "Tomtit / Miromiro" .GPE_SM "(Petroica macrocephala)" .GPE_SM "(c) 2007 Mark Jobling" .GPE_SM "@wikimedia (PD)" .MULE .\" -------------------------------------------------------------------- .GPE_NEXT 140 "Implementation (summary)" .TITLE "Implementation of the mdoc to man converter (2)" .BL .LI Typical example of a tool that was technically quite easy to build on top of existing infrastructure, that is the mandoc(3) parser library, but quite useful and powerful in practice. .LI At first, I underestimated the importance of this tool, development only proceeded haltingly, nearly exclusively at hackathons: .LI I started development on September 17, 2011 (s2k11, Ljubljana). .LI The bulk of the work was done around July 10, 2012 (g2k12, Budapest). .LI It is ready for production since November 19, 2012 (c2k12, Coimbra). .LE .GPE_SECTION CONCLUSION .PSPIC Images/SidMosdellTui.eps 8c .ce .GPE_SM "Tui (Prosthemadera novaeseelandiae)\ (c) 2011 Sid Mosdell @flickr (CC)" .\" ==================================================================== .GPE_NEXT 50 "Was anything else improved in mandoc(1)?" .TITLE "Continuous evolution of mandoc(1)" .sp -0.5v .BL .LI Output modes -Tuft8 and -Tlocale since May 20, 2011. .LI Indirect references in roff(7) expansion since April 7, 2014. .LI Expansion of roff(7) number registers since March 21, 2013 (Christos Zoulas). .LI Almost complete support for roff(7) numerical expressions since April 7, 2014. .LI Numeric comparison in roff(7) conditionals since April 3, 2013 (Chr. Zoulas). .LI String comparison in roff(7) conditionals since March 8, 2014. .LE .GPE_MULB 14c .BL .LI Newly supported roff(7) requests: .DS .ta 6c \&.as\~(append to string) .cc\~(control character) \&.it\~(input line trap) .ll\~(line length) \&.rr\~(remove register) .tr\~(character translation) .DE .LI newly supported man(7)-ext macros: .DS \&.EX/.EE (example display) \&.OP (optional element) \&.PD (paragraph distance) \&.UR/.UE (uniform resource identifier) .DE .LI Lots of bugfixes and formatting corrections. .LE .MULN .PSPIC Images/BrendaAndersonFantail.eps .ce 2 .GPE_SM "\h'-0.8c'Fantail / Piwakawaka (Rhipidura fuliginosa)" .GPE_SM "\h'-0.4c'(c) 2007 Brenda Anderson @flickr (CC)" .MULE .P .ce .GPE_EM "Matured considerably in addition to growing new features." .\" -------------------------------------------------------------------- .GPE_NEXT 90 "Conclusion: Did we reach our goals?" .TITLE "Did we reach our goals last time?" During BSDCan 2011, I presented the following "possible future directions": .BL .LI Install manual sources, not preformatted manuals. .GPE_EM "DONE June 23, 2011" .LI Implement -mdoc -Tman. .GPE_EM "DONE November 19, 2012" .LI Rewrite apropos(1) and makewhatis(8) to use mandoc. .GPE_EM "DONE April 14, 2014" .LI Write pod2mdoc(1) in Perl. .GPE_EM "WIP kristaps@ in C" .LI Implement -man -Tmdoc. .GPE_EM "WIP kristaps@ via docbook2mdoc" .LI Use the mandoc toolbox to replace man.cgi on the websites. .GPE_EM "OPEN" .LE .PSPIC Images/DaveYoungShelduck.eps 15c .ce .GPE_SM "Paradise Shelduck / Putangitangi (Tadorna variegata)\ (c) 2008 Dave Young @flickr (CC)" .\" -------------------------------------------------------------------- .GPE_NEXT 100 "What shall we do in the future?" .\" main topic (quoted) .TITLE "Possible future directions" .BL .LI Use the new apropos(1) to replace man.cgi on the websites. .LI Integrate preconv(1) into mandoc(1) for better UTF-8 handling. .LI Support transitions from man(7) to mdoc(7) with doclifter and docbook2mdoc. .LI Support semantic enrichment of Perl and libReSSL manuals with pod2mdoc. .LI Unify parsers, allowing improvement of low-level roff(7) support. .LE .PSPIC Images/AndrewBarclayMollymawk.eps 13.5c .ce .GPE_SM "Buller's Mollymawk / Toroa-teoteo (Thalassarche bulleri)\ (c) 2008 Andrew Barclay @flickr (CC)" .\" ==================================================================== .GPE_SECTION THANKS .GPE_NEXT 240 "Who contributed?" .TITLE Thanks! .S -2 .sp -2v .BVL 1c .LI "Kristaps Dzonsons (bsd.lv)" for writing mandoc .LI "Franco Fichtner (DragonFly), J\(:org Sonnenberger,\ Christos Zoulas, Tsugutomo Enami (NetBSD)" for code contributions .LI "Marc Espie (OpenBSD)" for OpenBSD ports integration and lots of important feedback .LI "Jason McIntyre (OpenBSD)" for lots of feedback and countless useful discussions .LI "Thomas Klausner (NetBSD)" for NetBSD and pkgsrc porting work and lots of feedback .LI "Ulrich Sp\(:orlein (FreeBSD)" for FreeBSD porting and many bug reports .LI "Werner Lemberg (GNU troff)" for tireless help with groff-mandoc synchronization .LI "Anthony J. Bentley (OpenBSD)" for porting related software to OpenBSD and for many bug reports .LI "Natanael Copa (Alpine), Jesse Adams (Arch),\ Matthias Scheler (Solaris), Ben Gras (Minix 3)" for porting mandoc(1) and providing feedback .LI "Todd C. Miller (OpenBSD & sudo)" for feedback and multiple patches for the mdoc-to-man converter .LE .S +2 .SK .GPE_MULB 15.8c 0v .TITLE Thanks! .S -2 .sp -1v .BVL 1c .LI "Jeremy Evans (OpenBSD)" for crucial help with SQLite database optimization .LI "Christian Weisgerber (OpenBSD)" for continuous work on mandoc issues in OpenBSD ports .LI "Stuart Henderson (OpenBSD)" for help with large numbers of porting issues .LI "Pascal Stumpf (OpenBSD)" for repeated help with difficult groff porting issues .LE .P For bug reports and useful suggestions and discussions: .S +2 .MULN .PSPIC Images/MarkJoblingRobin.eps .ce 2 .GPE_SM "\h'-1.4c'Robin / Toutouwai (Petroica australis)" .GPE_SM "\h'-1.8c'(c) 2007 Mark Jobling @wikimedia (PD)" .MULE .S -2 .sp -0.5 Antoine Jacoutot, Bob Beck, Brad Smith, Bret Lambert, Bryan Steele, David Coppa, .br David Gwynne, Gleydson Soares, Florian Obser, Igor Sobrado, Jasper Lievisse Adriaanse, J\('er\('emie Courr\(`eges-Anglas, Jonathan Gray, Juan Francisco Cantero Hurtado, Kenji Aoyama, Kenneth R. Westerback, Landry Breuil, Martin Pieuchot, Matthew Dempsky, Matthias Kilian, Miod Vallat, Nicholas Marriott, Nick Holland, Nigel Taylor, Okan Demirmen, Paul de Weerd, Philip Guenther, Stefan Sperling, Ted Unangst, Theo de Raadt, Todd T. Fries, Vadim Zhukov (OpenBSD) .P Nicolas Joly, Abhinav Upadhyay, Havard Eidnes, Jonathan Perkin (NetBSD), .br Antonio Huete Jimenez, Sascha Wildner (DragonFly), David Hill (Bitrig), .br Yuri Pankov (IllumOS), Michael Dexter (bsd.lv) .P Chris Hettrick, David Levine, Dmitrij D. Czarkoff, Fabian Raetz, Jan Stary, .br Maxim Belooussov, Mike Small, Mikolaj Kucharski, Steffen Nurpmeso, Tim van der Molen .S +2 .GPE_NEXT 190 "Where did the images come from?" .TITLE "Bye, and thanks for all the birds!" .S -6 .DS https://www.flickr.com/photos/whereisbrent/461055143\ Brent Barrett: Kea juvenile (by-nc-nd) http://www.columbia.edu/cu/computinghistory/1965.html\ Columbia University: IBM 7094 (with permission) Courtesy of University Archives, Columbia University in the City of New York http://cm.bell-labs.com/who/dmr/picture.html\ Bell Labs: PDP-11 (with permission) Reprinted with permission of Alcatel-Lucent USA Inc. http://www.mckusick.com/beastie/shirts/bsdunix.html\ USENIX: 4.2BSD Beastie https://www.flickr.com/photos/29954808@N00/1300190844\ 57Andrew: Rock Wren (by) https://www.flickr.com/photos/docnz/8528275645\ NZ DOC: Kakapo (by-nc-sa) http://commons.wikimedia.org/wiki/File:Tokoeka.jpg\ Glen Fergus: Southern Kiwi (by-sa) http://commons.wikimedia.org/wiki/File:Silvereye.jpg\ J. J. Harrison: Silvereye (by-sa) http://commons.wikimedia.org/wiki/File:Nz_boobook.JPG\ Aviceda: Morepork (by-sa) https://www.flickr.com/photos/sidm/6681523917\ Sid Mosdell: Bellbird (by) http://commons.wikimedia.org/wiki/File:Nz_falcon.JPG\ Py1jtp: NZ Falcon (by-sa) https://www.flickr.com/photos/digitaltrails/2214314908\ Digitaltrails: Rifleman (by-nc-sa) http://commons.wikimedia.org/wiki/File:Spotted_Shag_%28Phalacrocorax_punctatus%29_in_flight_2.jpg Avenue: Spotted Shag (by-sa) http://commons.wikimedia.org/wiki/File:Moa_mock_hunt.jpg\ Augustus Hamilton: Moa (c) expired http://commons.wikimedia.org/wiki/File:Little_Penguin_Feb09.jpg\ Fir0002/Flagstaffotos: Little Penguin (by-nc) https://www.flickr.com/photos/flissphil/53850663\ Philip Capper: Blue Duck (by) https://www.flickr.com/photos/sidm/5225410158\ Sid Mosdell: Red-crested parakeet (by) http://commons.wikimedia.org/wiki/File:Petroica_macrocephala_macrocephala1.jpg\ Mark Jobling: Tomtit (pd) https://www.flickr.com/photos/sidm/6557924841\ Sid Mosdell: Tui (by) https://www.flickr.com/photos/curiouskiwi/566823278\ Brenda Anderson: Fantail (by-nc-sa) https://www.flickr.com/photos/22018552@N08/2944307294\ Dave Young: Paradise Shelduck (by) https://www.flickr.com/photos/electropod/2817879475\ Andrew Barclay: Buller's Mollymawk (by-nc-nd) http://commons.wikimedia.org/wiki/File:070308_Stewart_Island_robin_on_Ulva.jpg\ Mark Jobling: NZ Robin (pd) .DE .ds gpe_next What would you like to ask?