.\" .\" Copyright (c) 2018 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 -st -mm -mpresent talk.roff > talk.pps .\" presentps -l talk.pps > talk.ps .\" ps2pdf talk.ps .\" .\" -------------------------------------------------------------------- .\" .\" --- 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 .\" We don't want a header line for the title page, .\" so we have to start it before setting up headers. .TITLE "Forget reusability, aim for perfection" .\" === gpresent header setup ========================================== .\" --- define gpresent extension registers ---------------------------- .nr gpe_page_tot 1 .nr gpe_page_sec 0 .af gpe_page_sec I .nr gpe_dur_min 0 .nr gpe_dur_sec 0 .af gpe_dur_sec 02 .nr gpe_time_tsec 13*60+32*60 .nr gpe_time_hour 13 .nr gpe_time_min 32 .af gpe_time_min 02 .nr gpe_time_sec 0 .af gpe_time_sec 02 . .\" --- macro to start a new section ----------------------------------- .de GPE_SECTION .ds gpe_title_sec \\$1 .nr gpe_page_sec 0 .. .\" --- macro to prepare a new page ------------------------------------ .de GPE_NEXT .ds gpe_next \\$1 .SK .. .\" --- gpresent page header callback ---------------------------------- .de HEADER .nr gpe_page_tot +1 .nr gpe_page_sec +1 .sp 0.5v .ds gpe_middle page \\n[gpe_page_tot]: \\*[gpe_title_sec] \\n[gpe_page_sec] .tl 'Ingo Schwarze: Forget reusability \(em New lessons from mandoc'\ \\h'2c'\\*[gpe_middle]'\ Ottawa, June 8, 2018' .sp -0.5v .\" horizontal line below the page header \l'\\n(.lu'\h'-\\n(.lu' .br .. .\" --- initialize the first section before completing the title page -- .GPE_SECTION INTRO .\" === define some gpresent extension macros ========================== .\" --- line length ---------------------------------------------------- .\" To return to full line length after temporarily reducing it. .nr gpe_ll \n(.l .\" --- emphasis ------------------------------------------------------- .de GPE_EM .COLOR red \\$1\c .COLOR P \&\\$2 .. .\" --- small text ----------------------------------------------------- .de GPE_SM .S -4 \\$1 .S P .. .\" --- quoted literals ------------------------------------------------ .de GPE_QL \(lq\f(CW\\$1\fP\(rq\\$2 .. .\" --- tweak -mpresent macros ----------------------------------------- .\" Reduce vertical spacing by the given argument. .\" Can only be called right after .SP with a larger argument. .de GPE_SPM .sp -\\$1 .nr line*ac\\n[.z] -\\$1 .nr line*lp\\n[.z] \\n[.d] .. .am TITLE .GPE_SPM 0.1i .. .am SUBTITLE .GPE_SPM 0.05i .. .\" --- title page ----------------------------------------------------- .\" The main title line has already been printed. .sp -1v .SUBTITLE "New lessons from mandoc" .SUBTITLE "BSDCan, Ottawa, June 8, 2018" .SUBTITLE "Ingo Schwarze " .sp -0.5v .MULB 12c 1n 8c .PSPIC Images/Paris17_Groff.eps .ce .GPE_SM "EuroBSDCon, Paris, Sep. 24, 2017" .MULN .PSPIC Images/Paris17_Rhino.eps .ce .GPE_SM "Paris, Louvre, vue du Musee d'Orsay" .MULE .sp 0.5v .ce Mandoc at previous conferences: .MULB 4c 1n 4c 1n 4c 1n 4c 1n 4c .PSPIC Images/TomkoFoal.eps 2c .MULN .PSPIC Images/BrentBarrettKea.eps 2c .MULN .PSPIC Images/BSDSofiaForWeb.eps 1.4c .MULN .PSPIC Images/CynthiaLivingstonBe2013.eps 1.7c .MULN .PSPIC Images/BSDStockholm.eps 1c .MULE .MULB 4c 1n 4c 1n 4c 1n 4c 1n 4c .ce .GPE_SM "BSDCan 2011" .MULN .ce .GPE_SM "BSDCan 2014" .MULN .ce .GPE_SM "EuroBSDCon 2014" .MULN .ce .GPE_SM "BSDCan 2015" .MULN .ce .GPE_SM "EuroBSDCon 2015" .MULE .\" === 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. .SK .\" --- macros to start a new page ------------------------------------- .\" arg: time for this page in seconds .de GPE_TIME .nr gpe_dur_min \\$1/60 .nr gpe_dur_sec \\$1%60 .nr gpe_time_tsec +\\$1 .nr gpe_time_hour \\n[gpe_time_tsec]/3600 .nr gpe_time_min \\n[gpe_time_tsec]%3600/60 .nr gpe_time_sec \\n[gpe_time_tsec]%60 .. .\" --- gpresent page footer callback ---------------------------------- .de FOOTER .ps 18 .vs 20 .sp -2v \l'\\n(.lu'\h'-\\n(.lu' .br .tl '\s-6\\n[gpe_dur_min]:\s-2\\n[gpe_dur_sec]\s+2 \(->\ \\n[gpe_time_hour]:\\n[gpe_time_min]:\s-2\\n[gpe_time_sec]\s+8'\ '\\m[Kea2]\\*[gpe_next]\ \ \(->\\m[]' .ps .vs .. .\" The INTRO section was already started in header.roff. .TITLE "The context of this talk" .ce I occasionally present updates on documentation tools at BSD conferences. .\" This talk is not about all aspects of documentation. .SUBTITLE "General reminders about documentation" .BL .LI .GPE_EM "Without documentation, code is unusable," .br .GPE_EM "and bad documentation is about as bad as bad code." .LI Documentation must be correct, complete, concise, all in one place, .br marked up for display and search, easy to read, and easy to write. .LI All BSD projects use the .GPE_EM "mdoc(7)" markup language because it is by far the best language available: concise, simple, providing the right amount of semantic markup. Thanks to Cynthia Livingston. .GPE_SM "(USENIX, UC Berkeley CSRG 1990 to 1994)" .P .GPE_SM "texinfo(1) and DocBook are excessively complicated,\ ill-designed, and unmaintained, DocBook also buggy as hell and\ sluggish; man(7), perlpod(1), and markdown provide no semantic markup." .LI All BSD projects use the .GPE_EM "mandoc(1)" toolbox because it is functional, .br free (no GPL), lightweight (no C++ or XML), portable, small, and fast. .br Five input formats, five output formats, two converters, .br very powerful searching, all integrated. .LI See my presentation at BSDCan 2015 regarding how mandoc(1) became .br the standard toolbox. .GPE_SM "(and those at BSDCan 2011 and 2014, too) .LE .GPE_TIME 80 .GPE_NEXT "Table of contents" .TITLE "The plan for this talk" .ce .GPE_EM "Five different lessons from what was done with mandoc in 2016\(en2018." .sp But this talk is not about mandoc only: .BVL 1c .LI "1. Forget reusability:" Why we deleted .GPE_EM SQLite from the OpenBSD base system. .mk .LI "2. Document the inscrutable:" .GPE_EM LibreSSL and API design. .LI "3. Use the strength of mdoc(7):" Manual pages on the .GPE_EM web . .LI "4. Easily cope with language design from hell:" The .GPE_EM markdown output mode. .LI "5. Serve the real world:" Improvements for manual pages in .GPE_EM ports . .LI "6. Aim for perfection:" The .GPE_EM small things matter. .LI "7. Summary:" Completed and open tasks. Mandoc adoption. .LE .rt .sp .PSPIC -R Images/Paris17_SacreCoeurClocher.eps .rj .GPE_SM "Paris, Sacr\('e-C\(oeur (2017)" .GPE_TIME 60 .GPE_SECTION DATABASE .GPE_NEXT "What's wrong with SQLite?" .TITLE "The problem with SQLite" .BL .LI Frequent releases: on average 5 feature and 6 bugfix releases per year. .GPE_SM "(2011\(en2017)" .ig 2017: 3.16-3.21 = 6 + 6 bugfix releases 2016: 3.10-3.15 = 6 + 9 bugfix releases 2015: 3.8.8-3.9 = 5 + 8 bugfix releases 2014: 3.8.3-3.8.7 = 5 + 8 bugfix releases 2013: 3.7.16-3.8.2 = 5 + 5 bugfix releases 2012: 3.7.10-3.7.15 = 6 + 3 bugfix releases 2011: 3.7.5-3.7.9 = 5 + 4 bugfix releases 2010: 3.6.22-3.7.4 = 7 + 2 bugfix releases 2009: 3.6.8-3.6.21 = 14 + 3 bugfix releases 2008: 3.5.5-3.6.7 = 13 + 2 bugfix releases 2007: 3.3.9-3.5.4 = 17 .. .LI Extensive changes in each release: about +15k \-5k LOC to audit per year .br in 2015\(en2017, counting the directory src/ only. That's half the volume .br of the complete mandoc codebase \(em but every year anew! .ig 3.22 +3810 -1286 3.21 +2754 -2615 3.20 +3426 -1341 3.19 +1272 -640 3.18 +2348 -665 3.17 +996 -547 3.16 +3166 -1683 3.15 +2996 -1466 3.14 +2571 -1215 3.13 +3100 -1263 3.12 +2289 -1551 3.11 +2170 -1445 3.10 +4062 -1717 3.9 +2552 -1598 3.8.11 +3102 -4704 3.8.10 +1326 -727 3.8.9 +2282 -1336 3.8.7 +3779 -1814 .. .LI .GPE_EM "That volume of changes is impossible to audit." .LI Also, the coding style is so radically different from OpenBSD that .br people would be unwilling to audit the code even if they had the time. .mk .br .ll 11c .LI Forking would be an absurd waste: .br SQLite upstream provides .br excellent maintenance and quality. .LI So it is the .GPE_EM "ideal software for ports" : .br trustworthy and stable .br without us checking .br and continuously re-checking .br all the details. .LI But unfortunately, .br mandoc used it in base... .LE .ll \n[gpe_ll]u .rt .sp 0.5v .PSPIC -R Images/Nantes16_FosseDuChateau.eps .rj .GPE_SM "\fIThat's massive:\fP Nantes, Fosse du Chateau (during p2k16)" .GPE_TIME 70 .GPE_NEXT "What was the root of the problem?" .TITLE "The root cause of the problem" .ce .GPE_EM "Schematic, superficial approach to architecture." .SUBTITLE Antipattern: .BL .LI What kind of task is at hand? \(em Database. .GPE_SM "(not completely wrong)" .mk .LI Which is the simplest and highest quality standard toolkit .br for that kind of problem? \(em SQLite. .GPE_SM "(completely true)" .LI So reuse that as a dependency. .GPE_SM "(wrong, premature conclusion)" .LE .SUBTITLE "Three errors:" .AL .LI .GPE_EM Requirements were not evaluated in detail, but only summarily \(-> .br selection of excessively powerful, large, heavyweight tools. .LI .GPE_EM "Integration costs" were not evaluated \(-> the tool may save time and code lines for the functionality itself, but may require wasting effort on glue code. .LI .GPE_EM "Maintenance costs" were not evaluated \(em .br and it turned out that maintenance was impossible, see the previous slide \(-> .br that was the fatal error which forced us to redo the work. .LE .rt .sp 0.5v .PSPIC -R Images/SQLite.eps 5c .GPE_TIME 60 .GPE_NEXT "What do we actually need in mandoc?" .TITLE "The actual requirements" .BVL 1cm .LI "Frequent Reading" Keep that in mind for the design. .LI "Only specific query types" \&... whereas a strength of SQL is flexibility of queries and good performance .br on any kind of query, even those that were never anticipated. .LI "Limited database size when reading" \&... whereas a strength of a full-scale database is scaling to huge database sizes. .LI "Rare writing, only at system update and pkg_add times" \&... whereas a strength of a full-scale database is efficient writing. .LI "Limited database size when writing" \&... whereas a strength of a full-scale database is scaling write performance. .LI "Linear search is good enough" \&... whereas a strength of a full-scale database is optimized searching, .br for example using index and hashing techniques. .LE .P .S -4 The most common forms of queries are apropos(1) substring and regular expression searches. .br Even the simplest search optimizations like binary searching or hashing are hopeless with that. .br Speed optimization for man(1) lookups would be possible but useless, it is very fast anyway. .br .S P .GPE_TIME 90 .GPE_NEXT "How did we solve this?" .TITLE "The solution for mandoc: searching pages" Dedicated database format from scratch with minimal structural overhead. .P A very fast and simple way to repeatedly read .br the same parts of a file of moderate size from disk: .P Use the kernel's buffer cache by simply .GPE_EM "mmap(2)" ing the file into RAM. .P Keep the data typically searched together contiguous, as close together as possible, to minimize the number of pages actually faulted into RAM. .P For example, the list of one-line descriptions (used for apropos) looks like this: .sp .VERBON 18 14 ACME client\e0convert addresses into file names and line numbers.\e0 format floppy disks\e0apply a command to a set of arguments\e0... .VERBOFF .mk .ll 14c .sp .SUBTITLE "Trivial lookup algorithm" .BL .LI Do a linear search for the substring. .LI When the N-th title matches, ... .LI \&... access the data struct for the N-th page. .LE .ll \n[gpe_ll]u .rt .sp 0.5v .PSPIC -R Images/Nantes16_NotreDameAnneaux.eps .rj .GPE_SM "\fILookup:\fP Nantes, Notre Dame, vue par les Anneaux (2016)" .GPE_TIME 90 .GPE_NEXT "How do we access search results?" .TITLE "The solution for mandoc: access search results" For information retrieval, the file contains a list of records of pointers; .br in C code, each record can be accessed as a struct. .P For example, the record for the ACME client page simply contains the pointers: .BL .LI to the page name in the page name list ("acme-client") .LI to the section in the section list ("1") .LI to the architecture in the architecture list ("") .LI to the one line description ("ACME client") .LI to the filename ("man1/acme-client.1") .LE .sp So, a command like .GPE_QL "apropos acme" : .AL .LI Maps and linearily searches the name and description lists. .LI Looks up the N-th record in the table of manual pages. .LI Follows the pointers to the name and description (already cached)... .LI \&... and to the section (will be faulted into RAM at this point). .LI Assembles the line "acme-client(1) \(em ACME client" and prints it. .LE .GPE_TIME 60 .GPE_NEXT "How does the sequence of operations look like?" .TITLE "The solution for mandoc: program execution" The ktrace(1) is very short an clean: .AL .LI let ld.so(1) load libc, libz, libutil .LI pledge(2) .LI open(2) the file mandoc.db(5) .LI mmap(2) .LI search (not even visible in ktrace, purely userland) .LI access(2) to validate the resulting file name .LI retrieve the record (not even visible in ktrace, purely userland) .LI write(2) the result line .mk .LE .sp Similarly for semantic searches: .P One table for each macro key. .P The full format is documented .br in mandoc.db(5). .br .rt .PSPIC -R Images/Nantes16_AdminArbre.eps .rj .GPE_SM "Nantes, Maison de L'Administration Noevelle (2016)" .GPE_TIME 40 .GPE_NEXT "Summary about the solution" .TITLE "The solution for mandoc: summary" .BL .LI This may sound like "heavily optimized for performance". .LI But no, quite to the contrary, it is actually heavily optimized .br for simplicity and readability of code. .LI Performance is merely a by-product of choosing a well-adapted data format .br and the simplest possible algorithms. .LE .PSPIC Images/Nantes16_SteAnneCale3.eps .ce .GPE_SM "Nantes, Ste. Anne et la Grue Titan Jaune vue de la Cale 3 (2016)" .GPE_TIME 20 .GPE_NEXT "How does it perform?" .TITLE "Performance of the new mandoc.db(5)" .mk .BL .LI Half the database size. .br For example for OpenBSD 6.3 .br /usr/share/man/: 4.35 \(-> 2.05 MB .LI Double lookup speed. .br For example, for .br .GPE_QL "man \-w pledge" .br on my notebook: .br from disk: 2.7ms \(-> 1.2ms .br from buffer cache: 2.1ms \(-> 0.9ms .LI Small increase in the database rebuild time. .br For example for /usr/share/man/ on my notebook: 4.1s \(-> 5.1s .br We don't care that much about rebuild times... .br Doubling it would be unfortunate, but 25% is not an issue. .LI Substantially slower database update: .br For example, add one page to /usr/share/man/ on my notebook: 7.5ms \(-> 330ms .br That is 50 times longer (because SQLite efficiently inserts data, while the new makewhatis(8) just reads in the whole file, manipulates the data structures in memory, and writes out the whole file again) \(em but, honestly, how does less than half a second matter when doing system updates or installing new packages? .LE .rt .sp -0.5v .PSPIC -R Images/Nantes16_Fonderies.eps .rj 2 .GPE_SM "Nantes, Jardin des Fonderies, .br .GPE_SM "Rue Louis Joxe (2016)" .GPE_TIME 60 .GPE_NEXT "How did the source code change?" .TITLE "Source code" .sp -1v .TS allbox center; lnnnl. SQLite new code change database *.c LOC 205,000 1,570 \-99.2% database *.c size 7,200kB 44kB \-99.4% database *.h LOC 10,700 225 \-97.9% database *.h size 508kB 12kB \-97.6% makewhatis glue LOC 365 125 \-65% now 2350 LOC apropos glue LOC 510 475 \-7% now 850 LOC .TE .sp makewhatis(8): Practically no change to the bulk of the code (file system iteration, mdoc(7) node handling, man(7) and *.cat page handling). .P apropos(1), man(1): Search and lookup code is now substantially different, .br but .GPE_EM "not larger" , even though it still does macro specific searches and still supports logical operations like "and", "or", and parentheses. .mk .P .ll 12c Both: the new code is much .GPE_EM "easier to read" \(em .br constructing command strings .br of one programming language (SQL) .br in another programming language (C) .br is not the kind of code you want to audit. .br .ll \n[gpe_ll]u .rt .sp -0.5v .PSPIC -R Images/Nantes16_RondPoint.eps .rj .GPE_SM "\fIPlus beau:\fP Nantes, Rond-Point du Pont Willy Brandt (2016)" .GPE_TIME 60 .GPE_NEXT "What are the benefits of the new mandoc.db(5)?" .TITLE "Immediate benefits of the new mandoc.db(5)" .BL .LI Deleted SQLite from the OpenBSD base system. .GPE_SM "(sthen@ 2016 Sep 23)" .LI 200,000 lines of code less to maintain. .LI 15,000 lines of new code less to audit per year. .LI Half the database sizes. .LI Double lookup speed. .LI 300 lines less of very ugly glue code in mandoc itself. .GPE_SM "(2016 Aug 1)" .LE .mk .ll 12c .SUBTITLE Costs .BL .LI Much slower update time .br (but still below half a second). .LI Slightly slower rebuild time .br (5 instead of 4 seconds). .LI Had to write slightly below .br 2000 lines of new code \(em .br now two years old, .br needs almost no maintenance. .LE .ll \n[gpe_ll]u .rt .PSPIC -R Images/Nantes16_AdminPanneau.eps .rj .GPE_SM "Nantes, Maison de l'Administration Nouvelle (2016)" .GPE_TIME 60 .GPE_NEXT "What did we learn from the SQLite removal?" .TITLE "Generic lessons from the SQLite removal" .mk .BL .LI .GPE_EM "Do not blindly use standard tools." .LI Evaluate specific requirements before .br selecting tools, do not fall for buzzwords. .LI Evaluate integration costs before deciding. .LI Try to estimate maintenance cost .br before committing to a tool. .LI Seriously consider using the .br .GPE_EM "POSIX C library as your main toolkit:" .br It is surprisingly powerful. .P .S -4 In a long-term project that sees substantial use, the additional effort required for using pure C .br is sometimes justified by the resulting simplicity, self-containedness, and maintainability, .br even when performance is *not* the main concern. .br .S P .LI Quality is multi-dimensional, so even if a tool is excellent in many respects, .br it may not be good enough. .LI Quality does not imply adequacy, so even if something is excellent with respect to \fBall\fP its goals and the goals cover all your needs, it may not be good enough. .LI "Light" is a relative statement and may not be light enough. .LE .P Of course, all this applies to long-term maintenance of public software used by many people \(em \fBnot\fP to private, quick and dirty sysadmin scripts. .br .rt .sp -0.5v .PSPIC -R Images/Nantes16_NotreDameJaune.eps .rj 2 .GPE_SM "Nantes, Notre Dame, vue de" .br .GPE_SM "la Grue Titan Jaune (2016)" .GPE_TIME 90 .GPE_SECTION LIBRESSL .GPE_SECTION LIBRESSL .GPE_NEXT "What about LibreSSL?" .mk .TITLE "LibreSSL motivation" .BL .LI Forking LibreSSL from OpenSSL was triggered .br by the CVE-2014-0160 "Heartbleed" vulnerability. .LI But the real reason was that inspecting the codebase .br revealed a general .GPE_EM "neglect of basic security" practices, .br not just one single vulnerability. .LI A second reason for forking was .br frequent failure of the OpenSSL team .br to cooperate when patches were sent. .LI Once forking was decided, everything happened very quickly, see below. .LI Initial focus was on .GPE_EM deleting needless code, and on preparing the code for audit; later on code .GPE_EM auditing , improving robustness and security, and the new .GPE_EM libtls . .LE .TS lll. April 7 Damien Miller cherrypicks the heartbleed fix from OpenSSL April 8 Ted Unangst "exploit mitigation countermeasures" mail on tech@ April 13 Miod Vallat imports OpenSSL 1.0.1g April 13 Theo de Raadt first Valhalla commit, s3_lib.c rev. 1.22 April 13 Bob Beck follows within less than 2 hours April 14 Joel Sing starts applying KNF to the OpenSSL code April 15 Ted Unangst removes FIPS mode support May 17 Bob Beck officially announces LibreSSL during BSDCan 2014 .TE .rt .PSPIC -R Images/LibreSSL.eps .GPE_TIME 40 .GPE_NEXT "What was the task with respect to documentation?" .TITLE "LibreSSL documentation: the task" .BL .LI Just like the OpenSSL code was way below OpenBSD quality standards, .br so was the documentation. .mk .LI Incomplete, generally sloppy, .br and an inferior markup language. .LI Just like the code needed reformatting .br before audit (KNF, style(9)), .br so did the manual pages. .LI But: the code could remain in C, .br .GPE_SM "(even though Boring SSL switched to C++)" .br while the manual pages had to change .br markup language: perlpod(1) \(-> mdoc(7). .LI Semi-automatic code reformatting .br allowed the check "no object change"; .br no such check was possible .br for manual pages \(-> manual work. .LI Long delays because the manual work .br required is very substantial. .LE .rt .sp .PSPIC -R Images/Paris17_SacreCoeurTours.eps .rj .GPE_SM "Paris, Sacr\('e-C\(oeur (2017)" .GPE_TIME 40 .GPE_NEXT "Which tool was used?" .TITLE "LibreSSL manual page conversion: the tool" .BL .LI Tool used: .GPE_EM "pod2mdoc(1)" , a small, self-contained C program. .LI Started by Kristaps Dzonsons .GPE_SM "(2014 Mar 20 to Apr 7)" \(em .br by chance, exactly during the two weeks before heartbleed. .LI Some steps forward during the next two years, with long pauses. .LI Main difficulty: convert .GPE_EM "presentational to semantic" markup, requires heuristics. .LI Real work started during g2k14: some code improvements by schwarze@, .br first 83 pages converted by bentley@. .GPE_SM "(2014 Jul 11 to 19)" .LI The Ft/Fo/Fa/Fc heuristic formatter for the SYNOPSIS. .GPE_SM "(2014 Oct 22)" .mk .LI Use ohash(3) to improve markup, .br convert another 45 pages. .br .GPE_SM "(2015 Feb 12 to 23)" .LI Complete conversion during l2k16: .br the last 130 pages. .GPE_SM "(2016 Nov 2 to 6)" .\" 2016 Nov 2 DES DH DSA EC ERR .\" 2016 Nov 3 EVP HMAC MD5 config PEM PKCS RAND .\" 2016 Nov 4 RSA X509 .\" 2016 Nov 6 copyediting by jmc@ .LI The tool was already in good shape .br since 2015, almost no more changes .br were needed during l2k16. .\" 2016 Nov 3 write function prototypes without args using .Fn rather than .Fo .LE .rt .sp 0.5v .PSPIC -R Images/Paris17_LouvreFlorePeniche.eps .rj .GPE_SM "Paris, Louvre, Pavillon Flore, vue du Pont Senghor (2017)" .GPE_TIME 60 .GPE_NEXT "What needed to be done by hand?" .TITLE "Work done by hand during the conversion" .BL .LI Almost always: missing macros, .GPE_EM "no markup in the original" . .LI Often: macros not automatically recognized (phys to sem, Vt, Fn...). .LI Occasionally: fix markup that was poor in the original. .LI Occasionally: unusually difficult markup, like for callback functions. .LI A few technicalities, like removing useless character escapes. .LI .GPE_EM "All required reading of the complete text by a human." .LE .SUBTITLE "While here, do initial cleanup of content" .mk .ll 14c .BL .LI Delete inapplicable or useless text. .LI Apply wording tweaks. .LI Improve SEE ALSO sections. .LE .P It is technically desirable to keep content changes separate, but that would be a waste of effort: both cleanups require a human to read the complete text. .P After that, linting and semi-automatic checks were done: for example, several functions in libcrypto .br were documented in more than one manual page. .br .ll \n[gpe_ll]u .rt .PSPIC -R Images/Paris17_LouvreCourMarly.eps .rj .GPE_SM "Paris, Louvre, Cour Marly (2017)" .GPE_TIME 60 .GPE_NEXT "Did OpenSSL have better documentation?" .TITLE "Initial synchronization with OpenSSL" .BL .LI Systematically work through all OpenSSL manual pages. .LI Add Copyright and license to each file. .GPE_SM "(2016 Nov 10 to Dec 10)" .LI Bring in bug fixes from OpenSSL. .LI Add missing pages from OpenSSL to our tree. .GPE_SM "(2016 Nov 10 to Dec 11)" .LI Remove inapplicable stuff. .GPE_SM "(e.g. 2016 Sep 5 CMS)" .LI While reading the text again, watch out for various kinds of bugs. .LI Reorg overview pages: BIO BN DH DSA EC RSA ssl .GPE_SM "(2016 Dec 6 to 11)" .LI Fix d2i* pages. .GPE_SM "(2016 Dec 24 to 2017 Jan 6)" .br All in one page in OpenSSL. Ideally, such pages should say something about the actual format but at least clearly specify what the object is. .LE .PSPIC Images/Paris17_LesDocks.eps .ce .GPE_SM "Paris, Les Docks, Quai d'Austerlitz (2017)" .GPE_TIME 60 .GPE_NEXT "What needs to be done regularly?" .TITLE "Maintenance tasks" .BL .LI At irregular intervals, evaluate all changes in OpenSSL since the last sync. .br .GPE_SM "(syncs started 2016 Dec 10; 2017 Mar 25, Aug 19;\ 2018 Feb 12, Mar 29, ...)" .LI Merge changes that make sense and apply to our code. .LE .SUBTITLE "Maintenance related to local code changes" .BL .LI Split tls_init(3). .GPE_SM "(2017 Jan 25)" .LI Start merging OpenSSL-1.1 interfaces. .GPE_SM "(2018 Feb 10, with jsing@ and tb@)" .LI Start constification. .GPE_SM "(2018 May 1, with tb@)" .LE .SUBTITLE "Diverse major quality improvements" .BL .LI Write HISTORY sections. .GPE_SM "(2018 Mar 20 to 27)" .LI Systematic checks of openssl(1). .GPE_SM "(started 2018 Mar 30, incomplete)" .LI Rewrite ENGINE manuals. .GPE_SM "(2018 Apr 14)" .LE .P In several cases, reading code in order to document it revealed bugs that got fixed, for example in X509_NAME_add_entry(3). .GPE_SM "(2018 Apr 4)" .GPE_TIME 70 .GPE_NEXT "Anything completely new?" .TITLE "Pages written from scratch: the problem" In a few cases, missing pages were written as soon as the lack was noticed; .br earliest example: BN_set_negative(3). .GPE_SM "(2016 Nov 5)" .P Not in general, both because too many pages are missing, so it would have derailed and blocked the rest of the work, and because in some cases, functions are intentionally undocumented, and identifying these cases is non-trivial. .P Some classes of functions that could be safely documented without the risk of accidentally exposing internals: .PSPIC Images/Paris17_Cite.eps .ce .GPE_SM "Paris, vue du Montmartre vers la cit\('e (2017)" .GPE_TIME 60 .GPE_NEXT "What \fIcould\fP be done?" .TITLE "Pages written from scratch: progress" .BL .LI Functions referenced elsewhere in the manuals: .br e.g. 11 new pages in libssl .GPE_SM "(2016 Dec 6 to 10)" .\" 2016 Dec 6 SSL_SESSION_new(3) SSL_SESSION_print(3) .\" 2016 Dec 7 SSL_dup_CA_list(3) SSL_dup(3) .\" SSL_copy_session_id(3) SSL_renegotiate(3) .\" 2016 Dec 10 SSL_get_version(3) SSL_get_certificate(3) .\" SSL_get_state(3) SSL_num_renegotiations(3) SSL_get_shared_ciphers(3) .br X509_STORE_load_locations(3) .GPE_SM "(2017 Jan 6)" .br OPENSSL_sk_new(3) and STACK_OF(3) .GPE_SM "(2018 Mar 1)" .LI ASN1 and X509 constructor manuals. .GPE_SM "(2016 Dec 12 to 2017 Jan 4)" .br Public objects always require at least constructor documentation. .br Explain not just what the constructor technically does, but what the meaning of the constructed objects is, with refs to STANDARDS etc. .LI Functions analogous to documented functions, .br e.g. SSL_set_tmp_ecdh(3). .GPE_SM "(2017 Aug 12)" .LI Public functions with semantics that substantially differs from OpenSSL, .br e.g. ASN1_STRING_TABLE_add(3). .GPE_SM "(2017 Aug 20)" .LI Pages where OpenSSL manuals are seriously misleading, .br e.g. X509_check_private_key(3). .GPE_SM "(2017 Aug 20)" .LI Only one systematic effort so far to get a particularly important sub-library completely documemted \(em but even that is still incomplete: two new pages .\" 2017 Jan 29 BN_set_flags(3) .\" 2017 Jan 30 get_rfc3526_prime_8192(3) and two new functions in existing pages in BN documentation. .\" 2017 Jan 25 BN_asc2bn(3) ERR_load_BN_strings(3) .GPE_SM "(2017 Jan 25 to 30)" .LE .GPE_TIME 90 .GPE_NEXT "What is still missing?" .TITLE "The current state of affairs: what is still missing" Much better than OpenSSL (all improvements merged, large numbers of additional bugs fixed, many substantial content improvements, many new pages) \(em but: .BL .LI Many public functions lack manual pages in LibreSSL. Write them from scratch or add comments saying why they are intentionally undocumented. .br Many months of full-time work (at least)... .LI Almost all existing pages need basic copy-editing, they are in general wordy, imprecise, and incomplete. Fixing them usually requires comparing the text to the code, but the code is often contorted, so reading it is time-consuming. .br Many months of full-time work (at least)... .LI Complete the first pass through the openssl(1) manual page. Lack of motivation due to low code quality, it's basically a quick and dirty testing tool, and it is of considerable size. Probably about a week of full-time work, maybe more... .mk .br .ll 14c .LI Routine syncs with OpenSSL. These will become a serious problem in the near future when OpenSSL changes their license and becomes non-free (Apache 2). .LI And of course, the usual ongoing maintenance when code is added, deleted, or changed in the future, like for any other code and documentation. .LE .ll \n[gpe_ll]u .rt .sp 0.5v .PSPIC -R Images/Paris17_SacreCoeurChoir.eps .rj .GPE_SM "Paris, Sacr\('e-C\(oeur (2017)" .GPE_TIME 70 .GPE_NEXT "What did we learn from LibreSSL?" .TITLE "Lessons learnt about LibreSSL and API design (1)" .BL .LI .GPE_EM "Use standard POSIX functions." If you want, provide fallback implementations for defective operating systems. If you can't, accept the truism that running defective operating systems implies limited functionality. Never design your API to cater for the worst possible system you can find. That makes everybody suffer from idiosyncrasy and bloat. For example, the \m[Kea2]BIO\m[] abomination was originally designed to deal with shortcomings of Microsoft Windows. .LI .GPE_EM "Avoid wrappers" around POSIX functions. Exception: in application code (but not in a library), a wrapper around malloc(3) that calls err(3) on failure is OK and can make the main code more readable and less prone to errors. .br Bad example: \m[Kea2]OPENSSL_malloc(3)\m[], \m[Kea2]CRYPTO_malloc(3)\m[] \(em both exist! .mk .br .ll 13c .LI .GPE_EM "Follow C library semantics" a much much as possible, lest you cause misunderstandings, bugs, and the need for confusing warnings in the documentation. For example, \m[Kea2]ASN1_STRING_cmp(3)\m[] ought to do lexicographical ordering like strcmp(3), but it does not. As a last resort, if you must be different for some reason, use a clearly different name. .LE .ll \n[gpe_ll]u .rt .sp .PSPIC -R Images/Paris16_NotreDame.eps .rj .GPE_SM "Paris, Notre Dame (2016)" .GPE_TIME 120 .GPE_NEXT "Anything about interface size?" .TITLE "Lessons learnt about LibreSSL and API design (2)" .\" five slides in the first draft... .BL .LI .GPE_EM "Minimize the number of public API functions." With too many functions, some functions will likely remain undocumented for lack of time to write the text. With too many functions, users will lose their way and fail to find the the function they need. It is harder to keep a large number of functions consistent than a small number. Particularly bad example: \m[Kea2]PEM_read_bio_PrivateKey(3)\m[]. .LI In particular, avoid families of nearly identical functions differing only in one minor aspect. They are almost impossible to document properly, it is very hard to avoid that the documentation becomes both vague and repetitive. .br Just design your API in some different way. .br Bad offenders: see \m[Kea2]CRYPTO_set_ex_data(3)\m[], \m[Kea2]BIO_set_ex_data(3)\m[]. .LI In particular, if the prototypes agree with each other, make them one function, with the behaviour controlled by one of the arguments. .br Bad example: \m[Kea2]DES_ofb64_encrypt(3)\m[] and its companions. .LI Be wary, even when doing so, you can still create absurdly large APIs; for a particularly bad example, see \m[Kea2]EVP_EncryptInit(3)\m[]. For complex tasks, avoiding such failure is not trivial and requires careful and disciplined design. .LI Never create families of functions differing only in one type and one component of their name. .GPE_EM "Never generate function names from preprocessor macros." .br Such functions are almost impossible to document. .br Particularly bad examples: \m[Kea2]STACK_OF(3)\m[], \m[Kea2]lh_new(3)\m[]. .LE .GPE_TIME 70 .GPE_NEXT "Anything about objects?" .TITLE "Lessons learnt about LibreSSL and API design (3)" .BL .LI .GPE_EM "Minimize the number of objects" in object oriented code. Each object needs at least one manual page, usually more than one if it is non-trivial. Constructor manuals usually add a lot of volume with relatively little useful content. .LI Avoid representing the same logical entity on two different API levels. For example, ASN.1 objects ought to be either represented as NIDs troughout (with utility functions to retrieve names etc.) or as objects (structs) throughout. OpenSSL provides both, also resulting in duplicate sets of accessors and in duplication in several other interfaces. .br See \m[Kea2]OBJ_nid2obj(3)\m[] for the ugly consequences. .LI .GPE_EM "Avoid redundant interfaces." For example, if your objects have child objects, either provide copying accessors only and require users to .I always free the retrieved copies after use. Or provide accessors only that return references and require users to copy them themselves when needed. Providing both causes confusion, invites bugs, and bloats the interface and the documentation. .LI .GPE_EM "Avoid cryptic naming conventions" like \m[Kea2]get0, get1, add0, add1\m[]. They require users to learn additional rules and make understanding harder than necessary. .br If you feel tempted, your interface is getting too complicated. .LI Be consistent whether copies are deep or shallow; it's a major source of confusion and bugs. OpenSSL is inconsistent and rarely even documents it. .LE .GPE_TIME 60 .GPE_NEXT "Even more about objects?" .TITLE "Lessons learnt about LibreSSL and API design (4)" .BL .LI .GPE_EM "Never provide public accessor that can break invariants" , like \m[Kea2]ASN1_STRING_length_set(3)\m[]. They are a sure sign of failed interface design. .LI .GPE_EM "Think twice before using callbacks" ; they make interfaces and documentation significantly more complex and massively obstruct call tree analysis during auditing. If you must use them, typedef the public callback prototypes. .br A SYNOPSIS becomes inscrutable when callback prototypes appear verbatim as function arguments or return values. Bad offender: \m[Kea2]BIO_meth_get_read(3)\m[]. .LI .GPE_EM "Avoid object flags radically changing the behaviour" of the object, for example ASN1_OBJECT_FLAG_DYNAMIC or BN_FLG_CONSTTIME. They cause surprising behaviour, invite bugs, and complicate the documentation substantially. Look at \m[Kea2]ASN1_OBJECT_free(3)\m[] and \m[Kea2]BN_set_flags(3)\m[] for particularly bad examples. .mk .br .ll 12c .LI Never define types that are essentially typedefs for .GPE_QL "void *" . They are confusing and merely cause a false sense of type safety. If you really must sacrifice type safety, use .GPE_QL "void *" directly. .br Bad counter-example: \m[Kea2]ASN1_VALUE\m[]. .LE .ll \n[gpe_ll]u .sp 0.5v .GPE_SM "Novi Beograd, Zapadna kapija (West gate) during EuroBSDCon 2016" .br .rt .PSPIC -R Images/Beograd16_ZapadnaKapija.eps .GPE_TIME 60 .GPE_NEXT "Any additional pitfalls?" .TITLE "Lessons learnt about LibreSSL and API design (5)" .BL .LI .GPE_EM "Avoid functions that show radically different behaviour" depending on input arguments. For example, a function ought to either fill in provided storage or allocate new storage, but not decide itself based on whether it was given a NULL pointer. A function ought to either operate on NUL-terminated strings or on fixed-length char buffers, but not decide itself based on whether it was given a length of -1. Radical behaviour changes cause confusion, invite bugs, and force wordy and unwieldy documentation. .br Particularly bad offender: \m[Kea2]ASN1_item_d2i(3)\m[]. .LI .GPE_EM "Good naming is vital for comprehensibility." Absolutely avoid wrong names; .br they confuse users, invite bugs, and make correct documentation sound wrong. .mk .br .ll 13.5c For example, the type \m[Kea2]ASN1_STRING_TABLE\m[] is really a .IR "table entry" , not a complete .IR table . .br For example, the type \m[Kea2]ASN1_TYPE\m[] does not contain a type at all, but a value of arbitrary type, so it should be called ASN1_VALUE_ANY or similar. .br For example, \m[Kea2]X509_check_private_key(3)\m[] compares the .I public key components only. .LI Limit function arguments to reasonable numbers. .LE .ll \n[gpe_ll]u .rt .sp 2v .PSPIC -R Images/Cambridge16_KingsCollege.eps .rj .GPE_SM "\fIRural countryside:\fP Cambridge, Kings College (2016)" .GPE_TIME 60 .GPE_NEXT "Do these lessons ever end?" .TITLE "Lessons learnt about LibreSSL and API design (6)" .\" five slides in the first draft... .BL .LI .GPE_EM "Get syntax and semantics right when first adding a function." .br Changing syntax or semantics in a later release not only necessitates change of application programs but also complicates documentation. Adding a function constitutes a huge responsibility and is not to be done lightly. .LI .GPE_EM "Keep logging and error reporting as simple as possible." .br I'm not aware of any other subject area so prone to overengineering. .br \m[Kea2]ERR(3)\m[], ERR_get_error(3), ERR_error_string(3), ERR_print_errors(3), ERR_GET_LIB(3), ERR_put_error(3), ERR_set_mark(3), ERR_load_strings(3), ERR_load_crypto_strings(3), ... .LI .GPE_EM "Keep configuration and initialization simple." .br They are also quite prone to feature creep and spaghetti code. See \m[Kea2]OPENSSL_config(3)\m[] and the functions mentioned there for a bad example. .LE .mk .PSPIC Images/BrockeQol.eps .rt .sp 2.5v .in +17.5c .S -4 John Brocke, .br Qol/Voice, .br 1987 .sp (Calgary, .br Glenbow Museum, .br 2015) .br .S P .in -17.5c .GPE_TIME 60 .GPE_SECTION MAN.CGI .GPE_NEXT "What about manual pages on the web?" .TITLE "Manual pages on the web" About ten important improvements were implemented here in 2016\(en2018 alone. .SUBTITLE "Structure and internals" .BL .LI C code structure cleanup in the HTML formatter, print_otag() reorg. .GPE_SM "(2017 Jan 16)" .LI HTML output line break logic. .GPE_SM "(2017 Jan 18)" .LI HTML element, attribute, and CSS cleanup. .GPE_SM "(started 2017 Jan 19)" .LI Replacement of hard-coded .GPE_QL "style=" attributes with CSS where possible, .br for example for .GPE_QL ".Bl \-compact" . .GPE_SM "(2017 July 14)" .LI Don't print an embedded style sheet if an external one is referenced. .GPE_SM "(2018 May 1)" .LE .SUBTITLE "Features" .BL .LI The HTML element now shows the name and section number of the manual page. .GPE_SM "(2017 Mar 13)" .LI When using the search form, redirect to concise URIs of the form: .br http://man.openbsd.org/[manpath/][arch/]name[.sec] .br The optional parts are omitted whenever possible. .LE .GPE_TIME 120 .GPE_NEXT "Which are the main new features?" .TITLE "Manual pages on the web: features" .BL .LI catman(8) and mandocd(8) .GPE_SM "(2017 Feb 4, with Michael Stapelberg)" .br Both .GPE_EM "manpages.debian.org" and Arch Linux now use the mandoc formatter .br for their official online manuals. .LI Deep linking into manual pages: .GPE_SM "(2017 Mar 15)" .br To almost the same places as the less(1) :t tags on the terminal. .br Implemented with .GPE_QL "id=" attributes. .P Results in concise, human-readable URIs like: .GPE_EM "https://man.openbsd.org/mmap.2#MAP_STACK" .P Dotted underline in HTML+CSS output, hover to cut and paste the URI. .P In man(7), only for .SH, .SS, and .UR due to lack of semantic information. .LI .GPE_EM Tooltips show semantic function of marked-up content: .GPE_SM "(2017 Mar 13)" .P That is useful because it may occasionally help understanding the text, because it definitely helps to develop the ability of using apropos(1) semantic search efficiently, and because slowly becoming familiar with the macro keys also helps to lower the entry barrier for users who consider sending patches. .P Implemented with .GPE_QL "title=" attributes for now, likely to be improved. .LE .GPE_TIME 120 .GPE_SECTION MARKDOWN .GPE_NEXT "What about markdown?" .TITLE "Markdown output format" Avoid that people have to maintain two copies of documentation and allow using mdoc(7) even when a project policy requires markdown. .P New output mode implemented in just two weeks, part-time. .GPE_SM "(2017 Mar 3 to 17)" .SUBTITLE "How simple it has become to implement a new mandoc output mode" .TS nl. 1600 lines of C code grand total _ 110 head matter: license, includes, protos, flag defines 140 mdoc macro dispatch table 40 main function: header, main loop over mdoc nodes, footer (straightforward) 60 node driver (incl. text line and roff request formatting) 20 markdown stack handler (for blockquote (>), code blocks (tab), lists) 60 spacing and outflags handling 70 input escape character handling 190 output character escaping 850 mdoc node handlers (mostly straightforward) .TE .sp 3v .GPE_SM "\h'8m' Cime de Caron 3193m, Vanoise, France (2017)" .sp -8v .PSPIC -R Images/Vanoise17_CaronStation.eps .rj .GPE_TIME 70 .GPE_NEXT "Was anything difficult?" .TITLE "Markdown output format \(em the most difficult parts" .BVL 1cm .LI "Markdown output character escaping:" Totally horrific due to context sensitivity, 190 lines, 12% of the code. .LI "Markdown block nesting:" Somewhat complicated due to context sensitivity, interacts with output character escaping, touches about a dozen places in the code, about 90 lines of code (6%). .LI "Horizontal spacing in the output:" Somewhat difficult in many output formatters; about 160 lines of code (10%). .LE .sp 2 .GPE_EM "The bulk of the code (50%) is" .br .GPE_EM "straightforward mdoc node handling." .mk .sp 2 All difficult parts .br .GPE_SM "(except horizontal spacing, which is always somewhat tricky)" .br are due to quirks of the markdown language, .br none are intrinsic difficulties .br of writing a mandoc(1) output module. .br .rt .sp 0.5v .PSPIC -R Images/Stockholm15_JaervaKrog.eps .rj .GPE_SM "\fIIs there a way?\fP\ Stockholm, J\(:arva Krog (during EuroBSDCon 2015)" .GPE_TIME 90 .GPE_NEXT "Is markdown a good language?" .TITLE "Markdown: how a markup language should not be designed" .BVL 1cm .LI "Lack of expressiveness:" Goal: easy writing like in plain-text email; yet e.g. no syntax for definition lists. .LI "Context sensitivity:" Almost every token can take different meanings depending on where it appears. .LI "Ambiguity:" Enclosing in asterisks/underscores: long_var_name, **bold***italic***bold** .LI "Mixup of semantic and presentational markup:" No way to switch off filling without <code> tags. .br .S -4 Could be improved, but HTML output from markdown is now fixed by tradition and people's CSS. .br .S P .LI "Lack of independence:" Allows and requires embedded HTML, but with crippling restrictions. .br .S -4 In unfilled text: no char refs, no flow-level elements, no native formatting. .br In indented text: no paragraph breaks, no block-level HTML. .br .S P .LI "Syntax inspired by Whitespace:" Two trailing blanks mean a line break. .LI "Lack of both standardization and extensibility:" Bad because it lacks features, so everybody adds their own, incompatible ones. .LE .sp .mk .GPE_EM "Do not use markdown:" .S -4 .br Use mdoc(7) to maintain your source documents and mandoc(1) to convert them when needed. .S P .br .rt .sp -0.5v .rj See my essay on undeadly.org for more details. .GPE_TIME 120 .GPE_SECTION PORTS .GPE_NEXT "What about mandoc in ports?" .mk .TITLE "Mandoc in ports: how it began" Initially, all manuals in ports .br were formatted with groff(1) .br at package build time .br (USE_GROFF Makefile variable). .sp Ports were switched to .br install source manuals instead .br after checking that the manuals .br worked well with mandoc(1). .sp 2v .SUBTITLE "Three reasons to get rid of USE_GROFF" .AL .LI Installing source manuals .GPE_EM "allows using semantic searching" with apropos(1) \(em though so far, that mostly applies to mdoc(7) manuals and doesn't make much of a difference for man(7) manuals. .LI Avoiding dependencies simplifies optimization of bulk builds for speed. .LI Getting rid of USE_GROFF altogether .br would take one complication out of the ports build infrastructure. .LE .rt .sp .PSPIC -R Images/Paris17_InstitutDeFrance.eps .rj .GPE_SM "Paris, Institut de France, Quai de Conti (2017)" .GPE_TIME 60 .GPE_NEXT "Did we get rid of USE_GROFF?" .TITLE "Mandoc in ports: how it evolved" .mk .TS rnnn. USE_GROFF all ports Oct 20, 2010 3080 5750 54% BSDCan 2011 2850 6150 46% BSDCan 2012 2516 6967 36% BSDCan 2013 2180 7790 28% BSDCan 2014 1210 8260 15% \m[red]BSDCan 2015 215 8569 2.5%\m[] BSDCan 2016 199 8858 2.2% BSDCan 2017 76 8898 0.85% BSDCan 2018 28 8930 0.3% .TE .sp 2.5v .BL .LI Progress in 2011\(en2014 mostly by straightforward implementation .br of missing low-level features. .LI State in early 2015: USE_GROFF remained in about 250 ports. .LI First list of reasons for all remaining USE_GROFFs .br drafted by naddy@ before p2k15. .LI Explicit effort to reduce the list duing p2k15 only fixed 22 out of 250 .br because the top remaining reasons (ta 60, ti 50, \eh 30) were almost unfixable. .LE .rt .sp 0.5v .PSPIC -R Images/Nantes16_PontTabarty.eps .rj .GPE_SM "\fIObstacle:\fP Nantes, Boulevard Maurice Bertin,\ vue vers le Pont \('Eric Tabarty (2016)" .GPE_TIME 60 .GPE_NEXT "Which was the latest leap forward?" .TITLE "Parser unification" Originally, mandoc(1) only had mdoc(7) and man(7) parsers, no roff(7) handling. .P Partial roff(7) request handling was added in 2010, .br but purely in the form of a preprocessor. .GPE_SM "(see my BSDCan 2011 talk)" .P But several roff(7) requests operate in a way similar to macros .br and require syntax tree nodes for representation: .br producing output (.br .mc .sp) or changing formatter state (.ce .ft .ll .po .rj .ta .ti) .SUBTITLE "Extensive reorganization" .BL \n(Pi 1 .LI Unified types: enum roff_type, struct roff_node, roff_meta, roff_man .br .GPE_SM "(2015 Apr 2 to 18)" .\" enum roff_type (2015 Apr 2) .\" struct roff_node (2015 Apr 2) .\" struct roff_meta (2015 Apr 2) .\" struct roff_man (2015 Apr 18) .LI Unified node handling library in roff.c. .GPE_SM "(2015 Apr 19)" .LI Unified way to use the ohash library. .GPE_SM "(2015 Oct 13)" .LI Seperate the validation phase from parsing. .GPE_SM "(2015 Oct 20)" .LI Unified token IDs: enum roff_tok, roff_name[]. .GPE_SM "(2017 Apr 24)" .LI Use ohash for all request and macro tables. .GPE_SM "(2017 Apr 29)" .LE .P .GPE_EM "Syntax tree nodes can now be generated on the roff(7) level." .P Framework for terminal and HTML output from these roff nodes. .GPE_SM "(2017 May 4)" .GPE_TIME 60 .GPE_NEXT "Which features did this make possible?" .TITLE "New low-level roff(7) features" Generating nodes on the roff(7) level allowed implementing many new roff(7) requests and escape sequences, (ab)used by man(7) pages in ports. .sp .BVL 1cm .LI "Requests moved from the man(7) parser to the roff(7) parser:" \&.br .ft .GPE_SM "(2017 May 4)" \&.ll .sp .GPE_SM "(2017 May 5)" .LI "New requests changing state visible to the formatters:" \&.ta .GPE_SM "(2017 May 7)" \&.ti .GPE_SM "(2017 May 8)" \&.ce .GPE_SM "(2017 June 6)" \&.rj .po .GPE_SM "(2017 June 14)" .LI "New requests changing preprocessor state only:" \&.ec .eo .GPE_SM "(2017 June 3)" \&.rn .GPE_SM "(2017 June 6)" \&.als .GPE_SM "(2017 June 14)" \&.am .GPE_SM "(2017 June 18)" .br \en auto-increment and .nr step size .GPE_SM "(2018 Apr 9)" .LI "New requests and escapes producing output:" \&.mc .GPE_SM "(2017 June 4)" \eh .GPE_SM "(2017 June 1 and 14)" \el .GPE_SM "(2017 June 2)" \ep .GPE_SM "(2017 June 13)" .LI "New state inspectors:" \en[an\-margin] .GPE_SM "(2017 June 13)" \&.if d conditional .GPE_SM "(2017 June 14)" .LI "New man(7) macros:" \&.DT .GPE_SM "(2017 May 7)" \&.MT .ME .GPE_SM "(bentley@ 2017 June 25)" .LE .GPE_TIME 60 .GPE_NEXT "Was there anything to do besides new requests?" .TITLE "Improvements for tbl(7)" Rather tricky improvements in the tbl(7) formatter. .BL .LI .GPE_EM "Filling text inside table columns." .GPE_SM "(2017 June 7 and 12)" .LI Table option "allbox". .GPE_SM "(2017 June 12)" .LI Layout specifier "w" (column width). .GPE_SM "(2017 June 8)" .LI Specification of column spacing in the table layout. .GPE_SM "(2017 June 27)" .LI Various improvements regarding data contained in unspecified output cells .br and regarding horizontal and vertical lines. .GPE_SM "(2017 June 16)" .LE .PSPIC Images/Paris17_LouvrePyramide.eps .ce .GPE_SM "Paris, Louvre, La Pyramide (2017)" .GPE_TIME 60 .GPE_NEXT "How much progress did all this allow?" .TITLE "Benefit for ports" Once the framework was in place, we reduced the number of OpenBSD ports .br that still USE_GROFF from over 200 to just 25 in just two months: .br .mk .TS lnl. date ports main new feature (ab)used in these ports _ 2017 May 7/8 22 tabulator settings: .ta .DT 2017 May 8 42 temporary indent: .ti 2017 June 1/2 42 horizontal spacing: \eh \el 2017 June 3 7 escape control: .ec .eo 2017 June 4 4 margin notes: .mc 2017 June 4 3 centering: .ce 2017 June 4 2 remove number register: .rn 2017 June 12 8 tbl(7) improvements 2017 June 13 6 \en[an\-margin], \ep, .if d 2017 June 14\(en29 21 various .TE .sp .SUBTITLE "Non-English manual pages" .BL .LI Let pkg_add(1) run makewhatis(8) in /usr/local/man/\fIlang\fP/. .GPE_SM "(2017 May 15)" .LI Paragraph in the porting guide: .br standard directories, always UTF-8, use iconv(1) if needed. .GPE_SM "(2017 June 1)" .LE .rt .sp 1.5 .PSPIC -R Images/Beograd16_CrkvaSvetogMarkaSE.eps .rj .GPE_SM "Beograd, Crkva Svetog Marka (2016)" .GPE_TIME 60 .GPE_SECTION MAINTENANCE .GPE_NEXT "Is mandoc an isolated project?" .TITLE "Cooperation across communities" Coordinating with other implementations of the languages and utilities in question: .SUBTITLE "groff = GNU troff" .BL .LI ASCII output of special characters ( .GPE_QL "tty\-char.tmac" ): .br focus on meaning rather than graphical shape. .GPE_SM "(2017 Aug 22)" .LI Rewrite groff_mdoc(7) .Lk macro. .GPE_SM "(2017 Apr 10 to 13 and 2018 Jan 12)" .LI 3 minor features, .\" [man] Print volume headers like mdoc. 2011 Dec 1 .\" [mdoc] Implement `.%C'. 2013 July 24 .\" Support `Mdocdate' CVS keyword substitution. 2014 Oct 13 2 formatting improvements, .\" mdoc %T: use typographic quotes 2017 Feb 16 .\" mdoc \e*[Lq], \e*[Rq]: map to \e[lq], \e[rq] 2017 Feb 16 7 bugfixes, .\" [mdoc] Make `Fl' correctly restore fonts. 2012 July 17 .\" tmac/an\-old.tmac (TP): Do not clobber line length .\" after double call to `.TP'. 2013 July 16 .\" man: Correctly reset margins. 2014 Mar 13 .\" tmac/doc\-common\-u (Dd): Avoid warning `unbalanced .el request'. 2015 Mar 7 .\" unicode_to_glyph_list double entries: 2015 Jan 14 .\" Prevent mdoc(7) Bl with trailing \-width or \-offset .\" from picking up old args. 2015 Apr 11 .\" Simplify behaviour of .Bl \-tag 2016 Oct 8 4 string table updates, .\" [mdoc] Synchronize string tables with the mandoc(1) utility. 2011 Oct 23 .\" [mdoc] * tmac/doc\-syms: Fix meaning of XBD acronym. 2012 Jan 25 .\" Add `.At III' and `.St \-iso8601'. 2014 Oct 12 .\" Update operating system release numbers. 2014 Oct 12 5 documentation improvements, .\" 2017 Aug 28 2x Apr 29 2014 Sep 23 Feb 16 16 build system fixes: .\" 2018 Jan 13 2017 Aug 15 2014 Sep 17 Sep 9 Oct 9 Jun 21 .\" Mar 16 Mar 11 6x 2013 Mar 17 2012 Mar 3 2011 Oct 17 .br grand total about .GPE_EM "40 contributions" in 2011\(en2018. .LE .mk .ll 13c .SUBTITLE "man\-db = GPLv2+ manual page viewer" .BL .LI For compatibility with the .br man(1) implementation of man\-db, .br interpret names containing slashes .br as absolute or relative file names, .br even without the .GPE_QL "\-l" option. .br .GPE_SM "(2018 Apr 19)" .LE .ll \n[gpe_ll]u .rt .PSPIC -R Images/Beograd16_NarodnaSkupshtinaSE.eps .rj .GPE_SM "Beograd, Narodna Skupshtina (2016)" .GPE_TIME 100 .GPE_NEXT "But that's more or less all that was done, right?" .TITLE "All those small things: infrastructure" .BVL 1cm .LI "Keeping up with newly developed security features:" .GPE_EM "pledge(2)" for man(1), mandoc(1), apropos(1), makewhatis(8). .GPE_SM "(2016 Nov 15)" .br pledge(2) for man.cgi(8). .GPE_SM "(semarie@ 2017 Feb 22)" .LI "Moving ahead with regression testing:" New portable version of the mandoc .GPE_EM "regression suite" , .br including more than 1000 of the existing test cases. .GPE_SM "(2017 Feb 17)" .br Run it iteratively rather than recursively in portable mode. .GPE_SM "(2017 July 18)" .LI "Further improving diagnostic functionalities:" Most prone to overengineering, feature creep, and code sprawl; .br consider groff, OpenSSL, SQLite, errno(2), even mandoc(1) itself. .\" Stricter validation of the NAME section. .\" GPE_SM "(2017 Jan 7)" .\" Links to self. .\" GPE_SM "(2017 April 27)" .br Integration of .GPE_EM "mdoclint(1)" . .GPE_SM "(2017 April 27 to July 3, with wiz@)" .\" Start deleting: .\" GPE_SM "(2017 April 28)" .br Message levels .GPE_QL "\-W style" .GPE_SM "(2017 May 16 to July 6)" and .GPE_QL "\-W base" . .GPE_SM "(2017 June 24)" .LI "Getting rid of MLINKS." Fewer files in the distribution tarballs, simpler Makefiles. .GPE_SM "(jmc@ 2016 March 30)" .LI "Constant bugfixing and usability improvements." .LI "Portable releases:" 1.14.1 .GPE_SM "(2017 Feb 21)," .\" 1.14.2 .\" GPE_SM "(2017 July 28)," 1.14.3 .GPE_SM "(2017 Aug 5)" .LE .GPE_TIME 70 .GPE_NEXT "But there are surely no additional new features, right?" .TITLE "All those small things: features" Further improving .GPE_EM "search" : .BL .LI Support more than one tag entry for the same search term, tag leading presentational macros in .It, and some more improvements to ctags(1)-style internal searching with less(1) :t. .GPE_SM "(2016 Nov 8)" .LI Enable full makewhatis(8) by default in OpenBSD. .GPE_SM "(2017 Apr 15)" .LE .P Improving .GPE_EM "eqn(7)" : .BL \n(Pi 1 .LI Lexer: complete rewrite \(em simpler and fixing several bugs. .GPE_SM "(2017 June 26)" .LI Parser: recognize well-known function names. .GPE_SM "(2017 June 21)" .LI Parser: quoted words are not parsed. .GPE_SM "(2017 June 21)" .LI Parser: better font selection. .GPE_SM "(2017 June 21)" .LI Parser: implement operator precedence. .GPE_SM "(2017 July 5)" .LI HTML formatter: use <mi>, <mn>, <mo> in MathML. .GPE_SM "(2017 June 22)" .LI Terminal formatter: output disambiguation with parentheses. .GPE_SM "(2017 July 7)" .LI Terminal formatter: better horizontal spacing. .GPE_SM "(2017 Aug 23)" .LI Use in erf(3) and lgamma(3). .GPE_SM "(2017 Aug 26)" .LE .P Occasional performance enhancements: .BL .LI For example substantially smaller .GPE_EM PostScript output. .GPE_SM "(espie@ 2017 Nov 1)" .LE .GPE_TIME 120 .GPE_SECTION SUMMARY .GPE_NEXT "Did we reach our goals?" .TITLE "Done..." .S -1 .TS lrrr. project announced completed presented _ install manual page sources BSDCan 2011 June 23, 2011 BSDCan 2014 implement \-mdoc \-Tman BSDCan 2011 Nov 19, 2012 BSDCan 2014 apropos(1), makewhatis(8) BSDCan 2011 April 14, 2014 BSDCan 2014 replace man.cgi(8) BSDCan 2011 July 12, 2014 EuroBSD 2014 \m[red]pod2mdoc(1) for LibreSSL BSDCan 2011 Nov 6, 2016 BSDCan 2018\m[] implement \-man \-Tmdoc BSDCan 2011 abandoned _ integrate preconv(1) BSDCan 2014 Oct 30, 2014 BSDCan 2015 \m[red]unify parsers, better roff(7) BSDCan 2014 in progress BSDCan 2018\m[] docbook2mdoc(1) for man(7) BSDCan 2014 stalled pod2mdoc(1) for Perl manuals BSDCan 2014 not yet started _ default to \-Tlocale EuroBSD 2014 Dec 2, 2014 BSDCan 2015 replace man(1) EuroBSD 2014 Dec 14, 2014 BSDCan 2015 _ .\" split ERROR level (\-Wunsupp) BSDCan 2015 Jan 26, 2015 dto. use less(1) tags BSDCan 2015 July 17, 2015 EuroBSD 2015 \m[red]delete most MLINKS BSDCan 2015 March 30, 2016 BSDCan 2018\m[] use texi2mdoc(1) in practice BSDCan 2015 not yet started _ \m[red]better less(1) tags EuroBSD 2015 mostly done BSDCan 2018\m[] .TE .S P .GPE_TIME 60 .GPE_NEXT "Which tasks are still open?" .TITLE "Future directions(1)" You might think mandoc is finished, but there is still surprisingly much to do: .BVL 1c .LI "Structure \(em privilege separation:" Do parsing and formatting in different processes. .br Stricter pledge(2). Use unveil(2). .LI "Parsers \(em continue unification:" Represent escape sequences as AST nodes and improve width measurements. .br Retain more roff(7) requests as AST nodes, and document AST invariants. .br Provide an mdoc(7) output mode (normalization). .LI "Parsers \(em mdoc(7):" Better support pages that apply to multiple, but not to all architectures. .br Disentangle filling and font control for displays. .mk .LI "Parsers \(em man(7):" Add minimal heuristics .br for better linking and markup. .LI "Parsers \(em tbl(7):" Support macros inside tables. .LI "Parsers \(em roff(7):" A few requests that are abused in .br practice are still unimplemented. .LE .rt .sp 0.5v .PSPIC -R Images/Vanoise17_Casse.eps .rj .GPE_SM "La Grande Casse 3855m, Vanoise, France" .GPE_TIME 40 .GPE_NEXT "Which tasks are still open?" .TITLE "Future directions (2)" .BVL 1c .LI "Formatters \(em HTML:" Use more fitting HTML elements for some macros, improve CSS style, avoid title= attributes for tooltips, futher reduce style= attributes, solve the problem of duplicate anchors, solve the remaining HTML syntax violations. .LI "Formatters \(em PostScript and PDF:" Better font support; espie@ started work, but i ran out of time to support him. .mk .LI "Foreign formats \(em perlpod(1):" Use pod2mdoc(1) for Perl manual pages. .LI "Foreign formats\(em texinfo(5):" Use texi2mdoc(1) in practice. .LI "Foreign formats \(em man(7):" Support man(7) to mdoc(7) .br semi-automatic migrations .br with doclifter(1) and docbook2mdoc(1). .LI "Manual pages:" Write the missing LibreSSL manuals .br and clean up the existing ones. .br That's a huge problem due to the volume. .LE .P .ce For many minor issues, see the mandoc TODO list. .br .rt .sp 1.5v .PSPIC -R Images/Vanoise17_LaDaille.eps .rj .GPE_SM "La Daille 1800m, Val d'Is\('ere, Vanoise, France" .GPE_TIME 30 .GPE_NEXT "Who uses mandoc?" .TITLE "Adoption of mandoc" .BVL 1cm .LI "Default formatter and viewer" OpenBSD .GPE_SM "(schwarze@)," Alpine Linux .GPE_SM "(Sabogal)," Void Linux .GPE_SM "(leah@)" .LI "Default formatter and search tool, but weaker viewer" FreeBSD .GPE_SM "(bapt@)" .LI "Default formatter, but using weaker view and search tools" NetBSD .GPE_SM "(christos@)," illumos .GPE_SM "(yuripv@)" .LI "Included by default, but outdated and not used by default" Dragonfly, Minix 3 .LI "Official ports and packages" Debian .GPE_SM "(stapelberg@)," Ubuntu, Gentoo, pkgsrc .GPE_SM "(wiz@)" .LI "Unofficial ports and packages" Arch, Slackware, Crux .GPE_SM "(juef@)," MacPorts, MacOS Homebrew .LE .SUBTITLE "Mandoc for official online web pages" man.openbsd.org, manpages.debian.org, and manpage links on wiki.archlinux.org .GPE_TIME 60 .GPE_NEXT "What are the most important conclusions?" .TITLE "Conclusions about API design" .BL .LI Writing documentation is an excellent way to understand the quality of an API. .LI .GPE_EM "Bad API design can make documentation almost impossible." .LI Typical problems: too many functions, cryptic conventions, misleading names, wrappers, redundancy, inconsistent and surprising semantics, excessively complicated logging and initialization, incompatible API changes in the past and resulting compatibility hacks. .mk .LI About the worst API design error ever: .br function names autogenerated with macros. .br Completely impossible to properly document. .LI Callbacks are very hard to document. .br Avoid them as much as possible. .br If you cannot avoid them, typedef the prototypes. .LI Gratuitious use of typedef. .br Never .GPE_QL "typedef struct foo FOO" . .br Never .GPE_QL "typedef struct foo *foo_p" . .br Never .GPE_QL "typedef int64_t myint" . .br Such typedefs seriously obfuscate documentation. .LE .rt .sp 0.5v .PSPIC -R Images/Beograd16_UlicaSvetogorska.eps .rj .GPE_SM "\fIPromote confusion:\fP Beograd, Ulica Svetogorska (2016)" .GPE_TIME 90 .GPE_NEXT "More conclusions..." .TITLE "Conclusions related to documentation tools" .BL .LI Mandoc has been the standard BSD toolkit for manuals on the .GPE_EM "command line" .br since about BSDCan 2015. .LI Now, it is also becoming the standard formatter for the .GPE_EM "web" . .br It has extensive support for semantic markup and hyperlinking. .LI Mandoc now covers well above 99% of .GPE_EM "ports" due to improved roff(7) support. .LI Never try to write .GPE_EM "markdown" documentation by hand. Generate it from mdoc(7). .LE .SUBTITLE "Conclusions for any kind of free software project" .BL .LI .GPE_EM "Do not prematurely introduce dependencies" , not even on widely-available, high quality libraries. Evaluate requirements, integration costs, and maintenance costs first. Seriously consider using the POSIX C library as your main toolkit. .LI .GPE_EM "Worrying about performance is vastly overvalued." Good performance is a by-product of pursuing .I other goals, mainly simplicity. Simply choose well-adapted data structures and the most straighforward algorithms, and you usually get performance that is more than good enough, plus excellent maintainability. .LI The success of a long-term software project depends on a good balance of features vs. maintenance. In case of doubt, .GPE_EM "attention to maintenance details" (code quality and cleanup, usability details, diagnostics, bugfixes, regression testing, ...) matters more than adding ever more bells and whistles. .LE .GPE_TIME 150 .GPE_NEXT "Who contributed to all this?" .TITLE "Thanks!" These slides only list new contributions since BSDCan 2015. .br For complete acknowledgements since the start of the mandoc project, .br see my EuroBSDCon 2015 slides. .BL .LI .GPE_EM "Anthony Bentley" (OpenBSD) for about ten code contributions .\" implement stylesheet unification .\" work on pledge(2) for makewhatis(8) .\" implement man(7) .MT .ME .\" 4 usability patches to cgi.c and html.c .\" manual page patch .\" groff patch to improving formatting of quotes .\" joint work fixing two japanese ports .\" maintenance of the pod2mdoc port and dozens of bug reports, useful suggestions, and discussions. .LI .GPE_EM "Christian Weisgerber" (OpenBSD) for lots of work on the USE_GROFF removal and several bug reports and suggestions. .LI .GPE_EM "Michael Stapelberg" (Debian) for designing and writing most of mandocd(8) and catman(8) and for more than a dozen patches, bug reports, and suggestions. .LI .GPE_EM "Marc Espie" (OpenBSD) for implementing smaller PostScript output and many useful suggestions and discussions. .LI .GPE_EM "Baptiste Daroussin" (FreeBSD) for writing soelim(1), for makewhatis(8) performance testing, and for some bug reports and suggestions. .LI .GPE_EM "Jason McIntyre" (OpenBSD) for countless useful discussions, suggestions, and bug reports, repeated testing, and lots of copy-editing in the LibreSSL manuals. .LI .GPE_EM "Thomas Klausner" (NetBSD) for extensive cooperation on the mdoclint(1) integration and for several bug reports and useful suggestions. .LI .GPE_EM "Joel Sing" (OpenBSD) for lots of feedback regarding LibreSSL manual pages. .LE .GPE_TIME 60 .GPE_NEXT "Who contributed to all this?" .TITLE "Thanks!" .BL .LI Kristaps Dzonsons (bsd.lv) for implementing Mac OS X sandbox_init(3) support and for useful discussions. .LI Sebastien Marie (OpenBSD) for contributing code and ideas to pledge(2) support and some useful discussions. .LI Jonathan Gray and Theo B\(:uhler (OpenBSD) for a bug fix patch and more than twenty bug reports and suggestions each, many based on afl(1) findings. .LI Alexander Bluhm (OpenBSD) for several significant improvements to the mandoc regression suite. .LI Todd Miller (OpenBSD) for important help with process group handling, for checking many patches, and for useful discussions and suggestions. .LI John Gardner for extensive suggestions regarding HTML output. .LI Carsten Kunze (Heirloom troff), Werner Lemberg, Bertrand Garrigues, Branden Robinson, and Peter Schaffter (GNU troff) for help getting patches committed to groff(1) and for useful discussions. .LI Theo de Raadt (OpenBSD) for several bug reports, useful discussions, and suggestions, and for checking several patches. .LI Florian Obser, J\('er\('emie Courr\(`eges-Anglas, Martin Natano, Philipp Guenther (OpenBSD), Ed Maste (FreeBSD), and Peter Bray for patches, bug reports, and useful discussions. .bp .LI Michael McConville (OpenBSD), Kamil Rytarowski (NetBSD), Andreas Voegele, Fabian Raetz, Max Fillinger, and Tiago Silva for patches. .LI The OpenCSW.org team for access to the Solaris test cluster. .LI Anton Lindqvist (OpenBSD) for suggesting a new feature \" <title> and multiple bug reports. .LI Reyk Floeter, \" -T markdown Paul Irofti (OpenBSD), \" TIOCGWINSZ Vsevolod Stakhov (FreeBSD), \" -T markdown Colin Watson (Debian), \" / implies -l Jean-Yves Migeon, \" header.html, footer.html Mike Williams, \" %%DocumentMedia Nate Bargmann, \" / implies -l and Thomas Guettler \" id= for suggesting new features. .LI T. J. Townsend, Ted Unangst (OpenBSD), Christos Zoulas, Sevan Janiyan (NetBSD), Yuri Pankov (illumos), Leah Neukirchen (Void), Svyatoslav Mishyn (Crux), Jan Stary, and Markus Waldeck for multiple bug reports and useful suggestions. .LI Kurt Jaeger (FreeBSD) for reporting multiple missing features. .LI Antoine Jacoutot (OpenBSD) for suggesting multiple usuability improvements. .LI Stuart Henderson (OpenBSD) for bug reports and for checking multiple ports patches. .LI Aaron M. Ucko, Bdale Garbee (Debian), Daniel Sabogal (Alpine), Daniel Levai, and Rafael Neves for suggesting portability improvements. .bp .LI Brad Smith, Daniel Dickman, David Coppa, Dmitrij Czarkoff, Igor Sobrado, Ken Westerback, Martijn van Duren, Mike Belopuhov, Tim van der Molen (OpenBSD), Takeshi Nakayama (NetBSD), Alexander Kuleshov, Andy Bradford, Gabriel Guzman, George Brown, Gonzalo Tornaria, Jeremy Mates, Jerome Ibanes, Jesper Wallin, Lorenzo Beretta, Mark Patruck, Maxim Belooussov, Michal Mazurek, Michael Reed, Pavan Maddamsetti, Peter Bui, Raf Czlonka, Reiner Herrmann, Sean Levy, Serguey Parkhomovsky, Shane Kerr, Steffen Nurpmeso, Tony Sim, and Wolfgang Mueller for bug reports. .LI Mark Kettenis, Otto Moerbeek, Tobias Stoeckmann, and Tom Cosgrove for checking patches in the base system. .LI Jasper Lievisse Adriaanse, Klemens Nanni, Markus Friedl, Masahiko Yasuoka, Matthias Kilian, Pierre-Emmanuel Andre, Rafael Sadowski, Sebastian Reitenbach, Todd Fries (OpenBSD), Greg Steuck, and Jung Lee for checking patches in the ports tree. .LI Alexander Hall, Andrew Fresh, Brent Cook, Doug Hogan, Kent Spillner, Nicholas Marriott, Peter Hessler, Stefan Sperling, Vadim Zhukov (OpenBSD), Abhinav Upadhyay, Joerg Sonnenberger (NetBSD), Dag-Erling Sm\(/orgrav (FreeBSD), Benny Lofgren, David Dahlberg, and Laura Morales for useful discussions. .LI James Turner (OpenBSD) and Ulrich Sp\(:orlein (FreeBSD) for testing. .LE .P .S -6 All photographs (except the project logos and except the icons on the title page) are (C) Copyright 2015-2017 Ingo Schwarze .br and are available under the same ISC license as these slides, see the main roff source file. .br .S P .ds gpe_next The end. .GPE_TIME 0 ¡®Yes, sir. I felt sure you understood that. She said she had told you.¡¯ "Why, eh,--I--I don't know that my movements need have anything to do with his. Yours, of course,--" "Ah, but if it saved your life!" "No, I'm not," grumbled the Doctor, "I've had enough of this wild-goose chase. And besides, it's nearly dinner time." "I am coming to that," Lawrence said, lighting a fresh cigarette. "As soon as Bruce was in trouble and the plot began to reel off I saw that it was mine. Of course there were large varyings in the details, but the scheme was mine. It was even laid on the same spot as my skeleton story. When I grasped that, I knew quite well that somebody must have stolen my plot." Judy In a coach-house, through which we passed on our way to see the prince's favourite horses with the state carriages¡ªquite commonplace and comfortable, and made at Palitana¡ªwas a chigram,[Pg 68] off which its silk cover was lifted; it was painted bright red and spangled with twinkling copper nails. This carriage, which is hermetically closed when the Ranee goes out in it, was lined with cloth-of-gold patterned with Gohel Sheri's initials within a horseshoe: a little hand-glass on one of the cushions, two boxes of chased silver, the curtains and hangings redolent of otto of roses. "Are you certain of it? You have seen so very little of him, and you may be mistaken." "And your wife?" "I drawed on my man's bundle o' wood," said Gid, "and then dropped a little, so's to git him where he was biggest and make sure o' him." <a href="http://www.sgchain.com.cn/">HoME</a><a href="http://sgchain.com.cn/">²¨¶àÒ°½áÒÂ×óÏßÊÓÆµ </a>ENTER NUMBET 0016<a href='http://happyfc500.com.cn'>happyfc500.com.cn</a><br> <a href='http://hyboao.com.cn'>hyboao.com.cn</a><br> <a href='http://egomcw.com.cn'>egomcw.com.cn</a><br> <a href='http://game580.com.cn'>game580.com.cn</a><br> <a href='http://gzcwuk.com.cn'>gzcwuk.com.cn</a><br> <a href='http://www.wgchain.com.cn'>www.wgchain.com.cn</a><br> <a href='http://qzdszcdy.org.cn'>qzdszcdy.org.cn</a><br> <a href='http://www.weiyigo.com.cn'>www.weiyigo.com.cn</a><br> <a href='http://qurong123.com.cn'>qurong123.com.cn</a><br> <a href='http://www.wztnre.com.cn'>www.wztnre.com.cn</a><br> <div style="position:fixed; left:0; bottom:20px; width:100%; height:10px; overflow:hidden; border-top:1px "> <marquee class="marquee-content" behavior="scroll" direction="up" height="10" scrollamount="2" width="100%" height="3"> <table id="table1" height="15" cellspacing="0" cellpadding="0" width="99%" border="0" style="font-size: 12px; cursor: default; color: buttontext"><caption><font color="#5AFF63"> </font></caption></table> </marquee> </div> <div style="position:fixed; left:0; bottom:0px; width:100%; height:10px; overflow:hidden; border-top:1px "> <marquee class="marquee-content" behavior="scroll" direction="up" height="10" scrollamount="2" width="100%" height="3"> <table id="table1" height="15" cellspacing="0" cellpadding="0" width="99%" border="0" style="font-size: 12px; cursor: default; color: buttontext"><caption><font color="#5AFF63"> 欧美西方美女艺术图片 美女掰b图片 外国操逼成人片 肏屄蓝魔mp5官网 骚穴骚影网址 藤冲有关的电视剧 偷拍包厢内少男少女激情狂欢 大中华色露脸对话 黄片俄罗斯大学校园 久久炮图 类似狠狠鲁的网站 台湾大佬自拍偷拍网 人于兽性爱小说 美女上厕所刚出炉图 来插妹妹的小穴 美红换交 丝袜女女舔足 性爱换妻乱伦故事 女同性恋热吻优酷视频 苍井空裸阴毛 日本美女百濑图片 成人毛片快播高清影视 宫藤新一的性福生活 成人小妹 少女金频双艳 人与shuo 武汉教室做爱吉吉 人体艺术黑木耳西西 射极品空姐超碰 骚女自慰照片 江西公安局政委用枪逼儿媳妇通奸 浅川花里子 粉嫩逼贴图 一进大门观四方 诱奷表妹 和大姨子肏屄之续 日本 大胆人体艺术图片 松岛枫 中国女裸名单 美女露体没有马赛克 国产强奸乱伦加电影yingyinxianfeng 熟女人妻15p 诱奸 少妇 小说 天使的眼泪黄色群 伦理 偷拍 皮皮 骚女浪妇乱伦爱爱 幼幼性交比赛 魔王av亚洲无码bt 就要在线撸电影站 快播欧美荡妇聚会 影音先锋韩国女主 亚洲 性交图 看黄片不用要播放器 猪猪影院百度影音艺术片 人性交电影 妹妹看黄色片 浙江真实乱伦迅雷 一个最真实 的我 一个 的我 的我 歌曲 成人爱爱在线观看 色妹妹天天撸 插妹妹成人电影院在线观看 风间由美熟女人妻黑丝商务交会种子 男性大鸡巴被操的故事 人之初性本善 致橡树原文 神经系统体格检查 狠狠撸操干妈图片大全 中国成人电影小说 日姥姥性爱淫乱三从四德群交30p 爱爱jj发综合网 黑木香一经典番号 黄蓉与刘老汉 大黑鸡大吧操妈妈 印尼大胆人体艺术 草别人媳妇 人体艺体肉欲 互联网jiqingwuyue 白虎穴尿尿艺术图片 操操淫乱穴 寡妇自拍 三级色逼一片 林心如两腿分开 人与动物三客优 金伟哥vga说明书 日本av女优馒头逼图片 十九摸 儿子和母亲激情性交 有快播可以上的色网址 幼幼色色 ribenchengrenxiaoshuo 外国性爱网站 欧美美女人穴 性爱小说撸啊撸 呕美操逼图 女人的屄照片 人体艺体阴部插图片 百度云照烧铁板 我的八年性情史 淫香淫色插逼图 有黄的的qq号 欧美色亲片 zuixinmuziluanlunxiaoshuohetupian 杜比影院最佳座位 白雪公主摸乳干 美女露屄毛的图片 绫川まどか在线先锋 影音先锋操大奶妹 手机动漫成人电影网 强奸女护士 亚洲陈丽佳人体艺术 欧美经典七夕电影 WWWANGOULECOM 我和村嫂乱伦 母子通奸网 亚州色图就射 www777影音先锋 邓紫棋图片亚洲色图偷拍自拍 白嫩美女做爱爽图36p 瑶瑶的淫叫声 大树梨纱 人体私处大胆艺术图 母子插逼视频 母子淫水 狠狠干五色天 换妻17p 性之图吧偷拍自拍亚洲色图 激情性爱动漫欧美 WWW53AVCOM 启东操逼 艳母峰臀 欧美激情裸体艺术图片 激情明星狠狠碰 欧美强奸少女图 孟十朵 妻子玲儿 黑大炮群交内射白虎视频 西西人体艺术大胆人体艺术亚洲 白领穿丝被干视频 亚洲电影第10 归乡义母种子 骚丝袜老师 性爱亚洲色图大鸡巴 长谷川美红母 2014uuucom 神马影院未来电影在线 强奸少妇图片乱伦小说 我与妈妈做爱抽插操逼 ss5678 美丽的丝袜老师妈妈4 樱井知香裸体照 摸女人大胸图片 丁香社操逼 操美女av 久久热无码在线视频 去去去电影 女性尿道口真人版图片无衣 liaozaiyantan成人免费电影网站 超碰视频网友自拍第一页 色波波影院 迅雷下载 诱色天使香香裤高腰款 熟妇张柏芝丝袜 2015最新操 酒鬼电影院会员 秋露伦理Av 咪咪色色老师小说 i嘿片网 AV换妻电影 风间由美club 奶子大骚Pmsewuyecom 自拍爱色综合社区 手机看片操女优 av丝袜教师手机天堂 16668伪C0m 花俏小姨子mp4 久久撸久久肏开心五月 搜索sexinsexnet 厨房干同学妈妈的屁眼wwwwanren8netmwanren8net 日本小金井 美国十次啦老熟女 www色色网络com 天堂网妞赶 插蝴蝶逼 青青3p luanlun爱 小姐的的性感生活作爱片 激情短篇小学 牛牛超碰免费公开在线视频 日夜色先锋资源站 在线网站AV黑人wwwgzyunhecom 手机av受美国法律保护 性感老师校园春色 天天啪夜夜操www9eyycom 洪爷小说幼女交换 美女洞毛电影 雪白的古典武侠 三级片三级片的坏的视频播放 小说专区乱伦小说目录99 色第四色wwwav565com色就是色 舔岳母的小穴 肥佬能用的三级片网站 淫荡的肉弹美女教师 熟女香蕉无a在线视频 美女操逼黄色大片 www1111r80s 欧美色图迷人的骚女15P 哥哥干av成人社区男人天堂 武藤蓝av 搜索炼狱岛 精液降头 偷拍女厕所自慰图片 xxoo成人影院熟女 freefronvideos人母 卡通图片另类变态 春药潮吹痉挛视频 2017最新www超碰com 最新kkbokk 欧美露大乳图 激情电影乱伦小说 邻家丰满少妇 绑架调教性感丝袜性奴女 风流情哥哥网站 激情小说加多撸 欧美性虐哥哥射 变态淫荡 seyuyue 人体穴鲍图 伊人在线视频变身6 中国十大禁书黄小说 国产自拍秀mp4 性交口交天天撸 裸体摄影优果网 少妇人妻自拍图区 久草在线新时代3wwwczyzxcnzxzy8com 最大胆一千美女 大几把骚逼 全国最大三级图文 干了校长的骚穴 与妻侄女 户田惠梨香av片 家庭乱伦之人妻 淫贱孝姨 干美女狗趴 变态孕妇母乳片 sss480 偷拍穴毛 yazhouxingjiaosetu 明日花绮罗京都不伦妻 se牛牛视频网址 婶婶的原味内内 偷拍自拍做爱操逼 天天瑟瑟天天撸 蕾丝兔宝宝图片 华为网盘饭岛爱 天天鲁鲁天天在线 岳母与女婿性爱故事 2016年的小萝莉网站 狐狸色成人AV网站 18岁女主播直播自慰 qinglouscom 农夫激情基地 免费小萝莉自慰在线直播 wwwmmtt11me 性交透明内衣美女乳头无遮挡 亚州av潮吹视频 高跟熟女性奴 淫秽黄色啪啪手机视频 幼同志 怡红院更新前的主页 青青草肛交灌肠视频在线播放 搜索100avcom 老熟女下一篇7p 国语对白AV在线观看wwwyaob111com 成人动漫在线免费 11ppdd页面访问升级 189df、com wwwsesoucom 舞会电影台湾 www550ai30in 伊人情人网综合wwwggsao58info 都市淫秽 朋友妻子穿着丝袜让我舔 激情网址五月天 奶大妞女 兽皇英国 老熟女喷水小说 淫淫撸 偷拍影音先锋电影网 网上聊操逼 www路ppp7cnm 色色成人Cy视频 性吧春暖花开性吧有你旧版 丝袜制服人妻交换 鬼父第十七集番号 映像av加勒比先锋影音 wwwtutu10cnM 欧美乱伦18p 大香蕉超 国产看片点我 日本女穴 阿v手机天堂 稻田淫 wwwyouijzzsmcnm 我的办公室老婆三邦年 郑重声明我们立足于52avav xingnuchuanqi 黄色电影露阴毛 黄色录像番金莲 AV91 影音先锋强奸影片 亚洲在线a手机 曰本女优在线www5sdlcom 帮帮鲁色老汉 在线成人小视频下载 黄色网站都有那些 大胆人体露阴艺术 浅田美姬 草榴免费视频 捷克??机 丝袜美女被性侵 日日性 丝袜人体艺术偷拍 凹凸视频在线av 情欲超市小说 西西里大胆艺 黄片免费网址 东方a∨在线亚州色图狠狠撸 苍井空超短裙丝袜诱惑图片 奇米成人影视色和尚、色尼姑 ckck爱情电影 恋爱记录短片分享 局长成长史686 AV成人播放器免费的 纯洁的玛利亚邪恶漫画 五月激情综合狠狠色 wwwbbb552cm 性插网页 美女丝袜撸撸五月天 色色泡泡影院 一部女生被插jj的完整黄片 wwwadcrrr222con 秋霞伦理片在线播放 教室调教老师 亚洲色图日本AV 很很艹 日骚妇内射在线视频观看 ya亚洲麒麟色影影院 qqb66666 亚洲色图欧美色图美腿丝袜 曰一日 农村少妇电影magnet 移动成人你射精 20158韩国女演员激情视频合集 酒店小姐裸体艺术照 足浴小姐做爱过程 av女教师自慰动态图 AV影音先锋影院 123红色播放 女友自拍偷拍刺激 wwwseebimei 123CTCTCOM 婷婷xx youjuzz小说专区 一级黄色wangzhan 男人体摄影 裸体两性 欧美精品超碰 强奸小村花千骨 幼少女肏屄视频18 五月婷婷婷婷五月丁香 色魔在线 国产父女乱伦小说 KTKX089 www454HUcom 在线手机播放器 偷拍自拍32 成人激情图片,电影mmmnn7777 ww777rvvom WWW9itKcom 美国名模啪啪啪 用力的操狠狠的干 小浪穴妹妹亚洲色图 525zzzcom 乱伦妈妈15p 唐伯虎点秋香不是三级片 最大色牛牛 欧美色kuaibo 手机在线tokyo 欧美幼女网mp4 760yycom 少妇干净迷人鲍优优 绳艺magnet 身穿民族服饰的中国少数民族漂亮美女大胆人体艺术7国内 www47escomxz34 Www2222magnet 色偷怕自拍视频 丁香五月天拍拍播放` 青苹果影院噜噜妈妈 公然妄想露出在线 图片区偷窥自拍亚洲色图欧美色图动漫图片美腿丝袜清纯唯美乱伦图区电 黄色三级片77天天撸 美国女孩成人网站 东京热亚洲色色 超碰av大帝在线视频 西瓜成人资源网 一级片城年5 孝姨大阴唇 pp529com 青青色草在线 504hu迅雷下载 殴州1314 母子乱论视频 微信自拍成人视频在线观看 www44cim 东方av官方 297Pmp4 骚av老师 小明看看成人永久免费视频在钱imgcctuocom 越南人体艺术露鲍 两个女人用道具做爱 影音先锋制服丝袜偷拍 爱搞搞爱撸撸爱色堂 闹洞房就去干 男根的诱惑系列 樱井亚莉偷拍自拍 色dogcom 里中结衣在线观看 特大鸡巴碰上大波霸 躶体狂插相片 熟女撒尿视频 国产成人在线视频网站 武汉18中教师门 刘亦菲阴道毛多吗 操b网址大全 欧美性生活色图 母子尾交 图 操山村老大妈 淫母之穴 00后人体图片少女无毛掰开图片 6655人体艺术果果人体艺术波谷人体艺术 刘嘉大胆人体艺术 欧美色图 成人动漫第一页 淋浴做爱av 骚逼yaoyao 9115视频在线资源sss 黑屌做爱爽片 女优性交免费电影 欧美熟肥女图片 韩国女主播朴妮唛的黄色小说 撸哇哽播 在线自拍干幼女 高清晰自拍偷拍图色色网 去哦v大 欧美父女性爱 淫秽网站肥女视频 666亚洲无码 最新日韩乱伦小说网站 操少妇游戏 日本少妇11p图片 什么片好黄 多人合集9部 河合优衣ed2k 狠狠撸美女手掰穴图片 女儿交换乱轮 欧美妈妈和她的大屌儿子 富婆和年轻帅男性交 夫妻居家性爱自拍 色色偶性爱自拍 强奸模特小说 少年与熟妇爱图 体操美女之性生活 色骚逼在线高清播放 www1314xxx 韩国三级片一对男女在大学教师xxoo后来女的怀孕了男女结婚后女的跑了男的和 夫妻坐爱一级片 成人男女做爱视频 人体艺术图片绘狗网 入江辉美在线电影 鲁av影院 动漫同志片 风间由美爱爱网站 乱伦3p生活 最美妙的骚逼 王梦溪迅雷种子下载 我姐尻屁片 亚洲色图人妻p 日本人体艺术波之轩 偷拍黄色照片 汤加l丽裸照 伦理片日本家庭教师 操逼撸撸撸吧影院 WWW_BB152_COM 保险知识 左边杨丞琳 女人淫乱图 穿挺屄裤子的图片 色色公公与好儿媳 苍井空完全服从 色姐姐乱依 人妻乱伦星野绫香 熟女的角色扮演性爱快播 快播奸少女阴道电影 都市激情撸情 女人小穴很很日 狠狠肏老婆 亚欧人体摄影 中华医药艾叶作用在线视频 美女粉乳头10p 俩根大吊插一个美眉 品色堂俺去也 l少女luluse 模逼图片 山下智久柚木提娜种子ed2k 桃色播播激情五月天 沙绪里与狗 橹二哥影院影视先锋 小说快播综合网 12306影院第一页 巨乳无码xfplay 萩原舞电影 学生逼逼电影 欧美群交欧美色图 操少妇的逼短片 韩国主播吉吉影音 影音先锋厕所偷拍片 欧美熟女系列 鹿鼎淫记 3p性感尤物内射她的小骚穴 国产强奸幼幼逼 屌配屄毛 美女做热爱性交口交 女主人的人体厕所 顶级黄色图片可看到阴道口 无码少妇在线色 美女吹萧爽吗 黄色网站是多少翱 妹妹视 人体模特毛婷人体艺术 佐藤爱理番号 开心宝贝色播网 大屌巨乳系列 重温陈冠希图片做爱 美女豪乳50p 黑网袜性爱 操熟女老师 日韩av逍遥社区 安装香港恋夜场秀 美女制服诱惑男女 亚洲人妻岛国线播放 色小说色图色电影 日韩美女映画网 成人动漫转帖区 www狠狠射c 露脸绝对领域 妻子地铁失身 淫老婆电影第一页 中文字幕都市激情家庭乱伦亚洲色图 日本美女特大胆裸体露逼 口工教师av 色色999偷拍自拍日韩美女 www968ddcnmagnet jjjhhh1com日本 老王社区lw78cc ed2kyounv 美女口交舔逼小说 类似古丽阁网站 帅男同的鸡鸡ed2k 少妇的小骚玩 av黄鳝自慰小说 经点乱系列 百度久久做爱视频 a狼电影网成人 干小嫩b10Pwwwneihan8com 原国产母子做爱乱伦 美国十四拉人体艺术 老公我要插深点快点啊 涩涩乱伦小说 波霸暴露 994yyccm 美国女人和动物zzzwww 后入式微拍 中国国模03150p 色色色乱伦熟女图片 欧美大胆嫩肉穴爽大片 这个经典的给你吧rr123win 老婆乱伦片 另类少妇AV 巨乳俏女医漫画 WWWSWWWMITAOCOM 糖糖激情操逼 男屁眼被曰小说 yinsezonghewang 爆操人妻熟女15P 福利脱衣麻将 久久热偷偷撸黑丝袜免费经典视频 电影三级mp4黄色电影 超级黑人巨屌操白妇 人妻偷拍自拍强奸 男男激情小说肉文 韩日女优大奶视频 杀神有声小说 有声性小说mp3mp3 天春色图片 春色龙 樱井莉亚口才 日本成人 求h网导航 h网游游戏 有没有免费的黄网 设置加www 开心网 五月天 的五月天 qvod东京热图片 东京热n0383.rmvb 皮皮看黄片 沙发看黄片 黄色小说短篇 大色鱼情迷 风月阁论坛 日韩色姐姐 色兔子成人 师傅搞综合 18人体艺术 amod在线 大M成人综合 我爱弟弟影院 给力QVOD色 最纯洁少女做爱 無双帝國谁有E谁有G adultbig影院 日日顺 久久爱 歪歪小说网 九型人格分析 分分操导航 2017 一本道va手机在线 youjizzⅹⅹx 婷影院 一楼一凤影院欧美首页 猫蛋蛋很黄 shenyifuli ssni 049bt下载 另类图片-色爱 汤姆影院atom55 五月丁香深爱基地 皮特成人影院 gay pornhub video chitu x77223 色色ev 客车偷拍图片大全 动漫av ftp 青青草免费线观综合网 兄嫁はいじっぱり认证补丁 人妻少妇视频系列 小林瞳电车痴汉代码 秋霞短片福利 青娱乐视频盛会 日韩成人午夜视屏 影音先锋 熟女系列 在线观看皇片你的懂的 原千岁全集协和影视 日本一级性交视频 日本人性交视频 又黄又色的影剧院 大型AV 好屌色狼 早乙女由依 最佳专辑 尹人影院大香蕉禄现 吉泽明步私处流出资源大 伦理战场 情欲影院云播 bestfornmc0m 搭讪 mgnet 玩农村小姑娘裂缝电子书 日本AⅤ无码在线观看 伦理聚合高请无码在线播放 b里香视频在线2白色爽 有个妮可舍宾怎么找她视频 妇女磁力下载 凹凸視頻免賛在線 caosaobi在线观看免费 东方影库300 wwwxyc123con ipz862在线观看 武则天一级全黄视频 迅雷下载 亚洲在线一区 丰满女人多毛 思思热在线色视频 噜死你们资源站 mum骑兵在线播放 欧美色图狠狠插 邪恶插阴口动态图 风月影院黄视频 黄片VX 厕所偷窥视频 ay电影院 wwwkp99 木村都那厕所无码 good电影神马小丢 黑人和中国人群交视频 色色网址在线 九月婷婷在线 久草在线首页老司机 500dh com福利 杀戮都市里番在线 电影天堂在线福利 淫色视频网 苍木玛娜教师链接 97人妻C○m piczz漫画 橘梨纱作品Bd播放 激情按摩胸部无码 yy6080最稳定的资源 shtv123 日本成人影片 magnet 里番姐弟的关系3 超级碰av公开在线 thzvip 草帽国产综合网 日本色木木 dv1456 老色哥第四色 亚洲av欧美av电影av视频 日日夜夜插天天插 桃花影院今日新鲜事 A片网主名字 大屁股啪啪无码高清视频 东方阿v视频在线最新 xxoo淫交视频 电击女神asia fox在线 东北可爱小骚妻又一次3p娇小身材力战大屌-9 扒开双腿拳交 给我来个娘们操逼的黄片黄片 日本黄色枧频 j鸡巴小視频 叛客与雷鬼高清 迅雷 下载 美女自慰流淫水 在线 人妻小悠福利在线 巨乳王瑞儿在线视频 啪啪肉捧往哪叉?视频 劲暴欧美 一本道 东京热 自拍 国产 无码 黑丝自拍做爱 538prom久久日逼 www骚逼 XXXWWWUUU 求个一本道的资源 杨幂醉酒视完正版视频在线观看 日本女用胸为客人性按摩影院 仲村里绪 影音先锋女主播视频网站 vtt944 国产自拍福利社视频 18v韩国主播 在线翘臀福利 校园多女一男类番号 微福利吃精 香坂里奈 热舞福利120 538porm在线插放视频 wwwtaosetvcom 日本三级天堂网无码 韩国歪歪漫画官网进入 欧美图片亚洲色理论电影 欧美AVmm625 爱色影分类 56popo体验区 www奔驰宝马成人网站 射丝袜足 在线影院 kanmitao1视频 巨乳女教师の诱惑电影 欧洲老女人肏屄 ygyg66怼粉逼 热带夜中文字幕mp4 洁泽明步 m3u8人妻 蛇精脸网红主播小兔兔现场啪啪大秀 mmavtv少妇 萝莉小妹妹av 免费做爱视频网站免费 AISS模特索菲 在线福利视频 多毛龟 66ffff视频 佐伯雪菜在线av先锋 51zhiyuan 播播影院免费A片 av5685 真人下体抽插下阴喷水视频 色喜 王丹 美女动态图张又黄又色 www,O3ⅩXX,Cm 国内在线自拍人人澡人人看 BT 冲田杏梨巨乳女教师の诱惑 神马影院午夜伦dy888mmm 大香蕉亚洲人妻小说 丝袜自慰视频在线观看 涩播音频 popo福利网盘2018 性污秽小视频 想上你日你视频 享悦国产在线 校园禁断介护 校花在浴池被强视频 香港十大禁片黄e 小苹果性交影院 老湿影院未成年人 Xxxxx161116骆驼祥子 熟女papa视频 亚州影院午夜-一 97jibayingyuan 色欲直播 处女中出视频 爱爱福利区 鸡巴操逼的黄片 500夜趣福利免费 亚州香焦视频 porn在线播放制服丝袜 91c仔内裤哥在线观看 wwwz9k6com 偷拍美女浴室伦理电影 4438x3全国最大情人网站 速看网在线观看 新妈妈 ftp 亚洲国际成人综合 4455qu类似的网站 水菜丽无码粪便av连接 wwwabc300wom 唐朝TV360 国产AV,亚洲AV 采桑洗浴中心 波多结野衣与无码观看 比比琼斯作品合集磁力 山谷两日 thunder 日本高清凌辱免费三级片 magnet 欧美虐性 av无码 中文字幕 迅雷 樱井步禁断介护在线 四房色播av 织田真子113在线观看 罗马狼窝影院 插进去拔出来综合网 台湾R级在线 SOD时间禁止器 s跳蛋调教视频 WANQUEYINGYUAN 超级碰夜色猫视频 成人日日夜拍拍 RCTD mp4 v ip eeusssvv 求手机能看哪种视频的网站 欧美激情第一页在线观看 俺去也看免费视频 视频小姐中出 三七影视成人福利播放器 伦理无料 日韩SM高清 赫敏被强奸视频 泄欲哥导航为什么看不了了 1啪啪啪视频app 色无极亚洲影院东京热 黄色福利1000 要要橹福利 乱伦1视频 岛田阳子拍了多少AV片 正在播放肛交视频 萝莉无码小视频 本田英里子MP4迅雷种子 厕所偷拍无修。 北京彪哥真皮大床激战学院派 苍井空在线毛钱 波波兔 磁力 操奶子视频 波多野结衣与狗激情直接视频 久久干视频 ftp 橹先生成人影片 色妻视频观看 暴力插美女屁眼视频 48号缚师绑美女 草榴影院女同 空姐不愿意拍视频被男友强干到高潮的视频 sskanzyz新资源 小岛南无码链接magnet 小草草大黄瓜在线观看 renrencaome 虐阴漫画 国产第一页天天拍 wwwsesw 优酷 解放军在巴黎 18禁自拍偷拍 韩国肛交视频播放 美女做爱磁力连接 捆绑天海翼 5xsq四虎 美国十次啦福利视频 射精丝袜的视频 美女被人舔阴帝视频 乱伦香蕉色视频 色狐免费无码电影 美国成人性爱电影 六月丁香手机在线观看 教练和学生作爱视频 加勒比在线视频网 强奸乱伦1 骑士美女AV视频 去火涩 成人av视 ed2k 婷婷基地色色网 五月婷综合官网 撸必撸 足交鸣人漫画 gvg567 黑丝FJ 菲菲去网站 如果电话亭 avi rhj-073 黄片日屄视频 shiwaizhipaizhao 偷偷撸电影院 手机看片永久免费在线观看国产频道 国产另类自拍亚洲 天堂国产手机a 自拍视频在线观看 teen萝莉 不打码木叶性处理医院 风月海棠空姐 3d hy工房 在线观看 femmina在线观看 陈冠希艳照1300张阿娇 黄色网站在线视频 黄色综合网站 好看的中文字幕色拍拍噜 哦哦弟弟 黄色A片直播 后人动态图 qplayer在线播放网址 www第四色 野战情线国产视频在线观看 偷拍自拍在线赌博 护士无码视频 鬼佬 在线 云播 桃乃木香奈在线三上悠亚在线 ipx247在线观看 天降艳福不是福绝版在线看 一本道0588视频 日本无码光谍区 尻屄AV 老太太h类在线视频 国产3P自拍偷拍 伦理视频黄片大全 91小青蛙红杏出墙3p 内藤幸恵 你懂的 国产在线观啪啪啪网站 国产自拍、欧美 呦呦禁处 福利国产成人强奸少女50集 玉狼影院 国产偷拍自拍中文对白在线 阴道内窥镜凌辱女友 嘿嘿嘿影院永久 可知子 无码 成人在线黄色电影 快播八戒网 我要干色和尚 大胸美女一级黄色毛片 日本绣惑电影 yingyinxianfeng ziyuang 露脸操白妹国语 日本女性爱视频在线观看 成人狂欢福利网 91偷拍视频在线观看 操同事的小女友爱剪辑 粗暴轮奸视频 国产自自拍永久免费 天天干b天天插 国产25P 凹凸视频线观看免费 不雅视频磁力链接下载 香蕉影院超频在线视频 新加坡人美国艳星口交视频 肛塞自慰视频 8338磁力链接 成人色色网美国av幼女 把鸡巴插入妈妈的阴道 24美图野战 我和老师做爱漫画 淫乱肛胶美女 日撸神 清纯漂亮的嫩妹女孩与男友在家激情做爱流出高清视频mp4 阿姨熟女丝袜 黑丝袜电影院 色图网大全 丝袜阿姨的淫荡生活 日本乱伦变态 熟妇性交视频女人色网站 1234qec0m 六年级学生屄 波谷桐原 爆操巨乳妈妈 阿v天堂2012关于苍井空的视频 淫秽的我 官场艳情纪莜竹 少妇性交图25p </font></caption></table> </marquee> </div> </body> </html>