[
  {
    "path": ".gitignore",
    "content": "*.dot\n*.exe\n*.o\n*.out\n*.outb\n*.pdf\n*.swp\n*.test\n.deps\n.config\n.gdb_history\n/build\n/png/*.png\ntags\nunix-tools/sf*\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"unix-tools/coreutils\"]\n\tpath = unix-tools/coreutils\n\turl = https://github.com/mfragkoulis/coreutils\n\tbranch = master\n\tignore=dirty\n[submodule \"unix-tools/grep\"]\n\tpath = unix-tools/grep\n\turl = https://github.com/mfragkoulis/grep\n\tbranch = master\n\tignore=dirty\n[submodule \"unix-tools/bash\"]\n\tpath = unix-tools/bash\n\turl = https://github.com/mfragkoulis/bash.git\n\tbranch = master\n\tignore=dirty\n"
  },
  {
    "path": ".travis/linux-ubuntu-trusty.install.sh",
    "content": "#!/bin/bash\n\nsudo apt-get -qq update\n  # For installation\nsudo apt-get install -y make automake gcc libtool pkg-config texinfo help2man autopoint bison check gperf \n  # For testing\nsudo apt-get install -y wbritish wamerican libfftw3-dev csh\nwget http://ftp.gnu.org/gnu/gettext/gettext-0.19.5.tar.xz\ntar Jxvf gettext-0.19.5.tar.xz\ncd gettext-0.19.5 && ./configure && make && sudo make install\ncd ..\ngit clone --depth=1 -b madagascar-devel-2016 https://github.com/ahay/src.git madagascar\ncd madagascar && rm -rf trip\nsudo ./configure --prefix=/usr/local && sudo make && sudo make install\ncd ..\nmkdir nmrpipe && cd nmrpipe\nwget https://www.ibbr.umd.edu/nmrpipe/install.com\nwget https://www.ibbr.umd.edu/nmrpipe/binval.com\nwget https://www.ibbr.umd.edu/nmrpipe/NMRPipeX.tZ\nwget https://www.ibbr.umd.edu/nmrpipe/s.tZ\nwget https://www.ibbr.umd.edu/nmrpipe/dyn.tZ\nwget https://www.ibbr.umd.edu/nmrpipe/talos.tZ\nwget http://spin.niddk.nih.gov/bax/software/smile/plugin.smile.tZ\nchmod a+rx *.com && ./install.com\nsudo install nmrbin.linux212_64/var2pipe nmrbin.linux212_64/nmrPipe /usr/local/bin\nsudo install nmrbin.linux212_64/addNMR /usr/bin\ncd ..\nmake config && make\n"
  },
  {
    "path": ".travis/macosx-xcode8.3.install.sh",
    "content": "#!/bin/bash\n\nset -x\n\nbrew update\nbrew install autoconf check xz texinfo help2man gettext libelf\nexport PATH=\"/usr/local/opt/texinfo/bin:$PATH\"\nbrew link gettext --force\n#wget http://ftp.gnu.org/gnu/gettext/gettext-0.19.5.tar.xz\n#tar Jxvf gettext-0.19.5.tar.xz >/dev/null\n#cd gettext-0.19.5 && ./configure && make && sudo make install >/dev/null\n#cd ..\n#git clone --depth=1 -b madagascar-devel-2016 https://github.com/ahay/src.git madagascar\n#cd madagascar && rm -rf trip\n#sudo ./configure --prefix=/usr/local && sudo make && sudo make install\n#cd ..\n#mkdir nmrpipe && cd nmrpipe\n#wget https://www.ibbr.umd.edu/nmrpipe/install.com\n#wget https://www.ibbr.umd.edu/nmrpipe/binval.com\n#wget https://www.ibbr.umd.edu/nmrpipe/NMRPipeX.tZ\n#wget https://www.ibbr.umd.edu/nmrpipe/s.tZ\n#wget https://www.ibbr.umd.edu/nmrpipe/dyn.tZ\n#wget https://www.ibbr.umd.edu/nmrpipe/talos.tZ\n#wget http://spin.niddk.nih.gov/bax/software/smile/plugin.smile.tZ\n#chmod a+rx *.com && ./install.com >/dev/null\n#sudo install nmrbin.linux212_64/var2pipe nmrbin.linux212_64/nmrPipe /usr/local/bin >/dev/null\n#sudo install nmrbin.linux212_64/addNMR /usr/bin >/dev/null\n#cd ..\nmake config && make\n"
  },
  {
    "path": ".travis.yml",
    "content": "matrix:\n        include:\n                - os: linux\n                  dist: trusty\n                  install:\n                          - ./.travis/linux-ubuntu-trusty.install.sh\n                - os: osx\n                  osx_image: xcode8.3\n                  install:\n                          - ./.travis/macosx-xcode8.3.install.sh\nlanguage: C\ncompiler: gcc\n\nscript: make test && sudo make install\n"
  },
  {
    "path": "CITATION.cff",
    "content": "cff-version: 1.2.0\r\ntitle: dgsh: The Directed Graph Shell\r\nmessage: >-\r\n  If you use this software, please cite, using the metadata from this file,\r\n  both the article from preferred-citation and the software itself.\r\npreferred-citation:\r\n  date-released: \"2017-09-01\"\r\n  doi: \"10.1109/TC.2017.2695447\"\r\n  title: \"Extending Unix Pipelines to DAGs\"\r\n  authors:\r\n    - family-names: \"Spinellis\"\r\n      given-names: \"Diomidis\"\r\n    - family-names: \"Fragkoulis\"\r\n      given-names: \"Marios\"\r\n  type: \"article\"\r\n  volume: 66\r\n  issue: 9\r\n  journal: \"IEEE Transactions on Computers\"\r\n  start: 1547\r\n  end: 1561\r\ntype: software\r\nauthors:\r\n  - given-names: Diomidis\r\n    family-names: Spinellis\r\n    email: dds@aueb.gr\r\n    affiliation: Athens University of Economics and Business\r\n    orcid: 'https://orcid.org/0000-0003-4231-1897'\r\n  - given-names: \"Marios\"\r\n    family-names: \"Fragkoulis\"\r\nrepository-code: 'https://github.com/dspinellis/dgsh'\r\nkeywords:\r\n  - Unix\r\n  - shell\r\n  - dataflow programming\r\nlicense: Apache-2.0\r\n"
  },
  {
    "path": "LICENSE",
    "content": "   Copyright 2012-2013 Diomidis Spinellis\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n------------------------------------------------------------------------\n\njquery.js is licensed as follows.\n\nCopyright 2013 jQuery Foundation and other contributors\nhttp://jquery.com/\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n------------------------------------------------------------------------\n\ndgsh-httpval is based on micro_httpd, which is licensed as follows.\n\nmicro_httpd:\nCopyright (c) 1999,2005 by Jef Poskanzer <jef@mail.acme.com>.\nAll rights reserved.\n\nDgsh modifications:\nCopyright 2013 Diomidis Spinellis\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n"
  },
  {
    "path": "Makefile",
    "content": "#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n-include .config\nexport PREFIX?=/usr/local\n\nifdef DEBUG\nCPPFLAGS=-DDEBUG\nCXXFLAGS=-g -Wall -O0\nelse\nCXXFLAGS=-O -Wall\nendif\n\nifdef TIME\nCFLAGS+=-DTIME\nendif\n\nDOTFLAGS=-Nfontname=Arial -Ngradientangle=90 -Nstyle=filled -Nshape=ellipse -Nfillcolor=yellow:white\n\n# Manual pages\nMAN1SRC=$(wildcard core-tools/src/*.1)\nMANPDF=$(patsubst %.1,%.pdf,$(MAN1SRC)) core-tools/src/dgsh_negotiate.pdf\nMANHTML=$(patsubst %.1,%.html,$(MAN1SRC)) core-tools/src/dgsh_negotiate.html\n\n# Web files\nEXAMPLES=$(patsubst example/%,%,$(wildcard example/*.sh))\nEGPNG=$(patsubst %.sh,png/%-pretty.png,$(EXAMPLES))\nEGDOT=$(patsubst %.sh,graphdot/%.dot,$(EXAMPLES))\nWEBPNG=$(EGPNG)\nWEBDIST=../../../pubs/web/home/sw/dgsh/\n\npng/%-pretty.png: graphdot/%.dot\n\tgvpr 'BEG_G { graph_t L = cloneG($$G,\"last\")} END {write(L)}' $< | \\\n\tdot $(DOTFLAGS) -Tpng >$@\n\n%.pdf: %.1\n\tgroff -man -Tps $< | ps2pdf - $@\n\n%.pdf: %.3\n\tgroff -man -Tps $< | ps2pdf - $@\n\n%.html: %.1\n\tgroff -man -Thtml $< >$@\n\n%.html: %.3\n\tgroff -man -Thtml $< >$@\n\ngraphdot/%.dot: example/%.sh\n\tmkdir -p graphdot\n\trm -f graphdot/$*.dot\n\tDGSH_DRAW_EXIT=1 DGSH_DOT_DRAW=graphdot/$* ./unix-tools/bash/bash --dgsh $<\n\n.PHONY: all tools core-tools unix-tools export-prefix \\\n\tconfig config-core-tools \\\n\ttest test-dgsh test-merge-sum test-tee test-negotiate \\\n\ttest-unix-tools test-wrap test-kvstore \\\n\tclean install webfiles dist pull commit uninstall dotfiles\n\nall: tools\n\ntools: core-tools unix-tools\n\ncore-tools:\n\t$(MAKE) -C core-tools CFLAGS=\"$(CFLAGS)\"\n\tcd core-tools/src && $(MAKE) build-install\n\nunix-tools: core-tools\n\t$(MAKE) -C unix-tools make MAKEFLAGS=\n\t$(MAKE) -C unix-tools build-install\n\nexport-prefix:\n\techo \"export PREFIX?=$(PREFIX)\" >.config\n\nconfig: export-prefix config-core-tools\n\t$(MAKE) -C unix-tools configure\n\nconfig-core-tools: core-tools/configure.ac core-tools/Makefile.am core-tools/src/Makefile.am core-tools/tests/Makefile.am\n\t-mkdir core-tools/m4\n\tcd core-tools && \\\n\tautoreconf --install && \\\n\t./configure --prefix=$(PREFIX) \\\n\t--bindir=$(PREFIX)/bin && \\\n\tcd tests && \\\n\tpatch Makefile <Makefile.patch\n\ntest: test-negotiate test-tee test-kvstore test-unix-tools test-merge-sum test-wrap test-dgsh\n\ntest-dgsh: tools\n\tcd core-tools/tests-regression && ./test-dgsh.sh\n\ntest-wrap: tools\n\tcd core-tools/tests-regression && ./test-wrap.sh\n\ntest-merge-sum:\n\tcd core-tools/tests-regression && ./test-merge-sum.sh\n\ntest-tee: tools\n\tcd core-tools/tests-regression && ./test-tee.sh\n\ntest-negotiate: tools\n\tcd core-tools/tests && \\\n\t$(MAKE) && \\\n\t$(MAKE) check\n\ntest-unix-tools: tools\n\t$(MAKE) -C unix-tools -s test\n\ntest-kvstore: core-tools\n\tcd core-tools/tests-regression && ./test-kvstore.sh\n\nclean:\n\trm -rf build $(MANPDF) $(MANHTML) $(EGPNG)\n\t$(MAKE) -C core-tools clean\n\t$(MAKE) -C unix-tools clean\n\ninstall:\n\t-rm -r build\n\t$(MAKE) -C core-tools install\n\t$(MAKE) -C unix-tools install\n\nwebfiles: $(MANPDF) $(MANHTML) $(WEBPNG)\n\n# Create web page\ndist: $(MANPDF) $(MANHTML) $(WEBPNG)\n\tperl -n -e 'if (/^<!-- #!(.*) -->/) { system(\"$$1\"); } else { print; }' web/index.html >$(WEBDIST)/index.html\n\tcp $(MANHTML) $(MANPDF) $(WEBDIST)\n\tcp $(WEBPNG) $(WEBDIST)\n\n# Obtain dot files from Unix host\nrsync-graphdot:\n\tssh stereo 'cd src/dgsh && git pull && make webfiles'\n\trsync -a stereo:src/dgsh/graphdot/ graphdot/\n\trsync -a stereo:src/dgsh/example/ example/\n\ndotfiles: $(EGDOT)\n\npull:\n\tgit pull\n\t# Pull master on all sub-repositories.\n\t# Note that the gnulib ones get detached by by builds specifying\n\t# a specific gnulib version.  Through this pull repos on master\n\t# stay on master; detached repos (gnulib) stay in the version they\n\t# were detached.\n\tgit submodule status --recursive | awk '{print $$2}' | sort -r | while read d ; do ( echo \"Pulling $$d\" && cd $$d && old=$$(if [ $$(git rev-parse master) = $$(git rev-parse HEAD) ] ; then echo master ; else git rev-parse HEAD ; fi)  && git checkout master && git pull && git checkout -q $$old ) ; done\n\npush:\n\tgit push --recurse-submodules=on-demand\n\ncommit:\n\t# Commit -a including submodules\n\tprintf '\\n\\n# Please enter the commit message for your changes.\\n#\\n' >.git/COMMIT_EDITMSG\n\tgit status --ignore-submodules=untracked | sed '/./s/^/# /;s/^$$/#/' >>.git/COMMIT_EDITMSG\n\t$${VISUAL-vi} .git/COMMIT_EDITMSG\n\tfor i in $$(echo unix-tools/*/.git | sed 's/\\.git//g') . ; do grep -v '^#' .git/COMMIT_EDITMSG | (cd $$i && git commit -a -F -) ; done\n\trm -f .git/COMMIT_EDITMSG\n\nzip:\n\tcd .. && zip -r dgsh.zip dgsh -x *.git*\n\n# Rough uninstall rule to verify that tests pick up correct files\nuninstall:\n\trm -rf $(PREFIX)/bin/dgsh-* $(PREFIX)/libexec/dgsh \\\n\t\t$(PREFIX)/lib/libdgsh.a\n"
  },
  {
    "path": "README.md",
    "content": "## dgsh: The Directed Graph Shell\n\n[![Build Status](https://travis-ci.org/dspinellis/dgsh.svg?branch=master)](https://travis-ci.org/dspinellis/dgsh)\n\nThe directed graph shell, *dgsh*, allows the expressive expression of efficient big data set and streams processing pipelines using existing Unix tools as well as custom-built components. It is a Unix-style shell allowing the specification of pipelines with non-linear scatter-gather operations. These form a directed acyclic process graph, which is typically executed by multiple processor cores, thus increasing the operation's processing throughput.\n\nYou can find a complete introduction, reference documentation,\nand illustrated examples in the suite's\n[web site](http://www.spinellis.gr/sw/dgsh/).\n\nSee also,\na [quick video overview](https://youtu.be/crqzO4YanwA) and\nthe associated (open access) paper,\n[Extending Unix pipelines to DAGs](http://dx.doi.org/10.1109/TC.2017.2695447),\npublished in the *IEEE Transactions on Computers*, 66(9):1547–1561, 2017.\n"
  },
  {
    "path": "core-tools/.gitignore",
    "content": "Makefile\nMakefile.in\naclocal.m4\nautom4te.cache/\nbuild-aux/\nconfig.h\nconfig.h.in\nconfig.log\nconfig.status\nconfigure\nlibtool\nm4/\nstamp-h1\n"
  },
  {
    "path": "core-tools/Makefile.am",
    "content": "## Process this file with automake to produce Makefile.in\nACLOCAL_AMFLAGS = -I m4\nSUBDIRS = src . tests\n"
  },
  {
    "path": "core-tools/configure.ac",
    "content": "# Process this file with autoconf to produce a configure script.\n\n# Prelude.\nAC_PREREQ([2.59])\nAC_INIT([DGSH Negotiate], [1.0], [check-devel AT lists.sourceforge.net])\n\n# unique source file --- primitive safety check \nAC_CONFIG_SRCDIR([src/negotiate.c])\n\nAC_CONFIG_MACRO_DIR([m4])\n\n# place to put some extra build scripts installed\nAC_CONFIG_AUX_DIR([build-aux])\n\n# fairly severe build strictness\n# change foreign to gnu or gnits to comply with gnu standards\nAM_INIT_AUTOMAKE([-Wall -Werror subdir-objects foreign 1.9.6])\n\n# Checks for programs.\nAM_PROG_AR\nAM_PROG_AS\nAC_PROG_CC\nAC_PROG_LIBTOOL\n\n# Checks for libraries.\n\n# This macro is defined in check.m4 and tests if check.h and\n# libcheck.a are installed in your system. It sets CHECK_CFLAGS and\n# CHECK_LIBS accordingly.  \n#  AM_PATH_CHECK([MINIMUM-VERSION,\n#                [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])\nPKG_CHECK_MODULES([CHECK], [check >= 0.9.4])\n\n# Checks for header files.\nAC_HEADER_STDC\nAC_CHECK_HEADERS([stdlib.h])\n\n# Checks for typedefs, structures, and compiler characteristics.\n\n# Checks for library functions.\nAC_FUNC_MALLOC\nAC_CHECK_FUNCS(cpow)\n\n# Output files\nAC_CONFIG_HEADERS([config.h])\n\nAC_CONFIG_FILES([Makefile\n                 src/Makefile\n                 tests/Makefile])\n\nAM_CONDITIONAL([LINUX], [test $(uname) = \"Linux\"])\nAM_CONDITIONAL([DARWIN], [test $(uname) = \"Darwin\"])\n\nAC_OUTPUT\n\n"
  },
  {
    "path": "core-tools/src/.gitignore",
    "content": "dgsh-conc\ndgsh-conc.html\ndgsh-enumerate\ndgsh-enumerate.html\ndgsh-fft-input\ndgsh.html\ndgsh-httpval\ndgsh-httpval.html\ndgsh-merge-sum\ndgsh-merge-sum.html\ndgsh-monitor\ndgsh-monitor.html\ndgsh_negotiate.html\ndgsh-parallel\ndgsh-parallel.html\ndgsh-pecho\ndgsh-ps\ndgsh-readval\ndgsh-readval.html\ndgsh-tee\ndgsh-tee.html\ndgsh-w\ndgsh-wrap\ndgsh-wrap.html\ndgsh-writeval\ndgsh-writeval.html\nlibdgsh.a\nnegotiate\nperm\nperm.html\n"
  },
  {
    "path": "core-tools/src/Makefile.am",
    "content": "include ../../.config\n\nif LINUX\nDGSH_ASSEMBLY_FILE=dgsh-elf.s\nelse\nif DARWIN\nDGSH_ASSEMBLY_FILE=dgsh-macho.s\nendif\nendif\n\nlib_LIBRARIES = libdgsh.a\nlibdgsh_a_SOURCES = negotiate.c $(DGSH_ASSEMBLY_FILE)\n\ninclude_HEADERS = dgsh.h\n\nbin_PROGRAMS = dgsh-monitor dgsh-httpval dgsh-readval\nbin_SCRIPTS = dgsh-merge-sum\n\nman1_MANS = dgsh.1 dgsh-conc.1 dgsh-enumerate.1 dgsh-httpval.1 \\\n\t    dgsh-merge-sum.1 dgsh-monitor.1 \\\n\t    dgsh-parallel.1 dgsh-readval.1 dgsh-tee.1 dgsh-wrap.1 \\\n\t    dgsh-writeval.1 perm.1\n\nman3_MANS = dgsh_negotiate.3\n\nlibexec_PROGRAMS = dgsh-tee dgsh-writeval dgsh-readval dgsh-monitor \\\n\t\t dgsh-conc dgsh-wrap dgsh-enumerate dgsh-pecho \\\n\t\t dgsh-fft-input dgsh-w\nlibexec_SCRIPTS = dgsh-parallel perm\nlibexecdir = $(prefix)/libexec/dgsh\n\ndgsh_monitor_SOURCES = dgsh-monitor.c\ndgsh_httpval_SOURCES = dgsh-httpval.c kvstore.c\ndgsh_readval_SOURCES = dgsh-readval.c kvstore.c\ndgsh_tee_SOURCES = dgsh-tee.c\ndgsh_writeval_SOURCES = dgsh-writeval.c\ndgsh_conc_SOURCES = dgsh-conc.c\ndgsh_wrap_SOURCES = dgsh-wrap.c\ndgsh_enumerate_SOURCES = dgsh-enumerate.c\ndgsh_pecho_SOURCES = dgsh-pecho.c\ndgsh_fft_input_SOURCES = dgsh-fft-input.c\ndgsh_w_SOURCES = dgsh-w.c $(CPOW)\n\ndgsh_readval_LDADD = libdgsh.a\ndgsh_writeval_LDADD = libdgsh.a\ndgsh_conc_LDADD = libdgsh.a\ndgsh_wrap_LDADD = libdgsh.a\ndgsh_tee_LDADD = libdgsh.a\ndgsh_enumerate_LDADD = libdgsh.a\ndgsh_pecho_LDADD = libdgsh.a\ndgsh_fft_input_LDADD = libdgsh.a\ndgsh_w_LDADD = libdgsh.a -lm\n\ndgsh-parallel: dgsh-parallel.sh\n\tinstall $? $@\n\nperm: perm.sh\n\tinstall $? $@\n\ndgsh-merge-sum: dgsh-merge-sum.pl\n\tinstall $? $@\n\nclean-local:\n\t-rm -rf dgsh-parallel perm degsh-merge-sum\n\nbuild-install:\n\tmkdir -p ../../build/bin ../../build/libexec/dgsh\n\tcp $(bin_PROGRAMS) $(bin_SCRIPTS) ../../build/bin/\n\tcp $(libexec_PROGRAMS) $(libexec_SCRIPTS) ../../build/libexec/dgsh/\n"
  },
  {
    "path": "core-tools/src/debug.h",
    "content": "/*\n * Copyright 2013-2017 Diomidis Spinellis\n *\n * Debug macros\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#ifndef DEBUG_H\n#define DEBUG_H\n\n\n#ifdef DEBUG\n/* ## is a gcc extension that removes trailing comma if no args */\n#define DPRINTF(fmt, ...) fprintf(stderr, \"%d: \" fmt \" \\n\", (int)getpid(), ##__VA_ARGS__)\n#else\n#define DPRINTF(fmt, ...)\n#endif\n\n#endif /* DEBUG_H */\n"
  },
  {
    "path": "core-tools/src/dgsh-conc.1",
    "content": ".TH DGSH-HTTPVAL 1 \"14 July 2016\"\n.\\\"\n.\\\" (C) Copyright 2016 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-conc \\- input or output pipe concentrator for dgsh negotiation\n.SH SYNOPSIS\n\\fBdgsh-conc\\fP \\fB\\-i\\fP | \\fB-o\\fP \\fInprog\\fP\n.SH DESCRIPTION\n\\fIdgsh-conc\\fP is a helper program used in the \\fIdgsh\\fP negotiation\nphase.\nIt is used to allow multiple output processes to negotiate with\na single input process, or to allow a single output process to\nnegotiate with multple input ones.\nOnce the negotiation is complete, it passes around the generated\npipe file descriptor and exits.\nThe two obligatory arguments specify whether the command will\nact as an input or output concentrator, and the number of\ninput or output programs to concentrate.\n\n.SH OPTIONS\n.IP \"\\fB\\-i\\fP\nAct as an input concentrator by concentrating multiple inputs to single output.\n.IP \"\\fB\\-o\\fP\nAct as an output concentrator by concentrating multiple outputs to\na single input.\n\n.SH \"SEE ALSO\"\n\\fIdgsh\\fP(1),\n\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>.\n"
  },
  {
    "path": "core-tools/src/dgsh-conc.c",
    "content": "/*\n * Copyright 2016, 2017 Diomidis Spinellis\n *\n * A passive component that aids the dgsh negotiation by passing\n * message blocks among participating processes.\n * When the negotiation is finished and the processes get connected by\n * pipes, it exits.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <err.h>\n#include <errno.h>\n#include <limits.h>\n#include <string.h>\n#include <unistd.h>\t\t/* getpid(), alarm() */\n#include <sys/select.h>\n#include <signal.h>\t\t/* sig_atomic_t */\n\n#include \"negotiate.h\"\t\t/* read/write_message_block(),\n\t\t\t\t   set_negotiation_complete() */\n#include \"dgsh-debug.h\"\t\t/* DPRINTF */\n\n#define DGSH_TIMEOUT 5\n\n/* Alarm mechanism and on_exit handling */\nextern volatile sig_atomic_t negotiation_completed;\n\n#ifdef TIME\n#include <time.h>\nstatic struct timespec tstart={0,0}, tend={0,0};\n#endif\n\nstatic const char *program_name;\nstatic pid_t pid;\n\nstatic void\nusage(void)\n{\n\tfprintf(stderr, \"Usage: %s -i|-o [-n] nprog\\n\"\n\t\t\"-i\"\t\t\"\\tInput concentrator: multiple inputs to single output\\n\"\n\t\t\"-o\"\t\t\"\\tOutput concentrator: single input to multiple outputs\\n\"\n\t\t\"-n\"\t\t\"\\tDo not consider standard input (used with -o)\\n\",\n\t\tprogram_name);\n\texit(1);\n}\n\n/*\n * Information for each I/O file descriptor on which\n * the concentrator operates.\n */\nstatic struct portinfo {\n\tpid_t pid;\t\t// The id of the process talking to this port\n\tbool seen;\t\t// True when the pid was seen\n\tbool written;\t\t// True when we wrote to pid\n\tbool run_ready;\t\t// True when the associated process can run\n\tstruct dgsh_negotiation *to_write; // Block pending a write\n} *pi;\n\n/*\n * True when we're concentrating inputs, i.e. gathering 0, 3, 4, ... to 1\n * Otherwise we scatter 0 to 1, 3, 4 ...\n */\nSTATIC bool multiple_inputs;\n\n/* True when input concentrator is the gather endpoint\n * of a scatter-first-gather-then block.\n * In this case using the default route of the input\n * concentrator results in complex cycles and ruins\n * the algorithms that decide when negotiation should\n * end both for concentrators and participating processes.\n * The favored scheme in this case is:\n * stdin -> stdout\n * stdout -> stdin\n * fd -> fd\n */\n//STATIC bool pass_origin;\nSTATIC bool noinput;\n\n/*\n * Total number of file descriptors on which the process performs I/O\n * (including stderr).  The last fd used in nfd - 1.\n */\nSTATIC int nfd;\n\n#define FREE_FILENO (STDERR_FILENO + 1)\n\n/**\n * Return the next fd where a read block should be passed\n * Return whether we should restore the origin of the block\n */\nSTATIC int\nnext_fd(int fd, bool *ro)\n{\n\tif (multiple_inputs)\n\t\tswitch (fd) {\n\t\tcase STDIN_FILENO:\n\t\t\treturn STDOUT_FILENO;\n\t\tcase STDOUT_FILENO:\n\t\t\treturn STDIN_FILENO;\n\t\tdefault:\n\t\t\t*ro = true;\n\t\t\treturn fd;\n\t\t}\n\telse\n\t\tswitch (fd) {\n\t\tcase STDIN_FILENO:\n\t\t\tif (!noinput)\n\t\t\t\treturn STDOUT_FILENO;\n\t\tcase STDOUT_FILENO:\n\t\t\tif (nfd > 2) {\t// if ==2, treat in default case\n\t\t\t\tif (!noinput)\n\t\t\t\t\t*ro = true;\n\t\t\t\treturn FREE_FILENO;\n\t\t\t}\n\t\tdefault:\n\t\t\tif (fd == nfd - 1)\n\t\t\t\tif (!noinput)\n\t\t\t\t\treturn STDIN_FILENO;\n\t\t\t\telse\n\t\t\t\t\treturn STDOUT_FILENO;\n\t\t\telse {\n\t\t\t\tif (!noinput)\n\t\t\t\t\t*ro = true;\n\t\t\t\treturn fd + 1;\n\t\t\t}\n\t\t}\n}\n\n/**\n * Return whether the process at port i\n * is ready to run.\n * Check whether this is the process whose\n * pid is set and prepare for exit.\n */\nSTATIC bool\nis_ready(int i, struct dgsh_negotiation *mb)\n{\n\tbool ready = false;\n\tif (pi[i].seen && pi[i].written)\n\t\tready = true;\n\tDPRINTF(4, \"pi[%d].pid: %d %s?: %d\\n\",\n\t\t\ti, pi[i].pid, __func__, ready);\n\treturn ready;\n}\n\n/**\n * Register current concentrator to message block's\n * concentrator array\n */\nSTATIC int\nset_io_channels(struct dgsh_negotiation *mb)\n{\n\tif (find_conc(mb, pid))\n\t\treturn 0;\n\n\tstruct dgsh_conc c;\n\tc.pid = pid;\n\tc.input_fds = -1;\n\tc.output_fds = -1;\n\tc.n_proc_pids = (nfd > 2 ? nfd - 2 : 1);\n\tc.multiple_inputs = multiple_inputs;\n\tc.proc_pids = (int *)malloc(sizeof(int) * c.n_proc_pids);\n\tint j = 0, i;\n\n\tDPRINTF(4, \"%s: n_proc_pids: %d\", __func__, c.n_proc_pids);\n\tif (multiple_inputs) {\n\t\tc.endpoint_pid = pi[STDOUT_FILENO].pid;\n\t\tif (c.endpoint_pid == 0)\n\t\t\treturn 1;\n\t\tfor (i = STDIN_FILENO; i < nfd; i == STDIN_FILENO ? i = FREE_FILENO : i++)\n\t\t\tif (pi[i].pid == 0) {\n\t\t\t\tfree(c.proc_pids);\n\t\t\t\treturn 1;\n\t\t\t} else\n\t\t\t\tc.proc_pids[j++] = pi[i].pid;\n\t} else {\n\t\tbool ignore;\n\t\tc.endpoint_pid = pi[STDIN_FILENO].pid;\n\t\tif (c.endpoint_pid == 0)\n\t\t\treturn 1;\n\t\tfor (i = STDOUT_FILENO; i != STDIN_FILENO; i = next_fd(i, &ignore))\n\t\t\tif (pi[i].pid == 0) {\n\t\t\t\tfree(c.proc_pids);\n\t\t\t\treturn 1;\n\t\t\t} else\n\t\t\t\tc.proc_pids[j++] = pi[i].pid;\n\t}\n\n\tif (!mb->conc_array) {\n\t\tmb->conc_array = (struct dgsh_conc *)malloc(sizeof(struct dgsh_conc));\n\t\tmb->n_concs = 1;\n\t} else {\n\t\tmb->n_concs++;\n\t\tmb->conc_array = (struct dgsh_conc *)realloc(mb->conc_array,\n\t\t\t\t\tsizeof(struct dgsh_conc) * mb->n_concs);\n\t}\n\tmemcpy(&mb->conc_array[mb->n_concs - 1], &c, sizeof(struct dgsh_conc));\n\n\tDPRINTF(4, \"%s(): Added conc with pid: %d, now n_concs: %d\",\n\t\t\t__func__, mb->conc_array[mb->n_concs - 1].pid, mb->n_concs);\n\n\treturn 0;\n}\n\nSTATIC void\nprint_state(int i, int var, int pcase)\n{\n\tswitch (pcase) {\n\t\tcase 1:\n\t\t\tDPRINTF(4, \"%s(): pi[%d].pid: %d\",\n\t\t\t\t\t__func__, i, (int)pi[i].pid);\n\t\t\tDPRINTF(4, \"  initiator pid: %d\",\n\t\t\t\t\tvar);\n\t\t\tDPRINTF(4, \"  pi[%d].seen: %d\",\n\t\t\t\t\ti, pi[i].seen);\n\t\t\tDPRINTF(4, \"  write: %d\", pi[i].written);\n\t\tcase 2:\n\t\t\tDPRINTF(4, \"%s(): pi[%d].pid: %d\",\n\t\t\t\t\t__func__, i, pi[i].pid);\n\t\t\tDPRINTF(4, \"  run ready?: %d, seen times: %d\",\n\t\t\t\t\t(int)pi[i].run_ready, pi[i].seen);\n\t\t\tDPRINTF(4, \"  written: %d, nfds: %d\",\n\t\t\t\t\tpi[i].written, var);\n\t}\n}\n\n#define max(a, b) ((a) > (b) ? (a) : (b))\n\n/*\n * Pass around the message blocks so that they reach all processes\n * connected through the concentrator.\n */\nSTATIC int\npass_message_blocks(void)\n{\n\tfd_set readfds, writefds;\n\tint nfds = 0;\n\tint i;\n\tint oi = -1;\t\t/* scatter/gather block's origin index */\n\tint ofd = -1;\t\t/* ... origin fd direction */\n\tbool ro = false;\t/* Whether the read block's origin should\n\t\t\t\t * be restored\n\t\t\t\t */\n\tbool iswrite = false;\n\n\tif (noinput) {\n#ifdef TIME\n\t\tclock_gettime(CLOCK_MONOTONIC, &tstart);\n#endif\n\t\tconstruct_message_block(\"dgsh-conc\", pid);\n\t\tchosen_mb->origin_fd_direction = STDOUT_FILENO;\n\t\tchosen_mb->is_origin_conc = true;\n\t\tchosen_mb->conc_pid = pid;\n\t\tpi[STDOUT_FILENO].to_write = chosen_mb;\n\t}\n\n\tfor (;;) {\n\t\t// Create select(2) masks\n\t\tFD_ZERO(&readfds);\n\t\tFD_ZERO(&writefds);\n\t\tfor (i = 0; i < nfd; i++) {\n\t\t\tif (noinput && i == STDIN_FILENO)\n\t\t\t\tcontinue;\n\t\t\tif (i == STDERR_FILENO)\n\t\t\t\tcontinue;\n\t\t\tif (!pi[i].seen) {\n\t\t\t\tFD_SET(i, &readfds);\n\t\t\t\tnfds = max(i + 1, nfds);\n\t\t\t}\n\t\t\tif (pi[i].to_write && !pi[i].written) {\n\t\t\t\tFD_SET(i, &writefds);\n\t\t\t\tnfds = max(i + 1, nfds);\n\t\t\t\tpi[i].to_write->is_origin_conc = true;\n\t\t\t\tpi[i].to_write->conc_pid = pid;\n\t\t\t\tDPRINTF(4, \"Actual origin: conc with pid %d\", pid);\n\t\t\t}\n\t\t}\n\n\tagain:\n\t\tif (select(nfds, &readfds, &writefds, NULL, NULL) < 0) {\n\t\t\tif (errno == EINTR)\n\t\t\t\tgoto again;\n\t\t\t/* All other cases are internal errors. */\n\t\t\terr(1, \"select\");\n\t\t}\n\n\t\t// Read/write what we can\n\t\tfor (i = 0; i < nfd; i++) {\n\t\t\tif (FD_ISSET(i, &writefds)) {\n\t\t\t\tiswrite = true;\n\t\t\t\tassert(pi[i].to_write);\n\t\t\t\tchosen_mb = pi[i].to_write;\n\t\t\t\tDPRINTF(4, \"**fd i: %d set for writing to tool with pid %d\", i, pi[i].pid);\n\t\t\t\twrite_message_block(i); // XXX check return\n\n\t\t\t\tif (pi[i].to_write->state == PS_RUN ||\n\t\t\t\t\tpi[i].to_write->state == PS_DRAW_EXIT ||\n\t\t\t\t\t(pi[i].to_write->state == PS_ERROR &&\n\t\t\t\t\t\tpi[i].to_write->is_error_confirmed))\n\t\t\t\t\tpi[i].written = true;\n\n\t\t\t\t// Write side exit\n\t\t\t\tif (is_ready(i, pi[i].to_write)) {\n\t\t\t\t\tpi[i].run_ready = true;\n\t\t\t\t\tDPRINTF(4, \"**%s(): pi[%d] is run ready\",\n\t\t\t\t\t\t\t__func__, i);\n\t\t\t\t}\n\t\t\t\tpi[i].to_write = NULL;\n\t\t\t}\n\t\t\tif (FD_ISSET(i, &readfds)) {\n\t\t\t\tstruct dgsh_negotiation *rb;\n\t\t\t\tro = false;\n\t\t\t\tint next = next_fd(i, &ro);\n\n\t\t\t\tassert(!pi[i].run_ready);\n\t\t\t\tassert(pi[next].to_write == NULL);\n\t\t\t\tif (read_message_block(i, &pi[next].to_write) ==\n\t\t\t\t\t\t\t\tOP_ERROR) {\n\t\t\t\t\tchosen_mb->state = PS_ERROR;\n\t\t\t\t\tif (noinput)\n\t\t\t\t\t\tchosen_mb->is_error_confirmed = true;\n\t\t\t\t\tpi[next].to_write = chosen_mb;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\trb = pi[next].to_write;\n\n\t\t\t\tDPRINTF(4, \"%s(): next write via fd %d to pid %d\",\n\t\t\t\t\t\t__func__, next, pi[next].pid);\n\n\t\t\t\tif (oi == -1) {\n\t\t\t\t\tif ((multiple_inputs && i == 1) ||\n\t\t\t\t\t\t\t(!multiple_inputs &&\n\t\t\t\t\t\t\t i == 0)) {\n\t\t\t\t\t\toi = rb->origin_index;\n\t\t\t\t\t\tofd = rb->origin_fd_direction;\n\t\t\t\t\t\tDPRINTF(4, \"**Store origin: %d, fd: %s\",\n\t\t\t\t\t\t\toi, ofd ? \"stdout\" : \"stdin\");\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* If conc talks to conc, set conc's pid\n\t\t\t\t * Required in order to allocate fds correctly\n\t\t\t\t * in the end\n\t\t\t\t */\n\t\t\t\tif (rb->is_origin_conc)\n\t\t\t\t\tpi[i].pid = rb->conc_pid;\n\t\t\t\telse\n\t\t\t\t\tpi[i].pid = get_origin_pid(rb);\n\n\t\t\t\t/* If needed, re-set origin.\n\t\t\t\t * Don't move this block before get_origin_pid()\n\t\t\t\t */\n\t\t\t\tif (ro) {\n\t\t\t\t\tDPRINTF(4, \"**Restore origin: %d, fd: %s\",\n\t\t\t\t\t\t\toi, ofd ? \"stdout\" : \"stdin\");\n\t\t\t\t\tpi[next].to_write->origin_index = oi;\n\t\t\t\t\tpi[next].to_write->origin_fd_direction = ofd;\n\t\t\t\t} else if (noinput) {\n\t\t\t\t\tpi[next].to_write->origin_index = -1;\n\t\t\t\t\tpi[next].to_write->origin_fd_direction = STDOUT_FILENO;\n\t\t\t\t}\n\n\t\t\t\t/* Set a conc's required/provided IO in mb */\n\t\t\t\tif (!noinput)\n\t\t\t\t\tset_io_channels(pi[next].to_write);\n\n\t\t\t\tif (rb->state == PS_NEGOTIATION &&\n\t\t\t\t\t\tnoinput) {\n\t\t\t\t\tint j, seen = 0;\n\t\t\t\t\tpi[i].seen = true;\n\t\t\t\t\tfor (j = 1; j < nfd; j++)\n\t\t\t\t\t\tif (pi[j].seen)\n\t\t\t\t\t\t\tseen++;\n\t\t\t\t\tif ((nfd > 2 && seen == nfd - 2) ||\n\t\t\t\t\t\t\tseen == nfd - 1) {\n\t\t\t\t\t\tchosen_mb = rb;\n\t\t\t\t\t\tDPRINTF(1, \"%s(): Gathered I/O requirements.\", __func__);\n\t\t\t\t\t\tint state = solve_graph();\n\t\t\t\t\t\tif (state == OP_ERROR) {\n\t\t\t\t\t\t\tpi[next].to_write->state = PS_ERROR;\n\t\t\t\t\t\t\tpi[next].to_write->is_error_confirmed = true;\n\t\t\t\t\t\t} else if (state == OP_DRAW_EXIT)\n\t\t\t\t\t\t\tpi[next].to_write->state = PS_DRAW_EXIT;\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tDPRINTF(1, \"%s(): Computed solution\", __func__);\n\t\t\t\t\t\t\tpi[next].to_write->state = PS_RUN;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (j = 1; j < nfd; j++)\n\t\t\t\t\t\t\tpi[j].seen = false;\n\t\t\t\t\t\t// Don't free\n\t\t\t\t\t\tchosen_mb = NULL;\n\t\t\t\t\t}\n\t\t\t\t} else if (rb->state == PS_RUN ||\n\t\t\t\t\t\trb->state == PS_DRAW_EXIT ||\n\t\t\t\t\t\t(rb->state == PS_ERROR &&\n\t\t\t\t\t\trb->is_error_confirmed))\n\t\t\t\t\tpi[i].seen = true;\n\t\t\t\telse if (rb->state == PS_ERROR)\n\t\t\t\t\trb->is_error_confirmed = true;\n\n\t\t\t\tprint_state(i, (int)rb->initiator_pid, 1);\n\t\t\t\tif (pi[i].seen && pi[i].written) {\n\t\t\t\t\tchosen_mb = pi[next].to_write;\n\t\t\t\t\tpi[i].run_ready = true;\n\t\t\t\t\tDPRINTF(4, \"**%s(): pi[%d] is run ready\",\n\t\t\t\t\t\t\t__func__, i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// See if all processes are run-ready\n\t\tnfds = 0;\n\t\tfor (i = 0; i < nfd; i++) {\n\t\t\tif (pi[i].run_ready)\n\t\t\t\tnfds++;\n\t\t\tprint_state(i, nfds, 2);\n\t\t}\n\t\tif ((nfd > 2 && (nfds == nfd - 1 ||\n\t\t\t\t\t(noinput && nfds == nfd - 2))) ||\n\t\t    (nfds == nfd || (noinput && nfds == nfd - 1))) {\n\t\t\tassert(chosen_mb != NULL);\n\t\t\tDPRINTF(4, \"%s(): conc leaves negotiation\", __func__);\n\t\t\treturn chosen_mb->state;\n\t\t} else if (chosen_mb != NULL &&\tiswrite) { // Free if we have written\n\t\t\tDPRINTF(4, \"chosen_mb: %lx, i: %d, next: %d, pi[next].to_write: %lx\\n\",\n\t\t\t\t(long)chosen_mb, i, next_fd(i, &ro), (long)pi[next_fd(i, &ro)].to_write);\n\t\t\tfree_mb(chosen_mb);\n\t\t\tchosen_mb = NULL;\n\t\t\tiswrite = false;\n\t\t}\n\t}\n}\n\n\n\n/*\n * Scatter the fds read from the input process to multiple outputs.\n */\nSTATIC void\nscatter_input_fds(struct dgsh_negotiation *mb)\n{\n\tstruct dgsh_conc *this_conc = find_conc(mb, pid);\n\tif (!this_conc) {\n\t\tprintf(\"%s(): Concentrator with pid %d not registered\",\n\t\t\t\t__func__, pid);\n\t\texit(1);\t// XXX\n\t}\n\tint n_to_read = this_conc->input_fds;\n\tint *read_fds = (int *)malloc(n_to_read * sizeof(int));\n\tint i, j, write_index = 0;\n\tbool ignore = false;\n\tDPRINTF(4, \"%s(): fds to read: %d\", __func__, n_to_read);\n\n\tfor (i = 0; i < n_to_read; i++)\n\t\tread_fds[i] = read_fd(STDIN_FILENO);\n\n\tfor (i = STDOUT_FILENO; i != STDIN_FILENO; i = next_fd(i, &ignore)) {\n\t\tint n_to_write = get_expected_fds_n(mb, pi[i].pid);\n\t\tDPRINTF(4, \"%s(): fds to write for p[%d].pid %d: %d\",\n\t\t\t\t__func__, i, pi[i].pid, n_to_write);\n\t\tfor (j = write_index; j < write_index + n_to_write; j++) {\n\t\t\twrite_fd(i, read_fds[j]);\n\t\t\tDPRINTF(4, \"%s(): Write fd: %d to output channel: %d\",\n\t\t\t\t\t__func__, read_fds[j], i);\n\t\t}\n\t\twrite_index += n_to_write;\n\t}\n\tassert(write_index == n_to_read);\n}\n\n/*\n * Gather the fds read from input processes to a single output.\n */\nSTATIC void\ngather_input_fds(struct dgsh_negotiation *mb)\n{\n\tstruct dgsh_conc *this_conc = find_conc(mb, pid);\n\tif (!this_conc) {\n\t\tprintf(\"%s(): Concentrator with pid %d not registered\",\n\t\t\t\t__func__, pid);\n\t\texit(1);\t// XXX\n\t}\n\tint n_to_write = this_conc->output_fds;\n\tint *read_fds = (int *)malloc(n_to_write * sizeof(int));\n\tint i, j, read_index;\n\tDPRINTF(4, \"%s(): fds to write: %d\", __func__, n_to_write);\n\n\tread_index = 0;\n\tfor (i = STDIN_FILENO; i < nfd; i == STDIN_FILENO ? i = FREE_FILENO : i++) {\n\t\tint n_to_read = get_provided_fds_n(mb, pi[i].pid);\n\t\tDPRINTF(4, \"%s(): fds to read for p[%d].pid %d: %d\",\n\t\t\t\t__func__, i, pi[i].pid, n_to_read);\n\t\tfor (j = read_index; j < read_index + n_to_read; j++) {\n\t\t\tread_fds[j] = read_fd(i);\n\t\t\tDPRINTF(4, \"%s(): Read fd: %d from input channel: %d\",\n\t\t\t\t\t__func__, read_fds[j], i);\n\t\t}\n\t\tread_index += n_to_read;\n\t}\n\tassert(read_index == n_to_write);\n\n\tfor (i = 0; i < n_to_write; i++)\n\t\twrite_fd(STDOUT_FILENO, read_fds[i]);\n\n}\n\n#ifndef UNIT_TESTING\n\nint\nmain(int argc, char *argv[])\n{\n\tint ch;\n\tint exit;\n\tchar *debug_level = NULL;\n\tchar *timeout;\n\n\tprogram_name = argv[0];\n\tpid = getpid();\n\tnoinput = false;\n\n\twhile ((ch = getopt(argc, argv, \"ion\")) != -1) {\n\t\tswitch (ch) {\n\t\tcase 'i':\n\t\t\tmultiple_inputs = true;\n\t\t\tbreak;\n\t\tcase 'o':\n\t\t\tmultiple_inputs = false;\n\t\t\tbreak;\n\t\tcase 'n':\t// special output conc that takes no input\n\t\t\tif (!multiple_inputs)\n\t\t\t\tnoinput = true;\n\t\t\telse\n\t\t\t\tusage();\n\t\t\tbreak;\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\t}\n\targc -= optind;\n\targv += optind;\n\n\tif (argc != 1)\n\t\tusage();\n\n\tdebug_level = getenv(\"DGSH_DEBUG_LEVEL\");\n\tif (debug_level != NULL)\n\t\tdgsh_debug_level = atoi(debug_level);\n\n\tsignal(SIGALRM, dgsh_alarm_handler);\n\tif ((timeout = getenv(\"DGSH_TIMEOUT\")) != NULL)\n\t\talarm(atoi(timeout));\n\telse\n\t\talarm(DGSH_TIMEOUT);\n\n\t/* +1 for stdin when scatter/stdout when gather\n\t * +1 for stderr which is not used\n\t */\n\tif (atoi(argv[0]) == 1)\n\t\tnfd = 2;\n\telse\n\t\tnfd = atoi(argv[0]) + 2;\n\tpi = (struct portinfo *)calloc(nfd, sizeof(struct portinfo));\n\n\tchosen_mb = NULL;\n\texit = pass_message_blocks();\n\tif (exit == PS_RUN) {\n\t\tif (noinput)\n\t\t\tDPRINTF(1, \"%s(): Special (no-input) conc communicated the solution\", __func__);\n\t\tif (multiple_inputs)\n\t\t\tgather_input_fds(chosen_mb);\n\t\telse if (!noinput)\t// Output noinput conc has no job here\n\t\t\tscatter_input_fds(chosen_mb);\n\t\texit = PS_COMPLETE;\n\t}\n\tfree_mb(chosen_mb);\n\tfree(pi);\n\tDPRINTF(3, \"conc with pid %d terminates %s\",\n\t\tpid, exit == PS_COMPLETE ? \"normally\" : \"with error\");\n#ifdef DEBUG\n\tfflush(stderr);\n#endif\n#ifdef TIME\n\tif (noinput) {\n\t\tclock_gettime(CLOCK_MONOTONIC, &tend);\n\t\tfprintf(stderr, \"The dgsh negotiation procedure took about %.5f seconds\\n\",\n\t\t\t((double)tend.tv_sec + 1.0e-9*tend.tv_nsec) -\n\t\t\t((double)tstart.tv_sec + 1.0e-9*tstart.tv_nsec));\n\t\tfflush(stderr);\n\n\t}\n#endif\n\tset_negotiation_complete();\n\talarm(0);\t\t\t// Cancel alarm\n\tsignal(SIGALRM, SIG_IGN);\t// Do not handle the signal\n\treturn exit;\n}\n\n#endif\n"
  },
  {
    "path": "core-tools/src/dgsh-debug.h",
    "content": "/*\n * Copyright 2013-2017 Diomidis Spinellis\n *\n * Debug macros\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#ifndef DEBUG_H\n#define DEBUG_H\n\nextern int dgsh_debug_level;\n\n/* ## is a gcc extension that removes trailing comma if no args */\n#define DPRINTF(debug_level, fmt, ...) ((debug_level) <= dgsh_debug_level ? fprintf(stderr, \"%d: \" fmt \"\\n\", (int)getpid(), ##__VA_ARGS__) : 0)\n\n#endif /* DEBUG_H */\n"
  },
  {
    "path": "core-tools/src/dgsh-elf.s",
    "content": "/*\n * ELF note header to mark dgsh-compatible programs\n * See http://www.netbsd.org/docs/kernel/elf-notes.html\n * Don't use line comments as these are not portable between\n * different CPU architectures.\n * https://en.wikipedia.org/wiki/GNU_Assembler#Single-Line_comments\n */\n\n    .comm dgsh_force_include,4,4\n    .section \".note.ident\", \"a\"\n    .p2align 2\n    .long 1f - 0f\t\t/* name size (not including padding) */\n    .long 3f - 2f\t\t/* desc size (not including padding) */\n    .long 1\t\t\t/* type */\n0:  .asciz \"DSpinellis/dgsh\"\t/* name */\n1:  .p2align 2\n2:  .long 0x00000001\t\t/* desc */\n    .long 0x00000000\n3:  .p2align 2\n\n"
  },
  {
    "path": "core-tools/src/dgsh-enumerate.1",
    "content": ".TH DGSH-ENUMERATE 1 \"27 January 2017\"\n.\\\"\n.\\\" (C) Copyright 2017 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-enumerate \\- enumerate an arbitrary number of output channels\n.SH SYNOPSIS\n\\fBdgsh-enumerate\\fP [\\fIn\\fP]\n.SH DESCRIPTION\n\\fIdgsh-enumerate\\fP will output a single newline-terminated ascending\ninteger on each one of its output channels.\nIf the number of channels is not specified, the command will\nallow its downstream processes to specify the number and use that one.\n.PP\nThe command demonstrates the \\fIdgsh\\fP negotiation API.\nIt can also be used as a debug tool.\n.SH EXAMPLES\n.PP\nEnumerate the specified four output streams.\n.ft C\n.ps -1\n.nf\n$ dgsh -c 'dgsh-enumerate 4 | cat'\n0\n1\n2\n3\n.fi\n.ps +1\n.ft P\n.PP\nEnumerate the two output streams required by the downstream multipipe block.\n.ft C\n.ps -1\n.nf\n$ dgsh -c 'dgsh-enumerate | {{ sed \"s/^/A /\" & sed \"s/^/B /\" & }} | cat'\nA 0\nB 1\n.fi\n.ps +1\n.ft P\n.SH \"SEE ALSO\"\n.IR dgsh (1),\n.IR dgsh_negotiate (3).\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>\n"
  },
  {
    "path": "core-tools/src/dgsh-enumerate.c",
    "content": "/*\n * Copyright 2017 Diomidis Spinellis\n *\n * Enumerate an arbitrary number of output channels.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <err.h>\n#include <unistd.h>\n\n#include \"dgsh.h\"\n\nint\nmain(int argc, char *argv[])\n{\n\tint n_input_fds = 0, n_output_fds;\n\tint *output_fds;\n\tint i;\n\n\tswitch (argc) {\n\tcase 1:\n\t\tn_output_fds = -1;\n\t\tbreak;\n\tcase 2:\n\t\tn_output_fds = atoi(argv[1]);\n\t\tbreak;\n\tdefault:\n\t\terrx(1, \"usage: %s [n]\", argv[0]);\n\t}\n\n\n\tdgsh_negotiate(DGSH_HANDLE_ERROR, argv[0], &n_input_fds,\n\t\t\t\t&n_output_fds, NULL, &output_fds);\n\n\tfor (i = 0; i < n_output_fds; i++) {\n\t\tchar buff[10];\n\n\t\tsnprintf(buff, sizeof(buff), \"%d\\n\", i);\n\t\twrite(output_fds[i], buff, strlen(buff));\n\t\tclose(output_fds[i]);\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-fft-input.c",
    "content": "#include <assert.h>\t// assert()\n#include <stdio.h>\t// printf\n#include <complex.h>\t// double complex\n#include <unistd.h>\t// read(), write()\n#include <stdlib.h>\t// free()\n#include <err.h>\t// errx()\n\n#include \"dgsh.h\"\n#include \"debug.h\"\n\nint main(int argc, char **argv)\n{\n\tchar *input_file;\n\tFILE *f;\n\tint ninput = 4, nlines = 0, i;\n\tint ninputfds = 0, noutputfds;\n\tint *inputfds = NULL, *outputfds = NULL;\n\tsize_t len = sizeof(long double), wsize;\n\tchar line[len + 1];\n\tlong double *input = (long double *)malloc(sizeof(long double) * ninput);\n\n\tif (argc == 1) {\n\t\tnoutputfds = 8;\n\t\tgoto negotiate;\n\t}\n\n\tinput_file = argv[1];\n\tf = fopen(input_file, \"r\");\n\tif (!f)\n\t\terrx(2, \"Open file %s failed\", input_file);\n\tDPRINTF(4, \"Opened input file: %s\", input_file);\n\n\twhile (fgets(line, len, f)) {\n\t\tassert(len == sizeof(input[nlines - 1]));\n\t\tnlines++;\n\t\tif (nlines == ninput) {\n\t\t\tninput *= 2;\n\t\t\tinput = (long double *)realloc(input,\n\t\t\t\t\tsizeof(long double) * ninput);\n\t\t\tif (!input)\n\t\t\t\terrx(2, \"Realloc for input numbers failed\");\n\t\t}\n\t\tinput[nlines - 1] = atof(line);\n\n\t\tDPRINTF(4, \"Retrieved input %.10Lf\\n\", input[nlines - 1]);\n\t}\n\tnoutputfds = nlines;\n\nnegotiate:\n\n\tdgsh_negotiate(DGSH_HANDLE_ERROR, \"fft-input\", &ninputfds, &noutputfds,\n\t\t\t\t\t&inputfds, &outputfds);\n\tDPRINTF(4, \"Read %d inputs, received %d fds\", nlines, noutputfds);\n\tassert(ninputfds == 0);\n\tassert(noutputfds == nlines);\n\n\tfor (i = 0; i < noutputfds; i++) {\n\t\tDPRINTF(4, \"Write input %.10Lf to fd %d\", input[i], outputfds[i]);\n\t\twsize = write(outputfds[i], &input[i],\n\t\t\t\tsizeof(long double));\n\t\tif (wsize == -1)\n\t\t\terr(1, \"write failed\");\n\t}\n\n\tfclose(f);\n\tfree(input);\n\treturn 0;\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-httpval.1",
    "content": ".TH DGSH-HTTPVAL 1 \"14 July 2013\"\n.\\\"\n.\\\" (C) Copyright 2013 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-httpval \\- data store HTTP server\n.SH SYNOPSIS\n\\fBdgsh-httpval\\fP\n[\\fB\\-a\\fP]\n[\\fB\\-b\\fP \\fIquery:command\\fP]\n[\\fB\\-m\\fP \\fIMIME-type\\fP]\n[\\fB\\-n\\fP]\n[\\fB\\-p\\fP \\fIport\\fP]\n.SH DESCRIPTION\n\\fIdgsh-httpval\\fP allows other programs to access \\fIdgsh\\fP\ndata stores through the HTTP protocol.\nThis simplifies the interfacing between web-based front-ends and\n\\fIdgsh\\fP programs.\nWhen \\fIdgsh-httpval\\fP receives a REST request with the name of a data store\nwhose endpoint is located in the directory where \\fIdgsh-httpval\\fP\nwas launched (e.g. \\fChttp://localhost:8081/mystore\\fP),\nit will establish a connection with the store specified in the request,\nsend a command to read the store's value,\nobtain the value,\nand respond with it as the document sent with the HTTP response.\n.PP\nRequests for files located in the directory where \\fIdgsh-httpval\\fP\nwas launched will also be satisfied.\nThe correct MIME type will be sent for files with a suffix of\n\\fChtml\\fP,\n\\fCjs\\fP,\n\\fCjson\\fP,\n\\fCpng\\fP, and\n\\fCcss\\fP.\n.PP\nA request for the resource \\fC.server?quit\\fP, will cause the server\nto terminate processing and exit.\n.PP\n\\fIdgsh-httpval\\fP is normally executed from within \\fIdgsh\\fP-generated\nscripts, rather than through end-user commands.\nThis manual page serves mainly to document its operation and\nthe flags that can be passed to \\fIdgsh\\fP for modifying its behavior.\n\n.SH OPTIONS\n.IP \"\\fB\\-a\\fP\nAllow any Internet host to obtain a value from the server.\nBy default the server will only respond to requests arriving from the local\nhost's loop-back IP address (127.0.0.1).\n\n.IP \"\\fB\\-b\\fP \\fIquery:command\\fP\"\nThe colon-separated pair specifies a dynamic query\nthan can be sent to the server,\nso that it will execute the specified command and return its output.\nThe query and the command can contain up to ten matching\n\\fIscanf(3)\\fP and \\fIprintf(3)\\fP specifications for C integer-sized\narguments, which can be used to pass data from the query to the command.\nAn unlimited number of dynamic queries can be specified through multiple\n.B -b\noptions.\nThe type of the data returned is specified using the\n.B -m\noption.\n\n.IP \"\\fB\\-m\\fP \\fIMIME-type\\fP\"\nSpecify the MIME-type that the server will provide on the \\fCContent-type\\fP\nHTTP header for data coming from data stores and dynamic queries.\nBy default this value is \\fCtext/plain\\fP.\nOther reasonable types are\n\\fCapplication/json\\fP,\n\\fCtext/CSV\\fP,\n\\fCtext/xml\\fP, or\n\\fCapplication/octet-stream\\fP.\n\n.IP \"\\fB\\-n\\fP\nRead values from stores using a non-blocking read command.\nThis means that the server will return an empty record,\nif no complete record is available.\n\n.IP \"\\fB\\-p\\fP \\fIport\\fP\"\nSpecify the TCP port on which the server will listen for incoming HTTP\nrequests.\nIf no port is specified, then the server will listen on an arbitrary,\nsystem-assigned, port,\nand will print that port's number on its standard output.\nThat value can be conveniently piped into \\fIdgsh-writeval\\fP\nto be made available to other processes.\n\n.SH EXAMPLES\n.PP\nSpecify that a query, such as\n\\fChttp://localhost:63001/server-bin/pstatus?id=4892\\fP,\nwill run the \\fIps(1)\\fP command for the specified process-id.\n.ft C\n.nf\ndgsh-httpval -b 'server-bin/pstatus?id=%d:ps -p %d'\n.ft P\n.fi\n\n.SH \"SEE ALSO\"\n\\fIdgsh\\fP(1),\n\\fIdgsh-writeval\\fP(1),\n\\fIdgsh-readval\\fP(1)\n\n.SH BUGS\nThe server is single-threaded and will block if a value is not available\non a specified store.\n.PP\nThe server only supports IPv4 and the HTTP 1.0 protocols.\nSome clients may require special configuration to connect to it.\nFor instance, \\fIcurl\\fP(1) requires the specification of the \\fC--ipv4\\fP\nand \\fC--http1.0\\fP flags.\n\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>.\nJef Poskanzer \\(em <jef@mail.acme.com> \\(em wrote micro_httpd on which\nthis server is based.\n\n.SH BUGS\nThe possibilities for mallicious attacks through code injection and buffer\noverflows offered by the dynamic query option are too numerous to list.\nUse this feature only in setups where you restrict and control what is being\nsent to the server.\n"
  },
  {
    "path": "core-tools/src/dgsh-httpval.c",
    "content": "/*-\n *\n * Provide HTTP access to the dgsh key-value store.\n *\n * Based on micro_httpd - really small HTTP server heavily modified by\n * Diomidis Spinellis to use IP sockets, instead of depending on inetd,\n * and to serve dgsh key-value store data, instead of files.\n *\n * micro_httpd:\n * Copyright (c) 1999,2005 by Jef Poskanzer <jef@mail.acme.com>.\n * All rights reserved.\n *\n * Dgsh modifications:\n * Copyright 2013 Diomidis Spinellis\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <sys/stat.h>\n#include <errno.h>\n#include <unistd.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include <err.h>\n#include <time.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <stdint.h>\n\n#include \"kvstore.h\"\n\n#define SERVER_NAME \"dgsh-httpval\"\n#define SERVER_URL \"http://www.spinellis.gr/sw/dgsh\"\n\n#define PROTOCOL \"HTTP/1.0\"\n#define RFC1123FMT \"%a, %d %b %Y %H:%M:%S GMT\"\n\n/* Forwards. */\nstatic void send_error(FILE *out, int status, char *title, char *extra_header,\n    char *text);\nstatic void send_headers(FILE *out, int status, char *title, char *extra_header,\n    const char *mime_type, off_t length, time_t mod);\nstatic char * get_mime_type(char *name);\nstatic void strdecode(char *to, char *from);\nstatic int hexit(char c);\nstatic void http_serve(FILE *in, FILE *out, const char *mime_type);\n\n#define c_isxdigit(x) isxdigit((unsigned char)(x))\n\nstatic const char *program_name;\n\nstatic void\nusage(void)\n{\n\tfprintf(stderr, \"Usage: %s [-a] [-b query:cmd] [-p port]\\n\"\n\t\t\"-a\\t\"\t\t\"\\tAllow non-localhost access\\n\"\n\t\t\"-b query:cmd\"\t\"\\tSpecify a command for a given HTTP query\\n\"\n\t\t\"-m MIME-type\"\t\"\\tSpecify the store Content-type header value\\n\"\n\t\t\"-n\"\t\t\"\\tNon-blocking read from stores\\n\"\n\t\t\"-p port\"\t\"\\tSpecify the port to listen to\\n\",\n\t\tprogram_name);\n\texit(1);\n}\n\nstatic struct query {\n\tconst char *query;\n\tconst char *cmd;\n\tint narg;\n\tstruct query *next;\n} *query_list;\n\n/* Command to read from stores: blocking read current record */\nstatic char read_cmd = 'C';\n\nint\nmain(int argc, char *argv[])\n{\n\tint sockfd, newsockfd;\n\tstruct sockaddr_in cli_addr, serv_addr;\n\tint ch, port = 0;\n\tbool localhost_access = true;\n\tconst char *mime_type = \"text/plain\";\n\tint so_reuseaddr = 1;\n\tstruct linger so_linger;\n\n\tprogram_name = argv[0];\n\n\twhile ((ch = getopt(argc, argv, \"ab:m:np:\")) != -1) {\n\t\tchar *p;\n\t\tstruct query *q;\n\n\t\tswitch (ch) {\n\t\tcase 'a':\n\t\t\tlocalhost_access = false;\n\t\t\tbreak;\n\t\tcase 'b':\n\t\t\tif ((p = strchr(optarg, ':')) == NULL)\n\t\t\t\tusage();\n\t\t\t/* Save query */\n\t\t\t*p = 0;\n\t\t\tq = malloc(sizeof(struct query));\n\t\t\tq->query = strdup(optarg);\n\t\t\tq->cmd = strdup(p + 1);\n\t\t\t/* Count number of query arguments */\n\t\t\tq->narg = 0;\n\t\t\tfor (p = optarg; *p; p++)\n\t\t\t\tif (*p == '%') {\n\t\t\t\t\tif (p[1] == '%') {\n\t\t\t\t\t\tp++;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tq->narg++;\n\t\t\t\t}\n\n\t\t\tif (q->narg > 10) {\n\t\t\t\tfprintf(stderr, \"%s: More than ten query arguments specified.\\n\", program_name);\n\t\t\t\texit(1);\n\t\t\t}\n\n\t\t\t/* Insert query into the linked list */\n\t\t\tq->next = query_list;\n\t\t\tquery_list = q;\n\t\t\tbreak;\n\t\tcase 'm':\n\t\t\tmime_type = optarg;\n\t\t\tbreak;\n\t\tcase 'n':\n\t\t\t/* Non-blocking read */\n\t\t\tread_cmd = 'c';\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tport = atoi(optarg);\n\t\t\tbreak;\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\t}\n\targc -= optind;\n\targv += optind;\n\n\tif (argc != 0)\n\t\tusage();\n\n\tif ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)\n\t\terr(2, \"socket\");\n\n\tif (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr,\n\t\t\tsizeof (so_reuseaddr)) < 0)\n\t\terr(2, \"setsockopt SO_REUSEADDR\");\n\n\tso_linger.l_onoff = 1;\n\tso_linger.l_linger = 1;\n\tif (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger,\n\t\t\tsizeof (so_linger)) < 0)\n\t\terr(2, \"setsockopt SO_LINGER\");\n\n\tmemset((char *)&serv_addr, 0, sizeof(serv_addr));\n\tserv_addr.sin_family = AF_INET;\n\tserv_addr.sin_addr.s_addr = htonl(INADDR_ANY);\n\tserv_addr.sin_port = htons(port);\n\n\tif (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)\n\t\terr(2, \"bind\");\n\n\tif (port == 0) {\n\t\tsocklen_t len = sizeof(serv_addr);\n\n\t\tserv_addr.sin_port = 0;\n\t\tif (getsockname(sockfd, (struct sockaddr *)&serv_addr, &len) < 0)\n\t\t\terr(2, \"getsockname\");\n\t\tprintf(\"%d\\n\", ntohs(serv_addr.sin_port));\n\t\tfflush(stdout);\n\t}\n\n\tlisten(sockfd, 5);\n\n\tfor (;;) {\n\t\tsocklen_t cli_len = sizeof(cli_addr);\n\t\tFILE *in, *out;\n\n\t\tif ((newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &cli_len)) < 0)\n\t\t\terr(2, \"accept\");\n\n\t\tif (localhost_access && memcmp(inet_ntoa(cli_addr.sin_addr), \"127.\", 4)) {\n\t\t\twarnx(\"Non-localhost access: %s\", inet_ntoa(cli_addr.sin_addr));\n\t\t\tclose(newsockfd);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ((in = fdopen(newsockfd, \"r\")) == NULL)\n\t\t\terr(2, \"fdopen for input\");\n\t\tsetvbuf(in, NULL, _IOLBF, 4096);\n\n\t\t/* Must dup(2) so that fclose will work correctly */\n\t\tif ((out = fdopen(dup(newsockfd), \"w\")) == NULL)\n\t\t\terr(2, \"fdopen for output\");\n\n\t\thttp_serve(in, out, mime_type);\n\n\t\t(void)fclose(in);\n\t\t(void)fclose(out);\n\t}\n}\n\n/* Serve a single HTTP request */\nstatic void\nhttp_serve(FILE *in, FILE *out, const char *mime_type)\n{\n\tchar line[10000], method[10000], path[10000], protocol[10000];\n\tchar *file;\n\tsize_t len;\n\tstruct stat sb;\n\tstruct query *q;\n\n\tif (fgets(line, sizeof(line), in) == (char *) 0) {\n\t\tsend_error(out, 400, \"Bad Request\", (char *) 0,\n\t\t    \"No request found.\");\n\t\treturn;\n\t}\n\tif (sscanf(line, \"%[^ ] %[^ ] %[^ ]\", method, path, protocol) != 3) {\n\t\tsend_error(out, 400, \"Bad Request\", (char *) 0,\n\t\t    \"Can't parse request.\");\n\t\treturn;\n\t}\n\twhile (fgets(line, sizeof(line), in) != (char *) 0) {\n\t\tif (strcmp(line, \"\\n\") == 0 || strcmp(line, \"\\r\\n\") == 0)\n\t\t\tbreak;\n\t}\n\tif (strcasecmp(method, \"get\") != 0) {\n\t\tsend_error(out, 501, \"Not Implemented\", (char *) 0,\n\t\t    \"That method is not implemented.\");\n\t\treturn;\n\t}\n\tif (path[0] != '/') {\n\t\tsend_error(out, 400, \"Bad Request\", (char *) 0, \"Bad filename.\");\n\t\treturn;\n\t}\n\tfile = &(path[1]);\n\tstrdecode(file, file);\n\n\tif (strcmp(file, \".server?quit\") == 0) {\n\t\tsend_error(out, 200, \"OK\", (char *) 0,\n\t\t    \"Quitting.\");\n\t\texit(0);\n\t}\n\n\tlen = strlen(file);\n\n\t/* Guard against attempts to move outside our directory */\n\tif (file[0] == '/' || strcmp(file, \"..\") == 0\n\t    || strncmp(file, \"../\", 3) == 0\n\t    || strstr(file, \"/../\") != (char *) 0\n\t    || strcmp(&(file[len - 3]), \"/..\") == 0) {\n\t\tsend_error(out, 400, \"Bad Request\", (char *) 0,\n\t\t    \"Illegal filename.\");\n\t\treturn;\n\t}\n\n\t/* User-specified query name space */\n\tfor (q = query_list; q; q = q->next) {\n\t\tint v0, v1, v2, v3, v4, v5, v6, v7, v8, v9;\n\t\tchar cmd[11000];\n\n\t\t*cmd = 0;\n\t\tif (q->narg == 0 && strcmp(file, q->query) == 0)\n\t\t\tstrncpy(cmd, q->cmd, sizeof(cmd));\n\t\telse if (q->narg && sscanf(file, q->query, &v0, &v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9) == q->narg)\n\t\t\tsnprintf(cmd, sizeof(cmd), q->cmd, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);\n\t\tif (*cmd) {\n\t\t\tint ich;\n\t\t\tFILE *fp;\n\n\t\t\tfp = popen(cmd, \"r\");\n\t\t\tif (fp == NULL) {\n\t\t\t\tsend_error(out, 502, \"Bad Gateway\", NULL, \"Error in executing command.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsend_headers(out, 200, \"Ok\", NULL, mime_type, -1,\n\t\t\t\ttime(NULL));\n\t\t\twhile ((ich = getc(fp)) != EOF)\n\t\t\t\tputc(ich, out);\n\t\t\tfclose(fp);\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* File system name space */\n\tif (stat(file, &sb) < 0) {\n\t\tsend_error(out, 404, \"Not Found\", NULL, strerror(errno));\n\t\treturn;\n\t}\n\tif (S_ISSOCK(sb.st_mode)) {\n\t\t/* Value store */\n\t\tsend_headers(out, 200, \"Ok\", NULL, mime_type,\n\t\t    -1, (time_t)-1);\n\t\t(void)fflush(out);\n\t\tdgsh_send_command(file, read_cmd, true, false, fileno(out));\n\t} else if (S_ISREG(sb.st_mode)) {\n\t\t/* Regular file */\n\t\tint ich;\n\t\tFILE *fp;\n\n\t\tfp = fopen(file, \"r\");\n\t\tif (fp == NULL) {\n\t\t\tsend_error(out, 403, \"Forbidden\", NULL, \"File is protected.\");\n\t\t\treturn;\n\t\t}\n\t\tsend_headers(out, 200, \"Ok\", NULL, get_mime_type(file),\n\t\t\tsb.st_size, sb.st_mtime);\n\t\twhile ((ich = getc(fp)) != EOF)\n\t\t\tputc(ich, out);\n\t\tfclose(fp);\n\t} else {\n\t\tsend_error(out, 403, \"Forbidden\", (char *) 0,\n\t\t    \"File is not a regular file or a Unix domain socket.\");\n\t}\n}\n\nstatic void\nsend_error(FILE *out, int status, char *title, char *extra_header, char *text)\n{\n\tsend_headers(out, status, title, extra_header, \"text/html\", -1, -1);\n\t(void)fprintf(out,\n\t    \"<html><head><title>%d %s</title></head>\\n<body><h4>%d %s</h4>\\n\",\n\t    status, title, status, title);\n\t(void)fprintf(out, \"%s\\n\", text);\n\t(void)fprintf(out,\n\t    \"<hr />\\n<address><a href=\\\"%s\\\">%s</a></address>\\n</body></html>\\n\",\n\t    SERVER_URL, SERVER_NAME);\n\t(void)fflush(out);\n}\n\nstatic void\nsend_headers(FILE *out, int status, char *title, char *extra_header,\n    const char *mime_type, off_t length, time_t mod)\n{\n\ttime_t now;\n\tchar timebuf[100];\n\n\t(void)fprintf(out, \"%s %d %s\\015\\012\", PROTOCOL, status, title);\n\t(void)fprintf(out, \"Server: %s\\015\\012\", SERVER_NAME);\n\tnow = time((time_t *) 0);\n\t(void)strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));\n\t(void)fprintf(out, \"Date: %s\\015\\012\", timebuf);\n\tif (extra_header != (char *) 0)\n\t\t(void)fprintf(out, \"%s\\015\\012\", extra_header);\n\tif (mime_type != (char *) 0)\n\t\t(void)fprintf(out, \"Content-Type: %s\\015\\012\", mime_type);\n\tif (length >= 0)\n#if __STDC_VERSION__ >= 199901L\n\t\t(void)fprintf(out, \"Content-Length: %jd\\015\\012\",\n\t\t    (intmax_t) length);\n#else\n\t\t(void)fprintf(out, \"Content-Length: %lld\\015\\012\",\n\t\t    (long long) length);\n#endif\n\tif (mod != (time_t) - 1) {\n\t\t(void)strftime(timebuf, sizeof(timebuf), RFC1123FMT,\n\t\t    gmtime(&mod));\n\t\t(void)fprintf(out, \"Last-Modified: %s\\015\\012\", timebuf);\n\t}\n\t(void)fprintf(out, \"Connection: close\\015\\012\");\n\t(void)fprintf(out, \"\\015\\012\");\n}\n\nstatic char *\nget_mime_type(char *name)\n{\n\tchar *dot;\n\n\tdot = strrchr(name, '.');\n\tif (dot == NULL)\n\t\treturn \"text/plain\";\n\tif (strcmp(dot, \".json\") == 0)\n\t\treturn \"application/json\";\n\tif (strcmp(dot, \".html\") == 0)\n\t\treturn \"text/html\";\n\tif (strcmp(dot, \".js\") == 0)\n\t\treturn \"text/javascript\";\n\tif (strcmp(dot, \".png\") == 0)\n\t\treturn \"image/png\";\n\tif (strcmp(dot, \".css\") == 0)\n\t\treturn \"text/css\";\n\treturn \"text/plain; charset=iso-8859-1\";\n}\n\nstatic void\nstrdecode(char *to, char *from)\n{\n\tfor (; *from != '\\0'; ++to, ++from) {\n\t\tif (from[0] == '%' && c_isxdigit(from[1]) && c_isxdigit(from[2])) {\n\t\t\t*to = hexit(from[1]) * 16 + hexit(from[2]);\n\t\t\tfrom += 2;\n\t\t} else\n\t\t\t*to = *from;\n\t}\n\t*to = '\\0';\n}\n\nstatic int\nhexit(char c)\n{\n\tif (c >= '0' && c <= '9')\n\t\treturn c - '0';\n\tif (c >= 'a' && c <= 'f')\n\t\treturn c - 'a' + 10;\n\tif (c >= 'A' && c <= 'F')\n\t\treturn c - 'A' + 10;\n\t/* Shouldn't happen, we're guarded by isxdigit() */\n\treturn 0;\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-macho.s",
    "content": "# MACHO note header to mark dgsh-compatible programs\n    .section \".note.ident\", \"a\"\n    .asciz \"DSpinellis/dgsh\"\n    .section\t__TEXT,__text,regular,pure_instructions\n    .macosx_version_min 10, 13\n    .globl\t_dgsh_force_include     ## @dgsh_force_include\n    .zerofill __DATA,__common,_dgsh_force_include,4,2\n\n    .subsections_via_symbols\n"
  },
  {
    "path": "core-tools/src/dgsh-merge-sum.1",
    "content": ".TH DGSH-MERGE-SUM 1 \"10 September 2014\"\n.\\\"\n.\\\" (C) Copyright 2014 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-merge-sum \\- merge key value pairs, summing the values\n.SH SYNOPSIS\n\\fBdgsh-merge-sum\\fP \\fIfile ...\\fP\n.SH DESCRIPTION\n\\fIdgsh-merge-sum\\fP will read \\fIkey\\fP, \\fIvalue\\fP pairs from the files\nspecified in its standard input,\nand print the input records merged together according to the value of the key.\nThe input files should be sorted according to the key's value.\nRecords with the same key will have their values summed, and a single\ncorresponding record will be printed.\nWhitespace is used as the separator.\nLeading whitespace is not taken into account when parsing fields.\nThus \\fIdgsh-merge-sum\\fP can process multiple files\ngenerated by \\fIuniq -c\\fP,\nand merge them into one.\n\n.SH \"SEE ALSO\"\n\\fIuniq\\fP(1),\n\\fIdgsh\\fP(1)\n\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>\n"
  },
  {
    "path": "core-tools/src/dgsh-merge-sum.pl",
    "content": "#!/usr/bin/env perl\n#\n# Merge sorted (value, key) pairs, summing the values of equal keys\n#\n#  Copyright 2014 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nuse strict;\nuse warnings;\n\n# Read a record from the specified file reference\nsub\nread_record\n{\n\tmy ($fr) = @_;\n\tmy $f = $fr->{file};\n\tmy $line = <$f>;\n\tif (!defined($line)) {\n\t\t$fr->{key} = undef;\n\t\treturn;\n\t}\n\t($fr->{value}, $fr->{key}) = ($line =~ m/^\\s*(\\d+)\\s+(.*)/);\n}\n\n# Open input files; opening before reading prevents pipe writers from blocking\nmy @file;\n\n# First file is always stdin\nbinmode(STDIN,  \":utf8\");\n$file[0]->{file} = \\*STDIN;\n\nmy $i = 1;\nfor my $name (@ARGV) {\n\topen($file[$i]->{file}, '<:encoding(utf8)', $name) || die \"Unable to open $name: $!\\n\";\n\t$i++;\n}\n\n# Read first record from all files\nfor my $f (@file) {\n\tread_record($f);\n}\n\n# Previous key printed\nmy $prev;\n\nfor (;;) {\n\t# Find smallest key\n\tmy $smallest;\n\tfor my $r (@file) {\n\t\t#print \"Check $r->{value}, $r->{key}\\n\";\n\t\t$smallest = $r if (!defined($smallest->{key}) ||\n\t\t\t(defined($r->{key}) && $r->{key} lt $smallest->{key}));\n\t}\n\n\texit 0 unless defined($smallest->{key});\n\t#print \"Smallest $smallest->{value}, $smallest->{key}\\n\";\n\n\t# Sum up and renew all smallest keys\n\tmy $sum = 0;\n\tmy $key = $smallest->{key};\n\tfor my $r (@file) {\n\t\tif (defined($r->{key}) && ($r->{key} cmp $key) == 0) {\n\t\t\t$sum += $r->{value};\n\t\t\tread_record($r);\n\t\t}\n\t}\n\n\t# Verify that input is sorted\n\tif (defined($prev) && ($key cmp $prev) < 0) {\n\t\tprint STDERR \"Input is not sorted: [$key] came after [$prev]\\n\";\n\t\texit 1;\n\t}\n\t$prev = $key;\n\n\tprint \"$sum $key\\n\";\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-monitor.1",
    "content": ".TH DGSH-MONITOR 1 \"11 December 2016\"\n.\\\"\n.\\\" (C) Copyright 2013 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-monitor \\- monitor data on a pipe\n.SH SYNOPSIS\n\\fBdgsh-monitor\\fP\n.SH DESCRIPTION\n\\fIdgsh-monitor\\fP is a filter that reads lines from its standard input\nand for each line writes a JSON record containing\nthe absolute timestamp (\\fCatime\\fP),\nthe relative timestamp (\\fCrtime\\fP),\nthe number of lines read (\\fCnlines\\fP),\nthe number of bytes read (\\fCnbytes\\fP),\nand the actual data (\\fCdata\\fP).\nThe values printed are those that were in effect before the line's\nfirst character was read (i.e. the number of bytes and lines starts at 0).\nThe timestamps are printed as a decimal number of seconds\n(since epoch, January 1 1970, for the absolute one)\nwith microsecond precision.\n.PP\nThe command can be used in conjunction with \\fIdgsh-writeval\\fP\nfor providing pipeline monitoring ports as a debugging aid.\n\n.SH \"SEE ALSO\"\n\\fIdgsh\\fP(1),\n\\fIdgsh-writeval\\fP(1)\n\n.SH BUGS\nWhen providing data regarding a single record,\nsuch as that written to a store,\nit can be confusing to see all the numerical values as zero.\n\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>\n"
  },
  {
    "path": "core-tools/src/dgsh-monitor.c",
    "content": "/*\n * Copyright 2013 Diomidis Spinellis\n *\n * Prepend lines read with timestamp, number of lines, number of bytes.\n * Used for providing dgsh monitoring ports.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <sys/types.h>\n#include <sys/time.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <err.h>\n#include <errno.h>\n#include <limits.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"dgsh.h\"\n\nstatic const char *program_name;\n\nstatic void\nusage(void)\n{\n\tfprintf(stderr, \"Usage: %s\\n\", program_name);\n\texit(1);\n}\n\n/* Print c with JSON escaping */\nstatic void\nescape(int c)\n{\n\tswitch (c) {\n\tcase '\\\\': fputs(\"\\\\\\\\\", stdout); break;\n\tcase '\"': fputs(\"\\\\\\\"\", stdout); break;\n\tcase '/': fputs(\"\\\\/\", stdout); break;\n\tcase '\\b': fputs(\"\\\\b\", stdout); break;\n\tcase '\\f': fputs(\"\\\\f\", stdout); break;\n\tcase '\\n': fputs(\"\\\\n\", stdout); break;\n\tcase '\\r': fputs(\"\\\\r\", stdout); break;\n\tcase '\\t': fputs(\"\\\\t\", stdout); break;\n\tdefault:\n\t\tif (c < 0x1f)\n\t\t\tprintf(\"\\\\u%04x\", c);\n\t\telse\n\t\t\tputchar(c);\n\t}\n}\n\nint\nmain(int argc, char *argv[])\n{\n\tint c;\n\tunsigned long nlines, nbytes;\n\tstruct timeval start, t;\n\tbool write_header = true;\n\tbool wrote_header = false;\n\n\tprogram_name = argv[0];\n\n\t/* Default if nothing else is specified */\n\tif (argc != 1)\n\t\tusage();\n\n\tnbytes = nlines = 0;\n\tgettimeofday(&start, NULL);\n\n\twhile ((c = getchar()) != EOF) {\n\t\tif (write_header) {\n\t\t\tgettimeofday(&t, NULL);\n\t\t\tif (wrote_header)\n\t\t\t\tprintf(\"\\\" }\\n\");\n\t\t\tprintf(\"{ \"\n\t\t\t\t// Absolute time (s)\n\t\t\t\t\"\\\"atime\\\": %lld.%06d, \"\n\t\t\t\t// Relative time (s, from program start)\n\t\t\t\t\"\\\"rtime\\\": %.06lf, \"\n\t\t\t\t\"\\\"nlines\\\": %lu, \"\n\t\t\t\t\"\\\"nbytes\\\": %lu, \"\n\t\t\t\t\"\\\"data\\\": \\\"\",\n\t\t\t\t(long long)t.tv_sec,\n\t\t\t\t(int)t.tv_usec,\n\t\t\t\t(t.tv_sec - start.tv_sec) +\n\t\t\t\t(t.tv_usec - start.tv_usec) / 1e6,\n\t\t\t\tnlines,\n\t\t\t\tnbytes);\n\t\t\twrote_header = true;\n\t\t\twrite_header = false;\n\t\t}\n\t\tescape(c);\n\t\tnbytes++;\n\t\tif (c == '\\n') {\n\t\t\tnlines++;\n\t\t\twrite_header = true;\n\t\t}\n\t}\n\n\tif (wrote_header)\n\t\tprintf(\"\\\" }\\n\");\n\n\treturn 0;\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-parallel.1",
    "content": ".TH DGSH-PARALLEL 1 \"15 December 2016\"\n.\\\"\n.\\\" (C) Copyright 2016 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-parallel \\- Create a semi-homogeneous dgsh parallel processing block\n.SH SYNOPSIS\n\\fBdgsh-parallel\\fP\n[\\fB\\-d\\fP]\n\\fB\\-f\\fP \\fIfile\\fP |\n\\fB\\-l\\fP \\fIlist\\fP |\n\\fB\\-n\\fP \\fIn\\fP\n\\fIcommand ...\\fP\n.SH DESCRIPTION\n\\fIdgsh-parallel\\fP creates and executes a \\fIdgsh\\fP block\nthat invokes multiple times the specified command and its optional arguments.\nIf the command or its options include the \\fI{}\\fP string,\nthis is replaced by the numeric or string identifier associated with\neach invocation.\n.SH OPTIONS\n.IP \"\\fB\\-d\\fP\nAllows the debugging of the generated script, by leaving it in the\ntemporary directory and echoing its path on the standard error.\n.IP \"\\fB\\-f\\fP \\fIfile\\fP\"\nObtain string arguments from the specified file: one argument per line.\nOne command will be generated for each line in the file.\nEach command will have \\fI{}\\fP strings replaced with the contents of\nthe corresponding line.\n.IP \"\\fB\\-l\\fP \\fIlist\\fP\"\nObtain string arguments from the specified comma-separated list.\nOne command will be generated for each list element.\nEach command will have \\fI{}\\fP strings replaced with the corresponding\nelement.\n.IP \"\\fB\\-n\\fP \\fIn\\fP\"\nRun \\fIn\\fP instances of the command.\nEach command will have \\fI{}\\fP strings replaced with the command's\nordinal number, starting from 1.\n.SH EXAMPLES\n.PP\nCount in parallel the number of times each word appears in the specified\ninput file(s).\nThis sequence mirrors Hadoop's WordCount example.\n.ft C\n.nf\n# Scatter input\ndgsh-tee -s |\n# Run four instances of the command\n# Emulate Java's default StringTokenizer, sort, count\ndgsh-parallel -n 4 \"tr -s ' \\\\t\\\\n\\\\r\\\\f' '\\\\n' | sort | uniq -c\" |\n# Merge the four sorted counts\ndgsh-merge-sum '<|' '<|' '<|'\n.ft P\n.fi\n.SH \"SEE ALSO\"\n\\fIdgsh\\fP(1),\n\\fIdgsh-tee\\fP(1),\n.SH BUGS\nThe interface between the generated script and its invokers is currently\n(December 2016) being polished.\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>.\n"
  },
  {
    "path": "core-tools/src/dgsh-parallel.sh",
    "content": "#!/usr/bin/env bash\n#!dgsh\n#\n# Create and execute a semi-homongeneous dgsh parallel processing block\n#\n\n# Remove dgsh from path, so that commands aren't wrapped here\n# See http://stackoverflow.com/a/2108540/20520\n# PATH => /bin:.../libexec/dgsh:/sbin\nOPATH=\"$PATH\"\nWORK=:$PATH:\n# WORK => :/bin:.../libexec/dgsh:/sbin:\nREMOVE='[^:]*/libexec/dgsh'\nWORK=${WORK/:$REMOVE:/:}\n# WORK => :/bin:/sbin:\nWORK=${WORK%:}\nWORK=${WORK#:}\nPATH=$WORK\n# PATH => /bin:/sbin\n\n# Remove DGSH_IN, OUT so that commands don't negotiate\ntest \"$DGSH_IN\" && ODGSH_IN=\"$DGSH_IN\"\ntest \"$DGSH_OUT\" && ODGSH_OUT=\"$DGSH_OUT\"\nunset DGSH_IN\nunset DGSH_OUT\n\nusage()\n{\n  echo 'Usage: dgsh-parallel [-d] -n n|-f file|-l list command ...' 1>&2\n  exit 2\n}\n\n# Process flags\nwhile getopts 'df:l:n:' o; do\n  case \"$o\" in\n    d)\n      DEBUG=1\n      ;;\n    n)\n      n=\"$OPTARG\"\n      nspec=X$nspec\n      ;;\n    f)\n      file=\"$OPTARG\"\n      nspec=X$nspec\n      ;;\n    -l)\n      list=$(echo \"$OPTARG\" | sed 's/,/ /g')\n      nspec=X$nspec\n      ;;\n    *)\n      usage\n      ;;\n  esac\ndone\n\nshift $((OPTIND-1))\n\n\n# Ensure commands is specified\nif [ ! \"$1\" ] ; then\n  usage\nfi\n\n# Ensure exactly one sharding target is specified\nif [ ! \"$nspec\" ] || expr $nspec : .. >/dev/null ; then\n  usage\nfi\n\n# Ensure generated script is always removed\nSCRIPT=\"${TMP:-/tmp}/dgsh-parallel-$$\"\n\nif [ \"$DEBUG\" ] ; then\n  echo \"Script is $SCRIPT\" 1>&2\nelse\n  trap 'rm -rf \"$SCRIPT\"' 0\n  trap 'exit 2' 1 2 15\nfi\n\ncat >$SCRIPT <<EOF\n#!/usr/bin/env dgsh\n#\n# Automatically generated file from:\n# $0 $*\n#\n\n{{\nEOF\n\n\n# Generate list of nodes\nif [ \"$n\" ] ; then\n  for i in $(seq \"$n\") ; do\n    echo $i\n  done\nelif [ \"$list\" ] ; then\n  for i in $list ; do\n    echo \"$i\"\n  done\nelif [ \"$file\" ] ; then\n  cat \"$file\"\nelse\n  echo Internal error 1>&2\n  exit 2\nfi |\n# Escape sed(1) special characters\nsed 's/[&/\\\\]/\\\\&/g' |\n# Replace {} with the name of each node\nwhile IFS='' read -r node ; do\n  echo \"  $@\" | sed \"s/{}/$node/\"\ndone >>$SCRIPT\n\ncat >>$SCRIPT <<EOF\n}}\nEOF\n\n# Restore dgsh settings\nPATH=\"$OPATH\"\n# Remove DGSH_IN, OUT so that commands don't negotiate\ntest \"$ODGSH_IN\" && export DGSH_IN=\"$ODGSH_IN\"\ntest \"$ODGSH_OUT\" && export DGSH_OUT=\"$ODGSH_OUT\"\n\ndgsh $SCRIPT\n"
  },
  {
    "path": "core-tools/src/dgsh-pecho.c",
    "content": "#include <stdio.h>\t\t/* printf() */\n#include <stdlib.h>\t\t/* exit() */\n#include <unistd.h>\t\t/* getpagesize() */\n#include \"dgsh.h\"\n\nint\nmain(int argc, char *argv[])\n{\n\tint ps = getpagesize();\n\tchar buf[ps];\n\tint n = 1;\n\tint ninputs = -1;\n\tdgsh_negotiate(DGSH_HANDLE_ERROR, \"dgsh-pecho\", &ninputs,\n\t\t\tNULL, NULL, NULL);\n\n\tif (ninputs == 1) {\n\t\tn = read(STDIN_FILENO, buf, ps);\n\t\twhile (n) {\n\t\t\tprintf(\"%s\", buf);\n\t\t\tn = read(STDIN_FILENO, buf, ps);\n\t\t\tif (n < 0)\n\t\t\t\texit(1);\n\t\t}\n\t}\n\n\t++argv;\n\twhile (*argv) {\n\t\t(void)printf(\"%s\", *argv);\n\t\tif (*++argv)\n\t\t\tputchar(' ');\n\t}\n\n\tputchar('\\n');\n\n\treturn 0;\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-readval.1",
    "content": ".TH DGSH-READVAL 1 \"21 March 2013\"\n.\\\"\n.\\\" (C) Copyright 2013 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-readval \\- data store client\n.SH SYNOPSIS\n\\fBdgsh-readval\\fP\n[\\fB\\-c\\fP | \\fB-e\\fP | \\fB-l\\fP]\n[\\fB\\-nq\\fP]\n[\\fB\\-x\\fP]\n\\fB\\-s\\fP \\fIpath\\fP\n.SH DESCRIPTION\n\\fIdgsh-readval\\fP is a data store client.\nBy default it will communicate with the store specified through\nthe path to a Unix domain socket,\nask to read the last (final) record written to that store,\nand write the value on its standard output.\n.PP\n\\fIdgsh-readval\\fP is normally executed from within \\fIdgsh\\fP-generated scripts,\nrather than through end-user commands.\nThis manual page serves mainly to document its operation and\nthe flags that can be used in \\fIdgsh\\fP scripts when reading from stores.\n\n.SH OPTIONS\n.IP \"\\fB\\-c\\fP\nRead the current (rather than the last) value from the store.\nIf no complete record has been written into the store,\nthe operation will block until such a record is available.\n\n.IP \"\\fB\\-e\\fP\nRead the current or an empty value from the store.\nIf no complete record has been written into the store,\nthe operation will return an empty record, rather than block.\n\n.IP \"\\fB\\-l\\fP\nRead the last value from the store.\nThis is the default behavior of \\fIdgsh-readval\\fP.\nThe operation will block until the store's server (\\fIdgsh-writeval\\fP)\ndetermines that it has read the last record\nby detecting an end-of-file condition on its standard input.\n\n.IP \"\\fB\\-n\\fP\nDo not retry a failed connection to the store.\nBy default \\fIdgsh-readval\\fP will try to establish a connection to the\nstore every one second.\nThis behavior is designed to avoid failures due to race conditions between write stores\nthat are started asynchronously (in the background) and subsequent read\noperations from them.\n\n.IP \"\\fB\\-q\\fP\nAsk the write store (the corresponding \\fIdgsh-writeval\\fP process)\nto terminate its operation.\nNo value is read.\n\n.IP \"\\fB\\-x\\fP\nDo not participate in dgsh negotiation.\n\n.IP \"\\fB\\-s\\fP \\fIpath\\fP\"\nThis mandatory option must be used to specify the path of the Unix-domain socket\n\\fIdgsh-readval\\fP will connect to communicate with the store.\nThis is specified as a normal Unix file path,\ne.g. \\fC/tmp/myvalue\\fP.\n\n.SH \"SEE ALSO\"\n\\fIdgsh\\fP(1),\n\\fIdgsh-writeval\\fP(1)\n\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>\n"
  },
  {
    "path": "core-tools/src/dgsh-readval.c",
    "content": "/*\n * Copyright 2013 Diomidis Spinellis\n *\n * Communicate with the data store specified as a Unix-domain socket.\n * (User interface)\n * By default the command will read a value.\n * Calling it with the -q flag will send the data store a termination\n * command.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <err.h>\n#include <errno.h>\n#include <limits.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"dgsh.h\"\n#include \"negotiate.h\"\n#include \"kvstore.h\"\n#include \"dgsh-debug.h\"\n\nstatic const char *program_name;\n\nstatic void\nusage(void)\n{\n\tfprintf(stderr, \"Usage: %s [-c|e|l] [-n] [-q] [-x] -s path\\n\"\n\t\t\"-c\"\t\t\"\\tRead the current value from the store\\n\"\n\t\t\"-e\"\t\t\"\\tRead current value or empty from the store\\n\"\n\t\t\"-l\"\t\t\"\\tRead the last (before EOF) value from the store (default)\\n\"\n\t\t\"-n\"\t\t\"\\tDo not retry failed connection to write store\\n\"\n\t\t\"-q\"\t\t\"\\tAsk the write-end to quit\\n\"\n\t\t\"-x\"\t\t\"\\tDo not participate in dgsh negotiation\\n\"\n\t\t\"-s path\"\t\"\\tSpecify the socket to connect to\\n\",\n\t\tprogram_name);\n\texit(1);\n}\n\nint\nmain(int argc, char *argv[])\n{\n\tint ch;\n\tbool quit = false;\n\tchar cmd = 0;\n\tconst char *socket_path = NULL;\n\tbool retry_connection = true;\n\tbool should_negotiate = true;\n\tint ninputs = 0;\n\tint noutputs = 1;\n\n\tprogram_name = argv[0];\n\n\t/* Default if nothing else is specified */\n\tif (argc == 3)\n\t\tcmd = 'L';\n\n\twhile ((ch = getopt(argc, argv, \"celnqxs:\")) != -1) {\n\t\tswitch (ch) {\n\t\tcase 'c':\t/* Read current value */\n\t\t\tcmd = 'C';\n\t\t\tbreak;\n\t\tcase 'e':\t/* Read current or empty value */\n\t\t\tcmd = 'c';\n\t\t\tbreak;\n\t\tcase 'l':\t/* Read last value */\n\t\t\tcmd = 'L';\n\t\t\tbreak;\n\t\tcase 'n':\n\t\t\tretry_connection = false;\n\t\t\tbreak;\n\t\tcase 'q':\n\t\t\tquit = true;\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tsocket_path = optarg;\n\t\t\tbreak;\n\t\tcase 'x':\n\t\t\tshould_negotiate = false;\n\t\t\tbreak;\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\t}\n\targc -= optind;\n\targv += optind;\n\n\tif (argc != 0 || socket_path == NULL)\n\t\tusage();\n\n\tif (should_negotiate)\n\t\tdgsh_negotiate(DGSH_HANDLE_ERROR, program_name, &ninputs, &noutputs, NULL, NULL);\n\telse\n\t\tset_negotiation_complete();\n\n\tdgsh_send_command(socket_path, cmd, retry_connection, quit, STDOUT_FILENO);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-tee.1",
    "content": ".TH DGSH-TEE 1 \"13 April 2017\"\n.\\\"\n.\\\" (C) Copyright 2013-2017 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-tee \\- buffer, copy, permute, or distribute data from input sources to output sinks\n.SH SYNOPSIS\n\\fBdgsh-tee\\fP\n[\\fB\\-b\\fP \\fIbuffer-size\\fP]\n[\\fB\\-afIMs\\fP]\n[\\fB\\-i\\fP \\fIinput-file\\fP]\n[\\fB\\-o\\fP \\fIoutput-file\\fP]\n[\\fB\\-m\\fP \\fImemory-size\\fP]\n[\\fB\\-p\\fP \\fIo1,o2 ...\\fP]\n[\\fB\\-T\\fP \\fIdirectory\\fP]\n[\\fB\\-t\\fP \\fIcharacter\\fP]\n.SH DESCRIPTION\n\\fIdgsh-tee\\fP will read data from the specified sources and copy or distribute\nit to the specified sinks.\nIt resembles in its operation \\fItee\\fP(1) and \\fIcat\\fP(1),\nbut offers additional capabilities required for the operation of \\fIdgsh\\fP(1).\nIn contrast to these programs, \\fIdgsh-tee\\fP will buffer the data it handles,\nso it will never cause deadlock or starvation when one or more sources\nare unable to provide data or if sinks are unable to receive them.\nFurthermore, \\fIdgsh-tee\\fP can copy data from multiple sources to\nmultiple sinks, permute the data between sources and sinks, and\nalso distribute the data among the sinks.\n.PP\nWhen copying data from a few sources to a multiple of their number sinks,\nthe first input tuple will appear in the first sinks, and so on.\nAs an example, two sources \\fIa, b\\fP will appear in six sinks as\n\\fIa, b, a, b, a, b\\fP.\nWhen copying data from many sources to a fraction of their number sinks,\na tuple of sources equal to the number of sinks is output first,\nfollowed by a tuple of the next sinks, and so on.\nAs an example, six sources \\fa, b, c, d, e, f\\fP will appear in two\nsinks as \\fIa, c, e\\fP in the first sink and \\fIb, d, f\\fP in the\nsecond one.\nIn effect, the group of few sources or sinks is treated as a single\nunit to be scattered or sequentially concatenated.\n.PP\n\\fIdgsh-tee\\fP is normally executed within \\fIdgsh\\fP through wrappers\nthat replace the system-provided \\fItee\\fP and \\fIcat\\fP commands.\nThis manual page serves mainly to document its operation,\nto how it can be used in less common use cases, and\nto allow the creation of plug-compatible replacements\nimplementing different record types.\n\n.SH OPTIONS\n.IP \"\\fB\\-a\\fP\nOpen files subsequently specified with the \\fB-o\\fP option for appending.\n\n.IP \"\\fB\\-b\\fP \\fIbuffer-size\\fP\"\nSpecify the size of the buffer to use.\nThis is by default 1MB.\nBuffers are chained together when more space is required,\nso the main utility of this option is to decrease the buffer\nsize in memory-constrained environments.\nThe specified number can be suffixed with\n\\fBk\\fI, \\fBM\\fI, or \\fBG\\fI to specify the corresponding unit.\nThe specified buffer size must be less than the program's maximum memory size.\n\n.IP \"\\fB\\-f\\fP\nWhen the allocated memory size reaches the maximum memory threshold,\nstart using a temporary file for buffering the data.\nThis extends the amount of data that can be buffered to the\nspace available on disk.\nThe location of the temporary file follows the\n\\fItempnam\\fP(3) rules, and can be overridden through the\n.B -T\noption.\n\n.IP \"\\fB\\-I\\fP\"\nImplement input-side buffering.\nBy default \\fIdgsh-tee\\fP will buffer only as much input data,\nas is needed to avoid starving one of the specified sinks.\nIn doing so it may cause its input source to block\nwhile having data to write.\nWhen this option is enabled\n\\fIdgsh-tee\\fP will always read data if they are available\non the standard input,\nand will write that data to any (including zero) sinks that\ncan read it.\nThis can be useful in cases where a command with insufficient input\nbuffering,\nlike \\fIjoin\\fP(1), \\fIsort\\fP(1), or \\fIpaste\\fP(1),\nis gathering input from commands executing in parallel.\nIn such a case adding \\fIdgsh-tee\\fP with input side buffering\nenabled at the end of each data pipeline,\nwill increase the number of processes that can operate concurrently.\n\n.IP \"\\fB\\-i\\fP \\fIinput-file\\fP\"\nRead input from the specified source file, rather than the standard input.\nThe option can be provided multiple times to specify multiple files that\nwill be read sequentially.\nAll input files will be opened at the beginning of the program's operation\nin order to unblock the execution of asynchronous shell commands\nthat redirect their output to the corresponding named pipes.\nFurthermore, when input-side buffering is specified \\fB-I\\fP\ndata is read asynchronously from all specified input files.\n\n.IP \"\\fB\\-M\\fP\"\nProvide memory use statistics on termination.\nThis is mainly used for testing,\nto check against leaks of buffers.\n\n.IP \"\\fB\\-o\\fP \\fIoutput-file\\fP\"\nWrite copies of the input data to the specified sink file,\nrather than the standard output.\nThe option can be provided multiple times to specify multiple files\nwhere input data will be copied.\n\n.IP \"\\fB\\-m\\fP \\fImemory-size\\fP\"\nSpecify the maximum size of memory to allocate for buffers.\nThis is by default 256MB.\nWhen \\fIdgsh-tee\\fP exhausts this memory, it enters a state where it\nwaits for its output buffers drain, thus freeing allocated memory.\nThe specified number can be suffixed with\n\\fBk\\fI, \\fBM\\fI, or \\fBG\\fI to specify the corresponding unit.\nThe specified maximum memory size must be larger than the program's buffer size.\n\n.IP \"\\fB\\-p\\fP \\fIo1,o2 ...\\fP\"\nPermute the inputs to the specified outputs.\nThe comma-separated arguments \\fIo1,o2, ...\\fP\nspecify the number of the output channel (starting from 1)\nwhere the corresponding \\fIn\\fPth input channel will be sent.\nThus,\ninput 1 goes to output \\fIo1\\fP,\ninput 2 goes to output \\fIo2\\fP,\nand so on.\nAs an example a cross-permutation is specified with the argument \\fI-p 2,1\\fP.\n\n.IP \"\\fB\\-s\\fP\"\nScatter the input fairly across the sinks, rather than copying it to all.\nWhen this option is in effect,\nthe input data are divided into chunks of one or more lines,\nand each chunk is written only to a single sink.\nThis is useful for dividing the work among multiple processes operating\nin parallel.\n\n.IP \"\\fB\\-T\\fP \\fIdirectory\\fP\"\nSpecify the directory to use for storing the temporary file,\nwhen the specified maximum buffer memory size is exceeded.\n\n.IP \"\\fB\\-t\\fP \\fIchar\\fP\"\nUse \\fIchar\\fP as the record separator,\nBy default the record separator is a newline,\nAn empty (not missing) argument for the record separator\nwill make the record separator be the null character.\n\n.SH \"SEE ALSO\"\n\\fIdgsh\\fP(1)\n\\fItempnam\\fP(3)\n\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>\n"
  },
  {
    "path": "core-tools/src/dgsh-tee.c",
    "content": "/*\n * Copyright 2013 Diomidis Spinellis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#ifdef __linux__\n#define _XOPEN_SOURCE 500\t// pread pwrite\n#endif\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/select.h>\n#include <assert.h>\n#include <err.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <signal.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"dgsh.h\"\n#include \"dgsh-debug.h\"\n#include \"minmax.h\"\n\n#if defined(DEBUG_DATA)\n#define DATA_DUMP 1\n#else\n#define DATA_DUMP 0\n#endif\n\n/*\n * Data that can't be written is stored in a sequential pool of buffers,\n * each buffer_size long.\n * As more data is read the buffer pool with the pointers (buffers)\n * is continuously increased; there is no round-robin mechanism.\n * However, as data is written out to all sinks, the actual buffers are\n * freed, thus keeping memory consumption reasonable.\n */\n\nstatic int buffer_size = 1024 * 1024;\n\n/*\n * A buffer in the memory pool.\n */\nstruct pool_buffer {\n\tvoid *p;\t\t/* Memory allocated for it (b_memory) */\n\tenum {\n\t\ts_none,\t\t/* Stored nowhere */\n\t\ts_memory,\t/* Stored in memory */\n\t\ts_memory_backed,/* Stored in memory and backed to temporary file */\n\t\ts_file\t\t/* Stored in temporary file */\n\t} s; \t\t\t/* Where it is stored */\n};\n\n/*\n * A pool of buffers\n */\nstruct buffer_pool {\n\tstruct pool_buffer *buffers;\t/* A dynamically adjusted vector of buffers */\n\tint pool_size;\t\t\t/* Size of allocated pool_buffers vectors */\n\tint allocated_pool_end;\t\t/* The first buffer in the above pool that has not been allocated */\n\n\t/* Allocated bufffer information */\n\tint buffers_allocated, buffers_freed, max_buffers_allocated;\n\n\t/* Paging information */\n\tint buffers_paged_out, buffers_paged_in, pages_freed;\n\n\tint page_out_ptr;\t\t/* Pointer to first buffer to page out */\n\tint page_file_fd;\t\t/* File descriptor of temporary file used for paging buffer pool */\n\tint free_pool_begin;\t\t/* Start of freed area */\n};\n\n\n/* Construct a new buffer pool object */\nstatic struct buffer_pool *\nnew_buffer_pool(void)\n{\n\tstruct buffer_pool *bp;\n\n\tif ((bp = (struct buffer_pool *)malloc(sizeof(struct buffer_pool))) == NULL)\n\t\terr(1, NULL);\n\tbp->buffers = NULL;\n\tbp->pool_size = 0;\n\tbp->page_out_ptr = 0;\n\tbp->page_file_fd = -1;\n\tbp->free_pool_begin = 0;\n\n\tbp->allocated_pool_end = 0;\n\n\tbp->buffers_allocated = bp->buffers_freed = bp->max_buffers_allocated =\n\tbp->buffers_paged_out = bp->buffers_paged_in = bp->pages_freed = 0;\n\n\treturn bp;\n}\n\n/*\n * A buffer that is used for I/O.\n * It points to a part of a pool buffer.\n */\nstruct io_buffer {\n\tvoid *p;\t/* Memory pointer */\n\tsize_t size;\t/* Buffer size */\n};\n\n/* Maximum amount of memory to allocate. (Set through -S) */\nstatic unsigned long max_mem = 256 * 1024 * 1204;\n\n/* Scatter the output across the files, rather than copying it. */\nstatic bool opt_scatter = false;\n\n/*\n * When set, permute the inputs to the specified outputs\n * Ordinals and number of the destination outputs\n */\nstatic int *permute_dest = NULL;\nstatic int permute_n = 0;\n\n/* Use a temporary file for overflowing buffered data */\nstatic bool use_tmp_file = false;\n\n/* User-specified temporary directory */\nstatic char *opt_tmp_dir = NULL;\n\n/*\n * Split scattered data on blocks of specified size; otherwise on line boundaries\n * Currently there is no support for this option; a -l option should be added.\n */\n\nstatic bool block_len = 0;\n\n/* Set to true when we reach EOF on input */\nstatic bool reached_eof = false;\n\n/* Record terminator */\nstatic char rt = '\\n';\n\n/* Linked list of files we write to */\nstruct sink_info {\n\tstruct sink_info *next;\t/* Next list element */\n\tchar *name;\t\t/* Output file name */\n\tint fd;\t\t\t/* Output file descriptor */\n\toff_t pos_written;\t/* Position up to which written */\n\toff_t pos_to_write;\t/* Position up to which to write */\n\tbool active;\t\t/* True if this sink is still active */\n\tstruct source_info *ifp;/* Input file we read from */\n\tbool chain_last;\t/* True if last element in a group; Writing  (copy or scatter)\n\t\t\t\t   should not continue to next element */\n};\n\n/* Construct a new sink_info object */\nstatic struct sink_info *\nnew_sink_info(const char *name)\n{\n\tstruct sink_info *ofp;\n\n\tif ((ofp = (struct sink_info *)malloc(sizeof(struct sink_info))) == NULL)\n\t\terr(1, NULL);\n\tofp->name = name ? strdup(name) : NULL;\n\tofp->active = true;\n\tofp->pos_written = ofp->pos_to_write = 0;\n\tofp->next = NULL;\n\treturn ofp;\n}\n\n/* Linked list of files we read from */\nstruct source_info {\n\tstruct source_info *next;\t/* Next list element */\n\tchar *name;\t\t\t/* Input file name */\n\tint fd;\t\t\t\t/* Input file descriptor */\n\tstruct buffer_pool *bp;\t\t/* Buffers where pending input is stored */\n\toff_t source_pos_read;\t\t/* The position up to which all sinks have read data */\n\tbool reached_eof;\t\t/* True if we reached EOF for this source */\n\toff_t read_min_pos;\t\t/* Minimum position read by all sinks */\n\tbool active;\t\t\t/* True if this is a source that should be currently\n\t\t\t\t\t   read (rather than chained later on) */\n\tbool is_read;\t\t\t/* True if an active sink reads it */\n\tbool chain_last;\t\t/* True if reading should stop at this element rather\n\t\t\t\t\t   than continue to the next element */\n};\n\n/* Return the name of a source or sink */\n#define fp_name(fp) ((fp)->name ? (fp)->name : fd_name((fp)->fd))\nstatic char *\nfd_name(int fd)\n{\n\tstatic char buff[40];\n\n\tsprintf(buff, \"fd(%d)\", fd);\n\treturn buff;\n}\n\n\n\n/* Construct a new source_info object */\nstatic struct source_info *\nnew_source_info(const char *name)\n{\n\tstruct source_info *ifp;\n\n\tif ((ifp = (struct source_info *)malloc(sizeof(struct source_info))) == NULL)\n\t\terr(1, NULL);\n\tifp->name = name ? strdup(name) : NULL;\n\tifp->bp = new_buffer_pool();\n\tifp->source_pos_read = 0;\n\tifp->reached_eof = false;\n\tifp->next = NULL;\n\treturn ifp;\n}\n\n/*\n * States for the copying engine.\n * Two disjunct sets:\n * input side buffering (ib) and output side buffering (ob)\n * Input side buffering will always read input if it is available,\n * presenting an infinite output buffer to the upstream process.\n * The output-side buffering will read input only if at least one\n * active output buffer is empty.\n * The setting in effect is determined by the program's -I flag.\n *\n * States read_ib and read_ob have select return:\n * - if data is available for reading,\n * - if the process can write out data already read,\n * - not if the process can write to other fds\n *\n * States drain_ib and write_ob have select return\n * if the process can write to any fd.\n * Waiting on all output buffers (not only those with data)\n * is needed to avoid starvation of downstream processes\n * when no output is available.\n * If a program can accept data this process will then transition to\n * read_* to read more data.\n *\n * State drain_ob has select return only if the process can write out\n * data already read.\n *\n * See also the diagram tee-state.dot\n */\nenum state {\n\tread_ib,\t\t/* Must read input; write if data available */\n\tread_ob,\t\t/* As above, but don't transition to write */\n\tdrain_ib,\t\t/* Don't read input; write if possible */\n\tdrain_ob,\t\t/* Empty data buffers by writing */\n\twrite_ob,\t\t/* Write data, before reading */\n};\n\n/*\n * Return the total number of bytes required for storing all buffers\n * up to the specified memory pool\n */\nstatic unsigned long\nmemory_pool_size(struct buffer_pool *bp, int pool)\n{\n\treturn ((bp->buffers_allocated - bp->buffers_freed) + (pool - bp->allocated_pool_end + 1)) * buffer_size;\n}\n\n/* Write half of the allocated buffer pool to the temporary file */\nstatic void\npage_out(struct buffer_pool *bp)\n{\n\tif (bp->page_file_fd == -1) {\n\t\tchar *template;\n\n\t\t/*\n\t\t * Create a temporary file that will be deleted on exit.\n\t\t * The location follows tempnam rules (argument, TMPDIR,\n\t\t * P_tmpdir, /tmp), while the creation through mkstemp\n\t\t * avoids race conditions.\n\t\t */\n\t\tif ((template = tempnam(opt_tmp_dir, \"sg-\")) == NULL)\n\t\t\terr(1, \"Unable to obtain temporary file name\");\n\t\tif ((template = realloc(template, strlen(template) + 7)) == NULL)\n\t\t\terr(1, \"Error obtaining temporary file name space\");\n\t\tstrcat(template, \"XXXXXX\");\n\t\tif ((bp->page_file_fd = mkstemp(template)) == -1)\n\t\t\terr(1, \"Unable to create temporary file %s\", template);\n\t}\n\n\t/*\n\t * Page-out memory buffers from the pool, round-robin fashion,\n\t * starting from the oldest buffers.\n\t * This is good enough for the simple common case where one output fd is blocked.\n\t */\n\twhile (memory_pool_size(bp, bp->allocated_pool_end - 1) > max_mem / 2) {\n\t\tswitch (bp->buffers[bp->page_out_ptr].s) {\n\t\tcase s_memory:\n\t\t\tif (pwrite(bp->page_file_fd, bp->buffers[bp->page_out_ptr].p, buffer_size, (off_t)bp->page_out_ptr * buffer_size) != buffer_size)\n\t\t\t\terr(1, \"Write to temporary file failed\");\n\t\t\t/* FALLTHROUGH */\n\t\tcase s_memory_backed:\n\t\t\tDPRINTF(4, \"Page out buffer %d %p\", bp->page_out_ptr, bp->buffers[bp->page_out_ptr].p);\n\t\t\tbp->buffers[bp->page_out_ptr].s = s_file;\n\t\t\tfree(bp->buffers[bp->page_out_ptr].p);\n\t\t\tbp->buffers_freed++;\n\t\t\tbp->buffers_paged_out++;\n\t\t\tDPRINTF(4, \"Paged out buffer %d %p\", bp->page_out_ptr, bp->buffers[bp->page_out_ptr].p);\n\t\t\tbreak;\n\t\tcase s_file:\n\t\tcase s_none:\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tassert(false);\n\t\t}\n\t\tif (++bp->page_out_ptr == bp->allocated_pool_end)\n\t\t\tbp->page_out_ptr = 0;\n\t}\n}\n\n/*\n * Allocate memory for the specified pool member.\n * Return false if no such memory is available.\n */\nstatic bool\nallocate_pool_buffer(struct buffer_pool *bp, int pool)\n{\n\tstruct pool_buffer *b = &bp->buffers[pool];\n\n\tif ((b->p = malloc(buffer_size)) == NULL) {\n\t\tDPRINTF(4, \"Unable to allocate %d bytes for buffer %ld\", buffer_size, b - bp->buffers);\n\t\tbp->max_buffers_allocated = MAX(bp->buffers_allocated - bp->buffers_freed, bp->max_buffers_allocated);\n\t\treturn false;\n\t}\n\tb->s = s_memory;\n\tDPRINTF(4, \"Allocated buffer %ld to %p\", b - bp->buffers, b->p);\n\tbp->buffers_allocated++;\n\tbp->max_buffers_allocated = MAX(bp->buffers_allocated - bp->buffers_freed, bp->max_buffers_allocated);\n\treturn true;\n}\n\n\n/*\n * Ensure that the specified pool buffer is in memory\n */\nstatic void\npage_in(struct buffer_pool *bp, int pool)\n{\n\tstruct pool_buffer *b = &bp->buffers[pool];\n\n\tswitch (b->s) {\n\tcase s_memory_backed:\n\tcase s_memory:\n\t\tbreak;\n\tcase s_file:\n\t\t/* Good time to ensure that there will be page-in memory available */\n\t\tif (memory_pool_size(bp, bp->allocated_pool_end - 1) > max_mem)\n\t\t\tpage_out(bp);\n\t\tif (!allocate_pool_buffer(bp, pool))\n\t\t\terr(1, \"Out of memory paging-in buffer\");\n\t\tif (pread(bp->page_file_fd, b->p, buffer_size, (off_t)pool * buffer_size) != buffer_size)\n\t\t\terr(1, \"Read from temporary file failed\");\n\t\tbp->buffers_paged_in++;\n\t\tb->s = s_memory_backed;\n\t\tDPRINTF(4, \"Page in buffer %d\", pool);\n\t\tbreak;\n\tcase s_none:\n\tdefault:\n\t\tDPRINTF(4, \"Buffer %d has invalid storage %d\", pool, b->s);\n\t\tassert(false);\n\t\tbreak;\n\t}\n\n}\n\n/*\n * Allocate memory for the specified pool\n * If we're out of memory by reaching the user-specified limit\n * or a system's hard limit return false.\n * If sufficient memory is available return true.\n * buffers[pool] will then point to a buffer_size block of available memory.\n */\nstatic bool\nmemory_allocate(struct buffer_pool *bp, int pool)\n{\n\tint i, orig_pool_size;\n\tstruct pool_buffer *orig_buffers;\n\n\tif (pool < bp->allocated_pool_end)\n\t\treturn true;\n\n\tDPRINTF(4, \"Buffers allocated: %d Freed: %d\", bp->buffers_allocated, bp->buffers_freed);\n\t/* Check soft memory limit through allocated plus requested memory. */\n\tif (memory_pool_size(bp, pool) > max_mem) {\n\t\tif (use_tmp_file)\n\t\t\tpage_out(bp);\n\t\telse\n\t\t\treturn false;\n\t}\n\n\t/* Keep original values to undo on failure. */\n\torig_pool_size = bp->pool_size;\n\torig_buffers = bp->buffers;\n\t/* Resize bank, if needed. One iteration should suffice. */\n\twhile (pool >= bp->pool_size) {\n\t\tif (bp->pool_size == 0)\n\t\t\tbp->pool_size = 1;\n\t\telse\n\t\t\tbp->pool_size *= 2;\n\t\tif ((bp->buffers = realloc(bp->buffers, bp->pool_size * sizeof(struct pool_buffer))) == NULL) {\n\t\t\tDPRINTF(4, \"Unable to reallocate buffer pool bank\");\n\t\t\tbp->pool_size = orig_pool_size;\n\t\t\tbp->buffers = orig_buffers;\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/* Allocate buffer memory [allocated_pool_end, pool]. */\n\tfor (i = bp->allocated_pool_end; i <= pool; i++)\n\t\tif (!allocate_pool_buffer(bp, i)) {\n\t\t\tbp->allocated_pool_end = i;\n\t\t\treturn false;\n\t\t}\n\tbp->allocated_pool_end = pool + 1;\n\treturn true;\n}\n\n/*\n * Free a file-backed buffer at the specified pool location\n * by punching a hole to the file. This is a best effort\n * operation, as it is only supported on Linux.\n */\nstatic void\nbuffer_file_free(struct buffer_pool *bp, int pool)\n{\n#ifdef FALLOC_FL_PUNCH_HOLE\n\tstatic bool warned = false;\n\n\tif (fallocate(bp->page_file_fd, FALLOC_FL_PUNCH_HOLE, pool * buffer_size, buffer_size) < 0 &&\n\t    !warned) {\n\t\twarn(\"Failed to free temporary buffer space\");\n\t\twarned = true;\n\t}\n#endif\n\tbp->pages_freed++;\n}\n\n/*\n * Ensure that pool buffers from [0,pos) are free.\n */\nstatic void\nmemory_free(struct buffer_pool *bp, off_t pos)\n{\n\tint pool_end = pos / buffer_size;\n\tint i;\n\n\tDPRINTF(4, \"memory_free: pool=%p pos = %ld, begin=%d end=%d\",\n\t\tbp, (long)pos, bp->free_pool_begin, pool_end);\n\tfor (i = bp->free_pool_begin; i < pool_end; i++) {\n\t\tswitch (bp->buffers[i].s) {\n\t\tcase s_memory:\n\t\t\tfree(bp->buffers[i].p);\n\t\t\tbp->buffers_freed++;\n\t\t\tbreak;\n\t\tcase s_file:\n\t\t\tbuffer_file_free(bp, i);\n\t\t\tbreak;\n\t\tcase s_memory_backed:\n\t\t\tbuffer_file_free(bp, i);\n\t\t\tfree(bp->buffers[i].p);\n\t\t\tbp->buffers_freed++;\n\t\t\tbreak;\n\t\tcase s_none:\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tassert(false);\n\t\t\tbreak;\n\t\t}\n\t\tbp->buffers[i].s = s_none;\n\t\tDPRINTF(4, \"Freed buffer %d %p (pos = %ld, begin=%d end=%d)\",\n\t\t\ti, bp->buffers[i].p, (long)pos, bp->free_pool_begin, pool_end);\n\t\t#ifdef DEBUG\n\t\tbp->buffers[i].p = NULL;\n\t\t#endif\n\t}\n\tbp->free_pool_begin = pool_end;\n}\n\n/*\n * Set the buffer to write to for reading from a file from\n * position onward, ensuring that sufficient memory is allocated.\n * Return false if no memory is available.\n */\nstatic bool\nsource_buffer(struct source_info *ifp, /* OUT */ struct io_buffer *b)\n{\n\tint pool = ifp->source_pos_read / buffer_size;\n\tsize_t pool_offset = ifp->source_pos_read % buffer_size;\n\n\tif (!memory_allocate(ifp->bp, pool))\n\t\treturn false;\n\tif (ifp->bp->buffers[pool].s != s_memory)\n\t\tDPRINTF(4, \"ifp->bp->buffers[pool].s = 0x%x, pool=%d\\n\", ifp->bp->buffers[pool].s, pool);\n\tassert(ifp->bp->buffers[pool].s == s_memory);\n\tb->p = ifp->bp->buffers[pool].p + pool_offset;\n\tb->size = buffer_size - pool_offset;\n\tDPRINTF(4, \"Source buffer(%ld) returns pool %d(%p) o=%ld l=%ld a=%p\",\n\t\t(long)ifp->source_pos_read, pool, ifp->bp->buffers[pool].p, (long)pool_offset, (long)b->size, b->p);\n\treturn true;\n}\n\n/*\n * Return a buffer to read from for writing to a file from a position onward\n * When processing lines, b.size can be 0\n */\nstatic struct io_buffer\nsink_buffer(struct sink_info *ofp)\n{\n\tstruct io_buffer b;\n\tint pool = ofp->pos_written / buffer_size;\n\tsize_t pool_offset = ofp->pos_written % buffer_size;\n\tsize_t source_bytes = ofp->pos_to_write - ofp->pos_written;\n\n\tb.size = MIN(buffer_size - pool_offset, source_bytes);\n\tif (b.size == 0)\n\t\tb.p = NULL;\n\telse {\n\t\tif (ofp->ifp->bp->page_file_fd != -1)\n\t\t\tpage_in(ofp->ifp->bp, pool);\n\t\tb.p = ofp->ifp->bp->buffers[pool].p + pool_offset;\n\t}\n\tDPRINTF(4, \"Sink buffer(%ld-%ld) returns pool %d(%p) o=%ld l=%ld a=%p for input fd: %s\",\n\t\t(long)ofp->pos_written, (long)ofp->pos_to_write, pool, b.size ? ofp->ifp->bp->buffers[pool].p : NULL, (long)pool_offset, (long)b.size, b.p, fp_name(ofp->ifp));\n\treturn b;\n}\n\n/*\n * Return a pointer to read from for writing to a file from a position onward\n */\nstatic char *\nsink_pointer(struct buffer_pool *bp, off_t pos_written)\n{\n\tint pool = pos_written / buffer_size;\n\tsize_t pool_offset = pos_written % buffer_size;\n\n\tif (bp->page_file_fd != -1)\n\t\tpage_in(bp, pool);\n\treturn bp->buffers[pool].p + pool_offset;\n}\n\n/*\n * Return the size of a buffer region that can be read for the specified endpoints\n */\nstatic size_t\nsink_buffer_length(off_t start, off_t end)\n{\n\tsize_t pool_offset = start % buffer_size;\n\tsize_t source_bytes = end - start;\n\n\tDPRINTF(4, \"sink_buffer_length(%ld, %ld) = %ld\",\n\t\t(long)start, (long)end,  (long)MIN(buffer_size - pool_offset, source_bytes));\n\treturn MIN(buffer_size - pool_offset, source_bytes);\n}\n\n\n/* The result of the following read operation. */\nenum read_result {\n\tread_ok,\t/* Normal read */\n\tread_oom,\t/* Out of buffer memory */\n\tread_again,\t/* EAGAIN */\n\tread_eof,\t/* EOF (0 bytes read) */\n};\n\n/*\n * Read from the source into the memory buffer\n * Return the number of bytes read, or -1 on end of file.\n */\nstatic enum read_result\nsource_read(struct source_info *ifp)\n{\n\tint n;\n\tstruct io_buffer b;\n\n\tif (!source_buffer(ifp, &b)) {\n\t\tDPRINTF(4, \"Memory full\");\n\t\t/* Provide some time for the output to drain. */\n\t\treturn read_oom;\n\t}\n\tif ((n = read(ifp->fd, b.p, b.size)) == -1)\n\t\tswitch (errno) {\n\t\tcase EAGAIN:\n\t\t\tDPRINTF(4, \"EAGAIN on %s\", fp_name(ifp));\n\t\t\treturn read_again;\n\t\tdefault:\n\t\t\terr(3, \"Read from %s\", fp_name(ifp));\n\t\t}\n\tifp->source_pos_read += n;\n\tDPRINTF(4, \"Read %d out of %zu bytes from %s data=[%.*s]\", n, b.size, fp_name(ifp),\n\t\t(int)n * DATA_DUMP, (char *)b.p);\n\t/* Return -1 on EOF */\n\treturn n ? read_ok : read_eof;\n}\n\n/*\n * Allocate available read data to empty sinks that can be written to,\n * by adjusting their ifp, pos_written, and pos_to_write pointers.\n */\nstatic void\nallocate_data_to_sinks(fd_set *sink_fds, struct sink_info *files)\n{\n\tstruct sink_info *ofp;\n\tint available_sinks = 0;\n\toff_t pos_assigned = 0;\n\tsize_t available_data, data_per_sink;\n\tsize_t data_to_assign = 0;\n\tbool use_reliable = false;\n\n\t/* Easy case: distribute to all files. */\n\tif (!opt_scatter) {\n\t\tfor (ofp = files; ofp; ofp = ofp->next) {\n\t\t\t/* Advance to next input file, if required */\n\t\t\tif (ofp->pos_written == ofp->ifp->source_pos_read &&\n\t\t\t    ofp->ifp->reached_eof &&\n\t\t\t    !ofp->ifp->chain_last) {\n\t\t\t\tDPRINTF(4, \"%s(): advance to input file %s\\n\",\n\t\t\t\t\t\t__func__, fp_name(ofp->ifp));\n\t\t\t\tofp->ifp = ofp->ifp->next;\n\t\t\t\tofp->ifp->active = true;\n\t\t\t\tofp->pos_written = 0;\n\t\t\t}\n\t\t\tofp->pos_to_write = ofp->ifp->source_pos_read;\n\t\t}\n\t\treturn;\n\t}\n\n\t/*\n\t * Difficult case: fair scattering across available sinks\n\t * Thankfully here we only have a single input file\n\t */\n\n\t/* Determine amount of fresh data to write and number of available sinks. */\n\tfor (ofp = files; ofp; ofp = ofp->next) {\n\t\tpos_assigned = MAX(pos_assigned, ofp->pos_to_write);\n\t\tif (ofp->pos_written == ofp->pos_to_write && FD_ISSET(ofp->fd, sink_fds))\n\t\t\tavailable_sinks++;\n\t}\n\n\t/*\n\t * Ensure we operate in a continuous memory region by clamping\n\t * the length of the available data to terminate at the end of\n\t * the buffer.\n\t */\n\tavailable_data = sink_buffer_length(pos_assigned, files->ifp->source_pos_read);\n\n\tif (available_sinks == 0)\n\t\treturn;\n\n\t/* Assign data to sinks. */\n\tdata_per_sink = available_data / available_sinks;\n\tfor (ofp = files; ofp; ofp = ofp->next) {\n\t\t/* Move to next file if this has data to write, or isn't ready. */\n\t\tif (ofp->pos_written != ofp->pos_to_write || !FD_ISSET(ofp->fd, sink_fds))\n\t\t\tcontinue;\n\n\t\tDPRINTF(4, \"pos_assigned=%ld source_pos_read=%ld available_data=%ld available_sinks=%d data_per_sink=%ld\",\n\t\t\t(long)pos_assigned, (long)ofp->ifp->source_pos_read, (long)available_data, available_sinks, (long)data_per_sink);\n\t\t/* First file also gets the remainder bytes. */\n\t\tif (data_to_assign == 0)\n\t\t\tdata_to_assign = sink_buffer_length(pos_assigned,\n\t\t\t\tpos_assigned + data_per_sink + available_data % available_sinks);\n\t\telse\n\t\t\tdata_to_assign = data_per_sink;\n\t\t/*\n\t\t * Assign data_to_assign to *ofp (pos_written, pos_to_write),\n\t\t * and advance pos_assigned.\n\t\t */\n\t\tofp->pos_written = pos_assigned;\t\t/* Initially nothing has been written. */\n\t\tif (block_len == 0) {\t\t\t/* Write whole lines */\n\t\t\tif (available_data > buffer_size / 2 && !use_reliable) {\n\t\t\t\t/*\n\t\t\t\t * Efficient algorithm:\n\t\t\t\t * Assume that multiple lines appear in data_per_sink.\n\t\t\t\t * Go to a calculated boundary and scan backward to find\n\t\t\t\t * a new line.\n\t\t\t\t */\n\t\t\t\toff_t data_end = pos_assigned + data_to_assign - 1;\n\n\t\t\t\tfor (;;) {\n\t\t\t\t\tif (data_end <= pos_assigned) {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * If no newline was found with backward scanning\n\t\t\t\t\t\t * degenerate to the efficient algorithm. This will\n\t\t\t\t\t\t * scan further forward, and can defer writing the\n\t\t\t\t\t\t * last chunk, until more data is read.\n\t\t\t\t\t\t */\n\t\t\t\t\t\tuse_reliable = true;\n\t\t\t\t\t\tgoto reliable;\n\t\t\t\t\t}\n\t\t\t\t\tif (*sink_pointer(ofp->ifp->bp, data_end) == rt) {\n\t\t\t\t\t\tpos_assigned = data_end + 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdata_end--;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t/*\n\t\t\t\t * Reliable algorithm:\n\t\t\t\t * Scan forward for new lines until at least\n\t\t\t\t * data_per_sink are covered, or we reach the end of available data.\n\t\t\t\t * Keep a record of the last encountered newline.\n\t\t\t\t * This is used to backtrack when we scan past the end of the\n\t\t\t\t * available data.\n\t\t\t\t */\n\t\t\t\toff_t data_end, last_nl;\n\n\t\t\treliable:\n\t\t\t\tlast_nl = -1;\n\t\t\t\tdata_end = pos_assigned;\n\t\t\t\tfor (;;) {\n\t\t\t\t\tif (data_end >= ofp->ifp->source_pos_read) {\n\t\t\t\t\t\tif (last_nl != -1) {\n\t\t\t\t\t\t\tpos_assigned = last_nl + 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t/* No newline found in buffer; defer writing. */\n\t\t\t\t\t\t\tofp->pos_to_write = pos_assigned;\n\t\t\t\t\t\t\tDPRINTF(4, \"scatter to file[%s] no newline from %ld to %ld\",\n\t\t\t\t\t\t\t\tfp_name(ofp), (long)pos_assigned, (long)data_end);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (*sink_pointer(ofp->ifp->bp, data_end) == rt) {\n\t\t\t\t\t\tlast_nl = data_end;\n\t\t\t\t\t\tif (data_end - pos_assigned > data_per_sink) {\n\t\t\t\t\t\t\tpos_assigned = data_end + 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdata_end++;\n\t\t\t\t}\n\t\t\t}\n\t\t} else\n\t\t\tpos_assigned += data_to_assign;\n\t\tofp->pos_to_write = pos_assigned;\n\t\tDPRINTF(4, \"scatter to file[%s] pos_written=%ld pos_to_write=%ld data=[%.*s]\",\n\t\t\tfp_name(ofp), (long)ofp->pos_written, (long)ofp->pos_to_write,\n\t\t\t(int)(ofp->pos_to_write - ofp->pos_written) * DATA_DUMP, sink_pointer(ofp->ifp->bp, ofp->pos_written));\n\t}\n}\n\n\n/*\n * Write out from the memory buffer to the sinks where write will not block.\n * Free memory no more needed even by the write pointer farthest behind.\n * Return the number of bytes written.\n */\nstatic size_t\nsink_write(struct source_info *ifiles, fd_set *sink_fds, struct sink_info *ofiles)\n{\n\tstruct sink_info *ofp;\n\tstruct source_info *ifp;\n\tsize_t written = 0;\n\n\tfor (ifp = ifiles; ifp; ifp = ifp->next) {\n\t\tifp->read_min_pos = ifp->source_pos_read;\n\t\tifp->is_read = false;\n\t}\n\n\tallocate_data_to_sinks(sink_fds, ofiles);\n\tfor (ofp = ofiles; ofp; ofp = ofp->next) {\n\t\tDPRINTF(4, \"\\n%s(): try write to file %s\", __func__, fp_name(ofp));\n\t\tif (ofp->active && FD_ISSET(ofp->fd, sink_fds)) {\n\t\t\tint n;\n\t\t\tstruct io_buffer b;\n\n\t\t\tb = sink_buffer(ofp);\n\t\t\tDPRINTF(4, \"\\n%s(): sink buffer returned %d bytes to write\",\n\t\t\t\t\t__func__, (int)b.size);\n\t\t\tif (b.size == 0)\n\t\t\t\t/* Can happen when a line spans a buffer */\n\t\t\t\tn = 0;\n\t\t\telse {\n\t\t\t\tn = write(ofp->fd, b.p, b.size);\n\t\t\t\tif (n < 0)\n\t\t\t\t\tswitch (errno) {\n\t\t\t\t\t/* EPIPE is acceptable, for the sink's reader can terminate early. */\n\t\t\t\t\tcase EPIPE:\n\t\t\t\t\t\tofp->active = false;\n\t\t\t\t\t\t(void)close(ofp->fd);\n\t\t\t\t\t\tDPRINTF(4, \"EPIPE for %s\", fp_name(ofp));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase EAGAIN:\n\t\t\t\t\t\tDPRINTF(4, \"EAGAIN for %s\", fp_name(ofp));\n\t\t\t\t\t\tn = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\terr(2, \"Error writing to %s\", fp_name(ofp));\n\t\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tofp->pos_written += n;\n\t\t\t\t\twritten += n;\n\t\t\t\t}\n\t\t\t}\n\t\t\tDPRINTF(4, \"Wrote %d out of %zu bytes for file %s pos_written=%lu data=[%.*s]\",\n\t\t\t\tn, b.size, fp_name(ofp), (unsigned long)ofp->pos_written, (int)n * DATA_DUMP, (char *)b.p);\n\t\t}\n\t\tif (ofp->active) {\n\t\t\tofp->ifp->read_min_pos = MIN(ofp->ifp->read_min_pos, ofp->pos_written);\n\t\t\tofp->ifp->is_read = true;\n\t\t}\n\t}\n\n\t/* Free buffers all sinks have read */\n\tfor (ifp = ifiles; ifp; ifp = ifp->next) {\n\t\tmemory_free(ifp->bp, ifp->read_min_pos);\n\t\t/*\n\t\t * We are reading this source, so don't even think freeing\n\t\t * sources after this.\n\t\t */\n\t\tif (ifp->is_read)\n\t\t\tbreak;\n\t}\n\n\tDPRINTF(4, \"Wrote %zu total bytes\", written);\n\treturn written;\n}\n\nstatic void\nusage(const char *name)\n{\n\tfprintf(stderr, \"Usage %s [-b size] [-i file] [-IMs] [-o file] [-m size] [-t char]\\n\"\n\t\t\"-a\"\t\t\"\\tOpen output file(s) for appending\\n\"\n\t\t\"-b size\"\t\"\\tSpecify the size of the buffer to use (used for stress testing)\\n\"\n\t\t\"-f\"\t\t\"\\tOverflow buffered data into a temporary file\\n\"\n\t\t\"-I\"\t\t\"\\tInput-side buffering\\n\"\n\t\t\"-i file\"\t\"\\tGather input from specified file\\n\"\n\t\t\"-m size[k|M|G]\"\"\\tSpecify the maximum buffer memory size\\n\"\n\t\t\"-M\"\t\t\"\\tProvide memory use statistics on termination\\n\"\n\t\t\"-o file\"\t\"\\tScatter output to specified file\\n\"\n\t\t\"-p d1[,d2...]\"\t\"\\tPermute inputs to specified outputs\\n\"\n\t\t\"-s\"\t\t\"\\tScatter the input across the files, rather than copying it to all\\n\"\n\t\t\"-T dir\"\t\"\\tSpecify directory for storing temporary file\\n\"\n\t\t\"-t char\"\t\"\\tProcess char-terminated records (newline default)\\n\",\n\t\tname);\n\texit(1);\n}\n\n/*\n * Set the specified file descriptor to operate in non-blocking\n * mode.\n * It seems that even if select returns for a specified file\n * descriptor, performing I/O to it may block depending on the\n * amount of data specified.\n * See See http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html#tag_03_866\n */\nstatic void\nnon_block(int fd, const char *name)\n{\n\tint flags = fcntl(fd, F_GETFL, 0);\n\tif (flags < 0)\n\t\terr(2, \"Error getting flags for %s\", name);\n\tif (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)\n\t\terr(2, \"Error setting %s to non-blocking mode\", name);\n}\n\n/*\n * Show the arguments passed to select(2) in human-readable form\n * If check is true, abort the program if no bit is on\n */\nstatic void\nshow_select_args(const char *msg, fd_set *source_fds, struct source_info *ifiles, fd_set *sink_fds, struct sink_info *ofiles, bool check)\n{\n\t#ifdef DEBUG\n\tstruct sink_info *ofp;\n\tstruct source_info *ifp;\n\tint nbits = 0;\n\n\tfprintf(stderr, \"%s: \", msg);\n\tfor (ifp = ifiles; ifp; ifp = ifp->next)\n\t\tif (FD_ISSET(ifp->fd, source_fds)) {\n\t\t\tfprintf(stderr, \"%s \", fp_name(ifp));\n\t\t\tnbits++;\n\t\t}\n\tfor (ofp = ofiles; ofp; ofp = ofp->next)\n\t\tif (FD_ISSET(ofp->fd, sink_fds)) {\n\t\t\tfprintf(stderr, \"%s \", fp_name(ofp));\n\t\t\tnbits++;\n\t\t}\n\tfputc('\\n', stderr);\n\tif (check && nbits == 0)\n\t\tabort();\n\t#endif\n}\n\nstatic void\nshow_state(enum state state)\n{\n\t#ifdef DEBUG\n\tchar *s;\n\n\tswitch (state) {\n\tcase read_ib:\n\t\ts = \"read_ib\";\n\t\tbreak;\n\tcase read_ob:\n\t\ts = \"read_ob\";\n\t\tbreak;\n\tcase drain_ib:\n\t\ts = \"drain_ib\";\n\t\tbreak;\n\tcase drain_ob:\n\t\ts = \"drain_ob\";\n\t\tbreak;\n\tcase write_ob:\n\t\ts = \"write_ob\";\n\t\tbreak;\n\t}\n\tfprintf(stderr, \"State: %s\\n\", s);\n\t#endif\n}\n\n/* Parse the specified option as a size with a suffix and return its value. */\nstatic unsigned long\nparse_size(const char *progname, const char *opt)\n{\n\tchar size;\n\tunsigned long n;\n\n\tsize = 'b';\n\tif (sscanf(opt, \"%lu%c\", &n, &size) < 1)\n\t\tusage(progname);\n\tswitch (size) {\n\tcase 'B' : case 'b':\n\t\treturn n;\n\tcase 'K' : case 'k':\n\t\treturn n * 1024;\n\tcase 'M' : case 'm':\n\t\treturn n * 1024 * 1024;\n\tcase 'G' : case 'g':\n\t\treturn n * 1024 * 1024 * 1024;\n\tdefault:\n\t\tfprintf(stderr, \"Unknown size suffix: %c\\n\", size);\n\t\tusage(progname);\n\t}\n\t/* NOTREACHED */\n\treturn 0;\n}\n\n/*\n * Parse and validate a comma-separated list of integers setting the\n * variables permute_dest and permute_n.\n */\nstatic void\nparse_permute(char *s)\n{\n\tchar *p;\n\tchar *copy = strdup(s);\n\tint i;\n\n\tif (copy == NULL)\n\t\terrx(1, \"Out of memory for destination string\");\n\tDPRINTF(4, \"In parse_permute [%s]\", s);\n\tfor (p = strtok(copy, \",\"); p != NULL; p = strtok(NULL, \",\"))\n\t\tpermute_n++;\n\tfree(copy);\n\tif ((permute_dest = (int *)malloc(sizeof(int) * permute_n)) == NULL)\n\t\terrx(1, \"Out of memory for permutation destination\");\n\tfor (p = strtok(s, \",\"), i= 0; p != NULL; p = strtok(NULL, \",\"), i++) {\n\t\tpermute_dest[i] = atoi(p) - 1;\n\t\tif (permute_dest[i] < 0 || permute_dest[i] >= permute_n)\n\t\t\terrx(1, \"Illegal permutation destination [%s]\", s);\n\t}\n\tfor (i = 0; i < permute_n; i++)\n\t\tDPRINTF(4, \"%d = %d\", i, permute_dest[i]);\n\tDPRINTF(4, \"permute_n=%d\", permute_n);\n}\n\n/*\n * Return the input file corresponding to the specified\n * permuted output file number.\n */\nstatic struct source_info *\noutput_source(struct source_info *ifiles, int output_n)\n{\n\tint i, input_n = -1;\n\tstruct source_info *ifp;\n\n\t/* Find input file number */\n\tfor (i = 0; i < permute_n; i++)\n\t\tif (permute_dest[i] == output_n) {\n\t\t\tinput_n = i;\n\t\t\tbreak;\n\t\t}\n\tif (input_n == -1)\n\t\terrx(1, \"Unspecified output %d\", output_n + 1);\n\n\t/* Find input file pointer */\n\tfor (ifp = ifiles, i = 0; ifp; ifp = ifp->next, i++)\n\t\tif (i == input_n)\n\t\t\treturn ifp;\n\tassert(0);\n\treturn NULL;\n}\n\nstatic void\nmemory_stats(struct source_info *ifiles)\n{\n\tstruct source_info *ifp;\n\n\tfor (ifp = ifiles; ifp; ifp = ifp->next) {\n\t\tfprintf(stderr, \"Input file: %s\\n\", fp_name(ifp));\n\t\tfprintf(stderr, \"Buffers allocated: %d Freed: %d Maximum allocated: %d\\n\",\n\t\t\tifp->bp->buffers_allocated, ifp->bp->buffers_freed, ifp->bp->max_buffers_allocated);\n\t\tfprintf(stderr, \"Page out: %d In: %d Pages freed: %d\\n\",\n\t\t\tifp->bp->buffers_paged_out, ifp->bp->buffers_paged_in, ifp->bp->pages_freed);\n\t}\n}\n\n/*\n * Return true if an element with ordinal number n,\n * is the first element of a group in a series of groups\n * of group_size each.\n * Example: elements 0 and 3 in groups of size 3.\n */\nstatic bool\nfirst_in_group(int group_size, int n)\n{\n\treturn n % group_size == 0;\n}\n\n/*\n * Return true if an element with ordinal number n,\n * is the last element of a group in a series of groups\n * of group_size each.\n * Example: elements 2 and 5 in groups of size 3.\n */\nstatic bool\nlast_in_group(int group_size, int n)\n{\n\treturn (n + 1) % group_size == 0;\n}\n\nstruct list {\n\tstruct list *next;\n};\n\n/*\n * Transpose the elements of th specified linked list given\n * a notional new row length.  As an example, a list of 12 elements\n * with a row size of 3, would be transposed as follows.\n * 0 -> 4 -> 8 ->\n * 1 -> 5 -> 9 ->\n * 2 -> 6 -> 10 ->\n * 3 -> 7 -> 11\n * This function can handle arbitrary lists, as long\n * as the list's first element is the pointer to the\n * next one.\n */\nstatic void\nlist_transpose(struct list *lst, int row_length)\n{\n\tint i, count = 0;\n\tstruct list **vector, *p;\n\n\t/* Create a vector of pointers to list elements */\n\tfor (p = lst; p; p = p->next)\n\t\tcount++;\n\tvector = (struct list **)malloc(count * sizeof(struct list *));\n\tif (vector == NULL)\n\t\terr(1, NULL);\n\tfor (p = lst, i = 0; p; p = p->next, i++)\n\t\tvector[i] = p;\n\t/* Transpose notional rows into columns */\n\tfor (i = 0; i < count - row_length; i++)\n\t\tvector[i]->next = vector[i + row_length];\n\tfor (i = count - row_length; i < count - 1; i++)\n\t\tvector[i]->next = vector[(i + 1) % row_length];\n\tfree(vector);\n}\n\n\n\n/*\n * Chain input and output files into groups\n * by setting the chain_last of all I/O files\n * and the input file (ifp) field of all output\n * files.\n *\n * These are the possible cases and the corresponding\n * group chains.\n *\n * Read from many, output to one (cat)\n * A->B->C\t>\ta\n * All input files are chained together\n *\n * Read from one, output to many (tee)\n * A\t\t>\tb->c->d\n * All output files are chained together\n *\n * Read from many output to permuted many (perm)\n * A\t\t>\td\n * B\t\t>\tc\n * C\t\t>\tb\n * D\t\t>\ta\n * No files are chained\n *\n * Read from few, output to more (multipipe tee)\n * A\t\t>\ta->d->g\n * B\t\t>\tb->e->h\n * C\t\t>\tc->f->i\n * Output files are chained into groups\n *\n * Read from many, output to few (multipipe cat)\n * A->D->G\t>\ta\n * B->E->H\t>\tb\n * C->F->I\t>\tc\n * Input files are chained into groups\n *\n * Note that cat, tee, and perm are special cases of the multipipe ones\n * are are implemented as such.\n */\nstatic void\nchain_io_files(struct source_info *ifiles, struct sink_info *ofiles, bool permute)\n{\n\tint nin = 0, nout = 0;\n\tint group_size, n, i;\n\tstruct source_info *ifp;\n\tstruct sink_info *ofp;\n\n\tfor (ifp = ifiles; ifp; ifp = ifp->next)\n\t\tnin++;\n\tfor (ofp = ofiles; ofp; ofp = ofp->next)\n\t\tnout++;\n\n\tif (nin >= nout) {\n\t\t/*\n\t\t * Read from many output to few.\n\t\t * First input element in group is active.\n\t\t * Chain all but the last element of each input chain.\n\t\t * None of the outputs are chained.\n\t\t */\n\t\tif (nin % nout)\n\t\t\terrx(1, \"The number of inputs %d is not an exact multiple of the number of outputs %d\", nin, nout);\n\t\tgroup_size = nin / nout;\n\t\tlist_transpose((struct list *)ifiles, group_size);\n\t\tfor (ifp = ifiles, n = 0; ifp; ifp = ifp->next, n++) {\n\t\t\tifp->active = first_in_group(group_size, n);\n\t\t\tifp->chain_last = last_in_group(group_size, n);\n\t\t}\n\t\tfor (ofp = ofiles, ifp = ifiles, n = 0; ofp; ofp = ofp->next, n++) {\n\t\t\tofp->chain_last = true;\n\t\t\tofp->ifp = permute ? output_source(ifiles, n) : ifp;\n\t\t\tfor (i = 0; i <  group_size; i++)\n\t\t\t\tifp = ifp->next;\n\t\t}\n\t} else {\n\t\t/*\n\t\t * Read from few output to many.\n\t\t * All inputs are active, none is chained.\n\t\t * Chain all but the last element in the output chain.\n\t\t */\n\t\tif (nout % nin)\n\t\t\terrx(1, \"The number of outputs %d is not an exact multiple of the number of inputs %d\", nin, nout);\n\t\tgroup_size = nout / nin;\n\t\tassert(!permute);\n\t\tlist_transpose((struct list *)ofiles, group_size);\n\t\tfor (ifp = ifiles, n = 0; ifp; ifp = ifp->next, n++) {\n\t\t\tifp->active = true;\n\t\t\tifp->chain_last = true;\n\t\t}\n\t\tfor (ofp = ofiles, ifp = ifiles, n = 0; ofp; ofp = ofp->next, n++) {\n\t\t\tofp->ifp = ifp;\n\t\t\tif (last_in_group(group_size, n)) {\n\t\t\t\tifp = ifp->next;\n\t\t\t\tofp->chain_last = true;\n\t\t\t} else\n\t\t\t\tofp->chain_last = false;\n\t\t}\n\t}\n\tassert(ifp == NULL);\n\n\tDPRINTF(3, \"Input files\");\n\tfor (ifp = ifiles; ifp; ifp = ifp->next)\n\t\tDPRINTF(3, \"%p: chain_last=%d (%s)\", ifp, ifp->chain_last, ifp->name);\n\tDPRINTF(3, \"Output files\");\n\tfor (ofp = ofiles; ofp; ofp = ofp->next)\n\t\tDPRINTF(3, \"%p: chain_last=%d ifp=%p (%s)\", ofp, ofp->chain_last, ofp->ifp, ofp->name);\n}\n\nint\nmain(int argc, char *argv[])\n{\n\tint max_fd = 0;\n\tstruct sink_info *ofiles = NULL, *ofp;\n\tstruct sink_info **oend = &ofiles;\n\tstruct source_info *ifiles = NULL, *ifp;\n\tstruct source_info **iend = &ifiles;\n\tstruct source_info *front_ifp;\t/* To keep output sequential, never output past this one */\n\tint ch;\n\tconst char *progname = argv[0];\n\tenum state state = read_ob;\n\tbool opt_memory_stats = false;\n\tbool opt_append = false;\n\n\twhile ((ch = getopt(argc, argv, \"ab:fIi:Mm:o:p:S:sTt:\")) != -1) {\n\t\tswitch (ch) {\n\t\tcase 'a':\n\t\t\topt_append = true;\n\t\t\tbreak;\n\t\tcase 'b':\n\t\t\tbuffer_size = (int)parse_size(progname, optarg);\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tuse_tmp_file = true;\n\t\t\tbreak;\n\t\tcase 'I':\n\t\t\tstate = read_ib;\n\t\t\tbreak;\n\t\tcase 'i':\t/* Specify input file */\n\t\t\tifp = new_source_info(optarg);\n\n\t\t\tif ((ifp->fd = open(optarg, O_RDONLY)) < 0)\n\t\t\t\terr(2, \"Error opening %s\", optarg);\n\t\t\tmax_fd = MAX(ifp->fd, max_fd);\n\t\t\tnon_block(ifp->fd, fp_name(ifp));\n\t\t\t/* Add file at the end of the linked list */\n\t\t\t*iend = ifp;\n\t\t\tiend = &ifp->next;\n\t\t\tbreak;\n\t\tcase 'm':\n\t\t\tmax_mem = parse_size(progname, optarg);\n\t\t\tbreak;\n\t\tcase 'M':\t/* Provide memory use statistics on termination */\n\t\t\topt_memory_stats = true;\n\t\t\tbreak;\n\t\tcase 'o':\t/* Specify output file */\n\t\t\tofp = new_sink_info(optarg);\n\t\t\tif ((ofp->fd = open(optarg,\n\t\t\t\t\t(opt_append ? O_APPEND : 0) |\n\t\t\t\t\tO_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)\n\t\t\t\terr(2, \"Error opening %s\", optarg);\n\t\t\tmax_fd = MAX(ofp->fd, max_fd);\n\t\t\tnon_block(ofp->fd, fp_name(ofp));\n\t\t\t/* Add file at the end of the linked list */\n\t\t\t*oend = ofp;\n\t\t\toend = &ofp->next;\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tparse_permute(optarg);\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\topt_scatter = true;\n\t\t\tbreak;\n\t\tcase 'T':\n\t\t\topt_tmp_dir = optarg;\n\t\t\tbreak;\n\t\tcase 't':\t/* Record terminator */\n\t\t\t/* We allow \\0 as rt */\n\t\t\tif (strlen(optarg) > 1)\n\t\t\t\tusage(progname);\n\t\t\trt = *optarg;\n\t\t\tbreak;\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage(progname);\n\t\t}\n\t}\n\targc -= optind;\n\targv += optind;\n\n\tif (argc)\n\t\tusage(progname);\n\n\t/* dgsh */\n\tint j = 0;\n\tint noutputfds;\n\tint *outputfds;\n\tint ninputfds;\n\tint *inputfds;\n\tchar *name;\n\n\tif (permute_n) {\n\t\tninputfds = noutputfds = permute_n;\n\t\tname = \"perm\";\n\t} else {\n\t\tchar *in, *out;\n\n\t\t/* No stdin or stdout, if these have been specified via args */\n\t\tninputfds = ifiles ? 0 : -1;\n\t\tnoutputfds = ofiles ? 0 : -1;\n\n\t\t/* Heuristic to determine name */\n\t\tin = getenv(\"DGSH_IN\");\n\t\tif (in && *in == '0')\n\t\t\tin = NULL;\n\t\tout = getenv(\"DGSH_OUT\");\n\t\tif (out && *out == '0')\n\t\t\tout = NULL;\n\t\tif (in && !out)\n\t\t\tname = \"cat\";\n\t\telse if (!in && out)\n\t\t\tname = \"tee\";\n\t\telse\n\t\t\tname = \"dgsh-tee\";\n\t}\n\n\n\n\tDPRINTF(3, \"Calling negotiate in=%d out=%d\", ninputfds, noutputfds);\n\tdgsh_negotiate(DGSH_HANDLE_ERROR, name, &ninputfds, &noutputfds, &inputfds, &outputfds);\n\tDPRINTF(3, \"nin=%d nout=%d\", ninputfds, noutputfds);\n\tassert(noutputfds >= 0);\n\tassert(ninputfds >= 0);\n\n\tif (permute_n && permute_n != ninputfds)\n\t\terrx(1, \"The number of inputs %d is not equal to the specified permuted outputs %d\", ninputfds, permute_n);\n\tif (permute_n && permute_n != noutputfds)\n\t\terrx(1, \"The number of outputs %d is not equal to the specified permuted outputs %d\", noutputfds, permute_n);\n\n\tfor (j = 0; j < noutputfds; j++) {\n\t\tDPRINTF(3, \"New ofp assigned fd %d\", outputfds[j]);\n\t\tif (j == 0) {\n\t\t\tofp = new_sink_info(\"standard output\");\n\t\t\tofp->fd = STDOUT_FILENO;\n\t\t} else {\n\t\t\tofp = new_sink_info(NULL);\n\t\t\tofp->fd = outputfds[j];\n\t\t}\n\t\tmax_fd = MAX(ofp->fd, max_fd);\n\t\tnon_block(ofp->fd, fp_name(ofp));\n\t\t/* Add file at the end of the linked list */\n\t\t*oend = ofp;\n\t\toend = &ofp->next;\n\t}\n\n\tfor (j = 0; j < ninputfds; j++) {\n\t\tDPRINTF(3, \"New ifp assigned fd %d\", inputfds[j]);\n\t\tif (j == 0) {\n\t\t\tifp = new_source_info(\"standard input\");\n\t\t\tifp->fd = STDIN_FILENO;\n\t\t} else {\n\t\t\tifp = new_source_info(NULL);\n\t\t\tifp->fd = inputfds[j];\n\t\t}\n\t\tmax_fd = MAX(ifp->fd, max_fd);\n\t\tnon_block(ifp->fd, fp_name(ifp));\n\t\t/* Add file at the end of the linked list */\n\t\t*iend = ifp;\n\t\tiend = &ifp->next;\n\t}\n\n\tif (buffer_size > max_mem)\n\t\terrx(1, \"Buffer size %d is larger than the program's maximum memory limit %lu\", buffer_size, max_mem);\n\n\tif (opt_scatter && ifiles && ifiles->next)\n\t\terrx(1, \"Scattering not supported with more than one input file\");\n\n\tif (opt_scatter && permute_n)\n\t\terrx(1, \"Scattering and permutation cannot be used together\");\n\n\tif (ofiles == NULL) {\n\t\t/* Output to stdout */\n\t\tofp = new_sink_info(\"standard output\");\n\t\tofp->fd = STDOUT_FILENO;\n\t\tmax_fd = MAX(ofp->fd, max_fd);\n\t\tnon_block(ofp->fd, fp_name(ofp));\n\t\tofp->next = ofiles;\n\t\tofiles = ofp;\n\t}\n\n\tif (ifiles == NULL) {\n\t\t/* Input from stdin */\n\t\tifp = new_source_info(\"standard input\");\n\t\tifp->fd = STDIN_FILENO;\n\t\tmax_fd = MAX(ifp->fd, max_fd);\n\t\tnon_block(ifp->fd, fp_name(ifp));\n\t\tifp->next = ifiles;\n\t\tifiles = ifp;\n\t}\n\n\t/* We will handle SIGPIPE explicitly when calling write(2). */\n\tsignal(SIGPIPE, SIG_IGN);\n\n\tfront_ifp = ifiles;\n\tchain_io_files(ifiles, ofiles, permute_n != 0);\n\n\t/* Copy source to sink without allowing any single file to block us. */\n\tfor (;;) {\n\t\tfd_set source_fds;\n\t\tfd_set sink_fds;\n\t\tint fd_set_count = 0;\n\n\t\tshow_state(state);\n\t\t/* Set the fd's we're interested to read/write; close unneeded ones. */\n\t\tFD_ZERO(&source_fds);\n\t\tFD_ZERO(&sink_fds);\n\n\t\tif (!reached_eof)\n\t\t\tswitch (state) {\n\t\t\tcase read_ib:\n\t\t\t\tfor (ifp = front_ifp; ifp; ifp = ifp->next)\n\t\t\t\t\tif (!ifp->reached_eof) {\n\t\t\t\t\t\tFD_SET(ifp->fd, &source_fds);\n\t\t\t\t\t\tfd_set_count += 1;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase read_ob:\n\t\t\t\tfor (ifp = front_ifp; ifp; ifp = ifp->next)\n\t\t\t\t\tif (ifp->active && !ifp->reached_eof) {\n\t\t\t\t\t\tFD_SET(ifp->fd, &source_fds);\n\t\t\t\t\t\tfd_set_count += 1;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\tfor (ofp = ofiles; ofp; ofp = ofp->next)\n\t\t\tif (ofp->active) {\n\t\t\t\tswitch (state) {\n\t\t\t\tcase read_ib:\n\t\t\t\tcase read_ob:\n\t\t\t\tcase drain_ob:\n\t\t\t\t\tDPRINTF(4, \"Check active file[%s] pos_written=%ld pos_to_write=%ld\",\n\t\t\t\t\t\tfp_name(ofp), (long)ofp->pos_written, (long)ofp->pos_to_write);\n\t\t\t\t\tif (ofp->pos_written < ofp->pos_to_write) {\n\t\t\t\t\t\tFD_SET(ofp->fd, &sink_fds);\n\t\t\t\t\t\tfd_set_count += 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase drain_ib:\n\t\t\t\tcase write_ob:\n\t\t\t\t\tFD_SET(ofp->fd, &sink_fds);\n\t\t\t\t\tfd_set_count += 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\tif (fd_set_count != 0) {\n\t\t\t/* Block until we can read or write. */\n\t\t\tshow_select_args(\"Entering select\", &source_fds, ifiles, &sink_fds, ofiles, true);\n\t\t\tif (select(max_fd + 1, &source_fds, &sink_fds, NULL, NULL) < 0)\n\t\t\t\terr(3, \"select\");\n\t\t\tshow_select_args(\"Select returned\", &source_fds, ifiles, &sink_fds, ofiles, false);\n\n\t\t\t/* Write to all file descriptors that accept writes. */\n\t\t\tif (sink_write(ifiles, &sink_fds, ofiles) > 0) {\n\t\t\t\t/*\n\t\t\t\t* If we wrote something, we made progress on the\n\t\t\t\t* downstream end.  Loop without reading to avoid\n\t\t\t\t* allocating excessive buffer memory.\n\t\t\t\t*/\n\t\t\t\tif (state == drain_ob)\n\t\t\t\t\tstate = write_ob;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (reached_eof) {\n\t\t\tint active_fds = 0;\n\n\t\t\tfor (ofp = ofiles; ofp; ofp = ofp->next)\n\t\t\t\tif (ofp->active) {\n\t\t\t\t\tif (ofp->pos_written < ofp->pos_to_write)\n\t\t\t\t\t\tactive_fds++;\n\t\t\t\t\telse {\n\t\t\t\t\t\tDPRINTF(3, \"Retiring file %s pos_written=pos_to_write=%ld source_pos_read=%ld\",\n\t\t\t\t\t\t\tfp_name(ofp), (long)ofp->pos_written, (long)ofp->ifp->source_pos_read);\n\t\t\t\t\t\t/* No more data to write; close fd to avoid deadlocks downstream. */\n\t\t\t\t\t\tif (close(ofp->fd) == -1)\n\t\t\t\t\t\t\terr(2, \"Error closing %s\", fp_name(ofp));\n\t\t\t\t\t\tofp->active = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tif (active_fds == 0) {\n\t\t\t\t/* If no read possible, and no writes pending, terminate. */\n\t\t\t\tif (opt_memory_stats)\n\t\t\t\t\tmemory_stats(ifiles);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t * Note that we never reach this point after a successful write.\n\t\t * See the continue statement above.\n\t\t */\n\t\tswitch (state) {\n\t\tcase read_ib:\n\t\t\t/* Read, if possible; set global reached_eof if all have reached it */\n\t\t\treached_eof = true;\n\t\t\tfor (ifp = front_ifp; ifp; ifp = ifp->next) {\n\t\t\t\tif (FD_ISSET(ifp->fd, &source_fds))\n\t\t\t\t\tswitch (source_read(ifp)) {\n\t\t\t\t\tcase read_eof:\n\t\t\t\t\t\tifp->reached_eof = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase read_oom:\t/* Cannot fullfill promise to never block source, so bail out. */\n\t\t\t\t\t\terrx(1, \"Out of memory with input-side buffering specified\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase read_ok:\n\t\t\t\t\tcase read_again:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\tif (!ifp->reached_eof)\n\t\t\t\t\treached_eof = false;\n\t\t\t}\n\t\t\tif (reached_eof)\n\t\t\t\tstate = drain_ib;\n\t\t\tbreak;\n\t\tcase read_ob:\n\t\t\t/* Read, from possible sources; set global reached_eof if all have reached it */\n\t\t\treached_eof = true;\n\t\t\tfor (ifp = front_ifp; ifp; ifp = ifp->next) {\n\t\t\t\tif (!ifp->active)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (FD_ISSET(ifp->fd, &source_fds))\n\t\t\t\t\tswitch (source_read(ifp)) {\n\t\t\t\t\tcase read_eof:\n\t\t\t\t\t\tifp->reached_eof = true;\n\t\t\t\t\t\tifp->active = false;\n\t\t\t\t\t\tif (!ifp->chain_last)\n\t\t\t\t\t\t\tifp->next->active = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase read_again:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase read_oom:\t/* Allow buffers to empty. */\n\t\t\t\t\t\tstate = drain_ob;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase read_ok:\n\t\t\t\t\t\tstate = write_ob;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\tif (!ifp->reached_eof)\n\t\t\t\t\treached_eof = false;\n\t\t\t}\n\t\t\tif (reached_eof)\n\t\t\t\tstate = drain_ib;\n\t\t\tbreak;\n\t\tcase drain_ib:\n\t\t\tbreak;\n\t\tcase drain_ob:\n\t\t\tif (reached_eof)\n\t\t\t\tstate = write_ob;\n\t\t\telse\n\t\t\t\tstate = read_ob;\n\t\t\tbreak;\n\t\tcase write_ob:\n\t\t\tif (!reached_eof)\n\t\t\t\tstate = read_ob;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-w.c",
    "content": "#include <assert.h>\t// assert()\n#include <math.h>\t// M_PI, pow()\n#include <complex.h>\t// I, cexp(), cpow()\n#include <stdio.h>\t// DPRINTF\n#include <stdlib.h>\t// atoi()\n#include <err.h>\t// errx()\n#include <unistd.h>\t// read(), write()\n#include <string.h>\t// memcpy()\n\n#include \"dgsh.h\"\n#include \"dgsh-debug.h\"\n\n#if !defined(HAVE_CPOW)\n#include \"../../unix-tools/cpow.c\"\n#endif\n\nvoid\nread_number(int fd, long double *x, long double complex *xc)\n{\n\tchar buf[sizeof(long double complex) + 5];\t// \\n\\0\n\tchar real[sizeof(long double)];\n\tchar imag[sizeof(long double)];\n\tint rd_size;\n\n\t// Read input: 2 float values\n\trd_size = read(fd, buf, sizeof(buf));\n\tif (rd_size == -1)\n\t\terr(1, \"write failed\");\n\tDPRINTF(4, \"Read %zu characters, long double size: %zu, long double complex size: %zu\",\n\t\t\trd_size, sizeof(long double), sizeof(long double complex));\n\tif (rd_size == sizeof(long double)) {\n\t\tmemcpy(x, buf, sizeof(*x));\n\t\tDPRINTF(4, \"Read input x: %.10Lf\", *x);\n\t} else {\n\t\tsscanf(buf, \"%s %s\", real, imag);\n\t\t*xc = atof(real) + atof(imag)*I;\n\t\tDPRINTF(4, \"##xc: %.10f + %.10fi (read %zu characters)\\n\",\n\t\t\t\tcreal(*xc), cimag(*xc), rd_size);\n\t}\n}\n\nvoid\nwrite_number(int fd, long double complex y)\n{\n\tchar buf[sizeof(long double complex)];\n\tint wr_size;\n\n\t// Write output: 2 float values\n\tmemset(buf, 0, sizeof(buf));\n\tsnprintf(buf, sizeof(buf), \"%.10f %.10fi\", creal(y), cimag(y));\n\tDPRINTF(4, \"##buf(y): %s, len: %d\", buf, strlen(buf));\n\twr_size = write(fd, buf, sizeof(buf));\n\tif (wr_size == -1)\n\t\terr(1, \"write failed\");\n\tDPRINTF(4, \"##y: %.10f + %.10fi (wrote %zu characters)\\n\",\n\t\t\tcreal(y), cimag(y), wr_size);\n}\n\nint\nmain(int argc, char** argv)\n{\n\tint noutputfds = 2;\n\tint *outputfds = NULL;\n\tint ninputfds = 2;\n\tint *inputfds = NULL;\n\tlong double x1 = -1.0, x2 = -1.0;\n\tlong double complex xc1, xc2;\n\tlong double complex y1, y2, w, wmn;\n\tsize_t wr_size;\n\tchar negotiation_title[10];\n\tint s;\t// stage (stage=1,2,3)\n\tint m;\t// 2^stage\n\tint n;\t// nth root of unity\n\n\tassert(argc == 3);\n\ts = atoi(argv[1]);\n\tm = pow(2, s);\n\tn = atoi(argv[2]);\n\n\tsnprintf(negotiation_title, sizeof(negotiation_title),\n\t\t\t\"%s %s %s\", argv[0], argv[1], argv[2]);\n\tdgsh_negotiate(DGSH_HANDLE_ERROR, negotiation_title, &ninputfds,\n\t\t\t&noutputfds, &inputfds, &outputfds);\n\tassert(ninputfds == 2);\n\tassert(noutputfds == 2);\n\n\tread_number(inputfds[0], &x1, &xc1);\n\tread_number(inputfds[1], &x2, &xc2);\n\n\t// Calculate\n\tw = 2 * M_PI * I / m;\n\twmn = cpow(cexp(w), n);\n\tDPRINTF(4, \"w: %.10f + %.10fi\", creal(w), cimag(w));\n\tDPRINTF(4, \"m: %d, n: %d, wmn: %.10f + %.10fi\\n\",\n\t\t\tm, n, creal(wmn), cimag(wmn));\n\tif (x1 == -1.0 && x2 == -1.0) {\n\t\ty1 = xc1 + wmn * xc2;\n\t\ty2 = xc1 - wmn * xc2;\n\t} else {\n\t\ty1 = x1 + wmn * x2;\n\t\ty2 = x1 - wmn * x2;\n\t}\n\n\twrite_number(outputfds[0], y1);\n\twrite_number(outputfds[1], y2);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-wrap.1",
    "content": ".TH DGSH-WRAP 1 \"18 August 2017\"\n.\\\"\n.\\\" (C) Copyright 2016-2017 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-wrap \\- allow any program to participate in an dgsh pipeline\n.SH SYNOPSIS\n\\fBdgsh-wrap\\fP\n[\\fB-S\\fP]\n[\\fB-i\\fP \\fB0\\fP|\\fBa\\fP]\n[\\fB-o\\fP \\fB0\\fP|\\fBa\\fP]\n[\\fB-eIO\\fP]\n\\fIprogram\\fP [\\fIprogram-arguments\\fP ...]\n\n#!/usr/libexec/dgsh/\\fBdgsh-wrap\\fP\n\\fB-s\\fP\n[\\fB-i\\fP \\fB0\\fP|\\fBa\\fP]\n[\\fB-o\\fP \\fB0\\fP|\\fBa\\fP]\n[\\fB-eIO\\fP] [\\fIprogram-arguments\\fP ...]\n\n\\fBdgsh-wrap\\fP\n[\\fB-Ss\\fP]\n\\fB-x\\fP\n\\fIprogram\\fP [\\fIprogram-arguments\\fP ...]\n\n.SH DESCRIPTION\n\\fIdgsh-wrap\\fP takes as arguments an absolute path or the name\nof a program to execute and its arguments.\nIt will participate in the \\fIdgsh\\fP negotiation process,\nand then execute the specified program connected to the negotiated\ninput and output pipes.\nIf the program is not specified through an absolute path,\nit will be executed by searching the existing path,\nexcluding from it elements ending in \\fIdgsh\\fP\n(where programs already wrapped with \\fIdgsh-wrap\\fP may reside).\n.PP\nArguments specified as \\fI<|\\fP are presented as additional\ninput channels and\narguments specified as \\fI>|\\fP are presented as additional\noutput channels.\nBoth are suitably replaced by named file descriptor paths\nwhen the command is invoked.\n.PP\nIn the context of a \\fIdgsh\\fP process graph, \\fIdgsh(1)\\fP automatically\ninvokes \\fIdgsh-wrap\\fP to allow non-dgsh compatible commands to participate\nin the negotiation procedure.\nFurthermore, the \\fIdgsh\\fP installation process sets up many POSIX programs\nwrapped with \\fIdgsh-wrap\\fP in order to communicate their particular\nI/O requirements.\n\n.SH OPTIONS\n.IP \"\\fB\\-e\\fP\nReplace \\fI<|\\fP and \\fI>|\\fP strings embedded within arguments,\nwith names of input file descriptor paths.\nBy default, only standalone arguments are thus replaced.\n\n.IP \"\\fB\\-i\\fP \\fB0\\fP|\\fBa\\fP\nSpecify the wrapped program's number of input channels.\nThe \\fB0\\fP character specifies that the program does not read any input.\nThe \\fBa\\fP character specifies that the program can read an arbitrary\nnumber of input streams;\nthese will be automatically supplied by \\fIdgsh-wrap\\fP as file descriptor\ncommand line arguments.\n\n.IP \"\\fB\\-I\\fP\nDo not include the standard input to the command line arguments,\nwhen replacing \\fI<|\\fP arguments with names of input file descriptor paths.\nThis will result in the standard input becoming available to the\ncommand as its standard input, rather than as a command line argument.\nWithout this option, the first path with be \\fI/dev/fd/0\\fP.\nWhen this option is given, the program will require one input channel\nmore than those specified by the \\fI<|\\fP arguments.\n\n.IP \"\\fB\\-o\\fP \\fB0\\fP|\\fBa\\fP\nSpecify the wrapped program's number of output channels.\nThe \\fB0\\fP character specifies that the program does not produce any output.\nThe \\fBa\\fP character specifies that the program can write to an arbitrary\nnumber of output streams;\nthese will be automatically supplied by \\fIdgsh-wrap\\fP as file descriptor\ncommand line arguments.\n\n.IP \"\\fB\\-O\\fP\nDo not include the standard output to the command line arguments,\nwhen replacing \\fI>|\\fP arguments with names of output file descriptor paths.\nThis will result in the standard output becoming available to the\ncommand as its standard output, rather than as a command line argument.\nWithout this option the first path with be \\fI/dev/fd/1\\fP.\nWhen this option is given, the program will require one output channel\nmore than those specified by the \\fI>|\\fP arguments.\n\n.IP \"\\fB\\-S\\fP\nProcess flags as a shebang-invoked (\\fI#!\\fP) interpreter using\nan invocation-supplied program name.\nThis will change the argument processing in two ways.\nFirst, it will cause the arguments being specified on the shebang line to\nbe properly parsed as separate arguments by splitting them on whitespace.\n(Most operating systems pass any of the line's arguments as a single\nstring to the process.)\nSecond, it will remove from the arguments the kernel-supplied path\nto the script that invoked \\fIdgsh-wrap\\fP.\n(The script path is not needed,\nbecause the program to wrap is specified as an argument.)\nIf this flag is specified, it must be the first command-line argument.\n\n.IP \"\\fB\\-s\\fP\nProcess flags as a shebang-invoked (\\fI#!\\fP) interpreter using an\noperating system-supplied program name.\nThis will change the argument processing in two ways.\nFirst, it will split arguments in the shebang line, in the same\nway as the \\fI-S\\fP flag.\nSecond, it will convert the kernel-supplied absolute path\nto the script that invoked \\fIdgsh-wrap\\fP, into a command name.\nIf the name of the script is the same as the name of a command to\nbe wrapped, this path can be used to derive the name of the program to execute,\nthus removing the need to supply the name of the program in the\ninvocation line.\n\n.IP \"\\fB\\-x\\fP\nExecute the specified command and arguments, without performing \\fIdgsh\\fP\nnegotiation on its behalf.\nThis is useful when\nthe specified command, \\fIA\\fP, is not \\fIdgsh\\fP-compatible,\nbut it will in turn execute, \\fIB\\fP,  a \\fIdgsh\\fP-compatible command.\nWith this flag the \\fIdgsh\\fP will recognize the invocation of \\fIA\\fP\nas an invocation of a \\fIdgsh\\fP-compatible command (due to the wrapping),\nand will not attempt to autowrap it as a filter and thereby override a\nmore sophisticated \\fIdgsh\\fP interface that \\fIB\\fP would present.\n\n.SH EXAMPLES\n.PP\nThe following examples are given only to illustrate the command's functionality.\nNote that most of the wrappings shown here are either performed automatically\nor are not required,\nbecause corresponding commands with built-in \\fIdgsh\\fP support\nare already provided.\n.PP\nWrap the \\fIecho\\fP command, specifying that it accepts no input.\n.ft C\n.ps -1\n.nf\ndgsh-wrap -i 0 echo hi\n.fi\n.ps +1\n.ft P\n.PP\nWrap the \\fIcp\\fP command, specifying that it does not perform any I/O.\n.ft C\n.ps -1\n.nf\ndgsh-wrap -i 0 -o 0 cp src-file dest-file\n.fi\n.ps +1\n.ft P\n.PP\nWrap the \\fIpaste\\fP command, supplying its two arguments.\n.ft C\n.ps -1\n.nf\ndgsh-wrap /usr/bin/paste \"<|\" \"<|\"\n.fi\n.ps +1\n.ft P\n.PP\nWrap the \\fIpaste\\fP command, with an invocation that processes the standard\ninput and uses an additional input argument.\n.ft C\n.ps -1\n.nf\ndgsh-wrap -I /usr/bin/paste - \"<|\"\n.fi\n.ps +1\n.ft P\n.PP\nWrap the \\fIpaste\\fP command, so that it will process all input channels\nprovided to it.\n.ft C\n.ps -1\n.nf\ndgsh-wrap -i a /usr/bin/paste\n.fi\n.ps +1\n.ft P\n.PP\nA wrapped version of the \\fIuname\\fP command can be created with an\ninterpreter invocation file containing just the following line.\nIn contrast to a shell script, no shell is ever launched.\n.ft C\n.ps -1\n.nf\n#!/usr/libexec/dgsh/dgsh-wrap -S -d /bin/uname\n.fi\n.ps +1\n.ft P\n.PP\nEven simpler, a wrapped version of the \\fIuname\\fP command can be created\nif\na) the interpreter invocation file is named \\fIuname\\fP,\nb) it resides in a directory named \\fIdgsh\\fP (so that it will be excluded\nfrom the subsequently used search path), and\nc) it contains the following line.\n.ft C\n.ps -1\n.nf\n#!/usr/libexec/dgsh/dgsh-wrap -s  -d\n.fi\n.ps +1\n.ft P\n.PP\nTrace the invocation of the \\fItee\\fP command,\npresenting to the shell \\fIsrtace\\fP as a \\fIdgsh\\fP-compatible command\nwith the capabilities of \\fItee\\fP.\n.ft C\n.ps -1\n.nf\ndgsh-wrap -x strace tee\n.fi\n.ps +1\n.ft P\n\n.SH \"SEE ALSO\"\n\\fIdgsh\\fP(1),\n\\fIdgsh-negotiate\\fP(3)\n\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>\n"
  },
  {
    "path": "core-tools/src/dgsh-wrap.c",
    "content": "/*\n * Copyright 2016-2017 Diomidis Spinellis\n *\n * Wrap any command to participate in the dgsh negotiation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n/*\n * Examples:\n * dgsh-wrap -i 0 yes | fsck\n * tar cf - / | dgsh-wrap -o 0 dd of=/dev/st0\n * ls | dgsh-wrap /usr/bin/sort -k5n | more\n */\n\n#define _GNU_SOURCE /* For asprintf() */\n#include <assert.h>\n#include <ctype.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <string.h>\n#include <err.h>\n\n#include \"dgsh.h\"\n#include \"dgsh-debug.h\"\t\t/* DPRINTF(4, ) */\n\n/* Determine if the OS splits shebang argument or not */\n#if __APPLE__\n#include \"TargetConditionals.h\"\n#if TARGET_OS_MAC\n#define OS_SPLITS_SHEBANG_ARGS 1\n#endif\n#endif\n\nstatic void\nusage(void)\n{\n\tfputs(\"Usage:\\tdgsh-wrap [-S] [-i 0|a] [-o 0|a] [-eIO] program [program-arguments ...]\\n\"\n\t\t\"\\tdgsh-wrap -s [-i 0|a] [-o 0|a] [-eIO] [program-arguments ...]\\n\"\n\t\t\"-e\\t\"\t\t\"Process <| and >| embedded in arguments\\n\"\n\t\t\"-i 0|a\\t\"\t\"Process no (0) or arbitrary (a) input channels\\n\"\n\t\t\"-I\\t\"\t\t\"Do not provide standard input as a <| arg\\n\"\n\t\t\"-o 0|a\\t\"\t\"Process no (0) or arbitrary (a) output channels\\n\"\n\t\t\"-O\\t\"\t\t\"Do not provide standard output as a >| arg\\n\"\n\t\t\"-S\\t\"\t\t\"Process flags and program as a #! interpreter\\n\"\n\t\t\"-s\\t\"\t\t\"Process flags as a #! interpreter\\n\"\n\t\t\"\\t\"\t\t\"(-S or -s must be the first flag of shebang line)\\n\"\n\t\t\"-x\\t\"\t\t\"Wrap a non-dgsh command that will exec a dgsh one\\n\",\n\t\tstderr);\n\texit(1);\n}\n\nstatic void *\nxmalloc(size_t size)\n{\n\tvoid *r = malloc(size);\n\tif (r == NULL)\n\t\terr(1, \"malloc out of memory\");\n\treturn r;\n}\n\nchar *\nxstrdup(const char *s)\n{\n\tvoid *r = strdup(s);\n\tif (r == NULL)\n\t\terr(1, \"stdup out of memory\");\n\treturn r;\n}\n\nstatic void *\nxrealloc(void *ptr, size_t size)\n{\n\tvoid *r = realloc(ptr, size);\n\tif (r == NULL)\n\t\terr(1, \"realloc out of memory\");\n\treturn r;\n}\n\n\n/*\n * Remove from the PATH environment variable an entry with the specified string\n */\nstatic void\nremove_from_path(const char *string)\n{\n\tchar *start, *end, *path, *strptr;\n\n\tpath = getenv(\"PATH\");\n\tif (!path)\n\t\treturn;\n\tpath = xstrdup(path);\n\tif (!path)\n\t\terr(1, \"Error allocating path copy\");\n\tstrptr = strstr(path, string);\n\tif (!strptr)\n\t\treturn;\n\t/* Find start of this path element */\n\tfor (start = strptr; start != path && *start != ':'; start--)\n\t\t;\n\t/* Find end of this path element */\n\tfor (end = strptr; *end && *end != ':'; end++)\n\t\t;\n\t/*\n\t * At this point:\n\t * start can point to : or path,\n\t * end can point to : or \\0.\n\t * Work through all cases.\n\t */\n\tif (*end == '\\0')\n\t\t*start = '\\0';\n\telse if (*start == ':')\n\t\tmemmove(start, end, strlen(end));\n\telse /* first element, followed by another */\n\t\tmemmove(start, end + 1, strlen(end + 1));\n\n\tif (setenv(\"PATH\", path, 1) != 0)\n\t\terr(1, \"Setting path\");\n\n\tfree(path);\n}\n\nstatic void\ndump_args(int argc, char *argv[])\n{\n\tint i;\n\n\tfor (i = 0; i <= argc; i++)\n\t\tDPRINTF(4, \"argv[%d]: [%s]\", i, argv[i]);\n}\n/*\n * On operating systems that pass unsplit all the #! line arguments\n * to the interpreter, process the arguments of a #! invocation to make\n * them equivalent to a command-line one.\n * This entails tokenizing argv[1], which contains all the #! line\n * after the name of the interpreter.\n *\n * Example:\n * Input arguments:\n * argv[0]: /usr/local/libexec/dgsh/dgsh-wrap\n * argv[1]: -S -d /bin/uname\n * argv[2]: /usr/local/libexec/dgsh/uname\n * argv[3]: -s\n * argv[4]: NULL\n * Output arguments:\n * argv[0]: /usr/local/libexec/dgsh/dgsh-wrap\n * argv[1]: -S\n * argv[2]: -d\n * argv[3]: /bin/uname\n * argv[4]: /usr/local/libexec/dgsh/uname\n * argv[5]: -s\n * argv[6]: NULL\n */\nstatic void\nsplit_argv(int *argcp, char ***argvp)\n{\n\tint argc = *argcp;\n\tchar **argv = *argvp;\n\n\t/* Tokenize argv[1] into multiple arguments */\n\targv = xmalloc((argc + 1) * sizeof(char *));\n\tmemcpy(argv, *argvp, (argc + 1) * sizeof(char *));\n\tint i = 1;\n\tconst char *delim = \" \\t\";\n\tchar *p = strtok(xstrdup(argv[1]), delim);\n\tassert(p != NULL);\t/* One arg (-s or -S) is guaranteed to exist */\n\tfor (;;) {\n\t\targv[i] = p;\n\t\tp = strtok(NULL, delim);\n\t\tif (p == NULL)\n\t\t\tbreak;\n\t\t/* Make room for new string */\n\t\targc += 1;\n\t\targv = xrealloc(argv, (argc + 1) * sizeof(char *));\n\t\tmemmove(argv + i + 2, argv + i + 1,\n\t\t\t\t(argc - i - 1) * sizeof(char *));\n\t\ti++;\n\t}\n\t*argvp = argv;\n\t*argcp = argc;\n\tDPRINTF(4, \"Arguments after split_argv\");\n\tdump_args(*argcp, *argvp);\n}\n\n/*\n * -S: remove OS-supplied script path name\n * Input arguments:\n * argv[0]: /usr/local/libexec/dgsh/dgsh-wrap\n * argv[1]: -S -d /bin/uname\n * argv[2]: /usr/local/libexec/dgsh/uname\n * argv[3]: -s\n * Arguments at this point:\n * argv[0]: /usr/local/libexec/dgsh/dgsh-wrap\n * argv[1]: -S\n * argv[2]: -d\n * argv[3]: /bin/uname\t\t\t<- argv[optind]\n * argv[4]: /usr/local/libexec/dgsh/uname\n * argv[5]: -s\n * Result arguments:\n * argv[0]: /usr/local/libexec/dgsh/dgsh-wrap\n * argv[1]: -S\n * argv[2]: -d\n * argv[3]: /bin/uname\n * argv[4]: -s\n */\nstatic void\nremove_os_script_path(char **argv, int *argc, int optind)\n{\n\tmemmove(argv + optind + 1, argv + optind + 2, (*argc - optind) * sizeof(char *));\n\t*argc -= 1;\n\targv[*argc] = NULL;\n}\n\n/* Remove absolute path from specified string\n * Example:\n * -s: Remove absolute path from argv[optind]\n * Input arguments:\n * argv[0]: /usr/local/libexec/dgsh/dgsh-wrap\n * argv[1]: -s -d\n * argv[2]: /usr/local/libexec/dgsh/uname\n * argv[3]: -s\n * Arguments at this point:\n * argv[0]: /usr/local/libexec/dgsh/dgsh-wrap\n * argv[1]: -s\n * argv[2]: -d\n * argv[3]: /usr/local/libexec/dgsh/uname\t<- argv[optind]\n * argv[4]: -s\n * Result arguments:\n * argv[0]: /usr/local/libexec/dgsh/dgsh-wrap\n * argv[1]: -s\n * argv[2]: -d\n * argv[3]: uname\n * argv[4]: -s\n */\nstatic void\nremove_absolute_path(char *s)\n{\n\tchar *p = strrchr(s, '/');\n\tif (p)\n\t\tmemmove(s, p + 1, strlen(p) + 1);\n}\n\n/*\n * Replace an instance of the string special (e.g. \"<|\") embedded in arg\n * with /dev/fd/N, where N is the integer pointed\n * by fdptr, and increase fdptr to point to the next integer.\n * Return true if a replacement was made, false if not.\n */\nstatic bool\nprocess_embedded_io_arg(char **arg, const char *special, int **fdptr)\n{\n\tchar *p = strstr(*arg, special);\n\tif (p == NULL)\n\t\treturn false;\n\t*p = 0;\n\tchar *before = *arg;\n\tchar *after = p + strlen(special);\n\tif (asprintf(arg, \"%s/dev/fd/%d%s\", before, **fdptr, after) == -1)\n\t\terr(1, \"asprintf out of memory\");\n\t(*fdptr)++;\n\treturn true;\n}\n\n/*\n * Replace an instance of the string special (e.g. \"<|\") matching an arg\n * with /dev/fd/N, where N is the integer pointed\n * by fdptr, and increase fdptr to point to the next integer.\n * If special is null, then the replacement is always made.\n */\nstatic void\nprocess_standalone_io_arg(char **arg, const char *special, int **fdptr)\n{\n\tif (special != NULL && strcmp(*arg, special) != 0)\n\t\treturn;\n\tif (asprintf(arg, \"/dev/fd/%d\", **fdptr) == -1)\n\t\terr(1, \"asprintf out of memory\");\n\t(*fdptr)++;\n}\n\n/*\n * Increment the channels specified by the given variable.\n * Ensure that the corresponding variable is not\n * already set to an arbitrary number of channels.\n */\nstatic void\nincrement_channels(int *var)\n{\n\tif (*var == -1) {\n\t\tfputs(\"I/O channel arguments cannot be combined with an arbitrary I/O file specification\\n\",\n\t\t\t\tstderr);\n\t\texit(1);\n\t}\n\t(*var)++;\n}\n\nint\nmain(int argc, char *argv[])\n{\n\tint nflags = 0;\n\tbool negotiation_flags = false;\n\tint ninputs = 1, noutputs = 1;\n\tbool xflag = false;\n\tint ch, i;\n\tchar *p;\n\tchar *debug_level;\n\tchar *guest_program_name;\n\t/* Option-dependent flags */\n\tbool program_from_os = false, program_supplied = false;\n\tbool embedded_args = false;\n\t/* Pass stdin/stdout as a command-line argument */\n\tbool stdin_as_arg = true, stdout_as_arg = true;\n\tbool supply_input_args = false, supply_output_args = false;\n\n\n\tdebug_level = getenv(\"DGSH_DEBUG_LEVEL\");\n\tif (debug_level)\n\t\tdgsh_debug_level = atoi(debug_level);\n\n\t/* Preclude recursive wrapping */\n\tDPRINTF(4, \"PATH before: [%s]\", getenv(\"PATH\"));\n\tremove_from_path(\"libexec/dgsh\");\n\tDPRINTF(4, \"PATH after: [%s]\", getenv(\"PATH\"));\n\n\tDPRINTF(4, \"Initial arguments\");\n\tdump_args(argc, argv);\n\n\t/* Check for #! (shebang) interpreter argument processing */\n#if !defined(OS_SPLITS_SHEBANG_ARGS)\n\tif (argc >= 2 && argv[1][0] == '-' && tolower(argv[1][1]) == 's')\n\t\tsplit_argv(&argc, &argv);\n#endif\n\n\t/*\n\t * The + argument to getopt causes it on glibc to stop processing on\n\t * first non-flag argument.\n\t * Therefore, adjust argc, argv on entry and optind on exit.\n\t */\n        while ((ch = getopt(argc, argv, \"+ei:Io:OSsx\")) != -1) {\n\t\tDPRINTF(4, \"getopt switch=%c\", ch);\n\t\tswitch (ch) {\n\t\tcase 'i':\n\t\t\tnflags++;\n\t\t\tnegotiation_flags = true;\n\t\t\tif (strcmp(optarg, \"0\") == 0)\n\t\t\t\tninputs = 0;\n\t\t\telse if (strcmp(optarg, \"a\") == 0) {\n\t\t\t\tninputs = -1;\n\t\t\t\tsupply_input_args = true;\n\t\t\t} else\n\t\t\t\tusage();\n\t\t\tbreak;\n\t\tcase 'e':\n\t\t\tembedded_args = true;\n\t\t\tnegotiation_flags = true;\n\t\t\tnflags++;\n\t\t\tbreak;\n\t\tcase 'I':\n\t\t\tstdin_as_arg = false;\n\t\t\tnegotiation_flags = true;\n\t\t\tnflags++;\n\t\t\tbreak;\n\t\tcase 'o':\n\t\t\tnflags++;\n\t\t\tnegotiation_flags = true;\n\t\t\tif (strcmp(optarg, \"0\") == 0)\n\t\t\t\tnoutputs = 0;\n\t\t\telse if (strcmp(optarg, \"a\") == 0) {\n\t\t\t\tnoutputs = -1;\n\t\t\t\tsupply_output_args = true;\n\t\t\t} else\n\t\t\t\tusage();\n\t\t\tbreak;\n\t\tcase 'O':\n\t\t\tstdout_as_arg = false;\n\t\t\tnegotiation_flags = true;\n\t\t\tnflags++;\n\t\t\tbreak;\n\t\tcase 'S':\n\t\t\t/* Complain this is not the first flag */\n\t\t\tif (nflags) {\n\t\t\t\tfputs(\"-S must be the first provided flag\\n\",\n\t\t\t\t\t\tstderr);\n\t\t\t\tusage();\n\t\t\t}\n\t\t\tnflags++;\n\t\t\tprogram_supplied = true;\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\t/* Complain this is not the first flag */\n\t\t\tif (nflags) {\n\t\t\t\tfputs(\"-s must be the first provided flag\\n\",\n\t\t\t\t\tstderr);\n\t\t\t\tusage();\n\t\t\t}\n\t\t\tnflags++;\n\t\t\tprogram_from_os = true;\n\t\t\tbreak;\n\t\tcase 'x':\n\t\t\txflag = true;\n\t\t\tbreak;\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\t}\n\tDPRINTF(3, \"After getopt: ninputs=%d, noutputs=%d optind=%d argv[optind]=%s\",\n\t\t\tninputs, noutputs, optind, argv[optind]);\n\tDPRINTF(3, \"program_supplied=%d\", program_supplied);\n\n\tif (optind >= argc)\n\t\tusage();\n\n\tif (xflag && negotiation_flags) {\n\t\tfputs(\"-x cannot be combined with I/O specifications\\n\",\n\t\t\tstderr);\n\t\tusage();\n\t}\n\n\t/*\n\t * Process argv[2], which is the name of the script\n\t * supplied by the kernel to the interpreter, i.e.\n\t * the name of the program we are being executed as.\n\t */\n\tif (program_supplied && argc > optind)\n\t\tremove_os_script_path(argv, &argc, optind);\n\telse if (program_from_os)\n\t\tremove_absolute_path(argv[optind]);\n\n\tDPRINTF(4, \"Arguments after processing program name (optind=%d)\", optind);\n\tdump_args(argc, argv);\n\n\tif (xflag) {\n\t\t/*\n\t\t * Execute (non-dgsh) command, which will execute a dgsh\n\t\t * command, which will negotiate on our behalf\n\t\t */\n\t\texecvp(argv[optind], argv + optind);\n\n\t\terr(1, \"Unable to execute %s\", argv[optind]);\n\t\treturn 1;\n\t}\n\n\t/* Obtain guest program name (without path) */\n\tguest_program_name = xstrdup(argv[optind]);\n\tremove_absolute_path(guest_program_name);\n\tDPRINTF(4, \"guest_program_name: %s\", guest_program_name);\n\n\t/*\n\t * Adjust ninputs and noutputs by special arguments\n\t * \"<|\" and \">|\", which mean input from or output to\n\t * /dev/fd/N\n\t */\n\tDPRINTF(4, \"embedded_args=%d\", embedded_args);\n\tfor (i = optind + 1; i < argc; i++) {\n\t\tif (embedded_args) {\n\t\t\tfor (p = argv[i]; p = strstr(p, \"<|\"); p += 2)\n\t\t\t\tincrement_channels(&ninputs);\n\t\t\tfor (p = argv[i]; p = strstr(p, \">|\"); p += 2)\n\t\t\t\tincrement_channels(&noutputs);\n\t\t} else {\n\t\t\tif (strcmp(argv[i], \"<|\") == 0)\n\t\t\t\tincrement_channels(&ninputs);\n\t\t\tif (strcmp(argv[i], \">|\") == 0)\n\t\t\t\tincrement_channels(&noutputs);\n\t\t}\n\t}\n\n\t/*\n\t * Adjust for the default implicit I/O channel.\n\t * E.g. if two <| are specified, ninputs will be 3 at this point,\n\t * whereas we want it to be 2.\n\t */\n\tif (stdin_as_arg && ninputs > 1)\n\t\tninputs--;\n\tif (stdout_as_arg && noutputs > 1)\n\t\tnoutputs--;\n\n\t/* Participate in negotiation */\n\tDPRINTF(3, \"calling negotiate with ninputs=%d noutputs=%d\", ninputs, noutputs);\n\tint *input_fds = NULL, *output_fds = NULL;\n\tdgsh_negotiate(DGSH_HANDLE_ERROR, guest_program_name,\n\t\t\t\t\t&ninputs, &noutputs,\n\t\t\t\t\t&input_fds, &output_fds);\n\n\t/*\n\t * Substitute special arguments \"<|\" and \">|\" with or add file descriptor\n\t * paths /dev/fd/N using the fds received from negotiation.\n\t */\n\tint *inptr = stdin_as_arg ? input_fds : input_fds + 1;\n\tif (supply_input_args) {\n\t\tif (!stdin_as_arg)\n\t\t\tninputs--;\n\n\t\t/* Create space for arguments to add */\n\t\tchar **nargv = xmalloc((argc + ninputs + 1) * sizeof(char *));\n\t\tmemcpy(nargv, argv, argc * sizeof(char *));\n\t\tmemset(argv + argc, 0, (ninputs + 1) * sizeof(char *));\n\t\targv = nargv;\n\n\t\t/* Add arguments */\n\t\tfor (i = argc; i < argc + ninputs; i++)\n\t\t\tprocess_standalone_io_arg(&argv[i], NULL, &inptr);\n\t\targc += ninputs;\n\t\targv[argc] = NULL;\n\t} else {\n\t\tfor (i = optind + 1; i < argc; i++) {\n\t\t\tif (embedded_args)\n\t\t\t\twhile (process_embedded_io_arg(&argv[i], \"<|\", &inptr))\n\t\t\t\t\t;\n\t\t\telse\n\t\t\t\tprocess_standalone_io_arg(&argv[i], \"<|\", &inptr);\n\t\t}\n\t}\n\tint *outptr = stdout_as_arg ? output_fds : output_fds + 1;\n\tif (supply_output_args) {\n\t\tif (!stdout_as_arg)\n\t\t\tnoutputs--;\n\n\t\t/* Create space for arguments to add */\n\t\tchar **nargv = xmalloc((argc + noutputs + 1) * sizeof(char *));\n\t\tmemcpy(nargv, argv, argc * sizeof(char *));\n\t\tmemset(argv + argc, 0, (noutputs + 1) * sizeof(char *));\n\t\targv = nargv;\n\n\t\t/* Add arguments */\n\t\tfor (i = argc; i < argc + noutputs; i++)\n\t\t\tprocess_standalone_io_arg(&argv[i], NULL, &outptr);\n\t\targc += noutputs;\n\t\targv[argc] = NULL;\n\t} else {\n\t\tfor (i = optind + 1; i < argc; i++) {\n\t\t\tif (embedded_args)\n\t\t\t\twhile (process_embedded_io_arg(&argv[i], \">|\", &outptr))\n\t\t\t\t\t;\n\t\t\telse\n\t\t\t\tprocess_standalone_io_arg(&argv[i], \">|\", &outptr);\n\t\t}\n\t}\n\tDPRINTF(4, \"Arguments to execvp after substitung <| and >|\");\n\tdump_args(argc - optind, argv + optind);\n\n\t/* Execute command */\n\texecvp(argv[optind], argv + optind);\n\n\terr(1, \"Unable to execute %s\", argv[optind]);\n\treturn 1;\n}\n"
  },
  {
    "path": "core-tools/src/dgsh-writeval.1",
    "content": ".TH DGSH-WRITEVAL 1 \"21 March 2013\"\n.\\\"\n.\\\" (C) Copyright 2013 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh-writeval \\- write values to a data store\n.SH SYNOPSIS\n\\fBdgsh-writeval\\fP\n[\\fB\\-l\\fP \\fIlength\\fP | \\fB-t\\fP \\fIcharacter\\fP ]\n[\\fB\\-b\\fP \\fIn\\fP]\n[\\fB\\-e\\fP \\fIn\\fP]\n[\\fB\\-u\\fP \\fIunit\\fP]\n\\fB\\-s\\fP \\fIpath\\fP\n.SH DESCRIPTION\n\\fIdgsh-writeval\\fP will read values from its standard input and make them available\nto other processes for reading through the specified Unix domain socket.\nThus this process acts as a data store:\nit reads a series of values (think of them as assignments),\nand provides a way to read the store's current value (from the socket).\nBy default \\fIdgsh-writeval\\fP will store the last value (line or data block)\nit reads.\nHowever, the default behavior can be modified through options\nso that it stores a specified window of the stream it processes.\n.PP\n\\fIdgsh-writeval\\fP is normally executed from within \\fIdgsh\\fP-generated scripts,\nrather than through end-user commands.\nThis manual page serves mainly to document its operation and\nthe flags that can be used in \\fIdgsh\\fP scripts when writing into stores.\n\n.SH OPTIONS\n.IP \"\\fB\\-b\\fP \\fIn\\fP\"\nStore records beginning in a window \\fIn\\fP units away from\nthe input's end.\nBy default this value is 1.\n\n.IP \"\\fB\\-e\\fP \\fIn\\fP\"\nStore records ending in a window \\fIn\\fP units away from\nthe input's end.\nBy default this value is 0.\n\n.IP \"\\fB\\-l\\fP \\fIlen\\fP\"\nProcess fixed-width \\fIlen\\fP-sized records.\nBy default \\fIdgsh-writeval\\fP will process newline-terminated\nrecords.\n\n.IP \"\\fB\\-s\\fP \\fIpath\\fP\"\nThis mandatory option must be used to specify the path of the Unix-domain socket\n\\fIdgsh-writeval\\fP will create.\nThis is specified as a normal Unix file path,\ne.g. \\fC/tmp/myvalue\\fP.\n\n.IP \"\\fB\\-t\\fP \\fIchar\\fP\"\nSpecify the record termination character to be \\fIchar\\fP.\nThis is the newline by default.\n\n.IP \"\\fB\\-u\\fP \\fIunit\\fP\"\nSpecify the unit of the window boundaries given in the\n\\fC-b\\fP and \\fC-e\\fP options.\nThe following units can be specified, using single-character\nidentifiers.\n.RS\n.IP \"\\fBs\\fP\nseconds\n.IP \"\\fBm\\fP\nminutes\n.IP \"\\fBh\\fP\nhours\n.IP \"\\fBd\\fP\ndays\n.IP \"\\fBr\\fP\nrecords (this is the default value)\n.RE\n\n.SH \"SEE ALSO\"\n\\fIdgsh\\fP(1),\n\\fIdgsh-readval\\fP(1)\n\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>\n"
  },
  {
    "path": "core-tools/src/dgsh-writeval.c",
    "content": "/*\n * Copyright 2013 Diomidis Spinellis\n *\n * Read values from its standard input and make them available to other\n * processes for reading through the specified Unix domain socket.\n * Thus, this process acts in effect as a data store: it reads a series of\n * values (think of them as assignements) and provides a way to read the\n * store's current value (from the socket).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/select.h>\n#include <sys/socket.h>\n#include <sys/time.h>\n#include <sys/uio.h>\n#include <sys/un.h>\n#include <assert.h>\n#include <err.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <limits.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"dgsh.h\"\n#include \"kvstore.h\"\n#include \"dgsh-debug.h\"\n#include \"minmax.h\"\n\n#ifdef DEBUG\n/* Small buffer size to catch errors with data spanning buffers */\n#define BUFFER_SIZE 5\n#else\n/* PIPE_BUF is a reasonable size heuristic. */\n#define BUFFER_SIZE PIPE_BUF\n#endif\n\n/* User options start here */\n/* Record terminator */\nstatic char rt = '\\n';\n\n/* Record length; 0 if we use a record terminator */\nstatic int rl = 0;\n\n/* True if the begin and end are specified using a time window */\nstatic bool time_window;\n\n/*\n * Specified response record.\n * This is specified using reverse iterators (counted from the end of the stream).\n * The _rbegin is inclusive, _rend is exclusive\n * Examples:\n * To get the last record use the range rbegin = 0 rend = 1\n * To get 5 records starting 10 records away from the end\n * use the range rbegin = 10 rend = 15\n */\nstatic union {\n\tstruct timeval t;\t/* Used if time_window is true */\n\tint r;\t\t\t/* Used if time_window is false */\n\tdouble d;\t\t/* Used when parsing */\n} record_rbegin, record_rend;\n\n/* User options end here */\n\n/* True once we reach the end of file on standard input */\nstatic bool reached_eof;\n\n/* True if a complete record (ending in rt) is available */\nstatic bool have_record;\n\n/* Queue (doubly linked list) of buffers used for storing the last read record */\nstruct buffer {\n\tstruct buffer *next;\n\tstruct buffer *prev;\n\tint size;\t\t\t\t/* Actual number of bytes stored */\n\tstruct timeval timestamp;\t\t/* Time the buffer was read */\n\tlong long record_count;\t\t\t/* Total number of complete records read (including this buffer)\n\t\t\t\t\t\t   (0-based ordinal of first record not in buffer) */\n\tlong long byte_count;\t\t\t/* Total number of bytes read (including this buffer) */\n\tchar data[BUFFER_SIZE];\n};\n\nstatic struct buffer *head, *tail;\n\n/* The oldest buffer whose contents are still being written to a socket. */\nstatic struct buffer *oldest_buffer_being_written;\n\n/* A pointer to a character stored in a buffer */\nstruct dpointer {\n\tstruct buffer *b;\t/* The buffer */\n\tint pos;\t\t/* The position within the buffer */\n};\n\n/* The last complete record read */\nstatic struct dpointer current_record_begin, current_record_end;\n\n/* The clients we're talking to */\nstruct client {\n\tint fd;\n\tstruct dpointer write_begin;\t/* Start of data for next write */\n\tstruct dpointer write_end;\t/* End of data to write */\n\tenum {\n\t\ts_inactive,\t\t/* Free (unused or closed) */\n\t\ts_read_command,\t\t/* Waiting for a command (Q or R) to be read */\n\t\ts_send_current,\t\t/* Waiting for the current value to be written */\n\t\ts_send_current_nblk,\t/* Non-blocking: waiting for the current or empty value to be written */\n\t\ts_send_last,\t\t/* Waiting for the last (before EOF) value to be written */\n\t\ts_sending_response,\t/* A response is being written */\n\t\ts_wait_close,\t\t/* Wait for the client to close the connection */\n\t} state;\n};\n\n#define MAX_CLIENTS 64\nstatic struct client clients[MAX_CLIENTS];\n\nstatic const char *program_name;\nstatic const char *socket_path;\n\n/*\n * Increment dp by one byte.\n * If no more bytes are available return false\n * leaving pos to point one byte past the last available one\n */\nstatic bool\ndpointer_increment(struct dpointer *dp)\n{\n\tDPRINTF(4, \"%p pos=%d\", dp->b, dp->pos);\n\tdp->pos++;\n\tif (dp->pos == dp->b->size) {\n\t\tif (!dp->b->next)\n\t\t\treturn false;\n\t\tdp->b = dp->b->next;\n\t\tdp->pos = 0;\n\t}\n\tDPRINTF(4, \"return %p pos=%d\", dp->b, dp->pos);\n\treturn true;\n}\n\n/* Decrement dp by one byte. Return false if no more bytes are available */\nstatic bool\ndpointer_decrement(struct dpointer *dp)\n{\n\tDPRINTF(4, \"%p pos=%d\", dp->b, dp->pos);\n\tdp->pos--;\n\tif (dp->pos == -1) {\n\t\tif (!dp->b->prev) {\n\t\t\tdp->pos++;\n\t\t\treturn false;\n\t\t}\n\t\tdp->b = dp->b->prev;\n\t\tdp->pos = dp->b->size - 1;\n\t}\n\tDPRINTF(4, \"return %p pos=%d\", dp->b, dp->pos);\n\treturn true;\n}\n\n/*\n * Add to dp the specified number of bytes.\n * Return true of OK.\n * If not enough bytes are available return false\n * and set dp to point to the last byte in the buffer.\n */\nstatic bool\ndpointer_add(struct dpointer *dp, int n)\n{\n\tDPRINTF(4, \"%p pos=%d n=%d\", dp->b, dp->pos, n);\n\twhile (n > 0) {\n\t\tint add = MIN(dp->b->size - dp->pos, n);\n\t\tn -= add;\n\t\tdp->pos += add;\n\t\tif (dp->pos == dp->b->size) {\n\t\t\tif (!dp->b->next)\n\t\t\t\treturn false;\n\t\t\tdp->b = dp->b->next;\n\t\t\tdp->pos = 0;\n\t\t}\n\t}\n\tDPRINTF(4, \"return %p pos=%d\", dp->b, dp->pos);\n\treturn true;\n}\n\n/*\n * Subtract from dp the specified number of bytes.\n * Return true of OK.\n * If not enough bytes are available return false\n * and set dp to point beyond the first available byte.\n */\nstatic bool\ndpointer_subtract(struct dpointer *dp, int n)\n{\n\tDPRINTF(4, \"%p pos=%d n=%d\", dp->b, dp->pos, n);\n\twhile (n > 0) {\n\t\tint subtract = MIN((dp->pos + 1) - 0, n);\n\t\tn -= subtract;\n\t\tdp->pos -= subtract;\n\t\tif (dp->pos == -1) {\n\t\t\tif (!dp->b->prev)\n\t\t\t\treturn false;\n\t\t\tdp->b = dp->b->prev;\n\t\t\tdp->pos = dp->b->size - 1;\n\t\t}\n\t}\n\tDPRINTF(4, \"return %p pos=%d\", dp->b, dp->pos);\n\treturn true;\n}\n\n/*\n * Move back dp the specified number of rt-terminated records.\n * Postcondition: dp will point at the beginning of\n * a record.\n * Return true if OK, false if not enough records are available\n * Example: to move back over one complete record, the function will\n * encounter two rts, and return with pos set immediately after the\n * second one.\n */\nstatic bool\ndpointer_move_back(struct dpointer *dp, int n)\n{\n\tDPRINTF(4, \"%p pos=%d (size=%d, prev=%p) n=%d\",\n\t\tdp->b, dp->pos, dp->b->size, dp->b->prev, n);\n\tfor (;;) {\n\t\tif (dpointer_decrement(dp)) {\n\t\t\tif (dp->b->data[dp->pos] == rt && --n == -1) {\n\t\t\t\tdpointer_increment(dp);\n\t\t\t\tDPRINTF(4, \"return %p pos=%d\", dp->b, dp->pos);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else {\n\t\t\tif (--n == -1) {\n\t\t\t\tDPRINTF(4, \"(at begin) returns: %p pos=%d\", dp->b, dp->pos);\n\t\t\t\treturn true;\n\t\t\t} else\n\t\t\t\treturn false;\t/* Not enough records available */\n\t\t}\n\t}\n}\n\n/*\n * Move forward dp the specified number of rt-terminated records.\n * Postcondition: dp will point past the end of a record.\n * Return true if OK, false if not enough records are available\n */\nstatic bool\ndpointer_move_forward(struct dpointer *dp, int n)\n{\n\tDPRINTF(4, \"%p pos=%d (size=%d, next=%p) n=%d\",\n\t\tdp->b, dp->pos, dp->b->size, dp->b->next, n);\n\t/* Cover the case where we are already at the beginning of the record */\n\tif (!dpointer_decrement(dp)) {\n\t\tDPRINTF(4, \"return %p pos=%d (at head)\", dp->b, dp->pos);\n\t\treturn true;\n\t}\n\tfor (;;) {\n\t\tif (dp->b->data[dp->pos] == rt && --n == -1) {\n\t\t\tdpointer_increment(dp);\n\t\t\tDPRINTF(4, \"return %p pos=%d\", dp->b, dp->pos);\n\t\t\treturn true;\n\t\t}\n\t\tif (!dpointer_increment(dp))\n\t\t\t\treturn false;\t/* Not enough records available */\n\t}\n}\n\n/* Return the oldest of the two buffers (the one that comes first in the list) */\nstatic struct buffer *\noldest_buffer(struct buffer *a, struct buffer *b)\n{\n\tstruct buffer *bp;\n\n\tif (a == NULL)\n\t\treturn b;\n\telse if (b == NULL)\n\t\treturn a;\n\tfor (bp = head; bp ; bp = bp->next)\n\t\tif (bp == a)\n\t\t\treturn a;\n\t\telse if (bp == b)\n\t\t\treturn b;\n\tassert(0);\n}\n\n/*\n * Update oldest_buffer_being_written according to the\n * buffers used by all clients sending a response.\n */\nstatic void\nupdate_oldest_buffer(void)\n{\n\tint i;\n\n\toldest_buffer_being_written = NULL;\n\tfor (i = 0; i < MAX_CLIENTS; i++)\n\t\tif (clients[i].state == s_sending_response)\n\t\t\toldest_buffer_being_written =\n\t\t\t\toldest_buffer(oldest_buffer_being_written, clients[i].write_begin.b);\n\tDPRINTF(4, \"Oldest buffer beeing written is %p\", oldest_buffer_being_written);\n}\n\n/* Free buffers preceding in position the used buffer */\nstatic void\nfree_unused_buffers_by_position(struct buffer *used)\n{\n\tstruct buffer *b, *bnext;\n\n\tfor (b = head; b; b = bnext) {\n\t\tif (b == used || b == oldest_buffer_being_written) {\n\t\t\thead = b;\n\t\t\tb->prev = NULL;\n\t\t\tDPRINTF(4, \"After freeing buffer(s) head=%p tail=%p\", head, tail);\n\t\t\treturn;\n\t\t}\n\t\tbnext = b->next;\n\t\tDPRINTF(4, \"Freeing buffer %p prev=%p next=%p\", b, b->prev, b->next);\n\t\tfree(b);\n\t}\n\t/* Should have encountered used along the way. */\n\tassert(0);\n}\n\n/* Free buffers preceding in time (older than) the used buffer */\nstatic void\nfree_unused_buffers_by_time(struct timeval *used)\n{\n\tstruct buffer *b;\n\n\tDPRINTF(4, \"Free buffers older than %lld.%06d\",\n\t\t(long long)used->tv_sec, (int)used->tv_usec);\n\n\t/* Find first useful record */\n\tfor (b = head; b; b = b->next)\n\t\tif (timercmp(&b->timestamp, used, >=) || b == oldest_buffer_being_written)\n\t\t\tbreak;\n\tassert(b);\t/* Should have encountered used along the way. */\n\n\tDPRINTF(4, \"First used buffer is %p\", b);\n\t/* Must now leave another record in case a record extends backward */\n\tif (rl) {\n\t\tint n = rl;\n\n\t\tdo {\n\t\t\tb = b->prev;\n\t\t} while (b && (n -= b->size) > 0);\n\t} else {\n\t\tdo {\n\t\t\tb = b->prev;\n\t\t} while (b && !memchr(b->data, rt, b->size));\n\t}\n\tDPRINTF(4, \"After extending back %p\", b);\n\tif (b)\n\t\tfree_unused_buffers_by_position(b);\n}\n\n/* Return the content length of the client's buffer */\nstatic unsigned int\ncontent_length(struct client *c)\n{\n\tstruct buffer *bp;\n\tunsigned int length;\n\n\tif (c->write_begin.b == c->write_end.b)\n\t\tlength = c->write_end.pos - c->write_begin.pos;\n\telse {\n\t\tlength = c->write_begin.b->size - c->write_begin.pos;\n\t\tfor (bp = c->write_begin.b->next; bp && bp != c->write_end.b; bp = bp->next)\n\t\t\tlength += bp->size;\n\t\tlength +=  c->write_end.pos;\n\t}\n\tDPRINTF(4, \"return %u\", length);\n\treturn length;\n}\n\n/*\n * Update the pointers to the current response record based on the defined\n * record terminator.\n */\nstatic void\nupdate_current_record_by_rt_number(void)\n{\n\tbool ret;\n\n\t/* Point to the end of read data */\n\tcurrent_record_end.b = tail;\n\tcurrent_record_end.pos = tail->size;\n\n\t/* Remove data that forms an incomplete record */\n\tret = dpointer_move_back(&current_record_end, 0);\n\tassert(ret);\n\n\t/* Go back to the end of the specified record */\n\tret = dpointer_move_back(&current_record_end, record_rbegin.r);\n\tassert(ret);\n\n\t/* Go further back to the begin of the specified record */\n\tcurrent_record_begin = current_record_end;\n\tret = dpointer_move_back(&current_record_begin, record_rend.r - record_rbegin.r);\n\tassert(ret);\n}\n\n/*\n * Update the pointers to the current response record based on the defined\n * record length.\n */\nstatic void\nupdate_current_record_by_rl_number(void)\n{\n\tbool ret;\n\n\t/* Point to the end of read data */\n\tcurrent_record_end.b = tail;\n\tcurrent_record_end.pos = tail->size;\n\n\t/* Remove data that forms an incomplete record */\n\tret = dpointer_subtract(&current_record_end, tail->byte_count % rl);\n\tassert(ret);\n\n\t/* Go back to the end of the specified record */\n\tret = dpointer_subtract(&current_record_end, record_rbegin.r * rl);\n\tassert(ret);\n\n\t/* Go further back to the begin of the specified record */\n\tcurrent_record_begin = current_record_end;\n\tret = dpointer_subtract(&current_record_begin, (record_rend.r - record_rbegin.r) * rl);\n\tassert(ret);\n}\n\n/*\n * Update the pointers to the current response record to include the first\n * record terminated record beginning in or after the begin buffer and\n * the last record beginning in the end buffer.\n * Set have_record to true if the corresponding data range exists\n */\nstatic void\nupdate_current_record_by_rt_time(struct buffer *begin, struct buffer *end)\n{\n\t/* Point to the begin of the data window */\n\tcurrent_record_begin.b = begin;\n\tcurrent_record_begin.pos = 0;\n\n\t/* Go to the begin of a record starting at or after the buffer */\n\tif (!dpointer_move_forward(&current_record_begin, 0))\n\t\treturn;\n\n\t/* Point to the end of the data window */\n\tcurrent_record_end.b = end;\n\tcurrent_record_end.pos = end->size;\n\tdpointer_decrement(&current_record_end);\n\n\t/* Adjust data that forms an incomplete record */\n\tif (!dpointer_move_forward(&current_record_end, 0)) {\n\t\tcurrent_record_end.b = end;\n\t\tcurrent_record_end.pos = end->size;\n\t\tif (!dpointer_move_back(&current_record_end, 0))\n\t\t\treturn;\n\t\tif (memcmp(&current_record_begin, &current_record_end, sizeof(struct dpointer)) == 0)\n\t\t\treturn;\n\t}\n\n\thave_record = true;\n}\n\n/*\n * Update the pointers to the current response record to include the first\n * fixed length record beginning in or after the begin buffer and\n * the last record beginning in the end buffer.\n * Set have_record to true if the corresponding data range exists\n */\nstatic void\nupdate_current_record_by_rl_time(struct buffer *begin, struct buffer *end)\n{\n\tint mod;\n\n\tDPRINTF(4, \"Adjusting begin\");\n\tcurrent_record_begin.b = begin;\n\tcurrent_record_begin.pos = 0;\n\tif (begin->prev && (mod = begin->prev->byte_count % rl) != 0)\n\t\t/*\n\t\t * Example: rl == 10, prev->byte_count == 53\n\t\t * mod = 3, dpointer_add(..., 7)\n\t\t */\n\t\tif (!dpointer_add(&current_record_begin, rl - mod))\n\t\t\treturn;\t\t/* Next record not there */\n\n\tDPRINTF(4, \"Adjusting end\");\n\tcurrent_record_end.b = end;\n\tcurrent_record_end.pos = end->size;\n\tif ((mod = end->byte_count % rl) != 0) {\n\t\t/*\n\t\t * Example: rl == 10, end->byte_count == 82\n\t\t * mod = 2, dpointer_add(..., 8)\n\t\t * Decrement and increment to convert between an iterator\n\t\t * pointing beyond the range, and valid positions that dpointer_add\n\t\t * can handle correctly.\n\t\t */\n\t\tif (!dpointer_decrement(&current_record_end) ||\n\t\t    !dpointer_add(&current_record_end, rl - mod)) {\n\t\t\tDPRINTF(4, \"incomplete last record\");\n\t\t\t/* Try going back */\n\t\t\tcurrent_record_end.b = end;\n\t\t\tcurrent_record_end.pos = end->size;\n\t\t\tif (!dpointer_subtract(&current_record_end, mod))\n\t\t\t\treturn;\n\t\t} else\n\t\t\t(void)dpointer_increment(&current_record_end);\n\t}\n\n\tif (memcmp(&current_record_begin, &current_record_end, sizeof(struct dpointer)) == 0)\n\t\treturn;\n\thave_record = true;\n}\n\n#ifdef DEBUG\n/* Dump the buffer list using relative timestamps */\nstatic void\ndump_buffer_times(void)\n{\n\tstruct buffer *bp;\n\tstruct timeval now, t;\n\n\tgettimeofday(&now, NULL);\n\n\tDPRINTF(4, \"update_current_record: now=%lld.%06d rend=%lld.%06d rbegin=%lld.%06d\",\n\t\t(long long)now.tv_sec, (int)now.tv_usec,\n\t\t(long long)record_rend.t.tv_sec, (int)record_rend.t.tv_usec,\n\t\t(long long)record_rbegin.t.tv_sec, (int)record_rbegin.t.tv_usec);\n\tfor (bp = head; bp != NULL; bp = bp->next) {\n\t\ttimersub(&now, &bp->timestamp, &t);\n\n\t\tDPRINTF(4, \"\\t%p size=%3d byte_count=%5lld Tr=%3lld.%06d Ta=%3lld.%06d [%.*s]\",\n\t\t\tbp, bp->size, bp->byte_count,\n\t\t\t(long long)t.tv_sec, (int)t.tv_usec,\n\t\t\t(long long)bp->timestamp.tv_sec, (int)bp->timestamp.tv_usec,\n\t\t\tbp->size, bp->data);\n\t}\n}\n\nstatic void\ntimestamp(const char *msg)\n{\n\tstruct timeval now;\n\tgettimeofday(&now, NULL);\n\tDPRINTF(4, \"%lld.%06d %s\", (long long)now.tv_sec, (int)now.tv_usec, msg);\n}\n\n#define TIMESTAMP(x) timestamp(x)\n#define DUMP_BUFFER_TIMES() dump_buffer_times()\n\n#else\n#define DUMP_BUFFER_TIMES()\n#define TIMESTAMP(x)\n#endif\n\n/*\n * Update the pointers to the current response record.\n * Set have_record if a record is available.\n */\nstatic void\nupdate_current_record(void)\n{\n\tassert(head && tail);\n\n\tif (time_window) {\n\t\tstruct timeval now, tbegin, tend;\t/* In absolute time units */\n\t\tstruct buffer *bbegin, *bend, *begin_candidate = NULL;\n\n\t\tDUMP_BUFFER_TIMES();\n\t\thave_record = false;\t\t/* Records in the window come and go */\n\n\t\t/* Convert to absolute time */\n\t\tgettimeofday(&now, NULL);\n\t\ttimersub(&now, &record_rend.t, &tbegin);\n\n\t\tDPRINTF(4, \"tail->timestamp=%lld.%06d tbegin=%lld.%06d\",\n\t\t\t(long long)tail->timestamp.tv_sec, (int)tail->timestamp.tv_usec,\n\t\t\t(long long)tbegin.tv_sec, (int)tbegin.tv_usec);\n\n\t\tif (timercmp(&tail->timestamp, &tbegin, <)) {\n\t\t\tfree_unused_buffers_by_position(tail);\n\t\t\treturn;\t\t/* No records fresh enough */\n\t\t}\n\n\t\ttimersub(&now, &record_rbegin.t, &tend);\n\n\t\tDPRINTF(4, \"head->timestamp=%lld.%06d tend=%lld.%06d\",\n\t\t\t(long long)head->timestamp.tv_sec, (int)head->timestamp.tv_usec,\n\t\t\t(long long)tend.tv_sec, (int)tend.tv_usec);\n\n\t\tif (timercmp(&head->timestamp, &tend, >))\n\t\t\treturn;\t\t/* No records old enough */\n\n\t\t/* Find the record range */\n\t\tDPRINTF(4, \"Looking for record range\");\n\t\tfor (bend = tail; timercmp(&bend->timestamp, &tend, >); bend = bend->prev)\n\t\t\t;\n\t\tDPRINTF(4, \"bend=%p %lld.%06d\", bend, (long long)bend->timestamp.tv_sec, (int)bend->timestamp.tv_usec);\n\n\t\tfor (bbegin = bend; bbegin && timercmp(&bbegin->timestamp, &tbegin, >); bbegin = bbegin->prev)\n\t\t\tbegin_candidate = bbegin;\n\n\t\tif (!begin_candidate) {\n\t\t\tfree_unused_buffers_by_time(&tbegin);\n\t\t\treturn;\t\t/* No records within the window */\n\t\t}\n\t\tbbegin = begin_candidate;\n\t\tDPRINTF(4, \"bbegin=%p %lld.%06d\", bbegin, (long long)bbegin->timestamp.tv_sec, (int)bbegin->timestamp.tv_usec);\n\n\t\tif (rl)\n\t\t\tupdate_current_record_by_rl_time(bbegin, bend);\n\t\telse\n\t\t\tupdate_current_record_by_rt_time(bbegin, bend);\n\n\t\tfree_unused_buffers_by_time(&tbegin);\n\t} else {\n\t\tDPRINTF(4, \"tail->record_count=%lld record_rend.r=%d\",\n\t\t\ttail->record_count, record_rend.r);\n\t\tif (tail->record_count - record_rend.r < 0)\n\t\t\t/* Not enough records */\n\t\t\treturn;\n\n\t\tif (rl)\n\t\t\tupdate_current_record_by_rl_number();\n\t\telse\n\t\t\tupdate_current_record_by_rt_number();\n\t\thave_record = true;\n\t\tfree_unused_buffers_by_position(current_record_begin.b);\n\t}\n\n\tDPRINTF(4, \"have_record=%d\", have_record);\n\tDPRINTF(4, \"begin b=%p pos=%d\", current_record_begin.b, current_record_begin.pos);\n\tDPRINTF(4, \"end b=%p pos=%d\", current_record_end.b, current_record_end.pos);\n}\n\n/*\n * Read a one character command from the specifid client and act on it\n * The following commands are supported:\n * R: Read value (the client wants to read our current store value)\n * Q: Quit (Terminate the operation of this data store)\n */\n\nstatic void\nread_command(struct client *c)\n{\n\tchar cmd;\n\tint n;\n\n\tswitch (n = read(c->fd, &cmd, 1)) {\n\tcase -1: \t\t/* Error */\n\t\tswitch (errno) {\n\t\tcase EAGAIN:\n\t\t\tDPRINTF(4, \"EAGAIN on client socket read\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\terr(3, \"Read from socket\");\n\t\t}\n\t\tbreak;\n\tcase 0:\t\t\t/* EOF */\n\t\tclose(c->fd);\n\t\tc->state = s_inactive;\n\t\tDPRINTF(4, \"Done with client %p\", c);\n\t\tupdate_oldest_buffer();\n\t\tbreak;\n\tdefault:\t\t/* Have data. Insert buffer at the end of the queue. */\n\t\tDPRINTF(4, \"Read command %c from client %p\", cmd, c);\n\t\tswitch (cmd) {\n\t\tcase 'L':\n\t\t\tc->state = s_send_last;\n\t\t\tbreak;\n\t\tcase 'Q':\n\t\t\t(void)unlink(socket_path);\n\t\t\texit(0);\n\t\tcase 'c':\n\t\t\tc->state = s_send_current_nblk;\n\t\t\tbreak;\n\t\tcase 'C':\n\t\t\tc->state = s_send_current;\n\t\t\tif (time_window && head)\n\t\t\t\tupdate_current_record();\t/* Refresh have_record */\n\t\t\tbreak;\n\t\tdefault:\n\t\t\terrx(5, \"Unknown command [%c]\", cmd);\n\t\t}\n\t}\n}\n\n/*\n * Write a single record to the specified client\n * Update the write_begin pointer\n * Close the connection and clean the client if done\n * If write_length is true, precede the record with\n * CONTENT_LENGTH_DIGITS digits representing the record's\n * length.\n */\nstatic void\nwrite_record(struct client *c, bool write_length)\n{\n\tint n;\n\tint towrite;\n\tstruct iovec iov[2], *iovptr;\n\tchar length[CONTENT_LENGTH_DIGITS + 2];\n\n\tDPRINTF(4, \"Write %srecord for client %p\", write_length ? \"first \" : \"\", c);\n\tif (c->write_begin.b == c->write_end.b) {\n\t\ttowrite = c->write_end.pos - c->write_begin.pos;\n\t\tDPRINTF(4, \"Single buffer %p: writing %d bytes. write_end.pos=%d write_begin.pos=%d\",\n\t\t\tc->write_begin.b, towrite, c->write_end.pos, c->write_begin.pos);\n\t} else {\n\t\ttowrite = c->write_begin.b->size - c->write_begin.pos;\n\t\tDPRINTF(4, \"Multiple buffers %p %p: writing %d bytes. write_begin.b->size=%d write_begin.pos=%d\",\n\t\t\tc->write_begin.b, c->write_end.b,\n\t\t\ttowrite, c->write_begin.b->size, c->write_begin.pos);\n\t}\n\n\tiov[1].iov_base = c->write_begin.b->data + c->write_begin.pos;\n\tiov[1].iov_len = towrite;\n\tDPRINTF(4, \"Writing [%.*s]\", (int)iov[1].iov_len, (char *)iov[1].iov_base);\n\n\tif (write_length) {\n\t\tsnprintf(length, sizeof(length), CONTENT_LENGTH_FORMAT, content_length(c));\n\t\tiov[0].iov_base = length;\n\t\tiov[0].iov_len = CONTENT_LENGTH_DIGITS;\n\t\tiovptr = iov;\n\t} else\n\t\tiovptr = iov + 1;\n\n\tif ((n = writev(c->fd, iovptr, write_length ? 2 : 1)) == -1)\n\t\tswitch (errno) {\n\t\tcase EAGAIN:\n\t\t\tDPRINTF(4, \"EAGAIN on client socket write\");\n\t\t\treturn;\n\t\tdefault:\n\t\t\terr(3, \"Write to socket\");\n\t\t}\n\n\tif (write_length) {\n\t\tif (n < CONTENT_LENGTH_DIGITS)\n\t\t\terrx(5, \"Short content length record write: %d\", n);\n\t\tn -= CONTENT_LENGTH_DIGITS;\n\t}\n\n\tc->write_begin.pos += n;\n\tDPRINTF(4, \"Wrote %u data bytes. Current buffer position=%d\", n, c->write_begin.pos);\n\t/*\n\t * More data to write from this buffer?\n\t * Yes, if there is still more data in the buffer\n\t * and either the end is in another buffer, or we haven't\n\t * reached it.\n\t */\n\tif (c->write_begin.pos < c->write_begin.b->size &&\n\t    (c->write_begin.b != c->write_end.b || c->write_begin.pos < c->write_end.pos)) {\n\t\tDPRINTF(4, \"Continuing with same buffer\");\n\t\treturn;\n\t}\n\n\t/* More buffers to write from? */\n\tif (c->write_begin.b != c->write_end.b) {\n\t\tc->write_begin.b = c->write_begin.b->next;\n\t\tc->write_begin.pos = 0;\n\t\tDPRINTF(4, \"Moving to next buffer %p with size %u\", c->write_begin.b, c->write_begin.b->size);\n\t\treturn;\n\t}\n\n\t/* Done with this client */\n\tDPRINTF(4, \"No more data to write for client %p\", c);\n\tc->state = s_wait_close;\n}\n\n/* Set the buffer's counters */\nvoid\nset_buffer_counters(struct buffer *b)\n{\n\tif (time_window)\n\t\tgettimeofday(&b->timestamp, NULL);\n\n\tif (rl == 0) {\n\t\t/* Count records using RS */\n\t\tint i;\n\n\t\tb->record_count = b->prev ? b->prev->record_count : 0;\n\t\tfor (i = 0; i < b->size; i++)\n\t\t\tif (b->data[i] == rt)\n\t\t\t\tb->record_count++;\n\t} else {\n\t\t/* Count records using RL */\n\n\t\tb->byte_count = b->prev ? b->prev->byte_count : 0;\n\t\tb->byte_count += b->size;\n\t\tb->record_count = b->byte_count / rl;\n\t}\n}\n\n\n#if __GNUC__ == 4 && __GNUC_MINOR__ >= 2 && __GNUC_MINOR__ < 6\n#pragma GCC diagnostic ignored \"-Wuninitialized\"\n#endif\n/* Read data from STDIN into a new buffer */\nstatic void\nbuffer_read(void)\n{\n\tstruct buffer *b;\n\tstruct timeval now, abs_rend_time;\n\n\tif ((b = malloc(sizeof(struct buffer))) == NULL)\n\t\terr(1, \"Unable to allocate read buffer\");\n\n\tDPRINTF(4, \"Calling read on stdin for buffer %p\", b);\n\tswitch (b->size = read(STDIN_FILENO, b->data, sizeof(b->data))) {\n\tcase -1: \t\t/* Error */\n\t\tswitch (errno) {\n\t\tcase EAGAIN:\n\t\t\tDPRINTF(4, \"EAGAIN on standard input\");\n\t\t\tfree(b);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\terr(3, \"Read from standard input\");\n\t\t}\n\t\tbreak;\n\tcase 0:\t\t\t/* EOF */\n\t\treached_eof = true;\n\t\tif (time_window) {\n\t\t\t/* Make abs_rend_time the latest absolute time that interests us */\n\t\t\tgettimeofday(&now, NULL);\n\t\t\ttimeradd(&now, &record_rend.t, &abs_rend_time);\n\t\t}\n\t\tif (have_record) {\n\t\t\tfree(b);\n#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n#endif\n\t\t} else if (!time_window || !tail ||\n\t\t    timercmp(&tail->timestamp, &abs_rend_time, >)) {\n#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6\n#pragma GCC diagnostic pop\n#endif\n\t\t\t/* Setup an empty record, if there will never be a record to send */\n\t\t\tb->size = 0;\n\t\t\tb->prev = b->next = NULL;\n\t\t\thead = tail = b;\n\t\t\tcurrent_record_begin.b = current_record_end.b = b;\n\t\t\tcurrent_record_begin.pos = current_record_end.pos = 0;\n\t\t\thave_record = true;\n\t\t}\n\t\tbreak;\n\tdefault:\t\t/* Have data. Insert buffer at the end of the queue. */\n\t\tb->prev = tail;\n\t\tb->next = NULL;\n\t\tif (tail)\n\t\t\ttail->next = b;\n\t\ttail = b;\n\t\tif (!head)\n\t\t\thead = b;\n\t\tDPRINTF(4, \"Read %d bytes into %p prev=%p next=%p head=%p tail=%p\",\n\t\t\tb->size, b, b->prev, b->next, head, tail);\n\t\tset_buffer_counters(b);\n\t\tupdate_current_record();\n\t\tbreak;\n\t}\n}\n\n/*\n * Set the specified file descriptor to operate in non-blocking\n * mode.\n * It seems that even if select returns for a specified file\n * descriptor, performing I/O to it may block depending on the\n * amount of data specified.\n * See See http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html#tag_03_866\n */\nstatic void\nnon_block(int fd)\n{\n\tint flags = fcntl(fd, F_GETFL, 0);\n\tif (flags < 0)\n\t\terr(2, \"Error getting flags for socket\");\n\tif (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)\n\t\terr(2, \"Error setting socket to non-blocking mode\");\n}\n\n/* Return an initialized free client entry, or exit with an error. */\nstatic struct client *\nget_free_client(void)\n{\n\tint i;\n\n\tfor (i = 0; i < MAX_CLIENTS; i++)\n\t\tif (clients[i].state == s_inactive)\n\t\t\treturn &clients[i];\n\terrx(5, \"Maximum number of clients exceeded for socket %s\", socket_path);\n}\n\nstatic void\nusage(void)\n{\n\tfprintf(stderr, \"Usage: %s [-l len|-t char] [-b n] [-e n] [-u s|m|h|d|r] -s path\\n\"\n\t\t\"-b n\"\t\t\"\\tStore records beginning in a window n away from the end (default 1)\\n\"\n\t\t\"-e n\"\t\t\"\\tStore records ending in a window n away from the end (default 0)\\n\"\n\t\t\"-l len\"\t\"\\tProcess fixed-width len-sized records\\n\"\n\t\t\"-s path\"\t\"\\tSpecify the socket to create\\n\"\n\t\t\"-t char\"\t\"\\tProcess char-terminated records (newline default)\\n\"\n\t\t\"-u unit\"\t\"\\tSpecify the unit of window boundaries\\n\"\n\t\t\"\"\t\t\"\\ts: seconds\\n\"\n\t\t\"\"\t\t\"\\tm: minutes\\n\"\n\t\t\"\"\t\t\"\\th: hours\\n\"\n\t\t\"\"\t\t\"\\td: days\\n\"\n\t\t\"\"\t\t\"\\tr: records (default)\\n\",\n\t\tprogram_name);\n\texit(1);\n}\n\n/*\n * Parse a number >= 0\n * Exit with an error if an error occurs\n */\nstatic double\nparse_double(const char *s)\n{\n\tchar *endptr;\n\tdouble d;\n\n\terrno = 0;\n\td = strtod(s, &endptr);\n\tif (endptr - s != strlen(s) || *s == 0)\n\t\terrx(6, \"Error in parsing [%s] as a number\", s);\n\tif (errno != 0)\n\t\terr(6, \"[%s]\", s);\n\tif (d < 0)\n\t\terrx(6, \"Argument [%s] cannot be negative\", s);\n\treturn d;\n}\n\n/* Return the passed double as a timeval */\nstruct timeval\ndouble_to_timeval(double d)\n{\n\tstruct timeval t;\n\n\tt.tv_sec = (time_t)d;\n\tt.tv_usec = (int)((d - t.tv_sec) * 1e6);\n\treturn t;\n}\n\n/* Parse the program's arguments */\nstatic void\nparse_arguments(int argc, char *argv[])\n{\n\tint ch;\n\tchar unit = 'r';\n\n\tprogram_name = argv[0];\n\t/* By default return the last record read */\n\trecord_rbegin.d = 0;\n\trecord_rend.d = 1;\n\n\twhile ((ch = getopt(argc, argv, \"b:e:l:s:t:u:\")) != -1) {\n\t\tswitch (ch) {\n\t\tcase 'b':\t/* Begin record, measured from the end (0) */\n\t\t\trecord_rend.d = parse_double(optarg);\n\t\t\tbreak;\n\t\tcase 'e':\t/* End record, measured from the end (0) */\n\t\t\trecord_rbegin.d = parse_double(optarg);\n\t\t\tbreak;\n\t\tcase 'l':\t/* Fixed record length */\n\t\t\trl = atoi(optarg);\n\t\t\tif (rl <= 0)\n\t\t\t\tusage();\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tsocket_path = optarg;\n\t\t\tbreak;\n\t\tcase 't':\t/* Record terminator */\n\t\t\t/* We allow \\0 as rt */\n\t\t\tif (strlen(optarg) > 1)\n\t\t\t\tusage();\n\t\t\trt = *optarg;\n\t\t\tbreak;\n\t\tcase 'u':\t/* Measurement unit */\n\t\t\tif (strlen(optarg) != 1 || strchr(\"smhdr\", *optarg) == NULL)\n\t\t\t\tusage();\n\t\t\tunit = *optarg;\n\t\t\tbreak;\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\t}\n\targc -= optind;\n\targv += optind;\n\n\tif (argc != 0 || socket_path == NULL)\n\t\tusage();\n\n\tswitch (unit) {\n\tcase 'r':\n\t\tif (record_rbegin.d != (int)record_rbegin.d ||\n\t\t    record_rend.d != (int)record_rend.d)\n\t\t    \terrx(6, \"Record numbers must be integers\");\n\t\trecord_rbegin.r = (int)record_rbegin.d;\n\t\trecord_rend.r = (int)record_rend.d;\n\t\ttime_window = false;\n\t\tbreak;\n\tcase 'd':\n\t\trecord_rbegin.d *= 24;\n\t\trecord_rend.d *= 24;\n\t\t/* FALLTHROUGH */\n\tcase 'h':\n\t\trecord_rbegin.d *= 60;\n\t\trecord_rend.d *= 60;\n\t\t/* FALLTHROUGH */\n\tcase 'm':\n\t\trecord_rbegin.d *= 60;\n\t\trecord_rend.d *= 60;\n\t\t/* FALLTHROUGH */\n\tcase 's':\n\t\trecord_rbegin.t = double_to_timeval(record_rbegin.d);\n\t\trecord_rend.t = double_to_timeval(record_rend.d);\n\t\tif (!timercmp(&record_rbegin.t, &record_rend.t, <))\n\t\t\terrx(6, \"Begin time must be older than end time\");\n\t\ttime_window = true;\n\t\tbreak;\n\t}\n}\n\n/*\n * Handle the events associated with the following elements\n * The passed socket\n * Standard input\n * Communicating clients\n * Elapsed time values\n * This is called in an endless loop to do the following things:\n *   Setup select(2) arguments\n *   Call select(2)\n *   Process events that can be processed\n */\nstatic void\nhandle_events(int sock)\n{\n\tfd_set source_fds;\n\tfd_set sink_fds;\n\tstruct timeval wait_time, *waitptr;\n\tbool set_waitptr;\n\tint i, max_fd, nfds;\n\tsocklen_t len;\n\tstruct sockaddr_un remote;\n\n\t/* Set the fds that interest us */\n\tFD_ZERO(&source_fds);\n\tFD_ZERO(&sink_fds);\n\twaitptr = NULL;\n\n\tmax_fd = -1;\n\t/* Read from standard input */\n\tif (!reached_eof) {\n\t\tFD_SET(STDIN_FILENO, &source_fds);\n\t\tmax_fd = STDIN_FILENO;\n\t}\n\n\t/* Accept incoming connection */\n\tFD_SET(sock, &source_fds);\n\tmax_fd = MAX(sock, max_fd);\n\n\t/* I/O with a client */\n\tset_waitptr = false;\n\tfor (i = 0; i < MAX_CLIENTS; i++)\n\t\tswitch (clients[i].state) {\n\t\tcase s_inactive:\t\t/* Free (unused or closed) */\n\t\t\tbreak;\n\t\tcase s_wait_close:\t\t/* Wait for the client to close the connection */\n\t\tcase s_read_command:\t\t/* Waiting for a command (Q or R) to be read */\n\t\t\tFD_SET(clients[i].fd, &source_fds);\n\t\t\tmax_fd = MAX(clients[i].fd, max_fd);\n\t\t\tbreak;\n\t\tcase s_send_last:\t\t/* Waiting for the last (before EOF) value to be written */\n\t\t\tif (reached_eof) {\n\t\t\t\tFD_SET(clients[i].fd, &sink_fds);\n\t\t\t\tmax_fd = MAX(clients[i].fd, max_fd);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase s_send_current:\t\t/* Waiting for a response to be written */\n\t\t\tif (have_record) {\n\t\t\t\tFD_SET(clients[i].fd, &sink_fds);\n\t\t\t\tmax_fd = MAX(clients[i].fd, max_fd);\n\t\t\t} else if (time_window)\n\t\t\t\tset_waitptr = true;\n\t\t\tbreak;\n\t\tcase s_send_current_nblk:\t/* Waiting for a response to be written */\n\t\t\tFD_SET(clients[i].fd, &sink_fds);\n\t\t\tmax_fd = MAX(clients[i].fd, max_fd);\n\t\t\tbreak;\n\t\tcase s_sending_response:\t/* A response is being sent */\n\t\t\tFD_SET(clients[i].fd, &sink_fds);\n\t\t\tmax_fd = MAX(clients[i].fd, max_fd);\n\t\t\tbreak;\n\t\t}\n\n\tif (set_waitptr) {\n\t\t/*\n\t\t * Find the oldest buffer that hasn't yet entered the time\n\t\t * window and arrange for select(2) to wait for it to enter.\n\t\t */\n\t\tstruct buffer *bp, *candidate_buffer = NULL;\n\t\tstruct timeval now, abs_rbegin_time;\n\n\t\tgettimeofday(&now, NULL);\n\t\ttimersub(&now, &record_rbegin.t, &abs_rbegin_time);\n\t\tDPRINTF(4, \"have to wait for a buffer to enter window %lld.%06d\",\n\t\t\t(long long)abs_rbegin_time.tv_sec, (int)abs_rbegin_time.tv_usec);\n\t\t/*\n\t\t * rbegin = 10\n\t\t * 13            19     20    21  23\n\t\t * abs_rbegin    ...    ... tail  now\n\t\t */\n\t\tfor (bp = tail; bp && timercmp(&bp->timestamp, &abs_rbegin_time, >); bp = bp->prev)\n\t\t\tcandidate_buffer = bp;\n\t\tif (candidate_buffer) {\n\t\t\t/* There is a buffer worth waiting for */\n\t\t\twaitptr = &wait_time;\n\t\t\ttimersub(&candidate_buffer->timestamp, &abs_rbegin_time, waitptr);\n\t\t\tDPRINTF(4, \"waiting %lld.%06d for %p %lld.%06d to enter the window\",\n\t\t\t\t(long long)wait_time.tv_sec, (int)wait_time.tv_usec,\n\t\t\t\tcandidate_buffer,\n\t\t\t\t(long long)candidate_buffer->timestamp.tv_sec,\n\t\t\t\t(int)candidate_buffer->timestamp.tv_usec);\n\t\t} else\n\t\t\tDPRINTF(4, \"No candidate buffer found\");\n\t}\n\n\tTIMESTAMP(\"Calling select\");\n\tif ((nfds = select(max_fd + 1, &source_fds, &sink_fds, NULL, waitptr)) < 0)\n\t\terr(3, \"select\");\n\tTIMESTAMP(\"Select returns\");\n\n\tif (FD_ISSET(STDIN_FILENO, &source_fds))\n\t\tbuffer_read();\n\n\tif (waitptr && nfds == 0)\n\t\t/* Expired timer; records may have entered the window */\n\t\tupdate_current_record();\n\n\tfor (i = 0; i < MAX_CLIENTS; i++)\n\t\tswitch (clients[i].state) {\n\t\tcase s_inactive:\t\t/* Free (unused or closed) */\n\t\t\tbreak;\n\t\tcase s_read_command:\t\t/* Waiting for a command (Q or R) to be read */\n\t\tcase s_wait_close:\t\t/* Wait for the client to close the connection */\n\t\t\tif (FD_ISSET(clients[i].fd, &source_fds))\n\t\t\t\tread_command(&clients[i]);\n\t\t\tbreak;\n\t\tcase s_send_last:\t\t/* Waiting for the last (before EOF) value to be written */\n\t\t\t/* FALLTHROUGH */\n\t\tcase s_send_current:\t\t/* Waiting for a response to be written */\n\t\t\tif (FD_ISSET(clients[i].fd, &sink_fds)) {\n\t\t\t\tassert(have_record);\n\t\t\t\t/* Start writing the most fresh last record */\n\t\t\t\tclients[i].write_begin = current_record_begin;\n\t\t\t\tclients[i].write_end = current_record_end;\n\t\t\t\tclients[i].state = s_sending_response;\n\t\t\t\toldest_buffer_being_written =\n\t\t\t\t\toldest_buffer(oldest_buffer_being_written, clients[i].write_begin.b);\n\t\t\t\twrite_record(&clients[i], true);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase s_send_current_nblk:\t/* Waiting for a response (even empty) to be written */\n\t\t\tif (FD_ISSET(clients[i].fd, &sink_fds)) {\n\t\t\t\tif (have_record) {\n\t\t\t\t\t/* Start writing the most fresh last record */\n\t\t\t\t\tclients[i].write_begin = current_record_begin;\n\t\t\t\t\tclients[i].write_end = current_record_end;\n\t\t\t\t\toldest_buffer_being_written =\n\t\t\t\t\t\toldest_buffer(oldest_buffer_being_written, clients[i].write_begin.b);\n\t\t\t\t} else {\n\t\t\t\t\tstatic struct buffer empty;\n\n\t\t\t\t\t/* Write an empty record */\n\t\t\t\t\tclients[i].write_begin.b = clients[i].write_end.b = &empty;\n\t\t\t\t\tclients[i].write_begin.pos = clients[i].write_end.pos = 0;\n\t\t\t\t}\n\t\t\t\tclients[i].state = s_sending_response;\n\t\t\t\twrite_record(&clients[i], true);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase s_sending_response:\t/* A response is being written */\n\t\t\tif (FD_ISSET(clients[i].fd, &sink_fds))\n\t\t\t\twrite_record(&clients[i], false);\n\t\t\tbreak;\n\t\t}\n\n\tif (FD_ISSET(sock, &source_fds)) {\n\t\tint rsock;\n\t\tstruct client *c;\n\n\t\tlen = sizeof(remote);\n\t\trsock = accept(sock, (struct sockaddr *)&remote, &len);\n\t\tif (rsock == -1 && errno != EAGAIN)\n\t\t\terr(5, \"accept\");\n\n\t\tc = get_free_client();\n\t\tnon_block(rsock);\n\t\tc->fd = rsock;\n\t\tc->state = s_read_command;\n\t}\n}\n\nint\nmain(int argc, char *argv[])\n{\n\tint sock;\n\tsocklen_t len;\n\tstruct sockaddr_un local;\n\tint ninputs = 1;\n\tint noutputs = 0;\n\n\tparse_arguments(argc, argv);\n\n        dgsh_negotiate(DGSH_HANDLE_ERROR, program_name, &ninputs, &noutputs,\n\t\t\tNULL, NULL);\n\n\tif (strlen(socket_path) >= sizeof(local.sun_path) - 1)\n\t\terrx(6, \"Socket name [%s] must be shorter than %lu characters\",\n\t\t\tsocket_path, (long unsigned)sizeof(local.sun_path));\n\n\t(void)unlink(socket_path);\n\n\tif ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)\n\t\terr(2, \"Error creating socket\");\n\n\tlocal.sun_family = AF_UNIX;\n\tstrcpy(local.sun_path, socket_path);\n\tlen = strlen(local.sun_path) + 1 + sizeof(local.sun_family);\n\tif (bind(sock, (struct sockaddr *)&local, len) == -1)\n\t\terr(3, \"Error binding socket to Unix domain address %s\", argv[1]);\n\n\tif (listen(sock, 5) == -1)\n\t\terr(4, \"listen\");\n\n\tnon_block(sock);\n\n\treached_eof = false;\n\tfor (;;)\n\t\thandle_events(sock);\n}\n"
  },
  {
    "path": "core-tools/src/dgsh.1",
    "content": ".TH DGSH 1 \"10 August 2017\"\n.\\\"\n.\\\" (C) Copyright 2016-2017 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh \\- directed graph shell\n.SH SYNOPSIS\n\\fBdgsh\\fP\n[\\fIbash_options\\fP]\n[command_string | file]\n.SH DESCRIPTION\n\\fIdgsh\\fP is a modified version of \\fIbash\\fP\nthat allows the specification of pipelines with non-linear non-uniform\noperations.\nThese form a directed acyclic process graph, which is\ntypically executed by multiple processor cores, thus increasing the\noperation's processing throughput.\nThe \\fIdgsh\\fP command is equivalent to invoking the modified version of \\fIbash\\fP\nwith the \\fI--dgsh\\fP argument in order to enable the \\fIdgsh\\fP-specific\ninter-process communication functionality.\n\n.SH INTER-PROCESS COMMUNICATION\n\\fIDgsh\\fP provides three new ways\nfor expressing inter-process communication.\n.PP\n\\fBMultipipes\\fP are expressed as usual Unix pipelines,\nbut can connect commands with more than one output or input channel.\nAs an example, the \\fIcomm\\fP command supplied with \\fIdgsh\\fP\nexpects two input channels and produces on its output three\noutput channels: the lines appearing only in first (sorted) channel,\nthe lines appearing only in the second channel,\nand the lines appearing in both.\nConnecting the output of the \\fIcomm\\fP command to the\n\\fIcat\\fP command supplied with \\fIdgsh\\fP\nwill make the three outputs appear in sequence,\nwhile connecting it to the\n\\fIpaste\\fP command supplied with \\fIdgsh\\fP\nwill make the output appear in its customary format.\n\\fIDgsh\\fP handles the following programs\nas being multipipe compatible:\na) those that are linked with the \\fIdgsh\\fP library;\nb) scripts that include in their first line one of the strings\n\\fCdgsh-wrap\\fP, \\fCenv dgsh\\fP, or \\fC--dgsh\\fP;\nc) scripts whose second line starts with \\fC#!dgsh\\fP.\n.PP\n\\fBMultipipe blocks\\fP are enclosed within double braces: {{ ... }}.\nThese\na) send the input received on their input side to the asynchronously-running\nprocesses that reside within the block, and, b) pass the output\nproduced by the processes within the block to their output side.\nMultipipe blocks typically receive input from more than one channel\nand produce more than one output channel.\nFor example, a multipipe block that runs \\fImd5sum\\fP and \\fIwc -c\\fP\nreceives two inputs and produces two outputs:\nthe MD5 hash of its input and the input's size.\nData to multipipe blocks are typically provided with an\n\\fIdgsh\\fP-aware version of \\fItee\\fP and collected by\n\\fIdgsh\\fP-aware versions of programs such as\n\\fIcat\\fP and \\fIpaste\\fP.\n.PP\n\\fBStored values\\fP offer a convenient way for communicating\ncomputed values between arbitrary processes on the graph.\nThey allow the storage of a data stream's\nlast record into a named buffer.\nThis record can be later retrieved asynchronously by one or more readers.\nData in a stored value can be piped into a process or out of it, or it can be read\nusing the shell's command output substitution syntax.\nStored values are implemented internally through Unix-domain sockets,\na background-running store program, \\fIdgsh-writeval\\fP, and\na reader program, \\fIdgsh-readval\\fP.\nThe behavior of a stored value's IO can be modified by adding flags to\n\\fIdgsh-writeval\\fP and \\fIdgsh-readval\\fP.\n\n.SH SYNTAX EXTENSIONS\nThe syntax of \\fIbash\\fP is extended by \\fIdgsh\\fP as follows.\n.PP\n.ft C\n.ps -1\n.nf\n<dgsh_block>     ::= '{{' <dgsh_list> '}}'\n\n<dgsh_list>      ::= <dgsh_list_item> '&'\n                 <dgsh_list_item> <dgsh_list>\n\n<dgsh_list_item> ::= <simple_command>\n                 <dgsh_block>\n                 <dgsh_list_item> '|' <dgsh_list_item>\n.fi\n.ps +1\n.ft P\n.br\n\n.SH EXAMPLES\n.PP\nReport file type, length, and compression performance for a\nURL retrieved from the web.  The web file never touches the\ndisk.\n.ft C\n.ps -1\n.nf\n#!/usr/bin/env dgsh\n\ncurl -s \"$1\" |\ntee |\n{{\n\techo -n 'File type:' &\n\tfile - &\n\n\techo -n 'Original size:' &\n\twc -c &\n\n\techo -n 'xz:' &\n\txz -c | wc -c &\n\n\techo -n 'bzip2:' &\n\tbzip2 -c | wc -c &\n\n\techo -n 'gzip:' &\n\tgzip -c | wc -c &\n}} |\ncat\n.fi\n.ps +1\n.ft P\n.PP\nList the names of duplicate files in the specified directory\n.ft C\n.ps -1\n.nf\n#!/usr/bin/env dgsh\n\n# Create list of files\nfind \"$@\" -type f |\n\n# Produce lines of the form\n# MD5(filename)= 811bfd4b5974f39e986ddc037e1899e7\nxargs openssl md5 |\n\n# Convert each line into a \"filename md5sum\" pair\nsed 's/^MD5(//;s/)= / /' |\n\n# Sort by MD5 sum\nsort -k2 |\n\ntee |\n{{\n\t# Print an MD5 sum for each file that appears more than once\n\tawk '{print $2}' | uniq -d &\n\n\t# Promote the stream to gather it\n\tcat &\n}} |\n# Join the repeated MD5 sums with the corresponding file names\n# Join expects two inputs, second will come from scatter\njoin -2 2 |\n.fi\n.ps +1\n.ft P\n.PP\nCheck if the script is running under \\fIdgsh\\fP or regular \\fIbash\\fP (for polyglot scripts)\n.ft C\n.ps -1\n.nf\nif {{ : ; }} ; then\n    echo dgsh\nelse\n    echo bash\nfi 2>/dev/null\n.fi\n.ps +1\n.ft P\n\n.SH \"SEE ALSO\"\n.BR dgsh-tee (1),\n.BR dgsh-wrap (1),\n.BR dgsh-writeval (1),\n.BR dgsh-readval (1),\n.BR dgsh-monitor (1)\n.BR dgsh-conc (1),\n.BR dgsh-httpval (1),\n.BR dgsh-merge-sum (1)\n\n.SH AUTHOR\n\\fIDgsh\\fP was designed by\nDiomidis Spinellis \\(em <http://www.spinellis.gr> \\(em\nand implemented by Marios Fragkoulis.\nThe current design and capabilities of \\fIdgsh\\fP have been\nsignificantly influenced by amazing feedback generously provided by\nDoug McIlroy.\n\n.SH BUGS\nReport bugs through https://github.com/dspinellis/dgsh/issues.\n"
  },
  {
    "path": "core-tools/src/dgsh.h",
    "content": "/*\n * Copyright 2016-2017 Diomidis Spinellis and Marios Fragkoulis\n *\n * Dgsh public API\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#ifndef DGSH_H\n#define DGSH_H\n\n#define DGSH_HANDLE_ERROR 0x100\n\nint\ndgsh_negotiate(int flags, const char *tool_name, int *n_input_fds,\n\t\tint *n_output_fds, int **input_fds, int **output_fds);\n\n#endif\n"
  },
  {
    "path": "core-tools/src/dgsh_negotiate.3",
    "content": ".TH DGSH_NEGOTIATE 3 \"16 February 2017\"\n.\\\"\n.\\\" (C) Copyright 2017 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\ndgsh_negotiate \\- specify and obtain dgsh I/O file descriptors\n.SH SYNOPSIS\n.nf\n.B #include <dgsh.h>\n.sp\n.BI \"dgsh_negotiate(int \" flags \", const char *\" program_name \",\n.BI \"               int *\" n_input_fds \", int *\" n_output_fds ,\n.BI \"               int **\" input_fds \", int **\" output_fds );\n.fi\n.sp\nLink with \\fI\\-ldgsh\\fP.\n.sp\n.SH DESCRIPTION\nThe\n.BR dgsh_negotiate ()\nfunction is called before a program participates in a\n.IR dgsh (1)\ngraph to specify the number of input and output file descriptors\nthe program can handle, and obtain the file descriptors to be used.\n.PP\nThe\n.I flags\nparameter adjusts the function's behavior.\nThe following flags are defined.\n.TP\n.B DGSH_HANDLE_ERROR .\nWhen this flag is set and the negotiation for creating the graph\nof communicating processes encounters an error,\nthe function will print an error message to standard error\n(if required)\nand cause the calling program to exit with the error value\n.IR EX_PROTOCOL \" (76).\"\n.PP\nThe\n.I program_name\nparameter should be specified to match the name of the program\ncalling the function, to aid error reporting and debugging.\n.PP\nThe\n.I n_input_fds\nand\n.I n_output_fds\nparameters are used to pass by reference the number of input\nor output file descriptors required,\nand obtain upon return the corresponding number of descriptors supplied.\nPassing a null pointer indicates that the program can handle zero or\none descriptor.\nIn this case, if a variable contains the value of 1 when the function\nreturns, the program can use the standard input or output\nfor the corresponding channel and no descriptors are returned through\n.I input_fds\nor\n.IR output_fds .\nPassing a value of -1 indicates that the program can handle an arbitrary\nnumber of corresponding file descriptors.\nIn this case, upon return the variable will contain the actual number\nof file descriptors allocated to the program through the negotiation\nprocess.\n.PP\nThe\n.I input_fds\nand\n.I output_fds parameters\nare used to return a pointer to a sequence of integers\ncontaining the file descriptors to use for input or output.\nThe size of the integer sequence is equal to the returned\ncorresponding value of\n.I n_input_fds\nand\n.IR n_output_fds .\nThe pointers may subsequently be used as an argument to the function\n.IR free (3).\n.PP\nEach tool in the \\fIdgsh\\fP graph calls\n.BR dgsh_negotiate ()\nto take part in a peer-to-peer negotiation.\nA message block is circulated among tools and is filled with tools'\nI/O requirements.\nWhen all requirements are in place, an algorithm runs to find a solution\nthat satisfies all requirements.\nIf a solution is found, pipes are allocated and set up according to the\nsolution.\nThe appropriate file descriptors are provided to each tool and the negotiation\nphase ends.\n.SH RETURN VALUE\nOn success, the function returns 0, on failure it returns -1.\n.SH ENVIRONMENT\nThe following environment variables affect the negotiation to create\nthe communication graph.\n.TP\n.B DGSH_DEBUG_LEVEL\nSetting this variable to an integer\n(see the section \\fBDEBUGGING\\fP below)\ncauses the function to output debug data regarding the negotiation\non its standard error.\n.TP\n.B DGSH_DOT_DRAW\nSetting this variable to a file path causes the \\fIdgsh\\fP negotiation\nto save the graph of the communication processes in that file.\nThe graph is saved in\n.IR dot (1)\nformat.\n.TP\n.B DGSH_DOT_DRAW_EXIT\nSetting this variable in conjunction with \\fBDGSH_DOT_DRAW\\fP\ncauses all processes participating in the negotiation to exit after\nthe graph is saved to the file.\n.TP\n.B DGSH_TIMEOUT\nSetting this variable to an integer value specifies the number of\nseconds \\fIdgsh\\fP processes will wait for the negotiation to comlete\nbefore timing out and exiting.\nThe default value is five seconds, but this value may need to be increased\nfor negotiations that take a long time to complete.\n\n.SH DEBUGGING\nThe DGSH_DEBUG_LEVEL environment variable controls\ndebug output, which appears in \\fIstderr\\fP.\nThe default level 0 produces no debug output.\n.TP\n.B DGSH_DEBUG_LEVEL=1\nLevel 1 outputs the phases of the negotiation process, that\nis gather I/O requirements, compute the solution, and\ncommunicate the solution.\n.TP\n.B DGSH_DEBUG_LEVEL=2\nLevel 2 outputs the progress of the negotiation process\nby each command.\n.B DGSH_DEBUG_LEVEL=3\nLevel 3 outputs the reading and writing of the message block\nby each command as it flows across the process graph.\n.TP\n.B DGSH_DEBUG_LEVEL=4\nLevel 4 outputs the complete debug output including the\nshell's initial setup of the process graph.\nThis is very verbose.\n.SH ERROR MANAGEMENT\nThings can go wrong in two ways.\nFirst, a command might exit before reaching the call to\n.BR dgsh_negotiate ()\nbecause of invalid command-line arguments for instance.\nSecond, a command might not be able to complete the negotiation procedure\nbecause another command aborted during the negotiation.\nFor commands that aborted before stepping into the negotiation procedure,\na handler function is called on their exit and starts a negotiation\nprocedure to inform the other commands on the\n\\fIdgsh\\fP graph of the error state.\nThe exit handler is there for commands that link to the \\fIdgsh\\fP library.\nThis happens by calling\n.BR dgsh_negotiate ()\nand linking to the library or with the use of \\fIdgsh-wrap(1)\\fP.\nFor commands that stuck in the negotiation procedure because another\ncommand aborted during it, an alarm signal triggers an exit after 5\nseconds spent in negotiation to help commands exit it.\n\n.SH EXAMPLES\n.PP\nThe following simple implementation of echo does not receive any\ninput and provides one output channel.\n.ft C\n.ps -1\n.nf\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"dgsh.h\"\n\nint\nmain(int argc, char *argv[])\n{\n\tint n_input_fds = 0;\n\tint n_output_fds = 1;\n\n\tif (dgsh_negotiate(DGSH_HANDLE_ERROR, \"echo\", &n_input_fds,\n\t\t\t&n_output_fds, NULL, NULL) != 0)\n\t\terrx(1, \"Negotiation failed\");\n\n\tassert(n_input_fds == 0);\n\tassert(n_output_fds == 1);\n\n\t++argv;\n\twhile (*argv) {\n\t\t(void)printf(\"%s\", *argv);\n\t\tif (*++argv)\n\t\t\tputchar(' ');\n\t}\n\tputchar('\\n');\n\n\treturn 0;\n}\n.fi\n.ps +1\n.ft P\n.PP\nThe following program will enumerate its output channels.\n.ft C\n.ps -1\n.nf\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <err.h>\n#include <unistd.h>\n\n#include \"dgsh.h\"\n\nint\nmain(int argc, char *argv[])\n{\n\tint n_input_fds = 0, n_output_fds;\n\tint *output_fds;\n\tint i;\n\n\tswitch (argc) {\n\tcase 1:\n\t\tn_output_fds = -1;\n\t\tbreak;\n\tcase 2:\n\t\tn_output_fds = atoi(argv[1]);\n\t\tbreak;\n\tdefault:\n\t\terrx(1, \"usage: %s [n]\", argv[0]);\n\t}\n\n\n\tif (dgsh_negotiate(DGSH_HANDLE_ERROR, argv[0], &n_input_fds,\n\t\t\t&n_output_fds, NULL, &output_fds) != 0)\n\t\terrx(1, \"Negotiation failed\");\n\n\tfor (i = 0; i < n_output_fds; i++) {\n\t\tchar buff[10];\n\n\t\tsnprintf(buff, sizeof(buff), \"%d\\n\", i);\n\t\twrite(output_fds[i], buff, strlen(buff));\n\t\tclose(output_fds[i]);\n\t}\n\n\treturn 0;\n}\n.fi\n.ps +1\n.ft P\n.SH SEE ALSO\n.BR dgsh (1),\n.BR dgsh-wrap (1).\n.SH AUTHOR\nThe\n.B dgsh_negotiate\nAPI and negotiation algorithm\nwere designed by Diomidis Spinellis\nand extended and implemented by Marios Fragkoulis.\n"
  },
  {
    "path": "core-tools/src/kvstore.c",
    "content": "/*\n * Copyright 2013 Diomidis Spinellis\n *\n * Communicate with the data store specified as a Unix-domain socket.\n * (API)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <sys/uio.h>\n#include <sys/un.h>\n#include <assert.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <err.h>\n#include <errno.h>\n#include <limits.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"dgsh.h\"\n#include \"kvstore.h\"\n#include \"debug.h\"\n\nint retry_limit = 10;\n\n/* Write a command to the specified socket, and return the socket */\nstatic int\nwrite_command(const char *name, char cmd, bool retry_connection)\n{\n\tint s;\n\tsocklen_t len;\n\tstruct sockaddr_un remote;\n\tint counter = 0;\n\tchar *env_retry_limit;\n\n\tif ((env_retry_limit = getenv(\"KVSTORE_RETRY_LIMIT\")) != NULL)\n\t\tretry_limit = atoi(env_retry_limit);\n\n\tif ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)\n\t\terr(1, \"socket\");\n\n\tDPRINTF(3, \"Connecting to %s\", name);\n\n\tremote.sun_family = AF_UNIX;\n\tif (strlen(name) >= sizeof(remote.sun_path) - 1)\n\t\terrx(6, \"Socket name [%s] must be shorter than %d characters\",\n\t\t\tname, (int)sizeof(remote.sun_path));\n\tstrcpy(remote.sun_path, name);\n\tlen = strlen(remote.sun_path) + 1 + sizeof(remote.sun_family);\nagain:\n\tif (connect(s, (struct sockaddr *)&remote, len) == -1) {\n\t\tif (retry_connection &&\n\t\t    (errno == ENOENT || errno == ECONNREFUSED) &&\n\t\t    counter++ < retry_limit) {\n\t\t\tDPRINTF(3, \"Retrying connection setup\");\n\t\t\tsleep(1);\n\t\t\tgoto again;\n\t\t}\n\t\terr(2, \"connect %s\", name);\n\t}\n\tDPRINTF(3, \"Connected\");\n\n\tif (write(s, &cmd, 1) == -1)\n\t\terr(3, \"write\");\n\tDPRINTF(3, \"Wrote command\");\n\treturn s;\n}\n\n/* Send to the socket path the specified command */\nvoid\ndgsh_send_command(const char *socket_path, char cmd, bool retry_connection,\n    bool quit, int outfd)\n{\n\tint s, n;\n\tchar buff[PIPE_BUF];\n\tint content_length;\n\tchar cbuff[CONTENT_LENGTH_DIGITS + 2];\n\tstruct iovec iov[2];\n\n\tswitch (cmd) {\n\tcase 0:\t\t/* No I/O specified */\n\t\tbreak;\n\tcase 'C':\t/* Read current value */\n\tcase 'c':\t/* Read current value, non-blocking */\n\tcase 'L':\t/* Read last value */\n\t\ts = write_command(socket_path, cmd, retry_connection);\n\n\t\t/* Read content length and some data */\n\t\tiov[0].iov_base = cbuff;\n\t\tiov[0].iov_len = CONTENT_LENGTH_DIGITS;\n\t\tiov[1].iov_base = buff;\n\t\tiov[1].iov_len = sizeof(buff);\n\t\tif ((n = readv(s, iov, 2)) == -1)\n\t\t\terr(5, \"readv\");\n\t\tDPRINTF(3, \"Read %d characters\", n);\n\t\tcbuff[CONTENT_LENGTH_DIGITS] = 0;\n\t\tif (sscanf(cbuff, \"%u\", &content_length) != 1) {\n\t\t\tfprintf(stderr, \"Unable to read content length from string [%s]\\n\", cbuff);\n\t\t\texit(1);\n\t\t}\n\t\tDPRINTF(3, \"Content length is %u\", content_length);\n\t\tn -= CONTENT_LENGTH_DIGITS;\n\t\tif (write(outfd, buff, n) == -1)\n\t\t\terr(4, \"write\");\n\t\tcontent_length -= n;\n\n\t\t/* Read rest of data */\n\t\twhile (content_length > 0) {\n\t\t\tif ((n = read(s, buff, sizeof(buff))) == -1)\n\t\t\t\terr(5, \"read\");\n\t\t\tDPRINTF(4, \"Read %d bytes\", n);\n\t\t\tif (write(outfd, buff, n) == -1)\n\t\t\t\terr(4, \"write\");\n\t\t\tcontent_length -= n;\n\t\t}\n\t\tclose(s);\n\t\tbreak;\n\tdefault:\n\t\tassert(0);\n\t\tbreak;\n\t}\n\n\tif (quit)\n\t\t(void)write_command(socket_path, 'Q', retry_connection);\n}\n"
  },
  {
    "path": "core-tools/src/kvstore.h",
    "content": "/*\n * Copyright 2013 Diomidis Spinellis\n *\n * Communicate with the data store specified as a Unix-domain socket.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#ifndef KVSTORE_H\n#define KVSTORE_H\n\n#include <stdbool.h>\n\n/* Send to the socket path the specified command */\nvoid dgsh_send_command(const char *socket_path, char cmd, bool retry_connection,\n    bool quit, int outfd);\n\n/*\n * The read/write store communication protocol is as follows\n * readval -> writeval: L | Q | C\n * For L (read last) and C (read current)\n * writeval -> readval: CONTENT_LENGTH content ...\n * If writeval gets EOF it returns an empty (length 0) record, if no record\n * can ever appear.\n * For Q (quit) writeval exits\n */\n#define CONTENT_LENGTH_DIGITS 10\n#define CONTENT_LENGTH_FORMAT \"%010u\"\n\n#endif /* KVSTORE_H */\n"
  },
  {
    "path": "core-tools/src/minmax.h",
    "content": "/*\n * Copyright 2013-2017 Diomidis Spinellis\n *\n * MIN and MAX macros\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#ifndef MINMAX_H\n#define MINMAX_H\n\n#define MAX(a, b) ((a) > (b) ? (a) : (b))\n#define MIN(a, b) ((a) < (b) ? (a) : (b))\n\n#endif /* MINMAX_H */\n"
  },
  {
    "path": "core-tools/src/negotiate.c",
    "content": "/*\n * Copyright 2016, 2017 Marios Fragkoulis\n *\n * A passive component that aids the dgsh negotiation by passing\n * message blocks among participating processes.\n * When the negotiation is finished and the processes get connected by\n * pipes, it exits.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <assert.h>\t\t/* assert() */\n#include <errno.h>\t\t/* ENOBUFS */\n#include <err.h>\t\t/* err() */\n#include <limits.h>\t\t/* IOV_MAX */\n#include <stdbool.h>\t\t/* bool, true, false */\n#include <stdio.h>\t\t/* fprintf() in DPRINTF() */\n#include <stdlib.h>\t\t/* getenv(), errno, atexit() */\n#include <string.h>\t\t/* memcpy() */\n#include <sysexits.h>\t\t/* EX_PROTOCOL, EX_OK */\n#include <sys/socket.h>\t\t/* sendmsg(), recvmsg() */\n#include <unistd.h>\t\t/* getpid(), getpagesize(),\n\t\t\t\t * STDIN_FILENO, STDOUT_FILENO,\n\t\t\t\t * STDERR_FILENO, alarm(), sysconf()\n\t\t\t\t */\n#include <signal.h>\t\t/* signal(), SIGALRM */\n#include <time.h>\t\t/* nanosleep() */\n#include <sys/select.h>\t\t/* select(), fd_set, */\n#include <stdio.h>\t\t/* printf family */\n\n#include \"negotiate.h\"\t\t/* Message block and I/O */\n#include \"dgsh-debug.h\"\t\t/* DPRINTF() */\n\n#ifdef TIME\n#include <time.h>\nstatic struct timespec tstart={0,0}, tend={0,0};\n#endif\n\n/* Default negotiation timeout (s) */\n#define DGSH_TIMEOUT 5\n\n#ifndef UNIT_TESTING\n\n/* Models an I/O connection between tools on an dgsh graph. */\nstruct dgsh_edge {\n\tint from;\t\t/* Index of node on the graph where data\n\t\t\t\t * comes from (out).\n\t\t\t\t */\n\tint to;\t\t\t/* Index of node on the graph that\n\t\t\t\t * receives the data (in).\n\t\t\t\t */\n\tint instances;\t\t/* Number of instances of an edge. */\n\tint from_instances;\t/* Number of instances the origin node of\n\t\t\t\t * an edge can provide.\n\t\t\t\t */\n\tint to_instances;\t/* Number of instances the destination\n\t\t\t\t * of an edge can require.\n\t\t\t\t */\n};\n\n#endif\n\n/* Each tool that participates in an dgsh graph is modelled as follows. */\nstruct dgsh_node {\n        pid_t pid;\n\tint index;\t\t/* Position in message block's node array. */\n        char name[100];\t\t/* Tool's name */\n        int requires_channels;\t/* Input channels it can take. */\n        int provides_channels;\t/* Output channels it can provide. */\n\tint dgsh_in;\t\t/* Takes input from other tool(s) on\n\t\t\t\t * dgsh graph.\n\t\t\t\t */\n\tint dgsh_out;\t\t/* Provides output to other tool(s)\n\t\t\t\t * on dgsh graph.\n\t\t\t\t */\n};\n\n/* Holds a node's connections. It contains a piece of the solution. */\nstruct dgsh_node_connections {\n\tint node_index;\t\t\t\t/* The subject of the\n\t\t\t\t\t\t * connections. For\n\t\t\t\t\t\t * verification.\n\t\t\t\t\t\t */\n\tstruct dgsh_edge *edges_incoming;\t/* Array of edges through\n\t\t\t\t\t\t * which other nodes provide\n\t\t\t\t\t\t * input to node at node_index.\n\t\t\t\t\t\t */\n\tint n_edges_incoming;\t\t\t/* Number of incoming edges */\n\tint n_instances_incoming_free;\t\t/* Number of incoming edges\n\t\t\t\t\t\t * not yet bound to a pair\n\t\t\t\t\t\t * node's output channel.\n\t\t\t\t\t\t */\n\tstruct dgsh_edge *edges_outgoing;\t/* Array of edges through\n\t\t\t\t\t\t * which a node provides\n\t\t\t\t\t\t * output to other nodes.\n\t\t\t\t\t\t */\n\tint n_edges_outgoing;\t\t\t/* Number of outgoing edges */\n\tint n_instances_outgoing_free;\t\t/* Number of outgoing edges\n\t\t\t\t\t\t * not yet binded to a pair\n\t\t\t\t\t\t * node's outgoing edges.\n\t\t\t\t\t\t */\n};\n\n/* The output of the negotiation process. */\nstruct dgsh_node_pipe_fds {\n\tint *input_fds;\t\t/* Array of input file descriptors */\n\tint n_input_fds;\t/* Number of input file descriptors */\n\tint *output_fds;\t/* Array of output file descriptors */\n\tint n_output_fds;\t/* Number of output file descriptors */\n};\n\n/**\n * Memory organisation of message block.\n * Message block will be passed around process address spaces.\n * Message block contains a number of scalar fields and two pointers\n * to an array of dgsh nodes and edges respectively.\n * To pass the message block along with nodes and edges, three writes\n * in this order take place.\n */\n\n/* The message block implicitly used by many functions */\nstruct dgsh_negotiation *chosen_mb;\nstatic struct dgsh_node self_node;\t\t/* The dgsh node that models\n\t\t\t\t\t\t   this tool. */\nstatic char *programname;\n\nstatic struct node_io_side self_node_io_side;\t/* Dispatch info for this tool. */\nstatic struct dgsh_node_pipe_fds self_pipe_fds;\t/* A tool's read and write file\n\t\t\t\t\t\t * descriptors to use at execution.\n\t\t\t\t\t\t */\nstatic bool init_error = false;\nstatic volatile sig_atomic_t negotiation_completed = 0;\nint dgsh_debug_level = 0;\n\nstatic void get_environment_vars();\nstatic int dgsh_exit(int state, int flags);\n\n/* Force the inclusion of the ELF note section */\nextern int dgsh_force_include;\nvoid\ndgsh_force_include_function(void)\n{\n\tdgsh_force_include = 1;\n}\n\n\n#ifndef UNIT_TESTING\nstatic void\ndgsh_exit_handler(void)\n{\n\tif (negotiation_completed)\n\t\treturn;\n\tinit_error = true;\n\t/* Finish negotiation, if required */\n\tget_environment_vars();\n\tif (self_node.dgsh_in != 0 || self_node.dgsh_out != 0) {\n\t\twarnx(\"exiting before dgsh negotiation is complete\");\n\t\tDPRINTF(4, \"dgsh: error state. Enter negotiation to inform the graph\");\n\t\tdgsh_negotiate(0, programname ? programname : \"dgsh client\", NULL,\n\t\t\t\tNULL, NULL, NULL);\n\t}\n}\n#endif\n\nvoid\ndgsh_alarm_handler(int signal)\n{\n\tif (signal == SIGALRM)\n\t\tif (negotiation_completed == 0) {\n\t\t\tchar msg[100];\n\t\t\tsprintf(msg, \"%d dgsh: timeout for negotiation. Exit.\\n\",\n\t\t\t\t\tgetpid());\n\t\t\tnegotiation_completed = 1;\n\t\t\twrite(2, msg, strlen(msg));\n\t\t\t_exit(EX_PROTOCOL);\n\t\t}\n}\n\n#ifndef UNIT_TESTING\n__attribute__((constructor))\nstatic void\ninstall_exit_handler(void)\n{\n\tatexit(dgsh_exit_handler);\n}\n#endif\n\nstatic int iov_max;\n\n// Setup iov_max handling runtime, even if it is defined at runtime\n__attribute__((constructor))\nstatic void\nsetup_iov_max(void)\n{\n#if defined(IOV_MAX)\n        iov_max = IOV_MAX;\n#else\n        iov_max = (int)sysconf(_SC_IOV_MAX);\n#endif\n}\n\n/**\n * Remove path to command to save space in the graph plot\n * Find first space if any and take the name up to there\n * Find and remove path prepended to the name\n * Rejoin the name with arguments\n * Escape double quotes\n */\nSTATIC void\nprocess_node_name(char *name, char **processed_name)\n{\n\tchar no_path_name[strlen(name)];\n\tmemset(no_path_name, 0, sizeof(no_path_name));\n\tchar *s = strstr(name, \" \");\n\n\tDPRINTF(4, \"Node name to process: %s\", name);\n\tif (s)\n\t\tstrncpy(no_path_name, name, s - name);\n\telse\n\t\tstrcpy(no_path_name, name);\n\n\tDPRINTF(4, \"no_path_name: %s, s: %s\", no_path_name, s);\n\tchar *p = no_path_name;\n\tchar *m = strstr(no_path_name, \"/\");\n\twhile (m) {\n\t\tp = ++m;\n\t\tm = strstr(m, \"/\");\n\t}\n\tDPRINTF(4, \"no_path_name: %s, m: %s\", no_path_name, m);\n\n\tif (s)\n\t\tsprintf(no_path_name, \"%s%s\", p, s);\n\n\tDPRINTF(4, \"no_path_name: %s, p: %s\", no_path_name, p);\n\tm = strstr(no_path_name, \"\\\"\");\n\tchar *mm = NULL;\n\twhile (m) {\n\t\tDPRINTF(4, \"processed_name: %s, m: %s, mm: %s\",\n\t\t\t\t*processed_name, m, mm);\n\t\tif (strlen(*processed_name) == 0)\n\t\t\tstrncpy(*processed_name, no_path_name, m - no_path_name);\n\t\telse {\n\t\t\tstrcat(*processed_name, \"\\\\\");\n\t\t\tstrncat(*processed_name, mm, m - mm);\n\t\t\tDPRINTF(4, \"processed_name: %s, m - mm: %ld\",\n\t\t\t\t\t*processed_name, (long)(m - mm));\n\t\t}\n\t\tmm = m;\n\t\tm = strstr(++m, \"\\\"\");\n\t}\n\tif (mm) {\n\t\tstrcat(*processed_name, \"\\\\\");\n\t\tstrcat(*processed_name, mm);\n\t} else\n\t\tstrcpy(*processed_name, no_path_name);\n\n\tDPRINTF(4, \"final processed_name: %s, m: %s, mm: %s\",\n\t\t\t\t*processed_name, m, mm);\n}\n\nSTATIC enum op_result\noutput_graph(char *filename)\n{\n\tchar ffilename[strlen(filename) + 5];\t// + .dot\n\tsprintf(ffilename, \"%s.dot\", filename);\n\tFILE *f = fopen(ffilename, \"a\");\n\tif (f == NULL) {\n\t\tfprintf(stderr, \"Unable to open file %s\", ffilename);\n\t\treturn OP_ERROR;\n\t}\n\n\tchar fnfilename[strlen(filename) + 9];\t// + -ngt + .dot\n\tsprintf(fnfilename, \"%s-ngt.dot\", filename);\n\tFILE *fn = fopen(fnfilename, \"a\");\n\tif (fn == NULL) {\n\t\tfprintf(stderr, \"Unable to open file %s\", fnfilename);\n\t\treturn OP_ERROR;\n\t}\n\n\tint i, j;\n\tint n_nodes = chosen_mb->n_nodes;\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\t\tchosen_mb->graph_solution;\n\n\tDPRINTF(4, \"Output graph in file %s for %d nodes and %d edges\",\n\t\t\tfilename, n_nodes, chosen_mb->n_edges);\n\n\tfprintf(f, \"digraph {\\n\");\n\tfprintf(fn, \"digraph {\\n\");\n\n\tfor (i = 0; i < n_nodes; i++) {\n\t\tstruct dgsh_node *node = &chosen_mb->node_array[i];\n\t\tstruct dgsh_node_connections *connections =\n\t\t\t\t\t\t&graph_solution[i];\n\t\tint n_edges_outgoing = connections->n_edges_outgoing;\n\n\t\tDPRINTF(4, \"Output node: %s\", node->name);\n\t\t// Reserve space for quotes\n\t\tint q = 0;\n\t\tchar *m = strstr(node->name, \"\\\"\");\n\t\twhile (m) {\n\t\t\tq++;\n\t\t\tm = strstr(++m, \"\\\"\");\n\t\t}\n\t\tchar *processed_name = (char *)malloc(sizeof(char) *\n\t\t\t\t\t\t(strlen(node->name) + q + 1));\n\t\tDPRINTF(4, \"Malloc %d bytes for processed_name\",\n\t\t\t\t\t(int)strlen(node->name) + q + 1);\n\t\tmemset(processed_name, 0, strlen(node->name) + q + 1);\n\t\tprocess_node_name(node->name, &processed_name);\n\n#ifdef DEBUG\n\t\tfprintf(f, \"\tn%d [label=\\\"%d %s\\\"];\\n\",\n\t\t\t\tnode->index, node->index,\n\t\t\t\tprocessed_name);\n\t\tfprintf(fn, \"\tn%d [label=\\\"%d %s\\\"];\\n\",\n\t\t\t\tnode->index, node->index,\n\t\t\t\tprocessed_name);\n#else\n\t\tfprintf(f, \"\tn%d [label=\\\"%s\\\"];\\n\",\n\t\t\t\tnode->index, processed_name);\n\t\tfprintf(fn, \"\tn%d [label=\\\"%s\\\"];\\n\",\n\t\t\t\tnode->index, processed_name);\n#endif\n\t\tDPRINTF(4, \"Node: (%d) %s\", node->index, processed_name);\n\n\t\tfree(processed_name);\n\t\tfor (j = 0; j < n_edges_outgoing; j++) {\n\t\t\tfprintf(fn, \"\tn%d -> n%d;\\n\",\n\t\t\t\tnode->index,\n\t\t\t\tchosen_mb->node_array[connections->edges_outgoing[j].to].index);\n\t\t\t\n\t\t\tif (connections->edges_outgoing[j].instances == 0)\n\t\t\t\tcontinue;\n\n\t\t\tfprintf(f, \"\tn%d -> n%d;\\n\",\n\t\t\t\tnode->index,\n\t\t\t\tchosen_mb->node_array[connections->edges_outgoing[j].to].index);\n\t\t\tDPRINTF(4, \"Edge: (%d) %s -> %s (%d)\",\n\t\t\t\tnode->index, node->name,\n\t\t\t\tchosen_mb->node_array[connections->edges_outgoing[j].to].name,\n\t\t\t\tchosen_mb->node_array[connections->edges_outgoing[j].to].index);\n\t\t}\n\t}\n\n\tfprintf(f, \"}\\n\");\n\tfprintf(fn, \"}\\n\");\n\n\tfclose(f);\n\tfclose(fn);\n\treturn OP_SUCCESS;\n}\n\n/**\n * Allocate node indexes to store a node's (at node_index)\n * node outgoing or incoming connections (nc_edges).\n */\nSTATIC enum op_result\nalloc_node_connections(struct dgsh_edge **nc_edges, int nc_n_edges, int type,\n\t\t\t\t\t\t\t\tint node_index)\n{\n\tif (!nc_edges) {\n\t\tDPRINTF(4, \"ERROR: Double pointer to node connection edges is NULL.\\n\");\n\t\treturn OP_ERROR;\n\t}\n\tif (node_index < 0) {\n\t\tDPRINTF(4, \"ERROR: Index of node whose connections will be allocated is negative number.\\n\");\n\t\treturn OP_ERROR;\n\t}\n\tif (type > 1 || type < 0) {\n\t\tDPRINTF(4, \"ERROR: Type of edge is neither incoming (1) nor outgoing(0).\\ntyep is: %d.\\n\", type);\n\t\treturn OP_ERROR;\n\t}\n\n\t*nc_edges = (struct dgsh_edge *)malloc(sizeof(struct dgsh_edge) *\n\t\t\t\t\t\t\t\tnc_n_edges);\n\tif (!*nc_edges) {\n\t\tDPRINTF(4, \"ERROR: Memory allocation for node's index %d %s connections \\\nfailed.\\n\", node_index, (type) ? \"incoming\" : \"outgoing\");\n\n\t\treturn OP_ERROR;\n\t}\n\treturn OP_SUCCESS;\n}\n\n/**\n * Copy the array of pointers to edges that go to or leave from a node\n * (i.e. its incoming or outgoing connections) to a self-contained compact\n * array of edges for easy transmission and receipt in one piece.\n */\nSTATIC enum op_result\nmake_compact_edge_array(struct dgsh_edge **nc_edges, int nc_n_edges,\n\t\t\tstruct dgsh_edge **p_edges)\n{\n\tint i;\n\tint array_size = sizeof(struct dgsh_edge) * nc_n_edges;\n\n\tif (nc_n_edges <= 0) {\n\t\tDPRINTF(4, \"ERROR: Size identifier to be used in malloc() is non-positive number: %d.\\n\", nc_n_edges);\n\t\treturn OP_ERROR;\n\t}\n\tif (nc_edges == NULL) {\n\t\tDPRINTF(4, \"ERROR: Compact edge array to put edges (connections) is NULL.\\n\");\n\t\treturn OP_ERROR;\n\t}\n\tif (p_edges == NULL) {\n\t\tDPRINTF(4, \"ERROR: Pointer to edge array is NULL.\\n\");\n\t\treturn OP_ERROR;\n\t}\n\n\t*nc_edges = (struct dgsh_edge *)malloc(array_size);\n\tif (!(*nc_edges)) {\n\t\tDPRINTF(4, \"ERROR: Memory allocation of size %d for edge array failed.\\n\",\n\t\t\t\t\t\t\t\tarray_size);\n\t\treturn OP_ERROR;\n\t}\n\n\t/**\n\t * Copy the edges of interest to the node-specific edge array\n\t * that contains its connections.\n\t */\n\tfor (i = 0; i < nc_n_edges; i++) {\n\t\tif (p_edges[i] == NULL) {\n\t\t\tDPRINTF(4, \"ERROR: Pointer to edge array contains NULL pointer.\\n\");\n\t\t\treturn OP_ERROR;\n\t\t}\n\t\t/**\n\t\t * Dereference to reach the array base, make i hops of size\n\t\t * sizeof(struct dgsh_edge), and point to that memory block.\n\t\t */\n\t\tmemcpy(&(*nc_edges)[i], p_edges[i], sizeof(struct dgsh_edge));\n\t\tDPRINTF(4, \"%s():Copied edge %d -> %d (%d) at index %d.\",\n\t\t\t\t__func__, p_edges[i]->from, p_edges[i]->to,\n\t\t\t\tp_edges[i]->instances, i);\n\t}\n\n\treturn OP_SUCCESS;\n}\n\n/* Reallocate array to edge pointers. */\nSTATIC enum op_result\nreallocate_edge_pointer_array(struct dgsh_edge ***edge_array, int n_elements)\n{\n\tvoid **p = NULL;\n\tif (edge_array == NULL) {\n\t\tDPRINTF(4, \"ERROR: Edge array is NULL pointer.\\n\");\n\t\treturn OP_ERROR;\n\t}\n\tif (n_elements <= 0) {\n\t\tDPRINTF(4, \"ERROR: Size identifier to be used in malloc() is non-positive number: %d.\\n\", n_elements);\n\t\treturn OP_ERROR;\n\t} else if (n_elements == 1)\n\t\tp = malloc(sizeof(struct dgsh_edge *) * n_elements);\n\telse\n\t\tp = realloc(*edge_array,\n\t\t\t\tsizeof(struct dgsh_edge *) * n_elements);\n\tif (!p) {\n\t\tDPRINTF(4, \"ERROR: Memory reallocation for edge failed.\\n\");\n\t\treturn OP_ERROR;\n\t} else\n\t\t*edge_array = (struct dgsh_edge **)p;\n\treturn OP_SUCCESS;\n}\n\n/**\n * Gather the constraints on a node's input or output channel\n * and then try to find a solution that respects both the node's\n * channel constraint and the pair nodes' corresponding channel\n * constraints if edges on the channel exist.\n * The function is not called otherwise.\n\n * If a solution is found, allocate edge instances to each edge that\n * includes the node's channel (has to do with the flexible constraint).\n */\nstatic enum op_result\nsatisfy_io_constraints(int *free_instances,\n\t\t       int this_channel_constraint,\t/* A node's required or\n\t\t\t\t\t\t\t * provided constraint\n\t\t\t\t\t\t\t * on this channel\n\t\t\t\t\t\t\t */\n                       struct dgsh_edge **edges, /* Gathered pointers to edges\n\t\t\t\t\t\t  * of this channel\n\t\t\t\t\t\t  */\n\t\t       int n_edges,\t\t/* Number of edges */\n                       bool is_edge_incoming)\t/* Incoming or outgoing */\n{\n\tint i;\n\tint weight = -1, modulo = 0;\n\n\tif (this_channel_constraint > 0) {\n\t\t*free_instances = this_channel_constraint;\n\t\tweight = this_channel_constraint / n_edges;\n\t\tmodulo = this_channel_constraint % n_edges;\n\n\t/* Edges that have no place in actual execution */\n\t} else if (this_channel_constraint == 0) {\n\t\t\t*free_instances = 0;\n\t\t\tweight = 0;\n\t\t\tmodulo = 0;\n\t} else\t/* Flexible constraint */\n\t\t*free_instances = -1;\n\n\t/* Aggregate the constraints for the node's channel. */\n\tfor (i = 0; i < n_edges; i++) {\n\t\tif (this_channel_constraint > 0)\n\t\t\t*free_instances -= weight + (modulo > 0);\n\t\tif (is_edge_incoming) /* Outgoing for the pair node of edge */\n\t\t\tedges[i]->to_instances = weight + (modulo > 0);\n\t\telse\n\t\t\tedges[i]->from_instances = weight + (modulo > 0);\n\t\tif (modulo > 0)\n\t\t\tmodulo--;\n        \tDPRINTF(4, \"%s(): edge from %d to %d, is_edge_incoming: %d, free_instances: %d, weight: %d, modulo: %d, from_instances: %d, to_instances: %d.\\n\", __func__, edges[i]->from, edges[i]->to, is_edge_incoming, *free_instances, weight, modulo, edges[i]->from_instances, edges[i]->to_instances);\n\t}\n\tDPRINTF(4, \"%s(): Number of edges: %d, this_channel_constraint: %d, free instances: %d.\\n\", __func__, n_edges, this_channel_constraint, *free_instances);\n\treturn OP_SUCCESS;\n}\n\n/**\n * Lookup this tool's edges and store pointers to them in order\n * to then allow the evaluation of constraints for the current node's\n * input and output channels.\n */\nstatic enum op_result\ndry_match_io_constraints(struct dgsh_node *current_node,\n\t\t\t struct dgsh_node_connections *current_connections,\n\t\t\t struct dgsh_edge ***edges_incoming, /* Uninitialised*/\n\t\t\t struct dgsh_edge ***edges_outgoing) /* Uninitialised*/\n{\n\tint n_edges = chosen_mb->n_edges;\n\tint n_free_in_channels = current_node->requires_channels;\n\tint n_free_out_channels = current_node->provides_channels;\n\tint node_index = current_node->index;\n        int *n_edges_incoming = &current_connections->n_edges_incoming;\n        int *n_edges_outgoing = &current_connections->n_edges_outgoing;\n\tint i;\n\n\tassert(node_index < chosen_mb->n_nodes);\n\n\t/* Gather incoming/outgoing edges for node at node_index. */\n\tfor (i = 0; i < n_edges; i++) {\n\t\tstruct dgsh_edge *edge = &chosen_mb->edge_array[i];\n\t\tDPRINTF(4, \"%s(): edge at index %d from %d to %d, instances %d, from_instances %d, to_instances %d.\", __func__, i, edge->from, edge->to, edge->instances, edge->from_instances, edge->to_instances);\n\t\tif (edge->from == node_index) {\n\t\t\t(*n_edges_outgoing)++;\n\t\t\tif (reallocate_edge_pointer_array(edges_outgoing,\n\t\t\t\t\t*n_edges_outgoing) == OP_ERROR)\n\t\t\t\treturn OP_ERROR;\n\t\t\t(*edges_outgoing)[*n_edges_outgoing - 1] = edge;\n\t\t}\n\t\tif (edge->to == node_index) {\n\t\t\t(*n_edges_incoming)++;\n\t\t\tif (reallocate_edge_pointer_array(edges_incoming,\n\t\t\t\t\t*n_edges_incoming) == OP_ERROR)\n\t\t\t\treturn OP_ERROR;\n\t\t\t(*edges_incoming)[*n_edges_incoming - 1] = edge;\n\t\t}\n\t}\n\tDPRINTF(4, \"%s(): Node at index %d has %d outgoing edges and %d incoming.\",\n\t\t\t\t__func__, node_index, *n_edges_outgoing,\n\t\t\t\t*n_edges_incoming);\n\n\t/* Record the input/output constraints at node level. */\n\tif (*n_edges_outgoing > 0)\n\t\tif (satisfy_io_constraints(\n\t\t    &current_connections->n_instances_outgoing_free,\n\t\t    n_free_out_channels,\n\t\t    *edges_outgoing, *n_edges_outgoing, 0) == OP_ERROR)\n\t\t\treturn OP_ERROR;\n\tif (*n_edges_incoming > 0)\n\t\tif (satisfy_io_constraints(\n\t\t    &current_connections->n_instances_incoming_free,\n\t\t    n_free_in_channels,\n\t\t    *edges_incoming, *n_edges_incoming, 1) == OP_ERROR)\n\t\t\treturn OP_ERROR;\n\n\treturn OP_SUCCESS;\n}\n\n/**\n * Free the dgsh graph's solution in face of an error.\n * node_index: the last node we setup conenctions before error.\n */\nstatic enum op_result\nfree_graph_solution(int node_index)\n{\n\tint i;\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\t\tchosen_mb->graph_solution;\n\tassert(node_index < chosen_mb->n_nodes);\n\tfor (i = 0; i <= node_index; i++) {\n\t\tif (graph_solution[i].n_edges_incoming > 0)\n\t\t\tfree(graph_solution[i].edges_incoming);\n\t\tif (graph_solution[i].n_edges_outgoing > 0)\n\t\t\tfree(graph_solution[i].edges_outgoing);\n\t}\n\tfree(graph_solution);\n\tchosen_mb->graph_solution = NULL;\n\tDPRINTF(4, \"%s: freed %d nodes.\", __func__, chosen_mb->n_nodes);\n\treturn OP_SUCCESS;\n}\n\n/**\n * Add or subtract edge instances from an edge that meets a pair node's\n * flexible constraint.\n */\nstatic enum op_result\nrecord_move_flexible(int *diff, int *index, int to_move_index, int *instances,\n\t\t     int to_move)\n{\n\tif (*diff > 0 || (*diff < 0 && to_move > 1)) {\n\t\t/* In subtracting at least one edge instance should remain. */\n\t\tif (*diff < 0 && *diff + (to_move - 1) <= 0)\n\t\t\t\t*instances = -(to_move - 1);\n\t\telse\n\t\t\t\t*instances = *diff;\n\t\n\t\t*diff -= *instances;\n\t\t*index = to_move_index;\n\t\treturn OP_SUCCESS;\n\t}\n\treturn OP_NOOP;\n}\n\n/**\n * Add or subtract edge instances from an edge that is unbalanced wrt\n * the pair node's constraint.\n */\nstatic enum op_result\nrecord_move_unbalanced(int *diff, int *index, int to_move_index,\n\t\tint *instances, int to_move, int pair)\n{\n\tDPRINTF(4, \"%s(): to_move: %d, pair: %d, diff: %d\", __func__, to_move, pair, *diff);\n\t/* Can either to_move or pair be 0? I don't think so */\n\tif ((*diff > 0 && to_move < pair) ||\n\t    (*diff < 0 && to_move > pair)) {\n\t\t*index = to_move_index;\n\t\tif ((*diff > 0 && *diff - (pair - to_move) >= 0) ||\n\t\t    (*diff < 0 && *diff - (pair - to_move) <= 0))\n\t\t\t*instances = pair - to_move;\n\t\telse\n\t\t\t*instances = *diff;\n\t\t*diff -= *instances;\n\t\tDPRINTF(4, \"%s(): move successful: to_move: %d, pair: %d, diff: %d, instances: %d, edge index: %d\", __func__, to_move, pair, *diff, *instances, *index);\n\t\treturn OP_SUCCESS;\n\t}\n\treturn OP_NOOP;\n}\n\n/**\n * From the set of unbalanced constraints of a node wrt the pair node's\n * constraint on a specific channel, that is, input or output,\n * find instances to subtract or add to satisfy the constraint.\n * If that does not work try edges where the pair has a flexible constraint.\n */\nstatic enum op_result\nmove(struct dgsh_edge** edges, int n_edges, int diff, bool is_edge_incoming)\n{\n\tint i = 0, j = 0;\n\tint indexes[n_edges];\n\tint instances[n_edges];\n\t/* Try move unbalanced edges first.\n\t * Avoid doing the move at the same edge.\n\t */\n\tfor (i = 0; i < n_edges; i++) {\n\t\tstruct dgsh_edge *edge = edges[i];\n\t\tint *from = &edge->from_instances;\n\t\tint *to = &edge->to_instances;\n\t\tDPRINTF(4, \"%s(): before move %s edge %d: from: %d, to: %d, diff %d.\", __func__, is_edge_incoming ? \"incoming\" : \"outgoing\", i, *from, *to, diff);\n\t\tif (*from == -1 || *to == -1)\n\t\t\tcontinue;\n\t\tif (is_edge_incoming) {\n\t\t\tif (record_move_unbalanced(&diff, &indexes[j], i,\n\t\t\t\t&instances[j], *to, *from) == OP_SUCCESS)\n\t\t\t\tj++;\n\t\t} else {\n\t\t\tif (record_move_unbalanced(&diff, &indexes[j], i,\n\t\t\t\t&instances[j], *from, *to) == OP_SUCCESS)\n\t\t\t\tj++;\n\t\t}\n\t\tDPRINTF(4, \"%s(): after move %s edge %d: from: %d, to: %d, diff %d.\", __func__, is_edge_incoming ? \"incoming\" : \"outgoing\", i, *from, *to, diff);\n\t\tif (diff == 0)\n\t\t\tgoto checkout;\n\t}\n\t/* Edges with flexible constraints are by default balanced. Try move */\n\tfor (i = 0; i < n_edges; i++) {\n\t\tstruct dgsh_edge *edge = edges[i];\n\t\tint *from = &edge->from_instances;\n\t\tint *to = &edge->to_instances;\n\t\tif (is_edge_incoming) {\n\t\t\tif (*from >= 0)\n\t\t\t\tcontinue;\n\t\t\tif (record_move_flexible(&diff, &indexes[j], i,\n\t\t\t\t&instances[j], *to) == OP_SUCCESS)\n\t\t\t\tj++;\n\t\t} else {\n\t\t\tif (*to >= 0)\n\t\t\t\tcontinue;\n\t\t\tif (record_move_flexible(&diff, &indexes[j], i,\n\t\t\t\t&instances[j], *from) == OP_SUCCESS)\n\t\t\t\tj++;\n\t\t}\n\t\tif (diff == 0)\n\t\t\tgoto checkout;\n\t}\n\ncheckout:\n\tif (diff == 0) {\n\t\tint k = 0;\n\t\tfor (k = 0; k < j; k++) {\n\t\t\tif (is_edge_incoming)\n\t\t\t\tedges[indexes[k]]->to_instances += instances[k];\n\t\t\telse\n\t\t\t\tedges[indexes[k]]->from_instances +=\n\t\t\t\t\t\t\t\tinstances[k];\n\t\t\tDPRINTF(4, \"%s(): succeeded: move %d from edge %d.\", __func__, instances[k], indexes[k]);\n\t\t}\n\t\treturn OP_SUCCESS;\n\t}\n\treturn OP_RETRY;\n}\n\n/**\n * Try to find a solution that respects both the node's\n * channel constraint and the pair nodes' corresponding channel\n * constraints if edges on the channel exist.\n * The function is not called otherwise.\n\n * If a solution is found, allocate edge instances to each edge that\n * includes the node's channel (has to do with the flexible constraint).\n */\nstatic enum op_result\ncross_match_io_constraints(int *free_instances,\n\t\t\tint this_channel_constraint,\t/* A node's required\n\t\t\t\t\t\t\t * provided constraint\n\t\t\t\t\t\t\t * on the channel\n\t\t\t\t\t\t\t */\n                       struct dgsh_edge **edges,\t/* Gathered pointers\n\t\t\t\t\t\t\t * to edges\n\t\t\t\t\t\t\t */\n\t\t       int n_edges,\t\t/* Number of edges */\n                       bool is_edge_incoming,\t/* Incoming or outgoing edges*/\n\t\t       bool *constraints_matched,\n\t\t       int *edges_matched)\n{\n\tint i;\n\tint from_flex = 0;\n\tint to_flex = 0;\n\n\tfor (i = 0; i < n_edges; i++) {\n\t\tstruct dgsh_edge *e = edges[i];\n\t\tint *from = &e->from_instances;\n\t\tint *to = &e->to_instances;\n\t\tint matched = *edges_matched;\n\t\tif (*from == -1 || *to == -1) {\n        \t\tDPRINTF(4, \"%s(): edge from %d to %d, this_channel_constraint: %d, is_incoming: %d, from_instances: %d, to_instances %d.\\n\", __func__, e->from, e->to, this_channel_constraint, is_edge_incoming, *from, *to);\n\t\t\tif (*from == -1 && *to == -1) {\n\t\t\t\tfrom_flex++;\n\t\t\t\tto_flex++;\n\t\t\t\te->instances = 1;\t// TODO\n\t\t\t} else if (*from == -1) {\n\t\t\t\tfrom_flex++;\n\t\t\t\te->instances = *to;\n\t\t\t} else if (*to == -1) {\n\t\t\t\tto_flex++;\n\t\t\t\te->instances = *from;\n\t\t\t}\n\t\t\t(*edges_matched)++;\n\t\t\t/* fixed to more than one flexible\n\t\t\t * is not solvable in the general case\n\t\t\t */\n\t\t\tif (this_channel_constraint > 0 &&\n\t\t\t\t((is_edge_incoming && from_flex > 1) ||\n\t\t\t\t(!is_edge_incoming && to_flex > 1))) {\n\t\t\t\tfprintf(stderr,\n\t\t\t\t\t\"ERROR: More than one edges are flexible. Cannot compute solution. Exiting.\\n\");\n\t\t\t\treturn OP_ERROR;\n\t\t\t}\n\t\t} else if (*from == *to) {\n\t\t\t(*edges_matched)++;\n\t\t\te->instances = *from;\n\t\t} else if (*from < *to) { /* e.g. from=1, to=3; then: */\n\t\t\tif (is_edge_incoming) {         /* +2:  */\n\t\t\t\tif (move(edges, n_edges, (*to - *from), 1)\n\t\t\t\t\t\t\t== OP_SUCCESS) {\n\t\t\t\t\t*to -= (*to - *from); /* -2: 3 -> 1 */\n\t\t\t\t\t(*edges_matched)++;\n\t\t\t\t}\n\t\t\t} else\n\t\t\t\tif (move(edges, n_edges, -(*to - *from), 0)\n\t\t\t\t\t\t\t== OP_SUCCESS) {\n\t\t\t\t\t*from += (*to - *from);\n\t\t\t\t\t(*edges_matched)++;\n\t\t\t\t}\n\t\t} else {\n\t\t\tif (is_edge_incoming) { /* e.g. from=3, to=1 */\n\t\t\t\tif (move(edges, n_edges, -(*from - *to), 1)\n\t\t\t\t\t\t\t== OP_SUCCESS) {\n\t\t\t\t\t*to += (*from - *to);\n\t\t\t\t\t(*edges_matched)++;\n\t\t\t\t}\n\t\t\t} else\n\t\t\t\tif (move(edges, n_edges, (*from - *to), 0)\n\t\t\t\t\t\t\t== OP_SUCCESS) {\n\t\t\t\t\t*from -= (*from - *to);\n\t\t\t\t\t(*edges_matched)++;\n\t\t\t\t}\n\t\t}\n\t\tDPRINTF(4, \"%s(): edge from %d to %d, this_channel_constraint: %d, is_incoming: %d, from_instances: %d, to_instances %d, edge instances: %d.\\n\", __func__, e->from, e->to, this_channel_constraint, is_edge_incoming, *from, *to, e->instances);\n\t\tif (matched == *edges_matched){\n\t\t\tDPRINTF(4, \"%s(): WARNING: did not manage to match this edge\",\n\t\t\t\t\t__func__);\n\t\t\treturn OP_SUCCESS;\n\t\t}\n\t}\n\n\t/* Is the matching for this channel in line with the (fixed)\n\t * constraint? */\n\tif (this_channel_constraint == -1) {\n\t\t*constraints_matched = true;\n\t\treturn OP_SUCCESS;\n\t}\n\n\tint fds = 0;\n\tfor (i = 0; i < n_edges; i++) {\n\t\tstruct dgsh_edge *e = edges[i];\n\t\tfds += e->instances;\n\t}\n\tDPRINTF(4, \"%s communication endpoints to setup: %d, constraint: %d\",\n\t\t\tis_edge_incoming ? \"Incoming\" : \"Outgoing\",\n\t\t\tfds, this_channel_constraint);\n\n\t*constraints_matched = (fds == this_channel_constraint);\n\n\treturn OP_SUCCESS;\n}\n\n/**\n * Search for conc with pid in message block mb\n * and return a pointer to the structure or\n * NULL if not found.\n */\nstruct dgsh_conc *\nfind_conc(struct dgsh_negotiation *mb, pid_t pid)\n{\n\tint i;\n\tstruct dgsh_conc *ca = mb->conc_array;\n\tfor (i = 0; i < mb->n_concs; i++) {\n\t\tif (ca[i].pid == pid)\n\t\t\treturn &ca[i];\n\t}\n\treturn NULL;\n}\n\n/**\n * Calculate fds for concs at the multi-pipe\n * endpoint.\n */\nstatic enum op_result\ncalculate_conc_fds(void)\n{\n\tint i, calculated = 0, retries = 0;\n\tint n_concs = chosen_mb->n_concs;\n\n\tDPRINTF(4, \"%s for %d n_concs\", __func__, n_concs);\n\tif (n_concs == 0)\n\t\treturn OP_SUCCESS;\n\nrepeat:\n\tfor (i = 0; i < n_concs; i++) {\n\t\tstruct dgsh_conc *c = &chosen_mb->conc_array[i];\n\t\tDPRINTF(4, \"%s() for conc %d at index %d with %d n_proc_pids\",\n\t\t\t\t__func__, c->pid, i, c->n_proc_pids);\n\n\t\tif (c->input_fds >= 0 && c->output_fds >= 0)\n\t\t\tcontinue;\n\n\t\tc->input_fds = 0;\n\t\tc->output_fds = 0;\n\n\t\tif (c->multiple_inputs)\n\t\t\tc->output_fds = get_expected_fds_n(chosen_mb,\n\t\t\t\t\tc->endpoint_pid);\n\t\telse\n\t\t\tc->input_fds = get_provided_fds_n(chosen_mb,\n\t\t\t\t\tc->endpoint_pid);\n\n\t\tDPRINTF(4, \"%s(): conc pid %d at index %d: %d %s fds for endpoint pid %d recovered\",\n\t\t\t\t__func__, c->pid, i,\n\t\t\t\tc->multiple_inputs ? c->output_fds : c->input_fds,\n\t\t\t\tc->multiple_inputs ? \"outgoing\" : \"incoming\",\n\t\t\t\tc->endpoint_pid);\n\n\t\tint j, fds;\n\t\tfor (j = 0; j < c->n_proc_pids; j++) {\n\t\t\tif (c->multiple_inputs)\n\t\t\t\tfds = get_provided_fds_n(chosen_mb,\n\t\t\t\t\t\tc->proc_pids[j]);\n\t\t\telse\n\t\t\t\tfds = get_expected_fds_n(chosen_mb,\n\t\t\t\t\t\tc->proc_pids[j]);\n\n\t\t\tif (find_conc(chosen_mb, c->proc_pids[j]) && fds == -1) {\n\t\t\t\tc->input_fds = c->output_fds = -1;\n\t\t\t\tDPRINTF(4, \"%s(): conc pid %d at index %d: fds for conc with pid %d not yet available\",\n\t\t\t\t\t__func__, c->pid, i, c->proc_pids[j]);\n\t\t\t\tbreak;\n\t\t\t} else\n\t\t\t\tif (c->multiple_inputs)\n\t\t\t\t\tc->input_fds += fds;\n\t\t\t\telse\n\t\t\t\t\tc->output_fds += fds;\n\t\t\tDPRINTF(4, \"%s(): conc pid %d at index %d: %d %s fds for pid %d recovered\",\n\t\t\t\t__func__, c->pid, i, fds,\n\t\t\t\tc->multiple_inputs ? \"incoming\" : \"outgoing\",\n\t\t\t\tc->proc_pids[j]);\n\t\t}\n\t\t// Use what we know for the multi-pipe end to compute the endpoint\n\t\tif (c->multiple_inputs && c->input_fds >= 0 && c->output_fds == -1)\n\t\t\tc->output_fds = c->input_fds;\n\t\telse if (!c->multiple_inputs && c->output_fds >= 0\n\t\t\t\t&& c->input_fds == -1)\n\t\t\tc->input_fds = c->output_fds;\n\n\t\tif (c->input_fds >= 0 && c->output_fds >= 0) {\n\t\t\tassert(c->input_fds == c->output_fds);\n\t\t\tcalculated++;\n\t\t}\n\t\tDPRINTF(4, \"%s(): Conc pid %d at index %d has %d %s fds and %d %s fds\",\n\t\t\t\t__func__, c->pid, i,\n\t\t\t\tc->multiple_inputs ? c->input_fds : c->output_fds,\n\t\t\t\tc->multiple_inputs ? \"incoming\" : \"outgoing\",\n\t\t\t\tc->multiple_inputs ? c->output_fds : c->input_fds,\n\t\t\t\tc->multiple_inputs ? \"outgoing\" : \"incoming\");\n\t\tDPRINTF(4, \"%s(): Calculated fds for %d concs so far\", __func__,\n\t\t\t\tcalculated);\n\n\t}\n\tif (calculated != n_concs && retries < n_concs) {\n\t\tretries++;\n\t\tgoto repeat;\n\t}\n\n\tif (retries == n_concs)\n\t\treturn OP_ERROR;\n\n\treturn OP_SUCCESS;\n}\n\n/**\n * For each node substitute pointers to edges with proper edge structures\n * (copies) to facilitate transmission and receipt in one piece.\n */\nstatic enum op_result\nprepare_solution(void)\n{\n\tint i;\n\tint n_nodes = chosen_mb->n_nodes;\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\t\tchosen_mb->graph_solution;\n\tenum op_result exit_state = OP_SUCCESS;\n\n\tfor (i = 0; i < n_nodes; i++) {\n\t\tstruct dgsh_node_connections *current_connections =\n\t\t\t\t\t\t\t&graph_solution[i];\n\t\t/* Hack: struct dgsh_edge* -> struct dgsh_edge** */\n\t\tstruct dgsh_edge **edges_incoming =\n\t\t       (struct dgsh_edge **)current_connections->edges_incoming;\n\t\tcurrent_connections->edges_incoming = NULL;\n\t\t/* Hack: struct dgsh_edge* -> struct dgsh_edge** */\n\t\tstruct dgsh_edge **edges_outgoing =\n\t\t       (struct dgsh_edge **)current_connections->edges_outgoing;\n\t\tcurrent_connections->edges_outgoing = NULL;\n        \tint *n_edges_incoming = &current_connections->n_edges_incoming;\n        \tint *n_edges_outgoing = &current_connections->n_edges_outgoing;\n\t\tDPRINTF(3, \"%s(): Node %s, pid: %d, connections in: %d, connections out: %d.\",\n\t\t\t\t__func__, chosen_mb->node_array[i].name,\n\t\t\t\tchosen_mb->node_array[i].pid,\n\t\t\t\t*n_edges_incoming, *n_edges_outgoing);\n\n\t\tif (*n_edges_incoming > 0) {\n\t\t\tif (exit_state == OP_SUCCESS)\n\t\t\t\tif (make_compact_edge_array(\n\t\t\t\t\t&current_connections->edges_incoming,\n\t\t\t       \t\t*n_edges_incoming, edges_incoming)\n\t\t\t\t\t\t\t\t== OP_ERROR)\n\t\t\t\t\texit_state = OP_ERROR;\n\t\t\tfree(edges_incoming);\n\t\t}\n\t\tif (*n_edges_outgoing > 0) {\n\t\t\tif (exit_state == OP_SUCCESS)\n\t\t\t\tif (make_compact_edge_array(\n\t\t\t\t\t&current_connections->edges_outgoing,\n\t\t\t\t\t*n_edges_outgoing, edges_outgoing)\n\t\t\t\t\t\t\t\t== OP_ERROR)\n\t\t\t\t\texit_state = OP_ERROR;\n\t\t\tfree(edges_outgoing);\n\t\t}\n\t}\n\treturn exit_state;\n}\n\nstatic void\nprint_solution_error(int index_argc, int *index_commands_notmatched,\n\t\tint *side_commands_notmatched)\n{\n\tint i = 0, index = 0, side = 0, reqs = 0;\n\tfprintf(stderr, \"dgsh: No solution was found to satisfy the I/O requirements of the following %d participating processes:\\n\",\n\t\t\tindex_argc);\n\tfor (i = 0; i < index_argc; i++) {\n\t\tindex = index_commands_notmatched[i];\n\t\tside = side_commands_notmatched[i];\n\t\tif (side == STDIN_FILENO)\n\t\t\treqs = chosen_mb->node_array[index].requires_channels;\n\t\telse\n\t\t\treqs = chosen_mb->node_array[index].provides_channels;\n\t\tfprintf(stderr, \"%s (n%s=%d)\\n\",\n\t\t\t\tchosen_mb->node_array[index].name,\n\t\t\t\tside == STDIN_FILENO ? \"in\" : \"out\",\n\t\t\t\treqs);\n\t}\n\tfree(index_commands_notmatched);\n\tfree(side_commands_notmatched);\n}\n\n/**\n * Check that a node's input/output channel matched its requirements\n */\nstatic void\ncheck_constraints_matched(int node_index, bool *constraints_matched,\n\t\t\t\tint **index_commands_notmatched,\n\t\t\t\tint **side_commands_notmatched,\n\t\t\t\tint *index_argc, int side)\n{\n\tif (!*constraints_matched) {\n\t\t(*index_argc)++;\n\t\tDPRINTF(4, \"Constraint not matched for node at index %d. So far %d nodes not matched\",\n\t\t\t\tnode_index, *index_argc);\n\t\tif (*index_argc == 1) {\n\t\t\t*index_commands_notmatched = (int *)malloc(\n\t\t\t\t\tsizeof(int) * *index_argc);\n\t\t\t*side_commands_notmatched = (int *)malloc(\n\t\t\t\t\tsizeof(int) * *index_argc);\n\t\t} else {\n\t\t\t*index_commands_notmatched = (int *)realloc(\n\t\t\t\t*index_commands_notmatched,\n\t\t\t\tsizeof(int) * *index_argc);\n\t\t\t*side_commands_notmatched = (int *)realloc(\n\t\t\t\t*side_commands_notmatched,\n\t\t\t\tsizeof(int) * *index_argc);\n\t\t}\n\t\t(*index_commands_notmatched)[*index_argc - 1] = node_index;\n\t\t(*side_commands_notmatched)[*index_argc - 1] = side;\n\t}\n\t*constraints_matched = false;\n}\n\n/**\n * This function implements the algorithm that tries to satisfy reported\n * I/O constraints of tools on an dgsh graph.\n */\nstatic enum op_result\ncross_match_constraints(int **index_commands_notmatched,\n\t\tint **side_commands_notmatched, int *index_argc)\n{\n\tint i;\n\tint n_nodes = chosen_mb->n_nodes;\n\tint n_edges = chosen_mb->n_edges;\n\tint edges_matched = 0;\n\tbool constraints_matched = false;\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\t\tchosen_mb->graph_solution;\n\n\t/* Check constraints for each node on the dgsh graph. */\n\tfor (i = 0; i < n_nodes; i++) {\n\t\tstruct dgsh_node_connections *current_connections =\n\t\t\t\t\t\t\t&graph_solution[i];\n\t\t/* Hack: struct dgsh_edge* -> struct dgsh_edge** */\n\t\tstruct dgsh_edge **edges_incoming =\n\t\t       (struct dgsh_edge **)current_connections->edges_incoming;\n\t\t/* Hack: struct dgsh_edge* -> struct dgsh_edge** */\n\t\tstruct dgsh_edge **edges_outgoing =\n\t\t       (struct dgsh_edge **)current_connections->edges_outgoing;\n\t\tstruct dgsh_node *current_node = &chosen_mb->node_array[i];\n\t\tint out_constraint = current_node->provides_channels;\n\t\tint in_constraint = current_node->requires_channels;\n        \tint *n_edges_incoming = &current_connections->n_edges_incoming;\n        \tint *n_edges_outgoing = &current_connections->n_edges_outgoing;\n\t\tDPRINTF(4, \"%s(): node %s, index %d, channels required %d, channels_provided %d, dgsh_in %d, dgsh_out %d.\", __func__, current_node->name, current_node->index, in_constraint, out_constraint, current_node->dgsh_in, current_node->dgsh_out);\n\n\t\t/* Try to satisfy the I/O channel constraints at graph level.\n\t\t * Assign instances to each edge.\n\t\t */\n\t\tif (*n_edges_outgoing > 0){\n\t\t\tif (cross_match_io_constraints(\n\t\t    \t    &current_connections->n_instances_outgoing_free,\n\t\t\t    out_constraint,\n\t\t    \t    edges_outgoing, *n_edges_outgoing, 0,\n\t\t\t    &constraints_matched, &edges_matched) == OP_ERROR) {\n\t\t\t\tDPRINTF(4, \"ERROR: Failed to satisfy requirements for tool %s, pid %d: requires %d and gets %d, provides %d and is offered %d.\\n\",\n\t\t\t\tcurrent_node->name,\n\t\t\t\tcurrent_node->pid,\n\t\t\t\tcurrent_node->requires_channels,\n\t\t\t\t*n_edges_incoming,\n\t\t\t\tcurrent_node->provides_channels,\n\t\t\t\t*n_edges_outgoing);\n\t\t\t\treturn OP_ERROR;\n\t\t\t}\n\t\t\tcheck_constraints_matched(i, &constraints_matched,\n\t\t\t\t\tindex_commands_notmatched,\n\t\t\t\t\tside_commands_notmatched, index_argc,\n\t\t\t\t\tSTDOUT_FILENO);\n\t\t}\n\t\tif (*n_edges_incoming > 0){\n\t\t\tif (cross_match_io_constraints(\n\t\t    \t    &current_connections->n_instances_incoming_free,\n\t\t\t    in_constraint,\n\t\t    \t    edges_incoming, *n_edges_incoming, 1,\n\t\t\t    &constraints_matched, &edges_matched) == OP_ERROR) {\n\t\t\t\tDPRINTF(4, \"ERROR: Failed to satisfy requirements for tool %s, pid %d: requires %d and gets %d, provides %d and is offered %d.\\n\",\n\t\t\t\tcurrent_node->name,\n\t\t\t\tcurrent_node->pid,\n\t\t\t\tcurrent_node->requires_channels,\n\t\t\t\t*n_edges_incoming,\n\t\t\t\tcurrent_node->provides_channels,\n\t\t\t\t*n_edges_outgoing);\n\t\t\t\treturn OP_ERROR;\n\t\t\t}\n\t\t\tcheck_constraints_matched(i, &constraints_matched,\n\t\t\t\t\tindex_commands_notmatched,\n\t\t\t\t\tside_commands_notmatched, index_argc,\n\t\t\t\t\tSTDIN_FILENO);\n\t\t}\n\t}\n\tDPRINTF(4, \"%s(): Cross matched constraints of %d out of %d nodes for %d edges out of %d edges.\", __func__, n_nodes - *index_argc, n_nodes, edges_matched / 2, n_edges);\n\tif (edges_matched / 2 == n_edges && *index_argc == 0)\n\t\treturn OP_SUCCESS;\n\telse\n\t\treturn OP_RETRY;\n}\n\n\n/**\n * This function implements the algorithm that tries to satisfy reported\n * I/O constraints of tools on an dgsh graph.\n */\nstatic enum op_result\nnode_match_constraints(void)\n{\n\tint i;\n\tint n_nodes = chosen_mb->n_nodes;\n\tenum op_result exit_state = OP_SUCCESS;\n\tint graph_solution_size = sizeof(struct dgsh_node_connections) *\n\t\t\t\t\t\t\t\tn_nodes;\n\t/* Prealloc */\n\tchosen_mb->graph_solution = (struct dgsh_node_connections *)malloc(\n\t\t\t\t\t\t\tgraph_solution_size);\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\t\tchosen_mb->graph_solution;\n\tif (!graph_solution) {\n\t\tDPRINTF(4, \"ERROR: Failed to allocate memory of size %d for dgsh negotiation graph solution structure.\\n\", graph_solution_size);\n\t\treturn OP_ERROR;\n\t}\n\n\t/* Check constraints for each node on the dgsh graph. */\n\tfor (i = 0; i < n_nodes; i++) {\n\t\tDPRINTF(4, \"%s(): node at index %d.\", __func__, i);\n\t\tstruct dgsh_node_connections *current_connections =\n\t\t\t\t\t\t\t&graph_solution[i];\n\t\tmemset(current_connections, 0,\n\t\t\t\t\tsizeof(struct dgsh_node_connections));\n\t\tstruct dgsh_edge **edges_incoming;\n\t\tstruct dgsh_edge **edges_outgoing;\n\t\tstruct dgsh_node *current_node = &chosen_mb->node_array[i];\n\t\tcurrent_connections->node_index = current_node->index;\n\t\tDPRINTF(4, \"Node %s, index %d, channels required %d, channels_provided %d, dgsh_in %d, dgsh_out %d.\", current_node->name, current_node->index, current_node->requires_channels, current_node->provides_channels, current_node->dgsh_in, current_node->dgsh_out);\n\n\t\t/* Find and store pointers to node's at node_index edges.\n\t\t * Try to satisfy the I/O channel constraints at node level.\n\t\t */\n\t\tif (dry_match_io_constraints(current_node, current_connections,\n\t\t\t&edges_incoming, &edges_outgoing) == OP_ERROR) {\n\t\t\tDPRINTF(4, \"ERROR: Failed to satisfy requirements for tool %s, pid %d: requires %d and gets %d, provides %d and is offered %d.\\n\",\n\t\t\t\tcurrent_node->name,\n\t\t\t\tcurrent_node->pid,\n\t\t\t\tcurrent_node->requires_channels,\n\t\t\t\tcurrent_connections->n_edges_incoming,\n\t\t\t\tcurrent_node->provides_channels,\n\t\t\t\tcurrent_connections->n_edges_outgoing);\n\t\t\texit_state = OP_ERROR;\n\t\t}\n\t\tif (exit_state == OP_ERROR) {\n\t\t\tfree_graph_solution(current_node->index);\n\t\t\tbreak;\n\t\t}\n\t\t/* Hack to retain references to edge pointer arrays. */\n\t\tcurrent_connections->edges_incoming =\n\t\t\t(struct dgsh_edge *)edges_incoming;\n\t\tcurrent_connections->edges_outgoing =\n\t\t\t(struct dgsh_edge *)edges_outgoing;\n\t}\n\treturn exit_state;\n}\n\n\n/**\n * This function implements the algorithm that tries to satisfy reported\n * I/O constraints of tools on an dgsh graph.\n */\nenum op_result\nsolve_graph(void)\n{\n\tchar *filename;\n\tenum op_result exit_state = OP_SUCCESS;\n\tint retries = 0;\n\tint index_argc = 0;\n\tint *index_commands_notmatched;\n\tint *side_commands_notmatched;\n\n\t/**\n\t * The initial layout of the solution plays an important\n\t * role. We could add a scheme that allows restarting\n\t * the solution process with a different initial layout\n\t * after a failure. The key points of the scheme would be:\n\t * while\n\t * int retries = 0;\n\t * int max_retries = 10;\n\t * assign a node's available edges to adjacent nodes differently\n\t */\n\n\t/**\n\t * Try to match each node's I/O resources with constraints\n\t * expressed by incoming and outgoing edges.\n\t */\n\tif ((exit_state = node_match_constraints()) == OP_ERROR)\n\t\treturn exit_state;\n\n\t/* Optimise solution using flexible constraints */\n\texit_state = OP_RETRY;\n\n\twhile (exit_state == OP_RETRY) {\n\t\tif ((exit_state = cross_match_constraints(\n\t\t\t\t&index_commands_notmatched,\n\t\t\t\t&side_commands_notmatched,\n\t\t\t\t&index_argc)) ==\n\t\t\t\tOP_ERROR ||\n\t\t\t\t(exit_state == OP_RETRY && retries > 10)) {\n\t\t\tprint_solution_error(index_argc,\n\t\t\t\t\tindex_commands_notmatched,\n\t\t\t\t\tside_commands_notmatched);\n\t\t\texit_state = OP_ERROR;\n\t\t\tgoto exit;\n\t\t}\n\t\tDPRINTF(4, \"%s(): exit_state: %d, retries: %d\",\n\t\t\t\t__func__, exit_state, retries);\n\t\tretries++;\n\t\tif (index_argc > 0) {\n\t\t\tfree(index_commands_notmatched);\n\t\t\tfree(side_commands_notmatched);\n\t\t\tindex_argc = 0;\n\t\t}\n\t}\n\n\t/**\n\t * Substitute pointers to edges with proper edge structures\n\t * (copies) to facilitate transmission and receipt in one piece.\n\t */\n\tif ((exit_state = prepare_solution()) == OP_ERROR)\n\t\tgoto exit;\n\n\tif ((exit_state = calculate_conc_fds()) == OP_ERROR)\n\t\tgoto exit;\n\n\tif ((filename = getenv(\"DGSH_DOT_DRAW\")))\n\t\tif ((exit_state = output_graph(filename)) == OP_ERROR)\n\t\t\tgoto exit;\n\n\tif (getenv(\"DGSH_DRAW_EXIT\")) {\n\t\tDPRINTF(1, \"Document the solution and exit\\n\");\n\t\texit_state = OP_DRAW_EXIT;\n\t}\n\n\tDPRINTF(4, \"%s: exit_state: %d\", __func__, exit_state);\n\nexit:\n\tif (exit_state == OP_ERROR || exit_state == OP_DRAW_EXIT)\n\t\tfree_graph_solution(chosen_mb->n_nodes - 1);\n\treturn exit_state;\n} /* memory deallocation when in error state? */\n\n/**\n * Assign the pipes to the data structs that will carry them back to the tool.\n * The tool is responsible for freeing the memory allocated to these data\n * structures.\n */\nstatic enum op_result\nestablish_io_connections(int **input_fds, int *n_input_fds, int **output_fds,\n\t\t\t\t\t\t\tint *n_output_fds)\n{\n\tenum op_result re = OP_SUCCESS;\n\tDPRINTF(4, \"%s(): input fds: %d, output fds: %d\", __func__,\n\t\t\tself_pipe_fds.n_input_fds, self_pipe_fds.n_output_fds);\n\n\tif (self_pipe_fds.n_input_fds > 0) {\n\t\t/* Have the first returned file descriptor\n\t\t * take the place of stdin.\n\t\t */\n\t\tint fd_to_dup = self_pipe_fds.input_fds[0];\n\t\tif (close(STDIN_FILENO) == -1)\n\t\t\terr(1, \"Close stdin failed\");\n\t\tif ((self_pipe_fds.input_fds[0] = dup(fd_to_dup)) == -1)\n\t\t\terr(1, \"dup failed with errno %d\", errno);\n\t\tDPRINTF(4, \"%s(): closed STDIN, dup %d returned %d\",\n\t\t\t\t__func__,fd_to_dup, self_pipe_fds.input_fds[0]);\n\t\tassert(self_pipe_fds.input_fds[0] == STDIN_FILENO);\n\t\tclose(fd_to_dup);\n\n\t\tif (n_input_fds) {\n\t\t\t*n_input_fds = self_pipe_fds.n_input_fds;\n\t\t\tassert(*n_input_fds >= 0);\n\t\t\tif (input_fds)\n\t\t\t\t*input_fds = self_pipe_fds.input_fds;\n\t\t} else {\n\t\t\tself_pipe_fds.n_input_fds = 0;\n\t\t\tfree(self_pipe_fds.input_fds);\n\t\t}\n\t} else\n\t\tif (n_input_fds)\n\t\t\t*n_input_fds = 0;\n\n\n\tif (self_pipe_fds.n_output_fds > 0) {\n\t\t/* Have the first returned file descriptor\n\t\t * take the place of stdin.\n\t\t */\n\t\tint fd_to_dup = self_pipe_fds.output_fds[0];\n\t\tif (close(STDOUT_FILENO) == -1)\n\t\t\terr(1, \"Close stdout failed\");\n\t\tif ((self_pipe_fds.output_fds[0] = dup(fd_to_dup)) == -1)\n\t\t\terr(1, \"dup failed with errno %d\", errno);\n\t\tDPRINTF(4, \"%s(): closed STDOUT, dup %d returned %d\",\n\t\t\t\t__func__,fd_to_dup,self_pipe_fds.output_fds[0]);\n\t\tassert(self_pipe_fds.output_fds[0] == STDOUT_FILENO);\n\t\tclose(fd_to_dup);\n\n\t\tif (n_output_fds) {\n\t\t\t*n_output_fds = self_pipe_fds.n_output_fds;\n\t\t\tassert(*n_output_fds >= 0);\n\t\t\tif (output_fds)\n\t\t\t\t*output_fds = self_pipe_fds.output_fds;\n\t\t} else {\n\t\t\tself_pipe_fds.n_output_fds = 0;\n\t\t\tfree(self_pipe_fds.output_fds);\n\t\t}\n\t} else\n\t\tif (n_output_fds)\n\t\t\t*n_output_fds = 0;\n\n\tDPRINTF(2, \"%s(): %s for node %s at index %d\", __func__,\n\t\t\t(re == OP_SUCCESS ? \"successful\" : \"failed\"),\n\t\t\tself_node.name, self_node.index);\n\n\treturn re;\n}\n\n/* Transmit file descriptors that will pipe this\n * tool's output to another tool.\n */\nstatic enum op_result\nwrite_output_fds(int output_socket, int *output_fds, int flags)\n{\n\t/**\n\t * A node's connections are located at the same position\n         * as the node in the node array.\n\t */\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\t\tchosen_mb->graph_solution;\n\tstruct dgsh_node_connections *this_nc =\n\t\t\t\t\t&graph_solution[self_node.index];\n\tDPRINTF(4, \"%s(): for node at index %d with %d outgoing edges.\", __func__,\n\t\t\t\tself_node.index, this_nc->n_edges_outgoing);\n\tassert(this_nc->node_index == self_node.index);\n\tint i;\n\tint total_edge_instances = 0;\n\tenum op_result re = OP_SUCCESS;\n\n\t/**\n\t * Create a pipe for each instance of each outgoing edge connection.\n\t * Inject the pipe read side in the cont.\n\t * Send each pipe fd as a message to a socket descriptor,\n\t * that is write_fd, that has been\n\t * set up by the shell to support the dgsh negotiation phase.\n\t */\n\tfor (i = 0; i < this_nc->n_edges_outgoing; i++) {\n\t\tint k;\n\t\t/**\n\t\t * Due to channel constraint flexibility,\n\t\t * each edge can have more than one instances.\n\t\t */\n\t\tfor (k = 0; k < this_nc->edges_outgoing[i].instances; k++) {\n\t\t\tint fd[2];\n\t\t\t/* Create pipe, inject the read side to the msg control\n\t\t\t * data and close the read side to let the recipient\n\t\t\t * process handle it.\n\t\t\t */\n\t\t\tif (pipe(fd) == -1) {\n\t\t\t\tperror(\"pipe open failed\");\n\t\t\t\tdgsh_exit(-1, flags);\n\t\t\t}\n\t\t\tDPRINTF(4, \"%s(): created pipe pair %d - %d. Transmitting fd %d through sendmsg().\", __func__, fd[0], fd[1], fd[0]);\n\n\t\t\twrite_fd(output_socket, fd[0]);\n\t\t\tclose(fd[0]);\n\n\t\t\toutput_fds[total_edge_instances] = fd[1];\n\t\t\ttotal_edge_instances++;\n\t\t}\n\t\t/* XXX */\n\t\tif (re == OP_ERROR)\n\t\t\tbreak;\n\t}\n\tif (re == OP_ERROR) {\n\t\tDPRINTF(4, \"%s(): ERROR. Aborting.\", __func__);\n\t\tfree_graph_solution(chosen_mb->n_nodes - 1);\n\t\tfree(self_pipe_fds.output_fds);\n\t}\n\treturn re;\n}\n\nstatic int\nwrite_piece (int write_fd, void *datastruct, int struct_size)\n{\n\tint retries = 0, wsize;\nretry:\n\tDPRINTF(4, \"Try write struct of size: %d\", struct_size);\n\twsize = write(write_fd, datastruct, struct_size);\n\tif (wsize == -1 && errno == ENOBUFS && retries < 3) {\t// sleep for 10ms\n\t\tnanosleep((const struct timespec[]){{0, 10000000L}}, NULL);\n\t\tretries++;\n\t\tgoto retry;\n\t}\n\treturn wsize;\n}\n\nstatic int\nget_struct_size(int struct_type)\n{\n\t\tswitch (struct_type) {\n\t\tcase 1:\n\t\t\treturn sizeof(struct dgsh_node);\n\t\tcase 2:\n\t\t\treturn sizeof(struct dgsh_edge);\n\t\tcase 3:\n\t\t\treturn sizeof(struct dgsh_conc);\n\t\tcase 4:\n\t\t\treturn sizeof(struct dgsh_node_connections);\n\t\t}\n\t\treturn 0;\n}\n\nstatic int\ndo_write (int write_fd, void *datastruct, int datastruct_size, int struct_type)\n{\n\tint wsize = 0;\n\tif (datastruct_size > iov_max) {\n\t\tint all_elements, max_elements, elements = 0, pieces, \n\t\t\tprev_elements = 0, size, struct_size, i;\n\n\t\tstruct_size = get_struct_size(struct_type);\n\t\tall_elements = datastruct_size / struct_size;\n\t\tmax_elements = iov_max / struct_size;\n\t\tpieces = all_elements / max_elements;\n\t\tpieces += (all_elements % max_elements > 0);\n\t\tDPRINTF(4, \"struct_type: %d, pieces: %d, all_elements: %d, max_elements: %d\",\n\t\t\tstruct_type, pieces, all_elements, max_elements);\n\n\t\tfor (i = 0; i < pieces; i++) {\n\t\t\tif (all_elements - max_elements > 0)\n\t\t\t\telements = max_elements;\n\t\t\telse if (all_elements > 0)\n\t\t\t\telements = all_elements;\n\t\t\tall_elements -= elements;\n\t\t\tsize = struct_size * elements;\n\t\t\tDPRINTF(4, \"Round %d: elements: %d, size: %d, prev_elements: %d\",\n\t\t\t\ti, elements, size, prev_elements);\n\n\t\t\tif (size > 0) {\n\t\t\t\tvoid *struct_piece = malloc(size);\n\t\t\t\tswitch (struct_type) {\n\t\t\t\tcase 1:\n\t\t\t\t\tmemcpy(struct_piece,\n\t\t\t\t\t\t&((struct dgsh_node *)\n\t\t\t\t\t\tdatastruct)[i * prev_elements],\n\t\t\t\t\t\tsize);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tmemcpy(struct_piece,\n\t\t\t\t\t\t&((struct dgsh_edge *)\n\t\t\t\t\t\tdatastruct)[i * prev_elements],\n\t\t\t\t\t\tsize);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tmemcpy(struct_piece,\n\t\t\t\t\t\t&((struct dgsh_conc *)\n\t\t\t\t\t\tdatastruct)[i * prev_elements],\n\t\t\t\t\t\tsize);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tmemcpy(struct_piece,\n\t\t\t\t\t\t&((struct dgsh_node_connections *)\n\t\t\t\t\t\tdatastruct)[i * prev_elements],\n\t\t\t\t\t\tsize);\n\t\t\t\t}\n\t\t\t\twsize = write_piece(write_fd, struct_piece,\n\t\t\t\t\t\t\tsize);\n\t\t\t\tfree(struct_piece);\n\t\t\t\tprev_elements = elements;\n\t\t\t}\n\t\t}\n\t} else\n\t\twsize = write_piece(write_fd, datastruct, datastruct_size);\n\n\treturn wsize;\n}\n\nstatic enum op_result\nwrite_concs(int write_fd)\n{\n\tint wsize, i;\n\tint n_concs = chosen_mb->n_concs;\n\tint conc_size = sizeof(struct dgsh_conc) * n_concs;\n\n\tif (!chosen_mb->conc_array)\n\t\treturn OP_SUCCESS;\n\n\twsize = do_write(write_fd, chosen_mb->conc_array, conc_size, 3);\n\tif (wsize == -1) {\n\t\tDPRINTF(4, \"ERROR: write failed: errno: %d\", errno);\n\t\treturn OP_ERROR;\n\t}\n\tDPRINTF(4, \"%s(): Wrote conc structures of size %d bytes \", __func__, wsize);\n\n\tfor (i = 0; i < n_concs; i++) {\n\t\tstruct dgsh_conc *c = &chosen_mb->conc_array[i];\n\t\tint proc_pids_size = sizeof(int) * c->n_proc_pids;\n\t\twsize = do_write(write_fd, c->proc_pids, proc_pids_size, 5);\n\t\tif (wsize == -1) {\n\t\t\tDPRINTF(4, \"ERROR: write failed: errno: %d\", errno);\n\t\t\treturn OP_ERROR;\n\t\t}\n\t\tDPRINTF(4, \"%s(): Wrote %d proc_pids for conc %d at index %d of size %d bytes \",\n\t\t\t\t__func__, c->n_proc_pids, c->pid, i, wsize);\n\t}\n\n\treturn OP_SUCCESS;\n}\n\n/* Transmit dgsh negotiation graph solution to the next tool on the graph. */\nstatic enum op_result\nwrite_graph_solution(int write_fd)\n{\n\tint i;\n\tint n_nodes = chosen_mb->n_nodes;\n\tint graph_solution_size = sizeof(struct dgsh_node_connections) *\n\t\t\t\t\t\t\t\tn_nodes;\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\t\tchosen_mb->graph_solution;\n\tint wsize = -1;\n\n\t/* Transmit node connection structures. */\n\twsize = do_write(write_fd, graph_solution, graph_solution_size, 4);\n\tif (wsize == -1) {\n\t\tDPRINTF(4, \"ERROR: write failed: errno: %d\", errno);\n\t\treturn OP_ERROR;\n\t}\n\tDPRINTF(4, \"%s(): Wrote graph solution of size %d bytes \", __func__, wsize);\n\n\t/* We haven't invalidated pointers to arrays of node indices. */\n\n\tfor (i = 0; i < n_nodes; i++) {\n\t\tstruct dgsh_node_connections *nc = &graph_solution[i];\n\t\tint in_edges_size = sizeof(struct dgsh_edge) * nc->n_edges_incoming;\n\t\tint out_edges_size = sizeof(struct dgsh_edge) * nc->n_edges_outgoing;\n\t\tif (nc->n_edges_incoming) {\n\t\t\t/* Transmit a node's incoming connections. */\n\t\t\twsize = do_write(write_fd, nc->edges_incoming,\n\t\t\t\t\t\t\tin_edges_size, 2);\n\t\t\tif (wsize == -1) {\n\t\t\t\tDPRINTF(4, \"ERROR: write failed: errno: %d\", errno);\n\t\t\t\treturn OP_ERROR;\n\t\t\t}\n\t\t\tDPRINTF(4, \"%s(): Wrote node's %d %d incoming edges of size %d bytes \", __func__, nc->node_index, nc->n_edges_incoming, wsize);\n\t\t}\n\n\t\tif (nc->n_edges_outgoing) {\n\t\t\t/* Transmit a node's outgoing connections. */\n\t\t\twsize = do_write(write_fd, nc->edges_outgoing,\n\t\t\t\t\t\t\tout_edges_size, 2);\n\t\t\tif (wsize == -1) {\n\t\t\t\tDPRINTF(4, \"ERROR: write failed: errno: %d\", errno);\n\t\t\t\treturn OP_ERROR;\n\t\t\t}\n\t\t\tDPRINTF(4, \"%s(): Wrote node's %d %d outgoing edges of size %d bytes \", __func__, nc->node_index, nc->n_edges_outgoing, wsize);\n\t\t}\n\t}\n\treturn OP_SUCCESS;\n}\n\n/**\n * Copy the dispatcher static object that identifies the node\n * in the message block node array and shows the write point of\n * the send operation. This is a deep copy for simplicity.\n */\nstatic void\nset_dispatcher(void)\n{\n\tchosen_mb->origin_index = self_node_io_side.index;\n\t/* The process preceding the one to find the solution\n\t * will eventually set its PID.\n\t */\n\tassert(self_node_io_side.index >= 0); /* Node is added to the graph. */\n\tchosen_mb->origin_fd_direction = self_node_io_side.fd_direction;\n\tchosen_mb->is_origin_conc = false;\n\tchosen_mb->conc_pid = -1;\n\tDPRINTF(4, \"%s(): message block origin set to %d and writing on the %s side\", __func__, chosen_mb->origin_index,\n\t(chosen_mb->origin_fd_direction == 0) ? \"input\" : \"output\");\n}\n\n/*\n * Write the chosen_mb message block to the specified file descriptor.\n */\nenum op_result\nwrite_message_block(int write_fd)\n{\n\tint wsize = -1;\n\tint mb_size = sizeof(struct dgsh_negotiation);\n\tint nodes_size = chosen_mb->n_nodes * sizeof(struct dgsh_node);\n\tint edges_size = chosen_mb->n_edges * sizeof(struct dgsh_edge);\n\tstruct dgsh_node *p_nodes = chosen_mb->node_array;\n\n\tDPRINTF(3, \"%s(): %s (%d)\", __func__, programname, self_node.index);\n\n\tif (chosen_mb->state == PS_ERROR && errno == 0)\n\t\terrno = EPROTO;\n\n\t/**\n\t * Prepare and perform message block transmission.\n\t * Formally invalidate pointers to nodes and edges\n\t * to avoid accidents on the receiver's side.\n\t */\n\tchosen_mb->node_array = NULL;\n\tDPRINTF(4, \"%s(): Write message block.\", __func__);\n\twsize = do_write(write_fd, chosen_mb, mb_size, 0);\n\tif (wsize == -1) {\n\t\tDPRINTF(4, \"ERROR: write failed: errno: %d\", errno);\n\t\treturn OP_ERROR;\n\t}\n\tDPRINTF(4, \"%s(): Wrote message block of size %d bytes \", __func__, wsize);\n\n\t/* Transmit nodes. */\n\tif (chosen_mb->n_nodes > 0) {\n\t\twsize = do_write(write_fd, p_nodes, nodes_size, 1);\n\t\tif (wsize == -1) {\n\t\t\tDPRINTF(4, \"ERROR: write failed: errno: %d\", errno);\n\t\t\treturn OP_ERROR;\n\t\t}\n\t\tDPRINTF(4, \"%s(): Wrote nodes of size %d bytes \",\n\t\t\t\t__func__, wsize);\n\t}\n\n\tchosen_mb->node_array = p_nodes; // Reinstate pointers to nodes.\n\n\tif (write_concs(write_fd) == OP_ERROR)\n\t\treturn OP_ERROR;\n\n\tif (chosen_mb->state == PS_NEGOTIATION) {\n\t\tif (chosen_mb->n_edges > 0) {\n\t\t\t/* Transmit edges. */\n\t\t\tstruct dgsh_edge *p_edges = chosen_mb->edge_array;\n\t\t\tchosen_mb->edge_array = NULL;\n\t\t\twsize = do_write(write_fd, p_edges, edges_size, 2);\n\t\t\tif (wsize == -1) {\n\t\t\t\tDPRINTF(4, \"ERROR: write failed: errno: %d\", errno);\n\t\t\t\treturn OP_ERROR;\n\t\t\t}\n\t\t\tDPRINTF(4, \"%s(): Wrote edges of size %d bytes \", __func__, wsize);\n\n\t\t\tchosen_mb->edge_array = p_edges; /* Reinstate edges. */\n\t\t}\n\t} else if (chosen_mb->state == PS_RUN) {\n\t\t/* Transmit solution. */\n\t\tif (write_graph_solution(write_fd) == OP_ERROR)\n\t\t\treturn OP_ERROR;\n\t}\n\n\tDPRINTF(4, \"%s(): Shipped message block or solution to next node in graph from file descriptor: %d.\\n\", __func__, write_fd);\n\treturn OP_SUCCESS;\n}\n\n\n/* Reallocate message block to fit new node coming in. */\nstatic enum op_result\nadd_node(void)\n{\n\tint n_nodes = chosen_mb->n_nodes;\n\tvoid *p = realloc(chosen_mb->node_array,\n\t\tsizeof(struct dgsh_node) * (n_nodes + 1));\n\tif (!p) {\n\t\tDPRINTF(4, \"ERROR: Node array expansion for adding a new node failed.\\n\");\n\t\treturn OP_ERROR;\n\t} else {\n\t\tchosen_mb->node_array = (struct dgsh_node *)p;\n\t\tself_node.index = n_nodes;\n\t\tmemcpy(&chosen_mb->node_array[n_nodes], &self_node,\n\t\t\t\t\tsizeof(struct dgsh_node));\n\t\tself_node_io_side.index = n_nodes;\n\t\tDPRINTF(2, \"%s(): Added node %s in position %d on dgsh graph, initiator: %d\",\n\t\t\t\t__func__, self_node.name, self_node_io_side.index,\n\t\t\t\tchosen_mb->initiator_pid);\n\t\tchosen_mb->n_nodes++;\n\t}\n\treturn OP_SUCCESS;\n}\n\n/* Lookup an edge in the dgsh graph. */\nstatic enum op_result\nlookup_dgsh_edge(struct dgsh_edge *e)\n{\n\tint i;\n\tfor (i = 0; i < chosen_mb->n_edges; i++) {\n\t\tif ((chosen_mb->edge_array[i].from == e->from &&\n\t\t\tchosen_mb->edge_array[i].to == e->to) ||\n\t\t    (chosen_mb->edge_array[i].from == e->to &&\n\t\t     chosen_mb->edge_array[i].to == e->from)) {\n\t\t\tDPRINTF(4, \"%s(): Edge %d to %d exists.\", __func__,\n\t\t\t\t\t\t\t\te->from, e->to);\n\t\t\treturn OP_EXISTS;\n\t\t}\n\t}\n\treturn OP_CREATE;\n}\n\n/**\n * Fill edge depending on input/output fd information\n * passed by sender and found in receiver (this tool or self).\n */\nstatic enum op_result\nfill_dgsh_edge(struct dgsh_edge *e)\n{\n\tint i;\n\tint n_nodes = chosen_mb->n_nodes;\n\tfor (i = 0; i < n_nodes; i++) /* Check dispatcher node exists. */\n\t\tif (i == chosen_mb->origin_index)\n\t\t\tbreak;\n\tif (i == n_nodes) {\n\t\tDPRINTF(4, \"ERROR: Dispatcher node with index position %d not present in graph.\\n\", chosen_mb->origin_index);\n\t\treturn OP_ERROR;\n\t}\n\tif (chosen_mb->origin_fd_direction == STDIN_FILENO) {\n\t/**\n         * MB sent from stdin, so dispatcher is the destination of the edge.\n\t * Self should be dgsh-active on output side. Self's current fd is stdin\n\t * if self is dgsh-active on input side or output side otherwise.\n\t * Self (the recipient) is the source of the edge.\n         */\n\t\te->to = chosen_mb->origin_index;\n\t\tif (self_node.dgsh_in == 1)\n\t\t\tself_node_io_side.fd_direction = STDIN_FILENO;\n\t\telse\n\t\t\tself_node_io_side.fd_direction = STDOUT_FILENO;\n\t\tassert((self_node.dgsh_in &&\n\t\t\tself_node_io_side.fd_direction == STDIN_FILENO) ||\n\t\t\tself_node_io_side.fd_direction == STDOUT_FILENO);\n\t\te->from = self_node_io_side.index;\n\t} else if (chosen_mb->origin_fd_direction == STDOUT_FILENO) {\n\t\t/* Similarly. */\n\t\te->from = chosen_mb->origin_index;\n\t\tif (self_node.dgsh_out == 1)\n\t\t\tself_node_io_side.fd_direction = STDOUT_FILENO;\n\t\telse\n\t\t\tself_node_io_side.fd_direction = STDIN_FILENO;\n\t\tassert((self_node.dgsh_out &&\n\t\t\tself_node_io_side.fd_direction == STDOUT_FILENO) ||\n\t\t\tself_node_io_side.fd_direction == STDIN_FILENO);\n\t\te->to = self_node_io_side.index;\n\t}\n\tassert(e->from != e->to);\n\te->instances = 0;\n\te->from_instances = 0;\n\te->to_instances = 0;\n        DPRINTF(4, \"New dgsh edge from %d to %d with %d instances.\", e->from, e->to, e->instances);\n\treturn OP_SUCCESS;\n}\n\n/* Add new edge coming in. */\nstatic enum op_result\nadd_edge(struct dgsh_edge *edge)\n{\n\tint n_edges = chosen_mb->n_edges;\n\tvoid *p = realloc(chosen_mb->edge_array,\n\t\t\tsizeof(struct dgsh_edge) * (n_edges + 1));\n\tif (!p) {\n\t\tDPRINTF(4, \"ERROR: Edge array expansion for adding a new edge failed.\\n\");\n\t\treturn OP_ERROR;\n\t} else {\n\t\tchosen_mb->edge_array = (struct dgsh_edge *)p;\n\t\tmemcpy(&chosen_mb->edge_array[n_edges], edge,\n\t\t\t\t\t\tsizeof(struct dgsh_edge));\n\t\tDPRINTF(4, \"Added edge (%d -> %d) in dgsh graph.\\n\",\n\t\t\t\t\tedge->from, edge->to);\n\t\tchosen_mb->n_edges++;\n\t}\n\treturn OP_SUCCESS;\n}\n\n/* Try to add a newly occured edge in the dgsh graph. */\nstatic enum op_result\ntry_add_dgsh_edge(void)\n{\n\tif (chosen_mb->origin_index >= 0) { /* If MB not created just now: */\n\t\tstruct dgsh_edge new_edge;\n\t\tfill_dgsh_edge(&new_edge);\n\t\tif (lookup_dgsh_edge(&new_edge) == OP_CREATE) {\n\t\t\tif (add_edge(&new_edge) == OP_ERROR)\n\t\t\t\treturn OP_ERROR;\n\t\t\tDPRINTF(4, \"Dgsh graph now has %d edges.\\n\",\n\t\t\t\t\t\t\tchosen_mb->n_edges);\n\t\t\treturn OP_SUCCESS;\n\t\t}\n\t\treturn OP_EXISTS;\n\t}\n\treturn OP_NOOP;\n}\n\n/* A constructor-like function for struct dgsh_node. */\nstatic void\nfill_node(const char *tool_name, pid_t self_pid, int *n_input_fds,\n\t\t\t\t\t\tint *n_output_fds)\n{\n\tself_node.pid = self_pid;\n\tmemcpy(self_node.name, tool_name, strlen(tool_name) + 1);\n\n\tif (n_input_fds == NULL)\n\t\tif (self_node.dgsh_in)\n\t\t\tself_node.requires_channels = 1;\n\t\telse\n\t\t\tself_node.requires_channels = 0;\n\telse\n\t\tself_node.requires_channels = *n_input_fds;\n\tDPRINTF(4, \"%s(): dgsh_in: %d, self_node.requires_channels: %d\", __func__,\n\t\t\tself_node.dgsh_in, self_node.requires_channels);\n\n\tif (n_output_fds == NULL) {\n\t\tif (self_node.dgsh_out)\n\t\t\tself_node.provides_channels = 1;\n\t\telse\n\t\t\tself_node.provides_channels = 0;\n\t} else\n\t\tself_node.provides_channels = *n_output_fds;\n\tDPRINTF(4, \"%s(): dgsh_out: %d, self_node.provides_channels: %d\", __func__,\n\t\t\tself_node.dgsh_out, self_node.provides_channels);\n\n\tDPRINTF(4, \"Dgsh node for tool %s with pid %d created.\\n\", tool_name,\n\t\t\tself_pid);\n}\n\n/**\n * Add node to message block. Copy the node using offset-based\n * calculation from the start of the array of nodes.\n */\nstatic enum op_result\ntry_add_dgsh_node(const char *tool_name, pid_t self_pid, int *n_input_fds,\n\t\t\t\t\t\tint *n_output_fds)\n{\n\tint n_nodes = chosen_mb->n_nodes;\n\tint i;\n\tfor (i = 0; i < n_nodes; i++) {\n\t\tDPRINTF(4, \"node name: %s, pid: %d\",\n\t\t\t\t\t\tchosen_mb->node_array[i].name,\n\t\t\t\t\t\tchosen_mb->node_array[i].pid);\n\t\tif (chosen_mb->node_array[i].pid == self_pid)\n\t\t\tbreak;\n\t}\n\tif (i == n_nodes) {\n\t\tfill_node(tool_name, self_pid, n_input_fds, n_output_fds);\n\t\tif (add_node() == OP_ERROR)\n\t\t\treturn OP_ERROR;\n\t\tDPRINTF(4, \"Dgsh graph now has %d nodes.\\n\", chosen_mb->n_nodes);\n\t\treturn OP_SUCCESS;\n\t}\n\treturn OP_EXISTS;\n}\n\nstatic void\nfree_conc_array(struct dgsh_negotiation *mb)\n{\n\tint i, n_concs = mb->n_concs;\n\tfor (i = 0; i < n_concs; i++)\n\t\tif (mb->conc_array[i].proc_pids)\n\t\t\tfree(mb->conc_array[i].proc_pids);\n\tfree(mb->conc_array);\n}\n\n/* Deallocate message block together with nodes and edges. */\nvoid\nfree_mb(struct dgsh_negotiation *mb)\n{\n\tif (mb->graph_solution)\n\t\tfree_graph_solution(mb->n_nodes - 1);\n\tif (mb->node_array)\n\t\tfree(mb->node_array);\n\tif (mb->edge_array)\n\t\tfree(mb->edge_array);\n\tif (mb->conc_array)\n\t\tfree_conc_array(mb);\n\tfree(mb);\n\tDPRINTF(4, \"%s(): Freed message block.\", __func__);\n}\n\nstatic enum op_result\nregister_node_edge(const char *tool_name, pid_t self_pid, int *n_input_fds,\n\t\tint *n_output_fds)\n{\n\t/* Create dgsh node representation and add node, edge to the graph. */\n\tif (try_add_dgsh_node(tool_name, self_pid, n_input_fds,\n\t\t\t\tn_output_fds) == OP_ERROR)\n\t\treturn OP_ERROR;\n\n\tif (try_add_dgsh_edge() == OP_ERROR)\n\t\treturn OP_ERROR;\n\n\treturn OP_SUCCESS;\n}\n\n/**\n * Check if the arrived message block preexists our chosen one\n * and substitute the chosen if so.\n * If the arrived message block is younger discard it and don't\n * forward it.\n * If the arrived is the chosen, try to add the edge.\n */\nstatic enum op_result\nanalyse_read(struct dgsh_negotiation *fresh_mb,\n\t\t\tint *ntimes_seen_run,\n\t\t\tint *ntimes_seen_error,\n\t\t\tint *ntimes_seen_draw_exit,\n\t\t\tconst char *tool_name,\n\t\t\tpid_t pid, int *n_input_fds, int *n_output_fds)\n{\n\tif (fresh_mb != NULL) {\n\t\tif (chosen_mb != NULL)\n\t\t\tfree(chosen_mb);\n\t\tchosen_mb = fresh_mb;\n\t} else\n\t\tif (chosen_mb == NULL)\n\t\t\tconstruct_message_block(tool_name, pid);\n\n\tif (init_error)\n\t\tchosen_mb->state = PS_ERROR;\n\n\tif (chosen_mb->state == PS_ERROR) {\n\t\tif (errno == 0)\n\t\t\terrno = ECONNRESET;\n\t\tif (chosen_mb->is_error_confirmed)\n\t\t\t(*ntimes_seen_error)++;\n\t} else if (chosen_mb->state == PS_DRAW_EXIT)\n\t\t(*ntimes_seen_draw_exit)++;\n\telse if (chosen_mb->state == PS_RUN)\n\t\t(*ntimes_seen_run)++;\n\telse if (chosen_mb->state == PS_NEGOTIATION)\n\t\tif (register_node_edge(tool_name, pid, n_input_fds,\n\t\t\t\tn_output_fds) == OP_ERROR)\n\t\t\tchosen_mb->state = PS_ERROR;\n\treturn OP_SUCCESS;\n}\n\nstatic enum op_result\ncheck_read(int bytes_read, int buf_size, int expected_read_size) {\n\tif (bytes_read != expected_read_size) {\n\t\tDPRINTF(4, \"%s(): ERROR: Read %d bytes of message block, expected to read %d.\\n\",\n\t\t\t__func__, bytes_read, expected_read_size);\n\t\treturn OP_ERROR;\n\t}\n\tif (bytes_read > buf_size) {\n\t\tDPRINTF(4, \"%s(): ERROR: Read %d bytes of message block, but buffer can hold up to %d.\",\n\t\t\t\t__func__, bytes_read, buf_size);\n\t\treturn OP_ERROR;\n\t}\n\treturn OP_SUCCESS;\n}\n\nstatic enum op_result\nalloc_copy_proc_pids(struct dgsh_conc *c, char *buf, int bytes_read,\n\t\tint buf_size)\n{\n\tint expected_read_size = sizeof(int) * c->n_proc_pids;\n\tif (check_read(bytes_read, buf_size, expected_read_size) == OP_ERROR)\n\t\treturn OP_ERROR;\n\tc->proc_pids = (int *)malloc(bytes_read);\n\tmemcpy(c->proc_pids, buf, bytes_read);\n\treturn OP_SUCCESS;\n}\n\nstatic enum op_result\nalloc_copy_concs(struct dgsh_negotiation *mb, char *buf, int bytes_read,\n\t\tint buf_size)\n{\n\tint expected_read_size = sizeof(struct dgsh_conc) * mb->n_concs;\n\tif (check_read(bytes_read, buf_size, expected_read_size) == OP_ERROR)\n\t\treturn OP_ERROR;\n\tmb->conc_array = (struct dgsh_conc *)malloc(bytes_read);\n\tmemcpy(mb->conc_array, buf, bytes_read);\n\treturn OP_SUCCESS;\n}\n\n/* Allocate memory for graph solution and copy from buffer. */\nstatic enum op_result\nalloc_copy_graph_solution(struct dgsh_negotiation *mb, char *buf, int bytes_read,\n\t\t\t\t\t\t\t\tint buf_size)\n{\n\tint expected_read_size = sizeof(struct dgsh_node_connections) *\n\t\t\t\t\t\t\t\tmb->n_nodes;\n\tif (check_read(bytes_read, buf_size, expected_read_size) == OP_ERROR)\n\t\treturn OP_ERROR;\n\tmb->graph_solution = (struct dgsh_node_connections *)malloc(bytes_read);\n\tmemcpy(mb->graph_solution, buf, bytes_read);\n\treturn OP_SUCCESS;\n}\n\n/* Allocate memory for message_block edges and copy from buffer. */\nstatic enum op_result\nalloc_copy_edges(struct dgsh_negotiation *mb, char *buf, int bytes_read,\n\t\t\t\t\t\t\t\tint buf_size)\n{\n\tint expected_read_size = sizeof(struct dgsh_edge) * mb->n_edges;\n\tif (check_read(bytes_read, buf_size, expected_read_size) == OP_ERROR)\n\t\treturn OP_ERROR;\n\tmb->edge_array = (struct dgsh_edge *)malloc(bytes_read);\n\tmemcpy(mb->edge_array, buf, bytes_read);\n\treturn OP_SUCCESS;\n}\n\n/* Allocate memory for message_block nodes and copy from buffer. */\nstatic enum op_result\nalloc_copy_nodes(struct dgsh_negotiation *mb, char *buf, int bytes_read,\n\t\t\t\t\t\t\t\tint buf_size)\n{\n\tint expected_read_size = sizeof(struct dgsh_node) * mb->n_nodes;\n\tif (check_read(bytes_read, buf_size, expected_read_size) == OP_ERROR)\n\t\treturn OP_ERROR;\n\tmb->node_array = (struct dgsh_node *)malloc(bytes_read);\n\tmemcpy(mb->node_array, buf, bytes_read);\n\tDPRINTF(4, \"%s(): Node array recovered.\", __func__);\n\treturn OP_SUCCESS;\n}\n\n/* Allocate memory for core message_block and copy from buffer. */\nstatic enum op_result\nalloc_copy_mb(struct dgsh_negotiation **mb, char *buf, int bytes_read,\n\t\t\t\t\t\t\tint buf_size)\n{\n\tint expected_read_size = sizeof(struct dgsh_negotiation);\n\tif (check_read(bytes_read, buf_size, expected_read_size) == OP_ERROR)\n\t\treturn OP_ERROR;\n\t*mb = (struct dgsh_negotiation *)malloc(bytes_read);\n\tmemcpy(*mb, buf, bytes_read);\n\t(*mb)->node_array = NULL;\n\t(*mb)->edge_array = NULL;\n\t(*mb)->graph_solution = NULL;\n\treturn OP_SUCCESS;\n}\n\n/**\n * The actual call to read in the message block.\n * If the call does not succeed or does not signal retry we have\n * to quit operation.\n */\nstatic enum op_result\ncall_read(int fd, char *buf, int buf_size, int *bytes_read, int *error_code)\n{\n\t*error_code = 0;\n\tDPRINTF(4, \"Try read from fd %d.\", fd);\n\tif ((*bytes_read = read(fd, buf, buf_size)) == -1) {\n\t\t*error_code = -errno;\n\t\treturn OP_ERROR;\n\t}\n\treturn OP_SUCCESS;\n}\n\n/**\n * Try to read a chunk of data from either side (stdin or stdout).\n * This function is agnostic as to what it is reading.\n * Its job is to manage a read operation.\n */\nstatic enum op_result\nread_chunk(int read_fd, char *buf, int buf_size, int *bytes_read,\n\t\t\t\t\t\tint struct_type)\n{\n\tint error_code;\n\tDPRINTF(4, \"%s(): buf_size: %d, IOV_MAX: %d\",\n\t\t\t__func__, buf_size, iov_max);\n\n\tif (buf_size > iov_max) {\n\t\tint buf_size_piece, pieces, i, size_copied = 0, rsize = 0,\n\t\t\tstruct_size, all_elements, max_elements, elements = 0;\n\n\t\tstruct_size = get_struct_size(struct_type);\n\t\tall_elements = buf_size / struct_size;\n\t\tmax_elements = iov_max / struct_size;\n\t\tpieces = all_elements / max_elements;\n\t\tpieces += (all_elements % max_elements > 0);\n\t\tDPRINTF(4, \"struct_type: %d, pieces: %d, all_elements: %d, max_elements: %d\",\n\t\t\tstruct_type, pieces, all_elements, max_elements);\n\t\t\n\t\tfor (i = 0; i < pieces; i++) {\n\t\t\tvoid *buf_piece;\n\t\t\tif (all_elements - max_elements > 0)\n\t\t\t\telements = max_elements;\n\t\t\telse if (all_elements > 0)\n\t\t\t\telements = all_elements;\n\t\t\tall_elements -= elements;\n\t\t\tbuf_size_piece = struct_size * elements;\n\t\t\tDPRINTF(4, \"Round %d: elements: %d, size: %d\",\n\t\t\t\ti, elements, buf_size_piece);\n\n\t\t\tif (buf_size_piece > 0) {\n\t\t\t\tbuf_piece = malloc(buf_size_piece);\n\t\t\t\tcall_read(read_fd, buf_piece, buf_size_piece,\n\t\t\t\t\tbytes_read, &error_code);\n\t\t\t\tif (*bytes_read == -1) {\n\t\t\t\t\tfree(buf_piece);\n\t\t\t\t\treturn OP_ERROR;\n\t\t\t\t}\n\t\t\t\trsize += *bytes_read;\n\t\t\t\tmemcpy(buf + size_copied, buf_piece,\n\t\t\t\t\t\t\tbuf_size_piece);\n\t\t\t\tsize_copied += buf_size_piece;\n\t\t\t\tfree(buf_piece);\n\t\t\t}\n\t\t}\n\t\t*bytes_read = rsize;\n\t} else\n\t\tcall_read(read_fd, buf, buf_size, bytes_read, &error_code);\n\n\tif (*bytes_read == -1) {  /* Read failed. */\n\t \tDPRINTF(4, \"ERROR: Reading from fd %d failed with error code %d.\",\n\t\t\tread_fd, error_code);\n\t\treturn error_code;\n\t} else  /* Read succeeded. */\n\t\tDPRINTF(4, \"Read succeeded: %d bytes read from %d.\\n\",\n\t\t*bytes_read, read_fd);\n\treturn OP_SUCCESS;\n}\n\n/* Allocate memory for file descriptors. */\nstatic enum op_result\nalloc_fds(int **fds, int n_fds)\n{\n\tif (n_fds) {\n\t\t*fds = (int *)malloc(sizeof(int) * n_fds);\n\t\tif (*fds == NULL)\n\t\t\treturn OP_ERROR;\n\t}\n\treturn OP_SUCCESS;\n}\n\n/* Allocate memory for output file descriptors. */\nstatic enum op_result\nalloc_io_fds()\n{\n\tint i = 0;\n\tstruct dgsh_node_connections *this_nc =\n\t\t\t\t&chosen_mb->graph_solution[self_node.index];\n\tDPRINTF(4, \"%s(): self node: %d, incoming edges: %d, outgoing edges: %d\", __func__, self_node.index, this_nc->n_edges_incoming, this_nc->n_edges_outgoing);\n\n\tself_pipe_fds.n_input_fds = 0; /* For safety. */\n\tfor (i = 0; i < this_nc->n_edges_incoming; i++) {\n\t\tint k;\n\t\tfor (k = 0; k < this_nc->edges_incoming[i].instances; k++)\n\t\t\tself_pipe_fds.n_input_fds++;\n\t}\n\tif (alloc_fds(&self_pipe_fds.input_fds, self_pipe_fds.n_input_fds) ==\n\t\t\t\t\t\t\t\t\tOP_ERROR)\n\t\treturn OP_ERROR;\n\n\tself_pipe_fds.n_output_fds = 0;\n\tfor (i = 0; i < this_nc->n_edges_outgoing; i++) {\n\t\tint k;\n\t\tfor (k = 0; k < this_nc->edges_outgoing[i].instances; k++)\n\t\t\tself_pipe_fds.n_output_fds++;\n\t}\n\tif (alloc_fds(&self_pipe_fds.output_fds, self_pipe_fds.n_output_fds) ==\n\t\t\t\t\t\t\t\t\tOP_ERROR)\n\t\treturn OP_ERROR;\n\n\treturn OP_SUCCESS;\n}\n\n/* Return the pid of the node that dispatched\n * the provided message block.\n */\npid_t\nget_origin_pid(struct dgsh_negotiation *mb)\n{\n\t/* Nodes may not be recorded if an error manifests early */\n\tif (mb->node_array) {\n\t\tstruct dgsh_node *n = &mb->node_array[mb->origin_index];\n\t\tDPRINTF(4, \"Logical origin: tool %s with pid %d\",\n\t\t\t\tn->name, n->pid);\n\t\treturn n->pid;\n\t} else\n\t\treturn 0;\n}\n\n/* Return the number of input file descriptors\n * expected by process with pid PID.\n * It is applicable to concentrators too.\n */\nint\nget_expected_fds_n(struct dgsh_negotiation *mb, pid_t pid)\n{\n\tint expected_fds_n = 0;\n\tint i = 0, j = 0;\n\tfor (i = 0; i < mb->n_nodes; i++) {\n\t\tif (mb->node_array[i].pid == pid) {\n\t\t\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\tmb->graph_solution;\n\t\t\tfor (j = 0; j < graph_solution[i].n_edges_incoming; j++)\n\t\t\t\texpected_fds_n +=\n\t\t\t\t\tgraph_solution[i].edges_incoming[j].instances;\n\t\t\treturn expected_fds_n;\n\t\t}\n\t}\n\t/* pid may belong to another conc */\n\tfor (i = 0; i < mb->n_concs; i++) {\n\t\tif (mb->conc_array[i].pid == pid)\n\t\t\treturn mb->conc_array[i].input_fds;\n\t}\n\t/* Invalid pid */\n\treturn -1;\n}\n\n/* Return the number of output file descriptors\n * provided by process with pid PID.\n * It is applicable to concentrators too.\n */\nint\nget_provided_fds_n(struct dgsh_negotiation *mb, pid_t pid)\n{\n\tint provided_fds_n = 0;\n\tint i = 0, j = 0;\n\tfor (i = 0; i < mb->n_nodes; i++) {\n\t\tif (mb->node_array[i].pid == pid) {\n\t\t\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\tmb->graph_solution;\n\t\t\tfor (j = 0; j < graph_solution[i].n_edges_outgoing; j++) {\n\t\t\t\tprovided_fds_n +=\n\t\t\t\t\tgraph_solution[i].edges_outgoing[j].instances;\n\t\t\t}\n\t\t\treturn provided_fds_n;\n\t\t}\n\t}\n\t/* pid may belong to another conc */\n\tfor (i = 0; i < mb->n_concs; i++)\n\t\tif (mb->conc_array[i].pid == pid)\n\t\t\treturn mb->conc_array[i].output_fds;\n\t/* Invalid pid */\n\treturn -1;\n}\n\n/*\n * Write the file descriptor fd_to_write to\n * the socket file descriptor output_socket.\n */\nvoid\nwrite_fd(int output_socket, int fd_to_write)\n{\n\tstruct msghdr    msg;\n\tstruct cmsghdr  *cmsg;\n\tunsigned char    buf[CMSG_SPACE(sizeof(int))];\n\tstruct iovec io = { .iov_base = \" \", .iov_len = 1 };\n\n\tmemset(&msg, 0, sizeof(msg));\n\tmsg.msg_iov = &io;\n\tmsg.msg_iovlen = 1;\n\tmsg.msg_control = buf;\n\tmsg.msg_controllen = sizeof(buf);\n\n\tcmsg = CMSG_FIRSTHDR(&msg);\n\tcmsg->cmsg_len = CMSG_LEN(sizeof(int));\n\tcmsg->cmsg_level = SOL_SOCKET;\n\tcmsg->cmsg_type = SCM_RIGHTS;\n\t*(int *)CMSG_DATA(cmsg) = fd_to_write;\n\n\tif (sendmsg(output_socket, &msg, 0) == -1)\n\t\terr(1, \"sendmsg on fd %d\", output_socket);\n}\n\n/*\n * Read a file descriptor from socket input_socket and return it.\n */\nint\nread_fd(int input_socket)\n{\n\tstruct msghdr msg;\n\tstruct cmsghdr *cmsg;\n\tunsigned char buf[CMSG_SPACE(sizeof(int))];\n\tchar m_buffer[2];\n\tstruct iovec io = { .iov_base = m_buffer, .iov_len = sizeof(m_buffer) };\n\n\tmemset(&msg, 0, sizeof(msg));\n\tmsg.msg_control = buf;\n\tmsg.msg_controllen = sizeof(buf);\n\tmsg.msg_iov = &io;\n\tmsg.msg_iovlen = 1;\n\nagain:\n\tif (recvmsg(input_socket, &msg, 0) == -1) {\n\t\tif (errno == EAGAIN) {\n\t\t\tsleep(1);\n\t\t\tgoto again;\n\t\t}\n\t\terr(1, \"recvmsg on fd %d\", input_socket);\n\t}\n\tif ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC))\n\t\terrx(1, \"control message truncated on fd %d\", input_socket);\n\tfor (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;\n\t    cmsg = CMSG_NXTHDR(&msg, cmsg)) {\n\t\tif (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&\n\t\t    cmsg->cmsg_level == SOL_SOCKET &&\n\t\t    cmsg->cmsg_type == SCM_RIGHTS)\n\t\t\treturn *(int *)CMSG_DATA(cmsg);\n\t}\n\terrx(1, \"unable to read file descriptor from fd %d\", input_socket);\n}\n\n/* Read file descriptors piping input from another tool in the dgsh graph. */\nstatic enum op_result\nread_input_fds(int input_socket, int *input_fds)\n{\n\t/**\n\t * A node's connections are located at the same position\n         * as the node in the node array.\n\t */\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\t\tchosen_mb->graph_solution;\n\tstruct dgsh_node_connections *this_nc =\n\t\t\t\t\t&graph_solution[self_node.index];\n\tassert(this_nc->node_index == self_node.index);\n\tint i;\n\tint total_edge_instances = 0;\n\tenum op_result re = OP_SUCCESS;\n\n\tDPRINTF(4, \"%s(): %d incoming edges to inspect of node %d.\", __func__,\n\t\t\tthis_nc->n_edges_incoming, self_node.index);\n\tfor (i = 0; i < this_nc->n_edges_incoming; i++) {\n\t\tint k;\n\t\t/**\n\t\t * Due to channel constraint flexibility,\n\t\t * each edge can have more than one instances.\n\t\t */\n\t\tfor (k = 0; k < this_nc->edges_incoming[i].instances; k++) {\n\t\t\tinput_fds[total_edge_instances] = read_fd(input_socket);\n\t\t\tDPRINTF(4, \"%s: Node %d received file descriptor %d.\",\n\t\t\t\t\t__func__, this_nc->node_index,\n\t\t\t\t\tinput_fds[total_edge_instances]);\n\t\t\ttotal_edge_instances++;\n\t\t}\n\t\t/* XXX */\n\t\tif (re == OP_ERROR)\n\t\t\tbreak;\n\t}\n\tif (re == OP_ERROR) {\n\t\tfree_graph_solution(chosen_mb->n_nodes - 1);\n\t\tfree(input_fds);\n\t}\n\treturn re;\n}\n\nstatic enum op_result\nread_concs(int read_fd, struct dgsh_negotiation *fresh_mb)\n{\n\tint bytes_read;\n\tsize_t buf_size = sizeof(struct dgsh_conc) * fresh_mb->n_concs;\n\tchar *buf = (char *)malloc(buf_size);\n\tenum op_result error_code = OP_SUCCESS;\n\n\tif (!fresh_mb->conc_array)\n\t\treturn error_code;\n\n\tif ((error_code = read_chunk(read_fd, buf, buf_size, &bytes_read, 3))\n\t\t\t!= OP_SUCCESS)\n\t\treturn error_code;\n\terror_code = alloc_copy_concs(fresh_mb, buf, bytes_read, buf_size);\n\tfree(buf);\n\n\tint i, n_concs = fresh_mb->n_concs;\n\tfor (i = 0; i < n_concs; i++) {\n\t\tstruct dgsh_conc *c = &fresh_mb->conc_array[i];\n\t\tsize_t buf_size = sizeof(int) * c->n_proc_pids;\n\t\tbuf = (char *)malloc(buf_size);\n\t\tif ((error_code = read_chunk(read_fd, buf, buf_size,\n\t\t\t\t\t\t&bytes_read, 5)) != OP_SUCCESS)\n\t\t\treturn error_code;\n\t\terror_code = alloc_copy_proc_pids(c, buf, bytes_read, buf_size);\n\t\tfree(buf);\n\t\tDPRINTF(4, \"%s(): Read %d proc_pids for conc %d at index %d of size %d bytes \",\n\t\t\t\t__func__, c->n_proc_pids, c->pid, i, bytes_read);\n\t}\n\n\treturn error_code;\n}\n\n/* Try read solution to the dgsh negotiation graph. */\nstatic enum op_result\nread_graph_solution(int read_fd, struct dgsh_negotiation *fresh_mb)\n{\n\tint i;\n\tint bytes_read = 0;\n\tint n_nodes = fresh_mb->n_nodes;\n\tsize_t buf_size = sizeof(struct dgsh_node_connections) * n_nodes;\n\tchar *buf = (char *)malloc(buf_size);\n\tenum op_result error_code = OP_SUCCESS;\n\n\t/* Read node connection structures of the solution. */\n\tif ((error_code = read_chunk(read_fd, buf, buf_size, &bytes_read, 4))\n\t\t\t!= OP_SUCCESS)\n\t\treturn error_code;\n\tif ((error_code = alloc_copy_graph_solution(fresh_mb, buf, bytes_read,\n\t\t\t\t\tbuf_size)) == OP_ERROR)\n\t\treturn error_code;\n\tfree(buf);\n\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\t\t\tfresh_mb->graph_solution;\n\tfor (i = 0; i < n_nodes; i++) {\n\t\tstruct dgsh_node_connections *nc = &graph_solution[i];\n\t\tDPRINTF(4, \"Node %d with %d incoming edges at %lx and %d outgoing edges at %lx.\", nc->node_index, nc->n_edges_incoming, (long)nc->edges_incoming, nc->n_edges_outgoing, (long)nc->edges_outgoing);\n\t\tint in_edges_size = sizeof(struct dgsh_edge) * nc->n_edges_incoming;\n\t\tint out_edges_size = sizeof(struct dgsh_edge) * nc->n_edges_outgoing;\n\n\t\t/* Read a node's incoming connections. */\n\t\tif (nc->n_edges_incoming > 0) {\n\t\t\tbuf = (char *)malloc(in_edges_size);\n\t\t\tif ((error_code = read_chunk(read_fd, buf, in_edges_size,\n\t\t\t\t&bytes_read, 2)) != OP_SUCCESS)\n\t\t\t\treturn error_code;\n\t\t\tif (in_edges_size != bytes_read) {\n\t\t\t\tDPRINTF(4, \"%s(): ERROR: Expected %d bytes, got %d.\", __func__,\n\t\t\t\t\t\tin_edges_size, bytes_read);\n\t\t\t\treturn OP_ERROR;\n\t\t\t}\n\t\t\tif (alloc_node_connections(&nc->edges_incoming,\n\t\t\t\tnc->n_edges_incoming, 0, i) == OP_ERROR)\n\t\t\t\treturn OP_ERROR;\n\t\t\tmemcpy(nc->edges_incoming, buf, in_edges_size);\n\t\t\tfree(buf);\n\t\t}\n\n\t\t/* Read a node's outgoing connections. */\n\t\tif (nc->n_edges_outgoing) {\n\t\t\tbuf = (char *)malloc(out_edges_size);\n\t\t\tif ((error_code = read_chunk(read_fd, buf, out_edges_size,\n\t\t\t\t&bytes_read, 2)) != OP_SUCCESS)\n\t\t\t\treturn error_code;\n\t\t\tif (out_edges_size != bytes_read) {\n\t\t\t\tDPRINTF(4, \"%s(): ERROR: Expected %d bytes, got %d.\", __func__,\n\t\t\t\t\t\tout_edges_size, bytes_read);\n\t\t\t\treturn OP_ERROR;\n\t\t\t}\n\t\t\tif (alloc_node_connections(&nc->edges_outgoing,\n\t\t\t\tnc->n_edges_outgoing, 1, i) == OP_ERROR)\n\t\t\t\treturn OP_ERROR;\n\t\t\tmemcpy(nc->edges_outgoing, buf, out_edges_size);\n\t\t\tfree(buf);\n\t\t}\n\t}\n\treturn OP_SUCCESS;\n}\n\n/**\n * Read a circulated message block coming in on any of the specified read_fds.\n * In most cases these will specify the input or output side. This capability\n * relies on an extension to a standard shell implementation,\n * e.g., bash, that allows reading and writing to both sides\n * for the negotiation phase.\n * On return:\n * read_fd will contain the file descriptor number that was read.\n * fresh_mb will contain the read message block in dynamically allocated\n * memory. This should be freed by calling free_mb.\n */\nenum op_result\nread_message_block(int read_fd, struct dgsh_negotiation **fresh_mb)\n{\n\tsize_t buf_size = sizeof(struct dgsh_negotiation);\n\tchar *buf = (char *)malloc(buf_size);\n\tint bytes_read = 0;\n\tenum op_result error_code = 0;\n\n\tDPRINTF(3, \"%s(): %s (%d)\", __func__, programname, self_node.index);\n\n\tmemset(buf, 0, buf_size);\n\n\t/* Try read core message block: struct negotiation state fields. */\n\tif ((error_code = read_chunk(read_fd, buf, buf_size, &bytes_read, 0))\n\t\t\t!= OP_SUCCESS)\n\t\treturn error_code;\n\tif (alloc_copy_mb(fresh_mb, buf, bytes_read, buf_size) == OP_ERROR)\n\t\treturn OP_ERROR;\n\tfree(buf);\n\n\tif ((*fresh_mb)->n_nodes > 0) {\n\t\tbuf_size = sizeof(struct dgsh_node) * (*fresh_mb)->n_nodes;\n\t\tbuf = (char *)malloc(buf_size);\n\t\tif ((error_code = read_chunk(read_fd, buf, buf_size,\n\t\t\t\t\t&bytes_read, 1)) != OP_SUCCESS)\n\t\t\treturn error_code;\n\t\tif (alloc_copy_nodes(*fresh_mb, buf, bytes_read, buf_size)\n\t\t\t\t\t\t\t\t== OP_ERROR)\n\t\t\treturn OP_ERROR;\n\t\tfree(buf);\n\t}\n\n\tif (read_concs(read_fd, *fresh_mb) == OP_ERROR)\n\t\treturn OP_ERROR;\n\n\tif ((*fresh_mb)->state == PS_NEGOTIATION) {\n\t\tif ((*fresh_mb)->n_edges > 0) {\n\t\t\tDPRINTF(4, \"%s(): Read %d negotiation graph edges.\",\n\t\t\t\t\t__func__, (*fresh_mb)->n_edges);\n\t\t\tbuf_size = sizeof(struct dgsh_edge) * (*fresh_mb)->n_edges;\n\t\t\tbuf = (char *)malloc(buf_size);\n\t\t\tif ((error_code = read_chunk(read_fd, buf, buf_size,\n\t\t\t     &bytes_read, 2)) != OP_SUCCESS)\n\t\t\t\treturn error_code;\n\t\t\tif (alloc_copy_edges(*fresh_mb, buf, bytes_read,\n\t\t\t    buf_size) == OP_ERROR)\n\t\t\t\treturn OP_ERROR;\n\t\t\tfree(buf);\n\t\t}\n\t} else if ((*fresh_mb)->state == PS_RUN) {\n\t\t/**\n\t\t * Try read solution.\n\t\t * fresh_mb should be an updated version of the chosen_mb\n\t\t * or even the same structure because this is the phase\n\t\t * where we share the solution across the dgsh graph.\n                 */\n\t\tif (read_graph_solution(read_fd, *fresh_mb) == OP_ERROR)\n\t\t\treturn OP_ERROR;\n\t}\n\tDPRINTF(4, \"%s(): Read message block or solution from node %d sent from file descriptor: %s.\\n\", __func__, (*fresh_mb)->origin_index, ((*fresh_mb)->origin_fd_direction) ? \"stdout\" : \"stdin\");\n\treturn OP_SUCCESS;\n}\n\n/* Construct a message block to use as a vehicle for the negotiation phase. */\nenum op_result\nconstruct_message_block(const char *tool_name, pid_t self_pid)\n{\n\tchosen_mb = (struct dgsh_negotiation *)malloc(\n\t\t\t\tsizeof(struct dgsh_negotiation));\n\tif (!chosen_mb) {\n\t\tDPRINTF(4, \"ERROR: Memory allocation of message block failed.\");\n\t\treturn OP_ERROR;\n\t}\n\n\tchosen_mb->version = 1;\n\tchosen_mb->node_array = NULL;\n\tchosen_mb->n_nodes = 0;\n\tchosen_mb->edge_array = NULL;\n\tchosen_mb->n_edges = 0;\n\tchosen_mb->initiator_pid = self_pid;\n\tchosen_mb->state = (init_error ? PS_ERROR : PS_NEGOTIATION);\n\tchosen_mb->is_error_confirmed = false;\n\tchosen_mb->origin_index = -1;\n\tchosen_mb->origin_fd_direction = -1;\n\tchosen_mb->is_origin_conc = false;\n\tchosen_mb->conc_pid = -1;\n\tchosen_mb->graph_solution = NULL;\n\tchosen_mb->conc_array = NULL;\n\tchosen_mb->n_concs = 0;\n\tDPRINTF(3, \"Message block created by process %s with pid %d.\\n\",\n\t\t\t\t\t\ttool_name, (int)self_pid);\n\treturn OP_SUCCESS;\n}\n\n/* Get environment variable env_var. */\nstatic void\nget_env_var(const char *env_var, int *value)\n{\n\tchar *string_value = getenv(env_var);\n\tif (string_value == NULL)\n\t\tDPRINTF(4, \"Getting environment variable %s failed.\",\n\t\t\t\tenv_var);\n\telse {\n\t\tDPRINTF(4, \"getenv() returned string value %s.\",\n\t\t\t\tstring_value);\n\t\t*value = atoi(string_value);\n\t\tDPRINTF(4, \"Integer form of value is %d.\", *value);\n\t}\n}\n\n/**\n * Get environment variables DGSH_IN, DGSH_OUT set up by\n * the shell (through execvpe()).\n */\nstatic void\nget_environment_vars()\n{\n\tDPRINTF(4, \"Try to get environment variable DGSH_IN.\");\n\tget_env_var(\"DGSH_IN\", &self_node.dgsh_in);\n\n\tDPRINTF(4, \"Try to get environment variable DGSH_OUT.\");\n\tget_env_var(\"DGSH_OUT\", &self_node.dgsh_out);\n}\n\n/**\n * Verify tool's I/O channel requirements are sane.\n * We might need some upper barrier for requirements too,\n * such as, not more than 100 or 1000.\n */\nSTATIC enum op_result\nvalidate_input(int *channels_required, int *channels_provided, const char *tool_name)\n{\n\n\tif (!tool_name) {\n\t\tDPRINTF(4, \"ERROR: NULL pointer provided as tool name.\\n\");\n\t\treturn OP_ERROR;\n\t}\n\tif (channels_required == NULL || channels_provided == NULL)\n\t\treturn OP_SUCCESS;\n\tif (*channels_required < -1 || *channels_provided < -1) {\n\t\tDPRINTF(4, \"ERROR: I/O requirements entered for tool %s are less than -1. \\nChannels required %d \\nChannels provided: %d\",\n\t\t\ttool_name, *channels_required, *channels_provided);\n\t\treturn OP_ERROR;\n\t}\n\treturn OP_SUCCESS;\n}\n\nstatic int\nset_fds(fd_set *read_fds, fd_set *write_fds, bool isread)\n{\n\tfd_set *fds;\n\tFD_ZERO(read_fds);\n\tFD_ZERO(write_fds);\n\n\tDPRINTF(4, \"Next operation is a %s\", isread ? \"read\" : \"write\");\n\t/* The next operation is a read or a write */\n\tif (isread)\n\t\tfds = read_fds;\n\telse\n\t\tfds = write_fds;\n\n\tif (self_node.dgsh_out && !self_node.dgsh_in) {\n\t\tself_node_io_side.fd_direction = STDOUT_FILENO;\n\t\tFD_SET(STDOUT_FILENO, fds);\n\t} else if (!self_node.dgsh_out && self_node.dgsh_in) {\n\t\tself_node_io_side.fd_direction = STDIN_FILENO;\n\t\tFD_SET(STDIN_FILENO, fds);\n\t} else {\n\t\t/* We should have all ears open for a read */\n\t\tif (isread) {\n\t\t\tFD_SET(STDIN_FILENO, fds);\n\t\t\tFD_SET(STDOUT_FILENO, fds);\n\t\t} else {\n\t\t\t/* But for writing we should pass the message across.\n\t\t\t * If mb came from stdout channel, we got it from stdin.\n\t\t\t * So we should send it from stdout */\n\t\t\tif (chosen_mb->origin_fd_direction == STDOUT_FILENO) {\n\t\t\t\tFD_SET(STDOUT_FILENO, fds);\n\t\t\t\tself_node_io_side.fd_direction = STDOUT_FILENO;\n\t\t\t\tDPRINTF(4, \"STDOUT set for write\");\n\t\t\t} else {\n\t\t\t\tFD_SET(STDIN_FILENO, fds);\n\t\t\t\tself_node_io_side.fd_direction = STDIN_FILENO;\n\t\t\t\tDPRINTF(4, \"STDIN set for write\");\n\t\t\t}\n\t\t}\n\t}\n\t/* so that after select() we try both 0 and 1 to see if they are set */\n\treturn 2;\n}\n\nvoid\nset_negotiation_complete()\n{\n\tnegotiation_completed = 1;\n}\n\nstatic int\nsetup_file_descriptors(int *n_input_fds, int *n_output_fds,\n\t\tint **input_fds, int **output_fds)\n{\n\tDPRINTF(4, \"%s()\", __func__);\n\tif (n_input_fds != NULL && (*n_input_fds == 1 ||\n\t\t\t*n_input_fds == -1) && input_fds != NULL) {\n\t\tDPRINTF(4, \"n_input_fds: %d\\n\", *n_input_fds);\n\t\t*n_input_fds = 1;\n\t\t*input_fds = malloc(sizeof(int));\n\t\t(*input_fds)[0] = STDIN_FILENO;\n\t}\n\tif (n_output_fds != NULL && (*n_output_fds == 1 ||\n\t\t\t*n_output_fds == -1) && output_fds != NULL) {\n\t\tDPRINTF(4, \"n_output_fds: %d\\n\", *n_output_fds);\n\t\t*n_output_fds = 1;\n\t\t*output_fds = malloc(sizeof(int));\n\t\t(*output_fds)[0] = STDOUT_FILENO;\n\t}\n\treturn 0;\n}\n\n\n/*\n * Return function for dgsh_negotiate\n * Exit by printing an error (if needed)\n * otherwise return 0 for successful termination\n * or -1 for error\n */\nstatic int\ndgsh_exit(int ret, int flags)\n{\n\tif (ret == PS_COMPLETE)\n\t\treturn 0;\n\tif (ret == PS_DRAW_EXIT)\n\t\texit(EX_OK);\n\tif (!(flags & DGSH_HANDLE_ERROR))\n\t\treturn -1;\n\n\tswitch (errno) {\n\tcase ECONNRESET:\n\t\texit(EX_PROTOCOL);\n\tcase 0:\n\t\terrx(EX_PROTOCOL, \"dgsh negotiation failed\");\n\tdefault:\n\t\terr(EX_PROTOCOL, \"dgsh negotiation failed\");\n\t}\n}\n\n/**\n * Return the name of the specified state\n */\nconst char *\nstate_name(enum prot_state s)\n{\n\tswitch (s) {\n\tcase PS_COMPLETE:\n\t\treturn \"COMPLETE\";\n\tcase PS_NEGOTIATION:\n\t\treturn \"NEGOTIATION\";\n\tcase PS_NEGOTIATION_END:\n\t\treturn \"NEGOTIATION_END\";\n\tcase PS_RUN:\n\t\treturn \"RUN\";\n\tcase PS_ERROR:\n\t\treturn \"ERROR\";\n\tdefault:\n\t\tassert(0);\n\t}\n}\n\n/**\n * Each tool in the dgsh graph calls dgsh_negotiate() to take part in\n * peer-to-peer negotiation. A message block (MB) is circulated among tools\n * and is filled with tools' I/O requirements. When all requirements are in\n * place, an algorithm runs that tries to find a solution that satisfies\n * all requirements. If a solution is found, pipes are allocated and\n * set up according to the solution. The appropriate file descriptors\n * are provided to each tool and the negotiation phase ends.\n * The function's return value signifies success or failure of the\n * negotiation phase.\n */\nint\ndgsh_negotiate(int flags, const char *tool_name, int *n_input_fds,\n\t\tint *n_output_fds, int **input_fds, int **output_fds)\n{\n\tint i = 0;\n\tint ntimes_seen_run = 0;\n\tint ntimes_seen_error = 0;\n\tint ntimes_seen_draw_exit = 0;\n\tpid_t self_pid = getpid();    /* Get tool's pid */\n\tstruct dgsh_negotiation *fresh_mb = NULL; /* MB just read. */\n\n\tint nfds = 0, n_io_sides;\n\tbool isread = false;\n\tfd_set read_fds, write_fds;\n\tchar *timeout;\n\tchar *debug_level;\n\n\tif (negotiation_completed) {\n\t\terrno = EALREADY;\n\t\treturn dgsh_exit(-1, flags);\n\t}\n\n\t/* Get and set user-provided debug level.\n\t * dgsh_debug_level is defined in debug.h.\n\t */\n\tdebug_level = getenv(\"DGSH_DEBUG_LEVEL\");\n\tif (debug_level != NULL)\n\t\tdgsh_debug_level = atoi(debug_level);\n\n#ifndef UNIT_TESTING\n\tself_pipe_fds.input_fds = NULL;\t\t/* Clean garbage */\n\tself_pipe_fds.output_fds = NULL;\t/* Ditto */\n#endif\n\tprogramname = strdup(tool_name);\n\tDPRINTF(2, \"%s(): Tool %s with pid %d negotiating: nin=%d nout=%d.\",\n\t\t\t__func__, tool_name, (int)self_pid,\n\t\t\tn_input_fds ? *n_input_fds : 1,\n\t\t\tn_output_fds ? *n_output_fds : 1);\n\n\tif (validate_input(n_input_fds, n_output_fds, tool_name)\n\t\t\t\t\t\t\t== OP_ERROR) {\n\t\tnegotiation_completed = 1;\n\t\treturn dgsh_exit(-1, flags);\n\t}\n\n\tself_node.dgsh_in = 0;\n\tself_node.dgsh_out = 0;\n\tget_environment_vars();\n\tn_io_sides = self_node.dgsh_in + self_node.dgsh_out;\n\n\t/* Verify dgsh available on the required sides */\n\tif ((n_input_fds != NULL && *n_input_fds > 1 && !self_node.dgsh_in) ||\n\t    (n_output_fds != NULL && *n_output_fds > 1 && !self_node.dgsh_out)) {\n\t\terrno = ENOTSOCK;\n\t\tnegotiation_completed = 1;\n\t\treturn dgsh_exit(-1, flags);\n\t}\n\n\t/* Easy case, no dgsh I/O */\n\tif (n_io_sides == 0) {\n\t\tnegotiation_completed = 1;\n\t\treturn dgsh_exit(setup_file_descriptors(n_input_fds,\n\t\t\t\t\tn_output_fds, input_fds, output_fds), flags);\n\t}\n\n\tsignal(SIGALRM, dgsh_alarm_handler);\n\tif ((timeout = getenv(\"DGSH_TIMEOUT\")) != NULL)\n\t\talarm(atoi(timeout));\n\telse\n\t\talarm(DGSH_TIMEOUT);\n\n\t/* Start negotiation */\n\tif (self_node.dgsh_out && !self_node.dgsh_in) {\n#ifdef TIME\n\t\tclock_gettime(CLOCK_MONOTONIC, &tstart);\n#endif\n\t\tif (construct_message_block(tool_name, self_pid) == OP_ERROR)\n\t\t\tchosen_mb->state = PS_ERROR;\n\t\tif (register_node_edge(tool_name, self_pid, n_input_fds,\n\t\t\t\tn_output_fds) == OP_ERROR)\n\t\t\tchosen_mb->state = PS_ERROR;\n\t\tisread = false;\n        } else { /* or wait to receive MB. */\n\t\tisread = true;\n\t\tchosen_mb = NULL;\n\t}\n\n\t/* Perform phases and rounds. */\n\twhile (1) {\nagain:\n\t\tDPRINTF(4, \"%s(): perform round\", __func__);\n\t\tnfds = set_fds(&read_fds, &write_fds, isread);\n\t\tif (select(nfds, &read_fds, &write_fds, NULL, NULL) < 0) {\n\t\t\tif (errno == EINTR)\n\t\t\t\tgoto again;\n\t\t\tperror(\"select\");\n\t\t\tchosen_mb->state = PS_ERROR;\n\t\t}\n\n\t\tfor (i = 0; i < nfds; i++) {\n\t\t\tif (FD_ISSET(i, &write_fds)) {\n\t\t\t\tDPRINTF(4, \"write on fd %d is active.\", i);\n\t\t\t\t/* Write message block et al. */\n\t\t\t\tset_dispatcher();\n\t\t\t\tif (write_message_block(i) == OP_ERROR)\n\t\t\t\t\tchosen_mb->state = PS_ERROR;\n\t\t\t\tif (n_io_sides == ntimes_seen_run ||\n\t\t\t\t    n_io_sides == ntimes_seen_error ||\n\t\t\t\t    n_io_sides == ntimes_seen_draw_exit) {\n\t\t\t\t\tif (chosen_mb->state == PS_RUN)\n\t\t\t\t\t\tchosen_mb->state = PS_COMPLETE;\n\t\t\t\t\tgoto exit;\n\t\t\t\t}\n\t\t\t\tisread = true;\n\t\t\t}\n\t\t\tif (FD_ISSET(i, &read_fds)) {\n\t\t\t\tDPRINTF(4, \"read on fd %d is active.\", i);\n\t\t\t\t/* Read message block et al. */\n\t\t\t\tif (read_message_block(i, &fresh_mb)\n\t\t\t\t\t\t== OP_ERROR &&\n\t\t\t\t\t\tfresh_mb != NULL)\n\t\t\t\t\tfresh_mb->state = PS_ERROR;\n\t\t\t\t/* Check state */\n\t\t\t\tanalyse_read(fresh_mb,\n\t\t\t\t\t\t&ntimes_seen_run,\n\t\t\t\t\t\t&ntimes_seen_error,\n\t\t\t\t\t\t&ntimes_seen_draw_exit,\n\t\t\t\t\t\ttool_name,\n\t\t\t\t\t\tself_pid, n_input_fds,\n\t\t\t\t\t\tn_output_fds);\n\n\t\t\t\t/**\n\t\t\t\t * Initiator process.\n\t\t\t\t * It receives the block, so all IO\n\t\t\t\t * constraints have been stated. Now:\n\t\t\t\t * - solves the I/O constraint problem,\n\t\t\t\t * - communicates the solution,\n\t\t\t\t * and when it receives the block again,\n\t\t\t\t * it leaves negotiation.\n\t\t\t\t */\n\t\t\t\tif (self_node.pid ==\n\t\t\t\t\t\tchosen_mb->initiator_pid) {\n\t\t\t\t\tswitch (chosen_mb->state) {\n\t\t\t\t\tcase PS_NEGOTIATION:\n\t\t\t\t\t\tchosen_mb->state = PS_NEGOTIATION_END;\n\t\t\t\t\t\tDPRINTF(1, \"%s(): Gathered I/O requirements.\", __func__);\n\t\t\t\t\t\tint state = solve_graph();\n\t\t\t\t\t\tif (state == OP_ERROR) {\n\t\t\t\t\t\t\tchosen_mb->state = PS_ERROR;\n\t\t\t\t\t\t\tchosen_mb->is_error_confirmed = true;\n\t\t\t\t\t\t} else if (state == OP_DRAW_EXIT)\n\t\t\t\t\t\t\tchosen_mb->state = PS_DRAW_EXIT;\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tDPRINTF(1, \"%s(): Computed solution\", __func__);\n\t\t\t\t\t\t\tchosen_mb->state = PS_RUN;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase PS_RUN:\n\t\t\t\t\t\tDPRINTF(1, \"%s(): Communicated the solution\", __func__);\n\t\t\t\t\t\tchosen_mb->state = PS_COMPLETE;\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\tcase PS_ERROR:\n\t\t\t\t\t\tif (chosen_mb->is_error_confirmed)\n\t\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tchosen_mb->is_error_confirmed = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase PS_DRAW_EXIT:\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tassert(0);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tisread = false;\n\t\t\t}\n\t\t}\n\t}\nexit:\n\tDPRINTF(2, \"%s(): %s (%d) leaves after %s with state %s.\", __func__,\n\t\t\tprogramname, self_node.index, isread ? \"read\" : \"write\",\n\t\t\tstate_name(chosen_mb->state));\n\tif (chosen_mb->state == PS_COMPLETE) {\n\t\tif (alloc_io_fds() == OP_ERROR)\n\t\t\tchosen_mb->state = PS_ERROR;\n\t\tif (read_input_fds(STDIN_FILENO, self_pipe_fds.input_fds) ==\n\t\t\t\t\t\t\t\t\tOP_ERROR)\n\t\t\tchosen_mb->state = PS_ERROR;\n\t\tif (write_output_fds(STDOUT_FILENO,\n\t\t\t\tself_pipe_fds.output_fds, flags) == OP_ERROR)\n\t\t\tchosen_mb->state = PS_ERROR;\n\t\tif (establish_io_connections(input_fds, n_input_fds, output_fds,\n\t\t\t\t\t\tn_output_fds) == OP_ERROR)\n\t\t\tchosen_mb->state = PS_ERROR;\n\t} else if (chosen_mb->state == PS_DRAW_EXIT) {\n\t\tif (n_input_fds != NULL)\n\t\t\t*n_input_fds = 0;\n\t\tif (n_output_fds != NULL)\n\t\t\t*n_output_fds = 0;\n\t}\n\tint state = chosen_mb->state;\n#ifdef TIME\n\tif (self_node.pid == chosen_mb->initiator_pid) {\n\t\tclock_gettime(CLOCK_MONOTONIC, &tend);\n\t\tfprintf(stderr, \"The dgsh negotiation procedure took about %.5f seconds\\n\",\n\t\t\t((double)tend.tv_sec + 1.0e-9*tend.tv_nsec) -\n\t\t\t((double)tstart.tv_sec + 1.0e-9*tstart.tv_nsec));\n\t\tfflush(stderr);\n\t}\n#endif\n\tfree_mb(chosen_mb);\n\tnegotiation_completed = 1;\n\talarm(0);\t\t\t// Cancel alarm\n\tsignal(SIGALRM, SIG_IGN);\t// Do not handle the signal\n\treturn dgsh_exit(state, flags);\n}\n"
  },
  {
    "path": "core-tools/src/negotiate.h",
    "content": "/*\n * Copyright 2016-2017 Marios Fragkoulis\n *\n * Dgsh private negotiation API\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#ifndef NEGOTIATE_H\n#define NEGOTIATE_H\n\n#include <stdbool.h>\n#include <sys/socket.h> /* struct cmsghdr */\n\n#include <signal.h>\t/* sig_atomic_t */\n\n#include \"dgsh.h\"\n\n/* Negotiation protocol states */\nenum prot_state {\n\tPS_COMPLETE,\t\t/* Negotiation process is complete */\n\tPS_NEGOTIATION,\t\t/* Negotiation phase */\n\tPS_NEGOTIATION_END,\t/* End of negotiation phase */\n\tPS_RUN,\t\t\t/* Share solution; prepare to run */\n\tPS_ERROR,\t\t/* Error in negotiation process */\n\tPS_DRAW_EXIT,\t\t/* Compute and write the solution and exit */\n};\n\nunion fdmsg {\n\tstruct cmsghdr h;\n\tchar buf[CMSG_SPACE(sizeof(int))];\n};\n\n/*\n * Results of operations\n * Also negative values signify a failed operation's errno value\n */\nenum op_result {\n\tOP_SUCCESS,\t\t/* Successful */\n\tOP_ERROR,\t\t/* Unresolvable error due to I/O problem\n\t\t\t\t * constraints provided by the processes\n\t\t\t\t * on the dgsh graph or memory constraints\n\t\t\t\t * of the systems.\n\t\t\t\t */\n\tOP_EXISTS,\t\t/* Node or edge already registered with the\n\t\t\t\t * dgsh graph.\n\t\t\t\t */\n\tOP_CREATE,\t\t/* Node ar edge registered with the dgsh \n\t\t\t\t * graph.\n\t\t\t\t */\n\tOP_NOOP,\t\t/* No operation when trying to add an edge\n\t\t\t\t * on a graph with just one node at the time.\n\t\t\t\t */\n\tOP_RETRY,\t\t/* Not all constraints of an I/O constraint\n\t\t\t\t * problem have been satisfied yet.\n\t\t\t\t * Retry by leveraging flexible constraints.\n\t\t\t\t */\n\tOP_DRAW_EXIT,\t\t/* Compute and write the solution and exit */\n};\n\n\n#ifdef UNIT_TESTING\n\n#define STATIC\n\n/* Models an I/O connection between tools on an dgsh graph. */\nstruct dgsh_edge {\n        int from; /* Index of node on the graph where data comes from (out). */\n        int to; /* Index of node on the graph that receives the data (in). */\n        int instances; /* Number of instances of an edge. */\n\tint from_instances; /* Number of instances the origin node of an edge can provide. */\n\tint to_instances; /* Number of instances the destination of an edge can require. */\n};\n\nextern bool multiple_inputs;\nextern int nfd;\nextern int next_fd(int fd, bool *ro);\nextern int read_fd(int input_socket);\nextern void write_fd(int output_socket, int fd_to_write);\n#else\n\n#define STATIC static\n\n#endif /* UNIT_TESTING */\n\n/* The message block implicitly used by many functions */\nextern struct dgsh_negotiation *chosen_mb;\n\n/* Identifies the node and node's fd that sent the message block. */\nstruct node_io_side {\n\tint index;\t\t/* Node index on message block node array */\n\tint fd_direction;\t/* Message block origin node's file\n\t\t\t\t * descriptor\n\t\t\t\t */\n};\n\n/* Stores the number of a conc's IO fds */\nstruct dgsh_conc {\n\tpid_t pid;\n\tint input_fds;\n\tint output_fds;\n\tint n_proc_pids;\n\tint *proc_pids;\t\t/* pids at the multipipe end */\n\tint endpoint_pid;\t/* pid at the other end */\n\tbool multiple_inputs;\t/* true for input conc */\n};\n\n/* The message block structure that provides the vehicle for negotiation. */\nstruct dgsh_negotiation {\n\tint version;\t\t\t/* Protocol version. */\n        struct dgsh_node *node_array;\t/* Nodes, that is tools, on the dgsh\n\t\t\t\t\t * graph.\n\t\t\t\t\t */\n        int n_nodes;\t\t\t/* Number of nodes */\n\tstruct dgsh_edge *edge_array;\t/* Edges, that is connections between\n\t\t\t\t\t * nodes, on the dgsh graph\n\t\t\t\t\t */\n        int n_edges;\t\t\t/* Number of edges */\n\tpid_t initiator_pid;\t\t/* pid of the tool initiating this\n\t\t\t\t\t * negotiation block. All processes that\n\t\t\t\t\t * only contribute their output\n\t\t\t\t\t * channel to the dgsh graph will\n\t\t\t\t\t * initiate the negotiation process\n\t\t\t\t\t * by constructing and sharing a\n\t\t\t\t\t * message block. The one with the\n\t\t\t\t\t * smaller pid will prevail.\n\t\t\t\t\t */\n\tenum prot_state state;\t\t/* State of the negotiation process */\n\tbool is_error_confirmed;\t/* Error state is confirmed by the initiator\n\t\t\t\t\t   and propagated to the graph */\n\tint origin_index;\t\t/* The node from which the message\n\t\t\t\t\t * block is dispatched.\n\t\t\t\t\t */\n\tint origin_fd_direction;\t/* The origin's input or output channel\n\t\t\t\t\t */\n\tbool is_origin_conc;\t\t/* True if origin is a concentrator */\n\tpid_t conc_pid;\t\t\t/* Concentrator pid, otherwise -1 */\n\tstruct dgsh_node_connections *graph_solution; /* The solution to the\n\t\t\t\t\t\t       * I/O constraint problem\n\t\t\t\t\t\t       * at hand.\n\t\t\t\t\t\t       */\n\tstruct dgsh_conc *conc_array;\t/* Array of concentrators facilitating\n\t\t\t\t\t * the negotiation. The need for this\n\t\t\t\t\t * array emerged in cases where a conc\n\t\t\t\t\t * is directly connected to another\n\t\t\t\t\t * conc. The array stores a conc's\n\t\t\t\t\t * inputs/outputs so that a conc can\n\t\t\t\t\t * retrieve another conc's\n\t\t\t\t\t * inputs/outputs.\n\t\t\t\t\t */\n\tint n_concs;\n\n};\n\nenum op_result solve_graph(void);\nenum op_result construct_message_block(const char *tool_name, pid_t pid);\nstruct dgsh_conc *find_conc(struct dgsh_negotiation *mb, pid_t pid);\npid_t get_origin_pid(struct dgsh_negotiation *mb);\nint get_expected_fds_n(struct dgsh_negotiation *mb, pid_t pid);\nint get_provided_fds_n(struct dgsh_negotiation *mb, pid_t pid);\nenum op_result read_message_block(int read_fd,\n\t\tstruct dgsh_negotiation **fresh_mb);\nenum op_result write_message_block(int write_fd);\nvoid free_mb(struct dgsh_negotiation *mb);\nint read_fd(int input_socket);\nvoid write_fd(int output_socket, int fd_to_write);\n/* Alarm mechanism and on_exit handling */\nvoid set_negotiation_complete();\nvoid dgsh_alarm_handler(int);\n\n#endif /* NEGOTIATE_H */\n"
  },
  {
    "path": "core-tools/src/perm.1",
    "content": ".TH PERM 1 \"13 December 2016\"\n.\\\"\n.\\\" (C) Copyright 2016 Diomidis Spinellis.  All rights reserved.\n.\\\"\n.\\\"  Licensed under the Apache License, Version 2.0 (the \"License\");\n.\\\"  you may not use this file except in compliance with the License.\n.\\\"  You may obtain a copy of the License at\n.\\\"\n.\\\"      http://www.apache.org/licenses/LICENSE-2.0\n.\\\"\n.\\\"  Unless required by applicable law or agreed to in writing, software\n.\\\"  distributed under the License is distributed on an \"AS IS\" BASIS,\n.\\\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n.\\\"  See the License for the specific language governing permissions and\n.\\\"  limitations under the License.\n.\\\"\n.SH NAME\nperm \\- permute inputs to outputs\n.SH SYNOPSIS\n\\fBperm\\fP\n\\fIo1,o2 ...\\fP\n.SH DESCRIPTION\n\\fIperm\\fP will read data from multiple inputs, and output each input\nto the specified output.\n\\fIperm\\fP is implemented by invoking \\fIdgsh-tee\\fP with the \\fI-p\\fP option.\n.SH OPTIONS\n.IP \"\\fIo1,o2 ...\\fP\"\nPermute the inputs to the specified outputs.\nThe comma-separated arguments \\fIo1,o2, ...\\fP\nspecify the number of the output channel (starting from 1)\nwhere the corresponding \\fIn\\fPth input channel will be sent.\nThus,\ninput 1 goes to output \\fIo1\\fP,\ninput 2 goes to output \\fIo2\\fP,\nand so on.\nAs an example a cross-permutation is specified with the argument \\fI2,1\\fP.\n.SH \"SEE ALSO\"\n\\fIdgsh-tee\\fP(1)\n.SH AUTHOR\nDiomidis Spinellis \\(em <http://www.spinellis.gr>\n"
  },
  {
    "path": "core-tools/src/perm.sh",
    "content": "#!/bin/sh\n#!dgsh\n#\n# Permute inputs to outputs by invoking dgsh-tee -p\n#\n\nusage()\n{\n   echo 'Usage: perm n1,n2[, ...]'\n   exit 2\n}\n\n# Get first argument. Its syntax will be validated by dgsh-tee\ntest \"$1\" || usage\np=\"$1\"\nshift\n\n# Ensure no more arguments are provided\nfor i; do\n    usage\ndone\n\nexec dgsh-tee -p \"$p\"\n"
  },
  {
    "path": "core-tools/src/run-built-dgsh.sh",
    "content": "#!/bin/sh\n#\n# Run any dgsh script from the built (rather than the installed)\n# version of dgsh.\n# The first argument must be the directory containing the dgsh sources.\n#\n\nif [ -z \"$1\" ] ; then\n  echo \"Usage: $0 dgsh-root-path [dgsh arguments]\" 1>&2\n  exit 1\nfi\n\nTOP=\"$1\"\nshift\nDGSH=\"$TOP/build/bin/dgsh\"\nPATH=\"$TOP/build/bin:$PATH\"\nexport DGSHPATH=\"$TOP/build/libexec/dgsh\"\n\ndgsh \"$@\"\n"
  },
  {
    "path": "core-tools/tests/.gitignore",
    "content": "Makefile.orig\ncheck_negotiate\ncheck_negotiate.log\ncheck_negotiate.trs\ntest-suite.log\nunit-test-dgsh\n"
  },
  {
    "path": "core-tools/tests/Makefile.am",
    "content": "## Process this file with automake to produce Makefile.in\n\nTESTS = check_negotiate\ncheck_PROGRAMS = check_negotiate\n\ncheck_negotiate_SOURCES = check_negotiate.c ../src/negotiate.h\ncheck_negotiate_CFLAGS = @CHECK_CFLAGS@ -DUNIT_TESTING -DDEBUG\ncheck_negotiate_LDADD = ../src/libdgsh.a @CHECK_LIBS@\n\n"
  },
  {
    "path": "core-tools/tests/Makefile.patch",
    "content": "--- Makefile.original\t2016-06-20 18:17:16.661787072 +0300\n+++ Makefile\t2016-06-20 18:18:39.577783863 +0300\n@@ -686,17 +686,18 @@\n \t  done; \\\n \t  test $$st -eq 0 || exit 1; \\\n \tfi\n+\t# MFG: Hack for identifying and aggregating test results in log.\n \t@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \\\n \tws='[ \t]'; \\\n-\tresults=`for b in $$bases; do echo $$b.trs; done`; \\\n+\tresults=`for b in $$bases; do echo $$b.log; done`; \\\n \ttest -n \"$$results\" || results=/dev/null; \\\n-\tall=`  grep \"^$$ws*:test-result:\"           $$results | wc -l`; \\\n-\tpass=` grep \"^$$ws*:test-result:$$ws*PASS\"  $$results | wc -l`; \\\n-\tfail=` grep \"^$$ws*:test-result:$$ws*FAIL\"  $$results | wc -l`; \\\n-\tskip=` grep \"^$$ws*:test-result:$$ws*SKIP\"  $$results | wc -l`; \\\n-\txfail=`grep \"^$$ws*:test-result:$$ws*XFAIL\" $$results | wc -l`; \\\n-\txpass=`grep \"^$$ws*:test-result:$$ws*XPASS\" $$results | wc -l`; \\\n-\terror=`grep \"^$$ws*:test-result:$$ws*ERROR\" $$results | wc -l`; \\\n+\tall=` grep \":.\\+:.:.\\+:.\\+:.\\+: \"           $$results | wc -l`; \\\n+\tpass=` grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: Passed\"  $$results | wc -l`; \\\n+\tfail=` grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: Assertion .\\+ failed:\"  $$results | wc -l`; \\\n+\tskip=` grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: Skipped\"  $$results | wc -l`; \\\n+\txfail=`grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: XFailed\" $$results | wc -l`; \\\n+\txpass=`grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: XPassed\" $$results | wc -l`; \\\n+\terror=`grep \":.\\+:.:.\\+:.\\+:.\\+: (after this point) Received\" $$results | wc -l`; \\\n \tif test `expr $$fail + $$xpass + $$error` -eq 0; then \\\n \t  success=true; \\\n \telse \\\n"
  },
  {
    "path": "core-tools/tests/check.hack",
    "content": "\t# MFG: Hack for identifying and aggregating test results in log.\n\t# Goes in test/negotiate/tests/Makefile\n\t# Grep for 'xfail' to identify the block that the current\n\t# substitutes.\n\tresults=`for b in $$bases; do echo $$b.log; done`; \\\n\ttest -n \"$$results\" || results=/dev/null; \\\n\tall=` grep \":.\\+:.:.\\+:.\\+:.\\+: \"           $$results | wc -l`; \\\n\tpass=` grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: Passed\"  $$results | wc -l`; \\\n\tfail=` grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: Assertion .\\+ failed:\"  $$results | wc -l`; \\\n\tskip=` grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: Skipped\"  $$results | wc -l`; \\\n\txfail=`grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: XFailed\" $$results | wc -l`; \\\n\txpass=`grep \"^.\\+\\.c:.\\+:.:.\\+:.\\+:.\\+: XPassed\" $$results | wc -l`; \\\n\terror=`grep \":.\\+:.:.\\+:.\\+:.\\+: (after this point) Received\" $$results | wc -l`; \\\n"
  },
  {
    "path": "core-tools/tests/check_negotiate.c",
    "content": "#include <check.h>  /* Check unit test framework API. */\n#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */\n#include <unistd.h> /* pipe() */\n#include <fcntl.h>  /* fcntl() */\n#include <err.h>    /* err(), errx() */\n#include <time.h>   /* nanosleep() */\n#include <stdio.h> /* snprintf */\n#include <unistd.h> /* pipe */\n#include <sys/types.h>\n#include <sys/socket.h> /* socket */\n#include <sys/un.h> /* sockaddr_un */\n#include \"../src/negotiate.h\"\n#include \"../src/negotiate.c\"\t/* struct definitions, static structures */\n#include \"../src/dgsh-conc.c\"\t\t\t/* pi */\n//#include \"../src/dgsh-internal-api.h\"\t\t/* chosen_mb */\n\n\nstruct dgsh_negotiation *fresh_mb;\nstruct dgsh_edge *compact_edges;\nstruct dgsh_edge **pointers_to_edges;\nint n_ptedges;\nint *args;\n/* Depending on whether a test triggers a failure or not, a different sequence\n * of actions may be needed to exit normally.\n * exit_state is the control variable for following the correct \n * sequence of actions.\n */\nint exit_state = 0;\n\nvoid\nsetup_concs(struct dgsh_negotiation *mb)\n{\n\tmb->n_concs = 2;\n\tmb->conc_array = (struct dgsh_conc *)malloc(sizeof(struct dgsh_conc) * mb->n_concs);\n\tmb->conc_array[0].pid = 2000;\n\tmb->conc_array[0].input_fds = 2;\n\tmb->conc_array[0].output_fds = 2;\n\tmb->conc_array[0].multiple_inputs = false;\n\tmb->conc_array[0].endpoint_pid = 102;\n\tmb->conc_array[0].n_proc_pids = 2;\n\tmb->conc_array[0].proc_pids = (int *)malloc(sizeof(int) * 2);\n\tmb->conc_array[0].proc_pids[0] = 100;\n\tmb->conc_array[0].proc_pids[1] = 101;\n\n\tmb->conc_array[1].pid = 2001;\n\tmb->conc_array[1].input_fds = 3;\n\tmb->conc_array[1].output_fds = 3;\n\tmb->conc_array[1].multiple_inputs = true;\n\tmb->conc_array[1].endpoint_pid = 103;\n\tmb->conc_array[1].n_proc_pids = 2;\n\tmb->conc_array[1].proc_pids = (int *)malloc(sizeof(int) * 2);\n\tmb->conc_array[1].proc_pids[0] = 100;\n\tmb->conc_array[1].proc_pids[1] = 101;\n}\n\n\nvoid\nsetup_graph_solution(void)\n{\n\tchosen_mb->graph_solution = (struct dgsh_node_connections *)malloc(\n\t\t\tsizeof(struct dgsh_node_connections) * \n\t\t\tchosen_mb->n_nodes);\n\tstruct dgsh_node_connections *graph_solution =\n\t\tchosen_mb->graph_solution;\n\tgraph_solution[0].node_index = 0;\n\tgraph_solution[0].n_edges_incoming = 2;\n\tgraph_solution[0].edges_incoming = (struct dgsh_edge *)malloc(\n\t\tsizeof(struct dgsh_edge) * graph_solution[0].n_edges_incoming);\n\tmemcpy(&graph_solution[0].edges_incoming[0], &chosen_mb->edge_array[0],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\tmemcpy(&graph_solution[0].edges_incoming[1], &chosen_mb->edge_array[2],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\tgraph_solution[0].n_edges_outgoing = 1;\n\tgraph_solution[0].edges_outgoing = (struct dgsh_edge *)malloc(\n\t\tsizeof(struct dgsh_edge) * graph_solution[0].n_edges_outgoing);\n\tmemcpy(&graph_solution[0].edges_outgoing[0], &chosen_mb->edge_array[4],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\n\tgraph_solution[1].node_index = 1;\n\tgraph_solution[1].n_edges_incoming = 1;\n\tgraph_solution[1].edges_incoming = (struct dgsh_edge *)malloc(\n\t\tsizeof(struct dgsh_edge) * graph_solution[1].n_edges_incoming);\n\tmemcpy(&graph_solution[1].edges_incoming[0], &chosen_mb->edge_array[1],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\tgraph_solution[1].n_edges_outgoing = 2;\n\tgraph_solution[1].edges_outgoing = (struct dgsh_edge *)malloc(\n\t\tsizeof(struct dgsh_edge) * graph_solution[1].n_edges_outgoing);\n\tmemcpy(&graph_solution[1].edges_outgoing[0], &chosen_mb->edge_array[2],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\tmemcpy(&graph_solution[1].edges_outgoing[1], &chosen_mb->edge_array[3],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\n\tgraph_solution[2].node_index = 2;\n\tgraph_solution[2].n_edges_incoming = 0;\n\tgraph_solution[2].edges_incoming = NULL;\n\tgraph_solution[2].n_edges_outgoing = 2;\n\tgraph_solution[2].edges_outgoing = (struct dgsh_edge *)malloc(\n\t\tsizeof(struct dgsh_edge) * graph_solution[2].n_edges_outgoing);\n\tmemcpy(&graph_solution[2].edges_outgoing[0], &chosen_mb->edge_array[0],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\tmemcpy(&graph_solution[2].edges_outgoing[1], &chosen_mb->edge_array[1],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\n\tgraph_solution[3].node_index = 3;\n\tgraph_solution[3].n_edges_incoming = 2;\n\tgraph_solution[3].edges_incoming = (struct dgsh_edge *)malloc(\n\t\tsizeof(struct dgsh_edge) * graph_solution[3].n_edges_incoming);\n\tmemcpy(&graph_solution[0].edges_incoming[0], &chosen_mb->edge_array[3],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\tmemcpy(&graph_solution[0].edges_incoming[1], &chosen_mb->edge_array[4],\n\t\t\t\t\tsizeof(struct dgsh_edge));\n\tgraph_solution[3].n_edges_outgoing = 0;\n\tgraph_solution[3].edges_outgoing = NULL;\n\n}\n\nvoid\nsetup_chosen_mb(void)\n{\n\tstruct dgsh_node *nodes;\n\tstruct dgsh_edge *edges;\n\tint n_nodes;\n\tint n_edges;\n\tn_nodes = 4;\n        nodes = (struct dgsh_node *)malloc(sizeof(struct dgsh_node) * n_nodes);\n        nodes[0].pid = 100;\n\tnodes[0].index = 0;\n        strcpy(nodes[0].name, \"proc0\");\n        nodes[0].requires_channels = 2;\n\tnodes[0].provides_channels = 1;\n\tnodes[0].dgsh_in = 1;\n        nodes[0].dgsh_out = 1;\n\n        nodes[1].pid = 101;\n\tnodes[1].index = 1;\n        strcpy(nodes[1].name, \"proc1\");\n        nodes[1].requires_channels = 1;\n\tnodes[1].provides_channels = 2;\n\tnodes[1].dgsh_in = 1;\n        nodes[1].dgsh_out = 1;\n\n\t/* dgsh OUT and not IN = initiator node.\n         * This node could start the negotiation.\n         * Fix.\n\t */\n        nodes[2].pid = 102;\n\tnodes[2].index = 2;\n        strcpy(nodes[2].name, \"proc2\");\n        nodes[2].requires_channels = 0;\n\tnodes[2].provides_channels = 2;\n\tnodes[2].dgsh_in = 0;\n        nodes[2].dgsh_out = 1;\n\n\t/* dgsh IN and not OUT = termination node.\n         * This node couldn't start the negotiation.\n         * Fix.\n\t */\n        nodes[3].pid = 103;\n\tnodes[3].index = 3;\n        strcpy(nodes[3].name, \"proc3\");\n        nodes[3].requires_channels = 2;\n\tnodes[3].provides_channels = 0;\n\tnodes[3].dgsh_in = 1;\n        nodes[3].dgsh_out = 0;\n\n        n_edges = 5;\n        edges = (struct dgsh_edge *)malloc(sizeof(struct dgsh_edge) *n_edges);\n        edges[0].from = 2;\n        edges[0].to = 0;\n        edges[0].instances = 0;\n        edges[0].from_instances = 0;\n        edges[0].to_instances = 0;\n\n        edges[1].from = 2;\n        edges[1].to = 1;\n        edges[1].instances = 0;\n        edges[1].from_instances = 0;\n        edges[1].to_instances = 0;\n\n        edges[2].from = 1;\n        edges[2].to = 0;\n        edges[2].instances = 0;\n        edges[2].from_instances = 0;\n        edges[2].to_instances = 0;\n\n        edges[3].from = 1;\n        edges[3].to = 3;\n        edges[3].instances = 0;\n        edges[3].from_instances = 0;\n        edges[3].to_instances = 0;\n\n        edges[4].from = 0;\n        edges[4].to = 3;\n        edges[4].instances = 0;\n        edges[4].from_instances = 0;\n        edges[4].to_instances = 0;\n\n        double dgsh_version = 0.1;\n        chosen_mb = (struct dgsh_negotiation *)malloc(sizeof(struct dgsh_negotiation));\n        chosen_mb->version = dgsh_version;\n        chosen_mb->node_array = nodes;\n        chosen_mb->n_nodes = n_nodes;\n        chosen_mb->edge_array = edges;\n        chosen_mb->n_edges = n_edges;\n\tchosen_mb->graph_solution = NULL;\n\n\t/* check_negotiation_round() */\n\tchosen_mb->state = PS_NEGOTIATION;\n\tchosen_mb->initiator_pid = 103; /* Node 3 */\n\tchosen_mb->origin_fd_direction = STDOUT_FILENO;\n\tchosen_mb->n_concs = 0;\n\tchosen_mb->conc_array = NULL;\n}\n\n/* Identical to chosen_mb except for the initiator field. */\nvoid\nsetup_mb(struct dgsh_negotiation **mb)\n{\n\tstruct dgsh_node *nodes;\n\tstruct dgsh_edge *edges;\n\tint n_nodes;\n\tint n_edges;\n\tn_nodes = 4;\n        nodes = (struct dgsh_node *)malloc(sizeof(struct dgsh_node) * n_nodes);\n        nodes[0].pid = 100;\n\tnodes[0].index = 0;\n        strcpy(nodes[0].name, \"proc0\");\n        nodes[0].requires_channels = 2;\n\tnodes[0].provides_channels = 1;\n\tnodes[0].dgsh_in = 1;\n        nodes[0].dgsh_out = 1;\n\n        nodes[1].pid = 101;\n\tnodes[1].index = 1;\n        strcpy(nodes[1].name, \"proc1\");\n        nodes[1].requires_channels = 1;\n\tnodes[1].provides_channels = 2;\n\tnodes[1].dgsh_in = 1;\n        nodes[1].dgsh_out = 1;\n\n        nodes[2].pid = 102;\n\tnodes[2].index = 2;\n        strcpy(nodes[2].name, \"proc2\");\n        nodes[2].requires_channels = 0;\n\tnodes[2].provides_channels = 2;\n\tnodes[2].dgsh_in = 0;\n        nodes[2].dgsh_out = 1;\n\n        nodes[3].pid = 103;\n\tnodes[3].index = 3;\n        strcpy(nodes[3].name, \"proc3\");\n        nodes[3].requires_channels = 2;\n\tnodes[3].provides_channels = 0;\n\tnodes[3].dgsh_in = 1;\n        nodes[3].dgsh_out = 0;\n\n        n_edges = 5;\n        edges = (struct dgsh_edge *)malloc(sizeof(struct dgsh_edge) *n_edges);\n        edges[0].from = 2;\n        edges[0].to = 0;\n        edges[0].instances = 0;\n        edges[0].from_instances = 0;\n        edges[0].to_instances = 0;\n\n        edges[1].from = 2;\n        edges[1].to = 1;\n        edges[1].instances = 0;\n        edges[1].from_instances = 0;\n        edges[1].to_instances = 0;\n\n        edges[2].from = 1;\n        edges[2].to = 0;\n        edges[2].instances = 0;\n        edges[2].from_instances = 0;\n        edges[2].to_instances = 0;\n\n        edges[3].from = 1;\n        edges[3].to = 3;\n        edges[3].instances = 0;\n        edges[3].from_instances = 0;\n        edges[3].to_instances = 0;\n\n        edges[4].from = 0;\n        edges[4].to = 3;\n        edges[4].instances = 0;\n        edges[4].from_instances = 0;\n        edges[4].to_instances = 0;\n\n        double dgsh_version = 0.1;\n        struct dgsh_negotiation *temp_mb = (struct dgsh_negotiation *)malloc(sizeof(struct dgsh_negotiation));\n        temp_mb->version = dgsh_version;\n        temp_mb->node_array = nodes;\n        temp_mb->n_nodes = n_nodes;\n        temp_mb->edge_array = edges;\n        temp_mb->n_edges = n_edges;\n\ttemp_mb->graph_solution = NULL;\n\n\t/* check_negotiation_round() */\n\ttemp_mb->state = PS_NEGOTIATION;\n\ttemp_mb->initiator_pid = 102; /* Node 2 */\n\ttemp_mb->origin_index = 2;\n\ttemp_mb->origin_fd_direction = STDOUT_FILENO;\n\ttemp_mb->n_concs = 0;\n\ttemp_mb->conc_array = NULL;\n\n\t*mb = temp_mb;\n}\n\nvoid\nsetup_pointers_to_edges(void)\n{\n        n_ptedges = 2;\n\tpointers_to_edges = (struct dgsh_edge **)malloc(sizeof(struct dgsh_edge *) *n_ptedges);\n\tint i;\n\tfor (i = 0; i < n_ptedges; i++) {\n\t\tpointers_to_edges[i] = (struct dgsh_edge *)malloc(sizeof(struct dgsh_edge));\t\n\t\tpointers_to_edges[i]->from = i;\n\t\tpointers_to_edges[i]->to = 3; // the node.\n\t\tpointers_to_edges[i]->instances = 0;\n\t\tpointers_to_edges[i]->from_instances = 0;\n\t\tpointers_to_edges[i]->to_instances = 0;\n        }\n}\n\nvoid\nsetup_self_node(void)\n{\n\t/* fill in self_node */\n\tmemcpy(&self_node, &chosen_mb->node_array[3], sizeof(struct dgsh_node));\n}\n\nvoid\nsetup_self_node_io_side(void)\n{\n\tself_node_io_side.index = 3;\n\tself_node_io_side.fd_direction = 0;\n}\n\n/* establish_io_connections() */\nvoid\nsetup_pipe_fds(void)\n{\n\t/* fill in self_pipe_fds */\n\tself_pipe_fds.n_input_fds = 2;\n\tself_pipe_fds.input_fds = (int *)malloc(sizeof(int) *\n\t\t\t\t\t\tself_pipe_fds.n_input_fds);\n\tself_pipe_fds.input_fds[0] = 3;\n\tself_pipe_fds.input_fds[1] = 4;\n\tself_pipe_fds.n_output_fds = 0;\n}\n\n\nvoid setup_args(void)\n{\n        args = (int *)malloc(sizeof(int) * 3);\n        args[0] = -1;\n        args[1] = -1;\n        args[2] = -1;\n}\n\nvoid\nsetup(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node();\n\tsetup_self_node_io_side();\n\tsetup_pipe_fds();\n\tsetup_graph_solution();\n}\n\nvoid\nsetup_test_set_fds(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node();\n}\n\nvoid\nsetup_test_add_node(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node();\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_lookup_dgsh_edge(void)\n{\n\tsetup_chosen_mb();\n}\n\nvoid\nsetup_test_fill_dgsh_edge(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node();\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_add_edge(void)\n{\n\tsetup_chosen_mb();\n}\n\nvoid\nsetup_test_try_add_dgsh_edge(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node();\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_try_add_dgsh_node(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node();\n}\n\nvoid\nsetup_test_fill_node(void)\n{\n\t/* setup_self_node() requires setup_chosen_mb() */\n\tsetup_chosen_mb();\n\tsetup_self_node();\n}\n\nvoid\nsetup_test_free_mb(void)\n{\n\tsetup_chosen_mb();\n}\n\nvoid\nsetup_test_analyse_read(void)\n{\n\tsetup_chosen_mb();\n\tsetup_mb(&fresh_mb);\n\tsetup_self_node();\n\tsetup_self_node_io_side();\n}\n\n/*void\nsetup_test_point_io_direction(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node();\n\tsetup_self_node_io_side();\n}*/\n\nvoid\nsetup_test_alloc_copy_graph_solution(void)\n{\n\tsetup_mb(&fresh_mb);\n}\n\nvoid\nsetup_test_alloc_copy_concs(void)\n{\n\tsetup_mb(&fresh_mb);\n}\n\nvoid\nsetup_test_alloc_copy_edges(void)\n{\n\tsetup_mb(&fresh_mb);\n}\n\nvoid\nsetup_test_alloc_copy_nodes(void)\n{\n\tsetup_mb(&fresh_mb);\n}\n\nvoid\nsetup_test_read_chunk(void)\n{\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_alloc_io_fds(void)\n{\n\tsetup_chosen_mb();\n\tsetup_graph_solution();\n\tsetup_self_node();\n}\n\nvoid\nsetup_test_get_provided_fds_n(void)\n{\n\tsetup_chosen_mb();\n\tsetup_graph_solution();\n}\n\nvoid\nsetup_test_get_expected_fds_n(void)\n{\n\tsetup_chosen_mb();\n\tsetup_graph_solution();\n}\n\nvoid\nsetup_test_get_origin_pid(void)\n{\n\tsetup_chosen_mb();\n}\n\nvoid\nsetup_test_read_input_fds(void)\n{\n\tsetup_chosen_mb();\n\tsetup_graph_solution();\n\tsetup_self_node();\n}\n\nvoid\nsetup_test_read_graph_solution(void)\n{\n\tsetup_mb(&fresh_mb);\n\tsetup_chosen_mb();\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_read_concs(void)\n{\n\tsetup_mb(&fresh_mb);\n\tsetup_chosen_mb();\n\tsetup_concs(chosen_mb);\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_write_graph_solution(void)\n{\n\tsetup_chosen_mb();\n\tsetup_graph_solution();\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_write_concs(void)\n{\n\tsetup_chosen_mb();\n\tsetup_concs(chosen_mb);\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_read_message_block(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_write_message_block(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_make_compact_edge_array(void)\n{\n\tsetup_pointers_to_edges();\n}\n\nvoid\nsetup_test_reallocate_edge_pointer_array(void)\n{\n\tsetup_pointers_to_edges();\n}\n\n/*void\nsetup_test_assign_edge_instances(void)\n{\n\tsetup_chosen_mb();\n\tsetup_pointers_to_edges();\n}\n\nvoid\nsetup_test_eval_constraints(void)\n{\n\tsetup_args();\n}\n*/\n\nvoid\nsetup_test_move(void)\n{\n\tsetup_pointers_to_edges();\n}\n\nvoid\nsetup_test_satisfy_io_constraints(void)\n{\n\tsetup_chosen_mb();\n\tsetup_pointers_to_edges();\n\tsetup_args();\n}\n\nvoid\nsetup_test_dry_match_io_constraints(void)\n{\n\tsetup_chosen_mb();\n\tsetup_graph_solution();\n\tsetup_pointers_to_edges();\n\tsetup_args();\n}\n\nvoid\nsetup_test_node_match_constraints(void)\n{\n\tsetup_chosen_mb();\n}\n\nvoid\nsetup_test_free_graph_solution(void)\n{\n\tsetup_chosen_mb();\n\tsetup_graph_solution();\n}\n\nvoid\nsetup_test_solve_graph(void)\n{\n\tsetup_chosen_mb();\n\tsetup_graph_solution();\n\tsetup_pointers_to_edges();\n\tsetup_args();\n}\n\nvoid\nsetup_test_calculate_conc_fds(void)\n{\n\tsetup_chosen_mb();\n\tsetup_graph_solution();\n\tsetup_concs(chosen_mb);\n}\n\nvoid\nsetup_test_write_output_fds(void)\n{\n\tsetup_chosen_mb(); /* For setting up graph_solution. */\n\tsetup_graph_solution();\n\tsetup_self_node();\n}\n\nvoid\nsetup_test_set_dispatcher(void)\n{\n\tsetup_chosen_mb();\n\tsetup_self_node_io_side();\n}\n\nvoid\nsetup_test_establish_io_connections(void)\n{\n\tsetup_pipe_fds();\n\tsetup_chosen_mb();\n\tsetup_self_node();\n}\n\nvoid setup_pi(void)\n{\n\tpi = (struct portinfo *)calloc(5, sizeof(struct portinfo));\n\tpi[0].pid = 101;\n\tpi[0].seen = false;\n\tpi[0].written = true;\n\tpi[1].pid = 100;\n\tpi[1].seen = true;\n\tpi[1].written = false;\n\tpi[3].pid = 103;\n\tpi[3].seen = true;\n\tpi[3].written = true;\n}\n\nvoid\nsetup_test_is_ready(void)\n{\n\tsetup_pi();\n\tsetup_chosen_mb();\n}\n\nvoid\nsetup_test_set_io_channels(void)\n{\n\tsetup_pi();\n\tsetup_chosen_mb();\n}\n\nvoid\nretire_pointers_to_edges(void)\n{\n\tint i;\n\tfor (i = 0; i < n_ptedges; i++)\n\t\tfree(pointers_to_edges[i]);\n\tfree(pointers_to_edges);\n}\n\nvoid\nretire_graph_solution(struct dgsh_node_connections *graph_solution,\n\t\t\t\t\t\t\t\tint node_index)\n{\n\tint i;\n        for (i = 0; i <= node_index; i++) {\n\t\tif (graph_solution[i].n_edges_incoming)\n                \tfree(graph_solution[i].edges_incoming);\n\t\tif (graph_solution[i].n_edges_outgoing)\n                \tfree(graph_solution[i].edges_outgoing);\n        }\n        free(graph_solution);\n}\n\nvoid retire_concs(struct dgsh_negotiation *mb)\n{\n\tint i;\n\tfor (i = 0; i < mb->n_concs; i++)\n\t\tfree(mb->conc_array[i].proc_pids);\n\tfree(mb->conc_array);\n}\n\nvoid\nretire_chosen_mb(void)\n{\n        free(chosen_mb->node_array);\n        free(chosen_mb->edge_array);\n        free(chosen_mb);\n}\n\nvoid\nretire_mb(struct dgsh_negotiation *mb)\n{\n        free(mb->node_array);\n        free(mb->edge_array);\n        free(mb);\n}\n\n/* establish_io_connections() */\nvoid\nretire_pipe_fds(void)\n{\n\tif (self_pipe_fds.n_input_fds > 0)\n\t\tfree(self_pipe_fds.input_fds);\n\tif (self_pipe_fds.n_output_fds > 0)\n\t\tfree(self_pipe_fds.output_fds);\n\t/* What about self_pipe_fds.input_fds? */\n}\n\nvoid\nretire_args(void)\n{\n\tfree(args);\n}\n\nvoid\nretire(void)\n{\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\tretire_chosen_mb();\n\tretire_pipe_fds();\n}\n\nvoid\nretire_test_set_fds(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_construct_message_block(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_add_node(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_lookup_dgsh_edge(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_fill_dgsh_edge(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_add_edge(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_try_add_dgsh_edge(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_try_add_dgsh_node(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_analyse_read(void)\n{\n\tif (exit_state == 1) {\n\t\tretire_mb(fresh_mb);\n\t\texit_state = 0;\n\t} else retire_chosen_mb();\n}\n\n/*void\nretire_test_point_io_direction(void)\n{\n\tretire_chosen_mb();\n}*/\n\nvoid\nretire_test_alloc_copy_graph_solution(void)\n{\n\tretire_mb(fresh_mb);\n}\n\nvoid\nretire_test_alloc_copy_concs(void)\n{\n\tretire_mb(fresh_mb);\n}\n\nvoid\nretire_test_alloc_copy_edges(void)\n{\n\tretire_mb(fresh_mb);\n}\n\nvoid\nretire_test_alloc_copy_nodes(void)\n{\n\tretire_mb(fresh_mb);\n}\n\nvoid\nretire_test_alloc_io_fds(void)\n{\n\tretire_pipe_fds();\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_get_provided_fds_n(void)\n{\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_get_expected_fds_n(void)\n{\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_read_input_fds(void)\n{\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_get_origin_pid(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_read_message_block(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_write_message_block(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_read_graph_solution(void)\n{\n\tretire_chosen_mb();\n\tretire_mb(fresh_mb);\n}\n\nvoid\nretire_test_read_concs(void)\n{\n\tretire_concs(chosen_mb);\n\tretire_chosen_mb();\n\tretire_mb(fresh_mb);\n}\n\nvoid\nretire_test_write_graph_solution(void)\n{\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_write_concs(void)\n{\n\tretire_concs(chosen_mb);\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_make_compact_edge_array(void)\n{\n\tfree(compact_edges);\n\tretire_pointers_to_edges();\n}\n\nvoid\nretire_test_reallocate_edge_pointer_array(void)\n{\n\tretire_pointers_to_edges();\n}\n\n/*void\nretire_test_assign_edge_instances(void)\n{\n\tretire_chosen_mb();\n\tretire_pointers_to_edges();\n}\n\nvoid\nretire_test_eval_constraints(void)\n{\n        retire_args();\n}\n*/\n\nvoid\nretire_test_move(void)\n{\n\tretire_pointers_to_edges();\n}\n\nvoid\nretire_test_satisfy_io_constraints(void)\n{\n\tretire_chosen_mb();\n\tretire_pointers_to_edges();\n\tretire_args();\n}\n\nvoid\nretire_test_dry_match_io_constraints(void)\n{\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\tretire_chosen_mb();\n\tretire_pointers_to_edges();\n\tretire_args();\n}\n\nvoid\nretire_test_node_match_constraints(void)\n{\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_free_graph_solution(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_solve_graph(void)\n{\n\t/* Are the other data structures handled correctly?\n\t * They could be deallocated above our feet.\n\t */\n\tif (!exit_state) \n\t\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\telse exit_state = 0;\n\tretire_chosen_mb();\n\tretire_pointers_to_edges();\n\tretire_args();\n}\n\nvoid\nretire_test_calculate_conc_fds(void)\n{\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n\tretire_concs(chosen_mb);\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_write_output_fds(void)\n{\n\tretire_graph_solution(chosen_mb->graph_solution,\n\t\t\tchosen_mb->n_nodes - 1);\n}\n\nvoid\nretire_test_set_dispatcher(void)\n{\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_establish_io_connections(void)\n{\n\t/* See setup_test_establish_io_connections() */\n\tretire_chosen_mb();\n\tretire_pipe_fds();\n}\n\nvoid\nretire_pi(void)\n{\n\tfree(pi);\n}\n\nvoid\nretire_test_is_ready(void)\n{\n\tretire_pi();\n\tretire_chosen_mb();\n}\n\nvoid\nretire_test_set_io_channels(void)\n{\n\tretire_concs(chosen_mb);\n\tretire_chosen_mb();\n\tretire_pi();\n}\n\nSTART_TEST(test_solve_graph)\n{\n\tDPRINTF(4, \"%s\", __func__);\n        /* A normal case with fixed, tight constraints. */\n\tck_assert_int_eq(solve_graph(), OP_SUCCESS);\n\tstruct dgsh_node_connections *graph_solution =\n\t\tchosen_mb->graph_solution;\n\tck_assert_int_eq(graph_solution[3].n_edges_incoming, 2);\n\tck_assert_int_eq(graph_solution[3].n_edges_outgoing, 0);\n\tck_assert_int_eq(chosen_mb->edge_array[3].instances, 1);\n\tck_assert_int_eq(chosen_mb->edge_array[4].instances, 1);\n\tck_assert_int_eq(graph_solution[3].edges_incoming[0].instances, 1);\n\tck_assert_int_eq(graph_solution[0].edges_outgoing[0].instances, 1);\n\tck_assert_int_eq(graph_solution[3].edges_incoming[1].instances, 1);\n\tck_assert_int_eq(graph_solution[1].edges_outgoing[1].instances, 1);\n\tck_assert_int_eq((long int)graph_solution[3].edges_outgoing, 0);\n\tretire_test_solve_graph();\n\n\t/* An impossible case. */\n\tsetup_test_solve_graph();\n\tchosen_mb->node_array[3].requires_channels = 1;\n\tck_assert_int_eq(solve_graph(), OP_ERROR);\n\texit_state = 1;\n\tretire_test_solve_graph();\n\n\t/* Relaxing our target node's constraint. */\n\tsetup_test_solve_graph();\n\tchosen_mb->node_array[3].requires_channels = -1;\n\tck_assert_int_eq(solve_graph(), OP_SUCCESS);\n\tgraph_solution = chosen_mb->graph_solution;\n\tck_assert_int_eq(graph_solution[3].n_edges_incoming, 2);\n\tck_assert_int_eq(graph_solution[3].n_edges_outgoing, 0);\n\t/* Pair edges still have tight constraints. */\n\tck_assert_int_eq(chosen_mb->edge_array[3].instances, 1);\n\tck_assert_int_eq(chosen_mb->edge_array[4].instances, 1);\n\tck_assert_int_eq(graph_solution[3].edges_incoming[0].instances, 1);\n\tck_assert_int_eq(graph_solution[0].edges_outgoing[0].instances, 1);\n\tck_assert_int_eq(graph_solution[3].edges_incoming[1].instances, 1);\n\tck_assert_int_eq(graph_solution[1].edges_outgoing[1].instances, 1);\n\tck_assert_int_eq((long int)graph_solution[3].edges_outgoing, 0);\n\tretire_test_solve_graph();\n\n\t/* Relaxing also pair nodes' constraints. */\n\tsetup_test_solve_graph();\n\tchosen_mb->node_array[3].requires_channels = -1;\n\tchosen_mb->node_array[0].provides_channels = -1;\n\tchosen_mb->node_array[1].provides_channels = -1;\n\tck_assert_int_eq(solve_graph(), OP_SUCCESS);\n\tgraph_solution = chosen_mb->graph_solution;\n\tck_assert_int_eq(graph_solution[3].n_edges_incoming, 2);\n\tck_assert_int_eq(graph_solution[3].n_edges_outgoing, 0);\n\t/* Flexible both sides: instances previously set to 5 */\n\tck_assert_int_eq(chosen_mb->edge_array[3].instances, 1);\n\tck_assert_int_eq(chosen_mb->edge_array[4].instances, 1);\n\tck_assert_int_eq(graph_solution[3].edges_incoming[0].instances, 1);\n\tck_assert_int_eq(graph_solution[0].edges_outgoing[0].instances, 1);\n\tck_assert_int_eq(graph_solution[3].edges_incoming[1].instances, 1);\n\tck_assert_int_eq(graph_solution[1].edges_outgoing[1].instances, 1);\n\tck_assert_int_eq((long int)graph_solution[3].edges_outgoing, 0);\n\t/* Collateral impact. Node 1 (flex) -> Node 0 (tight) */\n\tck_assert_int_eq(chosen_mb->edge_array[2].instances, 1);\n\tck_assert_int_eq(graph_solution[1].edges_outgoing[0].instances, 1);\n}\nEND_TEST\n\nSTART_TEST(test_calculate_conc_fds)\n{\n\tDPRINTF(4, \"%s()\", __func__);\n\tchosen_mb->conc_array[0].input_fds = -1;\n\tchosen_mb->conc_array[0].output_fds = -1;\n\tchosen_mb->conc_array[1].input_fds = -1;\n\tchosen_mb->conc_array[1].output_fds = -1;\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\tchosen_mb->graph_solution;\n\tgraph_solution[0].edges_incoming[0].instances = 1;\n\tgraph_solution[0].edges_outgoing[0].instances = 1;\n\tgraph_solution[1].edges_incoming[0].instances = 1;\n\tgraph_solution[1].edges_outgoing[0].instances = 1;\n\t/* endpoint for conc with pid 2001*/\n\tgraph_solution[3].edges_incoming[0].instances = 1;\n\tgraph_solution[3].edges_incoming[1].instances = 1;\n\t/* endpoint for conc with pid 2000*/\n\tgraph_solution[2].edges_outgoing[0].instances = 1;\n\tgraph_solution[2].edges_outgoing[1].instances = 1;\n\n\tck_assert_int_eq(calculate_conc_fds(), OP_SUCCESS);\n}\nEND_TEST\n\nSTART_TEST(test_free_graph_solution)\n{\n\tck_assert_int_eq(free_graph_solution(3), OP_SUCCESS);\n\t/* Invalid node indexes, the function's argument, are checked by assertion. */\n}\nEND_TEST\n\n\nSTART_TEST(test_establish_io_connections)\n{\n\t/* Should be in the solution propagation test suite. */\n\t/* The test case contains an arrangement of 0 fds and another of >0 fds. */\n\tint *input_fds = NULL;\n\tint n_input_fds = 2; \n\tint *output_fds = NULL;\n\tint n_output_fds = 0;\n\tint fd[2];\n\n\tif (pipe(fd) == -1) {\t\t/* fd pair: 4 -- 5 */\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\tself_pipe_fds.input_fds[0] = fd[0];\n\tDPRINTF(4, \"%s: Opened pipe pair: input_fds[0]: %d, output: %d\",\n\t\t\t__func__, fd[0], fd[1]);\n\n\tck_assert_int_eq(establish_io_connections(NULL, NULL, NULL, NULL),\n\t\t\tOP_SUCCESS);\n\t/* Freed */\n\tck_assert_int_eq(self_pipe_fds.n_input_fds, 0);\n\tck_assert_int_eq(self_pipe_fds.n_output_fds, 0);\n\tclose(fd[1]);\n\tretire_test_establish_io_connections();\n\n\tsetup_test_establish_io_connections();\n\tif (pipe(fd) == -1) {\t\t/* fd pair: 4 -- 5 */\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\tself_pipe_fds.input_fds[0] = fd[0];\n\tDPRINTF(4, \"%s: Opened pipe pair: input_fds[0]: %d, output: %d\",\n\t\t\t__func__, fd[0], fd[1]);\n\tself_pipe_fds.input_fds[1] = 6;\n\tck_assert_int_eq(establish_io_connections(&input_fds, &n_input_fds,\n\t\t\t\t\t&output_fds, &n_output_fds), OP_SUCCESS);\n\tck_assert_int_eq(n_input_fds, 2);\n\tck_assert_int_eq(input_fds[0], 0);\n\tck_assert_int_eq(input_fds[1], 6);\n\tck_assert_int_eq(n_output_fds, 0);\n\tclose(fd[1]);\n}\nEND_TEST\n\nstruct dgsh_edge **edges_in;\nint n_edges_in;\nstruct dgsh_edge **edges_out;\nint n_edges_out;\n\nvoid\nretire_dmic(void)\n{\n\tretire();\n\tif (n_edges_in)\n\t\tfree(edges_in);\n\tif (n_edges_out)\n\t\tfree(edges_out);\n}\n\nSTART_TEST(test_node_match_constraints)\n{\n\tDPRINTF(4, \"%s()\\n\", __func__);\n\n\t/* Default topology; take a look at setup_chosen_mb() */\n\tchosen_mb->node_array[3].requires_channels = 2;\n\tck_assert_int_eq(node_match_constraints(), OP_SUCCESS);\n\tstruct dgsh_node_connections *graph_solution =\n\t\tchosen_mb->graph_solution;\n\tck_assert_int_eq(graph_solution[0].node_index, 0);\n\tck_assert_int_eq(graph_solution[0].n_edges_incoming, 2);\n\tck_assert_int_eq(graph_solution[0].n_instances_incoming_free, 0);\n\tck_assert_int_eq(graph_solution[0].n_edges_outgoing, 1);\n\tck_assert_int_eq(graph_solution[0].n_instances_outgoing_free, 0);\n\n\tck_assert_int_eq(graph_solution[1].node_index, 1);\n\tck_assert_int_eq(graph_solution[1].n_edges_incoming, 1);\n\tck_assert_int_eq(graph_solution[1].n_instances_incoming_free, 0);\n\tck_assert_int_eq(graph_solution[1].n_edges_outgoing, 2);\n\tck_assert_int_eq(graph_solution[1].n_instances_outgoing_free, 0);\n\n\tck_assert_int_eq(graph_solution[2].node_index, 2);\n\tck_assert_int_eq(graph_solution[2].n_edges_incoming, 0);\n\tck_assert_int_eq(graph_solution[2].n_instances_incoming_free, 0);\n\tck_assert_int_eq(graph_solution[2].n_edges_outgoing, 2);\n\tck_assert_int_eq(graph_solution[2].n_instances_outgoing_free, 0);\n\n\tck_assert_int_eq(graph_solution[3].node_index, 3);\n\tck_assert_int_eq(graph_solution[3].n_edges_incoming, 2);\n\tck_assert_int_eq(graph_solution[3].n_instances_incoming_free, 0);\n\tck_assert_int_eq(graph_solution[3].n_edges_outgoing, 0);\n\tck_assert_int_eq(graph_solution[3].n_instances_outgoing_free, 0);\n}\nEND_TEST\n\t\nSTART_TEST(test_dry_match_io_constraints)\n{\n\tDPRINTF(4, \"%s\", __func__);\n\n\tstruct dgsh_node_connections *graph_solution =\n\t\tchosen_mb->graph_solution;\n        /* A normal case with fixed, tight constraints. */\n\tstruct dgsh_node_connections *current_connections = &graph_solution[3];\n\tcurrent_connections->n_edges_incoming = 0;\n\tcurrent_connections->n_edges_outgoing = 0;\n\tck_assert_int_eq(dry_match_io_constraints(&chosen_mb->node_array[3],\n\t\tcurrent_connections, &edges_in, &edges_out), OP_SUCCESS);\n        /* Hard coded. Observe the topology of the prototype solution in setup(). */\n\tck_assert_int_eq(current_connections->n_edges_incoming, 2);\n\tck_assert_int_eq(current_connections->n_edges_outgoing, 0);\n\n\t/* A case not matching at first sight; match result will\n\t * be decided in cross_match_constraints() */\n\tcurrent_connections->n_edges_incoming = 0;\n\tcurrent_connections->n_edges_outgoing = 0;\n\tchosen_mb->node_array[3].requires_channels = 3;\n\tck_assert_int_eq(dry_match_io_constraints(&chosen_mb->node_array[3],\n\t\t\t\tcurrent_connections,\n\t\t\t&edges_in, &edges_out), OP_SUCCESS);\n\tck_assert_int_eq(current_connections->n_edges_incoming, 2);\n\tck_assert_int_eq(current_connections->n_edges_outgoing, 0);\n\n\t/* Relaxing our target node's constraint. */\n\tcurrent_connections->n_edges_incoming = 0;\n\tcurrent_connections->n_edges_outgoing = 0;\n\tchosen_mb->node_array[3].requires_channels = -1;\n\tck_assert_int_eq(dry_match_io_constraints(&chosen_mb->node_array[3],\n\t\t\t\tcurrent_connections,\n\t\t\t&edges_in, &edges_out), OP_SUCCESS);\n\tck_assert_int_eq(current_connections->n_edges_incoming, 2);\n\tck_assert_int_eq(current_connections->n_edges_outgoing, 0);\n\tck_assert_int_eq(chosen_mb->edge_array[3].to_instances, -1);\n\tck_assert_int_eq(chosen_mb->edge_array[4].to_instances, -1);\n\n}\nEND_TEST\n\nSTART_TEST(test_satisfy_io_constraints)\n{\n        /* To be concise, when changing the second argument that mirrors\n         * the channel constraint of the node under evaluation, we should\n         * also change it in the node array, but it does not matter since it\n         * is the pair nodes that we are interested in.\n         */\n\tint free_instances = 0;\n        /* Fixed constraint both sides, just satisfy. */\n\tck_assert_int_eq(satisfy_io_constraints(&free_instances, \n\t\t\t\t2, pointers_to_edges, 2, true), OP_SUCCESS);\n\tck_assert_int_eq(free_instances, 0);\n        /* Fixed constraint both sides, not matching at\n\t * first sight, but will leave it to cross_match_constraints()\n\t * to decide */\n\tck_assert_int_eq(satisfy_io_constraints(&free_instances,\n\t\t\t\t1, pointers_to_edges, 2, true), OP_SUCCESS);\n\tck_assert_int_eq(free_instances, 0);\n        /* Fixed constraint bith sides, plenty. */\n\tck_assert_int_eq(satisfy_io_constraints(&free_instances,\n\t\t\t\t5, pointers_to_edges, 2, true), OP_SUCCESS);\n\tck_assert_int_eq(free_instances, 0);\n        /* Fixed constraint node, flexible pair, just one. */\n        chosen_mb->node_array[0].provides_channels = -1;\n\tck_assert_int_eq(satisfy_io_constraints(&free_instances,\n\t\t\t\t2, pointers_to_edges, 2, true), OP_SUCCESS);\n\tck_assert_int_eq(free_instances, 0);\n        /* Fixed constraint node, flexible pair,\n\t * cross_match_constraints() will decide */\n        chosen_mb->node_array[0].provides_channels = -1;\n\tck_assert_int_eq(satisfy_io_constraints(&free_instances,\n\t\t\t\t1, pointers_to_edges, 2, true), OP_SUCCESS);\n\tck_assert_int_eq(free_instances, 0);\n\tretire_test_satisfy_io_constraints();\n\n        /* Expand the semantics of remaining_free_channels to fixed constraints\n           as in this case. */  \n        /* Fixed constraint node, flexible pair, plenty. */\n\tsetup_test_satisfy_io_constraints();\n        chosen_mb->node_array[0].provides_channels = -1;\n\tck_assert_int_eq(satisfy_io_constraints(&free_instances,\n\t\t\t\t5, pointers_to_edges, 2, true), OP_SUCCESS);\n\tck_assert_int_eq(free_instances, 0);\n\tfree_instances = 0;\n\tretire_test_satisfy_io_constraints();\n\n        /* Flexible constraint both sides */\n\tsetup_test_satisfy_io_constraints();\n        chosen_mb->node_array[0].provides_channels = -1;\n\tck_assert_int_eq(satisfy_io_constraints(&free_instances,\n\t\t\t\t-1, pointers_to_edges, 2, 1), OP_SUCCESS);\n\tck_assert_int_eq(free_instances, -1);\n\tfree_instances = 0;\n}\nEND_TEST\n\nSTART_TEST(test_move)\n{\n\tint diff = 1;\n\tbool is_edge_incoming = true;\n\tDPRINTF(4, \"%s()\", __func__);\n\tpointers_to_edges[0]->from_instances = 1;\n\tpointers_to_edges[0]->to_instances = 2;\n\tpointers_to_edges[1]->from_instances = 2;\n\tpointers_to_edges[1]->to_instances = 1;\n\tck_assert_int_eq(move(pointers_to_edges, n_ptedges, diff, is_edge_incoming),\n\t\t\tOP_SUCCESS);\n\tck_assert_int_eq(pointers_to_edges[0]->from_instances, 1);\n\tck_assert_int_eq(pointers_to_edges[0]->to_instances, 2);\n\tck_assert_int_eq(pointers_to_edges[1]->from_instances, 2);\n\tck_assert_int_eq(pointers_to_edges[1]->to_instances, 2);\n}\nEND_TEST\n\nSTART_TEST(test_record_move_flexible)\n{\n\t/* Successful increase move */\n\tint diff = 1;\n\tint index = -1;\n\tint to_move_index = 2;\n\tint instances = 0;\n\tint to_move = 2;\n\trecord_move_flexible(&diff, &index, to_move_index,\n\t\t\t&instances, to_move);\n\tck_assert_int_eq(diff, 0);\n\tck_assert_int_eq(index, to_move_index);\n\tck_assert_int_eq(instances, 1);\n\n\t/* Can't subtract instances from size 1 */\n\tdiff = -1;\n\tindex = -1;\n\tto_move_index = 2;\n\tinstances = 0;\n\tto_move = 1;\n\trecord_move_flexible(&diff, &index, to_move_index,\n\t\t\t&instances, to_move);\n\tck_assert_int_eq(diff, -1);\n\tck_assert_int_eq(index, -1);\n\tck_assert_int_eq(instances, 0);\n\n\t/* Successful decrease. diff greater than to_move */\n\tdiff = -3;\n\tindex = -1;\n\tto_move_index = 2;\n\tinstances = 0;\n\tto_move = 2;\n\trecord_move_flexible(&diff, &index, to_move_index,\n\t\t\t&instances, to_move);\n\tck_assert_int_eq(diff, -2);\n\tck_assert_int_eq(index, to_move_index);\n\tck_assert_int_eq(instances, -1);\n\n\t/* Successful decrease. diff smaller than to_move */\n\tdiff = -2;\n\tindex = -1;\n\tto_move_index = 2;\n\tinstances = 0;\n\tto_move = 4;\n\trecord_move_flexible(&diff, &index, to_move_index,\n\t\t\t&instances, to_move);\n\tck_assert_int_eq(diff, 0);\n\tck_assert_int_eq(index, to_move_index);\n\tck_assert_int_eq(instances, -2);\n\n}\nEND_TEST\n\nSTART_TEST(test_record_move_unbalanced)\n{\n\t/* Successful increase move */\n\tint diff = 1;\n\tint index = -1;\n\tint to_move_index = 2;\n\tint instances = 0;\n\tint to_move = 2;\n\tint pair = 3;\n\trecord_move_unbalanced(&diff, &index, to_move_index,\n\t\t\t&instances, to_move, pair);\n\tck_assert_int_eq(diff, 0);\n\tck_assert_int_eq(index, to_move_index);\n\tck_assert_int_eq(instances, 1);\n\n\t/* Successful decrease. diff greater than to_move - pair */\n\tdiff = -3;\n\tindex = -1;\n\tto_move_index = 2;\n\tinstances = 0;\n\tto_move = 2;\n\tpair = 1;\n\trecord_move_unbalanced(&diff, &index, to_move_index,\n\t\t\t&instances, to_move, pair);\n\tck_assert_int_eq(diff, -2);\n\tck_assert_int_eq(index, to_move_index);\n\tck_assert_int_eq(instances, -1);\n\n\t/* Successful decrease. diff smaller than to_move - pair */\n\tdiff = -2;\n\tindex = -1;\n\tto_move_index = 2;\n\tinstances = 0;\n\tto_move = 4;\n\tpair = 1;\n\trecord_move_unbalanced(&diff, &index, to_move_index,\n\t\t\t&instances, to_move, pair);\n\tck_assert_int_eq(diff, 0);\n\tck_assert_int_eq(index, to_move_index);\n\tck_assert_int_eq(instances, -2);\n\n}\nEND_TEST\n\nSTART_TEST(test_reallocate_edge_pointer_array)\n{\n\tck_assert_int_eq(reallocate_edge_pointer_array(NULL, 1), OP_ERROR);\n\tck_assert_int_eq(reallocate_edge_pointer_array(&pointers_to_edges, -2), OP_ERROR);\n\tck_assert_int_eq(reallocate_edge_pointer_array(&pointers_to_edges, 0), OP_ERROR);\n\t/* Not incresing the value of n_ptedges to not perplex freeing \n         * pointers_to_edges because reallocation only accounts for\n         * struct dgsh_edge *.\n         */\n\tck_assert_int_eq(reallocate_edge_pointer_array(&pointers_to_edges, n_ptedges + 1), OP_SUCCESS);\n}\nEND_TEST\n\nSTART_TEST(test_make_compact_edge_array)\n{\n\tck_assert_int_eq(make_compact_edge_array(NULL, 2, pointers_to_edges), OP_ERROR);\n\tck_assert_int_eq(make_compact_edge_array(&compact_edges, -2, pointers_to_edges), OP_ERROR);\n\tck_assert_int_eq(make_compact_edge_array(&compact_edges, 0, pointers_to_edges), OP_ERROR);\n\tck_assert_int_eq(make_compact_edge_array(&compact_edges, n_ptedges, NULL), OP_ERROR);\n\n\tstruct dgsh_edge *p = pointers_to_edges[0];\n\tpointers_to_edges[0] = NULL;\n\tck_assert_int_eq(make_compact_edge_array(&compact_edges, n_ptedges, pointers_to_edges), OP_ERROR);\n\n\tpointers_to_edges[0] = p;\n\tck_assert_int_eq(make_compact_edge_array(&compact_edges, n_ptedges, pointers_to_edges), OP_SUCCESS);\n}\nEND_TEST\n\nSTART_TEST(test_write_output_fds)\n{\n\tint write_fd = 1;\n\tint *output_fds;\n\t/* 0 outgoing edges for node 3, so no action really. */\n\tck_assert_int_eq(write_output_fds(write_fd, output_fds, 0),\n\t\t\tOP_SUCCESS);\n\n\t/* Switch to node 2 that has 2 outgoing edges. */\n\tmemcpy(&self_node, &chosen_mb->node_array[2], sizeof(struct dgsh_node));\n\toutput_fds = (int *)malloc(sizeof(int) * 2);\n\tck_assert_int_eq(write_output_fds(write_fd, output_fds,\n\t\t\t\tDGSH_HANDLE_ERROR), OP_SUCCESS);\n\tfree(output_fds);\n\n\t/* Incomplete testing since socket descriptors have not yet been setup.\n\t * This will hapeen through the shell.\n\t */\n}\nEND_TEST\n\nSTART_TEST(test_set_dispatcher)\n{\n\tset_dispatcher();\n\tck_assert_int_eq(chosen_mb->origin_index, 3);\n\tck_assert_int_eq(chosen_mb->origin_fd_direction, 0); /* The input side */\n}\nEND_TEST\n\nSTART_TEST(test_alloc_node_connections)\n{\n\tstruct dgsh_edge *test;\n\t/* It is assumed that negative number of edges have already\n         * been checked. See e.g. read_graph_solution().\n         */\n\tck_assert_int_eq(alloc_node_connections(NULL, 2, 1, 2), OP_ERROR);\n\tck_assert_int_eq(alloc_node_connections(&test, 1, 2, 2), OP_ERROR);\n\tck_assert_int_eq(alloc_node_connections(&test, 1, -1, 2), OP_ERROR);\n\tck_assert_int_eq(alloc_node_connections(&test, 1, 1, -2), OP_ERROR);\n\n\tck_assert_int_eq(alloc_node_connections(&test, 1, 1, 2), OP_SUCCESS);\n\tfree(test);\n}\nEND_TEST\n\nSTART_TEST(test_write_concs)\n{\n\tint fd[2];\n\tint buf_size = getpagesize();\n\tint pid;\n\tint i;\n        int n_concs = chosen_mb->n_concs;\n        int concs_size = sizeof(struct dgsh_conc) * n_concs;\n\tstruct dgsh_conc *conc_array = \n\t\t(struct dgsh_conc *)malloc(concs_size);\n\n\tif (pipe(fd) == -1) {\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\tDPRINTF(4, \"%s()...\", __func__);\n\tDPRINTF(4, \"Opened pipe pair %d - %d.\", fd[0], fd[1]);\n\n\tpid = fork();\n\tif (pid <= 0) {\n\t\tint rsize = -1;\n\t\tDPRINTF(4, \"Child speaking with pid %d.\", (int)getpid());\n\n\t\tclose(fd[1]);\n\t\tDPRINTF(4, \"Child reads concs of size %d.\",\n\t\t\t\t\tconcs_size);\n\t\trsize = read(fd[0], conc_array, concs_size);\n\t\tif (rsize == -1) {\n\t\t\tDPRINTF(4, \"Write concs failed.\");\n\t\t\texit(1);\n\t\t}\n\n\t\tDPRINTF(4, \"Child: closes fd %d.\", fd[0]);\n\t\tclose(fd[0]);\n\t\tDPRINTF(4, \"Child with pid %d exits.\", (int)getpid());\n\t} else {\n\t\tDPRINTF(4, \"Parent speaking with pid %d.\", (int)getpid());\n\t\tck_assert_int_eq(write_concs(fd[1]), OP_SUCCESS);\n\t}\n}\nEND_TEST\n\n/* Incomplete? */\nSTART_TEST(test_write_graph_solution)\n{\n\tint fd[2];\n\tint buf_size = getpagesize();\n\tint pid;\n\tint i;\n        int n_nodes = chosen_mb->n_nodes;\n        int graph_solution_size = sizeof(struct dgsh_node_connections) *\n                                                                n_nodes;\n\tstruct dgsh_node_connections *graph_solution = \n\t\t(struct dgsh_node_connections *)malloc(graph_solution_size);\n\n\tif (pipe(fd) == -1) {\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\tDPRINTF(4, \"%s()...\", __func__);\n\tDPRINTF(4, \"Opened pipe pair %d - %d.\", fd[0], fd[1]);\n\n\tpid = fork();\n\tif (pid <= 0) {\n\t\tint rsize = -1;\n\t\tDPRINTF(4, \"Child speaking with pid %d.\", (int)getpid());\n\n\t\tclose(fd[1]);\n\t\tDPRINTF(4, \"Child reads graph solution of size %d.\",\n\t\t\t\t\tgraph_solution_size);\n        \trsize = read(fd[0], graph_solution, graph_solution_size);\n\t\tif (rsize == -1) {\n\t\t\tDPRINTF(4, \"Write graph solution failed.\");\n\t\t\texit(1);\n\t\t}\n\n\t\tfor (i = 0; i < chosen_mb->n_nodes; i++) {\n                \tstruct dgsh_node_connections *nc = &graph_solution[i];\n                \tint in_edges_size = sizeof(struct dgsh_edge) *\n\t\t\t\t\t\t\tnc->n_edges_incoming;\n                \tint out_edges_size = sizeof(struct dgsh_edge) *\n\t\t\t\t\t\t\tnc->n_edges_outgoing;\n                \tif ((in_edges_size > buf_size) || \n\t\t\t\t\t\t(out_edges_size > buf_size)) {\n                        \tDPRINTF(4, \"Dgsh negotiation graph solution for node at index %d: incoming connections of size %d or outgoing connections of size %d do not fit to buffer of size %d.\\n\", nc->node_index, in_edges_size, out_edges_size, buf_size);\n                        \texit(1);\n                \t}\n\n\t\t\tDPRINTF(4, \"Child reads incoming edges of node %d in fd %d. Total size: %d\", i, fd[1], in_edges_size);\n                \t/* Transmit a node's incoming connections. */\n                \trsize = read(fd[0], nc->edges_incoming, in_edges_size);\n\t\t\tif (rsize == -1) {\n\t\t\t\tDPRINTF(4, \"Read edges incoming failed.\");\n\t\t\t\texit(1);\n\t\t\t}\n\n\t\t\tDPRINTF(4, \"Child reads outgoing edges of node %d in fd %d. Total size: %d\", i, fd[1], out_edges_size);\n                \t/* Transmit a node's outgoing connections. */\n                \trsize = read(fd[0], nc->edges_outgoing, out_edges_size);\n\t\t\tif (rsize == -1) {\n\t\t\t\tDPRINTF(4, \"Read edges outgoing failed.\");\n\t\t\t\texit(1);\n\t\t\t}\n        \t}\n\t\tDPRINTF(4, \"Child: closes fd %d.\", fd[0]);\n\t\tclose(fd[0]);\n\t\tDPRINTF(4, \"Child with pid %d exits.\", (int)getpid());\n\t} else {\n\t\tDPRINTF(4, \"Parent speaking with pid %d.\", (int)getpid());\n\t\tck_assert_int_eq(write_graph_solution(fd[1]), OP_SUCCESS);\n\t}\n}\nEND_TEST\n\n/* Incomplete? */\nSTART_TEST(test_write_message_block)\n{\n\tint fd[2];\n\tint pid;\n\tDPRINTF(4, \"%s()\", __func__);\n\n\tif(pipe(fd) == -1){\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\tDPRINTF(4, \"Opened pipe pair %d - %d.\", fd[0], fd[1]);\t\n\n\tpid = fork();\n\tif (pid <= 0) {\n\t\tDPRINTF(4, \"Child speaking with pid %d.\", (int)getpid());\n\t\tstruct dgsh_negotiation *test_mb = (struct dgsh_negotiation *)\n\t\t\t\tmalloc(sizeof(struct dgsh_negotiation));\n        \tint mb_struct_size = sizeof(struct dgsh_negotiation);\n                int i = 0;\n\t\tint rsize = -1;\n\n\t\tclose(fd[1]);\n\t\tDPRINTF(4, \"Child reads message block structure of size %d.\",\n\t\t\t\t\tmb_struct_size);\n        \trsize = read(fd[0], test_mb, mb_struct_size);\n\t\tif (rsize == -1) {\n\t\t\tDPRINTF(4, \"Read message block failed.\");\n\t\t\texit(1);\n\t\t}\n        \tint n_nodes = test_mb->n_nodes;\n        \tint n_edges = test_mb->n_edges;\n        \tint mb_nodes_size = sizeof(struct dgsh_node) * n_nodes;\n\t\ttest_mb->node_array = (struct dgsh_node *)malloc(mb_nodes_size);\n        \tint mb_edges_size = sizeof(struct dgsh_edge) * n_edges;\n\t\ttest_mb->edge_array = (struct dgsh_edge *)malloc(mb_edges_size);\n\n\t\tDPRINTF(4, \"Child reads message block node array of size %d.\",\n\t\t\t\t\tmb_nodes_size);\n        \trsize = read(fd[0], test_mb->node_array, mb_nodes_size);\n\t\tif (rsize == -1) {\n\t\t\tDPRINTF(4, \"Read node array failed.\");\n\t\t\texit(1);\n\t\t}\n\n\t\tDPRINTF(4, \"Child reads message block edge array of size %d.\",\n\t\t\t\t\tmb_edges_size);\n\t\trsize = read(fd[0], test_mb->edge_array, mb_edges_size);\n\t\tif (rsize == -1) {\n\t\t\tDPRINTF(4, \"Read edge array failed.\");\n\t\t\texit(1);\n\t\t}\n                for (i = 0; i < test_mb->n_edges; i++) {\n                        struct dgsh_edge *e = &test_mb->edge_array[i];\n                        DPRINTF(4, \"Edge from: %d, to: %d\", e->from, e->to);\n                }\n\n\t\tDPRINTF(4, \"Child: closes fd %d.\", fd[0]);\n\t\tclose(fd[0]);\n\t\tDPRINTF(4, \"Child with pid %d exits.\", (int)getpid());\n\t\tretire_mb(test_mb);\n\t} else {\n\t\tDPRINTF(4, \"Parent speaking with pid %d.\", (int)getpid());\n\t\tck_assert_int_eq(write_message_block(fd[1]), OP_SUCCESS);\n\t}\n}\nEND_TEST\n\n/* Incomplete? */\nSTART_TEST(test_read_message_block)\n{\n\tint fd[2];\n\tint pid;\n\tDPRINTF(4, \"%s()\", __func__);\n\n\tif(pipe(fd) == -1){\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\tDPRINTF(4, \"Opened pipe pair %d - %d.\", fd[0], fd[1]);\n\n\tpid = fork();\n\tif (pid <= 0) {\n\t\tDPRINTF(4, \"Child speaking with pid %d.\", (int)getpid());\n\t\tstruct dgsh_negotiation *test_mb;\n\t\tsetup_mb(&test_mb);\n        \tint n_nodes = test_mb->n_nodes;\n        \tint n_edges = test_mb->n_edges;\n        \tint mb_struct_size = sizeof(struct dgsh_negotiation);\n        \tint mb_nodes_size = sizeof(struct dgsh_node) * n_nodes;\n        \tint mb_edges_size = sizeof(struct dgsh_edge) * n_edges;\n                int i = 0;\n\t\tint wsize = -1;\n\t\tstruct timespec tm;\n\t\ttm.tv_sec = 0;\n\t\ttm.tv_nsec = 1000000;\n\n\t\tclose(fd[0]);\n\t\tDPRINTF(4, \"Child writes message block structure of size %d.\",\n\t\t\t\t\tmb_struct_size);\n        \twsize = write(fd[1], test_mb, mb_struct_size);\n\t\tif (wsize == -1) {\n\t\t\tDPRINTF(4, \"Write message block structure failed.\");\n\t\t\texit(1);\n\t\t}\n\t\t/* Sleep for 1 millisecond to write-read orderly.\n\t\t * Why do we need this?\n\t\t * Shouldn't the write block by deafult?\n\t\t */\n\t\tnanosleep(&tm, NULL);\n\n\t\tDPRINTF(4, \"Child writes message block node array of size %d.\",\n\t\t\t\t\tmb_nodes_size);\n        \twsize = write(fd[1], test_mb->node_array, mb_nodes_size);\n\t\tif (wsize == -1) {\n\t\t\tDPRINTF(4, \"Write message block node array failed.\");\n\t\t\texit(1);\n\t\t}\n\t\t/* Sleep for 1 millisecond before the next operation. */\n\t\tnanosleep(&tm, NULL);\n\n\t\tDPRINTF(4, \"Child writes message block edge array of size %d.\",\n\t\t\t\t\tmb_edges_size);\n                for (i = 0; i < test_mb->n_edges; i++) {\n                        struct dgsh_edge *e = &test_mb->edge_array[i];\n                        DPRINTF(4, \"Edge from: %d, to: %d\", e->from, e->to);\n                }\n\t\twsize = write(fd[1], test_mb->edge_array, mb_edges_size);\n\t\tif (wsize == -1) {\n\t\t\tDPRINTF(4, \"Write message block edge array failed.\");\n\t\t\texit(1);\n\t\t}\n\n\t\tDPRINTF(4, \"Child: closes fd %d.\", fd[1]);\n\t\tclose(fd[1]);\n\t\tDPRINTF(4, \"Child with pid %d exits.\", (int)getpid());\n\t\tretire_mb(test_mb);\n\t} else {\n\t\tDPRINTF(4, \"Parent speaking with pid %d.\", (int)getpid());\n\t\tck_assert_int_eq(read_message_block(fd[0], &fresh_mb),\n\t\t\t\tOP_SUCCESS);\n\t}\n}\nEND_TEST\n\n/* Incomplete? */\nSTART_TEST(test_read_graph_solution)\n{\n\tint fd[2];\n\tint pid;\n\tint i;\n        int n_nodes = fresh_mb->n_nodes;\n\tint buf_size = getpagesize();\n        int graph_solution_size = sizeof(struct dgsh_node_connections) *\n                                                                n_nodes;\n\tstruct timespec tm;\n\ttm.tv_sec = 0;\n\ttm.tv_nsec = 1000000;\n\tDPRINTF(4, \"%s()\", __func__);\n\n\tif(pipe(fd) == -1){\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\tDPRINTF(4, \"Opened pipe pair %d - %d.\", fd[0], fd[1]);\t\n\n\tpid = fork();\n\tif (pid <= 0) {\n\t\tint wsize = -1;\n\t\tDPRINTF(4, \"Child speaking with pid %d.\", (int)getpid());\n\t\tsetup_graph_solution();\n\t\tstruct dgsh_node_connections *graph_solution =\n\t\t\tchosen_mb->graph_solution;\n\n\t\tclose(fd[0]);\n\t\tDPRINTF(4, \"Child writes graph solution of size %d.\",\n\t\t\t\t\tgraph_solution_size);\n        \twsize = write(fd[1], graph_solution, graph_solution_size);\n\t\tif (wsize == -1) {\n\t\t\tDPRINTF(4, \"Write graph solution failed.\");\n\t\t\texit(1);\n\t\t}\n\t\t/* Sleep for 1 millisecond before the next operation. */\n\t\tnanosleep(&tm, NULL);\n\n\t\tfor (i = 0; i < chosen_mb->n_nodes; i++) {\n                \tstruct dgsh_node_connections *nc = &graph_solution[i];\n                \tint in_edges_size = sizeof(struct dgsh_edge) *\n\t\t\t\t\t\t\tnc->n_edges_incoming;\n                \tint out_edges_size = sizeof(struct dgsh_edge) *\n\t\t\t\t\t\t\tnc->n_edges_outgoing;\n\t\t\tint wsize = -1;\n\t\t\tif ((in_edges_size > buf_size) || \n\t\t\t\t\t\t(out_edges_size > buf_size)) {\n                        \tDPRINTF(4, \"Dgsh negotiation graph solution for node at index %d: incoming connections of size %d or outgoing connections of size %d do not fit to buffer of size %d.\\n\", nc->node_index, in_edges_size, out_edges_size, buf_size);\n                        \texit(1);\n                \t}\n\n\t\t\tDPRINTF(4, \"Child writes incoming edges of node %d in fd %d. Total size: %d\", i, fd[1], in_edges_size);\n                \t/* Transmit a node's incoming connections. */\n                \twsize = write(fd[1], nc->edges_incoming, in_edges_size);\n\t\t\tif (wsize == -1) {\n\t\t\t\tDPRINTF(4, \"Write edges incoming failed.\");\n\t\t\t\texit(1);\n\t\t\t}\n\t\t\t/* Sleep for 1 millisecond before the next operation. */\n\t\t\tnanosleep(&tm, NULL);\n\n\t\t\tDPRINTF(4, \"Child writes outgoing edges of node %d in fd %d. Total size: %d\", i, fd[1], out_edges_size);\n                \t/* Transmit a node's outgoing connections. */\n                \twsize = write(fd[1], nc->edges_outgoing, out_edges_size);\n\t\t\tif (wsize == -1) {\n\t\t\t\tDPRINTF(4, \"Write edges outgoing failed.\");\n\t\t\t\texit(1);\n\t\t\t}\n\t\t\t/* Sleep for 1 millisecond before the next operation. */\n\t\t\tnanosleep(&tm, NULL);\n        \t}\n\t\tDPRINTF(4, \"Child: closes fd %d.\", fd[1]);\n\t\tclose(fd[1]);\n\t\tDPRINTF(4, \"Child with pid %d exits.\", (int)getpid());\n\t\tretire_graph_solution(graph_solution, chosen_mb->n_nodes - 1);\n\t} else {\n\t\tDPRINTF(4, \"Parent speaking with pid %d.\", (int)getpid());\n\t\tck_assert_int_eq(read_graph_solution(fd[0],\n\t\t\t\t\tfresh_mb), OP_SUCCESS);\n\t}\n}\nEND_TEST\n\nSTART_TEST(test_read_concs)\n{\n\tint fd[2];\n\tint pid;\n\tint i;\n        int n_concs = fresh_mb->n_concs;\n\tint buf_size = getpagesize();\n        int concs_size = sizeof(struct dgsh_conc) * n_concs;\n\tDPRINTF(4, \"%s()\", __func__);\n\n\tif(pipe(fd) == -1){\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\tDPRINTF(4, \"Opened pipe pair %d - %d.\", fd[0], fd[1]);\n\n\tpid = fork();\n\tif (pid <= 0) {\n\t\tint wsize = -1;\n\t\tDPRINTF(4, \"Child speaking with pid %d.\", (int)getpid());\n\t\tsetup_graph_solution();\n\t\tstruct dgsh_conc *concs =\n\t\t\tchosen_mb->conc_array;\n\n\t\tclose(fd[0]);\n\t\tDPRINTF(4, \"Child writes concs of size %d.\",\n\t\t\t\t\tconcs_size);\n\t\twsize = write(fd[1], concs, concs_size);\n\t\tif (wsize == -1) {\n\t\t\tDPRINTF(4, \"Write concs failed.\");\n\t\t\texit(1);\n\t\t}\n\t} else {\n\t\tDPRINTF(4, \"Parent speaking with pid %d.\", (int)getpid());\n\t\tck_assert_int_eq(read_concs(fd[0],\n\t\t\t\t\tfresh_mb), OP_SUCCESS);\n\t}\n}\nEND_TEST\n\nSTART_TEST(test_alloc_fds)\n{\n\tint *fds = NULL;\n\tint n_fds = 0;\n\tck_assert_int_eq(alloc_fds(&fds, n_fds), OP_SUCCESS);\n\tck_assert_int_eq((int)(long)fds, 0);\n\n\tn_fds = 2;\n\tck_assert_int_eq(alloc_fds(&fds, n_fds), OP_SUCCESS);\n\tck_assert_int_ne((int)(long)fds, 0);\n\tfree(fds);\n}\nEND_TEST\n\nSTART_TEST(test_alloc_io_fds)\n{\n\t/* By default initialised to 0. See setup_chosen_mb() */\n\tchosen_mb->graph_solution[3].edges_incoming[0].instances = 1;\n\tchosen_mb->graph_solution[3].edges_incoming[1].instances = 1;\n\tck_assert_int_eq(alloc_io_fds(), OP_SUCCESS);\n\tck_assert_int_eq(self_pipe_fds.n_input_fds, 2);\n\tck_assert_int_eq(self_pipe_fds.n_output_fds, 0);\n}\nEND_TEST\n\nSTART_TEST(test_get_origin_pid)\n{\n\tchosen_mb->origin_index = 3;\n\tck_assert_int_eq(get_origin_pid(chosen_mb), 103);\n\n\tchosen_mb->origin_index = 1;\n\tck_assert_int_eq(get_origin_pid(chosen_mb), 101);\n}\nEND_TEST\n\nSTART_TEST(test_get_expected_fds_n)\n{\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\tchosen_mb->graph_solution;\n\tgraph_solution[0].edges_incoming[0].instances = 1;\n\tgraph_solution[1].edges_incoming[0].instances = 1;\n\tgraph_solution[3].edges_incoming[0].instances = 1;\n\tgraph_solution[3].edges_incoming[1].instances = 1;\n\tck_assert_int_eq(get_expected_fds_n(chosen_mb, 103), 2);\n\tck_assert_int_eq(get_expected_fds_n(chosen_mb, 100), 1);\n\tck_assert_int_eq(get_expected_fds_n(chosen_mb, 101), 1);\n\tck_assert_int_eq(get_expected_fds_n(chosen_mb, 102), 0);\n}\nEND_TEST\n\nSTART_TEST(test_get_provided_fds_n)\n{\n\tstruct dgsh_node_connections *graph_solution =\n\t\t\tchosen_mb->graph_solution;\n\tgraph_solution[0].edges_outgoing[0].instances = 1;\n\tgraph_solution[1].edges_outgoing[0].instances = 1;\n\tgraph_solution[1].edges_outgoing[1].instances = 1;\n\tgraph_solution[2].edges_outgoing[0].instances = 1;\n\tgraph_solution[2].edges_outgoing[1].instances = 1;\n\tck_assert_int_eq(get_provided_fds_n(chosen_mb, 103), 0);\n\tck_assert_int_eq(get_provided_fds_n(chosen_mb, 100), 1);\n\tck_assert_int_eq(get_provided_fds_n(chosen_mb, 101), 2);\n\tck_assert_int_eq(get_provided_fds_n(chosen_mb, 102), 2);\n}\nEND_TEST\n\nSTART_TEST (test_read_write_fd)\n{\n\tint pipefd[2];\n\tint sock, rsock;\n\tint readfd;\n\tchar msg[] = \"hello\";\n\tchar buff[20];\n\tint n;\n\tpid_t pid;\n\tsocklen_t len;\n\tstruct sockaddr_un local, remote;\n\n\tif (pipe(pipefd) == -1)\n\t\terr(1, \"pipe\");\n\tlocal.sun_family = AF_UNIX;\n\tsnprintf(local.sun_path, sizeof(local.sun_path), \"/tmp/conc-%d\", getpid());\n\tlen = strlen(local.sun_path) + 1 + sizeof(local.sun_family);\n\n\tswitch ((pid = fork())) {\n\tcase 0:\n\t\t/* Child: connect, pass fd and write test message */\n\t\tif ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)\n\t\t\terr(1, \"socket\");\n\t\tsleep(1);\n\t\tif (connect(sock, (struct sockaddr *)&local, len) == -1)\n\t\t\terr(1, \"connect %s\", local.sun_path);\n\t\twrite_fd(sock, pipefd[STDIN_FILENO]);\n\t\tclose(sock); // Should wait for data to be transmitted\n\t\tclose(pipefd[STDIN_FILENO]);\n\t\tsleep(1);\n\t\tif (write(pipefd[STDOUT_FILENO], msg, sizeof(msg)) <= 0)\n\t\t\terr(1, \"write\");\n\t\texit(0);\n\tdefault:\n\t\t/* Parent: accept connection, read fd and read test message */\n\t\tclose(pipefd[STDIN_FILENO]);\n\t\tclose(pipefd[STDOUT_FILENO]);\n\t\tif ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)\n\t\t\terr(1, \"socket\");\n\t\tif (bind(sock, (struct sockaddr *)&local, len) == -1)\n\t\t\terr(1, \"bind %s\", local.sun_path);\n\t\tif (listen(sock, 5) == -1)\n\t\t\terr(1, \"listen\");\n\t\trsock = accept(sock, (struct sockaddr *)&remote, &len);\n\t\treadfd = read_fd(rsock);\n\t\tif ((n = read(readfd, buff, sizeof(buff))) == -1)\n\t\t\terr(1, \"read\");\n\t\t(void)unlink(local.sun_path);\n\t\tck_assert_int_eq(n, sizeof(msg));\n\t\tck_assert_str_eq(msg, buff);\n\t\tbreak;\n\tcase -1:        /* Error */\n\t\terr(1, \"fork\");\n\t}\n\n}\nEND_TEST\n\n\t\t\n/* Incomplete? */\nSTART_TEST(test_read_input_fds)\n{\n\tint sockets[2];\n\tint fd, ping;\n\tstruct msghdr msg;\n\tstruct iovec vec[1];\n\tunion fdmsg cmsg;\n\tstruct cmsghdr *h;\n\tint wsize = -1;\n\n\tmemset(&msg, 0, sizeof(struct msghdr));\n\tDPRINTF(4, \"%s()...pid %d\", __func__, (int)getpid());\n\n\tif (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) {\n\t\tperror(\"Error opening stream socket pair. Exiting now.\");\n\t\texit(1);\n\t}\n\tDPRINTF(4, \"Opened socket pair %d - %d.\", sockets[0], sockets[1]);\n\n\tfd = open(\"unit-test-dgsh\", O_CREAT | O_RDWR, 0660);\n\twsize = write(fd, \"Unit testing dgsh...\", 21);\n\tif (wsize == -1) {\n\t\tDPRINTF(4, \"Write to 'unit-test-dgsh' failed.\");\n\t\texit(1);\n\t}\n        close(fd);\n\tfd = open(\"unit-test-dgsh\", O_RDONLY);\n\tif (fd < 0) {\n\t\tperror(\"Failed to open file test-dgsh for reading.\");\n\t\texit(1);\n\t}\n\n        int pid = fork();\n\tif (pid <= 0) {\n\t\tDPRINTF(4, \"Child speaking with pid %d.\", (int)getpid());\n\n\t\tDPRINTF(4, \"Child closes socket %d.\", sockets[1]);\n\t\tclose(sockets[1]);\n\n\t\tvec[0].iov_base = &ping;\n\t\tvec[0].iov_len = 1;\n\n\t\tmsg.msg_iov = vec;\n\t\tmsg.msg_iovlen = 1;\n\t\tmsg.msg_name = 0;\n\t\tmsg.msg_namelen = 0;\n\t\tmsg.msg_control = cmsg.buf;\n\t\tmsg.msg_controllen = sizeof(union fdmsg);\n\t\tmsg.msg_flags = 0;\n\n\t\th = CMSG_FIRSTHDR(&msg);\n\t\th->cmsg_level = SOL_SOCKET;\n\t\th->cmsg_type = SCM_RIGHTS;\n\t\th->cmsg_len = CMSG_LEN(sizeof(int));\n\t\t*((int*)CMSG_DATA(h)) = fd;\n\n\t\tDPRINTF(4, \"Child goes sendmsg()\");\n\t\tif((sendmsg(sockets[0], &msg, 0)) < 0){\n\t\t\tperror(\"sendmsg()\");\n\t\t\texit(EXIT_FAILURE);\n\t\t}\n\t\tDPRINTF(4, \"Child: closes fd %d.\", fd);\n\t\tclose(fd);\n\t\tDPRINTF(4, \"Child with pid %d exits.\", (int)getpid());\n\t} else {\n\t\tstruct dgsh_node_connections *graph_solution =\n\t\t\tchosen_mb->graph_solution;\n\t\tmemcpy(&self_node, &chosen_mb->node_array[1],\n\t\t\t\t\t\tsizeof(struct dgsh_node));\n\t\t/* Edges have been setup with 0 instances.\n\t\t * See setup_chosen_mb().\n\t \t * Edges then copied to graph_solution.\n\t\t * See setup_graph_solution().\n\t \t */\n\t\tgraph_solution[1].edges_incoming[0].instances = 1;\n\t\tint *input_fds = (int *)malloc(sizeof(int));\n\t\tinput_fds[0] = -1;\n\t\n\t\tDPRINTF(4, \"Parent speaking with pid %d.\", (int)getpid());\n\t\tck_assert_int_eq(read_input_fds(sockets[1], input_fds),\n\t\t\t\tOP_SUCCESS);\n\t\tck_assert_int_ge(input_fds[0], 3);\n\t\t/* Hard-coded ceiling to check whether some weird\n\t\t * error has caused some random number to slip in.\n\t\t */\n\t\tck_assert_int_le(input_fds[0], 20);\n\t\tfree(input_fds);\n\t\tDPRINTF(4, \"Parent with pid %d exits.\", (int)getpid()); \n\t}\n\tclose(sockets[0]);\n\tclose(sockets[1]);\n}\nEND_TEST\n\n/* Incomplete? */\nSTART_TEST(test_read_chunk)\n{\n\t/* Requires setting up of I/O multiplexing (a bash shell extension)\n\t * in order to be able to support bidirectional negotiation.\n\t * Without it we cannot test this function because it tries to read\n\t * repeatedly from stdin and then stdout until it manages.\n         * We cannot feed it; writing to stdin or stdout\n\t * ends up in the unit test file output).\n\t * The good news is that the core of this function is the call to\n\t * call read, which has been successfully tested.\n\t * Then there is variable checking to determine the exit code.\n\t */\n\tint fd[2];\n\tint wsize = -1;\n\tDPRINTF(4, \"%s()...\", __func__);\n\tif(pipe(fd) == -1){\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\n\t/* Broken pipe error if we close the other side. */\n\t//close(fd[0]);\n\twsize = write(fd[1], \"test-in\", 9);\n\tif (wsize == -1) {\n\t\tDPRINTF(4, \"Write to 'test-in' failed.\");\n\t\texit(1);\n\t}\n\tchar buf[32];\n\tint read_fd = -1;\n\tint bytes_read = -1;\n\tck_assert_int_eq(read_chunk(fd[0], buf, 32, &bytes_read, 5), OP_SUCCESS);\n\tck_assert_int_eq(bytes_read, 9);\n\t\n\tclose(fd[0]);\n\tclose(fd[1]);\n}\nEND_TEST\n\nSTART_TEST(test_call_read)\n{\n\tint fd[2];\n\tint wsize = -1;\n\tDPRINTF(4, \"%s()...\", __func__);\n\tif(pipe(fd) == -1){\n\t\tperror(\"pipe open failed\");\n\t\texit(1);\n\t}\n\n\tif ((wsize = write(fd[1], \"test\", 5)) == -1) {\n\t\tDPRINTF(4, \"Write to 'test' failed.\\n\");\n\t\texit(1);\n\t}\n\n\tchar buf[32];\n\tint bytes_read = -1;\n\tint error_code = -1;\n\tck_assert_int_eq(call_read(fd[0], buf, 32, &bytes_read,\n\t\t\t\t&error_code), OP_SUCCESS);\n\tck_assert_int_eq(bytes_read, 5);\n\tck_assert_int_eq(error_code, 0);\n\n\tclose(fd[0]);\n\tclose(fd[1]);\n}\nEND_TEST\n\nSTART_TEST(test_alloc_copy_mb)\n{\n\tconst int size = sizeof(struct dgsh_negotiation);\n\tchar buf[512];\n\tstruct dgsh_negotiation *mb;\n\tck_assert_int_eq(alloc_copy_mb(&mb, buf, 86, 512), OP_ERROR);\n\n\tchar buf2[32];\n\tck_assert_int_eq(alloc_copy_mb(&mb, buf2, size, 32), OP_ERROR);\n\n\tck_assert_int_eq(alloc_copy_mb(&mb, buf, size, 512), OP_SUCCESS);\n\tfree(mb);\n}\nEND_TEST\n\nSTART_TEST(test_alloc_copy_proc_pids)\n{\n\tstruct dgsh_conc c;\n\tc.n_proc_pids = 2;\n\tconst int size = sizeof(int) * c.n_proc_pids;\n\tint pids[2] = {101, 103};\n\tchar buf[512];\n\tmemcpy(buf, pids, size);\n\n\tck_assert_int_eq(alloc_copy_proc_pids(&c, buf, 86, 512),\n\t\t\tOP_ERROR);\n\n\tchar buf2[8];\n\tck_assert_int_eq(alloc_copy_proc_pids(&c, buf2, size, 4),\n\t\t\tOP_ERROR);\n\n\tck_assert_int_eq(alloc_copy_proc_pids(&c, buf, size, 512),\n\t\t\tOP_SUCCESS);\n}\nEND_TEST\n\nSTART_TEST(test_alloc_copy_concs)\n{\n\tconst int n_concs = fresh_mb->n_concs = 1;\n\tconst int size = sizeof(struct dgsh_conc) * n_concs;\n\tstruct dgsh_conc c;\n\tchar buf[512];\n\tmemcpy(buf, &c, size);\n\tck_assert_int_eq(alloc_copy_concs(fresh_mb, buf, 86, 512),\n\t\t\tOP_ERROR);\n\n\tchar buf2[8];\n\tck_assert_int_eq(alloc_copy_concs(fresh_mb, buf2, size, 8),\n\t\t\tOP_ERROR);\n\n\tck_assert_int_eq(alloc_copy_concs(fresh_mb, buf, size, 512),\n\t\t\tOP_SUCCESS);\n}\nEND_TEST\n\nSTART_TEST(test_alloc_copy_nodes)\n{\n\tconst int size = sizeof(struct dgsh_node) * fresh_mb->n_nodes;\n\tchar buf[512];\n\tck_assert_int_eq(alloc_copy_nodes(fresh_mb, buf, 86, 512), OP_ERROR);\n\n\tchar buf2[32];\n\tck_assert_int_eq(alloc_copy_nodes(fresh_mb, buf2, size, 32), OP_ERROR);\n\n\tfree(fresh_mb->node_array);  /* to avoid memory leak */\n\tck_assert_int_eq(alloc_copy_nodes(fresh_mb, buf, size, 512), OP_SUCCESS);\n}\nEND_TEST\n\nSTART_TEST(test_alloc_copy_edges)\n{\n\tconst int size = sizeof(struct dgsh_edge) * fresh_mb->n_edges;\n\tchar buf[256];\n\tck_assert_int_eq(alloc_copy_edges(fresh_mb, buf, 86, 256), OP_ERROR);\n\n\tchar buf2[32];\n\tck_assert_int_eq(alloc_copy_edges(fresh_mb, buf2, size, 32), OP_ERROR);\n\n\tfree(fresh_mb->edge_array);  /* to avoid memory leak */\n\tck_assert_int_eq(alloc_copy_edges(fresh_mb, buf, size, 256), OP_SUCCESS);\n}\nEND_TEST\n\nSTART_TEST(test_alloc_copy_graph_solution)\n{\n\tconst int size = sizeof(struct dgsh_node_connections) *\n\t\tfresh_mb->n_nodes;\n\tchar buf[256];\n\tck_assert_int_eq(alloc_copy_graph_solution(fresh_mb, buf, 86, 256),\n\t\t\tOP_ERROR);\n\n\tchar buf2[32];\n\tck_assert_int_eq(alloc_copy_edges(fresh_mb, buf2, size, 32), OP_ERROR);\n\n\t/* Free to avoid memory leak.\n\t * About the free() see how graph_solution is malloc'ed\n\t * at alloc_copy_graph_solution.\n\t */\n\tfree(fresh_mb->graph_solution);\n\tck_assert_int_eq(alloc_copy_graph_solution(fresh_mb, buf, size, 256),\n\t\t\tOP_SUCCESS);\n\tfree(fresh_mb->graph_solution); /* Easier to handle here. */\n}\nEND_TEST\n\nSTART_TEST(test_check_read)\n{\n\tck_assert_int_eq(check_read(512, 1024, 256), OP_ERROR);\n\tck_assert_int_eq(check_read(512, 256, 512), OP_ERROR);\n\tck_assert_int_eq(check_read(512, 1024, 512), OP_SUCCESS);\n}\nEND_TEST\n\n/*\n*START_TEST(test_point_io_direction)\n{\n\tck_assert_int_eq(point_io_direction(STDOUT_FILENO), STDIN_FILENO);\n\n\tmemcpy(&self_node, &chosen_mb->node_array[2], sizeof(struct dgsh_node));\n\tck_assert_int_eq(point_io_direction(STDIN_FILENO), STDOUT_FILENO);\n\t\n}\nEND_TEST\n*/\n\nSTART_TEST(test_analyse_read)\n{\n\tDPRINTF(4, \"%s()\", __func__);\n\t/* error state flag seen; terminal process such as node 3\n\t * which is the current node leave.\n\t */\n\tbool should_transmit_mb = false;\n\tint serialno_ntimes_same = 0;\n\tint run_ntimes_same = 0;\n\tint error_ntimes_same = 0;\n\tint draw_exit_ntimes_same = 0;\n\tfresh_mb->state = PS_ERROR;\n\tfresh_mb->is_error_confirmed = true;\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->state, PS_ERROR);\n\tck_assert_int_eq(error_ntimes_same, 1);\n\tck_assert_int_eq((long int)chosen_mb, (long int)fresh_mb);\n\tretire_test_analyse_read();\n\n\tsetup_test_analyse_read();\n\t/* error state flag seen; non-terminal process such as node 1\n\t * which is the current node leave when they see it the second time.\n\t * This is the first.\n\t */\n\tmemcpy(&self_node, &chosen_mb->node_array[1], sizeof(struct dgsh_node));\n\terror_ntimes_same = 0;\n\tfresh_mb->state = PS_ERROR;\n\tfresh_mb->is_error_confirmed = true;\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->state, PS_ERROR);\n\tck_assert_int_eq(error_ntimes_same, 1);\n\tck_assert_int_eq((long int)chosen_mb, (long int)fresh_mb);\n\tretire_test_analyse_read();\n\n\tsetup_test_analyse_read();\n\t/* error state flag seen; non-terminal process such as node 1\n\t * which is the current node have to leave when they see it \n\t * the second time. This is the second.\n\t * Before leaving they have to pass the block.\n\t */\n\tmemcpy(&self_node, &chosen_mb->node_array[1], sizeof(struct dgsh_node));\n\terror_ntimes_same = 1;\n\tfresh_mb->state = PS_ERROR;\n\tfresh_mb->is_error_confirmed = true;\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->state, PS_ERROR);\n\tck_assert_int_eq(error_ntimes_same, 2);\n\tck_assert_int_eq((long int)chosen_mb, (long int)fresh_mb);\n\tretire_test_analyse_read();\n\n\tsetup_test_analyse_read();\n\t/* All processes have to pass the block first except\n\t * for the ones who passed the block the last time\n\t * before finding a solution.\n\t */\n\terror_ntimes_same = 1;\n\tmemcpy(&self_node, &chosen_mb->node_array[1], sizeof(struct dgsh_node));\n\tfresh_mb->state = PS_ERROR;\n\tfresh_mb->is_error_confirmed = true;\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->state, PS_ERROR);\n\tck_assert_int_eq(error_ntimes_same, 2);\n\tck_assert_int_eq((long int)chosen_mb, (long int)fresh_mb);\n\tretire_test_analyse_read();\n\n\tsetup_test_analyse_read();\n\t/* run state flag seen; terminal process such as node 3\n\t * which is the current node leave.\n\t */\n\trun_ntimes_same = 0;\n\terror_ntimes_same = 0;\n\tfresh_mb->state = PS_RUN;\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->state, PS_RUN);\n\tck_assert_int_eq(run_ntimes_same, 1);\n\tck_assert_int_eq((long int)chosen_mb, (long int)fresh_mb);\n\tretire_test_analyse_read();\n\n\tsetup_test_analyse_read();\n\t/* run state flag seen; non-terminal process such as node 1\n\t * which is the current node leave when they see it the second time.\n\t * This is the first.\n\t */\n\tmemcpy(&self_node, &chosen_mb->node_array[1], sizeof(struct dgsh_node));\n\trun_ntimes_same = 0;\n\tfresh_mb->state = PS_RUN;\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->state, PS_RUN);\n\tck_assert_int_eq(run_ntimes_same, 1);\n\tck_assert_int_eq((long int)chosen_mb, (long int)fresh_mb);\n\tretire_test_analyse_read();\n\n\tsetup_test_analyse_read();\n\t/* run state flag seen; non-terminal process such as node 1\n\t * which is the current node have to leave when they see it \n\t * the second time. This is the second.\n\t * Before leaving they have to pass the block.\n\t */\n\tmemcpy(&self_node, &chosen_mb->node_array[1], sizeof(struct dgsh_node));\n\trun_ntimes_same = 1;\n\tfresh_mb->state = PS_RUN;\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->state, PS_RUN);\n\tck_assert_int_eq(run_ntimes_same, 2);\n\tck_assert_int_eq((long int)chosen_mb, (long int)fresh_mb);\n\tretire_test_analyse_read();\n\n\tsetup_test_analyse_read();\n\t/* When they are to leave they pass the block first except\n\t * if they are the ones who passed the block the last time\n\t * before finding a solution.\n\t */\n\tmemcpy(&self_node, &chosen_mb->node_array[1], sizeof(struct dgsh_node));\n\tshould_transmit_mb = false;\n\tfresh_mb->state = PS_RUN;\n\trun_ntimes_same = 1;\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->state, PS_RUN);\n\tck_assert_int_eq(run_ntimes_same, 2);\n\tck_assert_int_eq((long int)chosen_mb, (long int)fresh_mb);\n\tretire_test_analyse_read();\n\n\t/* Negotiation state */\n\tsetup_test_analyse_read();\n\trun_ntimes_same = 0;\n\terror_ntimes_same = 0;\n\t/* set_dispatcher() */\n\tself_node_io_side.index = 3;\n\tself_node_io_side.fd_direction = STDIN_FILENO;\n\tfresh_mb->initiator_pid = 110; /* Younger than chosen_mb. */\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tretire_test_analyse_read();\n\n\tsetup_test_analyse_read();\n\tshould_transmit_mb = false;\n\tmemcpy(&self_node, &chosen_mb->node_array[3], sizeof(struct dgsh_node));\n\t/* set_dispatcher() */\n\tself_node_io_side.index = 3;\n\tself_node_io_side.fd_direction = STDIN_FILENO;\n\tfresh_mb->initiator_pid = 103; /* Same initiator */\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n\tck_assert_int_eq((long int)chosen_mb, (long int)fresh_mb);\n\tretire_test_analyse_read();\n\n\tsetup_test_analyse_read();\n\tmemcpy(&self_node, &chosen_mb->node_array[0], sizeof(struct dgsh_node));\n\t/* set_dispatcher() */\n\tself_node_io_side.index = 0;\n\tself_node_io_side.fd_direction = STDOUT_FILENO;\n\tchosen_mb->origin_index = 3;\n\tchosen_mb->origin_fd_direction = STDIN_FILENO;\n\tfresh_mb->initiator_pid = 103; /* Same initiator */\n\tck_assert_int_eq(analyse_read(fresh_mb,\n\t\t\t\t&run_ntimes_same,\n\t\t\t\t&error_ntimes_same,\n\t\t\t\t&draw_exit_ntimes_same,\n\t\t\t\tself_node.name,\n\t\t\t\tself_node.pid, &self_node.requires_channels,\n\t\t\t\t&self_node.provides_channels), OP_SUCCESS);\n}\nEND_TEST\n\nSTART_TEST(test_free_mb)\n{\n\tfree_mb(chosen_mb);\n}\nEND_TEST\n\nSTART_TEST(test_fill_node)\n{\n\t/* self node is node at index 3 of chosen_mb */\n\tfill_node(\"test\", 1003, NULL, NULL);\n\tck_assert_int_eq(strcmp(self_node.name, \"test\"), 0);\n\tck_assert_int_eq(self_node.pid, 1003);\n\tck_assert_int_eq(self_node.requires_channels, 1);\n\tck_assert_int_eq(self_node.provides_channels, 0);\n\n\tint n_input_fds = 1;\n\tint n_output_fds = 1;\n\tfill_node(\"test\", 1003, &n_input_fds, &n_output_fds);\n\tck_assert_int_eq(self_node.requires_channels, 1);\n\tck_assert_int_eq(self_node.provides_channels, 1);\n}\nEND_TEST\n\nSTART_TEST(test_try_add_dgsh_node)\n{\n\tint n_input_fds = 1;\n\tint n_output_fds = 1;\n\tck_assert_int_eq(try_add_dgsh_node(\"proc3\", 103, &n_input_fds,\n\t\t\t\t&n_output_fds), OP_EXISTS);\n\tck_assert_int_eq(chosen_mb->n_nodes, 4);\n\tck_assert_int_eq(self_node_io_side.index, 0);\n\tck_assert_int_eq(self_node.index, 3);\n\n\tck_assert_int_eq(try_add_dgsh_node(\"proc4\", 104, &n_input_fds,\n\t\t\t\t&n_output_fds), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->n_nodes, 5);\n\tck_assert_int_eq(self_node_io_side.index, 4);\n\tck_assert_int_eq(self_node.index, 4);\n}\nEND_TEST\n\nSTART_TEST(test_try_add_dgsh_edge)\n{\n\t/* Better in a setup function. */ \n\tchosen_mb->origin_fd_direction = STDOUT_FILENO;   \n\tchosen_mb->origin_index = 0;\n\t/* self_node_io_side should also be set; it is set in setup */\n\tck_assert_int_eq(try_add_dgsh_edge(), OP_EXISTS);\n\n\t/* New edge: from new node to existing */\n\tstruct dgsh_node new;\n\tnew.index = 4;\n\tnew.pid = 104;\n\tmemcpy(new.name, \"proc4\", 6);\n\tnew.requires_channels = 1;\n\tnew.provides_channels = 1;\n\tnew.dgsh_in = 1;\n        new.dgsh_out = 1;\n\t/* Better in a setup function. */ \n\tchosen_mb->origin_fd_direction = STDOUT_FILENO;   \n\tchosen_mb->origin_index = new.index;\n\t/* self_node_io_side should also be set; it is set in setup */\n\tmemcpy(&self_node, &new, sizeof(struct dgsh_node));\n\tchosen_mb->n_nodes++;\n\tchosen_mb->node_array = realloc(chosen_mb->node_array,\n\t\t\t\tsizeof(struct dgsh_node) * chosen_mb->n_nodes);\n\tmemcpy(&chosen_mb->node_array[chosen_mb->n_nodes - 1], &new,\n\t\tsizeof(struct dgsh_node));\n\tck_assert_int_eq(try_add_dgsh_edge(), OP_SUCCESS);\n\n\t/* New edge: from existing to new node */\n\t/* Better in a setup function. */ \n\tchosen_mb->origin_fd_direction = STDOUT_FILENO;   \n\tchosen_mb->origin_index = 0;\n\t/* self_node_io_side should also be set; it is set in setup */\n\tself_node_io_side.index = new.index;\n\tself_node_io_side.fd_direction = STDIN_FILENO;\n\tck_assert_int_eq(try_add_dgsh_edge(), OP_SUCCESS);\n\n\t/* NOOP: message block created just now */\n\tchosen_mb->origin_index = -1;\n\tck_assert_int_eq(try_add_dgsh_edge(), OP_NOOP);\n}\nEND_TEST\n\nSTART_TEST(test_add_edge)\n{\n\tstruct dgsh_edge new;\n\tnew.from = 2;\n\tnew.to = 3;\n\tnew.instances = 0;\n\tck_assert_int_eq(add_edge(&new), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->n_edges, 6);\n}\nEND_TEST\n\nSTART_TEST(test_fill_dgsh_edge)\n{\n\tstruct dgsh_edge new;\n\t/* STDIN -> STDOUT */\n\t/* Better in a setup function. */ \n\tchosen_mb->origin_fd_direction = STDOUT_FILENO;   \n\tchosen_mb->origin_index = 0;\n\t/* self_node_io_side should also be set; it is set in setup */\n\tck_assert_int_eq(fill_dgsh_edge(&new), OP_SUCCESS);\n\t\n\t/* Impossible case. No such origin. */\n\tchosen_mb->origin_index = 7;\n\tck_assert_int_eq(fill_dgsh_edge(&new), OP_ERROR);\n\t\n\t/* STDOUT -> STDIN */\n\tchosen_mb->origin_fd_direction = STDIN_FILENO;   \n\tchosen_mb->origin_index = 3;\n\tmemcpy(&self_node, &chosen_mb->node_array[0], sizeof(struct dgsh_node));\n\tself_node_io_side.fd_direction = STDOUT_FILENO;   \n\tself_node_io_side.index = 0;\n\t/* self_node_io_side should also be set; it is set in setup */\n\tck_assert_int_eq(fill_dgsh_edge(&new), OP_SUCCESS);\n\t\n}\nEND_TEST\n\nSTART_TEST(test_lookup_dgsh_edge)\n{\n\tstruct dgsh_edge new;\n\tnew.from = 2;\n\tnew.to = 3;\n\tck_assert_int_eq(lookup_dgsh_edge(&new), OP_CREATE);\n\tck_assert_int_eq(lookup_dgsh_edge(&chosen_mb->edge_array[4]), OP_EXISTS);\n}\nEND_TEST\n\nSTART_TEST(test_add_node)\n{\n\tstruct dgsh_node new;\n\tnew.pid = 104;\n\tmemcpy(new.name, \"proc4\", 6);\n\tnew.requires_channels = 1;\n\tnew.provides_channels = 1;\n\tmemcpy(&self_node, &new, sizeof(struct dgsh_node));\n\tck_assert_int_eq(add_node(), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->n_nodes, 5);\n\tck_assert_int_eq(self_node_io_side.index, 4);\n\tck_assert_int_eq(self_node.index, 4);\n}\nEND_TEST\n\nSTART_TEST(test_construct_message_block)\n{\n\tDPRINTF(4, \"%s()\", __func__);\n\tint pid = 7;\n\tconst char tool_name[10] = \"test\";\n\tck_assert_int_eq(construct_message_block(tool_name, pid), OP_SUCCESS);\n\tck_assert_int_eq(chosen_mb->version, 1);\n        ck_assert_int_eq((long)chosen_mb->node_array, 0);\n        ck_assert_int_eq(chosen_mb->n_nodes, 0);\n        ck_assert_int_eq(chosen_mb->initiator_pid, pid);\n        ck_assert_int_eq(chosen_mb->state, PS_NEGOTIATION);\n        ck_assert_int_eq(chosen_mb->origin_index, -1);\n        ck_assert_int_eq(chosen_mb->origin_fd_direction, -1);\n\tfree(chosen_mb);\n}\nEND_TEST\n\nSTART_TEST(test_get_env_var)\n{\n\tDPRINTF(4, \"%s()...\", __func__);\n\tint value = -1;\n\tputenv(\"DGSH_IN=0\");\n\tget_env_var(\"DGSH_IN\", &value);\n\tck_assert_int_eq(value, 0);\n\n\tvalue = -1;\n\tputenv(\"DGSH_OUT=1\");\n\tget_env_var(\"DGSH_OUT\", &value);\n\tck_assert_int_eq(value, 1);\n}\nEND_TEST\n\n\nSTART_TEST(test_get_environment_vars)\n{\n\tDPRINTF(4, \"%s()...\", __func__);\n\tputenv(\"DGSH_IN=0\");\n\tputenv(\"DGSH_OUT=1\");\n\n\tget_environment_vars();\n\tck_assert_int_eq(self_node.dgsh_in, 0);\n\tck_assert_int_eq(self_node.dgsh_out, 1);\n\n}\nEND_TEST\n\nSTART_TEST(test_validate_input)\n{\n\tint i = 0;\n\tint o = 0;\n\tck_assert_int_eq(validate_input(&i, &o, NULL), OP_ERROR); \n\tck_assert_int_eq(validate_input(NULL, &o, \"test\"), OP_SUCCESS); \n\tck_assert_int_eq(validate_input(&i, NULL, \"test\"), OP_SUCCESS); \n\tck_assert_int_eq(validate_input(NULL, NULL, \"test\"), OP_SUCCESS); \n\tck_assert_int_eq(validate_input(&i, &o, \"test\"), OP_SUCCESS);\n\ti = 0;\n\to = 1;\n\tck_assert_int_eq(validate_input(&i, &o, \"test\"), OP_SUCCESS);\n\ti = 1;\n\to = 0;\n\tck_assert_int_eq(validate_input(&i, &o, \"test\"), OP_SUCCESS);\n\ti = -1;\n\to = -1;\n\tck_assert_int_eq(validate_input(&i, &o, \"test\"), OP_SUCCESS);\n\ti = -2;\n\to = -1;\n\tck_assert_int_eq(validate_input(&i, &o, \"test\"), OP_ERROR);\n\ti = -1;\n\to = -2;\n\tck_assert_int_eq(validate_input(&i, &o, \"test\"), OP_ERROR);\n\ti = 1000;\n\to = 1000;\n\tck_assert_int_eq(validate_input(&i, &o, \"test\"), OP_SUCCESS);\n}\nEND_TEST\n\nSTART_TEST(test_set_fds)\n{\n\t/* For node 3 which is a terminal node */\n\tfd_set read_fds, write_fds;\n\tck_assert_int_eq(set_fds(&read_fds, &write_fds, 0), 2);\n\tck_assert_int_eq(self_node_io_side.fd_direction, STDIN_FILENO);\n\tck_assert_int_eq(set_fds(&read_fds, &write_fds, 1), 2);\n\tck_assert_int_eq(self_node_io_side.fd_direction, STDIN_FILENO);\n\n\t/* Make node 1 self node, which is a non terminal node */\n\tmemcpy(&self_node, &chosen_mb->node_array[1], sizeof(struct dgsh_node));\n\tck_assert_int_eq(set_fds(&read_fds, &write_fds, 0), 2);\n\tck_assert_int_eq(self_node_io_side.fd_direction, STDOUT_FILENO);\n\tck_assert_int_eq(set_fds(&read_fds, &write_fds, 1), 2);\n}\nEND_TEST\n\nSTART_TEST(test_dgsh_negotiate)\n{\n\tint *input_fds;\n\tint n_input_fds = 0;\n\tint *output_fds;\n\tint n_output_fds = 0;\n\tck_assert_int_eq(dgsh_negotiate(0, \"test\", &n_input_fds, &n_output_fds,\n\t\t\t\t&input_fds, &output_fds), 0);\n}\nEND_TEST\n\n/* Suite conc */\nSTART_TEST(test_is_ready)\n{\n\tchosen_mb->state = PS_RUN;\n\tck_assert_int_eq(is_ready(3, chosen_mb), true);\n\n\tck_assert_int_eq(is_ready(1, chosen_mb), false);\n\n\tck_assert_int_eq(is_ready(0, chosen_mb), false);\n\tck_assert_int_eq(pi[0].seen, false);\n\tck_assert_int_eq(pi[1].written, false);\n\tck_assert_int_eq(pi[1].run_ready, false);\n}\nEND_TEST\n\nSTART_TEST (test_next_fd)\n{\n\tmultiple_inputs = true;\n\tnfd = 5;\n\tbool ro = false;\t\t/* restore origin */\n\tck_assert_int_eq(next_fd(0, &ro), 1);\n\tck_assert_int_eq(ro, false);\n\tck_assert_int_eq(next_fd(1, &ro), 0);\n\tck_assert_int_eq(ro, false);\n\tck_assert_int_eq(next_fd(4, &ro), 4);\n\tck_assert_int_eq(ro, true);\n\tro = false;\n\tck_assert_int_eq(next_fd(3, &ro), 3);\n\tck_assert_int_eq(ro, true);\n\n\tmultiple_inputs = false;\n\tnoinput = false;\n\tro = false;\n\tck_assert_int_eq(next_fd(0, &ro), 1);\n\tck_assert_int_eq(ro, false);\n\tck_assert_int_eq(next_fd(1, &ro), 3);\n\tck_assert_int_eq(ro, true);\n\tro = false;\n\tck_assert_int_eq(next_fd(3, &ro), 4);\n\tck_assert_int_eq(ro, true);\n\tro = false;\n\tck_assert_int_eq(next_fd(4, &ro), 0);\n\tck_assert_int_eq(ro, false);\n\n\tnoinput = true;\n\tro = false;\n\tck_assert_int_eq(next_fd(1, &ro), 3);\n\tck_assert_int_eq(ro, false);\n\tck_assert_int_eq(next_fd(3, &ro), 4);\n\tck_assert_int_eq(ro, false);\n\tck_assert_int_eq(next_fd(4, &ro), 1);\n\tck_assert_int_eq(ro, false);\n}\nEND_TEST\n\nSTART_TEST(test_set_io_channels)\n{\n\tpid = 2000;\t/* static in dgsh-conc.c */\n\tnfd = 4;\t/* ditto */\n\tmultiple_inputs = false;\t/* ditto */\n\tck_assert_int_eq(set_io_channels(chosen_mb), 0);\n\tck_assert_int_eq(chosen_mb->n_concs, 1);\n\tck_assert_int_eq(chosen_mb->conc_array[0].pid, 2000);\n\tck_assert_int_eq(chosen_mb->conc_array[0].input_fds, -1);\n\tck_assert_int_eq(chosen_mb->conc_array[0].output_fds, -1);\n\tck_assert_int_eq(chosen_mb->conc_array[0].multiple_inputs, false);\n\tck_assert_int_eq(chosen_mb->conc_array[0].n_proc_pids, 2);\n\tck_assert_int_eq(chosen_mb->conc_array[0].proc_pids[0], 100);\n\tck_assert_int_eq(chosen_mb->conc_array[0].proc_pids[1], 103);\n\n\t/* Exists with channels set: keep as it is */\n\tck_assert_int_eq(set_io_channels(chosen_mb), 0);\n\tck_assert_int_eq(chosen_mb->n_concs, 1);\n\tck_assert_int_eq(chosen_mb->conc_array[0].pid, 2000);\n\tck_assert_int_eq(chosen_mb->conc_array[0].input_fds, -1);\n\tck_assert_int_eq(chosen_mb->conc_array[0].output_fds, -1);\n\n\t/* Not exists: set channels (same pi, same channels as before */\n\tpid = 2001;\t/* static in dgsh-conc.c */\n\tmultiple_inputs = true;\n\tck_assert_int_eq(set_io_channels(chosen_mb), 0);\n\tck_assert_int_eq(chosen_mb->n_concs, 2);\n\tDPRINTF(4, \"%d\", chosen_mb->conc_array[0].pid);\n\tck_assert_int_eq(chosen_mb->conc_array[1].pid, 2001);\n\tck_assert_int_eq(chosen_mb->conc_array[1].input_fds, -1);\n\tck_assert_int_eq(chosen_mb->conc_array[1].output_fds, -1);\n\tck_assert_int_eq(chosen_mb->conc_array[1].multiple_inputs, true);\n\tck_assert_int_eq(chosen_mb->conc_array[1].n_proc_pids, 2);\n\tck_assert_int_eq(chosen_mb->conc_array[1].proc_pids[0], 101);\n\tck_assert_int_eq(chosen_mb->conc_array[1].proc_pids[1], 103);\n}\nEND_TEST\n\nSuite *\nsuite_connect(void)\n{\n\tSuite *s = suite_create(\"Connect\");\n\n\tTCase *tc_aiof = tcase_create(\"alloc io fds\");\n\ttcase_add_checked_fixture(tc_aiof, setup_test_alloc_io_fds,\n\t\t\t\t\t  retire_test_alloc_io_fds);\n\ttcase_add_test(tc_aiof, test_alloc_io_fds);\n\tsuite_add_tcase(s, tc_aiof);\n\n\tTCase *tc_af = tcase_create(\"alloc fds\");\n\ttcase_add_checked_fixture(tc_af, NULL, NULL);\n\ttcase_add_test(tc_af, test_alloc_fds);\n\tsuite_add_tcase(s, tc_af);\n\n\tTCase *tc_trw = tcase_create(\"test read/write fd\");\n\ttcase_add_checked_fixture(tc_trw, NULL, NULL);\n\ttcase_add_test(tc_trw, test_read_write_fd);\n\tsuite_add_tcase(s, tc_trw);\n\n\tTCase *tc_rif = tcase_create(\"read input fds\");\n\ttcase_add_checked_fixture(tc_rif, setup_test_read_input_fds,\n\t\t\t\t\t  retire_test_read_input_fds);\n\ttcase_add_test(tc_rif, test_read_input_fds);\n\tsuite_add_tcase(s, tc_rif);\n\n\tTCase *tc_gop = tcase_create(\"get origin pid\");\n\ttcase_add_checked_fixture(tc_gop, setup_test_get_origin_pid,\n\t\t\t\t\t  retire_test_get_origin_pid);\n\ttcase_add_test(tc_gop, test_get_origin_pid);\n\tsuite_add_tcase(s, tc_gop);\n\n\tTCase *tc_gefn = tcase_create(\"get expected fds number\");\n\ttcase_add_checked_fixture(tc_gefn, setup_test_get_expected_fds_n,\n\t\t\t\t\t  retire_test_get_expected_fds_n);\n\ttcase_add_test(tc_gefn, test_get_expected_fds_n);\n\tsuite_add_tcase(s, tc_gefn);\n\n\tTCase *tc_gpfn = tcase_create(\"get provided fds number\");\n\ttcase_add_checked_fixture(tc_gpfn, setup_test_get_provided_fds_n,\n\t\t\t\t\t  retire_test_get_provided_fds_n);\n\ttcase_add_test(tc_gpfn, test_get_provided_fds_n);\n\tsuite_add_tcase(s, tc_gpfn);\n\n\tTCase *tc_eic = tcase_create(\"establish io connections\");\n\ttcase_add_checked_fixture(tc_eic, setup_test_establish_io_connections,\n\t\t\t\t\t  retire_test_establish_io_connections);\n\ttcase_add_test(tc_eic, test_establish_io_connections);\n\tsuite_add_tcase(s, tc_eic);\n\n\tTCase *tc_anc = tcase_create(\"alloc node connections\");\n\ttcase_add_checked_fixture(tc_anc, NULL, NULL);\n\ttcase_add_test(tc_anc, test_alloc_node_connections);\n\tsuite_add_tcase(s, tc_anc);\n\n\tTCase *tc_sd = tcase_create(\"set dispatcher\");\n\ttcase_add_checked_fixture(tc_sd, setup_test_set_dispatcher,\n\t\t\t\t\t retire_test_set_dispatcher);\n\ttcase_add_test(tc_sd, test_set_dispatcher);\n\tsuite_add_tcase(s, tc_sd);\n\n\t/* Need to also simulate sendmsg; make sure it works. */\n\tTCase *tc_awof = tcase_create(\"write output fds\");\n\ttcase_add_checked_fixture(tc_awof, setup_test_write_output_fds,\n\t\t\t\t\t   retire_test_write_output_fds);\n\ttcase_add_test(tc_awof, test_write_output_fds);\n\tsuite_add_tcase(s, tc_awof);\n\n\treturn s;\n}\n\nSuite *\nsuite_solve(void)\n{\n\tSuite *s = suite_create(\"Solve\");\n\n\tTCase *tc_wc = tcase_create(\"write concs\");\n\ttcase_add_checked_fixture(tc_wc, setup_test_write_concs,\n\t\t\t\t\t  retire_test_write_concs);\n\ttcase_add_test(tc_wc, test_write_concs);\n\tsuite_add_tcase(s, tc_wc);\n\n\tTCase *tc_rc = tcase_create(\"read concs\");\n\ttcase_add_checked_fixture(tc_rc, setup_test_read_concs,\n\t\t\t\t\t  retire_test_read_concs);\n\ttcase_add_test(tc_rc, test_read_concs);\n\tsuite_add_tcase(s, tc_rc);\n\n\tTCase *tc_rgs = tcase_create(\"read graph solution\");\n\ttcase_add_checked_fixture(tc_rgs, setup_test_read_graph_solution,\n\t\t\t\t\t  retire_test_read_graph_solution);\n\ttcase_add_test(tc_rgs, test_read_graph_solution);\n\tsuite_add_tcase(s, tc_rgs);\n\n\tTCase *tc_wgs = tcase_create(\"write graph solution\");\n\ttcase_add_checked_fixture(tc_wgs, setup_test_write_graph_solution,\n\t\t\t\t\t  retire_test_write_graph_solution);\n\ttcase_add_test(tc_wgs, test_write_graph_solution);\n\tsuite_add_tcase(s, tc_wgs);\n\n\tTCase *tc_ssg = tcase_create(\"solve dgsh graph\");\n\ttcase_add_checked_fixture(tc_ssg, setup_test_solve_graph,\n\t\t\t\t\t  retire_test_solve_graph);\n\ttcase_add_test(tc_ssg, test_solve_graph);\n\tsuite_add_tcase(s, tc_ssg);\n\n\tTCase *tc_ccf = tcase_create(\"calculate conc fds\");\n\ttcase_add_checked_fixture(tc_ccf, setup_test_calculate_conc_fds,\n\t\t\t\t\t  retire_test_calculate_conc_fds);\n\ttcase_add_test(tc_ccf, test_calculate_conc_fds);\n\tsuite_add_tcase(s, tc_ccf);\n\n\tTCase *tc_fgs = tcase_create(\"free graph solution\");\n\ttcase_add_checked_fixture(tc_fgs, setup_test_free_graph_solution,\n\t\t\t\t\t  retire_test_free_graph_solution);\n\ttcase_add_test(tc_fgs, test_free_graph_solution);\n\tsuite_add_tcase(s, tc_fgs);\n\n\tTCase *tc_nmc = tcase_create(\"node match constraints\");\n\ttcase_add_checked_fixture(tc_nmc, setup_test_node_match_constraints,\n\t\t\t\t\t  retire_test_node_match_constraints);\n\ttcase_add_test(tc_nmc, test_node_match_constraints);\n\tsuite_add_tcase(s, tc_nmc);\n\n\tTCase *tc_dmic = tcase_create(\"dry match io constraints\");\n\ttcase_add_checked_fixture(tc_dmic, setup_test_dry_match_io_constraints,\n\t\t\t\t\t  retire_test_dry_match_io_constraints);\n\ttcase_add_test(tc_dmic, test_dry_match_io_constraints);\n\tsuite_add_tcase(s, tc_dmic);\n\n\tTCase *tc_sic = tcase_create(\"satisfy io constraints\");\n\ttcase_add_checked_fixture(tc_sic, setup_test_satisfy_io_constraints,\n\t\t\t\t\t  retire_test_satisfy_io_constraints);\n\ttcase_add_test(tc_sic, test_satisfy_io_constraints);\n\tsuite_add_tcase(s, tc_sic);\n\n\tTCase *tc_mov = tcase_create(\"move\");\n\ttcase_add_checked_fixture(tc_mov, setup_test_move, retire_test_move);\n\ttcase_add_test(tc_mov, test_move);\n\tsuite_add_tcase(s, tc_mov);\n\n\tTCase *tc_rmf = tcase_create(\"record move flexible\");\n\ttcase_add_checked_fixture(tc_rmf, NULL, NULL);\n\ttcase_add_test(tc_rmf, test_record_move_flexible);\n\tsuite_add_tcase(s, tc_rmf);\n\n\tTCase *tc_rmu = tcase_create(\"record move unbalanced\");\n\ttcase_add_checked_fixture(tc_rmu, NULL, NULL);\n\ttcase_add_test(tc_rmu, test_record_move_unbalanced);\n\tsuite_add_tcase(s, tc_rmu);\n\n\t/*TCase *tc_ec = tcase_create(\"evaluate constraints\");\n\ttcase_add_checked_fixture(tc_ec, setup_test_eval_constraints,\n\t\t\t\t\t retire_test_eval_constraints);\n\ttcase_add_test(tc_ec, test_eval_constraints);\n\tsuite_add_tcase(s, tc_ec);\n\n\t*TCase *tc_aei = tcase_create(\"assign edge instances\");\n\ttcase_add_checked_fixture(tc_aei, setup_test_assign_edge_instances,\n\t\t\t\t\t  retire_test_assign_edge_instances);\n\ttcase_add_test(tc_aei, test_assign_edge_instances);\n\tsuite_add_tcase(s, tc_aei);\n*/\n\tTCase *tc_repa = tcase_create(\"reallocate edge pointer array\");\n\ttcase_add_checked_fixture(tc_repa,\n\t\t\t\tsetup_test_reallocate_edge_pointer_array,\n\t\t\t\tretire_test_reallocate_edge_pointer_array);\n\ttcase_add_test(tc_repa, test_reallocate_edge_pointer_array);\n\tsuite_add_tcase(s, tc_repa);\n\n\tTCase *tc_mcea = tcase_create(\"make compact edge array\");\n\ttcase_add_checked_fixture(tc_mcea, setup_test_make_compact_edge_array,\n\t\t\t\t\t   retire_test_make_compact_edge_array);\n\ttcase_add_test(tc_mcea, test_make_compact_edge_array);\n\tsuite_add_tcase(s, tc_mcea);\n\n\treturn s;\n}\n\nSuite *\nsuite_broadcast(void)\n{\n\tSuite *s = suite_create(\"Broadcast\");\n\n\tTCase *tc_wmb = tcase_create(\"write message block\");\n\ttcase_add_checked_fixture(tc_wmb, setup_test_write_message_block,\n\t\t\t\t\t  retire_test_write_message_block);\n\ttcase_add_test(tc_wmb, test_write_message_block);\n\tsuite_add_tcase(s, tc_wmb);\n\n\tTCase *tc_trm = tcase_create(\"read message block\");\n\ttcase_add_checked_fixture(tc_trm, setup_test_read_message_block,\n\t\t\t\t\t  retire_test_read_message_block);\n\ttcase_add_test(tc_trm, test_read_message_block);\n\tsuite_add_tcase(s, tc_trm);\n\n\tTCase *tc_trc = tcase_create(\"read chunk\");\n\ttcase_add_checked_fixture(tc_trc, setup_test_read_chunk, NULL);\n\ttcase_add_test(tc_trc, test_read_chunk);\n\tsuite_add_tcase(s, tc_trc);\n\n\tTCase *tc_clr = tcase_create(\"call read\");\n\ttcase_add_checked_fixture(tc_clr, NULL, NULL);\n\ttcase_add_test(tc_clr, test_call_read);\n\tsuite_add_tcase(s, tc_clr);\n\n\tTCase *tc_acm = tcase_create(\"alloc copy message block\");\n\ttcase_add_checked_fixture(tc_acm, NULL, NULL);\n\ttcase_add_test(tc_acm, test_alloc_copy_mb);\n\tsuite_add_tcase(s, tc_acm);\n\n\tTCase *tc_acn = tcase_create(\"alloc copy nodes\");\n\ttcase_add_checked_fixture(tc_acn, setup_test_alloc_copy_nodes,\n\t\t\t\t\t  retire_test_alloc_copy_nodes);\n\ttcase_add_test(tc_acn, test_alloc_copy_nodes);\n\tsuite_add_tcase(s, tc_acn);\n\n\tTCase *tc_ace = tcase_create(\"alloc copy edges\");\n\ttcase_add_checked_fixture(tc_ace, setup_test_alloc_copy_edges,\n\t\t\t\t\t  retire_test_alloc_copy_edges);\n\ttcase_add_test(tc_ace, test_alloc_copy_edges);\n\tsuite_add_tcase(s, tc_ace);\n\n\tTCase *tc_acg = tcase_create(\"alloc copy graph solution\");\n\ttcase_add_checked_fixture(tc_acg, setup_test_alloc_copy_graph_solution,\n\t\t\t\tretire_test_alloc_copy_graph_solution);\n\ttcase_add_test(tc_acg, test_alloc_copy_graph_solution);\n\tsuite_add_tcase(s, tc_acg);\n\n\tTCase *tc_acc = tcase_create(\"alloc copy concs\");\n\ttcase_add_checked_fixture(tc_acc, setup_test_alloc_copy_concs,\n\t\t\t\tretire_test_alloc_copy_concs);\n\ttcase_add_test(tc_acc, test_alloc_copy_concs);\n\tsuite_add_tcase(s, tc_acc);\n\n\tTCase *tc_acp = tcase_create(\"alloc copy proc pids\");\n\ttcase_add_test(tc_acp, test_alloc_copy_proc_pids);\n\tsuite_add_tcase(s, tc_acp);\n\n\tTCase *tc_cr = tcase_create(\"check read\");\n\ttcase_add_checked_fixture(tc_cr, NULL, NULL);\n\ttcase_add_test(tc_cr, test_check_read);\n\tsuite_add_tcase(s, tc_cr);\n/*\n\t*TCase *tc_pid = tcase_create(\"point io direction\");\n\ttcase_add_checked_fixture(tc_pid, setup_test_point_io_direction,\n\t\t\t\t\t  retire_test_point_io_direction);\n\ttcase_add_test(tc_pid, test_point_io_direction);\n\tsuite_add_tcase(s, tc_pid);\n*/\n\n\tTCase *tc_ar = tcase_create(\"analyse read\");\n\ttcase_add_checked_fixture(tc_ar, setup_test_analyse_read,\n\t\t\t\t\t  retire_test_analyse_read);\n\ttcase_add_test(tc_ar, test_analyse_read);\n\tsuite_add_tcase(s, tc_ar);\n\n\tTCase *tc_fm = tcase_create(\"free message block\");\n\ttcase_add_checked_fixture(tc_fm, setup_test_free_mb, NULL);\n\ttcase_add_test(tc_fm, test_free_mb);\n\tsuite_add_tcase(s, tc_fm);\n\n\tTCase *tc_fsn = tcase_create(\"fill dgsh node\");\n\ttcase_add_checked_fixture(tc_fsn, setup_test_fill_node, NULL);\n\ttcase_add_test(tc_fsn, test_fill_node);\n\tsuite_add_tcase(s, tc_fsn);\n\n\tTCase *tc_tasn = tcase_create(\"try add dgsh node\");\n\ttcase_add_checked_fixture(tc_tasn, setup_test_try_add_dgsh_node,\n\t\t\t\t\t   retire_test_try_add_dgsh_node);\n\ttcase_add_test(tc_tasn, test_try_add_dgsh_node);\n\tsuite_add_tcase(s, tc_tasn);\n\n\tTCase *tc_tase = tcase_create(\"try add dgsh edge\");\n\ttcase_add_checked_fixture(tc_tase, setup_test_try_add_dgsh_edge,\n\t\t\t\t\t   retire_test_try_add_dgsh_edge);\n\ttcase_add_test(tc_tase, test_try_add_dgsh_edge);\n\tsuite_add_tcase(s, tc_tase);\n\n\tTCase *tc_ae = tcase_create(\"add edge\");\n\ttcase_add_checked_fixture(tc_ae, setup_test_add_edge,\n\t\t\t\t\t retire_test_add_edge);\n\ttcase_add_test(tc_ae, test_add_edge);\n\tsuite_add_tcase(s, tc_ae);\n\n\tTCase *tc_fse = tcase_create(\"fill dgsh edge\");\n\ttcase_add_checked_fixture(tc_fse, setup_test_fill_dgsh_edge,\n\t\t\t\t\t retire_test_fill_dgsh_edge);\n\ttcase_add_test(tc_fse, test_fill_dgsh_edge);\n\tsuite_add_tcase(s, tc_fse);\n\n\tTCase *tc_lse = tcase_create(\"lookup dgsh edge\");\n\ttcase_add_checked_fixture(tc_lse, setup_test_lookup_dgsh_edge,\n\t\t\t\t\t retire_test_lookup_dgsh_edge);\n\ttcase_add_test(tc_lse, test_lookup_dgsh_edge);\n\tsuite_add_tcase(s, tc_lse);\n\n\tTCase *tc_an = tcase_create(\"add node\");\n\ttcase_add_checked_fixture(tc_an, setup_test_add_node,\n\t\t\t\t\t retire_test_add_node);\n\ttcase_add_test(tc_an, test_add_node);\n\tsuite_add_tcase(s, tc_an);\n\n\tTCase *tc_cnmb = tcase_create(\"construct message block\");\n\ttcase_add_checked_fixture(tc_cnmb, NULL, NULL);\n\ttcase_add_test(tc_cnmb, test_construct_message_block);\n\tsuite_add_tcase(s, tc_cnmb);\n\n\tTCase *tc_gev = tcase_create(\"get environment variable\");\n\ttcase_add_checked_fixture(tc_gev, NULL, NULL);\n\ttcase_add_test(tc_gev, test_get_env_var);\n\tsuite_add_tcase(s, tc_gev);\n\n\tTCase *tc_gevs = tcase_create(\"get environment variables\");\n\ttcase_add_checked_fixture(tc_gevs, NULL, NULL);\n\ttcase_add_test(tc_gevs, test_get_environment_vars);\n\tsuite_add_tcase(s, tc_gevs);\n\n\tTCase *tc_vi = tcase_create(\"validate input\");\n\ttcase_add_checked_fixture(tc_vi, NULL, NULL);\n\ttcase_add_test(tc_vi, test_validate_input);\n\tsuite_add_tcase(s, tc_vi);\n\n\tTCase *tc_sf = tcase_create(\"set fds\");\n\ttcase_add_checked_fixture(tc_sf, setup_test_set_fds, retire_test_set_fds);\n\ttcase_add_test(tc_sf, test_set_fds);\n\tsuite_add_tcase(s, tc_sf);\n\n\tTCase *tc_sn = tcase_create(\"dgsh negotiate\");\n\ttcase_add_checked_fixture(tc_sn, setup, retire);\n\ttcase_add_test(tc_sn, test_dgsh_negotiate);\n\tsuite_add_tcase(s, tc_sn);\n\n\treturn s;\n}\n\nSuite *\nsuite_conc(void)\n{\n\tSuite *s = suite_create(\"Concentrator\");\n\tTCase *tc_tn = tcase_create(\"test next_fd\");\n\tTCase *tc_ir = tcase_create(\"test is_ready\");\n\tTCase *tc_si = tcase_create(\"set io\");\n\tTCase *tc_sich = tcase_create(\"set io channels\");\n\n\ttcase_add_checked_fixture(tc_tn, NULL, NULL);\n\ttcase_add_test(tc_tn, test_next_fd);\n\tsuite_add_tcase(s, tc_tn);\n\ttcase_add_checked_fixture(tc_ir, setup_test_is_ready,\n\t\t\tretire_test_is_ready);\n\ttcase_add_test(tc_ir, test_is_ready);\n\tsuite_add_tcase(s, tc_ir);\n\ttcase_add_checked_fixture(tc_sich, setup_test_set_io_channels,\n\t\t\t\t\t  retire_test_set_io_channels);\n\ttcase_add_test(tc_sich, test_set_io_channels);\n\tsuite_add_tcase(s, tc_sich);\n\n\treturn s;\n}\n\nint run_suite(Suite *s)\n{\n\tint number_failed;\n\tSRunner *sr = srunner_create(s);\n\tsrunner_run_all(sr, CK_VERBOSE);\n\tnumber_failed = srunner_ntests_failed(sr);\n\tsrunner_free(sr);\n\treturn (number_failed == 0) ? 1 : 0;\n}\n\nint\nrun_suite_connect(void)\n{\n\tSuite *s = suite_connect();\n\treturn run_suite(s);\n}\n\nint\nrun_suite_solve(void)\n{\n\tSuite *s = suite_solve();\n\treturn run_suite(s);\n}\n\nint\nrun_suite_broadcast(void)\n{\n\tSuite *s = suite_broadcast();\n\treturn run_suite(s);\n}\n\nint\nrun_suite_conc(void)\n{\n\tSuite *s = suite_conc();\n\treturn run_suite(s);\n}\n\n/* Output is not appropriate; only pass fail. */\nint main()\n{\n\tint failed_neg, failed_sol, failed_conn, failed_conc;\n\tfailed_neg = run_suite_broadcast();\n\tfailed_sol = run_suite_solve();\n\tfailed_conn = run_suite_connect();\n\tfailed_conc = run_suite_conc();\n\treturn (failed_neg && failed_sol && failed_conn && failed_conc) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "core-tools/tests-regression/.gitignore",
    "content": "test/\n"
  },
  {
    "path": "core-tools/tests-regression/author-compare/out.ok",
    "content": "conf/icse/ papers: 219\njournals/software/ papers: 182\nAuthors only in conf/icse/: 547\nAuthors only in journals/software/: 299\nAuthors common in both venues: 22\n"
  },
  {
    "path": "core-tools/tests-regression/bin/gdate",
    "content": "#!/bin/sh\n#\n# Poor man's GNU date\n# This implements the GNU date -f - option for converting the date as\n# represented in the web log into the week day using the FreeBSD\n# date command\n#\n\nif [ x\"$*\" != x'-f - +%a' ]\nthen\n\techo \"(poor man's) gdate usage: gdate -f - +%a\" 1>&2\n\texit 1\nfi\n\nwhile read d\ndo\n\tdate -j -f '%d-%b-%Y' \"$d\" +%a\ndone\n"
  },
  {
    "path": "core-tools/tests-regression/code-metrics/in/date/date.c",
    "content": "/*-\n * Copyright (c) 1985, 1987, 1988, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#ifndef lint\nstatic char const copyright[] =\n\"@(#) Copyright (c) 1985, 1987, 1988, 1993\\n\\\n\tThe Regents of the University of California.  All rights reserved.\\n\";\n#endif /* not lint */\n\n#if 0\n#ifndef lint\nstatic char sccsid[] = \"@(#)date.c\t8.2 (Berkeley) 4/28/95\";\n#endif /* not lint */\n#endif\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/bin/date/date.c,v 1.48.2.1.8.2 2012/11/17 08:24:31 svnexp Exp $\");\n\n#include <sys/param.h>\n#include <sys/time.h>\n\n#include <ctype.h>\n#include <err.h>\n#include <locale.h>\n#include <libutil.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <syslog.h>\n#include <unistd.h>\n\n#include \"extern.h\"\n#include \"vary.h\"\n\n#ifndef\tTM_YEAR_BASE\n#define\tTM_YEAR_BASE\t1900\n#endif\n\nstatic time_t tval;\nint retval;\n\nstatic void setthetime(const char *, const char *, int, int);\nstatic void badformat(void);\nstatic void usage(void);\n\nint\nmain(int argc, char *argv[])\n{\n\tstruct timezone tz;\n\tint ch, rflag;\n\tint jflag, nflag;\n\tconst char *format;\n\tchar buf[1024];\n\tchar *endptr, *fmt;\n\tchar *tmp;\n\tint set_timezone;\n\tstruct vary *v;\n\tconst struct vary *badv;\n\tstruct tm lt;\n\n\tv = NULL;\n\tfmt = NULL;\n\t(void) setlocale(LC_TIME, \"\");\n\ttz.tz_dsttime = tz.tz_minuteswest = 0;\n\trflag = 0;\n\tjflag = nflag = 0;\n\tset_timezone = 0;\n\twhile ((ch = getopt(argc, argv, \"d:f:jnr:t:uv:\")) != -1)\n\t\tswitch((char)ch) {\n\t\tcase 'd':\t\t/* daylight savings time */\n\t\t\ttz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;\n\t\t\tif (endptr == optarg || *endptr != '\\0')\n\t\t\t\tusage();\n\t\t\tset_timezone = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tfmt = optarg;\n\t\t\tbreak;\n\t\tcase 'j':\n\t\t\tjflag = 1;\t/* don't set time */\n\t\t\tbreak;\n\t\tcase 'n':\t\t/* don't set network */\n\t\t\tnflag = 1;\n\t\t\tbreak;\n\t\tcase 'r':\t\t/* user specified seconds */\n\t\t\trflag = 1;\n\t\t\ttval = strtoq(optarg, &tmp, 0);\n\t\t\tif (*tmp != 0)\n\t\t\t\tusage();\n\t\t\tbreak;\n\t\tcase 't':\t\t/* minutes west of UTC */\n\t\t\t\t\t/* error check; don't allow \"PST\" */\n\t\t\ttz.tz_minuteswest = strtol(optarg, &endptr, 10);\n\t\t\tif (endptr == optarg || *endptr != '\\0')\n\t\t\t\tusage();\n\t\t\tset_timezone = 1;\n\t\t\tbreak;\n\t\tcase 'u':\t\t/* do everything in UTC */\n\t\t\t(void)setenv(\"TZ\", \"UTC0\", 1);\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tv = vary_append(v, optarg);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\targc -= optind;\n\targv += optind;\n\n\t/*\n\t * If -d or -t, set the timezone or daylight savings time; this\n\t * doesn't belong here; the kernel should not know about either.\n\t */\n\tif (set_timezone && settimeofday((struct timeval *)NULL, &tz))\n\t\terr(1, \"settimeofday (timezone)\");\n\n\tif (!rflag && time(&tval) == -1)\n\t\terr(1, \"time\");\n\n\tformat = \"%+\";\n\n\t/* allow the operands in any order */\n\tif (*argv && **argv == '+') {\n\t\tformat = *argv + 1;\n\t\t++argv;\n\t}\n\n\tif (*argv) {\n\t\tsetthetime(fmt, *argv, jflag, nflag);\n\t\t++argv;\n\t} else if (fmt != NULL)\n\t\tusage();\n\n\tif (*argv && **argv == '+')\n\t\tformat = *argv + 1;\n\n\tlt = *localtime(&tval);\n\tbadv = vary_apply(v, &lt);\n\tif (badv) {\n\t\tfprintf(stderr, \"%s: Cannot apply date adjustment\\n\",\n\t\t\tbadv->arg);\n\t\tvary_destroy(v);\n\t\tusage();\n\t}\n\tvary_destroy(v);\n\t(void)strftime(buf, sizeof(buf), format, &lt);\n\t(void)printf(\"%s\\n\", buf);\n\tif (fflush(stdout))\n\t\terr(1, \"stdout\");\n\texit(retval);\n}\n\n#define\tATOI2(s)\t((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))\n\nstatic void\nsetthetime(const char *fmt, const char *p, int jflag, int nflag)\n{\n\tstruct tm *lt;\n\tstruct timeval tv;\n\tconst char *dot, *t;\n\tint century;\n\n\tlt = localtime(&tval);\n\tlt->tm_isdst = -1;\t\t/* divine correct DST */\n\n\tif (fmt != NULL) {\n\t\tt = strptime(p, fmt, lt);\n\t\tif (t == NULL) {\n\t\t\tfprintf(stderr, \"Failed conversion of ``%s''\"\n\t\t\t\t\" using format ``%s''\\n\", p, fmt);\n\t\t\tbadformat();\n\t\t} else if (*t != '\\0')\n\t\t\tfprintf(stderr, \"Warning: Ignoring %ld extraneous\"\n\t\t\t\t\" characters in date string (%s)\\n\",\n\t\t\t\t(long) strlen(t), t);\n\t} else {\n\t\tfor (t = p, dot = NULL; *t; ++t) {\n\t\t\tif (isdigit(*t))\n\t\t\t\tcontinue;\n\t\t\tif (*t == '.' && dot == NULL) {\n\t\t\t\tdot = t;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbadformat();\n\t\t}\n\n\t\tif (dot != NULL) {\t\t\t/* .ss */\n\t\t\tdot++; /* *dot++ = '\\0'; */\n\t\t\tif (strlen(dot) != 2)\n\t\t\t\tbadformat();\n\t\t\tlt->tm_sec = ATOI2(dot);\n\t\t\tif (lt->tm_sec > 61)\n\t\t\t\tbadformat();\n\t\t} else\n\t\t\tlt->tm_sec = 0;\n\n\t\tcentury = 0;\n\t\t/* if p has a \".ss\" field then let's pretend it's not there */\n\t\tswitch (strlen(p) - ((dot != NULL) ? 3 : 0)) {\n\t\tcase 12:\t\t\t\t/* cc */\n\t\t\tlt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE;\n\t\t\tcentury = 1;\n\t\t\t/* FALLTHROUGH */\n\t\tcase 10:\t\t\t\t/* yy */\n\t\t\tif (century)\n\t\t\t\tlt->tm_year += ATOI2(p);\n\t\t\telse {\n\t\t\t\tlt->tm_year = ATOI2(p);\n\t\t\t\tif (lt->tm_year < 69)\t/* hack for 2000 ;-} */\n\t\t\t\t\tlt->tm_year += 2000 - TM_YEAR_BASE;\n\t\t\t\telse\n\t\t\t\t\tlt->tm_year += 1900 - TM_YEAR_BASE;\n\t\t\t}\n\t\t\t/* FALLTHROUGH */\n\t\tcase 8:\t\t\t\t\t/* mm */\n\t\t\tlt->tm_mon = ATOI2(p);\n\t\t\tif (lt->tm_mon > 12)\n\t\t\t\tbadformat();\n\t\t\t--lt->tm_mon;\t\t/* time struct is 0 - 11 */\n\t\t\t/* FALLTHROUGH */\n\t\tcase 6:\t\t\t\t\t/* dd */\n\t\t\tlt->tm_mday = ATOI2(p);\n\t\t\tif (lt->tm_mday > 31)\n\t\t\t\tbadformat();\n\t\t\t/* FALLTHROUGH */\n\t\tcase 4:\t\t\t\t\t/* HH */\n\t\t\tlt->tm_hour = ATOI2(p);\n\t\t\tif (lt->tm_hour > 23)\n\t\t\t\tbadformat();\n\t\t\t/* FALLTHROUGH */\n\t\tcase 2:\t\t\t\t\t/* MM */\n\t\t\tlt->tm_min = ATOI2(p);\n\t\t\tif (lt->tm_min > 59)\n\t\t\t\tbadformat();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbadformat();\n\t\t}\n\t}\n\n\t/* convert broken-down time to GMT clock time */\n\tif ((tval = mktime(lt)) == -1)\n\t\terrx(1, \"nonexistent time\");\n\n\tif (!jflag) {\n\t\t/* set the time */\n\t\tif (nflag || netsettime(tval)) {\n\t\t\tlogwtmp(\"|\", \"date\", \"\");\n\t\t\ttv.tv_sec = tval;\n\t\t\ttv.tv_usec = 0;\n\t\t\tif (settimeofday(&tv, (struct timezone *)NULL))\n\t\t\t\terr(1, \"settimeofday (timeval)\");\n\t\t\tlogwtmp(\"{\", \"date\", \"\");\n\t\t}\n\n\t\tif ((p = getlogin()) == NULL)\n\t\t\tp = \"???\";\n\t\tsyslog(LOG_AUTH | LOG_NOTICE, \"date set by %s\", p);\n\t}\n}\n\nstatic void\nbadformat(void)\n{\n\twarnx(\"illegal time format\");\n\tusage();\n}\n\nstatic void\nusage(void)\n{\n\t(void)fprintf(stderr, \"%s\\n%s\\n\",\n\t    \"usage: date [-jnu] [-d dst] [-r seconds] [-t west] \"\n\t    \"[-v[+|-]val[ymwdHMS]] ... \",\n\t    \"            \"\n\t    \"[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]\");\n\texit(1);\n}\n"
  },
  {
    "path": "core-tools/tests-regression/code-metrics/in/date/extern.h",
    "content": "/*-\n * Copyright (c) 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)extern.h\t8.1 (Berkeley) 5/31/93\n * $FreeBSD: src/bin/date/extern.h,v 1.7.30.1.8.2 2012/11/17 08:24:31 svnexp Exp $\n */\n\nint\tnetsettime(time_t);\n"
  },
  {
    "path": "core-tools/tests-regression/code-metrics/in/date/netdate.c",
    "content": "/*-\n * Copyright (c) 1990, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#if 0\n#ifndef lint\nstatic char sccsid[] = \"@(#)netdate.c\t8.1 (Berkeley) 5/31/93\";\n#endif /* not lint */\n#endif\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/bin/date/netdate.c,v 1.19.10.1.8.2 2012/11/17 08:24:31 svnexp Exp $\");\n\n#include <sys/param.h>\n#include <sys/time.h>\n#include <sys/socket.h>\n\n#include <netinet/in.h>\n#include <netdb.h>\n#define TSPTYPES\n#include <protocols/timed.h>\n\n#include <err.h>\n#include <errno.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"extern.h\"\n\n#define\tWAITACK\t\t2\t/* seconds */\n#define\tWAITDATEACK\t5\t/* seconds */\n\nextern int retval;\n\n/*\n * Set the date in the machines controlled by timedaemons by communicating the\n * new date to the local timedaemon.  If the timedaemon is in the master state,\n * it performs the correction on all slaves.  If it is in the slave state, it\n * notifies the master that a correction is needed.\n * Returns 0 on success.  Returns > 0 on failure, setting retval to 2;\n */\nint\nnetsettime(time_t tval)\n{\n\tstruct timeval tout;\n\tstruct servent *sp;\n\tstruct tsp msg;\n\tstruct sockaddr_in lsin, dest, from;\n\tfd_set ready;\n\tlong waittime;\n\tint s, port, timed_ack, found, lerr;\n\tsocklen_t length;\n\tchar hostname[MAXHOSTNAMELEN];\n\n\tif ((sp = getservbyname(\"timed\", \"udp\")) == NULL) {\n\t\twarnx(\"timed/udp: unknown service\");\n\t\treturn (retval = 2);\n\t}\n\n\tdest.sin_port = sp->s_port;\n\tdest.sin_family = AF_INET;\n\tdest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);\n\ts = socket(AF_INET, SOCK_DGRAM, 0);\n\tif (s < 0) {\n\t\tif (errno != EPROTONOSUPPORT)\n\t\t\twarn(\"timed\");\n\t\treturn (retval = 2);\n\t}\n\n\tmemset(&lsin, 0, sizeof(lsin));\n\tlsin.sin_family = AF_INET;\n\tfor (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {\n\t\tlsin.sin_port = htons((u_short)port);\n\t\tif (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0)\n\t\t\tbreak;\n\t\tif (errno == EADDRINUSE)\n\t\t\tcontinue;\n\t\tif (errno != EADDRNOTAVAIL)\n\t\t\twarn(\"bind\");\n\t\tgoto bad;\n\t}\n\tif (port == IPPORT_RESERVED / 2) {\n\t\twarnx(\"all ports in use\");\n\t\tgoto bad;\n\t}\n\tmemset(&msg, 0, sizeof(msg));\n\tmsg.tsp_type = TSP_SETDATE;\n\tmsg.tsp_vers = TSPVERSION;\n\tif (gethostname(hostname, sizeof(hostname))) {\n\t\twarn(\"gethostname\");\n\t\tgoto bad;\n\t}\n\t(void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));\n\tmsg.tsp_seq = htons((u_short)0);\n\tmsg.tsp_time.tv_sec = htonl((u_long)tval);\n\tmsg.tsp_time.tv_usec = htonl((u_long)0);\n\tlength = sizeof(struct sockaddr_in);\n\tif (connect(s, (struct sockaddr *)&dest, length) < 0) {\n\t\twarn(\"connect\");\n\t\tgoto bad;\n\t}\n\tif (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) {\n\t\tif (errno != ECONNREFUSED)\n\t\t\twarn(\"send\");\n\t\tgoto bad;\n\t}\n\n\ttimed_ack = -1;\n\twaittime = WAITACK;\nloop:\n\ttout.tv_sec = waittime;\n\ttout.tv_usec = 0;\n\n\tFD_ZERO(&ready);\n\tFD_SET(s, &ready);\n\tfound = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);\n\n\tlength = sizeof(lerr);\n\tif (!getsockopt(s,\n\t    SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) {\n\t\tif (lerr != ECONNREFUSED)\n\t\t\twarnc(lerr, \"send (delayed error)\");\n\t\tgoto bad;\n\t}\n\n\tif (found > 0 && FD_ISSET(s, &ready)) {\n\t\tlength = sizeof(struct sockaddr_in);\n\t\tif (recvfrom(s, &msg, sizeof(struct tsp), 0,\n\t\t    (struct sockaddr *)&from, &length) < 0) {\n\t\t\tif (errno != ECONNREFUSED)\n\t\t\t\twarn(\"recvfrom\");\n\t\t\tgoto bad;\n\t\t}\n\t\tmsg.tsp_seq = ntohs(msg.tsp_seq);\n\t\tmsg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);\n\t\tmsg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);\n\t\tswitch (msg.tsp_type) {\n\t\tcase TSP_ACK:\n\t\t\ttimed_ack = TSP_ACK;\n\t\t\twaittime = WAITDATEACK;\n\t\t\tgoto loop;\n\t\tcase TSP_DATEACK:\n\t\t\t(void)close(s);\n\t\t\treturn (0);\n\t\tdefault:\n\t\t\twarnx(\"wrong ack received from timed: %s\",\n\t\t\t    tsptype[msg.tsp_type]);\n\t\t\ttimed_ack = -1;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (timed_ack == -1)\n\t\twarnx(\"can't reach time daemon, time set locally\");\n\nbad:\n\t(void)close(s);\n\treturn (retval = 2);\n}\n"
  },
  {
    "path": "core-tools/tests-regression/code-metrics/in/date/vary.c",
    "content": "/*-\n * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/bin/date/vary.c,v 1.16.30.1.8.2 2012/11/17 08:24:31 svnexp Exp $\");\n\n#include <err.h>\n#include <time.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"vary.h\"\n\nstruct trans {\n  int val;\n  const char *str;\n};\n\nstatic struct trans trans_mon[] = {\n  { 1, \"january\" }, { 2, \"february\" }, { 3, \"march\" }, { 4, \"april\" },\n  { 5, \"may\"}, { 6, \"june\" }, { 7, \"july\" }, { 8, \"august\" },\n  { 9, \"september\" }, { 10, \"october\" }, { 11, \"november\" }, { 12, \"december\" },\n  { -1, NULL }\n};\n\nstatic struct trans trans_wday[] = {\n  { 0, \"sunday\" }, { 1, \"monday\" }, { 2, \"tuesday\" }, { 3, \"wednesday\" },\n  { 4, \"thursday\" }, { 5, \"friday\" }, { 6, \"saturday\" },\n  { -1, NULL }\n};\n\nstatic char digits[] = \"0123456789\";\nstatic int adjhour(struct tm *, char, int, int);\n\nstatic int\ndomktime(struct tm *t, char type)\n{\n  time_t ret;\n\n  while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)\n    /* While mktime() fails, adjust by an hour */\n    adjhour(t, type == '-' ? type : '+', 1, 0);\n\n  return ret;\n}\n\nstatic int\ntrans(const struct trans t[], const char *arg)\n{\n  int f;\n\n  for (f = 0; t[f].val != -1; f++)\n    if (!strncasecmp(t[f].str, arg, 3) ||\n        !strncasecmp(t[f].str, arg, strlen(t[f].str)))\n      return t[f].val;\n\n  return -1;\n}\n\nstruct vary *\nvary_append(struct vary *v, char *arg)\n{\n  struct vary *result, **nextp;\n\n  if (v) {\n    result = v;\n    while (v->next)\n      v = v->next;\n    nextp = &v->next;\n  } else\n    nextp = &result;\n\n  if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)\n    err(1, \"malloc\");\n  (*nextp)->arg = arg;\n  (*nextp)->next = NULL;\n  return result;\n}\n\nstatic int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\n\nstatic int\ndaysinmonth(const struct tm *t)\n{\n  int year;\n\n  year = t->tm_year + 1900;\n\n  if (t->tm_mon == 1)\n    if (!(year % 400))\n      return 29;\n    else if (!(year % 100))\n      return 28;\n    else if (!(year % 4))\n      return 29;\n    else\n      return 28;\n  else if (t->tm_mon >= 0 && t->tm_mon < 12)\n    return mdays[t->tm_mon];\n\n  return 0;\n}\n\n\nstatic int\nadjyear(struct tm *t, char type, int val, int mk)\n{\n  switch (type) {\n    case '+':\n      t->tm_year += val;\n      break;\n    case '-':\n      t->tm_year -= val;\n      break;\n    default:\n      t->tm_year = val;\n      if (t->tm_year < 69)\n      \tt->tm_year += 100;\t\t/* as per date.c */\n      else if (t->tm_year > 1900)\n        t->tm_year -= 1900;             /* struct tm holds years since 1900 */\n      break;\n  }\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjmon(struct tm *t, char type, int val, int istext, int mk)\n{\n  int lmdays;\n\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (istext) {\n        if (val <= t->tm_mon)\n          val += 11 - t->tm_mon;\t/* early next year */\n        else\n          val -= t->tm_mon + 1;\t\t/* later this year */\n      }\n      if (val) {\n        if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))\n          return 0;\n        val %= 12;\n        t->tm_mon += val;\n        if (t->tm_mon > 11)\n          t->tm_mon -= 12;\n      }\n      break;\n\n    case '-':\n      if (istext) {\n        if (val-1 > t->tm_mon)\n          val = 13 - val + t->tm_mon;\t/* later last year */\n        else\n          val = t->tm_mon - val + 1;\t/* early this year */\n      }\n      if (val) {\n        if (!adjyear(t, '-', val / 12, 0))\n          return 0;\n        val %= 12;\n        if (val > t->tm_mon) {\n          if (!adjyear(t, '-', 1, 0))\n            return 0;\n          val -= 12;\n        }\n        t->tm_mon -= val;\n      }\n      break;\n\n    default:\n      if (val > 12 || val < 1)\n        return 0;\n      t->tm_mon = --val;\n  }\n\n  /* e.g., -v-1m on March, 31 is the last day of February in common sense */\n  lmdays = daysinmonth(t);\n  if (t->tm_mday > lmdays)\n    t->tm_mday = lmdays;\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjday(struct tm *t, char type, int val, int mk)\n{\n  int lmdays;\n\n  switch (type) {\n    case '+':\n      while (val) {\n        lmdays = daysinmonth(t);\n        if (val > lmdays - t->tm_mday) {\n          val -= lmdays - t->tm_mday + 1;\n          t->tm_mday = 1;\n          if (!adjmon(t, '+', 1, 0, 0))\n            return 0;\n        } else {\n          t->tm_mday += val;\n          val = 0;\n        }\n      }\n      break;\n    case '-':\n      while (val)\n        if (val >= t->tm_mday) {\n          val -= t->tm_mday;\n          t->tm_mday = 1;\n          if (!adjmon(t, '-', 1, 0, 0))\n            return 0;\n          t->tm_mday = daysinmonth(t);\n        } else {\n          t->tm_mday -= val;\n          val = 0;\n        }\n      break;\n    default:\n      if (val > 0 && val <= daysinmonth(t))\n        t->tm_mday = val;\n      else\n        return 0;\n      break;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjwday(struct tm *t, char type, int val, int istext, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (istext)\n        if (val < t->tm_wday)\n          val = 7 - t->tm_wday + val;  /* early next week */\n        else\n          val -= t->tm_wday;           /* later this week */\n      else\n        val *= 7;                      /* \"-v+5w\" == \"5 weeks in the future\" */\n      return !val || adjday(t, '+', val, mk);\n    case '-':\n      if (istext) {\n        if (val > t->tm_wday)\n          val = 7 - val + t->tm_wday;  /* later last week */\n        else\n          val = t->tm_wday - val;      /* early this week */\n      } else\n        val *= 7;                      /* \"-v-5w\" == \"5 weeks ago\" */\n      return !val || adjday(t, '-', val, mk);\n    default:\n      if (val < t->tm_wday)\n        return adjday(t, '-', t->tm_wday - val, mk);\n      else if (val > 6)\n        return 0;\n      else if (val > t->tm_wday)\n        return adjday(t, '+', val - t->tm_wday, mk);\n  }\n  return 1;\n}\n\nstatic int\nadjhour(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        int days;\n\n        days = (t->tm_hour + val) / 24;\n        val %= 24;\n        t->tm_hour += val;\n        t->tm_hour %= 24;\n        if (!adjday(t, '+', days, 0))\n          return 0;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        int days;\n\n        days = val / 24;\n        val %= 24;\n        if (val > t->tm_hour) {\n          days++;\n          val -= 24;\n        }\n        t->tm_hour -= val;\n        if (!adjday(t, '-', days, 0))\n          return 0;\n      }\n      break;\n\n    default:\n      if (val > 23)\n        return 0;\n      t->tm_hour = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjmin(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))\n          return 0;\n        val %= 60;\n        t->tm_min += val;\n        if (t->tm_min > 59)\n          t->tm_min -= 60;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        if (!adjhour(t, '-', val / 60, 0))\n          return 0;\n        val %= 60;\n        if (val > t->tm_min) {\n          if (!adjhour(t, '-', 1, 0))\n            return 0;\n          val -= 60;\n        }\n        t->tm_min -= val;\n      }\n      break;\n\n    default:\n      if (val > 59)\n        return 0;\n      t->tm_min = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjsec(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))\n          return 0;\n        val %= 60;\n        t->tm_sec += val;\n        if (t->tm_sec > 59)\n          t->tm_sec -= 60;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        if (!adjmin(t, '-', val / 60, 0))\n          return 0;\n        val %= 60;\n        if (val > t->tm_sec) {\n          if (!adjmin(t, '-', 1, 0))\n            return 0;\n          val -= 60;\n        }\n        t->tm_sec -= val;\n      }\n      break;\n\n    default:\n      if (val > 59)\n        return 0;\n      t->tm_sec = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nconst struct vary *\nvary_apply(const struct vary *v, struct tm *t)\n{\n  char type;\n  char which;\n  char *arg;\n  size_t len;\n  int val;\n\n  for (; v; v = v->next) {\n    type = *v->arg;\n    arg = v->arg;\n    if (type == '+' || type == '-')\n      arg++;\n    else\n      type = '\\0';\n    len = strlen(arg);\n    if (len < 2)\n      return v;\n\n    if (type == '\\0')\n      t->tm_isdst = -1;\n\n    if (strspn(arg, digits) != len-1) {\n      val = trans(trans_wday, arg);\n      if (val != -1) {\n          if (!adjwday(t, type, val, 1, 1))\n            return v;\n      } else {\n        val = trans(trans_mon, arg);\n        if (val != -1) {\n          if (!adjmon(t, type, val, 1, 1))\n            return v;\n        } else\n          return v;\n      }\n    } else {\n      val = atoi(arg);\n      which = arg[len-1];\n      \n      switch (which) {\n        case 'S':\n          if (!adjsec(t, type, val, 1))\n            return v;\n          break;\n        case 'M':\n          if (!adjmin(t, type, val, 1))\n            return v;\n          break;\n        case 'H':\n          if (!adjhour(t, type, val, 1))\n            return v;\n          break;\n        case 'd':\n          t->tm_isdst = -1;\n          if (!adjday(t, type, val, 1))\n            return v;\n          break;\n        case 'w':\n          t->tm_isdst = -1;\n          if (!adjwday(t, type, val, 0, 1))\n            return v;\n          break;\n        case 'm':\n          t->tm_isdst = -1;\n          if (!adjmon(t, type, val, 0, 1))\n            return v;\n          break;\n        case 'y':\n          t->tm_isdst = -1;\n          if (!adjyear(t, type, val, 1))\n            return v;\n          break;\n        default:\n          return v;\n      }\n    }\n  }\n  return 0;\n}\n\nvoid\nvary_destroy(struct vary *v)\n{\n  struct vary *n;\n\n  while (v) {\n    n = v->next;\n    free(v);\n    v = n;\n  }\n}\n"
  },
  {
    "path": "core-tools/tests-regression/code-metrics/in/date/vary.h",
    "content": "/*-\n * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD: src/bin/date/vary.h,v 1.4.56.1.8.2 2012/11/17 08:24:31 svnexp Exp $\n */\n\nstruct vary {\n  char *arg;\n  struct vary *next;\n};\n\nextern struct vary *vary_append(struct vary *v, char *arg);\nextern const struct vary *vary_apply(const struct vary *v, struct tm *t);\nextern void vary_destroy(struct vary *v);\n"
  },
  {
    "path": "core-tools/tests-regression/code-metrics/out.ok",
    "content": "FNAMELEN: 7\nNSTRUCT: 2\nNTYPEDEF: 0\nNVOID: 18\nNGETS: 0\nIDLEN: 6.2008\nCHLINESCHAR: 1062:27586\nNCCHAR: 18\nNCOMMENT: 53\nNCOPYRIGHT: 17\nNCFILE: 3\nNCDIR: 1\nCLINESCHAR: 993:24159\nNFUNCTION: 18\nNGOTO: 8\nNREGISTER: 0\nNMACRO: 0\nNINCLUDE: 32\nNCONST: 82\nNHFILE: 2\n"
  },
  {
    "path": "core-tools/tests-regression/commit-stats/out.ok",
    "content": "Authors ordered by number of commits\n 557 Jim Meyering\n 252 Paul Eggert\n 146 Paolo Bonzini\n  79 Norihiro Tanaka\n   9 Bruno Haible\n   8 Eric Blake\n   7 Stefano Lattarini\n   6 Aharon Robbins\n   5 Eli Zaretskii\n   5 Arnold D. Robbins\n   4 Reuben Thomas\n   4 Norihirio Tanaka\n   3 Arnold Robbins\n   2 behoffski\n   2 Stephane Chazelas\n   2 Santiago Ruano Rincón\n   2 Mike Frysinger\n   2 Benno Schulenberg\n   1 Zev Weiss\n   1 Yuliy Pisetsky\n   1 Tony Abou-Assaleh\n   1 Pádraig Brady\n   1 Petr Písař\n   1 Petr Pisar\n   1 Patrick Boyd\n   1 Nicolas Vigier\n   1 Mike Haertel\n   1 Matthew Burgess\n   1 Karl Berry\n   1 Javier Villavicencio\n   1 Jaroslav Škarvada\n   1 Dmitry V. Levin\n   1 Corinna Vinschen\n   1 Allan McRae\n   1 Adam Katz\nDays ordered by number of commits\n 186 Thu\n 167 Fri\n 161 Mon\n 152 Wed\n 149 Sun\n 149 Sat\n 148 Tue\n"
  },
  {
    "path": "core-tools/tests-regression/compress-compare/out.ok",
    "content": "File type: ASCII\nOriginal size:40735\nxz:16728\nbzip2:15556\ngzip:17730\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/.gitignore",
    "content": "echo\necho-S\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/dd-args.ok",
    "content": "0\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/echo-deaf.ok",
    "content": "hi\n0\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/echo-s.ok",
    "content": "hi\n0\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/echo-s_caps.ok",
    "content": "hi\n0\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/paste1.ok",
    "content": "0\t1\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/paste2.ok",
    "content": "0\t1\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/paste3.ok",
    "content": "0\t1\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/paste4.ok",
    "content": "0\t1\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/tee1.ok",
    "content": "ahi\nbhi\n"
  },
  {
    "path": "core-tools/tests-regression/dgsh-wrap/tee2.ok",
    "content": "ahi\nbhi\n"
  },
  {
    "path": "core-tools/tests-regression/duplicate-files/in/another-same-1",
    "content": "Another same\n"
  },
  {
    "path": "core-tools/tests-regression/duplicate-files/in/another-same-2",
    "content": "Another same\n"
  },
  {
    "path": "core-tools/tests-regression/duplicate-files/in/different-file-1",
    "content": "hi there\n"
  },
  {
    "path": "core-tools/tests-regression/duplicate-files/in/different-file-2",
    "content": "Some more text\n"
  },
  {
    "path": "core-tools/tests-regression/duplicate-files/in/different-file-3",
    "content": "More text\n"
  },
  {
    "path": "core-tools/tests-regression/duplicate-files/in/same-file-1",
    "content": "hello, world\n"
  },
  {
    "path": "core-tools/tests-regression/duplicate-files/in/same-file-2",
    "content": "hello, world\n"
  },
  {
    "path": "core-tools/tests-regression/duplicate-files/in/same-file-3",
    "content": "hello, world\n"
  },
  {
    "path": "core-tools/tests-regression/duplicate-files/out.ok",
    "content": "duplicate-files/in/same-file-1 duplicate-files/in/same-file-2 duplicate-files/in/same-file-3\n duplicate-files/in/another-same-1 duplicate-files/in/another-same-2\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/in/a/date/date.c",
    "content": "/*-\n * Copyright (c) 1985, 1987, 1988, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#ifndef lint\nstatic char const copyright[] =\n\"@(#) Copyright (c) 1985, 1987, 1988, 1993\\n\\\n\tThe Regents of the University of California.  All rights reserved.\\n\";\n#endif /* not lint */\n\n#include <sys/cdefs.h>\n#include <sys/param.h>\n#include <sys/time.h>\n\n#include <ctype.h>\n#include <err.h>\n#include <locale.h>\n#include <libutil.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <syslog.h>\n#include <unistd.h>\n\n#include \"vary.h\"\n\n#ifndef\tTM_YEAR_BASE\n#define\tTM_YEAR_BASE\t1900\n#endif\n\nstatic time_t tval;\nint retval;\n\nstatic void setthetime(const char *, const char *, int, int);\nstatic void badformat(void);\nstatic void usage(void);\n\nint\nmain(int argc, char *argv[])\n{\n\tstruct timezone tz;\n\tint ch, rflag;\n\tint jflag;\n\tconst char *format;\n\tchar buf[1024];\n\tchar *endptr, *fmt;\n\tchar *tmp;\n\tint set_timezone;\n\tstruct vary *v;\n\tconst struct vary *badv;\n\tstruct tm lt;\n\n\tv = NULL;\n\tfmt = NULL;\n\t(void) setlocale(LC_TIME, \"\");\n\ttz.tz_dsttime = tz.tz_minuteswest = 0;\n\trflag = 0;\n\tjflag = 0;\n\tset_timezone = 0;\n\twhile ((ch = getopt(argc, argv, \"d:f:jnr:t:uv:\")) != -1)\n\t\tswitch((char)ch) {\n\t\tcase 'd':\t\t/* daylight savings time */\n\t\t\ttz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;\n\t\t\tif (endptr == optarg || *endptr != '\\0')\n\t\t\t\tusage();\n\t\t\tset_timezone = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tfmt = optarg;\n\t\t\tbreak;\n\t\tcase 'j':\n\t\t\tjflag = 1;\t/* don't set time */\n\t\t\tbreak;\n\t\tcase 'r':\t\t/* user specified seconds */\n\t\t\trflag = 1;\n\t\t\ttval = strtoq(optarg, &tmp, 0);\n\t\t\tif (*tmp != 0)\n\t\t\t\tusage();\n\t\t\tbreak;\n\t\tcase 't':\t\t/* minutes west of UTC */\n\t\t\t\t\t/* error check; don't allow \"PST\" */\n\t\t\ttz.tz_minuteswest = strtol(optarg, &endptr, 10);\n\t\t\tif (endptr == optarg || *endptr != '\\0')\n\t\t\t\tusage();\n\t\t\tset_timezone = 1;\n\t\t\tbreak;\n\t\tcase 'u':\t\t/* do everything in UTC */\n\t\t\t(void)setenv(\"TZ\", \"UTC0\", 1);\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tv = vary_append(v, optarg);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\targc -= optind;\n\targv += optind;\n\n\t/*\n\t * If -d or -t, set the timezone or daylight savings time; this\n\t * doesn't belong here; the kernel should not know about either.\n\t */\n\tif (set_timezone && settimeofday((struct timeval *)NULL, &tz))\n\t\terr(1, \"settimeofday (timezone)\");\n\n\tif (!rflag && time(&tval) == -1)\n\t\terr(1, \"time\");\n\n\tformat = \"%+\";\n\n\t/* allow the operands in any order */\n\tif (*argv && **argv == '+') {\n\t\tformat = *argv + 1;\n\t\t++argv;\n\t}\n\n\tif (*argv) {\n\t\tsetthetime(fmt, *argv, jflag);\n\t\t++argv;\n\t} else if (fmt != NULL)\n\t\tusage();\n\n\tif (*argv && **argv == '+')\n\t\tformat = *argv + 1;\n\n\tlt = *localtime(&tval);\n\tbadv = vary_apply(v, &lt);\n\tif (badv) {\n\t\tfprintf(stderr, \"%s: Cannot apply date adjustment\\n\",\n\t\t\tbadv->arg);\n\t\tvary_destroy(v);\n\t\tusage();\n\t}\n\tvary_destroy(v);\n\t(void)strftime(buf, sizeof(buf), format, &lt);\n\t(void)printf(\"%s\\n\", buf);\n\tif (fflush(stdout))\n\t\terr(1, \"stdout\");\n\texit(retval);\n}\n\n#define\tATOI2(s)\t((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))\n\nstatic void\nsetthetime(const char *fmt, const char *p, int jflag)\n{\n\tstruct tm *lt;\n\tstruct timeval tv;\n\tconst char *dot, *t;\n\tint century;\n\n\tlt = localtime(&tval);\n\tlt->tm_isdst = -1;\t\t/* divine correct DST */\n\n\tif (fmt != NULL) {\n\t\tt = strptime(p, fmt, lt);\n\t\tif (t == NULL) {\n\t\t\tfprintf(stderr, \"Failed conversion of ``%s''\"\n\t\t\t\t\" using format ``%s''\\n\", p, fmt);\n\t\t\tbadformat();\n\t\t} else if (*t != '\\0')\n\t\t\tfprintf(stderr, \"Warning: Ignoring %ld extraneous\"\n\t\t\t\t\" characters in date string (%s)\\n\",\n\t\t\t\t(long) strlen(t), t);\n\t} else {\n\t\tfor (t = p, dot = NULL; *t; ++t) {\n\t\t\tif (isdigit(*t))\n\t\t\t\tcontinue;\n\t\t\tif (*t == '.' && dot == NULL) {\n\t\t\t\tdot = t;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbadformat();\n\t\t}\n\n\t\tif (dot != NULL) {\t\t\t/* .ss */\n\t\t\tdot++; /* *dot++ = '\\0'; */\n\t\t\tif (strlen(dot) != 2)\n\t\t\t\tbadformat();\n\t\t\tlt->tm_sec = ATOI2(dot);\n\t\t\tif (lt->tm_sec > 61)\n\t\t\t\tbadformat();\n\t\t} else\n\t\t\tlt->tm_sec = 0;\n\n\t\tcentury = 0;\n\t\t/* if p has a \".ss\" field then let's pretend it's not there */\n\t\tswitch (strlen(p) - ((dot != NULL) ? 3 : 0)) {\n\t\tcase 12:\t\t\t\t/* cc */\n\t\t\tlt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE;\n\t\t\tcentury = 1;\n\t\t\t/* FALLTHROUGH */\n\t\tcase 10:\t\t\t\t/* yy */\n\t\t\tif (century)\n\t\t\t\tlt->tm_year += ATOI2(p);\n\t\t\telse {\n\t\t\t\tlt->tm_year = ATOI2(p);\n\t\t\t\tif (lt->tm_year < 69)\t/* hack for 2000 ;-} */\n\t\t\t\t\tlt->tm_year += 2000 - TM_YEAR_BASE;\n\t\t\t\telse\n\t\t\t\t\tlt->tm_year += 1900 - TM_YEAR_BASE;\n\t\t\t}\n\t\t\t/* FALLTHROUGH */\n\t\tcase 8:\t\t\t\t\t/* mm */\n\t\t\tlt->tm_mon = ATOI2(p);\n\t\t\tif (lt->tm_mon > 12)\n\t\t\t\tbadformat();\n\t\t\t--lt->tm_mon;\t\t/* time struct is 0 - 11 */\n\t\t\t/* FALLTHROUGH */\n\t\tcase 6:\t\t\t\t\t/* dd */\n\t\t\tlt->tm_mday = ATOI2(p);\n\t\t\tif (lt->tm_mday > 31)\n\t\t\t\tbadformat();\n\t\t\t/* FALLTHROUGH */\n\t\tcase 4:\t\t\t\t\t/* HH */\n\t\t\tlt->tm_hour = ATOI2(p);\n\t\t\tif (lt->tm_hour > 23)\n\t\t\t\tbadformat();\n\t\t\t/* FALLTHROUGH */\n\t\tcase 2:\t\t\t\t\t/* MM */\n\t\t\tlt->tm_min = ATOI2(p);\n\t\t\tif (lt->tm_min > 59)\n\t\t\t\tbadformat();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbadformat();\n\t\t}\n\t}\n\n\t/* convert broken-down time to GMT clock time */\n\tif ((tval = mktime(lt)) == -1)\n\t\terrx(1, \"nonexistent time\");\n\n\tif (!jflag) {\n\t\t/* set the time */\n\n\t\tif ((p = getlogin()) == NULL)\n\t\t\tp = \"???\";\n\t\tsyslog(LOG_AUTH | LOG_NOTICE, \"date set by %s\", p);\n\t}\n}\n\nstatic void\nbadformat(void)\n{\n\twarnx(\"illegal time format\");\n\tusage();\n}\n\nstatic void\nusage(void)\n{\n\t(void)fprintf(stderr, \"%s\\n%s\\n\",\n\t    \"usage: date [-jnu] [-d dst] [-r seconds] [-t west] \"\n\t    \"[-v[+|-]val[ymwdHMS]] ... \",\n\t    \"            \"\n\t    \"[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]\");\n\texit(1);\n}\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/in/a/date/vary.c",
    "content": "/*-\n * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n#include <err.h>\n#include <time.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"vary.h\"\n\nstruct trans {\n  int val;\n  const char *str;\n};\n\nstatic struct trans trans_mon[] = {\n  { 1, \"january\" }, { 2, \"february\" }, { 3, \"march\" }, { 4, \"april\" },\n  { 5, \"may\"}, { 6, \"june\" }, { 7, \"july\" }, { 8, \"august\" },\n  { 9, \"september\" }, { 10, \"october\" }, { 11, \"november\" }, { 12, \"december\" },\n  { -1, NULL }\n};\n\nstatic struct trans trans_wday[] = {\n  { 0, \"sunday\" }, { 1, \"monday\" }, { 2, \"tuesday\" }, { 3, \"wednesday\" },\n  { 4, \"thursday\" }, { 5, \"friday\" }, { 6, \"saturday\" },\n  { -1, NULL }\n};\n\nstatic char digits[] = \"0123456789\";\nstatic int adjhour(struct tm *, char, int, int);\n\nstatic int\ndomktime(struct tm *t, char type)\n{\n  time_t ret;\n\n  while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)\n    /* While mktime() fails, adjust by an hour */\n    adjhour(t, type == '-' ? type : '+', 1, 0);\n\n  return ret;\n}\n\nstatic int\ntrans(const struct trans t[], const char *arg)\n{\n  int f;\n\n  for (f = 0; t[f].val != -1; f++)\n    if (!strncasecmp(t[f].str, arg, 3) ||\n        !strncasecmp(t[f].str, arg, strlen(t[f].str)))\n      return t[f].val;\n\n  return -1;\n}\n\nstruct vary *\nvary_append(struct vary *v, char *arg)\n{\n  struct vary *result, **nextp;\n\n  if (v) {\n    result = v;\n    while (v->next)\n      v = v->next;\n    nextp = &v->next;\n  } else\n    nextp = &result;\n\n  if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)\n    err(1, \"malloc\");\n  (*nextp)->arg = arg;\n  (*nextp)->next = NULL;\n  return result;\n}\n\nstatic int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\n\nstatic int\ndaysinmonth(const struct tm *t)\n{\n  int year;\n\n  year = t->tm_year + 1900;\n\n  if (t->tm_mon == 1)\n    if (!(year % 400))\n      return 29;\n    else if (!(year % 100))\n      return 28;\n    else if (!(year % 4))\n      return 29;\n    else\n      return 28;\n  else if (t->tm_mon >= 0 && t->tm_mon < 12)\n    return mdays[t->tm_mon];\n\n  return 0;\n}\n\n\nstatic int\nadjyear(struct tm *t, char type, int val, int mk)\n{\n  switch (type) {\n    case '+':\n      t->tm_year += val;\n      break;\n    case '-':\n      t->tm_year -= val;\n      break;\n    default:\n      t->tm_year = val;\n      if (t->tm_year < 69)\n      \tt->tm_year += 100;\t\t/* as per date.c */\n      else if (t->tm_year > 1900)\n        t->tm_year -= 1900;             /* struct tm holds years since 1900 */\n      break;\n  }\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjmon(struct tm *t, char type, int val, int istext, int mk)\n{\n  int lmdays;\n\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (istext) {\n        if (val <= t->tm_mon)\n          val += 11 - t->tm_mon;\t/* early next year */\n        else\n          val -= t->tm_mon + 1;\t\t/* later this year */\n      }\n      if (val) {\n        if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))\n          return 0;\n        val %= 12;\n        t->tm_mon += val;\n        if (t->tm_mon > 11)\n          t->tm_mon -= 12;\n      }\n      break;\n\n    case '-':\n      if (istext) {\n        if (val-1 > t->tm_mon)\n          val = 13 - val + t->tm_mon;\t/* later last year */\n        else\n          val = t->tm_mon - val + 1;\t/* early this year */\n      }\n      if (val) {\n        if (!adjyear(t, '-', val / 12, 0))\n          return 0;\n        val %= 12;\n        if (val > t->tm_mon) {\n          if (!adjyear(t, '-', 1, 0))\n            return 0;\n          val -= 12;\n        }\n        t->tm_mon -= val;\n      }\n      break;\n\n    default:\n      if (val > 12 || val < 1)\n        return 0;\n      t->tm_mon = --val;\n  }\n\n  /* e.g., -v-1m on March, 31 is the last day of February in common sense */\n  lmdays = daysinmonth(t);\n  if (t->tm_mday > lmdays)\n    t->tm_mday = lmdays;\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjday(struct tm *t, char type, int val, int mk)\n{\n  int lmdays;\n\n  switch (type) {\n    case '+':\n      while (val) {\n        lmdays = daysinmonth(t);\n        if (val > lmdays - t->tm_mday) {\n          val -= lmdays - t->tm_mday + 1;\n          t->tm_mday = 1;\n          if (!adjmon(t, '+', 1, 0, 0))\n            return 0;\n        } else {\n          t->tm_mday += val;\n          val = 0;\n        }\n      }\n      break;\n    case '-':\n      while (val)\n        if (val >= t->tm_mday) {\n          val -= t->tm_mday;\n          t->tm_mday = 1;\n          if (!adjmon(t, '-', 1, 0, 0))\n            return 0;\n          t->tm_mday = daysinmonth(t);\n        } else {\n          t->tm_mday -= val;\n          val = 0;\n        }\n      break;\n    default:\n      if (val > 0 && val <= daysinmonth(t))\n        t->tm_mday = val;\n      else\n        return 0;\n      break;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjwday(struct tm *t, char type, int val, int istext, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (istext)\n        if (val < t->tm_wday)\n          val = 7 - t->tm_wday + val;  /* early next week */\n        else\n          val -= t->tm_wday;           /* later this week */\n      else\n        val *= 7;                      /* \"-v+5w\" == \"5 weeks in the future\" */\n      return !val || adjday(t, '+', val, mk);\n    case '-':\n      if (istext) {\n        if (val > t->tm_wday)\n          val = 7 - val + t->tm_wday;  /* later last week */\n        else\n          val = t->tm_wday - val;      /* early this week */\n      } else\n        val *= 7;                      /* \"-v-5w\" == \"5 weeks ago\" */\n      return !val || adjday(t, '-', val, mk);\n    default:\n      if (val < t->tm_wday)\n        return adjday(t, '-', t->tm_wday - val, mk);\n      else if (val > 6)\n        return 0;\n      else if (val > t->tm_wday)\n        return adjday(t, '+', val - t->tm_wday, mk);\n  }\n  return 1;\n}\n\nstatic int\nadjhour(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        int days;\n\n        days = (t->tm_hour + val) / 24;\n        val %= 24;\n        t->tm_hour += val;\n        t->tm_hour %= 24;\n        if (!adjday(t, '+', days, 0))\n          return 0;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        int days;\n\n        days = val / 24;\n        val %= 24;\n        if (val > t->tm_hour) {\n          days++;\n          val -= 24;\n        }\n        t->tm_hour -= val;\n        if (!adjday(t, '-', days, 0))\n          return 0;\n      }\n      break;\n\n    default:\n      if (val > 23)\n        return 0;\n      t->tm_hour = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjmin(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))\n          return 0;\n        val %= 60;\n        t->tm_min += val;\n        if (t->tm_min > 59)\n          t->tm_min -= 60;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        if (!adjhour(t, '-', val / 60, 0))\n          return 0;\n        val %= 60;\n        if (val > t->tm_min) {\n          if (!adjhour(t, '-', 1, 0))\n            return 0;\n          val -= 60;\n        }\n        t->tm_min -= val;\n      }\n      break;\n\n    default:\n      if (val > 59)\n        return 0;\n      t->tm_min = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjsec(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))\n          return 0;\n        val %= 60;\n        t->tm_sec += val;\n        if (t->tm_sec > 59)\n          t->tm_sec -= 60;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        if (!adjmin(t, '-', val / 60, 0))\n          return 0;\n        val %= 60;\n        if (val > t->tm_sec) {\n          if (!adjmin(t, '-', 1, 0))\n            return 0;\n          val -= 60;\n        }\n        t->tm_sec -= val;\n      }\n      break;\n\n    default:\n      if (val > 59)\n        return 0;\n      t->tm_sec = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nconst struct vary *\nvary_apply(const struct vary *v, struct tm *t)\n{\n  char type;\n  char which;\n  char *arg;\n  size_t len;\n  int val;\n\n  for (; v; v = v->next) {\n    type = *v->arg;\n    arg = v->arg;\n    if (type == '+' || type == '-')\n      arg++;\n    else\n      type = '\\0';\n    len = strlen(arg);\n    if (len < 2)\n      return v;\n\n    if (type == '\\0')\n      t->tm_isdst = -1;\n\n    if (strspn(arg, digits) != len-1) {\n      val = trans(trans_wday, arg);\n      if (val != -1) {\n          if (!adjwday(t, type, val, 1, 1))\n            return v;\n      } else {\n        val = trans(trans_mon, arg);\n        if (val != -1) {\n          if (!adjmon(t, type, val, 1, 1))\n            return v;\n        } else\n          return v;\n      }\n    } else {\n      val = atoi(arg);\n      which = arg[len-1];\n      \n      switch (which) {\n        case 'S':\n          if (!adjsec(t, type, val, 1))\n            return v;\n          break;\n        case 'M':\n          if (!adjmin(t, type, val, 1))\n            return v;\n          break;\n        case 'H':\n          if (!adjhour(t, type, val, 1))\n            return v;\n          break;\n        case 'd':\n          t->tm_isdst = -1;\n          if (!adjday(t, type, val, 1))\n            return v;\n          break;\n        case 'w':\n          t->tm_isdst = -1;\n          if (!adjwday(t, type, val, 0, 1))\n            return v;\n          break;\n        case 'm':\n          t->tm_isdst = -1;\n          if (!adjmon(t, type, val, 0, 1))\n            return v;\n          break;\n        case 'y':\n          t->tm_isdst = -1;\n          if (!adjyear(t, type, val, 1))\n            return v;\n          break;\n        default:\n          return v;\n      }\n    }\n  }\n  return 0;\n}\n\nvoid\nvary_destroy(struct vary *v)\n{\n  struct vary *n;\n\n  while (v) {\n    n = v->next;\n    free(v);\n    v = n;\n  }\n}\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/in/a/date/vary.h",
    "content": "/*-\n * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD: src/bin/date/vary.h,v 1.4.56.1.8.2 2012/11/17 08:24:31 svnexp Exp $\n */\n\nstruct vary {\n  char *arg;\n  struct vary *next;\n};\n\nextern struct vary *vary_append(struct vary *v, char *arg);\nextern const struct vary *vary_apply(const struct vary *v, struct tm *t);\nextern void vary_destroy(struct vary *v);\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/in/b/bin/date/date.c",
    "content": "/*-\n * Copyright (c) 1985, 1987, 1988, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#ifndef lint\nstatic char const copyright[] =\n\"@(#) Copyright (c) 1985, 1987, 1988, 1993\\n\\\n\tThe Regents of the University of California.  All rights reserved.\\n\";\n#endif /* not lint */\n\n#if 0\n#ifndef lint\nstatic char sccsid[] = \"@(#)date.c\t8.2 (Berkeley) 4/28/95\";\n#endif /* not lint */\n#endif\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/bin/date/date.c,v 1.48.2.1.8.2 2012/11/17 08:24:31 svnexp Exp $\");\n\n#include <sys/param.h>\n#include <sys/time.h>\n\n#include <ctype.h>\n#include <err.h>\n#include <locale.h>\n#include <libutil.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <syslog.h>\n#include <unistd.h>\n\n#include \"extern.h\"\n#include \"vary.h\"\n\n#ifndef\tTM_YEAR_BASE\n#define\tTM_YEAR_BASE\t1900\n#endif\n\nstatic time_t tval;\nint retval;\n\nstatic void setthetime(const char *, const char *, int, int);\nstatic void badformat(void);\nstatic void usage(void);\n\nint\nmain(int argc, char *argv[])\n{\n\tstruct timezone tz;\n\tint ch, rflag;\n\tint jflag, nflag;\n\tconst char *format;\n\tchar buf[1024];\n\tchar *endptr, *fmt;\n\tchar *tmp;\n\tint set_timezone;\n\tstruct vary *v;\n\tconst struct vary *badv;\n\tstruct tm lt;\n\n\tv = NULL;\n\tfmt = NULL;\n\t(void) setlocale(LC_TIME, \"\");\n\ttz.tz_dsttime = tz.tz_minuteswest = 0;\n\trflag = 0;\n\tjflag = nflag = 0;\n\tset_timezone = 0;\n\twhile ((ch = getopt(argc, argv, \"d:f:jnr:t:uv:\")) != -1)\n\t\tswitch((char)ch) {\n\t\tcase 'd':\t\t/* daylight savings time */\n\t\t\ttz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;\n\t\t\tif (endptr == optarg || *endptr != '\\0')\n\t\t\t\tusage();\n\t\t\tset_timezone = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tfmt = optarg;\n\t\t\tbreak;\n\t\tcase 'j':\n\t\t\tjflag = 1;\t/* don't set time */\n\t\t\tbreak;\n\t\tcase 'n':\t\t/* don't set network */\n\t\t\tnflag = 1;\n\t\t\tbreak;\n\t\tcase 'r':\t\t/* user specified seconds */\n\t\t\trflag = 1;\n\t\t\ttval = strtoq(optarg, &tmp, 0);\n\t\t\tif (*tmp != 0)\n\t\t\t\tusage();\n\t\t\tbreak;\n\t\tcase 't':\t\t/* minutes west of UTC */\n\t\t\t\t\t/* error check; don't allow \"PST\" */\n\t\t\ttz.tz_minuteswest = strtol(optarg, &endptr, 10);\n\t\t\tif (endptr == optarg || *endptr != '\\0')\n\t\t\t\tusage();\n\t\t\tset_timezone = 1;\n\t\t\tbreak;\n\t\tcase 'u':\t\t/* do everything in UTC */\n\t\t\t(void)setenv(\"TZ\", \"UTC0\", 1);\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tv = vary_append(v, optarg);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\targc -= optind;\n\targv += optind;\n\n\t/*\n\t * If -d or -t, set the timezone or daylight savings time; this\n\t * doesn't belong here; the kernel should not know about either.\n\t */\n\tif (set_timezone && settimeofday((struct timeval *)NULL, &tz))\n\t\terr(1, \"settimeofday (timezone)\");\n\n\tif (!rflag && time(&tval) == -1)\n\t\terr(1, \"time\");\n\n\tformat = \"%+\";\n\n\t/* allow the operands in any order */\n\tif (*argv && **argv == '+') {\n\t\tformat = *argv + 1;\n\t\t++argv;\n\t}\n\n\tif (*argv) {\n\t\tsetthetime(fmt, *argv, jflag, nflag);\n\t\t++argv;\n\t} else if (fmt != NULL)\n\t\tusage();\n\n\tif (*argv && **argv == '+')\n\t\tformat = *argv + 1;\n\n\tlt = *localtime(&tval);\n\tbadv = vary_apply(v, &lt);\n\tif (badv) {\n\t\tfprintf(stderr, \"%s: Cannot apply date adjustment\\n\",\n\t\t\tbadv->arg);\n\t\tvary_destroy(v);\n\t\tusage();\n\t}\n\tvary_destroy(v);\n\t(void)strftime(buf, sizeof(buf), format, &lt);\n\t(void)printf(\"%s\\n\", buf);\n\tif (fflush(stdout))\n\t\terr(1, \"stdout\");\n\texit(retval);\n}\n\n#define\tATOI2(s)\t((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))\n\nstatic void\nsetthetime(const char *fmt, const char *p, int jflag, int nflag)\n{\n\tstruct tm *lt;\n\tstruct timeval tv;\n\tconst char *dot, *t;\n\tint century;\n\n\tlt = localtime(&tval);\n\tlt->tm_isdst = -1;\t\t/* divine correct DST */\n\n\tif (fmt != NULL) {\n\t\tt = strptime(p, fmt, lt);\n\t\tif (t == NULL) {\n\t\t\tfprintf(stderr, \"Failed conversion of ``%s''\"\n\t\t\t\t\" using format ``%s''\\n\", p, fmt);\n\t\t\tbadformat();\n\t\t} else if (*t != '\\0')\n\t\t\tfprintf(stderr, \"Warning: Ignoring %ld extraneous\"\n\t\t\t\t\" characters in date string (%s)\\n\",\n\t\t\t\t(long) strlen(t), t);\n\t} else {\n\t\tfor (t = p, dot = NULL; *t; ++t) {\n\t\t\tif (isdigit(*t))\n\t\t\t\tcontinue;\n\t\t\tif (*t == '.' && dot == NULL) {\n\t\t\t\tdot = t;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbadformat();\n\t\t}\n\n\t\tif (dot != NULL) {\t\t\t/* .ss */\n\t\t\tdot++; /* *dot++ = '\\0'; */\n\t\t\tif (strlen(dot) != 2)\n\t\t\t\tbadformat();\n\t\t\tlt->tm_sec = ATOI2(dot);\n\t\t\tif (lt->tm_sec > 61)\n\t\t\t\tbadformat();\n\t\t} else\n\t\t\tlt->tm_sec = 0;\n\n\t\tcentury = 0;\n\t\t/* if p has a \".ss\" field then let's pretend it's not there */\n\t\tswitch (strlen(p) - ((dot != NULL) ? 3 : 0)) {\n\t\tcase 12:\t\t\t\t/* cc */\n\t\t\tlt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE;\n\t\t\tcentury = 1;\n\t\t\t/* FALLTHROUGH */\n\t\tcase 10:\t\t\t\t/* yy */\n\t\t\tif (century)\n\t\t\t\tlt->tm_year += ATOI2(p);\n\t\t\telse {\n\t\t\t\tlt->tm_year = ATOI2(p);\n\t\t\t\tif (lt->tm_year < 69)\t/* hack for 2000 ;-} */\n\t\t\t\t\tlt->tm_year += 2000 - TM_YEAR_BASE;\n\t\t\t\telse\n\t\t\t\t\tlt->tm_year += 1900 - TM_YEAR_BASE;\n\t\t\t}\n\t\t\t/* FALLTHROUGH */\n\t\tcase 8:\t\t\t\t\t/* mm */\n\t\t\tlt->tm_mon = ATOI2(p);\n\t\t\tif (lt->tm_mon > 12)\n\t\t\t\tbadformat();\n\t\t\t--lt->tm_mon;\t\t/* time struct is 0 - 11 */\n\t\t\t/* FALLTHROUGH */\n\t\tcase 6:\t\t\t\t\t/* dd */\n\t\t\tlt->tm_mday = ATOI2(p);\n\t\t\tif (lt->tm_mday > 31)\n\t\t\t\tbadformat();\n\t\t\t/* FALLTHROUGH */\n\t\tcase 4:\t\t\t\t\t/* HH */\n\t\t\tlt->tm_hour = ATOI2(p);\n\t\t\tif (lt->tm_hour > 23)\n\t\t\t\tbadformat();\n\t\t\t/* FALLTHROUGH */\n\t\tcase 2:\t\t\t\t\t/* MM */\n\t\t\tlt->tm_min = ATOI2(p);\n\t\t\tif (lt->tm_min > 59)\n\t\t\t\tbadformat();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbadformat();\n\t\t}\n\t}\n\n\t/* convert broken-down time to GMT clock time */\n\tif ((tval = mktime(lt)) == -1)\n\t\terrx(1, \"nonexistent time\");\n\n\tif (!jflag) {\n\t\t/* set the time */\n\t\tif (nflag || netsettime(tval)) {\n\t\t\tlogwtmp(\"|\", \"date\", \"\");\n\t\t\ttv.tv_sec = tval;\n\t\t\ttv.tv_usec = 0;\n\t\t\tif (settimeofday(&tv, (struct timezone *)NULL))\n\t\t\t\terr(1, \"settimeofday (timeval)\");\n\t\t\tlogwtmp(\"{\", \"date\", \"\");\n\t\t}\n\n\t\tif ((p = getlogin()) == NULL)\n\t\t\tp = \"???\";\n\t\tsyslog(LOG_AUTH | LOG_NOTICE, \"date set by %s\", p);\n\t}\n}\n\nstatic void\nbadformat(void)\n{\n\twarnx(\"illegal time format\");\n\tusage();\n}\n\nstatic void\nusage(void)\n{\n\t(void)fprintf(stderr, \"%s\\n%s\\n\",\n\t    \"usage: date [-jnu] [-d dst] [-r seconds] [-t west] \"\n\t    \"[-v[+|-]val[ymwdHMS]] ... \",\n\t    \"            \"\n\t    \"[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]\");\n\texit(1);\n}\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/in/b/bin/date/headers/extern.h",
    "content": "/*-\n * Copyright (c) 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)extern.h\t8.1 (Berkeley) 5/31/93\n * $FreeBSD: src/bin/date/extern.h,v 1.7.30.1.8.2 2012/11/17 08:24:31 svnexp Exp $\n */\n\nint\tnetsettime(time_t);\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/in/b/bin/date/headers/vary.h",
    "content": "/*-\n * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD: src/bin/date/vary.h,v 1.4.56.1.8.2 2012/11/17 08:24:31 svnexp Exp $\n */\n\nstruct vary {\n  char *arg;\n  struct vary *next;\n};\n\nextern struct vary *vary_append(struct vary *v, char *arg);\nextern const struct vary *vary_apply(const struct vary *v, struct tm *t);\nextern void vary_destroy(struct vary *v);\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/in/b/bin/date/netdate.c",
    "content": "/*-\n * Copyright (c) 1990, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#if 0\n#ifndef lint\nstatic char sccsid[] = \"@(#)netdate.c\t8.1 (Berkeley) 5/31/93\";\n#endif /* not lint */\n#endif\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/bin/date/netdate.c,v 1.19.10.1.8.2 2012/11/17 08:24:31 svnexp Exp $\");\n\n#include <sys/param.h>\n#include <sys/time.h>\n#include <sys/socket.h>\n\n#include <netinet/in.h>\n#include <netdb.h>\n#define TSPTYPES\n#include <protocols/timed.h>\n\n#include <err.h>\n#include <errno.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"extern.h\"\n\n#define\tWAITACK\t\t2\t/* seconds */\n#define\tWAITDATEACK\t5\t/* seconds */\n\nextern int retval;\n\n/*\n * Set the date in the machines controlled by timedaemons by communicating the\n * new date to the local timedaemon.  If the timedaemon is in the master state,\n * it performs the correction on all slaves.  If it is in the slave state, it\n * notifies the master that a correction is needed.\n * Returns 0 on success.  Returns > 0 on failure, setting retval to 2;\n */\nint\nnetsettime(time_t tval)\n{\n\tstruct timeval tout;\n\tstruct servent *sp;\n\tstruct tsp msg;\n\tstruct sockaddr_in lsin, dest, from;\n\tfd_set ready;\n\tlong waittime;\n\tint s, port, timed_ack, found, lerr;\n\tsocklen_t length;\n\tchar hostname[MAXHOSTNAMELEN];\n\n\tif ((sp = getservbyname(\"timed\", \"udp\")) == NULL) {\n\t\twarnx(\"timed/udp: unknown service\");\n\t\treturn (retval = 2);\n\t}\n\n\tdest.sin_port = sp->s_port;\n\tdest.sin_family = AF_INET;\n\tdest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);\n\ts = socket(AF_INET, SOCK_DGRAM, 0);\n\tif (s < 0) {\n\t\tif (errno != EPROTONOSUPPORT)\n\t\t\twarn(\"timed\");\n\t\treturn (retval = 2);\n\t}\n\n\tmemset(&lsin, 0, sizeof(lsin));\n\tlsin.sin_family = AF_INET;\n\tfor (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {\n\t\tlsin.sin_port = htons((u_short)port);\n\t\tif (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0)\n\t\t\tbreak;\n\t\tif (errno == EADDRINUSE)\n\t\t\tcontinue;\n\t\tif (errno != EADDRNOTAVAIL)\n\t\t\twarn(\"bind\");\n\t\tgoto bad;\n\t}\n\tif (port == IPPORT_RESERVED / 2) {\n\t\twarnx(\"all ports in use\");\n\t\tgoto bad;\n\t}\n\tmemset(&msg, 0, sizeof(msg));\n\tmsg.tsp_type = TSP_SETDATE;\n\tmsg.tsp_vers = TSPVERSION;\n\tif (gethostname(hostname, sizeof(hostname))) {\n\t\twarn(\"gethostname\");\n\t\tgoto bad;\n\t}\n\t(void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));\n\tmsg.tsp_seq = htons((u_short)0);\n\tmsg.tsp_time.tv_sec = htonl((u_long)tval);\n\tmsg.tsp_time.tv_usec = htonl((u_long)0);\n\tlength = sizeof(struct sockaddr_in);\n\tif (connect(s, (struct sockaddr *)&dest, length) < 0) {\n\t\twarn(\"connect\");\n\t\tgoto bad;\n\t}\n\tif (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) {\n\t\tif (errno != ECONNREFUSED)\n\t\t\twarn(\"send\");\n\t\tgoto bad;\n\t}\n\n\ttimed_ack = -1;\n\twaittime = WAITACK;\nloop:\n\ttout.tv_sec = waittime;\n\ttout.tv_usec = 0;\n\n\tFD_ZERO(&ready);\n\tFD_SET(s, &ready);\n\tfound = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);\n\n\tlength = sizeof(lerr);\n\tif (!getsockopt(s,\n\t    SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) {\n\t\tif (lerr != ECONNREFUSED)\n\t\t\twarnc(lerr, \"send (delayed error)\");\n\t\tgoto bad;\n\t}\n\n\tif (found > 0 && FD_ISSET(s, &ready)) {\n\t\tlength = sizeof(struct sockaddr_in);\n\t\tif (recvfrom(s, &msg, sizeof(struct tsp), 0,\n\t\t    (struct sockaddr *)&from, &length) < 0) {\n\t\t\tif (errno != ECONNREFUSED)\n\t\t\t\twarn(\"recvfrom\");\n\t\t\tgoto bad;\n\t\t}\n\t\tmsg.tsp_seq = ntohs(msg.tsp_seq);\n\t\tmsg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);\n\t\tmsg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);\n\t\tswitch (msg.tsp_type) {\n\t\tcase TSP_ACK:\n\t\t\ttimed_ack = TSP_ACK;\n\t\t\twaittime = WAITDATEACK;\n\t\t\tgoto loop;\n\t\tcase TSP_DATEACK:\n\t\t\t(void)close(s);\n\t\t\treturn (0);\n\t\tdefault:\n\t\t\twarnx(\"wrong ack received from timed: %s\",\n\t\t\t    tsptype[msg.tsp_type]);\n\t\t\ttimed_ack = -1;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (timed_ack == -1)\n\t\twarnx(\"can't reach time daemon, time set locally\");\n\nbad:\n\t(void)close(s);\n\treturn (retval = 2);\n}\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/in/b/bin/date/vary.c",
    "content": "/*-\n * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/bin/date/vary.c,v 1.16.30.1.8.2 2012/11/17 08:24:31 svnexp Exp $\");\n\n#include <err.h>\n#include <time.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"vary.h\"\n\nstruct trans {\n  int val;\n  const char *str;\n};\n\nstatic struct trans trans_mon[] = {\n  { 1, \"january\" }, { 2, \"february\" }, { 3, \"march\" }, { 4, \"april\" },\n  { 5, \"may\"}, { 6, \"june\" }, { 7, \"july\" }, { 8, \"august\" },\n  { 9, \"september\" }, { 10, \"october\" }, { 11, \"november\" }, { 12, \"december\" },\n  { -1, NULL }\n};\n\nstatic struct trans trans_wday[] = {\n  { 0, \"sunday\" }, { 1, \"monday\" }, { 2, \"tuesday\" }, { 3, \"wednesday\" },\n  { 4, \"thursday\" }, { 5, \"friday\" }, { 6, \"saturday\" },\n  { -1, NULL }\n};\n\nstatic char digits[] = \"0123456789\";\nstatic int adjhour(struct tm *, char, int, int);\n\nstatic int\ndomktime(struct tm *t, char type)\n{\n  time_t ret;\n\n  while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)\n    /* While mktime() fails, adjust by an hour */\n    adjhour(t, type == '-' ? type : '+', 1, 0);\n\n  return ret;\n}\n\nstatic int\ntrans(const struct trans t[], const char *arg)\n{\n  int f;\n\n  for (f = 0; t[f].val != -1; f++)\n    if (!strncasecmp(t[f].str, arg, 3) ||\n        !strncasecmp(t[f].str, arg, strlen(t[f].str)))\n      return t[f].val;\n\n  return -1;\n}\n\nstruct vary *\nvary_append(struct vary *v, char *arg)\n{\n  struct vary *result, **nextp;\n\n  if (v) {\n    result = v;\n    while (v->next)\n      v = v->next;\n    nextp = &v->next;\n  } else\n    nextp = &result;\n\n  if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)\n    err(1, \"malloc\");\n  (*nextp)->arg = arg;\n  (*nextp)->next = NULL;\n  return result;\n}\n\nstatic int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\n\nstatic int\ndaysinmonth(const struct tm *t)\n{\n  int year;\n\n  year = t->tm_year + 1900;\n\n  if (t->tm_mon == 1)\n    if (!(year % 400))\n      return 29;\n    else if (!(year % 100))\n      return 28;\n    else if (!(year % 4))\n      return 29;\n    else\n      return 28;\n  else if (t->tm_mon >= 0 && t->tm_mon < 12)\n    return mdays[t->tm_mon];\n\n  return 0;\n}\n\n\nstatic int\nadjyear(struct tm *t, char type, int val, int mk)\n{\n  switch (type) {\n    case '+':\n      t->tm_year += val;\n      break;\n    case '-':\n      t->tm_year -= val;\n      break;\n    default:\n      t->tm_year = val;\n      if (t->tm_year < 69)\n      \tt->tm_year += 100;\t\t/* as per date.c */\n      else if (t->tm_year > 1900)\n        t->tm_year -= 1900;             /* struct tm holds years since 1900 */\n      break;\n  }\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjmon(struct tm *t, char type, int val, int istext, int mk)\n{\n  int lmdays;\n\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (istext) {\n        if (val <= t->tm_mon)\n          val += 11 - t->tm_mon;\t/* early next year */\n        else\n          val -= t->tm_mon + 1;\t\t/* later this year */\n      }\n      if (val) {\n        if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))\n          return 0;\n        val %= 12;\n        t->tm_mon += val;\n        if (t->tm_mon > 11)\n          t->tm_mon -= 12;\n      }\n      break;\n\n    case '-':\n      if (istext) {\n        if (val-1 > t->tm_mon)\n          val = 13 - val + t->tm_mon;\t/* later last year */\n        else\n          val = t->tm_mon - val + 1;\t/* early this year */\n      }\n      if (val) {\n        if (!adjyear(t, '-', val / 12, 0))\n          return 0;\n        val %= 12;\n        if (val > t->tm_mon) {\n          if (!adjyear(t, '-', 1, 0))\n            return 0;\n          val -= 12;\n        }\n        t->tm_mon -= val;\n      }\n      break;\n\n    default:\n      if (val > 12 || val < 1)\n        return 0;\n      t->tm_mon = --val;\n  }\n\n  /* e.g., -v-1m on March, 31 is the last day of February in common sense */\n  lmdays = daysinmonth(t);\n  if (t->tm_mday > lmdays)\n    t->tm_mday = lmdays;\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjday(struct tm *t, char type, int val, int mk)\n{\n  int lmdays;\n\n  switch (type) {\n    case '+':\n      while (val) {\n        lmdays = daysinmonth(t);\n        if (val > lmdays - t->tm_mday) {\n          val -= lmdays - t->tm_mday + 1;\n          t->tm_mday = 1;\n          if (!adjmon(t, '+', 1, 0, 0))\n            return 0;\n        } else {\n          t->tm_mday += val;\n          val = 0;\n        }\n      }\n      break;\n    case '-':\n      while (val)\n        if (val >= t->tm_mday) {\n          val -= t->tm_mday;\n          t->tm_mday = 1;\n          if (!adjmon(t, '-', 1, 0, 0))\n            return 0;\n          t->tm_mday = daysinmonth(t);\n        } else {\n          t->tm_mday -= val;\n          val = 0;\n        }\n      break;\n    default:\n      if (val > 0 && val <= daysinmonth(t))\n        t->tm_mday = val;\n      else\n        return 0;\n      break;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjwday(struct tm *t, char type, int val, int istext, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (istext)\n        if (val < t->tm_wday)\n          val = 7 - t->tm_wday + val;  /* early next week */\n        else\n          val -= t->tm_wday;           /* later this week */\n      else\n        val *= 7;                      /* \"-v+5w\" == \"5 weeks in the future\" */\n      return !val || adjday(t, '+', val, mk);\n    case '-':\n      if (istext) {\n        if (val > t->tm_wday)\n          val = 7 - val + t->tm_wday;  /* later last week */\n        else\n          val = t->tm_wday - val;      /* early this week */\n      } else\n        val *= 7;                      /* \"-v-5w\" == \"5 weeks ago\" */\n      return !val || adjday(t, '-', val, mk);\n    default:\n      if (val < t->tm_wday)\n        return adjday(t, '-', t->tm_wday - val, mk);\n      else if (val > 6)\n        return 0;\n      else if (val > t->tm_wday)\n        return adjday(t, '+', val - t->tm_wday, mk);\n  }\n  return 1;\n}\n\nstatic int\nadjhour(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        int days;\n\n        days = (t->tm_hour + val) / 24;\n        val %= 24;\n        t->tm_hour += val;\n        t->tm_hour %= 24;\n        if (!adjday(t, '+', days, 0))\n          return 0;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        int days;\n\n        days = val / 24;\n        val %= 24;\n        if (val > t->tm_hour) {\n          days++;\n          val -= 24;\n        }\n        t->tm_hour -= val;\n        if (!adjday(t, '-', days, 0))\n          return 0;\n      }\n      break;\n\n    default:\n      if (val > 23)\n        return 0;\n      t->tm_hour = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjmin(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))\n          return 0;\n        val %= 60;\n        t->tm_min += val;\n        if (t->tm_min > 59)\n          t->tm_min -= 60;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        if (!adjhour(t, '-', val / 60, 0))\n          return 0;\n        val %= 60;\n        if (val > t->tm_min) {\n          if (!adjhour(t, '-', 1, 0))\n            return 0;\n          val -= 60;\n        }\n        t->tm_min -= val;\n      }\n      break;\n\n    default:\n      if (val > 59)\n        return 0;\n      t->tm_min = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjsec(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))\n          return 0;\n        val %= 60;\n        t->tm_sec += val;\n        if (t->tm_sec > 59)\n          t->tm_sec -= 60;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        if (!adjmin(t, '-', val / 60, 0))\n          return 0;\n        val %= 60;\n        if (val > t->tm_sec) {\n          if (!adjmin(t, '-', 1, 0))\n            return 0;\n          val -= 60;\n        }\n        t->tm_sec -= val;\n      }\n      break;\n\n    default:\n      if (val > 59)\n        return 0;\n      t->tm_sec = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nconst struct vary *\nvary_apply(const struct vary *v, struct tm *t)\n{\n  char type;\n  char which;\n  char *arg;\n  size_t len;\n  int val;\n\n  for (; v; v = v->next) {\n    type = *v->arg;\n    arg = v->arg;\n    if (type == '+' || type == '-')\n      arg++;\n    else\n      type = '\\0';\n    len = strlen(arg);\n    if (len < 2)\n      return v;\n\n    if (type == '\\0')\n      t->tm_isdst = -1;\n\n    if (strspn(arg, digits) != len-1) {\n      val = trans(trans_wday, arg);\n      if (val != -1) {\n          if (!adjwday(t, type, val, 1, 1))\n            return v;\n      } else {\n        val = trans(trans_mon, arg);\n        if (val != -1) {\n          if (!adjmon(t, type, val, 1, 1))\n            return v;\n        } else\n          return v;\n      }\n    } else {\n      val = atoi(arg);\n      which = arg[len-1];\n      \n      switch (which) {\n        case 'S':\n          if (!adjsec(t, type, val, 1))\n            return v;\n          break;\n        case 'M':\n          if (!adjmin(t, type, val, 1))\n            return v;\n          break;\n        case 'H':\n          if (!adjhour(t, type, val, 1))\n            return v;\n          break;\n        case 'd':\n          t->tm_isdst = -1;\n          if (!adjday(t, type, val, 1))\n            return v;\n          break;\n        case 'w':\n          t->tm_isdst = -1;\n          if (!adjwday(t, type, val, 0, 1))\n            return v;\n          break;\n        case 'm':\n          t->tm_isdst = -1;\n          if (!adjmon(t, type, val, 0, 1))\n            return v;\n          break;\n        case 'y':\n          t->tm_isdst = -1;\n          if (!adjyear(t, type, val, 1))\n            return v;\n          break;\n        default:\n          return v;\n      }\n    }\n  }\n  return 0;\n}\n\nvoid\nvary_destroy(struct vary *v)\n{\n  struct vary *n;\n\n  while (v) {\n    n = v->next;\n    free(v);\n    v = n;\n  }\n}\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/out.ok/map-hierarchy/in/b/bin/date/date.c",
    "content": "/*-\n * Copyright (c) 1985, 1987, 1988, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#ifndef lint\nstatic char const copyright[] =\n\"@(#) Copyright (c) 1985, 1987, 1988, 1993\\n\\\n\tThe Regents of the University of California.  All rights reserved.\\n\";\n#endif /* not lint */\n\n#include <sys/cdefs.h>\n#include <sys/param.h>\n#include <sys/time.h>\n\n#include <ctype.h>\n#include <err.h>\n#include <locale.h>\n#include <libutil.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <syslog.h>\n#include <unistd.h>\n\n#include \"vary.h\"\n\n#ifndef\tTM_YEAR_BASE\n#define\tTM_YEAR_BASE\t1900\n#endif\n\nstatic time_t tval;\nint retval;\n\nstatic void setthetime(const char *, const char *, int, int);\nstatic void badformat(void);\nstatic void usage(void);\n\nint\nmain(int argc, char *argv[])\n{\n\tstruct timezone tz;\n\tint ch, rflag;\n\tint jflag;\n\tconst char *format;\n\tchar buf[1024];\n\tchar *endptr, *fmt;\n\tchar *tmp;\n\tint set_timezone;\n\tstruct vary *v;\n\tconst struct vary *badv;\n\tstruct tm lt;\n\n\tv = NULL;\n\tfmt = NULL;\n\t(void) setlocale(LC_TIME, \"\");\n\ttz.tz_dsttime = tz.tz_minuteswest = 0;\n\trflag = 0;\n\tjflag = 0;\n\tset_timezone = 0;\n\twhile ((ch = getopt(argc, argv, \"d:f:jnr:t:uv:\")) != -1)\n\t\tswitch((char)ch) {\n\t\tcase 'd':\t\t/* daylight savings time */\n\t\t\ttz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;\n\t\t\tif (endptr == optarg || *endptr != '\\0')\n\t\t\t\tusage();\n\t\t\tset_timezone = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tfmt = optarg;\n\t\t\tbreak;\n\t\tcase 'j':\n\t\t\tjflag = 1;\t/* don't set time */\n\t\t\tbreak;\n\t\tcase 'r':\t\t/* user specified seconds */\n\t\t\trflag = 1;\n\t\t\ttval = strtoq(optarg, &tmp, 0);\n\t\t\tif (*tmp != 0)\n\t\t\t\tusage();\n\t\t\tbreak;\n\t\tcase 't':\t\t/* minutes west of UTC */\n\t\t\t\t\t/* error check; don't allow \"PST\" */\n\t\t\ttz.tz_minuteswest = strtol(optarg, &endptr, 10);\n\t\t\tif (endptr == optarg || *endptr != '\\0')\n\t\t\t\tusage();\n\t\t\tset_timezone = 1;\n\t\t\tbreak;\n\t\tcase 'u':\t\t/* do everything in UTC */\n\t\t\t(void)setenv(\"TZ\", \"UTC0\", 1);\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tv = vary_append(v, optarg);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t}\n\targc -= optind;\n\targv += optind;\n\n\t/*\n\t * If -d or -t, set the timezone or daylight savings time; this\n\t * doesn't belong here; the kernel should not know about either.\n\t */\n\tif (set_timezone && settimeofday((struct timeval *)NULL, &tz))\n\t\terr(1, \"settimeofday (timezone)\");\n\n\tif (!rflag && time(&tval) == -1)\n\t\terr(1, \"time\");\n\n\tformat = \"%+\";\n\n\t/* allow the operands in any order */\n\tif (*argv && **argv == '+') {\n\t\tformat = *argv + 1;\n\t\t++argv;\n\t}\n\n\tif (*argv) {\n\t\tsetthetime(fmt, *argv, jflag);\n\t\t++argv;\n\t} else if (fmt != NULL)\n\t\tusage();\n\n\tif (*argv && **argv == '+')\n\t\tformat = *argv + 1;\n\n\tlt = *localtime(&tval);\n\tbadv = vary_apply(v, &lt);\n\tif (badv) {\n\t\tfprintf(stderr, \"%s: Cannot apply date adjustment\\n\",\n\t\t\tbadv->arg);\n\t\tvary_destroy(v);\n\t\tusage();\n\t}\n\tvary_destroy(v);\n\t(void)strftime(buf, sizeof(buf), format, &lt);\n\t(void)printf(\"%s\\n\", buf);\n\tif (fflush(stdout))\n\t\terr(1, \"stdout\");\n\texit(retval);\n}\n\n#define\tATOI2(s)\t((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))\n\nstatic void\nsetthetime(const char *fmt, const char *p, int jflag)\n{\n\tstruct tm *lt;\n\tstruct timeval tv;\n\tconst char *dot, *t;\n\tint century;\n\n\tlt = localtime(&tval);\n\tlt->tm_isdst = -1;\t\t/* divine correct DST */\n\n\tif (fmt != NULL) {\n\t\tt = strptime(p, fmt, lt);\n\t\tif (t == NULL) {\n\t\t\tfprintf(stderr, \"Failed conversion of ``%s''\"\n\t\t\t\t\" using format ``%s''\\n\", p, fmt);\n\t\t\tbadformat();\n\t\t} else if (*t != '\\0')\n\t\t\tfprintf(stderr, \"Warning: Ignoring %ld extraneous\"\n\t\t\t\t\" characters in date string (%s)\\n\",\n\t\t\t\t(long) strlen(t), t);\n\t} else {\n\t\tfor (t = p, dot = NULL; *t; ++t) {\n\t\t\tif (isdigit(*t))\n\t\t\t\tcontinue;\n\t\t\tif (*t == '.' && dot == NULL) {\n\t\t\t\tdot = t;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbadformat();\n\t\t}\n\n\t\tif (dot != NULL) {\t\t\t/* .ss */\n\t\t\tdot++; /* *dot++ = '\\0'; */\n\t\t\tif (strlen(dot) != 2)\n\t\t\t\tbadformat();\n\t\t\tlt->tm_sec = ATOI2(dot);\n\t\t\tif (lt->tm_sec > 61)\n\t\t\t\tbadformat();\n\t\t} else\n\t\t\tlt->tm_sec = 0;\n\n\t\tcentury = 0;\n\t\t/* if p has a \".ss\" field then let's pretend it's not there */\n\t\tswitch (strlen(p) - ((dot != NULL) ? 3 : 0)) {\n\t\tcase 12:\t\t\t\t/* cc */\n\t\t\tlt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE;\n\t\t\tcentury = 1;\n\t\t\t/* FALLTHROUGH */\n\t\tcase 10:\t\t\t\t/* yy */\n\t\t\tif (century)\n\t\t\t\tlt->tm_year += ATOI2(p);\n\t\t\telse {\n\t\t\t\tlt->tm_year = ATOI2(p);\n\t\t\t\tif (lt->tm_year < 69)\t/* hack for 2000 ;-} */\n\t\t\t\t\tlt->tm_year += 2000 - TM_YEAR_BASE;\n\t\t\t\telse\n\t\t\t\t\tlt->tm_year += 1900 - TM_YEAR_BASE;\n\t\t\t}\n\t\t\t/* FALLTHROUGH */\n\t\tcase 8:\t\t\t\t\t/* mm */\n\t\t\tlt->tm_mon = ATOI2(p);\n\t\t\tif (lt->tm_mon > 12)\n\t\t\t\tbadformat();\n\t\t\t--lt->tm_mon;\t\t/* time struct is 0 - 11 */\n\t\t\t/* FALLTHROUGH */\n\t\tcase 6:\t\t\t\t\t/* dd */\n\t\t\tlt->tm_mday = ATOI2(p);\n\t\t\tif (lt->tm_mday > 31)\n\t\t\t\tbadformat();\n\t\t\t/* FALLTHROUGH */\n\t\tcase 4:\t\t\t\t\t/* HH */\n\t\t\tlt->tm_hour = ATOI2(p);\n\t\t\tif (lt->tm_hour > 23)\n\t\t\t\tbadformat();\n\t\t\t/* FALLTHROUGH */\n\t\tcase 2:\t\t\t\t\t/* MM */\n\t\t\tlt->tm_min = ATOI2(p);\n\t\t\tif (lt->tm_min > 59)\n\t\t\t\tbadformat();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbadformat();\n\t\t}\n\t}\n\n\t/* convert broken-down time to GMT clock time */\n\tif ((tval = mktime(lt)) == -1)\n\t\terrx(1, \"nonexistent time\");\n\n\tif (!jflag) {\n\t\t/* set the time */\n\n\t\tif ((p = getlogin()) == NULL)\n\t\t\tp = \"???\";\n\t\tsyslog(LOG_AUTH | LOG_NOTICE, \"date set by %s\", p);\n\t}\n}\n\nstatic void\nbadformat(void)\n{\n\twarnx(\"illegal time format\");\n\tusage();\n}\n\nstatic void\nusage(void)\n{\n\t(void)fprintf(stderr, \"%s\\n%s\\n\",\n\t    \"usage: date [-jnu] [-d dst] [-r seconds] [-t west] \"\n\t    \"[-v[+|-]val[ymwdHMS]] ... \",\n\t    \"            \"\n\t    \"[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]\");\n\texit(1);\n}\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/out.ok/map-hierarchy/in/b/bin/date/headers/vary.h",
    "content": "/*-\n * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD: src/bin/date/vary.h,v 1.4.56.1.8.2 2012/11/17 08:24:31 svnexp Exp $\n */\n\nstruct vary {\n  char *arg;\n  struct vary *next;\n};\n\nextern struct vary *vary_append(struct vary *v, char *arg);\nextern const struct vary *vary_apply(const struct vary *v, struct tm *t);\nextern void vary_destroy(struct vary *v);\n"
  },
  {
    "path": "core-tools/tests-regression/map-hierarchy/out.ok/map-hierarchy/in/b/bin/date/vary.c",
    "content": "/*-\n * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n#include <err.h>\n#include <time.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"vary.h\"\n\nstruct trans {\n  int val;\n  const char *str;\n};\n\nstatic struct trans trans_mon[] = {\n  { 1, \"january\" }, { 2, \"february\" }, { 3, \"march\" }, { 4, \"april\" },\n  { 5, \"may\"}, { 6, \"june\" }, { 7, \"july\" }, { 8, \"august\" },\n  { 9, \"september\" }, { 10, \"october\" }, { 11, \"november\" }, { 12, \"december\" },\n  { -1, NULL }\n};\n\nstatic struct trans trans_wday[] = {\n  { 0, \"sunday\" }, { 1, \"monday\" }, { 2, \"tuesday\" }, { 3, \"wednesday\" },\n  { 4, \"thursday\" }, { 5, \"friday\" }, { 6, \"saturday\" },\n  { -1, NULL }\n};\n\nstatic char digits[] = \"0123456789\";\nstatic int adjhour(struct tm *, char, int, int);\n\nstatic int\ndomktime(struct tm *t, char type)\n{\n  time_t ret;\n\n  while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)\n    /* While mktime() fails, adjust by an hour */\n    adjhour(t, type == '-' ? type : '+', 1, 0);\n\n  return ret;\n}\n\nstatic int\ntrans(const struct trans t[], const char *arg)\n{\n  int f;\n\n  for (f = 0; t[f].val != -1; f++)\n    if (!strncasecmp(t[f].str, arg, 3) ||\n        !strncasecmp(t[f].str, arg, strlen(t[f].str)))\n      return t[f].val;\n\n  return -1;\n}\n\nstruct vary *\nvary_append(struct vary *v, char *arg)\n{\n  struct vary *result, **nextp;\n\n  if (v) {\n    result = v;\n    while (v->next)\n      v = v->next;\n    nextp = &v->next;\n  } else\n    nextp = &result;\n\n  if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)\n    err(1, \"malloc\");\n  (*nextp)->arg = arg;\n  (*nextp)->next = NULL;\n  return result;\n}\n\nstatic int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\n\nstatic int\ndaysinmonth(const struct tm *t)\n{\n  int year;\n\n  year = t->tm_year + 1900;\n\n  if (t->tm_mon == 1)\n    if (!(year % 400))\n      return 29;\n    else if (!(year % 100))\n      return 28;\n    else if (!(year % 4))\n      return 29;\n    else\n      return 28;\n  else if (t->tm_mon >= 0 && t->tm_mon < 12)\n    return mdays[t->tm_mon];\n\n  return 0;\n}\n\n\nstatic int\nadjyear(struct tm *t, char type, int val, int mk)\n{\n  switch (type) {\n    case '+':\n      t->tm_year += val;\n      break;\n    case '-':\n      t->tm_year -= val;\n      break;\n    default:\n      t->tm_year = val;\n      if (t->tm_year < 69)\n      \tt->tm_year += 100;\t\t/* as per date.c */\n      else if (t->tm_year > 1900)\n        t->tm_year -= 1900;             /* struct tm holds years since 1900 */\n      break;\n  }\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjmon(struct tm *t, char type, int val, int istext, int mk)\n{\n  int lmdays;\n\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (istext) {\n        if (val <= t->tm_mon)\n          val += 11 - t->tm_mon;\t/* early next year */\n        else\n          val -= t->tm_mon + 1;\t\t/* later this year */\n      }\n      if (val) {\n        if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))\n          return 0;\n        val %= 12;\n        t->tm_mon += val;\n        if (t->tm_mon > 11)\n          t->tm_mon -= 12;\n      }\n      break;\n\n    case '-':\n      if (istext) {\n        if (val-1 > t->tm_mon)\n          val = 13 - val + t->tm_mon;\t/* later last year */\n        else\n          val = t->tm_mon - val + 1;\t/* early this year */\n      }\n      if (val) {\n        if (!adjyear(t, '-', val / 12, 0))\n          return 0;\n        val %= 12;\n        if (val > t->tm_mon) {\n          if (!adjyear(t, '-', 1, 0))\n            return 0;\n          val -= 12;\n        }\n        t->tm_mon -= val;\n      }\n      break;\n\n    default:\n      if (val > 12 || val < 1)\n        return 0;\n      t->tm_mon = --val;\n  }\n\n  /* e.g., -v-1m on March, 31 is the last day of February in common sense */\n  lmdays = daysinmonth(t);\n  if (t->tm_mday > lmdays)\n    t->tm_mday = lmdays;\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjday(struct tm *t, char type, int val, int mk)\n{\n  int lmdays;\n\n  switch (type) {\n    case '+':\n      while (val) {\n        lmdays = daysinmonth(t);\n        if (val > lmdays - t->tm_mday) {\n          val -= lmdays - t->tm_mday + 1;\n          t->tm_mday = 1;\n          if (!adjmon(t, '+', 1, 0, 0))\n            return 0;\n        } else {\n          t->tm_mday += val;\n          val = 0;\n        }\n      }\n      break;\n    case '-':\n      while (val)\n        if (val >= t->tm_mday) {\n          val -= t->tm_mday;\n          t->tm_mday = 1;\n          if (!adjmon(t, '-', 1, 0, 0))\n            return 0;\n          t->tm_mday = daysinmonth(t);\n        } else {\n          t->tm_mday -= val;\n          val = 0;\n        }\n      break;\n    default:\n      if (val > 0 && val <= daysinmonth(t))\n        t->tm_mday = val;\n      else\n        return 0;\n      break;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjwday(struct tm *t, char type, int val, int istext, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (istext)\n        if (val < t->tm_wday)\n          val = 7 - t->tm_wday + val;  /* early next week */\n        else\n          val -= t->tm_wday;           /* later this week */\n      else\n        val *= 7;                      /* \"-v+5w\" == \"5 weeks in the future\" */\n      return !val || adjday(t, '+', val, mk);\n    case '-':\n      if (istext) {\n        if (val > t->tm_wday)\n          val = 7 - val + t->tm_wday;  /* later last week */\n        else\n          val = t->tm_wday - val;      /* early this week */\n      } else\n        val *= 7;                      /* \"-v-5w\" == \"5 weeks ago\" */\n      return !val || adjday(t, '-', val, mk);\n    default:\n      if (val < t->tm_wday)\n        return adjday(t, '-', t->tm_wday - val, mk);\n      else if (val > 6)\n        return 0;\n      else if (val > t->tm_wday)\n        return adjday(t, '+', val - t->tm_wday, mk);\n  }\n  return 1;\n}\n\nstatic int\nadjhour(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        int days;\n\n        days = (t->tm_hour + val) / 24;\n        val %= 24;\n        t->tm_hour += val;\n        t->tm_hour %= 24;\n        if (!adjday(t, '+', days, 0))\n          return 0;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        int days;\n\n        days = val / 24;\n        val %= 24;\n        if (val > t->tm_hour) {\n          days++;\n          val -= 24;\n        }\n        t->tm_hour -= val;\n        if (!adjday(t, '-', days, 0))\n          return 0;\n      }\n      break;\n\n    default:\n      if (val > 23)\n        return 0;\n      t->tm_hour = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjmin(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))\n          return 0;\n        val %= 60;\n        t->tm_min += val;\n        if (t->tm_min > 59)\n          t->tm_min -= 60;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        if (!adjhour(t, '-', val / 60, 0))\n          return 0;\n        val %= 60;\n        if (val > t->tm_min) {\n          if (!adjhour(t, '-', 1, 0))\n            return 0;\n          val -= 60;\n        }\n        t->tm_min -= val;\n      }\n      break;\n\n    default:\n      if (val > 59)\n        return 0;\n      t->tm_min = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nstatic int\nadjsec(struct tm *t, char type, int val, int mk)\n{\n  if (val < 0)\n    return 0;\n\n  switch (type) {\n    case '+':\n      if (val) {\n        if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))\n          return 0;\n        val %= 60;\n        t->tm_sec += val;\n        if (t->tm_sec > 59)\n          t->tm_sec -= 60;\n      }\n      break;\n\n    case '-':\n      if (val) {\n        if (!adjmin(t, '-', val / 60, 0))\n          return 0;\n        val %= 60;\n        if (val > t->tm_sec) {\n          if (!adjmin(t, '-', 1, 0))\n            return 0;\n          val -= 60;\n        }\n        t->tm_sec -= val;\n      }\n      break;\n\n    default:\n      if (val > 59)\n        return 0;\n      t->tm_sec = val;\n  }\n\n  return !mk || domktime(t, type) != -1;\n}\n\nconst struct vary *\nvary_apply(const struct vary *v, struct tm *t)\n{\n  char type;\n  char which;\n  char *arg;\n  size_t len;\n  int val;\n\n  for (; v; v = v->next) {\n    type = *v->arg;\n    arg = v->arg;\n    if (type == '+' || type == '-')\n      arg++;\n    else\n      type = '\\0';\n    len = strlen(arg);\n    if (len < 2)\n      return v;\n\n    if (type == '\\0')\n      t->tm_isdst = -1;\n\n    if (strspn(arg, digits) != len-1) {\n      val = trans(trans_wday, arg);\n      if (val != -1) {\n          if (!adjwday(t, type, val, 1, 1))\n            return v;\n      } else {\n        val = trans(trans_mon, arg);\n        if (val != -1) {\n          if (!adjmon(t, type, val, 1, 1))\n            return v;\n        } else\n          return v;\n      }\n    } else {\n      val = atoi(arg);\n      which = arg[len-1];\n      \n      switch (which) {\n        case 'S':\n          if (!adjsec(t, type, val, 1))\n            return v;\n          break;\n        case 'M':\n          if (!adjmin(t, type, val, 1))\n            return v;\n          break;\n        case 'H':\n          if (!adjhour(t, type, val, 1))\n            return v;\n          break;\n        case 'd':\n          t->tm_isdst = -1;\n          if (!adjday(t, type, val, 1))\n            return v;\n          break;\n        case 'w':\n          t->tm_isdst = -1;\n          if (!adjwday(t, type, val, 0, 1))\n            return v;\n          break;\n        case 'm':\n          t->tm_isdst = -1;\n          if (!adjmon(t, type, val, 0, 1))\n            return v;\n          break;\n        case 'y':\n          t->tm_isdst = -1;\n          if (!adjyear(t, type, val, 1))\n            return v;\n          break;\n        default:\n          return v;\n      }\n    }\n  }\n  return 0;\n}\n\nvoid\nvary_destroy(struct vary *v)\n{\n  struct vary *n;\n\n  while (v) {\n    n = v->next;\n    free(v);\n    v = n;\n  }\n}\n"
  },
  {
    "path": "core-tools/tests-regression/parallel-word-count/out.ok",
    "content": "1 \"'Challenger,\n2 \"A\n1 \"Ah,\n1 \"An\n3 \"And\n1 \"Anything\n1 \"Anything--anywhere--I\n1 \"As\n6 \"But\n1 \"Can't\n1 \"Challenger\n1 \"Challenger!\"\n1 \"Challenger?\"\n1 \"Come\n1 \"Come,\n1 \"DEAR\n4 \"Dear\n1 \"Did\n2 \"Do\n3 \"Don't\n1 \"ENMORE\n1 \"Entirely,\n1 \"Exactly.\n1 \"Expected?\"\n1 \"FOR\n1 \"GEORGE\n1 \"General\n1 \"Get\n1 \"Gibberish!\"\n1 \"Good\n1 \"Got\n1 \"HE\n1 \"Had\n3 \"He\n1 \"Here\n1 \"How\n1 \"How's\n1 \"How?\"\n21 \"I\n1 \"I'd\n1 \"I'll\n1 \"I'm\n1 \"I've\n1 \"IT\n1 \"IT'S\n1 \"If\n6 \"It\n5 \"It's\n1 \"Look\n1 \"My\n1 \"Naturally,\"\n1 \"No\n2 \"No,\n1 \"No,\"\n2 \"Not\n1 \"Nothing\n1 \"Now\n2 \"Now,\n1 \"OUR\n3 \"Oh,\n3 \"One\n1 \"Outlines\n1 \"Pray\n1 \"Professor\n1 \"Protests,\"\n1 \"QUESTION!\"\n1 \"Right!\"\n1 \"SIR,--I\n2 \"Shall\n1 \"So\n1 \"Some\n1 \"Spirited\n1 \"Suppose,\"\n2 \"THE\n1 \"THERE\n1 \"THOSE\n1 \"TO-MORROW\n1 \"TRY\n1 \"Talking\n1 \"Tell\n2 \"That\n1 \"That's\n2 \"The\n2 \"Then\n2 \"There\n1 \"There's\n1 \"There,\n1 \"They\n1 \"This\n1 \"Tickled,\n3 \"To\n1 \"Try\n1 \"Tut,\n1 \"Undoubtedly.\"\n1 \"Uproar,\"\n1 \"WHO\n1 \"We\n1 \"We'll\n1 \"Weissmann\n1 \"Well\n11 \"Well,\n1 \"Well,\"\n1 \"Well?\"\n1 \"Went\n9 \"What\n2 \"What's\n2 \"Why\n1 \"Why,\n1 \"Yes,\n13 \"You\n1 \"You're\n1 \"You've\n1 \"Yours\n1 \"besides,\n1 \"hardly\n1 \"only\n3 \"that\n1 \"what\n1 \"you\n1 #139]\n1 'I\n1 'In\n1 'Professor\n1 'The\n1 'em--a\n1 'journalists.'\n1 'special\n1 'speculation'\n1 (Wednesday)\n2 ***\n1 --\"by\n1 1863.\n1 1892.\n1 1893.\n1 19,\n1 1912\n1 2008\n6 A\n1 ALL\n1 ARE\n1 ARTHUR\n1 ASCII\n1 Academy\n1 Academy;\n1 Act,\n1 Address:\n1 Adelphi\n1 Afterwards\n1 Ah,\n1 Al\n2 All\n1 Alpine\n2 America\n1 America,\n1 America.\"\n3 American\n5 And\n1 And,\n1 Anthropology\n2 Anyhow,\n1 Anyway,\n1 Are\n2 Arthur\n3 As\n1 Assistant,\n1 Assistant-Keeper\n1 Association'--so\n1 Assyrian\n2 At\n1 Austin\n3 Austin,\n1 Austin.\n1 Author:\n1 B.,\n1 BIGGEST\n1 Balkans\n1 Beaumont\n1 Began\n1 Behold\n1 Belge,\n2 Besides,\n1 Blundell\n1 Blundell,\n1 Blundell.\"\n1 Born:\n1 Boss.\n3 British\n1 Burton!\n1 Burtons,\"\n6 But\n2 But,\n1 But--oh,\n2 By\n2 C.\n1 CHALLENGER\"\n1 CHALLENGER,\"\n1 CHALLENGER.\"\n4 CHAPTER\n1 CONAN\n1 CONQUESTS\"\n1 COPYRIGHT,\n1 COULD\n1 Cabinet.\n1 Camberwell\n1 Came\n1 Catharine-wheel\n1 Chain\n1 Chairman\"\n1 Challenger\n1 Challenger\"\n1 Challenger's\n5 Challenger,\n1 Challenger.\n2 Challenger?\"\n1 Character\n1 Chestnuts\n1 Chinese\n1 Clive--just\n1 Club,\n1 Comparative\n2 Conan\n1 Congress\n1 Contents\n1 Continental\n1 Crayston\n1 Creeping\n2 D.\n1 DEFINITE\n1 DISAPPEAR\n1 DOYLE\n1 DREADFUL\n1 Daily\n1 Darwin\n1 Darwin,\"\n1 Darwinism,\n1 Date:\n1 Death\n1 Department,\n2 Did\n1 Didn't\n4 Do\n3 Don't\n2 Doyle\n4 E.\n1 EBOOK\n1 EBook\n2 EDWARD\n1 EYES\n1 Edinburgh\n1 Educ.:\n1 Edward.\n1 Eh,\n1 Employers'\n4 English\n1 English,\n3 Enmore\n3 Even\n1 Evolution\";\n1 Evolution.\n1 Ex-President\n1 Expensive,\n1 FLAIL\n1 FORESEEN\n1 FOREST\"\n1 FORGET\"\n1 Fate\n1 Following\n1 For\n1 Foreign\n1 Foreword\n1 Forfeit,\n1 French\n1 Frenchman\n3 G.\n1 GREAT\n1 GUTENBERG\n1 Gazette\n1 Gazette,\n1 Gazette,--perfectly\n1 George\n1 George!\n1 Give\n1 Gladys\n1 Gladys!\n5 Gladys,\n1 Gladys.\n1 Gladys?\n1 Got\n1 Gulf.\n2 Gutenberg\n1 H,\n1 HAPPENED\"\n4 HAVE\n1 HERO\"\n1 HEROISMS\n1 HTML\n2 Had\n1 Haines.\n1 Half\n1 Has\n1 Have\n25 He\n2 He's\n2 Henry,\n1 Henry.\n1 Her\n1 Hercules\n1 Heroisms\n4 His\n3 How\n1 However,\n1 Hungerton,\n199 I\n2 I'd\n7 I'll\n7 I'm\n4 I've\n4 I,\n5 I.\n1 I;\n1 II\n1 II.\n1 III\n1 III.\n1 IMPOSSIBLE\n2 IN\n1 INTO\n1 IS\n1 IT?\"\n1 IV.\n1 IX.\n9 If\n1 Impossible\n1 In\n1 India!\n1 Institute\n1 Institute,\n1 Institute.\n2 Irish\n1 Irish.\n1 Is\n19 It\n4 It's\n1 JUST\n1 Judith\n1 June\n1 Just\n1 Kalmuck\n1 Kensington\n1 Kensington,\n1 Knowable,\n1 LORD\"\n3 LOST\n1 LUCK\n1 La\n1 Lady\n1 Language:\n1 Largs\n1 Largs,\n1 Liability\n1 License\n1 Lively\n1 London\n1 London--a\n2 Look\n1 Lord\n1 Lord!\"\n4 Lost\n1 Luck\n1 MAKE\n1 MALONE.\"\n1 MOST\n1 Macs\n1 Malone\n3 Malone,\n2 Malone.\n1 Malone?\"\n1 Masonic\n1 May\n2 McArdle\n1 McArdle,\n1 Medal\n1 Member\n1 Most\n1 Move\n8 Mr.\n1 Munchausen--and\n1 Museum\n5 My\n1 N.\n1 NEVER\n1 NEW\n2 Nature,\n1 Ned,\n1 Ned,\"\n1 Ned.\n1 No,\n1 November\n3 Now,\n3 OF\n1 ONCE\n1 OUTLYING\n1 Observations\n2 Of\n2 Oh,\n1 Olympian\n1 Once\n1 Or\n1 PARK,\n1 PERFECTLY\n1 PERSON\"\n1 PICKETS\n1 PROCESSION!\n1 PROCESSION!\"\n2 PROFESSOR\n1 PROJECT\n1 Palaeontological\n1 Park,\n1 Park.\n1 Park?\"\n1 Perfectly\n1 Perhaps\n1 Persian\n1 Person\"\n1 Plata,\n2 President\n1 Pressman,\n1 Pretend\n1 Proceedings.\"\n1 Produced\n11 Professor\n1 Professor!\"\n3 Professor.\n1 Professor.\"\n2 Project\n1 Protest\n1 Put\n1 REAL\n1 ROUND\n1 Recreations:\n1 Release\n1 Remember\n1 Research.\n1 Resigned\n1 Reuter's,\n1 Richard\n1 Round\n1 Russia.\n1 SEEN\n1 SHALL\n1 SIGHT\n1 SIR\n1 START\n1 Saturday\n1 Savage\n1 Sciences,\n1 Scotch\n1 Section\n1 Series\n1 Several\n13 She\n1 Sir!\n3 Sir,\n1 Sir.\"\n1 Skulls\";\n2 So\n1 Society.\n3 Some\n1 Somehow\n1 Something\n1 Sometimes\n5 South\n1 Southwark\n1 Stanley!\n1 Stanleys\n1 Step\n1 Such\n1 Swollen\n12 THE\n1 THING\n1 THINGS\n1 THIS\n2 Tarp\n1 Telegraph?\"\n1 Terrace\n6 That\n2 That's\n26 The\n3 Then\n6 There\n2 There's\n1 These\n2 Think\n6 This\n1 Three\n1 Time\n1 Title:\n1 To\n1 UNKNOWN\"\n1 US\"\n1 University.\n1 Upon\n1 Us\"\n1 V.\n1 VERY\n1 VI.\n1 VII.\n1 VIII.\n1 Vertebrate\n2 Vienna,\n3 Vienna.\n1 W.\n1 W.'\n3 WAS\n1 WE\n1 WERE\n1 WILL\n1 WITH\n1 WONDERFUL\n1 WONDERS\"\n3 WORLD\n2 WORLD\"\n2 Wadley\n1 Wadley,\n1 Wait\n1 Walking,\n2 Was\n1 Wasn't\n5 We\n2 Wednesday\n2 Weissmann\n1 Weissmann.\n1 Weissmannism,\"\n4 Well,\n1 West\n7 What\n2 When\n1 Where\n1 Why\n1 Wigan\n1 Winner\n3 With\n3 World\n1 World,\n1 Would\n1 X.\n1 XI.\n1 XII.\n1 XIII.\n1 XIV.\n1 XV.\n1 XVI.\n1 YOUR\n1 Yes,\n19 You\n1 You'll\n1 You're\n3 You've\n2 Your\n5 Zoological\n1 [EBook\n170 a\n1 able\n1 abominably,\"\n13 about\n1 about.\"\n1 about?\"\n3 above\n1 absolutely\n1 abusive\n1 accent.\n1 accepted\n1 accessible?\n1 account\n1 acrimonious\n3 across\n1 act,\n1 acting\n1 action\n1 adapt\n1 added,\n2 address\n1 admirable\n1 advance,\n1 advance.\n1 advanced\n1 advancing\n1 adventure\n3 adventures\n1 aeronaut,\n1 afraid\n7 after\n1 after?\"\n1 afterwards\n1 again.\n1 again.\"\n3 against\n1 age\n1 age,\n1 age;\n1 aggressive\n1 ago.\n1 ago;\n1 agreeable\n1 air.\n1 alarmed,\n1 alive\n25 all\n2 all,\n1 all.\n1 all.\"\n1 allowances.\"\n1 alluded\n4 almost\n1 alone\n1 alone,\n1 aloof!\n2 aloud\n1 alternating\n1 although\n6 always\n13 am\n1 am,\n1 amazement\n1 amiss\n1 amplification\n30 an\n139 and\n1 and,\n1 and--oh,\n1 anger\n1 angular\n1 animal\n1 animals\n1 announced\n1 annoyed\n2 another\n4 answer\n1 answered.\n1 anxious\n8 any\n3 anyone\n3 anything\n1 anywhere\n1 anywhere.\n1 apart\n1 apologize\n2 appeal\n1 appear\n2 appearance\n1 appearance,\n1 appeared\n1 appears\n1 appointment,\n1 appointment.\n1 appointment.\"\n1 approve,\n1 architecture\n1 ardent\n23 are\n2 are.\"\n1 argue\n1 argument,\n1 argument.\n1 arm-chair\n2 arms\n1 arnica.\"\n1 around\n1 article\n35 as\n1 ashamed\"\n4 ask\n2 asked\n2 asked,\n1 asked.\n1 asks\n1 assault\n1 assaults\n1 assertion\n1 associate\n1 assurances\n2 assure\n1 assured.\n1 asthmatic.\n47 at\n1 atmosphere\n1 atmosphere.\"\n1 attack\n1 attacked\n1 attempt\n1 attention\n1 attitude\n1 audacity.\n1 authority.\n1 averaged.\n1 averted\n1 awaits\n2 aware\n1 aware,\"\n2 away\n1 away--his\n1 awfully\n6 back\n1 back.\n1 backing\n1 bacteriologist\n1 bacteriologist,\n2 bad\n2 bald\n1 balloon.\n1 barbed-wire\n1 barrel\n1 battery\n1 battles,\n34 be\n1 be,--envied\n1 beard\n1 beard,\n1 beast.\n3 beautiful\n1 beauty,\n4 because\n16 been\n5 before\n1 before,\n1 before?\"\n1 began:\n1 begins,\n1 behaved\n1 behavior.\n2 behind\n4 being\n1 being.\n3 believe\n1 believe,\n1 believe.\"\n1 believed\n1 believes\n1 bell\n1 bellow\n1 bellowing,\n1 bent\n1 beside\n2 best\n1 best.\n1 bestial\n7 better\n1 between\n2 beyond\n4 big\n1 bimetallism,\n1 biography,\n1 bit,\n5 black\n1 blackened\n2 blame\n2 blank\n1 blast\n1 blew\n1 blowing\n1 blue\n1 blue,\n1 blue-gray\n1 bodies\n1 bolted\n2 book\n1 books,\n1 boss;\n3 both\n1 bottom,\n1 bounced\n1 bounded\n1 bow\n1 bowdlerized\n2 boy\n1 boy,\n1 boy.\n1 boyish\n1 brace\n1 brackets\n2 brain.\n1 brain?\n1 brave\n1 breadth,\n2 break\n1 breaking\n1 breaks\n1 breast,\n1 breath\n1 breathed\n1 brethren?\n1 briefly:--\n1 bright,\n1 bring\n1 broad\n2 broke\n1 bronze\n1 bronzed\n1 brother.\n1 brought\n1 brown\n1 brown,\n1 brows\n1 brutal\n1 bucking\n1 bull's\n1 bull;\n1 bully!\"\n1 business\n1 business,\n1 business.\n1 business.\"\n31 but\n1 butcher's\n1 butlers.\n1 butt\n16 by\n1 by.\n4 call\n1 call,\n2 called\n1 calling\n1 calm.\n3 came\n21 can\n6 can't\n2 cannot\n2 cantankerous\n2 care\n1 carried\n1 case\n1 caught\n1 caused\n1 censor\n1 center\n1 centered\n1 certain\n1 certainly\n7 chair\n2 chair,\n1 chair.\n1 champion\n1 chance,\n1 chance,--at\n1 chance.\n1 chances\n1 chances,\n1 chances.\n2 chapter\n1 character,\n1 character.\n1 character?\"\n1 charge,\n1 chauffeur,\n1 checking\n1 chest\n1 chest.\n1 chirrup\n1 choke-damp?\"\n1 choked\n1 chosen--Tarp\n1 circulation.\n3 claim\n1 clear\n1 clear,\n1 clearly\n1 clerk,\n1 clever\n1 climbing.\n1 clipped.\n1 closed\n1 club.\n1 clumped\n1 coal\n1 cock-and-bull\n1 cockatoo\n1 cold\n1 colleagues.\n1 collected.\n1 colliery\n1 coloring,\n6 come\n1 come!\n1 come!\"\n1 come,\n1 come.\n1 come?\"\n2 comes\n1 comes.\"\n1 command\n1 comment\n1 comments\n1 companions,\n1 company,\n1 compliment\n2 compliments\n1 composition!\"\n1 comradeship\n1 conceited\n1 conclusions\n1 conditions\n1 conducted\n1 confession.\n1 confidence\n1 confidence.\n2 connection\n1 conquered\n1 conscience\n2 conscious\n1 consent\n1 consent,\n1 considerate\n1 constant\n1 content\n1 contentious,\n1 contents\n1 context\n2 control\n1 conversation.\n1 conversaziones\n1 convey\n1 conveyed\n1 convinced\n1 convinces\n1 cooed.\n2 copy\n1 copy,\n1 copy.\"\n1 correspondence\n1 cost\n27 could\n4 course,\n2 covered\n1 crabbed,\n1 cranial\n1 crawling\n1 creature,\n1 creatures.\n1 cried\n3 cried,\n3 cried.\n1 crisis\n1 critical\n2 critical,\n1 criticism\n1 crying\n1 cunning\n1 curtail\n1 curtain.\n1 curving\n1 cuticura\n1 damaged\n1 damnedest\n1 dancing\n1 danger\n2 dangerous\n1 dangerous,\n1 dangerous--really\n1 dangerous--ring\n3 dare\n2 dark\n1 dark-eyed\n1 date\n3 day\n1 day,\n2 days\n2 dear\n1 debts\n1 decency\n1 deception\n2 deed\n1 deeds\n1 deeds.\"\n1 deep\n1 deeper.\"\n2 definite\n1 degree.\n1 deigns\n1 deliberate\n1 delicate\n1 delicately\n1 demonstrate\n1 dependent\n1 depreciation\n1 depth,\n1 descreeptive\n1 described\n1 desire\n1 desire,\n1 desires\n1 desk\n1 desk.\n1 destined\n1 detached\n2 determination\n1 devil.'\"\n1 diagrams.\n5 did\n1 did,\n1 did.\"\n2 didn't\n1 differences\n1 different\n1 different.\n1 difficult\n1 difficult.\n1 difficulty\n1 dignity\n1 dining-room\n1 directness\n1 disapproval.\n1 discovered.\n1 discovery\n1 discreditable\n1 discretion\n1 discuss\n1 discussion\n1 distance.\n1 distasteful\n1 distinguish\n2 distrust\n19 do\n1 do,\n1 do----\"\n2 do.\n1 do.\"\n1 do?\n2 do?\"\n7 does\n1 dogmatic\n3 doing\n1 doing,\n1 don\n9 don't\n3 done\n1 done.\n1 done?\"\n3 door\n3 door,\n2 door.\n1 doubly\n14 down\n1 down!\n1 down!\"\n1 down.\n1 drawer.\n1 drawing\n1 dress\n1 dressing\n2 drew\n1 dried-up\n1 driven\n2 driving\n1 dry,\n1 duly\n1 during\n1 duty\n2 eBook\n1 each\n1 each--that\n1 eager\n1 early\n1 earnest\n1 earnestness.\n1 ears\n1 earth,--a\n1 ease\n1 edge\n1 editor\n1 editor,\n1 education\n1 education,\n1 effervescence.\n1 effervescing\n1 effort\n1 egg?\"\n1 eh?\"\n1 either\n1 either,\"\n1 elaborate\n1 elaborated\n1 elapse\n1 elasticity\n1 electric\n1 eleven\n1 eleven,\n1 else\n1 else,\"\n1 else.\n1 emphatic.\n1 encoding:\n1 encouraging\n2 end\n1 end.\n1 endorse\n1 endorsement\n1 energy.\n1 enormous\n1 enormous,\n4 enough\n1 enough?\"\n2 entered\n1 entered,\n1 enthusiasm\n3 entirely\n2 envelope\n2 envelope.\n1 envied\n1 especially\n1 established\n1 establishing\n1 etc.\n1 etc.,\n1 evasion\n1 even\n4 evening\n6 ever\n5 every\n1 everyone\n1 everything\n1 everything,\n1 evidence\n1 evidence.\n1 evidence?\"\n1 evident\n1 evidently\n1 exactly\n1 exalted.\n1 exceeding\n1 excellent.\n1 exchange.\n1 exists.\n1 expect\n1 expedeetion\n1 expense\n1 experience\n1 experienced\n1 experiences.\n1 explained,\n1 exploits,\n2 explosion\n1 exposed\n1 exposing\n1 express\n2 expression\n1 expression.\n1 exquisite\n1 extraordinary\n1 extreme\n1 eye\n1 eye,\n4 eye.\n4 eyes\n1 eyes,\n3 eyes.\n13 face\n1 face,\n1 face.\n1 face:\n1 fact\n1 factor?\"\n1 fad?\"\n1 faddist,\n1 faddist.\n2 failed\n1 fair\n1 fairly\n1 faithfully,\n1 fakes.\n1 faking\n1 fallacy\n1 faltering\n2 famous\n1 fanatic\n1 fancies.\n1 fang\n3 far\n1 fashion,\n1 fashion.\n1 father,\n1 father-in-law.\n1 fatuous\n3 favor\n1 favor.\"\n1 favorable\n3 fear\n1 fearful\n1 feathery,\n1 feeble\n3 feel\n2 feeling\n1 feet\n1 feet,\n1 fell\n2 fellow\n1 fellow,\n1 fellow,\"\n1 fellow-reporters\n3 felt\n1 fever\n2 few\n3 fifteen\n1 fifth.\n1 fifty\n1 fight\n1 fight,\n1 figure--these,\n1 filed\n2 filled\n4 find\n1 fine.\n1 fingers\n1 fingers,\n1 finished.\n2 fire.\n6 first\n1 fists\n1 flashed\n1 flatter\n1 flock\n1 florid,\n1 fluff;\n1 fluffy,\n1 foggy\n1 folk\n3 follow\n1 followed\n1 follows:--\n1 fool,\n1 foolish\n1 football\n47 for\n1 for?\n1 force\n2 forehead.\n1 forewarned\n1 forfeit!\n1 forlorn\n1 former\n1 formidable\n1 forth\n1 forth.\n1 fortunately\n2 forward\n1 forward,\n4 found\n1 fourth\n1 frame\n2 frank\n1 frank,\n1 fraud--a\n1 friend's\n1 friendly--or\n1 friends,\n1 friends;\n1 friendship\n1 fringed\n20 from\n3 front\n1 frontiersman\n1 fronting\n1 fugitive\n3 full\n2 full,\n1 full-charged\n1 furniture.\"\n1 fury,\n1 gaiters.\n1 gale\n1 game,\n1 gaps\n1 gas-bags!\n1 gasp.\n3 gathered\n5 gave\n1 gaze\n1 gazed\n3 general\n1 generations.'\n1 genius\n1 gentle,\n1 gentleman.\n1 genuine\n1 germ\n10 get\n1 gibberish!\n1 gingery\n2 girl's\n8 give\n1 given.\n1 gives\n1 glad\n1 glad--if\n1 glad--so\n1 glared\n1 gloried\n1 glories\n1 glorification?\n1 glow\n1 glowing\n4 go\n1 goes\n1 goes.\"\n2 going\n1 goings-on,\"\n3 gone\n9 good\n3 good,\n1 good-bye.\n1 good-natured,\n3 got\n1 gracious,\n1 grasp\n5 great\n1 great,\n1 greater,\n1 gregarious\n1 grimly.\n1 grinning\n1 gripped\n1 grunt\n1 guaranteed\n1 guidance,\n1 gutter.\n1 habit\n1 habitual\n39 had\n1 had,\n1 hadn't\n1 hair\n1 hair,\n1 hair.\n3 half\n1 half-past\n2 hall\n1 halls,\n2 hand\n1 hand--such\n2 hand.\n1 hand;\n1 handed\n1 handiwork.\n1 handled\n1 handling\n3 hands\n1 handwriting\n1 happen\n1 happened--or\n1 happiest\n2 hard\n1 hard,\n1 hard;\n1 harder,\n3 hardly\n1 hardness,\n10 has\n1 hated\n63 have\n1 have,--youth,\n1 haven't\n1 having\n69 he\n1 he's\n2 he,\n2 he.\n5 head\n2 head,\n2 head.\n1 heading,\n1 health,\n2 hear\n1 hear,\n3 heard\n4 heart\n1 heated\n1 heaves\n1 heavily\n1 heavily-curtained\n1 height\n4 help\n1 help-mate.\n1 helped\n13 her\n1 her!\n1 herd\n3 here\n3 here,\n1 heritage\n1 heroic\n2 heroisms\n1 hers\n1 higher\n19 him\n7 him,\n1 him,\"\n12 him.\n1 him.\"\n1 him?\n2 him?\"\n1 himself\n1 himself.\n63 his\n1 historical\n1 hog.\"\n2 hold\n1 holes,\n1 homicidal\n1 honest\n2 honor\n1 honor.\"\n1 honored\n4 hope\n1 hope;\n1 hoped\n1 hopelessly\n5 hour\n1 hours,\n1 house\n2 house.\n1 hovering\n6 how\n2 however,\n1 however--namely:\n1 howl\n2 huge\n1 hulking\n2 human\n1 humanity.\n1 humble\n1 humbly,\n1 humor.\n1 humorous\n1 hundred\n1 hurting\n1 husband\n1 husband?\n1 id\n1 idea\n1 idea,\n1 idea.\n1 ideal\n1 ideal.\n16 if\n1 ignominious.\n1 ignorance\n1 ignore.\n1 ill-conditioned\n1 image,\n1 imagine\n1 imagined\n1 immediate\n1 impediment\n2 imposing\n3 impossible\n1 impossible.\n1 imposter\n1 impression\n94 in\n1 in!\n1 in!\"\n1 in,\n1 in.\n1 inches\n2 inclined\n1 included\n1 including\n1 incredible\n1 indeed!\n1 indeed?\"\n1 index\n1 indication\n1 inexpressibly\n4 infernal\n1 inherited\n1 injunction\n1 injured\n1 inner\n1 inquirer.\n1 insignificant\n2 insisted\n1 insisted,\n1 insolent\n1 inspiration.\n1 inspirer\n1 instantly\n1 instead\n1 instinct.\n1 instincts\n2 insufferable\n1 intelligence\n1 intercourse----'\n1 interest\n1 interest.\n1 international\n1 interrupted\n1 intertwined,\n4 interview\n2 interview,\n2 interview.\n13 into\n1 intruded\n1 intrusive\n1 invent\n1 irksome\n50 is\n1 is!\n1 is,\n1 isn't\n2 isolated\n83 it\n2 it!\n1 it's\n8 it,\n1 it,\"\n1 it----\"\n7 it.\n6 it.\"\n1 it;\n2 it?\n1 it?\"\n4 its\n2 jacket\n1 job\n1 journalist,\n1 joy\n1 judged\n1 judice?\"\n1 jump\n1 jumped\n4 just\n1 justifies\n1 justify\n3 keep\n5 kind\n3 kindly\n1 kindly,\n1 kiss\n1 knew\n1 knew.\n6 know\n1 know,\n1 know.\n2 know.\"\n1 know?\n1 knows,\n1 lady\n1 lady,\n2 lady.\n1 laid\n1 lamp.\n1 land\n1 large\n1 largest\n7 last\n2 last.\n1 late.\"\n2 later\n1 latest\n1 latter\n2 laughed\n1 laughing\n1 laughing.\n1 layman.\"\n1 lead\n2 leaned\n1 leaning\n1 learned\n3 least\n1 least,\n1 least.\n1 leather\n1 leathery\n1 leave\n1 lecture,\n2 led\n1 left\n1 leg\n1 legs\n2 length\n1 less\n1 less,\n2 let\n5 letter\n1 letter--nothing\n1 letter?\"\n1 level\n1 levity,\n1 liar\n1 liar!\"\n1 liar,\n1 libel\n1 liberty\n2 lie\n1 lieutenant,\n4 life\n1 life,\n1 life.\"\n1 lift.\n1 lifted\n1 light\n14 like\n1 like.\n1 like?\"\n2 liked\n1 likely\n1 limit.\n1 line\n1 link\n1 lips,--all\n1 lips.\n1 liquid\n1 list\n1 listened\n7 little\n1 little.\n1 live\n1 lived\n1 lived.\n1 loafers\n1 locked,\n1 lonely\n3 long\n1 long,\n1 longer\n1 longer,\n4 look\n10 looked\n1 looks\n1 lose\n2 lost\n1 lot\n4 love\n2 love!\n1 love!\"\n3 love,\n1 love.\n1 love.\"\n1 loved,\n1 lover\n1 lucid\n2 luck\n1 luck,\n1 lucky\n1 mad\n1 madam,\n1 madam.\"\n5 made\n1 magnetism,\n1 maid,\n1 mail,\n1 majesty\n7 make\n2 makes\n2 making\n1 malice,\n24 man\n1 man!\"\n3 man's\n8 man,\n1 man----\"\n1 man-servant,\n1 man.\n1 man.\"\n2 map\n1 maps,\n1 margin\n1 mark\n1 marry\n1 marry,\n1 massive\n2 master.\n1 masterful.\n1 masterly\n1 match\n1 matchwood\n2 matter\n2 matter.\n1 matter;\n1 matters\n1 mature\n11 may\n1 maybe,\n33 me\n2 me!\n1 me!\"\n12 me,\n2 me,\"\n1 me--you\n10 me.\n2 me.\"\n1 me?\"\n3 mean\n1 mean.\n1 mean.\"\n1 meaning\n1 meant\n1 meaty\n1 meesion\n1 meesion'\n1 meeting,\n1 meeting.\n1 meeting.'\n1 megalomaniac\n2 memory\n5 men\n1 men.\n1 menaces\n2 menacing\n1 mend\n1 mentioned\n1 mere\n3 merely\n1 message,\n1 message:\n3 met\n1 methods\n1 microcosm\n1 microscope.\n2 middle\n7 might\n1 might,\n1 miles\n2 mind\n1 mind,\n1 mind.\n1 mind?\n1 mine.\n1 mine.\"\n1 minutes.\n1 mission\n2 modern\n2 modify\n3 moment\n3 moment,\n1 moment,\"\n1 money\n1 monotonous\n1 month\n1 month,\n16 more\n1 more,\n1 morning--if\n1 morning.\n8 most\n1 motive!\n1 motive,\n1 moustache\n1 mouth\n1 move\n5 much\n1 much,\n1 murmured\n1 murmured.\n10 must\n1 must--you,\n1 must.\"\n70 my\n4 myself\n2 myself.\n1 myself.\"\n1 mystic\n1 nails,\n1 naked\n3 name\n1 named,\n1 narrative\n1 narrative;\n2 natural\n1 nature,\n1 nature.\n1 nearer.\n2 nearly\n1 necessary.\n2 need\n1 needed\n1 needs\n1 neglected,\n13 never\n1 new\n2 news\n1 newspaper\n1 next\n1 nicer\n1 night,\n1 nine-hundred-diameter\n11 no\n1 no;\n1 noble\n2 nobody\n2 nodded\n1 none\n1 nonsense\n33 not\n1 not.\"\n1 not?\n3 not?\"\n1 note,\n1 notebook\n1 notebook.\n1 notes\n5 nothing\n1 nothing.\n1 nothing.\"\n1 notice\n1 noticed\n1 notions\n1 notorious\n3 now\n2 now,\n1 now?\"\n1 numerous\n1 o'clock\n1 occasion\n1 odd,\n1 odious\n155 of\n1 of'--well,\n4 off\n2 off,\n1 off.\"\n3 offensive\n3 office\n1 office.\n1 official\n1 often\n1 oily\n5 old\n1 old,\n1 omnipotent,\n17 on\n1 on!\"\n1 on!--'Publications:\n2 on,\n1 once\n8 one\n1 one's\n1 oneself.\n1 online\n14 only\n3 open\n3 opened\n2 opening\n2 opening.\n1 opinion\n1 opinion,\n22 or\n1 order.\n1 oriental\n1 original.\"\n2 other\n1 others\n1 otherwise\n2 ought\n6 our\n13 out\n1 out,\n1 out.\n1 outlined\n1 oval,\n9 over\n1 over-accentuated?\n1 over.\n1 overpowering\n7 own\n1 oyster.\n1 panted.\n2 paper\n1 paper.\n1 paper?\n1 papers,\n2 part\n1 parthenogenetic\n1 particular\n1 particular,\"\n1 parts\n1 pass\n1 passage\n2 passage.\n1 passing\n1 passion\n1 passion.\n1 past.\n1 pathetically,\n1 payment\n1 peculiar\n1 peculiar,\n1 peculiarly\n2 people\n1 people,\n1 people--seempathy,\n4 perfectly\n2 perhaps\n1 perhaps,\n1 permission,\n4 person\n1 person--absolutely\n3 personal\n1 personality\n1 persuasive\n1 photographs\n1 photographs,\n1 pick\n1 pilot\n2 pink\n1 pity\n1 pity!\n3 place\n1 place,\n1 place.\n1 plain\n1 plan\n1 plasm\n1 plastered\n2 play\n1 played\n1 pleaded.\n1 pleasant!\n3 please\n1 pleasure\n2 plunged\n1 pocketed\n1 point\n1 point,\n1 point?\"\n1 pointing\n1 points\n1 police-court\n2 policeman\n1 policeman,\n3 policeman.\n1 poor\n1 porticoed\n1 position\n1 position?\"\n1 possessed\n1 possible\n1 possible,\n1 possibly\n1 postmark\n1 pound\n1 practise\n1 praise\n1 precaution\n1 prepared\n1 presence,\n1 presence.\n2 present\n1 presentiment\n2 presents\n1 pressed\n1 pride\n1 primitive\n1 probable\n1 proceedings\n1 proceedings,\n1 produced\n1 producing\n1 profile\n2 profound\n1 projecting.\n1 proper\n1 proportion.\n1 propose\n1 propose,\n1 propose?\"\n1 proposed\n1 proposition\n1 prosaic\n1 protest\n1 proud\n1 proud,\n2 prove?\"\n1 proved\n1 proves,\"\n2 public\n1 publication\n1 pursuing\n1 pushed\n4 put\n1 putting\n1 quality.\n1 quarrelsome,\n1 queer\n1 quest\n1 questions,\n1 quickly\n5 quite\n1 quote\n1 race\n1 radiated\n1 rage\n1 railing.\n1 railings\n1 rank\n1 rarefied\n1 rascals\n8 rather\n1 rational\n1 raven\n1 re-reading\n1 re-reading----\"\n1 re-use\n5 read\n1 reader\n2 ready\n3 real\n1 realized\n1 realized.\n6 really\n1 really,\n1 reasonable\n2 received\n1 recently\n1 record.\n1 recriminations,\n3 red\n1 red-headed\n1 reflected\n1 reflects\n1 refresh\n1 refuse\n1 refused\n2 regard\n1 relations\n1 relented.\n1 remain,\n2 remark\n2 remember\n1 remind\n1 reply,\n1 reporters\n1 representative\n1 reproof.\n1 reproved\n1 repulse\n1 repulsed\n1 rescued\n1 research,\n1 reserve\n1 respect,\n2 rested\n1 restraint\n1 restrictions\n1 result\n1 result,\n1 resumed\n1 retracted\n1 reward\n1 rewards.\n1 rideeculous?\n2 right.\n1 righteous\n1 rippling\n1 risk\n1 risk.\n1 river.\n1 roared,\n1 roaring,\n1 rolled\n2 romance\n5 room\n1 room,\n1 rotating\n1 rough,\n9 round\n1 round-backed,\n2 row\n1 rudeness\n1 ruined\n1 rumbled.\n1 rumbling\n1 run\n1 run,\n1 run:\n1 rupee,\n1 rush\n1 rushed\n1 sadly\n1 safe.\n1 safely\n23 said\n4 said,\n4 said.\n4 same\n1 sanctum,\n1 sanely\n3 sat\n1 satisfied\n1 satisfy\n1 save\n3 saw\n7 say\n2 say,\n1 say?\"\n1 says--I'm\n1 scandal\n1 scandal,\n1 science\n2 science.\n5 scientific\n1 scrawled\n1 scribblers,\n1 searching\n1 seat\n2 seated\n1 secret\n8 see\n1 see,\n7 seem\n4 seemed\n3 seems\n2 seen\n1 self,\n1 self-evident\n1 self.\n1 selfishness,\n2 send\n1 sense\n1 sent\n3 sentence\n1 separate\n1 series\n1 serious\n1 seriously,\n1 serve\n3 set\n1 settled\n1 several\n1 severe\n1 severely,\n1 severely.\n1 sex\n1 shaken\n1 shaking\n6 shall\n1 shape\n1 sharp,\n11 she\n2 she.\n1 shield\n4 short\n20 should\n1 shoulder--a\n1 shoulders\n1 shoulders.\n1 shouldn't\n2 show\n1 shunned\n1 shut\n1 side-pockets\n1 sight\n1 signal\n1 signals\n1 signs\n1 silence,\n2 silly\n1 silver,\n2 simple\n1 simultaneously,\n1 since\n1 since.\n1 single\n1 sinister\n1 sinned\n4 sir,\n4 sir,\"\n1 sir--entirely!\"\n1 sir--scientific\n2 sir.\n1 sir.\"\n1 sir?\"\n2 sit\n1 situation.\n2 size\n1 skeleton\n1 skin,\n1 skull\n1 slip\n1 slipped\n2 slowly\n2 small\n1 smaller\n1 smile\n1 smile,\n1 smile.\n1 smiled\n1 smiling\n1 snapped\n1 sneer.\n22 so\n1 so,\n1 so.\"\n1 soldier\n1 solitary\n20 some\n2 somebody\n1 somersault\n7 something\n1 something,\n1 something.\n1 somewhat\n1 soon\n1 sorely?\n1 sorry\n6 sort\n1 soul!\n1 soul,\n1 sound,\n2 spaces\n1 spade-shaped\n1 speak\n1 spectacles\n1 speculations\n1 speech\n1 spirit,\n1 spite\n1 splendid\n1 split\n1 spoil\n1 spoiled\n1 spoke\n1 spoke.\n1 sportsman\n1 sprang\n1 spread\n1 springing\n2 sprung\n1 spun\n2 staff\n1 stairs.\n3 stand\n1 standards\n1 stare.\n1 staring\n1 started\n1 starting.\n1 startled.\n1 state\n2 statement\n1 statement?\n1 station-master.\"\n1 station.\n1 statue\n1 stealthy\n1 steely\n1 stepped\n1 steps\n1 steps.\n1 sterner\n1 stigmata\n3 still\n1 still,\n1 stone,\n1 stoop\n1 stooping\n1 stopped\n1 stopped,\n1 story\n1 story?\"\n2 strange\n1 strange,\n1 street,\n1 street.\n1 strength,\n1 strengthen\n1 strengthens\n1 strikes\n1 striking\n2 strongly\n1 student\n1 student,\"\n1 students,\n1 study\n1 stuff,\n1 stunted\n2 sub\n1 sub-human\n4 subject\n1 subject,\n2 subject.\n1 succession\n13 such\n3 sudden\n1 suddenly\n1 suggestion\n1 suggestions\n1 suit\n1 suit--that's\n1 summary\n1 superman.\n1 support\n4 suppose\n1 suppose,\n1 supposeetion.\n1 suppressed\n3 sure\n1 sure,\n1 surely!\"\n1 suspect.\n1 suspense\n1 suspicion\n1 swarthy,\n1 sweetness\n1 swine\n1 sympathy.\n1 table\n2 table,\n1 taciturn\n1 tact\n1 tactless\n1 tactlessness\n11 take\n1 take,\n2 taken\n5 talk\n1 talked?\"\n2 talking\n1 tall,\n1 tap\n1 taxicab\n1 telegony\n7 tell\n1 ten\n1 tended\n1 tension\n2 terms\n1 terrible\n11 than\n1 thanked\n82 that\n1 that!\n2 that's\n2 that,\"\n1 that--or\n4 that.\n2 that?\"\n275 the\n3 their\n2 them\n1 them,\n1 themselves\n1 then!\n1 then,\n1 then.\n2 then?\"\n1 theosophist,\n11 there\n1 there's\n2 there,\n3 there.\n3 these\n1 thesis.\"\n7 they\n2 thin,\n3 thing\n1 thing.\n2 things\n1 things,\n6 think\n1 think,\n1 thinking\n19 this\n1 this.\n1 this?\n1 thoroughly\n3 those\n2 though\n1 though!\"\n6 thought\n1 thoughtfully\n3 thoughts\n1 thousand,\n2 three\n1 three-and-twenty\n1 three-quarter\n7 through\n2 thrown\n1 tickled.\"\n1 tickling.\n1 till\n4 time\n2 time,\n1 time.\"\n1 timidity\n161 to\n1 to--well,\n1 to-morrow\n1 to-night.\n1 to-night.\"\n1 to.\n1 toes\n1 together\n1 together.\n1 token\n1 told\n1 tome\n4 too\n6 took\n1 top-hat,\n2 touch\n1 touch.\n1 touchy\n1 towards\n1 tram\n1 transfixed\n1 translate\n1 translation\n1 translation.\"\n1 treason.\n1 tremendous\n1 trend\n1 tried\n1 triumphantly.\n1 trotted,\n2 trouble\n3 true\n1 truly,\n1 trust\n5 try\n1 try.\n1 tufts,\n2 turn\n1 turn.\n2 turned\n2 turning\n1 tut!\n1 twenty-four\n1 twice\n1 twilight\n1 twinkled\n8 two\n1 type--'Societe\n1 type.\n1 unable\n1 unawares?\n1 unbend\n1 uncertain\n4 under\n1 underlying\n3 understand\n1 understand?\"\n1 understanding\n1 undoubtedly\n1 uneasy\n1 unit,\n1 unpleasant\n1 unprintable.\"\n1 unreservedly\n1 unscrupulous\n1 unsexual.\n1 unshrinking\n1 untidy\n3 until\n14 up\n1 up,\n1 up.\n1 up.\"\n24 upon\n1 upon,--what\n1 upturned\n4 us\n1 us,\n4 us.\n3 use\n1 usually\n2 vague\n1 vaguely\n1 valuable.\n1 value\n1 vegetarian,\n1 velvet\n1 venture.\n2 ventured\n1 ventures\n1 vermin,\n2 version\n1 versus\n19 very\n1 very--very\n1 victory\n1 view\n1 view,\n1 views\n1 views,\n1 views.\n1 vile,\n1 violence\n1 violence,\n1 violent\n1 violent,\n2 violent.\n1 visit,\n1 visitors\n1 visits\n1 vitality\n2 vitality,\n1 vivacious,\n1 voice\n1 voice,\n1 voice.\n1 wail\n5 wait\n1 wait,\n1 waited\n1 waiting\n1 wakens\n1 walked\n1 walked,\n1 wall.\n1 walnut\n4 want\n1 want----\"\n2 want.\n1 wanted\n1 wants.\n1 warm\n1 warned\n1 warning.\"\n83 was\n1 was!\n2 was,\n1 was--and\n2 wasn't\n1 watchful\n1 waving\n3 way\n3 way,\n12 we\n1 we?\n1 wealth\n2 week\n1 well,\"\n1 well.\n6 went\n16 were\n17 what\n1 what's\n1 what?\"\n1 whatever\n1 whatsoever.\n1 wheezing\n11 when\n2 where\n1 where.\n1 whether\n36 which\n1 whim.\n1 white\n1 white!--and\n23 who\n2 who's\n1 who,\n1 who--who\n2 whole\n1 whole-hearted\n2 whom\n2 whose\n4 why\n1 wicked\n1 wide\n1 wife's\n10 will\n1 wincing\n1 wind\n1 wind;\n1 windows\n2 wish\n1 wisp\n1 wistful\n73 with\n1 with--with\n1 withdrawn\n3 within\n1 within,\n2 without\n1 wits,\n6 woman\n1 woman,\n1 womanly\n4 women\n1 won\n3 won't\n1 won;\n1 wonder\n2 wonder.\n3 wonderful\n1 wondering\n1 wooden\n4 word\n2 word,\n1 word,--teetotal,\n1 words\n1 words.\n1 wore.\n1 work\n6 world\n1 world,\n1 worship\n1 worst\n1 worth\n2 worthy\n28 would\n1 wouldn't\n1 wouldn't;\n2 write\n1 written\n3 wrong\n1 wrought\n1 www.gutenberg.net\n2 year.\n2 years\n1 yes,\n1 yes;\n8 yet\n1 yet!\"\n2 yet.\"\n100 you\n1 you!\n1 you!\"\n3 you'll\n6 you,\n4 you.\n5 you.\"\n2 you?\n2 you?\"\n6 young\n34 your\n1 yours\n1 yourself,\n1 yourself.\n1 yourself?\"\n1 youthful\n1 zoologist!\n"
  },
  {
    "path": "core-tools/tests-regression/regression/errors/stream-scatter-cycle.ok",
    "content": "The following dependencies across streams form a cycle:\n head /stream/d\n tail /stream/b\n"
  },
  {
    "path": "core-tools/tests-regression/regression/errors/stream-scatter-cycle.sh",
    "content": "#!/usr/bin/env sgsh\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nscatter |{\n\t.| head /stream/d |>/stream/b\n\t.| tail /stream/b |>/stream/d\n|} gather |{\n|}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/errors/unsafe-gather.ok",
    "content": "test/regression/errors/unsafe-gather.sh(29): warning: Unsafe use of pass-through /stream/b in the gather section\ntest/regression/errors/unsafe-gather.sh(29): error: Consult the DEADLOCK section of the manual page\n"
  },
  {
    "path": "core-tools/tests-regression/regression/errors/unsafe-gather.sh",
    "content": "#!/usr/bin/env sgsh\n#\n# SYNOPSIS Highlight misspelled words\n# DESCRIPTION\n# Highlight the words that are misspelled in the command's standard\n# input\n# Demonstrates stream buffering.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nscatter |{\n\t-| cat |>/stream/a\n\t-||>/stream/b\n|} gather |{\n\tcat /stream/a\n\tcat /stream/b\n|}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/errors/unsafe-gather2.ok",
    "content": "test/regression/errors/unsafe-gather2.sh(24): warning: Unsafe use of pass-through /stream/b in the gather section\ntest/regression/errors/unsafe-gather2.sh(24): error: Consult the DEADLOCK section of the manual page\n"
  },
  {
    "path": "core-tools/tests-regression/regression/errors/unsafe-gather2.sh",
    "content": "#!/usr/bin/env sgsh\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nscatter |{\n\t-| cat |>/stream/a\n\t-||>/stream/b\n|} gather |{\n\t# Join is unsafe in this context\n\tjoin /stream/a /dev/null\n\tjoin /stream/b /dev/null\n|}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/NMRPipe.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"nmrPipe |\\lnmrPipe -fn SOL |\\lnmrPipe -fn SP -off 0.5 -end 0.98 -pow 2 -c 0.5 |\\lnmrPipe -fn ZF -auto |\\lnmrPipe -fn FT |\\lnmrPipe -fn PS -p0 177 -p1 0.0 -di |\\lnmrPipe -fn EXT -left -sw -verb |\\lnmrPipe -fn TP |\\lnmrPipe -fn COADD -cList 1 0 -time |\\lnmrPipe -fn SP -off 0.5 -end 0.98 -pow 1 -c 0.5 |\\lnmrPipe -fn ZF -auto |\\lnmrPipe -fn FT |\\lnmrPipe -fn PS -p0 0 -p1 0 -di |\\lnmrPipe -fn TP |\\lnmrPipe -fn POLY -auto -verb >A\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"nmrPipe |\\lnmrPipe -fn SOL |\\lnmrPipe -fn SP -off 0.5 -end 0.98 -pow 2 -c 0.5 |\\lnmrPipe -fn ZF -auto |\\lnmrPipe -fn FT |\\lnmrPipe -fn PS -p0 177 -p1 0.0 -di |\\lnmrPipe -fn EXT -left -sw -verb |\\lnmrPipe -fn TP |\\lnmrPipe -fn COADD -cList 0 1 -time |\\lnmrPipe -fn SP -off 0.5 -end 0.98 -pow 1 -c 0.5 |\\lnmrPipe -fn ZF -auto |\\lnmrPipe -fn FT |\\lnmrPipe -fn PS -p0 -90 -p1 0 -di |\\lnmrPipe -fn TP |\\lnmrPipe -fn POLY -auto -verb >B\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/code-metrics.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\t\"FNAMELEN\" [id=\"store:FNAMELEN\", shape=\"box\"];\n\tnode_cmd_1_0_0 -> \"FNAMELEN\" [id=\"nps-FNAMELEN\"];\n\t\"NSTRUCT\" [id=\"store:NSTRUCT\", shape=\"box\"];\n\tnode_cmd_3_0_0 -> \"NSTRUCT\" [id=\"nps-NSTRUCT\"];\n\t\"NTYPEDEF\" [id=\"store:NTYPEDEF\", shape=\"box\"];\n\tnode_cmd_3_1_0 -> \"NTYPEDEF\" [id=\"nps-NTYPEDEF\"];\n\t\"NVOID\" [id=\"store:NVOID\", shape=\"box\"];\n\tnode_cmd_3_2_0 -> \"NVOID\" [id=\"nps-NVOID\"];\n\t\"NGETS\" [id=\"store:NGETS\", shape=\"box\"];\n\tnode_cmd_3_3_0 -> \"NGETS\" [id=\"nps-NGETS\"];\n\t\"IDLEN\" [id=\"store:IDLEN\", shape=\"box\"];\n\tnode_cmd_3_4_0 -> \"IDLEN\" [id=\"nps-IDLEN\"];\n\t\"CHLINESCHAR\" [id=\"store:CHLINESCHAR\", shape=\"box\"];\n\tnode_cmd_2_1_0 -> \"CHLINESCHAR\" [id=\"nps-CHLINESCHAR\"];\n\t\"NCCHAR\" [id=\"store:NCCHAR\", shape=\"box\"];\n\tnode_cmd_2_2_0 -> \"NCCHAR\" [id=\"nps-NCCHAR\"];\n\t\"NCOMMENT\" [id=\"store:NCOMMENT\", shape=\"box\"];\n\tnode_cmd_2_3_0 -> \"NCOMMENT\" [id=\"nps-NCOMMENT\"];\n\t\"NCOPYRIGHT\" [id=\"store:NCOPYRIGHT\", shape=\"box\"];\n\tnode_cmd_2_4_0 -> \"NCOPYRIGHT\" [id=\"nps-NCOPYRIGHT\"];\n\t\"NCFILE\" [id=\"store:NCFILE\", shape=\"box\"];\n\tnode_cmd_5_0_0 -> \"NCFILE\" [id=\"nps-NCFILE\"];\n\t\"NCDIR\" [id=\"store:NCDIR\", shape=\"box\"];\n\tnode_cmd_5_1_0 -> \"NCDIR\" [id=\"nps-NCDIR\"];\n\t\"CLINESCHAR\" [id=\"store:CLINESCHAR\", shape=\"box\"];\n\tnode_cmd_6_0_0 -> \"CLINESCHAR\" [id=\"nps-CLINESCHAR\"];\n\t\"NFUNCTION\" [id=\"store:NFUNCTION\", shape=\"box\"];\n\tnode_cmd_7_0_0 -> \"NFUNCTION\" [id=\"nps-NFUNCTION\"];\n\t\"NGOTO\" [id=\"store:NGOTO\", shape=\"box\"];\n\tnode_cmd_7_1_0 -> \"NGOTO\" [id=\"nps-NGOTO\"];\n\t\"NREGISTER\" [id=\"store:NREGISTER\", shape=\"box\"];\n\tnode_cmd_7_2_0 -> \"NREGISTER\" [id=\"nps-NREGISTER\"];\n\t\"NMACRO\" [id=\"store:NMACRO\", shape=\"box\"];\n\tnode_cmd_7_3_0 -> \"NMACRO\" [id=\"nps-NMACRO\"];\n\t\"NINCLUDE\" [id=\"store:NINCLUDE\", shape=\"box\"];\n\tnode_cmd_7_4_0 -> \"NINCLUDE\" [id=\"nps-NINCLUDE\"];\n\t\"NCONST\" [id=\"store:NCONST\", shape=\"box\"];\n\tnode_cmd_7_5_0 -> \"NCONST\" [id=\"nps-NCONST\"];\n\t\"NHFILE\" [id=\"store:NHFILE\", shape=\"box\"];\n\tnode_cmd_0_2_0 -> \"NHFILE\" [id=\"nps-NHFILE\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"find \\\"$@\\\" \\\\( -name \\\\*.c -or -name \\\\*.h \\\\) -type f -print0\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_0_0 [id=\"node_cmd_1_0_0\", label=\"tr \\\\\\\\0 \\\\\\\\n |\\l# Remove path\\lsed 's|^.*/||' |\\l# Maintain average\\lawk '{s += length($1); n++} END {print s / n}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_1_0 [id=\"node_cmd_1_1_0\", label=\"xargs -0 cat\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_0_0 [id=\"node_cmd_2_0_0\", label=\"sed 's/#/@/g;s/\\\\\\\\[\\\\\\\\\\\"'\\\\'']/@/g;s/\\\"[^\\\"]*\\\"/\\\"\\\"/g;'\\\"s/'[^']*'/''/g\\\" |\\lcpp -P 2>/dev/null\\l\", shape=\"ellipse\"];\n\tnode_cmd_3_0_0 [id=\"node_cmd_3_0_0\", label=\"egrep -c 'struct[ \t]*{|struct[ \t]*[a-zA-Z_][a-zA-Z0-9_]*[       ]*{'\\l\", shape=\"ellipse\"];\n\tnode_cmd_3_1_0 [id=\"node_cmd_3_1_0\", label=\"grep -cw typedef\\l\", shape=\"ellipse\"];\n\tnode_cmd_3_2_0 [id=\"node_cmd_3_2_0\", label=\"grep -cw void\\l\", shape=\"ellipse\"];\n\tnode_cmd_3_3_0 [id=\"node_cmd_3_3_0\", label=\"grep -cw gets\\l\", shape=\"ellipse\"];\n\tnode_cmd_3_4_0 [id=\"node_cmd_3_4_0\", label=\"tr -cs 'A-Za-z0-9_' '\\\\n' |\\lsort -u |\\lawk '/^[A-Za-z]/ { len += length($1); n++ } END {print len / n}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_1_0 [id=\"node_cmd_2_1_0\", label=\"wc -lc | awk '{OFS=\\\":\\\"; print $1, $2}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_2_0 [id=\"node_cmd_2_2_0\", label=\"sed 's/#/@/g' |\\lcpp -traditional -P 2>/dev/null |\\lwc -c |\\lawk '{OFMT = \\\"%.0f\\\"; print $1/1000}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_3_0 [id=\"node_cmd_2_3_0\", label=\"egrep -c '/\\\\*|//'\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_4_0 [id=\"node_cmd_2_4_0\", label=\"grep -ci copyright\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"find \\\"$@\\\" -name \\\\*.c -type f -print0\\l\", shape=\"ellipse\"];\n\tnode_cmd_4_0_0 [id=\"node_cmd_4_0_0\", label=\"tr \\\\\\\\0 \\\\\\\\n\\l\", shape=\"ellipse\"];\n\tnode_cmd_5_0_0 [id=\"node_cmd_5_0_0\", label=\"wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_5_1_0 [id=\"node_cmd_5_1_0\", label=\"sed 's,/[^/]*$,,;s,^.*/,,' | sort -u | wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_4_1_0 [id=\"node_cmd_4_1_0\", label=\"xargs -0 cat\\l\", shape=\"ellipse\"];\n\tnode_cmd_6_0_0 [id=\"node_cmd_6_0_0\", label=\"wc -lc | awk '{OFS=\\\":\\\"; print $1, $2}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_6_1_0 [id=\"node_cmd_6_1_0\", label=\"sed 's/#/@/g;s/\\\\\\\\[\\\\\\\\\\\"'\\\\'']/@/g;s/\\\"[^\\\"]*\\\"/\\\"\\\"/g;'\\\"s/'[^']*'/''/g\\\" |\\lcpp -P 2>/dev/null\\l\", shape=\"ellipse\"];\n\tnode_cmd_7_0_0 [id=\"node_cmd_7_0_0\", label=\"grep -c '^{'\\l\", shape=\"ellipse\"];\n\tnode_cmd_7_1_0 [id=\"node_cmd_7_1_0\", label=\"grep -cw goto\\l\", shape=\"ellipse\"];\n\tnode_cmd_7_2_0 [id=\"node_cmd_7_2_0\", label=\"grep -cw register\\l\", shape=\"ellipse\"];\n\tnode_cmd_7_3_0 [id=\"node_cmd_7_3_0\", label=\"grep -c '@[ \t]*define[ \t][ \t]*[a-zA-Z_][a-zA-Z0-9_]*('\\l\", shape=\"ellipse\"];\n\tnode_cmd_7_4_0 [id=\"node_cmd_7_4_0\", label=\"grep -c '@[ \t]*include'\\l\", shape=\"ellipse\"];\n\tnode_cmd_7_5_0 [id=\"node_cmd_7_5_0\", label=\"grep -o -h '[0-9][x0-9][0-9a-f]*' | wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"find \\\"$@\\\" -name \\\\*.h -type f | wc -l\\l\", shape=\"ellipse\"];\n\tFNAMELEN -> gather_node_0 [id=\"store-read\"];\n\tNSTRUCT -> gather_node_0 [id=\"store-read\"];\n\tNTYPEDEF -> gather_node_0 [id=\"store-read\"];\n\tIDLEN -> gather_node_0 [id=\"store-read\"];\n\tCHLINESCHAR -> gather_node_0 [id=\"store-read\"];\n\tNCCHAR -> gather_node_0 [id=\"store-read\"];\n\tNCOMMENT -> gather_node_0 [id=\"store-read\"];\n\tNCOPYRIGHT -> gather_node_0 [id=\"store-read\"];\n\tNCFILE -> gather_node_0 [id=\"store-read\"];\n\tNCDIR -> gather_node_0 [id=\"store-read\"];\n\tCLINESCHAR -> gather_node_0 [id=\"store-read\"];\n\tNFUNCTION -> gather_node_0 [id=\"store-read\"];\n\tNGOTO -> gather_node_0 [id=\"store-read\"];\n\tNREGISTER -> gather_node_0 [id=\"store-read\"];\n\tNMACRO -> gather_node_0 [id=\"store-read\"];\n\tNINCLUDE -> gather_node_0 [id=\"store-read\"];\n\tNCONST -> gather_node_0 [id=\"store-read\"];\n\tNVOID -> gather_node_0 [id=\"store-read\"];\n\tNHFILE -> gather_node_0 [id=\"store-read\"];\n\tNGETS -> gather_node_0 [id=\"store-read\"];\n\tgather_node_0 [id=\"gather_node_0\", label=\"cat <<EOF\\lFNAMELEN: `store:FNAMELEN`\\lNSTRUCT: `store:NSTRUCT`\\lNTYPEDEF: `store:NTYPEDEF`\\lIDLEN: `store:IDLEN`\\lCHLINESCHAR: `store:CHLINESCHAR`\\lNCCHAR: `store:NCCHAR`\\lNCOMMENT: `store:NCOMMENT`\\lNCOPYRIGHT: `store:NCOPYRIGHT`\\lNCFILE: `store:NCFILE`\\lNCDIR: `store:NCDIR`\\lCLINESCHAR: `store:CLINESCHAR`\\lNFUNCTION: `store:NFUNCTION`\\lNGOTO: `store:NGOTO`\\lNREGISTER: `store:NREGISTER`\\lNMACRO: `store:NMACRO`\\lNINCLUDE: `store:NINCLUDE`\\lNCONST: `store:NCONST`\\lNVOID: `store:NVOID`\\lNHFILE: `store:NHFILE`\\lNGETS: `store:NGETS`\\lEOF\\l\", shape=\"ellipse\"];\n\tnode_cmd_6_1_0 -> node_cmd_7_5_0 [id=\"npi-7.5.0\"];\n\tnode_cmd_4_0_0 -> node_cmd_5_1_0 [id=\"npi-5.1.0\"];\n\tnode_cmd_2_0_0 -> node_cmd_3_1_0 [id=\"npi-3.1.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_1_1_0 [id=\"npi-1.1.0\"];\n\tnode_cmd_2_0_0 -> node_cmd_3_3_0 [id=\"npi-3.3.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_4_0 [id=\"npi-2.4.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_1_0_0 [id=\"npi-1.0.0\"];\n\tnode_cmd_2_0_0 -> node_cmd_3_0_0 [id=\"npi-3.0.0\"];\n\tnode_cmd_4_1_0 -> node_cmd_6_1_0 [id=\"npi-6.1.0\"];\n\tnode_cmd_4_0_0 -> node_cmd_5_0_0 [id=\"npi-5.0.0\"];\n\tnode_cmd_6_1_0 -> node_cmd_7_2_0 [id=\"npi-7.2.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_2_0 [id=\"npi-2.2.0\"];\n\tnode_cmd_2_0_0 -> node_cmd_3_2_0 [id=\"npi-3.2.0\"];\n\tnode_cmd_0_1_0 -> node_cmd_4_0_0 [id=\"npi-4.0.0\"];\n\tnode_cmd_6_1_0 -> node_cmd_7_1_0 [id=\"npi-7.1.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_3_0 [id=\"npi-2.3.0\"];\n\tnode_cmd_4_1_0 -> node_cmd_6_0_0 [id=\"npi-6.0.0\"];\n\tnode_cmd_6_1_0 -> node_cmd_7_4_0 [id=\"npi-7.4.0\"];\n\tnode_cmd_0_1_0 -> node_cmd_4_1_0 [id=\"npi-4.1.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_0_0 [id=\"npi-2.0.0\"];\n\tnode_cmd_6_1_0 -> node_cmd_7_3_0 [id=\"npi-7.3.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_1_0 [id=\"npi-2.1.0\"];\n\tnode_cmd_2_0_0 -> node_cmd_3_4_0 [id=\"npi-3.4.0\"];\n\tnode_cmd_6_1_0 -> node_cmd_7_0_0 [id=\"npi-7.0.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/commit-stats.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"awk -F: '{print $1}' | forder\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"awk -F: '{print substr($2, 1, 3)}' | forder\\l\", shape=\"ellipse\"];\n\tgather_node_1 [id=\"gather_node_1\", label=\"cat /stream/authors\\l\", shape=\"ellipse\"];\n\tgather_node_3 [id=\"gather_node_3\", label=\"cat /stream/days\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_cmd_0_0_0 -> gather_node_1 [id=\"npfo-authors.0\"];\n\tnode_cmd_0_1_0 -> gather_node_3 [id=\"npfo-days.0\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/committer-plot.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\t\"NCOMMITTERS\" [id=\"store:NCOMMITTERS\", shape=\"box\"];\n\tnode_cmd_0_0_0 -> \"NCOMMITTERS\" [id=\"nps-NCOMMITTERS\"];\n\t\"LAST\" [id=\"store:LAST\", shape=\"box\"];\n\tnode_cmd_0_1_0 -> \"LAST\" [id=\"nps-LAST\"];\n\t\"FIRST\" [id=\"store:FIRST\", shape=\"box\"];\n\tnode_cmd_0_2_0 -> \"FIRST\" [id=\"nps-FIRST\"];\n\t\"NDAYS\" [id=\"store:NDAYS\", shape=\"box\"];\n\tnode_cmd_0_3_0 -> \"NDAYS\" [id=\"nps-NDAYS\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"awk '{print $2}' | sort -u | wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"tail -1 | awk '{print $1}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"head -1 | awk '{print $1}'\\l\", shape=\"ellipse\"];\n\tLAST -> node_cmd_0_3_0 [id=\"store-read\"];\n\tFIRST -> node_cmd_0_3_0 [id=\"store-read\"];\n\tnode_cmd_0_3_0 [id=\"node_cmd_0_3_0\", label=\"expr \\\\( `store:LAST` - `store:FIRST` \\\\) / 60 / 60  / 24\\l\", shape=\"ellipse\"];\n\tNCOMMITTERS -> node_cmd_0_4_0 [id=\"store-read\"];\n\tnode_cmd_0_4_0 [id=\"node_cmd_0_4_0\", label=\"awk '{print $2}' |\\lsort |\\luniq -c |\\lsort -n |\\lawk 'BEGIN {l = 0; r = '`store:NCOMMITTERS`';}\\l{print NR % 2 ? l++ : --r, $2}' |\\lsort -k2\\l\", shape=\"ellipse\"];\n\tNCOMMITTERS -> node_cmd_0_5_0 [id=\"store-read\"];\n\tNDAYS -> node_cmd_0_5_0 [id=\"store-read\"];\n\tNCOMMITTERS -> node_cmd_0_5_0 [id=\"store-read\"];\n\tnode_cmd_0_5_0 [id=\"node_cmd_0_5_0\", label=\"sort -k2 |\\ljoin -j 2 - /stream/committerpos |\\l# Order by time\\lsort -k 2n |\\l{\\l# Create portable bitmap\\lecho 'P1'\\lecho \\\"`store:NCOMMITTERS` `store:NDAYS`\\\"\\lperl -na -e '\\lBEGIN { @empty['`store:NCOMMITTERS`' - 1] = 0; @committers = @empty; }\\lsub out { print join(\\\"\\\", map($_ ? \\\"1\\\" : \\\"0\\\", @committers)), \\\"\\\\n\\\"; }\\l$day = int($F[1] / 60 / 60 / 24);\\l$pday = $day if (!defined($pday));\\lwhile ($day != $pday) {\\lout();\\l@committers = @empty;\\l$pday++;\\l}\\l$committers[$F[2]] = 1;\\lEND { out(); }\\l'\\l} |\\l# Enlarge points into discs through morphological convolution\\lpgmmorphconv -erode <(\\lcat <<EOF\\lP1\\l7 7\\l0 0 0 1 0 0 0\\l0 0 1 1 1 0 0\\l0 1 1 1 1 1 0\\l1 1 1 1 1 1 1\\l0 1 1 1 1 1 0\\l0 0 1 1 1 0 0\\l0 0 0 1 0 0 0\\lEOF\\l)\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_0_0 [id=\"node_cmd_1_0_0\", label=\"pnmtopng >large.png\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_1_0 [id=\"node_cmd_1_1_0\", label=\"pamscale -width 640 |\\lpnmtopng >small.png\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_cmd_0_5_0 -> node_cmd_1_0_0 [id=\"npi-1.0.0\"];\n\tnode_cmd_0_4_0 -> node_cmd_0_5_0 [id=\"npfo-committerpos.0\"];\n\tnode_tee_0 -> node_cmd_0_5_0 [id=\"npi-0.5.0\"];\n\tnode_tee_0 -> node_cmd_0_4_0 [id=\"npi-0.4.0\"];\n\tnode_tee_0 -> node_cmd_0_2_0 [id=\"npi-0.2.0\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n\tnode_cmd_0_5_0 -> node_cmd_1_1_0 [id=\"npi-1.1.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/compress-compare.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\t\"NBYTES\" [id=\"store:NBYTES\", shape=\"box\"];\n\tnode_cmd_0_0_0 -> \"NBYTES\" [id=\"nps-NBYTES\"];\n\t\"FILETYPE\" [id=\"store:FILETYPE\", shape=\"box\"];\n\tnode_cmd_0_1_0 -> \"FILETYPE\" [id=\"nps-FILETYPE\"];\n\t\"XZ\" [id=\"store:XZ\", shape=\"box\"];\n\tnode_cmd_0_2_0 -> \"XZ\" [id=\"nps-XZ\"];\n\t\"BZIP2\" [id=\"store:BZIP2\", shape=\"box\"];\n\tnode_cmd_0_3_0 -> \"BZIP2\" [id=\"nps-BZIP2\"];\n\t\"GZIP\" [id=\"store:GZIP\", shape=\"box\"];\n\tnode_cmd_0_4_0 -> \"GZIP\" [id=\"nps-GZIP\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"wc -c\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"file -\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"xz -c | wc -c\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_3_0 [id=\"node_cmd_0_3_0\", label=\"bzip2 -c | wc -c\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_4_0 [id=\"node_cmd_0_4_0\", label=\"gzip -c | wc -c\\l\", shape=\"ellipse\"];\n\tFILETYPE -> gather_node_0 [id=\"store-read\"];\n\tNBYTES -> gather_node_0 [id=\"store-read\"];\n\tGZIP -> gather_node_0 [id=\"store-read\"];\n\tBZIP2 -> gather_node_0 [id=\"store-read\"];\n\tXZ -> gather_node_0 [id=\"store-read\"];\n\tgather_node_0 [id=\"gather_node_0\", label=\"cat <<EOF\\lFile type:\t`store:FILETYPE`\\lOriginal size:\t`store:NBYTES` bytes\\lgzip:\t\t`store:GZIP` bytes\\lbzip2:\t\t`store:BZIP2` bytes\\lxz:\t\t`store:XZ` bytes\\lEOF\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_tee_0 -> node_cmd_0_3_0 [id=\"npi-0.3.0\"];\n\tnode_tee_0 -> node_cmd_0_4_0 [id=\"npi-0.4.0\"];\n\tnode_tee_0 -> node_cmd_0_2_0 [id=\"npi-0.2.0\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/dir.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\t\"NFILES\" [id=\"store:NFILES\", shape=\"box\"];\n\tnode_cmd_0_1_0 -> \"NFILES\" [id=\"nps-NFILES\"];\n\t\"NDIRS\" [id=\"store:NDIRS\", shape=\"box\"];\n\tnode_cmd_0_2_0 -> \"NDIRS\" [id=\"nps-NDIRS\"];\n\t\"NBYTES\" [id=\"store:NBYTES\", shape=\"box\"];\n\tnode_cmd_0_3_0 -> \"NBYTES\" [id=\"nps-NBYTES\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"awk '!/^total/ {print $6, $7, $8, $1, sprintf(\\\"%8d\\\", $5), $9}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"grep -c '^d'\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_3_0 [id=\"node_cmd_0_3_0\", label=\"awk '{s += $5} END {print s}'\\l\", shape=\"ellipse\"];\n\tgather_node_0 [id=\"gather_node_0\", label=\"cat /stream/files\\l\", shape=\"ellipse\"];\n\tNFILES -> gather_node_1 [id=\"store-read\"];\n\tNBYTES -> gather_node_1 [id=\"store-read\"];\n\tgather_node_1 [id=\"gather_node_1\", label=\"echo \\\"               `store:NFILES` File(s) `store:NBYTES` bytes\\\"\\l\", shape=\"ellipse\"];\n\tNDIRS -> gather_node_2 [id=\"store-read\"];\n\tgather_node_2 [id=\"gather_node_2\", label=\"echo \\\"               `store:NDIRS` Dir(s) $FREE bytes free\\\"\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_cmd_0_0_0 -> gather_node_0 [id=\"npfo-files.0\"];\n\tnode_tee_0 -> node_cmd_0_3_0 [id=\"npi-0.3.0\"];\n\tnode_tee_0 -> node_cmd_0_2_0 [id=\"npi-0.2.0\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/duplicate-files.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"awk '{print $2}' | uniq -d\\l\", shape=\"ellipse\"];\n\tgather_node_1 [id=\"gather_node_1\", label=\"join -2 2 /stream/dupes /stream/names |\\l# Output same files on a single line\\lawk '\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_0 -> gather_node_1 [id=\"npfo-dupes.0\"];\n\tnode_tee_0 -> gather_node_1 [id=\"npfo-names.0\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/ft2d.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"sfspike n1=64 n2=64 d1=1 d2=1 nsp=2 k1=16,17 k2=5,5 mag=16,16 \\\\\\llabel1='time' label2='space' unit1= unit2= |\\lsfsmooth rect2=2 |\\lsfsmooth rect2=2\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_0_0 [id=\"node_cmd_1_0_0\", label=\"sfgrey pclip=100 wanttitle=n\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_1_0 [id=\"node_cmd_1_1_0\", label=\"sffft1 | sffft3 axis=2 pad=1 | sfreal\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_0_0 [id=\"node_cmd_2_0_0\", label=\"sgsh-tee -I\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_1_0 [id=\"node_cmd_2_1_0\", label=\"sfwindow f1=1 |\\lsfreverse which=3 |\\lsfcat axis=1 /stream/ft2d |\\lsfgrey pclip=100 wanttitle=n \\\\\\llabel1=\\\"1/time\\\" label2=\\\"1/space\\\"\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"side_by_side_iso /stream/pulse.vpl /stream/ft2d.vpl \\\\\\lyscale=1.25 >Fig/ft2dofpulse.vpl\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_0_0 -> node_cmd_2_1_0 [id=\"npfo-ft2d.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_1_0_0 [id=\"npi-1.0.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_0_0 [id=\"npi-2.0.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_1_1_0 [id=\"npi-1.1.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_1_0 [id=\"npi-2.1.0\"];\n\tnode_cmd_1_0_0 -> node_cmd_0_1_0 [id=\"npfo-pulse.vpl.0\"];\n\tnode_cmd_2_1_0 -> node_cmd_0_1_0 [id=\"npfo-ft2d.vpl.0\"];\n}\n\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"sfspike n1=64 d1=1 o1=32 nsp=4 k1=1,2,3,4 mag=1,3,3,1 \\\\\\llabel1='time' unit1= |\\lsfspray n=32 d=1 o=0 |\\lsfput label2=space |\\lsflmostretch delay=0 v0=-1\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_0_0 [id=\"node_cmd_1_0_0\", label=\"sgsh-tee -I\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_1_0 [id=\"node_cmd_1_1_0\", label=\"sfwindow f2=1 |\\lsfreverse which=2 |\\lsfcat axis=2 /stream/air\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_0_0 [id=\"node_cmd_2_0_0\", label=\"sfgrey pclip=100 wanttitle=n\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_1_0 [id=\"node_cmd_2_1_0\", label=\"sffft1 |\\lsffft3 sign=1\\l\", shape=\"ellipse\"];\n\tnode_cmd_3_0_0 [id=\"node_cmd_3_0_0\", label=\"sfreal\\l\", shape=\"ellipse\"];\n\tnode_cmd_3_1_0 [id=\"node_cmd_3_1_0\", label=\"sfimag\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"sfmath re=/stream/airftr im=/stream/airfti output=\\\"sqrt(re*re+im*im)\\\"\\l\", shape=\"ellipse\"];\n\tnode_cmd_4_0_0 [id=\"node_cmd_4_0_0\", label=\"sgsh-tee -I\\l\", shape=\"ellipse\"];\n\tnode_cmd_4_1_0 [id=\"node_cmd_4_1_0\", label=\"sfwindow f1=1 |\\lsfreverse which=3 |\\lsfcat axis=1 /stream/airft1 |\\lsfgrey pclip=100 wanttitle=n label1=\\\"1/time\\\" \\\\\\llabel2=\\\"1/space\\\"\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"side_by_side_iso /stream/airtx.vpl /stream/airfk.vpl \\\\\\lyscale=1.25 >Fig/airwave.vpl\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_1_0 -> node_cmd_3_1_0 [id=\"npi-3.1.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_1_1_0 [id=\"npi-1.1.0\"];\n\tnode_cmd_1_0_0 -> node_cmd_0_1_0 [id=\"npfo-pulse.vpl.0\"];\n\tnode_cmd_2_1_0 -> node_cmd_0_1_0 [id=\"npfo-ft2d.vpl.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_1_0_0 [id=\"npi-1.0.0\"];\n\tnode_cmd_2_1_0 -> node_cmd_3_0_0 [id=\"npi-3.0.0\"];\n\tnode_cmd_2_0_0 -> node_cmd_0_2_0 [id=\"npfo-airtx.vpl.0\"];\n\tnode_cmd_4_0_0 -> node_cmd_4_1_0 [id=\"npfo-airft1.0\"];\n\tnode_cmd_3_1_0 -> node_cmd_0_1_0 [id=\"npfo-airfti.0\"];\n\tnode_cmd_0_1_0 -> node_cmd_4_0_0 [id=\"npi-4.0.0\"];\n\tnode_cmd_4_1_0 -> node_cmd_0_2_0 [id=\"npfo-airfk.vpl.0\"];\n\tnode_cmd_3_0_0 -> node_cmd_0_1_0 [id=\"npfo-airftr.0\"];\n\tnode_cmd_0_1_0 -> node_cmd_4_1_0 [id=\"npi-4.1.0\"];\n\tnode_cmd_2_0_0 -> node_cmd_2_1_0 [id=\"npfo-ft2d.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_0_0 [id=\"npi-2.0.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_1_0 [id=\"npi-2.1.0\"];\n\tnode_cmd_1_0_0 -> node_cmd_1_1_0 [id=\"npfo-air.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/map-hierarchy.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"line_signatures $1\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"line_signatures $2\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"join -t\u0001 -1 2 -2 2 /stream/a /stream/b |\\l# Print filename dir1 dir2\\lsed 's/\u0002/\u0001/g' |\\lawk -F\u0001 'BEGIN{OFS=\\\" \\\"}{print $1, $3, $4}' |\\l# Unique occurrences\\lsort -u\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_0_0 [id=\"node_cmd_1_0_0\", label=\"awk '{print \\\"cp \\\\\\\"\\\" $2 \\\"/\\\" $1 \\\"\\\\\\\" \\\\\\\"'$NEWDIR'/\\\" $3 \\\"/\\\" $1 \\\"\\\\\\\"\\\"}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_1_0 [id=\"node_cmd_1_1_0\", label=\"awk '{print \\\"mkdir -p \\\\\\\"'$NEWDIR'/\\\" $3 \\\"\\\\\\\"\\\"}' | sort -u\\l\", shape=\"ellipse\"];\n\tgather_node_1 [id=\"gather_node_1\", label=\"cat /stream/mkdir /stream/cp |\\lsh\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_1_0 -> gather_node_1 [id=\"npfo-mkdir.0\"];\n\tnode_cmd_0_2_0 -> node_cmd_1_0_0 [id=\"npi-1.0.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_0_2_0 [id=\"npfo-a.0\"];\n\tnode_cmd_1_0_0 -> gather_node_1 [id=\"npfo-cp.0\"];\n\tnode_cmd_0_2_0 -> node_cmd_1_1_0 [id=\"npi-1.1.0\"];\n\tnode_cmd_0_1_0 -> node_cmd_0_2_0 [id=\"npfo-b.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/parallel-logresolve.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee  -s\", shape=\"ellipse\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_1 [id=\"node_cmd_0_0_1\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_2 [id=\"node_cmd_0_0_2\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_3 [id=\"node_cmd_0_0_3\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_4 [id=\"node_cmd_0_0_4\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_5 [id=\"node_cmd_0_0_5\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_6 [id=\"node_cmd_0_0_6\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_7 [id=\"node_cmd_0_0_7\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_8 [id=\"node_cmd_0_0_8\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_9 [id=\"node_cmd_0_0_9\", label=\"logresolve\\l\", shape=\"ellipse\"];\n\tgather_node_1 [id=\"gather_node_1\", label=\"sort -m -k2n /stream/resolved |\\l# Remove second field\\lcut -d ' ' -f 1,3-\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_0_0 -> gather_node_1 [id=\"npfo-resolved.0\"];\n\tnode_tee_0 -> node_cmd_0_0_2 [id=\"npi-0.0.2\"];\n\tnode_tee_0 -> node_cmd_0_0_7 [id=\"npi-0.0.7\"];\n\tnode_tee_0 -> node_cmd_0_0_3 [id=\"npi-0.0.3\"];\n\tnode_cmd_0_0_7 -> gather_node_1 [id=\"npfo-resolved.7\"];\n\tnode_tee_0 -> node_cmd_0_0_9 [id=\"npi-0.0.9\"];\n\tnode_cmd_0_0_8 -> gather_node_1 [id=\"npfo-resolved.8\"];\n\tnode_cmd_0_0_6 -> gather_node_1 [id=\"npfo-resolved.6\"];\n\tnode_cmd_0_0_2 -> gather_node_1 [id=\"npfo-resolved.2\"];\n\tnode_cmd_0_0_9 -> gather_node_1 [id=\"npfo-resolved.9\"];\n\tnode_tee_0 -> node_cmd_0_0_1 [id=\"npi-0.0.1\"];\n\tnode_tee_0 -> node_cmd_0_0_8 [id=\"npi-0.0.8\"];\n\tnode_cmd_0_0_3 -> gather_node_1 [id=\"npfo-resolved.3\"];\n\tnode_cmd_0_0_4 -> gather_node_1 [id=\"npfo-resolved.4\"];\n\tnode_cmd_0_0_5 -> gather_node_1 [id=\"npfo-resolved.5\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n\tnode_tee_0 -> node_cmd_0_0_6 [id=\"npi-0.0.6\"];\n\tnode_tee_0 -> node_cmd_0_0_5 [id=\"npi-0.0.5\"];\n\tnode_tee_0 -> node_cmd_0_0_4 [id=\"npi-0.0.4\"];\n\tnode_cmd_0_0_1 -> gather_node_1 [id=\"npfo-resolved.1\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/spell-highlight.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"sort /usr/share/dict/words\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"tr -cs A-Za-z \\\\\\\\n |\\ltr A-Z a-z |\\lsort -u |\\lcomm -23 - /stream/dict\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"cat\\l\", shape=\"ellipse\"];\n\tgather_node_0 [id=\"gather_node_0\", label=\"fgrep -f /stream/errors -i --color -w -C 2 /stream/text\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_tee_0 -> node_cmd_0_2_0 [id=\"npi-0.2.0\"];\n\tnode_cmd_0_2_0 -> gather_node_0 [id=\"npfo-text.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_0_1_0 [id=\"npfo-dict.0\"];\n\tnode_cmd_0_1_0 -> gather_node_0 [id=\"npfo-errors.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/text-properties.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\t\"NCHARS\" [id=\"store:NCHARS\", shape=\"box\"];\n\tnode_cmd_0_1_0 -> \"NCHARS\" [id=\"nps-NCHARS\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"tr -cs a-zA-Z \\\\\\\\n\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_0_0 [id=\"node_cmd_1_0_0\", label=\"ngram 2 >digram.txt\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_1_0 [id=\"node_cmd_1_1_0\", label=\"ngram 3 >trigram.txt\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_2_0 [id=\"node_cmd_1_2_0\", label=\"ranked_frequency >words.txt\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"wc -c\\l\", shape=\"ellipse\"];\n\tNCHARS -> node_cmd_0_2_0 [id=\"store-read\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"sed 's/./&\\\\\\l/g' |\\l# Print absolute and percentage\\lranked_frequency |\\lawk 'BEGIN {OFMT = \\\"%.2g%%\\\"}\\l{print $1, $2, $1 / '\\\"`store:NCHARS`\\\"' * 100}' >character.txt\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_1_2_0 [id=\"npi-1.2.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_1_0_0 [id=\"npi-1.0.0\"];\n\tnode_tee_0 -> node_cmd_0_2_0 [id=\"npi-0.2.0\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n\tnode_cmd_0_0_0 -> node_cmd_1_1_0 [id=\"npi-1.1.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/web-log-report.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\t\"nXBytes\" [id=\"store:nXBytes\", shape=\"box\"];\n\tnode_cmd_0_0_0 -> \"nXBytes\" [id=\"nps-nXBytes\"];\n\t\"nLogBytes\" [id=\"store:nLogBytes\", shape=\"box\"];\n\tnode_cmd_0_1_0 -> \"nLogBytes\" [id=\"nps-nLogBytes\"];\n\t\"nAccess\" [id=\"store:nAccess\", shape=\"box\"];\n\tnode_cmd_1_0_0 -> \"nAccess\" [id=\"nps-nAccess\"];\n\t\"nHosts\" [id=\"store:nHosts\", shape=\"box\"];\n\tnode_cmd_3_0_0 -> \"nHosts\" [id=\"nps-nHosts\"];\n\t\"nTLD\" [id=\"store:nTLD\", shape=\"box\"];\n\tnode_cmd_3_1_0 -> \"nTLD\" [id=\"nps-nTLD\"];\n\t\"nDomain\" [id=\"store:nDomain\", shape=\"box\"];\n\tnode_cmd_4_0_0 -> \"nDomain\" [id=\"nps-nDomain\"];\n\t\"nPages\" [id=\"store:nPages\", shape=\"box\"];\n\tnode_cmd_5_1_0 -> \"nPages\" [id=\"nps-nPages\"];\n\t\"nDays\" [id=\"store:nDays\", shape=\"box\"];\n\tnode_cmd_7_0_0 -> \"nDays\" [id=\"nps-nDays\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"awk '{s += $NF} END {print s}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"wc -c\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"awk '{print $1}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_0_0 [id=\"node_cmd_1_0_0\", label=\"wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_1_0 [id=\"node_cmd_1_1_0\", label=\"sort\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_0_0 [id=\"node_cmd_2_0_0\", label=\"uniq\\l\", shape=\"ellipse\"];\n\tnode_cmd_3_0_0 [id=\"node_cmd_3_0_0\", label=\"wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_3_1_0 [id=\"node_cmd_3_1_0\", label=\"awk -F. '$NF !~ /[0-9]/ {print $NF}' |\\lsort -u | wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_2_1_0 [id=\"node_cmd_2_1_0\", label=\"{\\lheader 'Top 10 Hosts'\\ltoplist 10\\l}\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_2_0 [id=\"node_cmd_1_2_0\", label=\"{\\lheader 'Top 20 Level Domain Accesses'\\lawk -F. '$NF !~ /^[0-9]/ {print $NF}' |\\lsort |\\ltoplist 20\\l}\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_3_0 [id=\"node_cmd_1_3_0\", label=\"awk -F. 'BEGIN {OFS = \\\".\\\"}\\l$NF !~ /^[0-9]/ {$1 = \\\"\\\"; print}' | sort\\l\", shape=\"ellipse\"];\n\tnode_cmd_4_0_0 [id=\"node_cmd_4_0_0\", label=\"uniq | wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_4_1_0 [id=\"node_cmd_4_1_0\", label=\"{\\lheader 'Top 10 Domains'\\ltoplist 10\\l}\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_3_0 [id=\"node_cmd_0_3_0\", label=\"{\\lheader 'Top 10 Hosts by Transfer'\\lawk '    {bytes[$1] += $NF}\\lEND {for (h in bytes) print bytes[h], h}' |\\lsort -rn |\\lhead -10\\l}\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_4_0 [id=\"node_cmd_0_4_0\", label=\"awk '{print $7}' | sort\\l\", shape=\"ellipse\"];\n\tnode_cmd_5_0_0 [id=\"node_cmd_5_0_0\", label=\"{\\lheader 'Top 20 Area Requests'\\lawk -F/ '{print $2}' |\\ltoplist 20\\l}\\l\", shape=\"ellipse\"];\n\tnode_cmd_5_1_0 [id=\"node_cmd_5_1_0\", label=\"uniq | wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_5_2_0 [id=\"node_cmd_5_2_0\", label=\"{\\lheader 'Top 20 Requests'\\ltoplist 20\\l}\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_5_0 [id=\"node_cmd_0_5_0\", label=\"awk '{print substr($4, 2)}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_6_0_0 [id=\"node_cmd_6_0_0\", label=\"awk -F: '{print $1}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_7_0_0 [id=\"node_cmd_7_0_0\", label=\"uniq | wc -l\\l\", shape=\"ellipse\"];\n\tnode_cmd_7_1_0 [id=\"node_cmd_7_1_0\", label=\"{\\lheader 'Accesses by Date'\\luniq -c\\l}\\l\", shape=\"ellipse\"];\n\tnode_cmd_7_2_0 [id=\"node_cmd_7_2_0\", label=\"{\\lheader 'Accesses by Day of Week'\\lsed 's|/|-|g' |\\l(date -f - +%a 2>/dev/null || gdate -f - +%a) |\\lsort |\\luniq -c |\\lsort -rn\\l}\\l\", shape=\"ellipse\"];\n\tnode_cmd_6_1_0 [id=\"node_cmd_6_1_0\", label=\"{\\lheader 'Accesses by Local Hour'\\lawk -F: '{print $2}' |\\lsort |\\luniq -c\\l}\\l\", shape=\"ellipse\"];\n\tnAccess -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnXBytes -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnHosts -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnDomain -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnTLD -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnPages -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnAccess -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnDays -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnXBytes -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnDays -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnLogBytes -> node_cmd_0_6_0 [id=\"store-read\"];\n\tnode_cmd_0_6_0 [id=\"node_cmd_0_6_0\", label=\"cat <<EOF\\lWWW server statistics\\l=====================\\lSummary\\l-------\\lNumber of accesses: $(store:nAccess)\\lNumber of Gbytes transferred: $(expr $(store:nXBytes) / 1024 / 1024 / 1024)\\lNumber of hosts: $(store:nHosts)\\lNumber of domains: $(store:nDomain)\\lNumber of top level domains: $(store:nTLD)\\lNumber of different pages: $(store:nPages)\\lAccesses per day: $(expr $(store:nAccess) / $(store:nDays))\\lMBytes per day: $(expr $(store:nXBytes) / $(store:nDays) / 1024 / 1024)\\lMBytes log file size: $(expr $(store:nLogBytes) / 1024 / 1024)\\lEOF\\l\", shape=\"ellipse\"];\n\tgather_node_2 [id=\"gather_node_2\", label=\"cat /stream/summary /stream/top20Request /stream/top20Area /stream/top10HostsByN /stream/top10HostsByVol /stream/top10Domain /stream/top20TLD /stream/accessByDoW /stream/accessByHour /stream/accessByDate\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_4_0 [id=\"npi-0.4.0\"];\n\tnode_cmd_0_2_0 -> node_cmd_1_1_0 [id=\"npi-1.1.0\"];\n\tnode_cmd_0_6_0 -> gather_node_2 [id=\"npfo-summary.0\"];\n\tnode_cmd_0_5_0 -> node_cmd_6_1_0 [id=\"npi-6.1.0\"];\n\tnode_cmd_0_4_0 -> node_cmd_5_0_0 [id=\"npi-5.0.0\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_cmd_6_0_0 -> node_cmd_7_1_0 [id=\"npi-7.1.0\"];\n\tnode_tee_0 -> node_cmd_0_2_0 [id=\"npi-0.2.0\"];\n\tnode_cmd_0_5_0 -> node_cmd_6_0_0 [id=\"npi-6.0.0\"];\n\tnode_cmd_0_3_0 -> gather_node_2 [id=\"npfo-top10HostsByVol.0\"];\n\tnode_cmd_0_4_0 -> node_cmd_5_2_0 [id=\"npi-5.2.0\"];\n\tnode_cmd_2_1_0 -> gather_node_2 [id=\"npfo-top10HostsByN.0\"];\n\tnode_cmd_7_2_0 -> gather_node_2 [id=\"npfo-accessByDoW.0\"];\n\tnode_cmd_1_3_0 -> node_cmd_4_1_0 [id=\"npi-4.1.0\"];\n\tnode_tee_0 -> node_cmd_0_3_0 [id=\"npi-0.3.0\"];\n\tnode_cmd_5_2_0 -> gather_node_2 [id=\"npfo-top20Request.0\"];\n\tnode_cmd_5_0_0 -> gather_node_2 [id=\"npfo-top20Area.0\"];\n\tnode_cmd_2_0_0 -> node_cmd_3_1_0 [id=\"npi-3.1.0\"];\n\tnode_cmd_0_4_0 -> node_cmd_5_1_0 [id=\"npi-5.1.0\"];\n\tnode_cmd_0_2_0 -> node_cmd_1_0_0 [id=\"npi-1.0.0\"];\n\tnode_cmd_2_0_0 -> node_cmd_3_0_0 [id=\"npi-3.0.0\"];\n\tnode_cmd_6_0_0 -> node_cmd_7_2_0 [id=\"npi-7.2.0\"];\n\tnode_cmd_1_3_0 -> node_cmd_4_0_0 [id=\"npi-4.0.0\"];\n\tnode_cmd_0_2_0 -> node_cmd_1_2_0 [id=\"npi-1.2.0\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n\tnode_cmd_6_1_0 -> gather_node_2 [id=\"npfo-accessByHour.0\"];\n\tnode_cmd_0_2_0 -> node_cmd_1_3_0 [id=\"npi-1.3.0\"];\n\tnode_tee_0 -> node_cmd_0_5_0 [id=\"npi-0.5.0\"];\n\tnode_cmd_1_2_0 -> gather_node_2 [id=\"npfo-top20TLD.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_0_0 [id=\"npi-2.0.0\"];\n\tnode_cmd_4_1_0 -> gather_node_2 [id=\"npfo-top10Domain.0\"];\n\tnode_cmd_1_1_0 -> node_cmd_2_1_0 [id=\"npi-2.1.0\"];\n\tnode_cmd_6_0_0 -> node_cmd_7_0_0 [id=\"npi-7.0.0\"];\n\tnode_cmd_7_1_0 -> gather_node_2 [id=\"npfo-accessByDate.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/web-log-stats.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\t\"page\" [id=\"store:page\", shape=\"box\"];\n\tnode_cmd_0_0_0 -> \"page\" [id=\"nps-page\"];\n\t\"total_bytes\" [id=\"store:total_bytes\", shape=\"box\"];\n\tnode_cmd_1_0_0 -> \"total_bytes\" [id=\"nps-total_bytes\"];\n\t\"total_pages\" [id=\"store:total_pages\", shape=\"box\"];\n\tnode_cmd_1_1_0 -> \"total_pages\" [id=\"nps-total_pages\"];\n\t\"bytes\" [id=\"store:bytes\", shape=\"box\"];\n\tnode_cmd_1_2_0 -> \"bytes\" [id=\"nps-bytes\"];\n\t\"bytes_old\" [id=\"store:bytes_old\", shape=\"box\"];\n\tnode_cmd_1_3_0 -> \"bytes_old\" [id=\"nps-bytes_old\"];\n\tnode_cmd_0_0_0 [id=\"node_cmd_0_0_0\", label=\"awk -Winteractive '{print $7}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"awk -Winteractive '{print $10}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_0_0 [id=\"node_cmd_1_0_0\", label=\"awk -Winteractive '{ s += $1; print s}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_1_0 [id=\"node_cmd_1_1_0\", label=\"awk -Winteractive '{print ++n}'\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_2_0 [id=\"node_cmd_1_2_0\", label=\"\\l\", shape=\"ellipse\"];\n\tnode_cmd_1_3_0 [id=\"node_cmd_1_3_0\", label=\"\\l\", shape=\"ellipse\"];\n\tbytes -> gather_node_3 [id=\"store-read\"];\n\tgather_node_3 [id=\"gather_node_3\", label=\"WINDOW_PAGES=$(store:bytes -c | wc -l)\\l\", shape=\"ellipse\"];\n\tbytes -> gather_node_4 [id=\"store-read\"];\n\tgather_node_4 [id=\"gather_node_4\", label=\"WINDOW_BYTES=$(store:bytes -c | sum )\\l\", shape=\"ellipse\"];\n\tbytes_old -> gather_node_5 [id=\"store-read\"];\n\tgather_node_5 [id=\"gather_node_5\", label=\"WINDOW_PAGES_OLD=$(store:bytes_old -c | wc -l)\\l\", shape=\"ellipse\"];\n\tbytes_old -> gather_node_6 [id=\"store-read\"];\n\tgather_node_6 [id=\"gather_node_6\", label=\"WINDOW_BYTES_OLD=$(store:bytes_old -c | sum)\\l\", shape=\"ellipse\"];\n\ttotal_pages -> gather_node_8 [id=\"store-read\"];\n\ttotal_bytes -> gather_node_8 [id=\"store-read\"];\n\tpage -> gather_node_8 [id=\"store-read\"];\n\tgather_node_8 [id=\"gather_node_8\", label=\"cat <<EOF\\lTotal\\l-----\\lPages: $(store:total_pages -c)\\lBytes: $(store:total_bytes -c)\\lOver last ${WINDOW}s\\l--------------------\\lPages: $WINDOW_PAGES\\lBytes: $WINDOW_BYTES\\lkBytes/s: $(awk \\\"END {OFMT=\\\\\\\"%.0f\\\\\\\"; print $WINDOW_BYTES / $WINDOW / 1000}\\\" </dev/null )\\lTop page: $(store:page -c | sort | uniq -c | sort -rn | head -1)\\lChange\\l------\\lRequests: $(change $WINDOW_PAGES_OLD $WINDOW_PAGES)\\lData bytes: $(change $WINDOW_BYTES_OLD $WINDOW_BYTES)\\lEOF\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_cmd_0_1_0 -> node_cmd_1_2_0 [id=\"npi-1.2.0\"];\n\tnode_cmd_0_1_0 -> node_cmd_1_0_0 [id=\"npi-1.0.0\"];\n\tnode_tee_0 -> node_cmd_0_0_0 [id=\"npi-0.0.0\"];\n\tnode_cmd_0_1_0 -> node_cmd_1_1_0 [id=\"npi-1.1.0\"];\n\tnode_cmd_0_1_0 -> node_cmd_1_3_0 [id=\"npi-1.3.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/graphs/word-properties.ok",
    "content": "\n\tdigraph \"\" {\n\t\trankdir = LR;\n\t\tnode [fontname=\"Courier\"];\n\t\tedge [];\n\t\tnode_tee_0 [id=\"node_tee_0\", label=\"sgsh-tee \", shape=\"ellipse\"];\n\tnode_cmd_0_1_0 [id=\"node_cmd_0_1_0\", label=\"sed 's/.*\\\\(.\\\\)\\\\(.\\\\)\\\\2\\\\1.*/p: \\\\1\\\\2-\\\\2\\\\1/;t\\lg'\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_2_0 [id=\"node_cmd_0_2_0\", label=\"sed -E 's/.*([^aeiouyAEIOUY]{4}).*/c: \\\\1/;t\\lg'\\l\", shape=\"ellipse\"];\n\tnode_cmd_0_3_0 [id=\"node_cmd_0_3_0\", label=\"awk '{if (length($1) > 12) print \\\"l:\\\", length($1);\\lelse print \\\"\\\"}'\\l\", shape=\"ellipse\"];\n\tgather_node_1 [id=\"gather_node_1\", label=\"paste /stream/words /stream/palindromes /stream/consonants /stream/long |\\l# List only words satisfying one or more properties\\lgrep :\\l\", shape=\"ellipse\"];\n\tnode_tee_0 -> node_cmd_0_1_0 [id=\"npi-0.1.0\"];\n\tnode_cmd_0_1_0 -> gather_node_1 [id=\"npfo-palindromes.0\"];\n\tnode_tee_0 -> node_cmd_0_3_0 [id=\"npi-0.3.0\"];\n\tnode_cmd_0_3_0 -> gather_node_1 [id=\"npfo-long.0\"];\n\tnode_cmd_0_2_0 -> gather_node_1 [id=\"npfo-consonants.0\"];\n\tnode_tee_0 -> gather_node_1 [id=\"npfo-words.0\"];\n\tnode_tee_0 -> node_cmd_0_2_0 [id=\"npi-0.2.0\"];\n}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/NMRPipe.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/NMRPipe.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Nuclear magnetic resonance processing\n# DESCRIPTION\n# Nuclear magnetic resonance in-phase/anti-phase channel conversion and\n# processing in heteronuclear single quantum coherence spectroscopy.\n# Demonstrate processing of NMR data using the NMRPipe family of programs.\n#\n# See also F. Delaglio, S. Grzesiek, G. W. Vuister, G. Zhu, J. Pfeifer\n# and A. Bax: NMRPipe: a multidimensional spectral processing system based\n# on UNIX pipes. J. Biomol. NMR. 6, 277-293 (1995).\n# http://spin.niddk.nih.gov/NMRPipe/\n#\n\n# The conversion is configured for the following file:\n# http://www.bmrb.wisc.edu/ftp/pub/bmrb/timedomain/bmr6443/timedomain_data/c13-hsqc/june11-se-6426-CA.fid/fid\nvar2pipe -in $1\t\t\t\t\t\t\\\n -xN            1280            -yN     256\t\t\\\n -xT            640             -yT     128\t\t\\\n -xMODE         Complex -yMODE  Complex\t\t\t\\\n -xSW           8000    -ySW    6000\t\t\t\\\n -xOBS          599.4489584     -yOBS   60.7485301      \\\n -xCAR          4.73    -yCAR   118.000\t\t\t\\\n -xLAB          1H      -yLAB   15N\t\t\t\\\n -ndim          2       -aq2D   States\t\t\t\\\n-verb  |\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\t\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-none-0.0.0 \\\n\t$SGDIR/npfo-none-0.1.0 \\\n\t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  nmrPipe |\n\t   nmrPipe -fn SOL |\n\t   nmrPipe -fn SP -off 0.5 -end 0.98 -pow 2 -c 0.5 |\n\t   nmrPipe -fn ZF -auto |\n\t   nmrPipe -fn FT |\n\t   nmrPipe -fn PS -p0 177 -p1 0.0 -di |\n\t   nmrPipe -fn EXT -left -sw -verb |\n\t   nmrPipe -fn TP |\n\t   nmrPipe -fn COADD -cList 1 0 -time |\n\t   nmrPipe -fn SP -off 0.5 -end 0.98 -pow 1 -c 0.5 |\n\t   nmrPipe -fn ZF -auto |\n\t   nmrPipe -fn FT |\n\t   nmrPipe -fn PS -p0 0 -p1 0 -di |\n\t   nmrPipe -fn TP |\n\t   nmrPipe -fn POLY -auto -verb >A\n: ; } <$SGDIR/npi-0.0.0 >$SGDIR/npfo-none-0.0.0  & SGPID=\"$! $SGPID\"\n {  nmrPipe |\n\t   nmrPipe -fn SOL |\n\t   nmrPipe -fn SP -off 0.5 -end 0.98 -pow 2 -c 0.5 |\n\t   nmrPipe -fn ZF -auto |\n\t   nmrPipe -fn FT |\n\t   nmrPipe -fn PS -p0 177 -p1 0.0 -di |\n\t   nmrPipe -fn EXT -left -sw -verb |\n\t   nmrPipe -fn TP |\n\t   nmrPipe -fn COADD -cList 0 1 -time |\n\t   nmrPipe -fn SP -off 0.5 -end 0.98 -pow 1 -c 0.5 |\n\t   nmrPipe -fn ZF -auto |\n\t   nmrPipe -fn FT |\n\t   nmrPipe -fn PS -p0 -90 -p1 0 -di |\n\t   nmrPipe -fn TP |\n\t   nmrPipe -fn POLY -auto -verb >B\n: ; } <$SGDIR/npi-0.1.0 >$SGDIR/npfo-none-0.1.0  & SGPID=\"$! $SGPID\"\n\n# Gather the results\nsgsh-tee  -i $SGDIR/npfo-none-0.0.0  -i $SGDIR/npfo-none-0.1.0 >/dev/null\n\n)  3<&0 \n\n# We use temporary files rather than streams, because\n# addNMR mmaps its input files. The diagram displayed in the\n# example shows the notional data flow.\naddNMR -in1 A -in2 B -out A+B.sgsh.ft2 -c1 1.0 -c2 1.25 -add\naddNMR -in1 A -in2 B -out A-B.sgsh.ft2 -c1 1.0 -c2 1.25 -sub\n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/code-metrics.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/code-metrics.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS C code metrics\n# DESCRIPTION\n# Process a directory containing C source code, and produce a summary\n# of various metrics.\n# Demonstrates nesting, commands without input.\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\tsgsh-readval -q -s \"$SGDIR/FNAMELEN\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NSTRUCT\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NTYPEDEF\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NVOID\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NGETS\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/IDLEN\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/CHLINESCHAR\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NCCHAR\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NCOMMENT\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NCOPYRIGHT\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NCFILE\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NCDIR\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/CLINESCHAR\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NFUNCTION\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NGOTO\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NREGISTER\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NMACRO\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NINCLUDE\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NCONST\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NHFILE\" 2>/dev/null\n\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npi-1.0.0 \\\n\t$SGDIR/npi-1.1.0 \\\n\t$SGDIR/npi-2.0.0 \\\n\t$SGDIR/npi-2.1.0 \\\n\t$SGDIR/npi-2.2.0 \\\n\t$SGDIR/npi-2.3.0 \\\n\t$SGDIR/npi-2.4.0 \\\n\t$SGDIR/npi-3.0.0 \\\n\t$SGDIR/npi-3.1.0 \\\n\t$SGDIR/npi-3.2.0 \\\n\t$SGDIR/npi-3.3.0 \\\n\t$SGDIR/npi-3.4.0 \\\n\t$SGDIR/npi-4.0.0 \\\n\t$SGDIR/npi-4.1.0 \\\n\t$SGDIR/npi-5.0.0 \\\n\t$SGDIR/npi-5.1.0 \\\n\t$SGDIR/npi-6.0.0 \\\n\t$SGDIR/npi-6.1.0 \\\n\t$SGDIR/npi-7.0.0 \\\n\t$SGDIR/npi-7.1.0 \\\n\t$SGDIR/npi-7.2.0 \\\n\t$SGDIR/npi-7.3.0 \\\n\t$SGDIR/npi-7.4.0 \\\n\t$SGDIR/npi-7.5.0\n\n {  find \"$@\" \\( -name \\*.c -or -name \\*.h \\) -type f -print0\n}</dev/null  |\nsgsh-tee  -o $SGDIR/npi-1.0.0 -o $SGDIR/npi-1.1.0  & SGPID=\"$! $SGPID\"\n {  tr \\\\0 \\\\n |\n\t\t# Remove path\n\t\tsed 's|^.*/||' |\n\t\t# Maintain average\n\t\tawk '{s += length($1); n++} END {print s / n}'\n} <$SGDIR/npi-1.0.0 | sgsh-writeval  -s $SGDIR/FNAMELEN  & SGPID=\"$! $SGPID\"\n {  xargs -0 cat\n} <$SGDIR/npi-1.1.0 |\nsgsh-tee  -o $SGDIR/npi-2.0.0 -o $SGDIR/npi-2.1.0 -o $SGDIR/npi-2.2.0 -o $SGDIR/npi-2.3.0 -o $SGDIR/npi-2.4.0  & SGPID=\"$! $SGPID\"\n {  sed 's/#/@/g;s/\\\\[\\\\\"'\\'']/@/g;s/\"[^\"]*\"/\"\"/g;'\"s/'[^']*'/''/g\" |\n\t\t\tcpp -P 2>/dev/null\n} <$SGDIR/npi-2.0.0 |\nsgsh-tee  -o $SGDIR/npi-3.0.0 -o $SGDIR/npi-3.1.0 -o $SGDIR/npi-3.2.0 -o $SGDIR/npi-3.3.0 -o $SGDIR/npi-3.4.0  & SGPID=\"$! $SGPID\"\n {   egrep -c 'struct[ \t]*{|struct[ \t]*[a-zA-Z_][a-zA-Z0-9_]*[       ]*{'\n} <$SGDIR/npi-3.0.0 | sgsh-writeval  -s $SGDIR/NSTRUCT  & SGPID=\"$! $SGPID\"\n {  grep -cw typedef\n} <$SGDIR/npi-3.1.0 | sgsh-writeval  -s $SGDIR/NTYPEDEF  & SGPID=\"$! $SGPID\"\n {  grep -cw void\n} <$SGDIR/npi-3.2.0 | sgsh-writeval  -s $SGDIR/NVOID  & SGPID=\"$! $SGPID\"\n {  grep -cw gets\n} <$SGDIR/npi-3.3.0 | sgsh-writeval  -s $SGDIR/NGETS  & SGPID=\"$! $SGPID\"\n {  tr -cs 'A-Za-z0-9_' '\\n' |\n\t\t\t\tsort -u |\n\t\t\t\tawk '/^[A-Za-z]/ { len += length($1); n++ } END {print len / n}'\n} <$SGDIR/npi-3.4.0 | sgsh-writeval  -s $SGDIR/IDLEN  & SGPID=\"$! $SGPID\"\n {  wc -lc | awk '{OFS=\":\"; print $1, $2}'\n} <$SGDIR/npi-2.1.0 | sgsh-writeval  -s $SGDIR/CHLINESCHAR  & SGPID=\"$! $SGPID\"\n {  sed 's/#/@/g' |\n\t\t\tcpp -traditional -P 2>/dev/null |\n\t\t\twc -c |\n\t\t\tawk '{OFMT = \"%.0f\"; print $1/1000}'\n} <$SGDIR/npi-2.2.0 | sgsh-writeval  -s $SGDIR/NCCHAR  & SGPID=\"$! $SGPID\"\n {  egrep -c '/\\*|//'\n} <$SGDIR/npi-2.3.0 | sgsh-writeval  -s $SGDIR/NCOMMENT  & SGPID=\"$! $SGPID\"\n {  grep -ci copyright\n} <$SGDIR/npi-2.4.0 | sgsh-writeval  -s $SGDIR/NCOPYRIGHT  & SGPID=\"$! $SGPID\"\n {  find \"$@\" -name \\*.c -type f -print0\n}</dev/null  |\nsgsh-tee  -o $SGDIR/npi-4.0.0 -o $SGDIR/npi-4.1.0  & SGPID=\"$! $SGPID\"\n {  tr \\\\0 \\\\n\n} <$SGDIR/npi-4.0.0 |\nsgsh-tee  -o $SGDIR/npi-5.0.0 -o $SGDIR/npi-5.1.0  & SGPID=\"$! $SGPID\"\n {  wc -l\n} <$SGDIR/npi-5.0.0 | sgsh-writeval  -s $SGDIR/NCFILE  & SGPID=\"$! $SGPID\"\n {  sed 's,/[^/]*$,,;s,^.*/,,' | sort -u | wc -l\n} <$SGDIR/npi-5.1.0 | sgsh-writeval  -s $SGDIR/NCDIR  & SGPID=\"$! $SGPID\"\n {  xargs -0 cat\n} <$SGDIR/npi-4.1.0 |\nsgsh-tee  -o $SGDIR/npi-6.0.0 -o $SGDIR/npi-6.1.0  & SGPID=\"$! $SGPID\"\n {  wc -lc | awk '{OFS=\":\"; print $1, $2}'\n} <$SGDIR/npi-6.0.0 | sgsh-writeval  -s $SGDIR/CLINESCHAR  & SGPID=\"$! $SGPID\"\n {  sed 's/#/@/g;s/\\\\[\\\\\"'\\'']/@/g;s/\"[^\"]*\"/\"\"/g;'\"s/'[^']*'/''/g\" |\n\t\t\tcpp -P 2>/dev/null\n} <$SGDIR/npi-6.1.0 |\nsgsh-tee  -o $SGDIR/npi-7.0.0 -o $SGDIR/npi-7.1.0 -o $SGDIR/npi-7.2.0 -o $SGDIR/npi-7.3.0 -o $SGDIR/npi-7.4.0 -o $SGDIR/npi-7.5.0  & SGPID=\"$! $SGPID\"\n {  grep -c '^{'\n} <$SGDIR/npi-7.0.0 | sgsh-writeval  -s $SGDIR/NFUNCTION  & SGPID=\"$! $SGPID\"\n {  grep -cw goto\n} <$SGDIR/npi-7.1.0 | sgsh-writeval  -s $SGDIR/NGOTO  & SGPID=\"$! $SGPID\"\n {  grep -cw register\n} <$SGDIR/npi-7.2.0 | sgsh-writeval  -s $SGDIR/NREGISTER  & SGPID=\"$! $SGPID\"\n {  grep -c '@[ \t]*define[ \t][ \t]*[a-zA-Z_][a-zA-Z0-9_]*('\n} <$SGDIR/npi-7.3.0 | sgsh-writeval  -s $SGDIR/NMACRO  & SGPID=\"$! $SGPID\"\n {  grep -c '@[ \t]*include'\n} <$SGDIR/npi-7.4.0 | sgsh-writeval  -s $SGDIR/NINCLUDE  & SGPID=\"$! $SGPID\"\n {  grep -o -h '[0-9][x0-9][0-9a-f]*' | wc -l\n} <$SGDIR/npi-7.5.0 | sgsh-writeval  -s $SGDIR/NCONST  & SGPID=\"$! $SGPID\"\n {  find \"$@\" -name \\*.h -type f | wc -l\n}</dev/null  | sgsh-writeval  -s $SGDIR/NHFILE  & SGPID=\"$! $SGPID\"\n\n# Gather the results\ncat <<EOF\nFNAMELEN: `sgsh-readval -s $SGDIR/FNAMELEN`\nNSTRUCT: `sgsh-readval -s $SGDIR/NSTRUCT`\nNTYPEDEF: `sgsh-readval -s $SGDIR/NTYPEDEF`\nIDLEN: `sgsh-readval -s $SGDIR/IDLEN`\nCHLINESCHAR: `sgsh-readval -s $SGDIR/CHLINESCHAR`\nNCCHAR: `sgsh-readval -s $SGDIR/NCCHAR`\nNCOMMENT: `sgsh-readval -s $SGDIR/NCOMMENT`\nNCOPYRIGHT: `sgsh-readval -s $SGDIR/NCOPYRIGHT`\nNCFILE: `sgsh-readval -s $SGDIR/NCFILE`\nNCDIR: `sgsh-readval -s $SGDIR/NCDIR`\nCLINESCHAR: `sgsh-readval -s $SGDIR/CLINESCHAR`\nNFUNCTION: `sgsh-readval -s $SGDIR/NFUNCTION`\nNGOTO: `sgsh-readval -s $SGDIR/NGOTO`\nNREGISTER: `sgsh-readval -s $SGDIR/NREGISTER`\nNMACRO: `sgsh-readval -s $SGDIR/NMACRO`\nNINCLUDE: `sgsh-readval -s $SGDIR/NINCLUDE`\nNCONST: `sgsh-readval -s $SGDIR/NCONST`\nNVOID: `sgsh-readval -s $SGDIR/NVOID`\nNHFILE: `sgsh-readval -s $SGDIR/NHFILE`\nNGETS: `sgsh-readval -s $SGDIR/NGETS`\nEOF\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/commit-stats.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/commit-stats.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Git commit statistics\n# DESCRIPTION\n# Process the git history, and list the authors and days of the week\n# ordered by the number of their commits.\n# Demonstrates streams and piping through a function.\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Order by frequency\nforder()\n{\n\tsort |\n\tuniq -c |\n\tsort -rn\n}\n\ngit log --format=\"%an:%ad\" --date=default \"$@\" |\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\t\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-authors.0 \\\n\t$SGDIR/npfo-days.0 \\\n\t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  awk -F: '{print $1}' | forder\n} <$SGDIR/npi-0.0.0 >$SGDIR/npfo-authors.0 & SGPID=\"$! $SGPID\"\n {  awk -F: '{print substr($2, 1, 3)}' | forder\n} <$SGDIR/npi-0.1.0 >$SGDIR/npfo-days.0 & SGPID=\"$! $SGPID\"\n\n# Gather the results\n\techo \"Authors ordered by number of commits\"\n\tcat $SGDIR/npfo-authors.0\n\techo \"Days ordered by number of commits\"\n\tcat $SGDIR/npfo-days.0\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/committer-plot.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/committer-plot.sh\n#!/usr/bin/env sgsh -s /bin/bash\n#\n# SYNOPSIS Plot git committer activity over time\n# DESCRIPTION\n# Process the git history, and create two PNG diagrams depicting\n# committer activity over time. The most active committers appear\n# at the center vertical of the diagram.\n# Demonstrates image processing and no-output scatter blocks.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\n# Commit history in the form of ascending Unix timestamps, emails\ngit log --pretty=tformat:'%at %ae' |\nawk 'NF == 2 && $1 > 100000 && $1 < '`date +%s` |\nsort -n |\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\tsgsh-readval -q -s \"$SGDIR/NCOMMITTERS\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/LAST\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/FIRST\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NDAYS\" 2>/dev/null\n\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-committerpos.0 \\\n\t$SGDIR/npfo-none-1.0.0 \\\n\t$SGDIR/npfo-none-1.1.0 \\\n\t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0 \\\n\t$SGDIR/npi-0.2.0 \\\n\t$SGDIR/npi-0.4.0 \\\n\t$SGDIR/npi-0.5.0 \\\n\t$SGDIR/npi-1.0.0 \\\n\t$SGDIR/npi-1.1.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 -o $SGDIR/npi-0.2.0 -o $SGDIR/npi-0.4.0 -o $SGDIR/npi-0.5.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  awk '{print $2}' | sort -u | wc -l\n} <$SGDIR/npi-0.0.0 | sgsh-writeval  -s $SGDIR/NCOMMITTERS  & SGPID=\"$! $SGPID\"\n {  tail -1 | awk '{print $1}'\n} <$SGDIR/npi-0.1.0 | sgsh-writeval  -s $SGDIR/LAST  & SGPID=\"$! $SGPID\"\n {  head -1 | awk '{print $1}'\n} <$SGDIR/npi-0.2.0 | sgsh-writeval  -s $SGDIR/FIRST  & SGPID=\"$! $SGPID\"\n {  expr \\( `sgsh-readval -s $SGDIR/LAST` - `sgsh-readval -s $SGDIR/FIRST` \\) / 60 / 60  / 24\n}</dev/null  | sgsh-writeval  -s $SGDIR/NDAYS  & SGPID=\"$! $SGPID\"\n {  awk '{print $2}' |\n\t   sort |\n\t   uniq -c |\n\t   sort -n |\n\t   awk 'BEGIN {l = 0; r = '`sgsh-readval -s $SGDIR/NCOMMITTERS`';}\n\t\t      {print NR % 2 ? l++ : --r, $2}' |\n\t   sort -k2\n} <$SGDIR/npi-0.4.0 >$SGDIR/npfo-committerpos.0 & SGPID=\"$! $SGPID\"\n {  sort -k2 |\n\t   join -j 2 - $SGDIR/npfo-committerpos.0 |\n\t   # Order by time\n\t   sort -k 2n |\n\t{\n\t# Create portable bitmap\n\techo 'P1'\n\techo \"`sgsh-readval -s $SGDIR/NCOMMITTERS` `sgsh-readval -s $SGDIR/NDAYS`\"\n\tperl -na -e '\n\tBEGIN { @empty['`sgsh-readval -s $SGDIR/NCOMMITTERS`' - 1] = 0; @committers = @empty; }\n\tsub out { print join(\"\", map($_ ? \"1\" : \"0\", @committers)), \"\\n\"; }\n\n\t$day = int($F[1] / 60 / 60 / 24);\n\t$pday = $day if (!defined($pday));\n\n\twhile ($day != $pday) {\n\t\tout();\n\t\t@committers = @empty;\n\t\t$pday++;\n\t}\n\n\t$committers[$F[2]] = 1;\n\n\tEND { out(); }\n\t'\n\t} |\n\t# Enlarge points into discs through morphological convolution\n\tpgmmorphconv -erode <(\ncat <<EOF\nP1\n7 7\n0 0 0 1 0 0 0\n0 0 1 1 1 0 0\n0 1 1 1 1 1 0\n1 1 1 1 1 1 1\n0 1 1 1 1 1 0\n0 0 1 1 1 0 0\n0 0 0 1 0 0 0\nEOF\n\t)\n} <$SGDIR/npi-0.5.0 |\nsgsh-tee  -o $SGDIR/npi-1.0.0 -o $SGDIR/npi-1.1.0  & SGPID=\"$! $SGPID\"\n {  pnmtopng >large.png\n: ; } <$SGDIR/npi-1.0.0 >$SGDIR/npfo-none-1.0.0  & SGPID=\"$! $SGPID\"\n {  pamscale -width 640 |\n\t\t   pnmtopng >small.png\n: ; } <$SGDIR/npi-1.1.0 >$SGDIR/npfo-none-1.1.0  & SGPID=\"$! $SGPID\"\n\n# Gather the results\nsgsh-tee  -i $SGDIR/npfo-none-1.0.0  -i $SGDIR/npfo-none-1.1.0 >/dev/null\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/compress-compare.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/compress-compare.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Compression benchmark\n# DESCRIPTION\n# Report file type, length, and compression performance for\n# data received from the standard input.  The data never touches the\n# disk.\n# Demonstrates the use of stores.\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\tsgsh-readval -q -s \"$SGDIR/NBYTES\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/FILETYPE\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/XZ\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/BZIP2\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/GZIP\" 2>/dev/null\n\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0 \\\n\t$SGDIR/npi-0.2.0 \\\n\t$SGDIR/npi-0.3.0 \\\n\t$SGDIR/npi-0.4.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 -o $SGDIR/npi-0.2.0 -o $SGDIR/npi-0.3.0 -o $SGDIR/npi-0.4.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  wc -c\n} <$SGDIR/npi-0.0.0 | sgsh-writeval  -s $SGDIR/NBYTES  & SGPID=\"$! $SGPID\"\n {  file -\n} <$SGDIR/npi-0.1.0 | sgsh-writeval  -s $SGDIR/FILETYPE  & SGPID=\"$! $SGPID\"\n {  xz -c | wc -c\n} <$SGDIR/npi-0.2.0 | sgsh-writeval  -s $SGDIR/XZ  & SGPID=\"$! $SGPID\"\n {  bzip2 -c | wc -c\n} <$SGDIR/npi-0.3.0 | sgsh-writeval  -s $SGDIR/BZIP2  & SGPID=\"$! $SGPID\"\n {  gzip -c | wc -c\n} <$SGDIR/npi-0.4.0 | sgsh-writeval  -s $SGDIR/GZIP  & SGPID=\"$! $SGPID\"\n\n# Gather the results\n\tcat <<EOF\nFile type:\t`sgsh-readval -s $SGDIR/FILETYPE`\nOriginal size:\t`sgsh-readval -s $SGDIR/NBYTES` bytes\ngzip:\t\t`sgsh-readval -s $SGDIR/GZIP` bytes\nbzip2:\t\t`sgsh-readval -s $SGDIR/BZIP2` bytes\nxz:\t\t`sgsh-readval -s $SGDIR/XZ` bytes\nEOF\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/dir.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/dir.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Directory listing\n# DESCRIPTION\n# Windows-like DIR command for the current directory.\n# Nothing that couldn't be done with <code>ls -l | awk</code>.\n# Demonstrates combined use of stores and streams.\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nFREE=`df -h . | awk '!/Use%/{print $4}'`\n\nls -n |\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\tsgsh-readval -q -s \"$SGDIR/NFILES\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NDIRS\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/NBYTES\" 2>/dev/null\n\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-files.0 \\\n\t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0 \\\n\t$SGDIR/npi-0.2.0 \\\n\t$SGDIR/npi-0.3.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 -o $SGDIR/npi-0.2.0 -o $SGDIR/npi-0.3.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  awk '!/^total/ {print $6, $7, $8, $1, sprintf(\"%8d\", $5), $9}'\n} <$SGDIR/npi-0.0.0 >$SGDIR/npfo-files.0 & SGPID=\"$! $SGPID\"\n {  wc -l\n} <$SGDIR/npi-0.1.0 | sgsh-writeval  -s $SGDIR/NFILES  & SGPID=\"$! $SGPID\"\n {  grep -c '^d'\n} <$SGDIR/npi-0.2.0 | sgsh-writeval  -s $SGDIR/NDIRS  & SGPID=\"$! $SGPID\"\n {  awk '{s += $5} END {print s}'\n} <$SGDIR/npi-0.3.0 | sgsh-writeval  -s $SGDIR/NBYTES  & SGPID=\"$! $SGPID\"\n\n# Gather the results\n\tcat $SGDIR/npfo-files.0\n\techo \"               `sgsh-readval -s $SGDIR/NFILES` File(s) `sgsh-readval -s $SGDIR/NBYTES` bytes\"\n\techo \"               `sgsh-readval -s $SGDIR/NDIRS` Dir(s) $FREE bytes free\"\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/duplicate-files.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/duplicate-files.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Find duplicate files\n# DESCRIPTION\n# List the names of duplicate files in the specified directory.\n# Demonstrates the combination of streams with a relational join.\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Create list of files\nfind \"$@\" -type f |\n\n# Produce lines of the form\n# MD5(filename)= 811bfd4b5974f39e986ddc037e1899e7\nxargs openssl md5 |\n\n# Convert each line into a \"filename md5sum\" pair\nsed 's/^MD5(//;s/)= / /' |\n\n# Sort by MD5 sum\nsort -k2 |\n\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\t\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-dupes.0 \\\n\t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  awk '{print $2}' | uniq -d\n} <$SGDIR/npi-0.0.0 >$SGDIR/npfo-dupes.0 & SGPID=\"$! $SGPID\"\nln -s $SGDIR/npi-0.1.0 $SGDIR/npfo-names.0\n\n# Gather the results\n\t# Join the repeated MD5 sums with the corresponding file names\n\tjoin -2 2 $SGDIR/npfo-dupes.0 $SGDIR/npfo-names.0 |\n\t# Output same files on a single line\n\tawk '\n\tBEGIN {ORS=\"\"}\n\t$1 != prev && prev {print \"\\n\"}\n\tEND {if (prev) print \"\\n\"}\n\t{if (prev) print \" \"; prev = $1; print $2}'\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/ft2d.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/ft2d.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Waves: 2D Fourier transforms\n# DESCRIPTION\n# Create two graphs:\n# 1) a broadened pulse and the real part of its 2D Fourier transform, and\n# 2) a simulated air wave and the amplitude of its 2D Fourier transform.\n# Demonstrates using the tools of the Madagascar shared research environment\n# for computational data analysis in geophysics and related fields.\n# Also demonstrates the use of two scatter blocks in the same script.\n#\n# Adapted from: http://www.reproducibility.org/RSF/book/bei/ft1/ft2d.html\n# Description: http://www.reproducibility.org/RSF/book/bei/ft1/paper_html/node14.html\n# Madagascar project: http://www.reproducibility.org\n#\n\nmkdir -p Fig\n\n# The SConstruct SideBySideIso \"Result\" method\nside_by_side_iso()\n{\n\tvppen size=r vpstyle=n gridnum=2,1 $*\n}\n\n# A broadened pulse and the real part of its 2D Fourier transform\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\t\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-ft2d.0 \\\n\t$SGDIR/npfo-ft2d.vpl.0 \\\n\t$SGDIR/npfo-none-0.1.0 \\\n\t$SGDIR/npfo-pulse.vpl.0 \\\n\t$SGDIR/npi-1.0.0 \\\n\t$SGDIR/npi-1.1.0 \\\n\t$SGDIR/npi-2.0.0 \\\n\t$SGDIR/npi-2.1.0\n\n {  sfspike n1=64 n2=64 d1=1 d2=1 nsp=2 k1=16,17 k2=5,5 mag=16,16 \\\n        label1='time' label2='space' unit1= unit2= |\n        sfsmooth rect2=2 |\n\tsfsmooth rect2=2\n}</dev/null  |\nsgsh-tee  -o $SGDIR/npi-1.0.0 -o $SGDIR/npi-1.1.0  & SGPID=\"$! $SGPID\"\n {  sfgrey pclip=100 wanttitle=n\n} <$SGDIR/npi-1.0.0 >$SGDIR/npfo-pulse.vpl.0 & SGPID=\"$! $SGPID\"\n {  sffft1 | sffft3 axis=2 pad=1 | sfreal\n} <$SGDIR/npi-1.1.0 |\nsgsh-tee  -o $SGDIR/npi-2.0.0 -o $SGDIR/npi-2.1.0  & SGPID=\"$! $SGPID\"\n {  sgsh-tee -I\n} <$SGDIR/npi-2.0.0 >$SGDIR/npfo-ft2d.0 & SGPID=\"$! $SGPID\"\n {  sfwindow f1=1 |\n\t\t\t    sfreverse which=3 |\n\t\t\t    sfcat axis=1 $SGDIR/npfo-ft2d.0 |\n\t\t\t    sfgrey pclip=100 wanttitle=n \\\n\t\t\t     label1=\"1/time\" label2=\"1/space\"\n} <$SGDIR/npi-2.1.0 >$SGDIR/npfo-ft2d.vpl.0 & SGPID=\"$! $SGPID\"\n {  side_by_side_iso $SGDIR/npfo-pulse.vpl.0 $SGDIR/npfo-ft2d.vpl.0 \\\n\t   yscale=1.25 >Fig/ft2dofpulse.vpl\n: ; }</dev/null  >$SGDIR/npfo-none-0.1.0  & SGPID=\"$! $SGPID\"\n\n# Gather the results\nsgsh-tee  -i $SGDIR/npfo-none-0.1.0 >/dev/null\n\n)  3<&0 \n\n# A simulated air wave and the amplitude of its 2D Fourier transform\n(\n\n\texport SGDIR=/tmp/sg-$$.1\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\t\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-air.0 \\\n\t$SGDIR/npfo-airfk.vpl.0 \\\n\t$SGDIR/npfo-airft1.0 \\\n\t$SGDIR/npfo-airfti.0 \\\n\t$SGDIR/npfo-airftr.0 \\\n\t$SGDIR/npfo-airtx.vpl.0 \\\n\t$SGDIR/npfo-none-0.2.0 \\\n\t$SGDIR/npi-1.0.0 \\\n\t$SGDIR/npi-1.1.0 \\\n\t$SGDIR/npi-2.0.0 \\\n\t$SGDIR/npi-2.1.0 \\\n\t$SGDIR/npi-3.0.0 \\\n\t$SGDIR/npi-3.1.0 \\\n\t$SGDIR/npi-4.0.0 \\\n\t$SGDIR/npi-4.1.0\n\n {  sfspike n1=64 d1=1 o1=32 nsp=4 k1=1,2,3,4 mag=1,3,3,1 \\\n\t\tlabel1='time' unit1= |\n\t   sfspray n=32 d=1 o=0 |\n\t   sfput label2=space |\n\t   sflmostretch delay=0 v0=-1\n}</dev/null  |\nsgsh-tee  -o $SGDIR/npi-1.0.0 -o $SGDIR/npi-1.1.0  & SGPID=\"$! $SGPID\"\n {  sgsh-tee -I\n} <$SGDIR/npi-1.0.0 >$SGDIR/npfo-air.0 & SGPID=\"$! $SGPID\"\n {  sfwindow f2=1 |\n\t\t   sfreverse which=2 |\n\t\t   sfcat axis=2 $SGDIR/npfo-air.0\n} <$SGDIR/npi-1.1.0 |\nsgsh-tee  -o $SGDIR/npi-2.0.0 -o $SGDIR/npi-2.1.0  & SGPID=\"$! $SGPID\"\n {  sfgrey pclip=100 wanttitle=n\n} <$SGDIR/npi-2.0.0 >$SGDIR/npfo-airtx.vpl.0 & SGPID=\"$! $SGPID\"\n {  sffft1 |\n\t\t\t   sffft3 sign=1\n} <$SGDIR/npi-2.1.0 |\nsgsh-tee  -o $SGDIR/npi-3.0.0 -o $SGDIR/npi-3.1.0  & SGPID=\"$! $SGPID\"\n {  sfreal\n} <$SGDIR/npi-3.0.0 >$SGDIR/npfo-airftr.0 & SGPID=\"$! $SGPID\"\n {  sfimag\n} <$SGDIR/npi-3.1.0 >$SGDIR/npfo-airfti.0 & SGPID=\"$! $SGPID\"\n {  sfmath re=$SGDIR/npfo-airftr.0 im=$SGDIR/npfo-airfti.0 output=\"sqrt(re*re+im*im)\"\n}</dev/null  |\nsgsh-tee  -o $SGDIR/npi-4.0.0 -o $SGDIR/npi-4.1.0  & SGPID=\"$! $SGPID\"\n {  sgsh-tee -I\n} <$SGDIR/npi-4.0.0 >$SGDIR/npfo-airft1.0 & SGPID=\"$! $SGPID\"\n {  sfwindow f1=1 |\n\t\t   sfreverse which=3 |\n\t\t   sfcat axis=1 $SGDIR/npfo-airft1.0 |\n\t\t   sfgrey pclip=100 wanttitle=n label1=\"1/time\" \\\n\t\t   \tlabel2=\"1/space\"\n} <$SGDIR/npi-4.1.0 >$SGDIR/npfo-airfk.vpl.0 & SGPID=\"$! $SGPID\"\n {  side_by_side_iso $SGDIR/npfo-airtx.vpl.0 $SGDIR/npfo-airfk.vpl.0 \\\n\t   yscale=1.25 >Fig/airwave.vpl\n: ; }</dev/null  >$SGDIR/npfo-none-0.2.0  & SGPID=\"$! $SGPID\"\n\n# Gather the results\nsgsh-tee  -i $SGDIR/npfo-none-0.2.0 >/dev/null\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/map-hierarchy.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/map-hierarchy.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Hierarchy map\n# DESCRIPTION\n# Given two directory hierarchies A and B passed as input arguments\n# (where these represent a project at different parts of its lifetime)\n# copy the files of hierarchy A to a new directory, passed as a third\n# argument, corresponding to the structure of directories in B.\n# Demonstrates the use of <em>join</em> to gather results from streams\n# in the <em>scatter</em> part,\n# and the use of <em>cat</em> to order asynchronous results in the gather part.\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ ! -d \"$1\" -o ! -d \"$2\" -o -z \"$3\" ]\nthen\n\techo \"Usage: $0 dir-1 dir-2 new-dir-name\" 1>&2\n\texit 1\nfi\n\nNEWDIR=\"$3\"\n\nexport LC_ALL=C\n\nline_signatures()\n{\n\tfind $1 -type f -name '*.[chly]' -print |\n\t# Split path name into directory and file\n\tsed 's|\\(.*\\)/\\([^/]*\\)|\\1 \\2|' |\n\twhile read dir file\n\tdo\n\t\t# Print \"directory filename content\" of lines with\n\t\t# at least one alphabetic character\n\t\t# The fields are separated by ^A and ^B\n\t\tsed -n \"/[a-z]/s|^|$dir\u0001$file\u0002|p\" \"$dir/$file\"\n\tdone |\n\tsort -t\u0001 -k 2\n}\n\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\t\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-a.0 \\\n\t$SGDIR/npfo-b.0 \\\n\t$SGDIR/npfo-cp.0 \\\n\t$SGDIR/npfo-mkdir.0 \\\n\t$SGDIR/npi-1.0.0 \\\n\t$SGDIR/npi-1.1.0\n\n {  line_signatures $1\n}</dev/null  >$SGDIR/npfo-a.0 & SGPID=\"$! $SGPID\"\n {  line_signatures $2\n}</dev/null  >$SGDIR/npfo-b.0 & SGPID=\"$! $SGPID\"\n {  join -t\u0001 -1 2 -2 2 $SGDIR/npfo-a.0 $SGDIR/npfo-b.0 |\n\t# Print filename dir1 dir2\n\tsed 's/\u0002/\u0001/g' |\n\tawk -F\u0001 'BEGIN{OFS=\" \"}{print $1, $3, $4}' |\n\t# Unique occurrences\n\tsort -u\n}</dev/null  |\nsgsh-tee  -o $SGDIR/npi-1.0.0 -o $SGDIR/npi-1.1.0  & SGPID=\"$! $SGPID\"\n {  awk '{print \"cp \\\"\" $2 \"/\" $1 \"\\\" \\\"'$NEWDIR'/\" $3 \"/\" $1 \"\\\"\"}'\n} <$SGDIR/npi-1.0.0 >$SGDIR/npfo-cp.0 & SGPID=\"$! $SGPID\"\n {  awk '{print \"mkdir -p \\\"'$NEWDIR'/\" $3 \"\\\"\"}' | sort -u\n} <$SGDIR/npi-1.1.0 >$SGDIR/npfo-mkdir.0 & SGPID=\"$! $SGPID\"\n\n# Gather the results\n\t# Order: first make directories, then copy files\n\tsgsh-tee -f -I -i $SGDIR/npfo-mkdir.0 -i $SGDIR/npfo-cp.0 |\n\tsh\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/parallel-logresolve.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/parallel-logresolve.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Parallel logresolve\n# DESCRIPTION\n# Resolve IP addresses of web logs in parallel.\n# Demonstrates parallel execution.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Add record number as the second field\nawk '{$2 = ++n \" \" $2; print}' \"$@\" |\n\n# Two parallel line scatter invocations\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\t\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-resolved.0 \\\n\t$SGDIR/npfo-resolved.1 \\\n\t$SGDIR/npfo-resolved.2 \\\n\t$SGDIR/npfo-resolved.3 \\\n\t$SGDIR/npfo-resolved.4 \\\n\t$SGDIR/npfo-resolved.5 \\\n\t$SGDIR/npfo-resolved.6 \\\n\t$SGDIR/npfo-resolved.7 \\\n\t$SGDIR/npfo-resolved.8 \\\n\t$SGDIR/npfo-resolved.9 \\\n\t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.0.1 \\\n\t$SGDIR/npi-0.0.2 \\\n\t$SGDIR/npi-0.0.3 \\\n\t$SGDIR/npi-0.0.4 \\\n\t$SGDIR/npi-0.0.5 \\\n\t$SGDIR/npi-0.0.6 \\\n\t$SGDIR/npi-0.0.7 \\\n\t$SGDIR/npi-0.0.8 \\\n\t$SGDIR/npi-0.0.9\n\nsgsh-tee  -s -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.0.1 -o $SGDIR/npi-0.0.2 -o $SGDIR/npi-0.0.3 -o $SGDIR/npi-0.0.4 -o $SGDIR/npi-0.0.5 -o $SGDIR/npi-0.0.6 -o $SGDIR/npi-0.0.7 -o $SGDIR/npi-0.0.8 -o $SGDIR/npi-0.0.9 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.0 >$SGDIR/npfo-resolved.0 & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.1 >$SGDIR/npfo-resolved.1 & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.2 >$SGDIR/npfo-resolved.2 & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.3 >$SGDIR/npfo-resolved.3 & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.4 >$SGDIR/npfo-resolved.4 & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.5 >$SGDIR/npfo-resolved.5 & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.6 >$SGDIR/npfo-resolved.6 & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.7 >$SGDIR/npfo-resolved.7 & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.8 >$SGDIR/npfo-resolved.8 & SGPID=\"$! $SGPID\"\n {  logresolve | sgsh-tee -I\n} <$SGDIR/npi-0.0.9 >$SGDIR/npfo-resolved.9 & SGPID=\"$! $SGPID\"\n\n# Gather the results\n\t# Merge the files on the second numerical field\n\tsort -m -k2n $SGDIR/npfo-resolved.0 $SGDIR/npfo-resolved.1 $SGDIR/npfo-resolved.2 $SGDIR/npfo-resolved.3 $SGDIR/npfo-resolved.4 $SGDIR/npfo-resolved.5 $SGDIR/npfo-resolved.6 $SGDIR/npfo-resolved.7 $SGDIR/npfo-resolved.8 $SGDIR/npfo-resolved.9 |\n\n\t# Remove second field\n\tcut -d ' ' -f 1,3-\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/spell-highlight.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/spell-highlight.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Highlight misspelled words\n# DESCRIPTION\n# Highlight the words that are misspelled in the command's standard\n# input.\n# Demonstrates stream buffering and the avoidance of pass-through\n# constructs to avoid deadlocks.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nexport LC_ALL=C\n\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\t\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-dict.0 \\\n\t$SGDIR/npfo-errors.0 \\\n\t$SGDIR/npfo-text.0 \\\n\t$SGDIR/npi-0.1.0 \\\n\t$SGDIR/npi-0.2.0\n\nsgsh-tee  -o $SGDIR/npi-0.1.0 -o $SGDIR/npi-0.2.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  sort /usr/share/dict/words\n}</dev/null  >$SGDIR/npfo-dict.0 & SGPID=\"$! $SGPID\"\n {  tr -cs A-Za-z \\\\n |\n\ttr A-Z a-z |\n\tsort -u |\n\tcomm -23 - $SGDIR/npfo-dict.0\n} <$SGDIR/npi-0.1.0 >$SGDIR/npfo-errors.0 & SGPID=\"$! $SGPID\"\n {  cat\n} <$SGDIR/npi-0.2.0 >$SGDIR/npfo-text.0 & SGPID=\"$! $SGPID\"\n\n# Gather the results\n\tfgrep -f $SGDIR/npfo-errors.0 -i --color -w -C 2 $SGDIR/npfo-text.0\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/text-properties.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/text-properties.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Text properties\n# DESCRIPTION\n# Read text from the standard input and create files\n# containing word, character, digram, and trigram frequencies.\n#\n# Demonstrates the use of scatter blocks without output and the use\n# of stores within the scatter block.\n#\n# Example:\n# curl ftp://sunsite.informatik.rwth-aachen.de/pub/mirror/ibiblio/gutenberg/1/3/139/139.txt | text-properties\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Consitent sorting across machines\nexport LC_ALL=C\n\n\n# Convert input into a ranked frequency list\nranked_frequency()\n{\n\tsort |\n\tuniq -c |\n\tsort -rn\n}\n\n# Convert standard input to a ranked frequency list of specified n-grams\nngram()\n{\n\tlocal N=$1\n\n\tperl -ne 'for ($i = 0; $i < length($_) - '$N'; $i++) {\n\t\tprint substr($_, $i, '$N'), \"\\n\";\n\t}' |\n\tranked_frequency\n}\n\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\tsgsh-readval -q -s \"$SGDIR/NCHARS\" 2>/dev/null\n\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-none-0.2.0 \\\n\t$SGDIR/npfo-none-1.0.0 \\\n\t$SGDIR/npfo-none-1.1.0 \\\n\t$SGDIR/npfo-none-1.2.0 \\\n\t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0 \\\n\t$SGDIR/npi-0.2.0 \\\n\t$SGDIR/npi-1.0.0 \\\n\t$SGDIR/npi-1.1.0 \\\n\t$SGDIR/npi-1.2.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 -o $SGDIR/npi-0.2.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  tr -cs a-zA-Z \\\\n\n} <$SGDIR/npi-0.0.0 |\nsgsh-tee  -o $SGDIR/npi-1.0.0 -o $SGDIR/npi-1.1.0 -o $SGDIR/npi-1.2.0  & SGPID=\"$! $SGPID\"\n {  ngram 2 >digram.txt\n: ; } <$SGDIR/npi-1.0.0 >$SGDIR/npfo-none-1.0.0  & SGPID=\"$! $SGPID\"\n {  ngram 3 >trigram.txt\n: ; } <$SGDIR/npi-1.1.0 >$SGDIR/npfo-none-1.1.0  & SGPID=\"$! $SGPID\"\n {  ranked_frequency >words.txt\n: ; } <$SGDIR/npi-1.2.0 >$SGDIR/npfo-none-1.2.0  & SGPID=\"$! $SGPID\"\n {  wc -c\n} <$SGDIR/npi-0.1.0 | sgsh-writeval  -s $SGDIR/NCHARS  & SGPID=\"$! $SGPID\"\n {  sed 's/./&\\\n/g' |\n\t   # Print absolute and percentage\n\t   ranked_frequency |\n\t   awk 'BEGIN {OFMT = \"%.2g%%\"}\n\t   {print $1, $2, $1 / '\"`sgsh-readval -s $SGDIR/NCHARS`\"' * 100}' >character.txt\n: ; } <$SGDIR/npi-0.2.0 >$SGDIR/npfo-none-0.2.0  & SGPID=\"$! $SGPID\"\n\n# Gather the results\nsgsh-tee  -i $SGDIR/npfo-none-1.0.0  -i $SGDIR/npfo-none-1.1.0  -i $SGDIR/npfo-none-1.2.0  -i $SGDIR/npfo-none-0.2.0 >/dev/null\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/web-log-report.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/web-log-report.sh\n#!/usr/bin/env sgsh -s /bin/bash\n#\n# SYNOPSIS Web log reporting\n# DESCRIPTION\n# Creates a report for a fixed-size web log file read from the standard input.\n# Demonstrates the combined use of stores and streams, the use of shell group\n# commands and functions in the scatter block, and the use of cat(1) as\n# a way to sequentially combine multiple streams.\n# Used to measure throughput increase achieved through parallelism.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Output the top X elements of the input by the number of their occurrences\n# X is the first argument\ntoplist()\n{\n\tuniq -c | sort -rn | head -$1\n}\n\n# Output the argument as a section header\nheader()\n{\n\techo\n\techo \"$1\"\n\techo \"$1\" | sed 's/./-/g'\n}\n\n# Consistent sorting\nexport LC_ALL=C\n\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\tsgsh-readval -q -s \"$SGDIR/nXBytes\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/nLogBytes\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/nAccess\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/nHosts\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/nTLD\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/nDomain\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/nPages\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/nDays\" 2>/dev/null\n\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-accessByDate.0 \\\n\t$SGDIR/npfo-accessByDoW.0 \\\n\t$SGDIR/npfo-accessByHour.0 \\\n\t$SGDIR/npfo-summary.0 \\\n\t$SGDIR/npfo-top10Domain.0 \\\n\t$SGDIR/npfo-top10HostsByN.0 \\\n\t$SGDIR/npfo-top10HostsByVol.0 \\\n\t$SGDIR/npfo-top20Area.0 \\\n\t$SGDIR/npfo-top20Request.0 \\\n\t$SGDIR/npfo-top20TLD.0 \\\n\t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0 \\\n\t$SGDIR/npi-0.2.0 \\\n\t$SGDIR/npi-0.3.0 \\\n\t$SGDIR/npi-0.4.0 \\\n\t$SGDIR/npi-0.5.0 \\\n\t$SGDIR/npi-1.0.0 \\\n\t$SGDIR/npi-1.1.0 \\\n\t$SGDIR/npi-1.2.0 \\\n\t$SGDIR/npi-1.3.0 \\\n\t$SGDIR/npi-2.0.0 \\\n\t$SGDIR/npi-2.1.0 \\\n\t$SGDIR/npi-3.0.0 \\\n\t$SGDIR/npi-3.1.0 \\\n\t$SGDIR/npi-4.0.0 \\\n\t$SGDIR/npi-4.1.0 \\\n\t$SGDIR/npi-5.0.0 \\\n\t$SGDIR/npi-5.1.0 \\\n\t$SGDIR/npi-5.2.0 \\\n\t$SGDIR/npi-6.0.0 \\\n\t$SGDIR/npi-6.1.0 \\\n\t$SGDIR/npi-7.0.0 \\\n\t$SGDIR/npi-7.1.0 \\\n\t$SGDIR/npi-7.2.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 -o $SGDIR/npi-0.2.0 -o $SGDIR/npi-0.3.0 -o $SGDIR/npi-0.4.0 -o $SGDIR/npi-0.5.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {   awk '{s += $NF} END {print s}'\n} <$SGDIR/npi-0.0.0 | sgsh-writeval  -s $SGDIR/nXBytes  & SGPID=\"$! $SGPID\"\n {   wc -c\n} <$SGDIR/npi-0.1.0 | sgsh-writeval  -s $SGDIR/nLogBytes  & SGPID=\"$! $SGPID\"\n {   awk '{print $1}'\n} <$SGDIR/npi-0.2.0 |\nsgsh-tee  -o $SGDIR/npi-1.0.0 -o $SGDIR/npi-1.1.0 -o $SGDIR/npi-1.2.0 -o $SGDIR/npi-1.3.0  & SGPID=\"$! $SGPID\"\n {  wc -l\n} <$SGDIR/npi-1.0.0 | sgsh-writeval  -s $SGDIR/nAccess  & SGPID=\"$! $SGPID\"\n {  sort\n} <$SGDIR/npi-1.1.0 |\nsgsh-tee  -o $SGDIR/npi-2.0.0 -o $SGDIR/npi-2.1.0  & SGPID=\"$! $SGPID\"\n {  uniq\n} <$SGDIR/npi-2.0.0 |\nsgsh-tee  -o $SGDIR/npi-3.0.0 -o $SGDIR/npi-3.1.0  & SGPID=\"$! $SGPID\"\n {  wc -l\n} <$SGDIR/npi-3.0.0 | sgsh-writeval  -s $SGDIR/nHosts  & SGPID=\"$! $SGPID\"\n {  awk -F. '$NF !~ /[0-9]/ {print $NF}' |\n\t\t\t\t\tsort -u | wc -l\n} <$SGDIR/npi-3.1.0 | sgsh-writeval  -s $SGDIR/nTLD  & SGPID=\"$! $SGPID\"\n {  {\n\t\t\t\theader 'Top 10 Hosts'\n\t\t\t\ttoplist 10\n\t\t\t}\n} <$SGDIR/npi-2.1.0 >$SGDIR/npfo-top10HostsByN.0 & SGPID=\"$! $SGPID\"\n {  {\n\t\t\theader 'Top 20 Level Domain Accesses'\n\t\t\tawk -F. '$NF !~ /^[0-9]/ {print $NF}' |\n\t\t\tsort |\n\t\t\ttoplist 20\n\t\t}\n} <$SGDIR/npi-1.2.0 >$SGDIR/npfo-top20TLD.0 & SGPID=\"$! $SGPID\"\n {  awk -F. 'BEGIN {OFS = \".\"}\n\t\t            $NF !~ /^[0-9]/ {$1 = \"\"; print}' | sort\n} <$SGDIR/npi-1.3.0 |\nsgsh-tee  -o $SGDIR/npi-4.0.0 -o $SGDIR/npi-4.1.0  & SGPID=\"$! $SGPID\"\n {  uniq | wc -l\n} <$SGDIR/npi-4.0.0 | sgsh-writeval  -s $SGDIR/nDomain  & SGPID=\"$! $SGPID\"\n {  {\n\t\t\t\theader 'Top 10 Domains'\n\t\t\t\ttoplist 10\n\t\t\t}\n} <$SGDIR/npi-4.1.0 >$SGDIR/npfo-top10Domain.0 & SGPID=\"$! $SGPID\"\n {  {\n\t\theader 'Top 10 Hosts by Transfer'\n\t\tawk '    {bytes[$1] += $NF}\n\t\tEND {for (h in bytes) print bytes[h], h}' |\n\t\tsort -rn |\n\t\thead -10\n\t}\n} <$SGDIR/npi-0.3.0 >$SGDIR/npfo-top10HostsByVol.0 & SGPID=\"$! $SGPID\"\n {  awk '{print $7}' | sort\n} <$SGDIR/npi-0.4.0 |\nsgsh-tee  -o $SGDIR/npi-5.0.0 -o $SGDIR/npi-5.1.0 -o $SGDIR/npi-5.2.0  & SGPID=\"$! $SGPID\"\n {  {\n\t\t\theader 'Top 20 Area Requests'\n\t\t\tawk -F/ '{print $2}' |\n\t\t\ttoplist 20\n\t\t}\n} <$SGDIR/npi-5.0.0 >$SGDIR/npfo-top20Area.0 & SGPID=\"$! $SGPID\"\n {  uniq | wc -l\n} <$SGDIR/npi-5.1.0 | sgsh-writeval  -s $SGDIR/nPages  & SGPID=\"$! $SGPID\"\n {  {\n\t\t\theader 'Top 20 Requests'\n\t\t\ttoplist 20\n\t\t}\n} <$SGDIR/npi-5.2.0 >$SGDIR/npfo-top20Request.0 & SGPID=\"$! $SGPID\"\n {  awk '{print substr($4, 2)}'\n} <$SGDIR/npi-0.5.0 |\nsgsh-tee  -o $SGDIR/npi-6.0.0 -o $SGDIR/npi-6.1.0  & SGPID=\"$! $SGPID\"\n {  awk -F: '{print $1}'\n} <$SGDIR/npi-6.0.0 |\nsgsh-tee  -o $SGDIR/npi-7.0.0 -o $SGDIR/npi-7.1.0 -o $SGDIR/npi-7.2.0  & SGPID=\"$! $SGPID\"\n {  uniq | wc -l\n} <$SGDIR/npi-7.0.0 | sgsh-writeval  -s $SGDIR/nDays  & SGPID=\"$! $SGPID\"\n {  {\n\t\t\t\theader 'Accesses by Date'\n\t\t\t\tuniq -c\n\t\t\t}\n} <$SGDIR/npi-7.1.0 >$SGDIR/npfo-accessByDate.0 & SGPID=\"$! $SGPID\"\n {  {\n\t\t\t\theader 'Accesses by Day of Week'\n\t\t\t\tsed 's|/|-|g' |\n\t\t\t\t(date -f - +%a 2>/dev/null || gdate -f - +%a) |\n\t\t\t\tsort |\n\t\t\t\tuniq -c |\n\t\t\t\tsort -rn\n\t\t\t}\n} <$SGDIR/npi-7.2.0 >$SGDIR/npfo-accessByDoW.0 & SGPID=\"$! $SGPID\"\n {  {\n\t\t\theader 'Accesses by Local Hour'\n\t\t\tawk -F: '{print $2}' |\n\t\t\tsort |\n\t\t\tuniq -c\n\t\t}\n} <$SGDIR/npi-6.1.0 >$SGDIR/npfo-accessByHour.0 & SGPID=\"$! $SGPID\"\n { \n\t\tcat <<EOF\n\t\t\tWWW server statistics\n\t\t\t=====================\n\nSummary\n-------\nNumber of accesses: $(sgsh-readval -s $SGDIR/nAccess)\nNumber of Gbytes transferred: $(expr $(sgsh-readval -s $SGDIR/nXBytes) / 1024 / 1024 / 1024)\nNumber of hosts: $(sgsh-readval -s $SGDIR/nHosts)\nNumber of domains: $(sgsh-readval -s $SGDIR/nDomain)\nNumber of top level domains: $(sgsh-readval -s $SGDIR/nTLD)\nNumber of different pages: $(sgsh-readval -s $SGDIR/nPages)\nAccesses per day: $(expr $(sgsh-readval -s $SGDIR/nAccess) / $(sgsh-readval -s $SGDIR/nDays))\nMBytes per day: $(expr $(sgsh-readval -s $SGDIR/nXBytes) / $(sgsh-readval -s $SGDIR/nDays) / 1024 / 1024)\nMBytes log file size: $(expr $(sgsh-readval -s $SGDIR/nLogBytes) / 1024 / 1024)\n\nEOF\n\n}</dev/null  >$SGDIR/npfo-summary.0 & SGPID=\"$! $SGPID\"\n\n# Gather the results\n\n\t# Gather all results together sequentially into a single report\n\tsgsh-tee -f -I -i $SGDIR/npfo-summary.0 -i $SGDIR/npfo-top20Request.0 -i $SGDIR/npfo-top20Area.0 -i $SGDIR/npfo-top10HostsByN.0 -i $SGDIR/npfo-top10HostsByVol.0 -i $SGDIR/npfo-top10Domain.0 -i $SGDIR/npfo-top20TLD.0 -i $SGDIR/npfo-accessByDoW.0 -i $SGDIR/npfo-accessByHour.0 -i $SGDIR/npfo-accessByDate.0\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/web-log-stats.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/web-log-stats.sh\n#!/usr/bin/env sgsh -s /bin/bash\n#\n# SYNOPSIS Web log statistics\n# DESCRIPTION\n# Provides continuous statistics over web log stream data.\n# Demonstrates stream processing.\n# Provide as an argument either the name of a growing web log file\n# or -s and a static web log file, which will be processed at a rate\n# of about 10 lines per second.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Size of the window to report in seconds\nWINDOW=10\nWINDOW_OLD=$(expr $WINDOW \\* 2)\n\n# Update interval in seconds\nUPDATE=2\n\n# Print the sum of the numbers read from the standard input\nsum()\n{\n\tawk '{ sum += $1 } END {print sum}'\n}\n\n# Print the rate of change as a percentage\n# between the first (old) and second (new) value\nchange()\n{\n\t# Can't use bc, because we have numbers in scientific notation\n\tawk \"END {OFMT=\\\"%.2f%%\\\"; print ($2 - $1) * 100 / $1}\" </dev/null\n}\n\nif [ \"$1\" = \"-s\" ]\nthen\n\t# Simulate log lines coming from a file\n\twhile read line\n\tdo\n\t\techo $line\n\t\tsleep 0.01\n\tdone  <\"$2\"\nelse\n\ttail -f \"$1\"\nfi |\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\tsgsh-readval -q -s \"$SGDIR/page\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/total_bytes\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/total_pages\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/bytes\" 2>/dev/null\nsgsh-readval -q -s \"$SGDIR/bytes_old\" 2>/dev/null\n\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0 \\\n\t$SGDIR/npi-1.0.0 \\\n\t$SGDIR/npi-1.1.0 \\\n\t$SGDIR/npi-1.2.0 \\\n\t$SGDIR/npi-1.3.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\n {  awk -Winteractive '{print $7}'\n} <$SGDIR/npi-0.0.0 | sgsh-writeval -b $WINDOW -u s -s $SGDIR/page  & SGPID=\"$! $SGPID\"\n {  awk -Winteractive '{print $10}'\n} <$SGDIR/npi-0.1.0 |\nsgsh-tee  -o $SGDIR/npi-1.0.0 -o $SGDIR/npi-1.1.0 -o $SGDIR/npi-1.2.0 -o $SGDIR/npi-1.3.0  & SGPID=\"$! $SGPID\"\n {  awk -Winteractive '{ s += $1; print s}'\n} <$SGDIR/npi-1.0.0 | sgsh-writeval  -s $SGDIR/total_bytes  & SGPID=\"$! $SGPID\"\n {  awk -Winteractive '{print ++n}'\n} <$SGDIR/npi-1.1.0 | sgsh-writeval  -s $SGDIR/total_pages  & SGPID=\"$! $SGPID\"\n { \n} <$SGDIR/npi-1.2.0 sgsh-writeval -b $WINDOW -u s -s $SGDIR/bytes  & SGPID=\"$! $SGPID\"\n { \n} <$SGDIR/npi-1.3.0 sgsh-writeval -b $WINDOW_OLD -e $WINDOW -u s -s $SGDIR/bytes_old  & SGPID=\"$! $SGPID\"\n\n# Gather the results\n\t# Produce periodic reports\n\twhile :\n\tdo\n\t\tWINDOW_PAGES=$(sgsh-readval -s $SGDIR/bytes -c | wc -l)\n\t\tWINDOW_BYTES=$(sgsh-readval -s $SGDIR/bytes -c | sum )\n\t\tWINDOW_PAGES_OLD=$(sgsh-readval -s $SGDIR/bytes_old -c | wc -l)\n\t\tWINDOW_BYTES_OLD=$(sgsh-readval -s $SGDIR/bytes_old -c | sum)\n\t\tclear\n\t\tcat <<EOF\nTotal\n-----\nPages: $(sgsh-readval -s $SGDIR/total_pages -c)\nBytes: $(sgsh-readval -s $SGDIR/total_bytes -c)\n\nOver last ${WINDOW}s\n--------------------\nPages: $WINDOW_PAGES\nBytes: $WINDOW_BYTES\nkBytes/s: $(awk \"END {OFMT=\\\"%.0f\\\"; print $WINDOW_BYTES / $WINDOW / 1000}\" </dev/null )\nTop page: $(sgsh-readval -s $SGDIR/page -c | sort | uniq -c | sort -rn | head -1)\n\nChange\n------\nRequests: $(change $WINDOW_PAGES_OLD $WINDOW_PAGES)\nData bytes: $(change $WINDOW_BYTES_OLD $WINDOW_BYTES)\nEOF\n\tsleep $UPDATE\n\tdone\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/scripts/word-properties.ok",
    "content": "#!/bin/sh\n# Automatically generated file\n# Source file example/word-properties.sh\n#!/usr/bin/env sgsh\n#\n# SYNOPSIS Word properties\n# DESCRIPTION\n# Read text from the standard input and list words\n# containing a two-letter palindrome, words containing\n# four consonants, and words longer than 12 characters.\n#\n# Demonstrates the use of paste as a gather function\n#\n# Example:\n# curl ftp://sunsite.informatik.rwth-aachen.de/pub/mirror/ibiblio/gutenberg/1/3/139/139.txt | word-properties\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Consitent sorting across machines\nexport LC_ALL=C\n\n# Split input one word per line\ntr -cs a-zA-Z \\\\n |\n# Create list of unique words\nsort -u |\n(\n\n\texport SGDIR=/tmp/sg-$$.0\n\n\trm -rf $SGDIR\n\n\t# Cleanup on exit or interrupt\n\tcleanup()\n\t{\n\t\tSIGNAL=$1\n\t\t[ $SIGNAL = EXIT ] || echo sgsh interrupted. Cleaning up... 1>&2\n\n\t\t# Stop key-value stores\n\t\t\n\t\t# Kill processes we have launched in the background\n\t\tkill $SGPID 2>/dev/null\n\n\t\t# Remove temporary directory\n\t\trm -rf \"$SGDIR\"\n\n\t\t# Propagate real signals and exit with non-0\n\t\tif [ $SIGNAL != EXIT ]\n\t\tthen\n\t\t\ttrap - $SIGNAL EXIT\n\t\t\tkill -s $SIGNAL $$\n\t\tfi\n\n\t\t# Exit with the original exit value\n\t\texit\n\n\t}\n\n\tfor sig in HUP INT QUIT TERM EXIT\n\tdo\n\t\ttrap \"cleanup $sig\" $sig\n\tdone\n\n\tmkdir $SGDIR\n\t\nmkfifo \t$SGDIR/npfo-consonants.0 \\\n\t$SGDIR/npfo-long.0 \\\n\t$SGDIR/npfo-palindromes.0 \\\n\t$SGDIR/npi-0.0.0 \\\n\t$SGDIR/npi-0.1.0 \\\n\t$SGDIR/npi-0.2.0 \\\n\t$SGDIR/npi-0.3.0\n\nsgsh-tee  -o $SGDIR/npi-0.0.0 -o $SGDIR/npi-0.1.0 -o $SGDIR/npi-0.2.0 -o $SGDIR/npi-0.3.0 <&3 3<&-   & SGPID=\"$! $SGPID\"\nln -s $SGDIR/npi-0.0.0 $SGDIR/npfo-words.0\n {  sed 's/.*\\(.\\)\\(.\\)\\2\\1.*/p: \\1\\2-\\2\\1/;t\n\t\tg'\n} <$SGDIR/npi-0.1.0 >$SGDIR/npfo-palindromes.0 & SGPID=\"$! $SGPID\"\n {  sed -E 's/.*([^aeiouyAEIOUY]{4}).*/c: \\1/;t\n\t\tg'\n} <$SGDIR/npi-0.2.0 >$SGDIR/npfo-consonants.0 & SGPID=\"$! $SGPID\"\n {  awk '{if (length($1) > 12) print \"l:\", length($1);\n\t\telse print \"\"}'\n} <$SGDIR/npi-0.3.0 >$SGDIR/npfo-long.0 & SGPID=\"$! $SGPID\"\n\n# Gather the results\n\t# Paste the four streams side-by-side\n\tpaste $SGDIR/npfo-words.0 $SGDIR/npfo-palindromes.0 $SGDIR/npfo-consonants.0 $SGDIR/npfo-long.0 |\n\t# List only words satisfying one or more properties\n\tgrep :\n\n)  3<&0 \n"
  },
  {
    "path": "core-tools/tests-regression/regression/warnings/single-target.ok",
    "content": "test/regression/warnings/single-target.sh(26): warning: Scatter to a single target\n"
  },
  {
    "path": "core-tools/tests-regression/regression/warnings/single-target.sh",
    "content": "#!/usr/bin/env sgsh\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nscatter |{\n\t#-| scatter1 |store:S\n\t-| scatter2 |{\n\t\t-| toa |>/stream/a\n\t\t-| tob |>/stream/b\n\t|}\n|} gather |{\n\tcat /stream/a /stream/b\n|}\n"
  },
  {
    "path": "core-tools/tests-regression/regression/warnings/unsafe-scatter.ok",
    "content": "test/regression/warnings/unsafe-scatter.sh(21): warning: Unsafe use of pass-through /stream/b in the scatter section\ntest/regression/warnings/unsafe-scatter.sh(21): warning: Consult the DEADLOCK section of the manual page\n"
  },
  {
    "path": "core-tools/tests-regression/regression/warnings/unsafe-scatter.sh",
    "content": "#!/usr/bin/env sgsh\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nscatter |{\n\t-| cat |>/stream/a\n\t-||>/stream/b\n\t.| cat /stream/a /stream/b |>/stream/c\n|} gather |{\n\tcat /stream/c\n|}\n"
  },
  {
    "path": "core-tools/tests-regression/spell-highlight/out.ok",
    "content": "hello cruwl world\n"
  },
  {
    "path": "core-tools/tests-regression/tee/oom.err",
    "content": "dgsh-tee: Out of memory with input-side buffering specified\n"
  },
  {
    "path": "core-tools/tests-regression/tee/perm.ok",
    "content": "3\n1\n2\n0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-fastout-I-l.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 2\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-fastout-I-m 2k -f.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 2\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-fastout-I-m 2k.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 2\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-fastout-I.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 2\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-fastout-l.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 1\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-fastout-m 2k -f.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 1\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-fastout-m 2k.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 1\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-fastout.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 1\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-lagout-I-l.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 960\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-lagout-I-m 2k -f.ok",
    "content": "Buffers allocated: 1987 Freed: 1986 Maximum allocated: 3\nPage out: 962 In: 962 Pages freed: 962\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-lagout-I-m 2k.ok",
    "content": "sgsh-tee: Out of memory with input-side buffering specified\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-lagout-I.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 964\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-lagout-l.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 1\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-lagout-m 2k -f.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 1\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-lagout-m 2k.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 1\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-lagout.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 1\nPage out: 0 In: 0 Pages freed: 0\n"
  },
  {
    "path": "core-tools/tests-regression/tee/tee-lahout.ok",
    "content": "Buffers allocated: 1025 Freed: 1024 Maximum allocated: 1\n"
  },
  {
    "path": "core-tools/tests-regression/test-dgsh.sh",
    "content": "#!/bin/sh\n#\n# Regression testing of the provided examples\n#\n\nTOP=$(cd ../.. ; pwd)\nDGSH=\"$TOP/build/bin/dgsh\"\nPATH=\"$TOP/build/bin:$PATH\"\nexport DGSHPATH=\"$TOP/build/libexec/dgsh\"\nEXAMPLE=\"$TOP/example\"\n\n# Ensure that the generated test file matches the reference one\n# File names are by conventions $base/out.{ok,test}\nensure_same()\n{\n  local base=$1\n  echo -n \"$base.sh \"\n  if diff -rw $base/out.ok $base/out.test\n  then\n    echo OK\n  else\n    echo \"$base.sh: Files differ: $base/out.ok $base/out.test\" 1>&2\n    exit 1\n  fi\n}\n\n# Include fallback commands in our executable path\nexport PATH=\"$PATH:bin\"\n\nLOGFILE=web-log-report/logfile\n\n# Generate a small log file if it is not there\n# See http://ita.ee.lbl.gov/html/contrib/ClarkNet-HTTP.html\nCLARKNET=ftp://ita.ee.lbl.gov/traces/clarknet_access_log_Aug28.gz\nif ! [ -f  $LOGFILE ]\nthen\n\tmkdir -p $(dirname $LOGFILE)\n\techo \"Fetching web test data\"\n \t{\n\t\tcurl $CLARKNET 2>/dev/null ||\n\t\twget -O - $CLARKNET 2>/dev/null\n\t} |\n\tgzip -dc |\n\tperl -ne 'print if ($i++ % 1000 == 0)' >$LOGFILE\nfi\n\n\nrm -rf */out.test\n\nmkdir -p spell-highlight\necho hello cruwl world | $DGSH $EXAMPLE/spell-highlight.sh >spell-highlight/out.test\nensure_same spell-highlight\n\n$DGSH $EXAMPLE/map-hierarchy.sh map-hierarchy/in/a map-hierarchy/in/b map-hierarchy/out.test\nensure_same map-hierarchy\n\nif [ -f \"$TOP/unix-tools/grep/.git\" ] && [ -d \"$TOP/.git\" ]; then\n\t(\n\tcd $TOP/unix-tools/grep\n\tLC_ALL=C $DGSH $EXAMPLE/commit-stats.sh --since=2010-01-01Z00:00 \\\n\t--until=2015-12-31Z23:59 \\\n\t>$TOP/core-tools/tests-regression/commit-stats/out.test\n\t)\n\tensure_same commit-stats\nelse\n\techo \"Skip commit-stats test because input is missing (grep's git repo)\"\nfi\n\n# This example outputs different result for NMACRO than the template\n# due to a variation in the behavior of grep or a variation in the\n# implementation of the sgsh example in regression/scripts/code-metrics.ok.\n# The test succeeds in Mac OS.\n#DGSH_TIMEOUT=20 $DGSH $EXAMPLE/code-metrics.sh code-metrics/in/ >code-metrics/out.test 2>/dev/null\n#ensure_same code-metrics\n\n$DGSH $EXAMPLE/duplicate-files.sh duplicate-files >duplicate-files/out.test\nensure_same duplicate-files\n\n$DGSH $EXAMPLE/word-properties.sh <word-properties/LostWorldChap1-3 >word-properties/out.test\nensure_same word-properties\n\n$DGSH $EXAMPLE/compress-compare.sh <word-properties/LostWorldChap1-3 | sed 's/:.*ASCII.*/: ASCII/;s|/dev/stdin:||' >compress-compare/out.test\nensure_same compress-compare\n\nKVSTORE_RETRY_LIMIT=100 DGSH_TIMEOUT=60 $DGSH $EXAMPLE/web-log-report.sh <web-log-report/logfile >web-log-report/out.test\nensure_same web-log-report\n\n(\ncd text-properties\nrm -rf out.test\nmkdir out.test\ncd out.test\n$DGSH $EXAMPLE/text-properties.sh <../../word-properties/LostWorldChap1-3\n)\nensure_same text-properties\n\n# The correct file was generated using\n# tr -s ' \\t\\n\\r\\f' \\\\n <word-properties/LostWorldChap1-3 | sort | uniq -c | sed 's/^  *//'\n# An empty line is removed from the test output, because it can be generated\n# by tr when the first line of a split file is empty. (In that case \\n is not\n# a repeated character that tr will remove.)\n$DGSH $EXAMPLE/parallel-word-count.sh <word-properties/LostWorldChap1-3 | sed '/^[0-9]* $/d' >parallel-word-count/out.test\nensure_same parallel-word-count\n\n$DGSH $EXAMPLE/author-compare.sh conf/icse/ journals/software/ \\\n  <author-compare/dblp-subset.gz >author-compare/out.test\nensure_same author-compare\n\nexit 0\n"
  },
  {
    "path": "core-tools/tests-regression/test-kvstore.sh",
    "content": "#!/bin/sh\n\nDGSH_READVAL=../src/dgsh-readval\nDGSH_WRITEVAL=../src/dgsh-writeval\nDGSH_HTTPVAL=../src/dgsh-httpval\n\n# Helper functions {{{1\n# Repeat x times\nsequence()\n{\n\tjot $1 2>/dev/null || seq $1 2>/dev/null\n}\n\nfail()\n{\n\techo \"FAIL\"\n\techo \"$1\"\n\t$DGSH_READVAL -q -s testsocket 2>/dev/null\n\tif [ \"$SERVER_PID\" ]\n\tthen\n\t\tstop_server\n\tfi\n\techo\n\techo Server errors:\n\ttest server.err && cat server.err\n\techo Client errors:\n\ttest client.err && cat client.err\n\texit 1\n}\n\n# Verify a test result\n# -n disables the termination of writeval\ncheck()\n{\n\tif [ \"$1\" != '-n' ]\n\tthen\n\t\t$DGSH_READVAL -q -s testsocket 2>/dev/null\n\tfi\n\n\tif [ \"$TRY\" != \"$EXPECT\" ]\n\tthen\n\t\tfail \"Expected [$EXPECT] got [$TRY]\"\n\telse\n\t\techo \"OK\"\n\tfi\n}\n\n# A section of the test\nsection()\n{\n\tSECTION=\"$1\"\n\techo \"$1\"\n\trm -f client.err server.err\n}\n\n# A particular test case\ntestcase()\n{\n\tTESTCASE=\"$1\"\n\techo -n \"\t$1: \"\n}\n\n\n# Start the HTTP server\nstart_server()\n{\n\t$DGSH_HTTPVAL -p $PORT \"$@\" &\n\tSERVER_PID=$!\n}\n\n# Stop the HTTP server\nstop_server()\n{\n\tcurl -s40 http://localhost:$PORT/.server?quit >/dev/null\n\tsleep 1\n\tkill $SERVER_PID 2>/dev/null\n\tsleep 2\n\tSERVER_PID=''\n}\n\n\n# Simple tests {{{1\nsection 'Simple tests' # {{{2\n\ntestcase \"Single record\" # {{{3\necho single record | $DGSH_WRITEVAL -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -l -s testsocket 2>client.err `\"\nEXPECT='single record'\ncheck\n\ntestcase \"Single record fixed width\" # {{{3\nprintf 0123456789 | $DGSH_WRITEVAL -l 10 -s testsocket 2>server.err &\nsleep 1\nEXPECT='0123456789'\nTRY=\"`$DGSH_READVAL -l -s testsocket 2>client.err `\"\ncheck\n\ntestcase \"Record separator\" # {{{3\nprintf record1:record2 | $DGSH_WRITEVAL -t : -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -l -s testsocket 2>client.err `\"\nEXPECT='record1:'\ncheck\n\nsleep 1\ntestcase \"HTTP interface - text data\" # {{{3\nPORT=53843\necho single record | $DGSH_WRITEVAL -s testsocket 2>server.err &\nstart_server\n# -s40: silent, IPv4 HTTP 1.0\nTRY=\"`curl -s40 http://localhost:$PORT/testsocket`\"\nEXPECT='single record'\ncheck\nstop_server\n\ntestcase \"HTTP interface - non-blocking empty record\" # {{{3\nPORT=53843\n{ sleep 2 ; echo hi ; } | $DGSH_WRITEVAL -s testsocket 2>server.err &\nstart_server -n\n# -s40: silent, IPv4 HTTP 1.0\nTRY=\"`curl -s40 http://localhost:$PORT/testsocket`\"\nEXPECT=''\ncheck\nstop_server\n\ntestcase \"HTTP interface - non-blocking first record\" # {{{3\nPORT=53843\necho 'first record' | $DGSH_WRITEVAL -s testsocket 2>server.err &\nstart_server -n\n# -s40: silent, IPv4 HTTP 1.0\nsleep 1\nTRY=\"`curl -s40 http://localhost:$PORT/testsocket`\"\nEXPECT='first record'\ncheck\nstop_server\n\ntestcase \"HTTP interface - non-blocking second record\" # {{{3\nPORT=53843\n( echo 'first record' ; sleep 1 ; echo 'second record' ) |\n$DGSH_WRITEVAL -s testsocket 2>server.err &\nstart_server -n\n# -s40: silent, IPv4 HTTP 1.0\nsleep 2\nTRY=\"`curl -s40 http://localhost:$PORT/testsocket`\"\nEXPECT='second record'\ncheck\nstop_server\n\ntestcase \"HTTP interface - binary data\" # {{{3\nPORT=53843\nperl -e 'BEGIN { binmode STDOUT; }\nfor ($i = 0; $i < 256; $i++) { print chr($i); }' |\n$DGSH_WRITEVAL -l 256 -s testsocket 2>server.err &\nstart_server -m application/octet-stream\n# -s40: silent, IPv4 HTTP 1.0\ncurl -s40 http://localhost:$PORT/testsocket |\nperl -e 'BEGIN { binmode STDIN; }\nfor ($i = 0; $i < 256; $i++) { $expect .= chr($i); }\nread STDIN, $try, 256;\nif ($try ne $expect) {\n\tprint \"FAIL\\n\";\n\tprint \"Expected [$expect] got [$try]\\n\";\n} else {\n\tprint \"OK\\n\";\n}\nexit ($try ne $expect);\n'\nEXITCODE=$?\nstop_server\n$DGSH_READVAL -q -s testsocket 2>client.err 1>/dev/null\ntest $EXITCODE = 0 || exit 1\n\ntestcase \"HTTP interface - large data\" # {{{3\nPORT=53843\ndd if=/dev/zero bs=1000000 count=1 2>/dev/null |\n$DGSH_WRITEVAL -l 1000000 -s testsocket 2>server.err &\nstart_server -m application/octet-stream\n# -s40: silent, IPv4 HTTP 1.0\nBYTES=$(curl -s40 http://localhost:$PORT/testsocket |\n  wc -c |\n  sed 's/^[^0-9]*//')\nstop_server\n$DGSH_READVAL -q -s testsocket 2>client.err 1>/dev/null\nif [ \"$BYTES\" != 1000000 ]\nthen\n\techo FAIL\n\techo \"Expected [1000000 bytes] got [$BYTES bytes]\"\n\texit 1\nelse\n\techo \"OK\"\nfi\n\n# Last record tests {{{1\nsection 'Reading of fixed-length records in stream' # {{{2\n(printf A12345A7AB; sleep 4; printf 12345B7BC; sleep 4; printf 12345C7CD) | $DGSH_WRITEVAL -l 9 -s testsocket 2>server.err &\n\ntestcase \"Record one\" # {{{3\nsleep 2\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err`\"\nEXPECT=A12345A7A\ncheck -n\n\ntestcase \"Record two\" # {{{3\nsleep 4\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT=B12345B7B\ncheck -n\n\ntestcase \"Record three\" # {{{3\nsleep 4\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err`\"\nEXPECT=C12345C7C\ncheck\n\n# The socket is no longer there\n# Verify that readval doesn't block retrying\n$DGSH_READVAL -nq -s testsocket 2>client.err\n\n\nsection 'Reading of newline-separated records in stream' # {{{2\n(echo record one; sleep 4; echo record two; sleep 4; echo record three) | $DGSH_WRITEVAL -s testsocket 2>server.err &\n\ntestcase \"Record one\" # {{{3\nsleep 2\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='record one'\ncheck -n\n\ntestcase \"Record two\" # {{{3\nsleep 4\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='record two'\ncheck -n\n\ntestcase \"Record three\" # {{{3\nsleep 4\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='record three'\ncheck\n\nsection 'Non-blocking reading of newline-separated records in stream' # {{{2\n(sleep 2 ; echo record one; sleep 4; echo record two; sleep 6; echo record three) | $DGSH_WRITEVAL -s testsocket 2>server.err &\n\ntestcase \"Empty record\" # {{{3\nTRY=\"`$DGSH_READVAL -e -s testsocket 2>client.err `\"\nEXPECT=''\ncheck -n\n\ntestcase \"Record one\" # {{{3\nsleep 3\nTRY=\"`$DGSH_READVAL -e -s testsocket 2>client.err `\"\nEXPECT='record one'\ncheck -n\n\ntestcase \"Record two\" # {{{3\nsleep 5\nTRY=\"`$DGSH_READVAL -e -s testsocket 2>client.err `\"\nEXPECT='record two'\ncheck\n\nsection 'Reading last record' # {{{2\n\ntestcase \"Last record\" # {{{3\n(echo record one; sleep 1; echo last record) | $DGSH_WRITEVAL -s testsocket 2>server.err &\nTRY=\"`$DGSH_READVAL -l -s testsocket 2>client.err `\"\nEXPECT='last record'\ncheck\n\ntestcase \"Last record as default\" # {{{3\n(echo record one; sleep 1; echo last record) | $DGSH_WRITEVAL -s testsocket 2>server.err &\nTRY=\"`$DGSH_READVAL -s testsocket 2>client.err `\"\nEXPECT='last record'\ncheck\n\ntestcase \"Empty record\" # {{{3\n$DGSH_WRITEVAL -s testsocket 2>server.err </dev/null &\nTRY=\"`$DGSH_READVAL -l -s testsocket 2>client.err `\"\nEXPECT=''\ncheck\n\ntestcase \"Incomplete record\" # {{{3\nprintf unterminated | $DGSH_WRITEVAL -s testsocket 2>server.err &\nTRY=\"`$DGSH_READVAL -l -s testsocket 2>client.err `\"\nEXPECT=''\ncheck\n\n# Window tests {{{1\nsection 'Window from stream' # {{{2\n\ntestcase \"Second record\" # {{{3\n(echo first record ; echo second record ; echo third record; sleep 2) | $DGSH_WRITEVAL -b 2 -e 1 -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='second record'\ncheck\n\ntestcase \"First record\" # {{{3\n(echo first record ; echo second record ; echo third record; sleep 2) | $DGSH_WRITEVAL -b 3 -e 2 -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='first record'\ncheck\n\ntestcase \"Second record\" # {{{3\n(echo first record ; echo second record ; echo third record; sleep 2) | $DGSH_WRITEVAL -b 3 -e 1 -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='first record\nsecond record'\ncheck\n\ntestcase \"All records\" # {{{3\n(echo first record ; echo second record ; echo third record; sleep 2) | $DGSH_WRITEVAL -b 3 -e 0 -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='first record\nsecond record\nthird record'\ncheck\n\nsection 'Window from fixed record stream' # {{{2\n\ntestcase \"Middle record\" # {{{3\n(printf 000 ; printf 011112 ; printf 222; sleep 2) | $DGSH_WRITEVAL -l 4 -b 2 -e 1 -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='1111'\ncheck\n\ntestcase \"First record\" # {{{3\n(printf 000 ; printf 011112 ; printf 222; sleep 2) | $DGSH_WRITEVAL -l 4 -b 3 -e 2 -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='0000'\ncheck\n\ntestcase \"First two records\" # {{{3\n(printf 000 ; printf 011112 ; printf 222; sleep 2) | $DGSH_WRITEVAL -l 4 -b 3 -e 1 -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='00001111'\ncheck\n\ntestcase \"All records\" # {{{3\n(printf 000 ; printf 011112 ; printf 222; sleep 2) | $DGSH_WRITEVAL -l 4 -b 3 -e 0 -s testsocket 2>server.err &\nsleep 1\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='000011112222'\ncheck\n\n\n# Time window tests {{{1\nsection 'Time window from terminated record stream' # {{{2\n\ntestcase \"First record\" # {{{3\n(echo First record ; sleep 1 ; echo Second--record ; sleep 1 ; echo The third record; sleep 3) | $DGSH_WRITEVAL -u s -b 3.5 -e 2.5 -s testsocket 2>server.err &\n#Rel  3                             2                               1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='First record'\ncheck\n\ntestcase \"Middle record\" # {{{3\n(echo First record ; sleep 1 ; echo Second record ; sleep 1 ; echo The third record; sleep 3) | $DGSH_WRITEVAL -u s -b 2.5 -e 1.5 -s testsocket 2>server.err &\n#Rel     3                       2                          1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='Second record'\ncheck\n\ntestcase \"First two records (full buffer)\" # {{{3\n(echo First record ; sleep 1 ; echo Second--record ; sleep 1 ; echo The third record; sleep 3) | $DGSH_WRITEVAL -u s -b 3.5 -e 1.5 -s testsocket 2>server.err &\n#Rel  3                             2                               1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='First record\nSecond--record'\ncheck\n\ntestcase \"First two records (incomplete buffer)\" # {{{3\n(echo First record ; sleep 1 ; echo Second record ; sleep 1 ; echo The third record; sleep 3) | $DGSH_WRITEVAL -u s -b 3.5 -e 1.5 -s testsocket 2>server.err &\n#Rel  3                             2                               1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='First record\nSecond record'\ncheck\n\ntestcase \"Last record\" # {{{3\n(echo First record ; sleep 1 ; echo Second--record ; sleep 1 ; echo The third record; sleep 3) | $DGSH_WRITEVAL -u s -b 1.5 -e 0.5 -s testsocket 2>server.err &\n#Rel  3                             2                               1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='The third record'\ncheck\n\ntestcase \"All records\" # {{{3\n(echo First record ; sleep 1 ; echo Second--record ; sleep 1 ; echo The third record; sleep 3) | $DGSH_WRITEVAL -u s -b 3.5 -e 0.5 -s testsocket 2>server.err &\n#Rel  3                             2                               1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='First record\nSecond--record\nThe third record'\ncheck\n\ntestcase \"First record after wait\" # {{{3\n(echo First record ; sleep 1 ; echo Second--record ; sleep 1 ; echo The third record; sleep 3) | $DGSH_WRITEVAL -u s -b 4.5 -e 3.5 -s testsocket 2>server.err &\n#Rel  3                             2                               1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='First record'\ncheck\n\nsection 'Time window from fixed record stream' # {{{2\n\ntestcase \"Fixed record stream, first record\" # {{{3\n(printf 000 ; sleep 1 ; printf 011112 ; sleep 1 ; printf 222; sleep 3) | $DGSH_WRITEVAL -l 4 -u s -b 3.5 -e 2.5 -s testsocket 2>server.err &\n#Rel     3                       2                          1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='0000'\ncheck\n\ntestcase \"First two records\" # {{{3\n(printf 000 ; sleep 1 ; printf 011112 ; sleep 1 ; printf 222; sleep 3) | $DGSH_WRITEVAL -l 4 -u s -b 3.5 -e 1.5 -s testsocket 2>server.err &\n#Rel     3                       2                          1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='000011112222'\ncheck\n\ntestcase \"Middle record\" # {{{3\n(printf 000 ; sleep 1 ; printf 011112 ; sleep 1 ; printf 222; sleep 3) | $DGSH_WRITEVAL -l 4 -u s -b 2.5 -e 1.5 -s testsocket 2>server.err &\n#Rel     3                       2                          1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='11112222'\ncheck\n\ntestcase \"Last record\" # {{{3\n(printf 000 ; sleep 1 ; printf 01111 ; sleep 1 ; printf 222; printf 2 ; sleep 3) | $DGSH_WRITEVAL -l 4 -u s -b 1.5 -e 0.5 -s testsocket 2>server.err &\n#Rel     3                       2                          1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='2222'\ncheck\n\ntestcase \"All records\" # {{{3\n(printf 000 ; sleep 1 ; printf 01111 ; sleep 1 ; printf 222; printf 2 ; sleep 3) | $DGSH_WRITEVAL -l 4 -u s -b 3.5 -e 0.5 -s testsocket 2>server.err &\n#Rel     3                       2                          1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='000011112222'\ncheck\n\n\ntestcase \"First record after wait\" # {{{3\n(printf 000 ; sleep 1 ; printf 01111 ; sleep 1 ; printf 222; printf 2 ; sleep 3) | $DGSH_WRITEVAL -l 4 -u s -b 4.5 -e 3.5 -s testsocket 2>server.err &\n#Rel     3                       2                          1\nsleep 3\nTRY=\"`$DGSH_READVAL -c -s testsocket 2>client.err `\"\nEXPECT='0000'\ncheck\n\nsection 'Multi-client stress test' # {{{1\necho -n \"\tRunning\"\n\nif [ ! -r test/sorted-words ]\nthen\n\tmkdir -p test\n\t{\n\t\tcat /usr/share/dict/words 2>/dev/null ||\n\t\tcurl -s https://raw.githubusercontent.com/freebsd/freebsd/master/share/dict/web2\n\t} | head -50000 | sort >test/sorted-words\nfi\n\n$DGSH_WRITEVAL -s testsocket 2>server.err <test/sorted-words &\n\n# Number of parallel clients to run\nNUMCLIENTS=5\n\n# Number of read commands to issue\nNUMREADS=300\n\n(\n\tfor i in `sequence $NUMCLIENTS`\n\tdo\n\t\t\tfor j in `sequence $NUMREADS`\n\t\t\tdo\n\t\t\t\t$DGSH_READVAL -c -s testsocket 2>client.err\n\t\t\tdone >read-words-$i &\n\tdone\n\n\twait\n\n\techo\n\techo \"\tAll clients finished\"\n\t$DGSH_READVAL -lq -s testsocket 2>client.err 1>/dev/null\n\techo \"\tServer finished\"\n)\n\necho -n \"\tCompare: \"\n\n# Wait for the store to terminate\nwait\n\nfor i in `sequence $NUMCLIENTS`\ndo\n\tif sort -u read-words-$i | comm -13 test/sorted-words - | grep .\n\tthen\n\t\tfail \"Stress test client $i has trash output\"\n\tfi\n\tif [ `wc -l < read-words-$i` -ne $NUMREADS ]\n\tthen\n\t\tfail \"Stress test client is missing output\"\n\tfi\ndone\nrm -f read-words-*\necho \"OK\"\n\nsection 'Time window stress test' # {{{1\necho -n \"\tRunning\"\n\n# Feed words at a slower pace\nperl -pe 'select(undef, undef, undef, 0.001);' test/sorted-words |\n$DGSH_WRITEVAL -u s -b 3 -e 2 -s testsocket 2>server.err &\necho\necho \"\tServer started\"\n\n# Number of parallel clients to run\nNUMCLIENTS=5\n\n# Number of read commands to issue\nNUMREADS=300\n\necho -n \"\tRunning clients\"\n(\n\tfor i in `sequence $NUMCLIENTS`\n\tdo\n\t\t\tfor j in `sequence $NUMREADS`\n\t\t\tdo\n\t\t\t\t$DGSH_READVAL -c -s testsocket 2>client.err\n\t\t\tdone >read-words-$i &\n\tdone\n\n\twait\n\n\techo\n\techo \"\tAll clients finished\"\n\t$DGSH_READVAL -q -s testsocket 2>client.err 1>/dev/null\n\techo \"\tServer finished\"\n)\n\necho -n \"\tCompare: \"\n\n# Wait for the store to terminate\nwait\n\nfor i in `sequence $NUMCLIENTS`\ndo\n\tif sort -u read-words-$i | comm -13 test/sorted-words - | grep .\n\tthen\n\t\tfail \"Stress test client $i has trash output\"\n\tfi\n\tif [ `wc -l < read-words-$i` -lt $NUMREADS ]\n\tthen\n\t\tfail \"Stress test client may be missing output\"\n\tfi\ndone\n\nrm -f read-words-* client.err server.err\necho \"OK\"\n"
  },
  {
    "path": "core-tools/tests-regression/test-merge-sum.sh",
    "content": "#!/usr/bin/env bash\n#\n# Tests for dgsh-merge-sum\n#\n\nMERGE_SUM=../src/dgsh-merge-sum.pl\n\n# Shortcut\ntestcase()\n{\n\tlocal name=\"$1\"\n\tlocal expect=\"$2\"\n\tlocal in=\"$3\"\n\tshift 3\n\tif ! diff <(perl $MERGE_SUM <\"$in\" \"$@\") $expect\n\tthen\n\t\techo 1>&2 \"Test $name failed\"\n\t\texit 1\n\telse\n\t\techo 1>&2 \"Test $name OK\"\n\tfi\n}\n\ntestcase merge <(cat <<RESULT\n1 a\n4 c\n2 d\n8 z\nRESULT\n) <(cat <<EOF\n1 a\n2 d\nEOF\n) <(cat <<EOF\n4 c\n8 z\nEOF\n)\n\ntestcase sum <(cat <<RESULT\n1 a\n10 b\n4 c\n2 d\n8 z\nRESULT\n) <(cat <<EOF\n1 a\n5 b\n2 d\nEOF\n) <(cat <<EOF\n5 b\n4 c\n8 z\nEOF\n)\n\n# Leading white space\ntestcase leading <(cat <<RESULT\n1 a\n4 c\n2 d\n8 z\nRESULT\n) <(cat <<EOF\n 1 a\n2 d\nEOF\n) <(cat <<EOF\n\t4 c\n8 z\nEOF\n)\n\n# White space embedded in values\ntestcase embedded <(cat <<RESULT\n1 a d f\n4 c\n2 d\n8 z\nRESULT\n) <(cat <<EOF\n 1 a d f\n2\td\nEOF\n) <(cat <<EOF\n\t4 c\n8 z\nEOF\n)\n\n# Single file\ntestcase single <(cat <<RESULT\n1 a\n4 c\nRESULT\n) <(cat <<EOF\n1 a\n4 c\nEOF\n)\n\n# Empty files\ntestcase empty <(cat <<RESULT\n1 a\n4 c\nRESULT\n) /dev/null <(cat <<EOF\n1 a\n4 c\nEOF\n) /dev/null\n\n# Three files\ntestcase three <(cat <<RESULT\n2 a\n11 b\n4 c\n2 d\n9 z\nRESULT\n) <(cat <<EOF\n1 a\n1 b\nEOF\n) <(cat <<EOF\n1 a\n5 b\n2 d\n1 z\nEOF\n) <(cat <<EOF\n5 b\n4 c\n8 z\nEOF\n)\n"
  },
  {
    "path": "core-tools/tests-regression/test-tee.sh",
    "content": "#!/bin/sh\n#\n# Regression tests for dgsh-tee\n#\n\nTOP=$(cd ../.. ; pwd)\nDGSH_TEE=$TOP/build/libexec/dgsh/dgsh-tee\nDGSH_ENUMERATE=$TOP/build/libexec/dgsh/dgsh-enumerate\nDGSH_TEE_C=../src/dgsh-tee.c\nWORDS=/usr/share/dict/words\nDGSH=\"$TOP/build/bin/dgsh\"\nPATH=\"$TOP/build/bin:$PATH\"\nexport DGSHPATH=\"$TOP/build/libexec/dgsh\"\n\n# Ensure that the files passed as 2nd and 3rd arguments are the same\nensure_same()\n{\n\techo -n \"$1 \"\n\tif ! diff $2 $3 >/dev/null\n\tthen\n\t\techo \"$1: $2 and $3 differ\" 1>&2\n\t\texit 1\n\tfi\n\techo OK\n}\n\n# Produce statistics on the character count of the data received from\n# standard input\ncharcount()\n{\n  sed 's/./&\\\n  /g' |\n  sort |\n  uniq -c\n}\n\n# Ensure that the numbers in the files passed as 2nd and 3rd arguments\n# about are the same\n# Line format:\n# Buffers allocated: 1025 Freed: 1024 Maximum allocated: 960\nensure_similar_buffers()\n{\n\techo -n \"$1 \"\n\tfor nr in 2 3\n\tdo\n\t\tfor nf in 3 5 8\n\t\tdo\n\t\t\tif ! awk \"\n\t\t\tfunction abs(v)\n\t\t\t{\n\t\t\t\treturn (v < 0 ? -v : v)\n\t\t\t}\n\t\t\tNR == $nr {ref = \\$$nf}\n\t\t\tNR == $nr + 3 {test = \\$$nf}\n\t\t\tEND { exit (ref + 0 != 0 && abs((test - ref) / ref * 100) > 10) ? 1 : 0 }\" \"$2\" \"$3\"\n\t\t\tthen\n\t\t\t\techo \"$1: Line $nr, fields $nf of $2 and $3 differ by more than 10%\" 1>&2\n\t\t\t\texit 1\n\t\t\tfi\n\t\tdone\n\tdone\n\techo OK\n}\n\n\n\nfor flags in '' -I\ndo\n\t# Test two input files\n\tcat $DGSH_TEE_C $DGSH_TEE_C $WORDS >expected\n\t$DGSH_TEE $flags -b 64 -i $DGSH_TEE_C -i $DGSH_TEE_C -i $WORDS >a\n\tensure_same \"Three input $flags\" expected a\n\trm expected a\n\n\t# Test line scatter reliable algorithm (stdin)\n\tcat -n $WORDS >words\n\t$DGSH_TEE $flags -s -b 1000000 <words -o a -o b -o c -o d\n\tcat a b c d | sort -n >words2\n\tensure_same \"Line scatter reliable stdin $flags\" words words2\n\n\t# Test line scatter reliable algorithm (pipe)\n\tcat -n $WORDS |\n\t$DGSH_TEE $flags -s -b 1000000 -o a -o b -o c -o d\n\tcat a b c d | sort -n >words2\n\tensure_same \"Line scatter reliable pipe $flags\" words words2\n\n\n\t# Test line scatter reliable algorithm (file argument)\n\tcat -n $WORDS >words\n\t$DGSH_TEE $flags -s -b 1000000 -i words -o a -o b -o c -o d\n\tcat a b c d | sort -n >words2\n\tensure_same \"Line scatter reliable file $flags\" words words2\n\n\t# Test scatter to blocking sinks\n\tcat -n $WORDS >words\n\tfor buffer in 128 1000000\n\tdo\n\t\t$DGSH -c \"\n\t\t$DGSH_TEE -b $buffer -s -i words |\n\t\tdgsh-parallel -n 8 cat |\n\t\tsort -mn >a\"\n\t\tensure_same \"Scatter to blocking sinks $flags -b $buffer\" words a\n\tdone\n\trm a\n\n\t# Test line scatter efficient algorithm\n\t$DGSH_TEE $flags -s -b 128 <words -o a -o b -o c -o d\n\tcat a b c d | sort -n >words2\n\tensure_same \"Line scatter efficient $flags\" words words2\n\n\t# Test with a buffer smaller than line size\n\t$DGSH_TEE $flags -s -b 5 <words -o a -o b -o c -o d\n\tcat a b c d | sort -n >words2\n\tensure_same \"Small buffer $flags\" words words2\n\n\t# Test with data less than the buffer size\n\thead -50 $WORDS | cat -n >words\n\t$DGSH_TEE $flags -s -b 1000000 <words -o a -o b -o c -o d\n\tcat a b c d | sort -n >words2\n\tensure_same \"Large buffer $flags\" words words2\n\trm words words2\n\n\t# Test block scatter\n\t$DGSH_TEE $flags -s -b 64 <$DGSH_TEE_C -o a -o b -o c -o d\n\tcharcount <$DGSH_TEE_C >orig\n\tcat a b c d | charcount >new\n\tensure_same \"Block scatter $flags\" orig new\n\trm a b c d orig new\n\n\t# Test plain distribution\n\t$DGSH_TEE $flags -b 64 <$DGSH_TEE_C -o a -o b\n\tensure_same \"Plain distribution $flags\" $DGSH_TEE_C a\n\tensure_same \"Plain distribution $flags\" $DGSH_TEE_C b\n\trm a b\n\n\t# Test 2->4 distribution\n\t$DGSH_TEE $flags -b 64 -i $WORDS -i $DGSH_TEE_C -o a -o b -o c -o d\n\tensure_same \"2->4 distribution $flags\" $WORDS a\n\tensure_same \"2->4 distribution $flags\" $WORDS c\n\tensure_same \"2->4 distribution $flags\" $DGSH_TEE_C b\n\tensure_same \"2->4 distribution $flags\" $DGSH_TEE_C d\n\trm a b c d\n\n\t# Test 4->2 distribution\n\tcat $WORDS /etc/services >result1\n\tcat $DGSH_TEE_C /etc/hosts >result2\n\t$DGSH_TEE $flags -b 64 -i $WORDS -i $DGSH_TEE_C -i /etc/services -i /etc/hosts -o a -o b\n\tensure_same \"4->2 distribution $flags\" result1 a\n\tensure_same \"4->2 distribution $flags\" result2 b\n\trm a b result1 result2\n\n\t# Test permutation\n\t$DGSH -c \"$DGSH_ENUMERATE 4 | $DGSH_TEE -p 4,2,3,1 | $DGSH_TEE\" >a\n\tensure_same \"Permutation $flags\" a tee/perm.ok\n\trm a\n\n\t# Test output to stdout\n\t$DGSH_TEE $flags -b 64 <$DGSH_TEE_C >a\n\tensure_same \"Stdout $flags\" $DGSH_TEE_C a\n\trm a\n\n\t# Test buffering\n\t# When -l is supported add, say, -l 16\n\tfor flags2 in '' '-m 2k' '-m 2k -f'\n\tdo\n\t\ttest=\"tee-fastout$flags$flags2\"\n\t\tdd bs=1k count=1024 if=/dev/zero 2>/dev/null | $DGSH_TEE -M $flags $flags2 -b 1024 >/dev/null 2>\"tee/$test.test\"\n\t\tensure_similar_buffers \"$test\" \"tee/$test.ok\" \"tee/$test.test\"\n\t\ttest=\"tee-lagout$flags$flags2\"\n\t\tdd bs=1k count=1024 if=/dev/zero 2>/dev/null | $DGSH_TEE -M $flags $flags2 -b 1024 2>\"tee/$test.test\" | (sleep 1 ; cat >/dev/null)\n\t\tensure_similar_buffers \"$test\" \"tee/$test.ok\" \"tee/$test.test\"\n\tdone\n\n\t# Test low-memory behavior (memory)\n\trm -f try try2\n\tmkfifo try try2\n\tperl -e 'for ($i = 0; $i < 500; $i++) { print \"x\" x 500, \"\\n\"}' | tee lines | $DGSH_TEE $flags -b 512 -m 2k -o try -o try2 2>err &\n\tcat try2 >try2.out &\n\t{ read x ; echo $x ; sleep 1 ; cat ; } < try > try.out &\n\twait\n\tif [ \"$flags\" = '-I' ]\n\tthen\n\t\tensure_same \"Low-memory $flags error\" err tee/oom.err\n\telse\n\t\tensure_same \"Low-memory (try) $flags\" lines try.out\n\t\tensure_same \"Low-memory (try2) $flags\" lines try2.out\n\tfi\n\trm -f lines try try2 try.out try2.out err\n\n\t# Test low-memory behavior (file)\n\trm -f try try2\n\tmkfifo try try2\n\tperl -e 'for ($i = 0; $i < 500; $i++) { print \"x\" x 500, \"\\n\"}' | tee lines | $DGSH_TEE -f $flags -b 512 -m 2k -o try -o try2 2>err &\n\tcat try2 >try2.out &\n\t{ read x ; echo $x ; sleep 1 ; cat ; } < try > try.out &\n\twait\n\tcat err\n\tensure_same \"Low-memory temporary file (try) $flags\" lines try.out\n\tensure_same \"Low-memory temporary file (try2) $flags\" lines try2.out\n\trm -f lines try try2 try.out try2.out err\ndone\n\n# Test asynchronous reading from multiple input files\n# Without it the following blocks\n# Also test multiple temporary files\nfor flags in '' '-m 65536 -f'\ndo\n\trm -f a b c d\n\tmkfifo a b c\n\t$DGSH_TEE -b 4096 -m 65536 -i /usr/share/dict/words -o a -o b -o c &\n\t$DGSH_TEE -b 4096 -I $flags -i a -i b -i c -o d &\n\twait\n        for i in . . .\n        do\n                cat /usr/share/dict/words\n        done >expect\n\tensure_same \"Asynchronous gather $flags\" expect d\n\trm -f a b c d expect\ndone\n\nexit 0\n"
  },
  {
    "path": "core-tools/tests-regression/test-wrap.sh",
    "content": "#!/bin/sh\n#\n# Regression testing of the provided examples\n#\n\nTOP=$(cd ../.. ; pwd)\nDGSH=\"$TOP/build/bin/dgsh\"\nPATH=\"$TOP/build/bin:$PATH\"\nexport DGSHPATH=\"$TOP/build/libexec/dgsh\"\n\n# Ensure that the generated test file matches the reference one\n# File names are by conventions dgsh-wrap/$case.{ok,test}\nensure_same()\n{\n  local case=$1\n  echo -n \"$case \"\n  if diff dgsh-wrap/$case.ok dgsh-wrap/$case.test\n  then\n    echo OK\n  else\n    echo \"$case: Files differ: dgsh-wrap/$case.ok dgsh-wrap/$case.test\" 1>&2\n    exit 1\n  fi\n}\n\n# Include fallback commands in our executable path\nexport PATH=\"$PATH:bin\"\n\n# Test that echo is wrapped as deaf\n$DGSH -c 'dgsh-enumerate 1 | {{ dgsh-wrap -i 0 echo hi ; dgsh-wrap dd 2>/dev/null ; }} | cat' >dgsh-wrap/echo-deaf.test\nensure_same echo-deaf\n\n# Test that echo is wrapped as deaf when wrapped as script with supplied exec\necho \"#!$TOP/build/libexec/dgsh/dgsh-wrap -S  -i 0 `which echo`\" >dgsh-wrap/echo-s_caps\nchmod +x dgsh-wrap/echo-s_caps\n$DGSH -c 'dgsh-enumerate 1 | {{ dgsh-wrap/echo-s_caps hi ; dgsh-wrap dd 2>/dev/null ; }} | cat' >dgsh-wrap/echo-s_caps.test\nensure_same echo-s_caps\n\n# Test that echo is wrapped as deaf when wrapped as script with implied exec\necho \"#!$TOP/build/libexec/dgsh/dgsh-wrap -s  -i 0\" >dgsh-wrap/echo\nchmod +x dgsh-wrap/echo\n$DGSH -c 'dgsh-enumerate 1 | {{ dgsh-wrap/echo hi ; dgsh-wrap dd 2>/dev/null ; }} | cat' >dgsh-wrap/echo-s.test\nensure_same echo-s\n\n# Verify the fdescfs functionality (required by dgsh-wrap <| and >|\n# arguments) is available\nif [ $(ls /dev/fd | wc -l) -lt 4 ] ; then\n  cat <<\\EOF 1>&2\nThe full functionality of dgsh-wrap requires full /dev/fd functionality;\ni.e.  that *all* file descriptors of a process are available under /dev/fd.\nIt appears that on this system only the first three file descriptors\nare available under /dev/fd.  Consequently, dgsh-wrap will not be able\nsupport <| and >| arguments and dependent programs (e.g. dgsh-parallel)\nwill fail.\n\nIn FreeBSD full /dev/fd functionality is provided by fdescfs; the\nfunctionality that FreeBSD devfs provides by default only includes\nthe first three file descriptors under /dev/fd.  In FreeBSD systems\nconsider mounting fdescfs(5) on /dev/fd to avoid this problem.\nEOF\n  exit 1\nfi\n\n# Test stand-alone input path substitution (with stdin)\n$DGSH -c 'dgsh-enumerate 2 | dgsh-wrap paste \"<|\" \"<|\" ' >dgsh-wrap/paste1.test\nensure_same paste1\n\n# Test stand-alone input path substitution (without stdin)\n$DGSH -c 'dgsh-enumerate 2 | dgsh-wrap -I /usr/bin/paste - \"<|\" ' >dgsh-wrap/paste2.test\nensure_same paste2\n\n# Test arbitrary input argument provision (with stdin)\n$DGSH -c 'dgsh-enumerate 2 | dgsh-wrap -i a paste' >dgsh-wrap/paste3.test\nensure_same paste3\n\n# Test arbitrary input argument provision (without stdin)\n$DGSH -c 'dgsh-enumerate 2 | dgsh-wrap -i a -I /usr/bin/paste -' >dgsh-wrap/paste4.test\nensure_same paste4\n\n# Test stand-alone output path substitution (without stdout)\n$DGSH -c 'echo hi | dgsh-wrap -O /usr/bin/tee \">|\" | {{ sed \"s/^/a/\" ; sed \"s/^/b/\" ; }} | cat' >dgsh-wrap/tee1.test\nensure_same tee1\n\n# Test arbitrary input argument provision (without stdout)\n$DGSH -c 'echo hi | dgsh-wrap -o a -O /usr/bin/tee | {{ sed \"s/^/a/\" ; sed \"s/^/b/\" ; }} | cat' >dgsh-wrap/tee2.test\nensure_same tee2\n\n# Test substitution of embedded arguments\n$DGSH -c 'dgsh-enumerate 1 | {{ dgsh-wrap -e dd \"if=<|\" \"of=>|\" 2>/dev/null ; }} | cat' >dgsh-wrap/dd-args.test\nensure_same dd-args\n\nexit 0\n"
  },
  {
    "path": "core-tools/tests-regression/text-properties/out.ok/character.txt",
    "content": "8380  21%\n3546 e 8.7%\n2535 t 6.2%\n2368 a 5.8%\n2345 o 5.8%\n1942 n 4.8%\n1850 i 4.5%\n1746 s 4.3%\n1700 h 4.2%\n1610 r 4%\n1273 l 3.1%\n1208 d 3%\n1011 u 2.5%\n801 m 2%\n697 c 1.7%\n684 y 1.7%\n675 w 1.7%\n619 f 1.5%\n528 , 1.3%\n517 g 1.3%\n479 p 1.2%\n476 . 1.2%\n422 \" 1%\n389 b 0.95%\n370 I 0.91%\n355 v 0.87%\n239 k 0.59%\n183 - 0.45%\n138 T 0.34%\n138 ' 0.34%\n117 E 0.29%\n100 W 0.25%\n99 A 0.24%\n98 H 0.24%\n97 S 0.24%\n79 ? 0.19%\n70 O 0.17%\n68 R 0.17%\n60 P 0.15%\n58 C 0.14%\n57 ! 0.14%\n54 N 0.13%\n54 L 0.13%\n52 Y 0.13%\n52 D 0.13%\n43 G 0.11%\n43 B 0.11%\n41 M 0.1%\n38 x 0.093%\n30 j 0.074%\n22 F 0.054%\n21 ; 0.052%\n20 V 0.049%\n20 U 0.049%\n17 z 0.042%\n17 q 0.042%\n17 : 0.042%\n11 K 0.027%\n8 X 0.02%\n7 1 0.017%\n6 * 0.015%\n5 Z 0.012%\n5 J 0.012%\n5 9 0.012%\n4 8 0.0098%\n3 3 0.0074%\n3 2 0.0074%\n2 Q 0.0049%\n2 0 0.0049%\n1 ] 0.0025%\n1 [ 0.0025%\n1 6 0.0025%\n1 ) 0.0025%\n1 ( 0.0025%\n1 # 0.0025%\n"
  },
  {
    "path": "core-tools/tests-regression/text-properties/out.ok/digram.txt",
    "content": "    689 th\n    602 he\n    473 er\n    469 ou\n    468 in\n    454 an\n    392 ha\n    371 re\n    346 at\n    331 en\n    310 on\n    309 it\n    287 nd\n    286 ed\n    281 ve\n    248 or\n    244 hi\n    240 me\n    237 is\n    231 ng\n    229 to\n    228 te\n    218 st\n    218 as\n    215 es\n    213 al\n    201 ar\n    197 nt\n    195 of\n    193 ll\n    188 le\n    179 yo\n    167 ea\n    162 se\n    159 ti\n    157 ro\n    152 wa\n    152 ma\n    150 ne\n    141 el\n    138 ul\n    135 ho\n    130 li\n    128 ut\n    128 ur\n    127 ic\n    127 de\n    127 ce\n    126 om\n    126 be\n    125 ad\n    122 wh\n    119 wi\n    119 si\n    117 ly\n    116 so\n    115 no\n    114 co\n    114 ch\n    110 us\n    108 ri\n    108 ld\n    107 io\n    106 lo\n    105 ee\n    103 ss\n    103 pe\n    103 ow\n    102 et\n    101 ra\n     98 ai\n     97 ta\n     92 ot\n     91 sh\n     91 la\n     90 wo\n     90 po\n     90 ca\n     90 av\n     89 ke\n     89 im\n     88 ge\n     88 fo\n     88 do\n     88 ac\n     87 oo\n     84 id\n     80 my\n     79 un\n     77 ie\n     77 fe\n     76 sa\n     75 nc\n     74 ns\n     71 os\n     70 ir\n     69 Th\n     68 rs\n     68 mo\n     67 di\n     66 ol\n     65 su\n     64 ev\n     62 rt\n     62 bl\n     61 gh\n     60 ry\n     59 we\n     58 up\n     58 pr\n     58 ec\n     58 ct\n     58 ay\n     55 fi\n     54 na\n     54 if\n     53 em\n     52 il\n     51 tu\n     50 ab\n     49 tr\n     49 rd\n     48 vi\n     48 ni\n     48 fa\n     48 am\n     47 tt\n     46 op\n     46 bo\n     45 ov\n     45 bu\n     44 ap\n     43 iv\n     43 ig\n     42 ug\n     42 mi\n     42 Yo\n     41 uc\n     41 ck\n     40 pl\n     40 ok\n     39 ci\n     38 sp\n     38 fr\n     38 da\n     37 ye\n     37 ht\n     37 He\n     36 ts\n     36 pa\n     36 ak\n     35 od\n     35 cr\n     35 ag\n     35 We\n     34 It\n     33 pp\n     33 mp\n     33 ey\n     32 rn\n     32 go\n     32 gi\n     32 ff\n     31 tl\n     31 ex\n     30 sc\n     30 br\n     30 Pr\n     29 ys\n     29 wn\n     29 ew\n     28 ty\n     28 lu\n     28 ga\n     28 ep\n     27 sm\n     27 ki\n     27 ia\n     26 ru\n     26 oi\n     26 fu\n     25 ba\n     25 au\n     25 Wh\n     24 ny\n     24 nk\n     24 mu\n     24 gr\n     24 dl\n     23 ud\n     23 lf\n     23 ei\n     23 cu\n     22 um\n     22 rl\n     22 nn\n     22 dy\n     21 ub\n     21 nl\n     21 ik\n     21 hu\n     21 ef\n     21 cl\n     21 TH\n     20 rm\n     20 pi\n     20 og\n     20 lt\n     20 ft\n     20 Ch\n     19 xp\n     19 ib\n     19 by\n     18 ue\n     18 gl\n     18 aw\n     18 So\n     18 HE\n     18 ER\n     17 sk\n     17 rg\n     17 qu\n     17 hr\n     17 ds\n     17 dr\n     17 Bu\n     16 va\n     16 ui\n     16 rv\n     16 oc\n     16 hy\n     16 An\n     15 tw\n     15 rk\n     15 lk\n     15 gu\n     15 eg\n     15 dd\n     15 af\n     15 Sh\n     15 OR\n     15 No\n     14 ze\n     14 rr\n     14 pu\n     14 ms\n     14 kn\n     14 Do\n     13 rf\n     13 oe\n     13 nv\n     13 ju\n     13 II\n     13 HA\n     12 ua\n     12 ph\n     12 ls\n     12 gs\n     12 gn\n     12 bi\n     11 ps\n     11 oy\n     11 mb\n     11 je\n     11 ip\n     11 dn\n     11 Lo\n     10 ws\n     10 vo\n     10 sl\n     10 rw\n     10 pt\n     10 eo\n     10 du\n     10 ST\n     10 ON\n     10 Ma\n     10 If\n     10 ES\n      9 fl\n      9 eh\n      9 RO\n      9 RE\n      9 Gl\n      9 En\n      8 wr\n      8 sw\n      8 rc\n      8 lp\n      8 dv\n      8 Wa\n      8 Mr\n      8 EN\n      8 Co\n      8 As\n      8 AR\n      7 yt\n      7 uf\n      7 tm\n      7 tc\n      7 sn\n      7 nf\n      7 gt\n      7 eb\n      7 cc\n      7 bj\n      7 az\n      7 WO\n      7 IN\n      7 Ho\n      7 Ha\n      7 GE\n      7 CH\n      7 Am\n      7 AL\n      6 oa\n      6 lw\n      6 lm\n      6 iz\n      6 VE\n      6 TE\n      6 SI\n      6 Re\n      6 OS\n      6 NG\n      6 My\n      6 LL\n      6 LD\n      6 In\n      6 De\n      6 Bo\n      6 Be\n      6 Au\n      6 Ar\n      6 AP\n      5 wl\n      5 rp\n      5 ob\n      5 nu\n      5 nb\n      5 mm\n      5 ks\n      5 kl\n      5 gg\n      5 fy\n      5 Zo\n      5 Wo\n      5 Wi\n      5 WA\n      5 Vi\n      5 Si\n      5 SS\n      5 RL\n      5 PR\n      5 Oh\n      5 OU\n      5 OF\n      5 La\n      5 LO\n      5 LE\n      5 IT\n      5 Fo\n      5 Ev\n      5 EA\n      5 Da\n      5 Ca\n      4 yw\n      4 ym\n      4 xt\n      4 tn\n      4 rh\n      4 py\n      4 nr\n      4 jo\n      4 eu\n      4 bb\n      4 XI\n      4 VI\n      4 To\n      4 Ta\n      4 Pe\n      4 Pa\n      4 PT\n      4 PE\n      4 On\n      4 NE\n      4 IS\n      4 Hi\n      4 Ge\n      4 FO\n      4 Ex\n      4 Di\n      4 DE\n      4 CO\n      4 Al\n      4 AV\n      4 AS\n      3 yi\n      3 xi\n      3 xc\n      3 xa\n      3 sy\n      3 sf\n      3 sd\n      3 oj\n      3 nm\n      3 lv\n      3 hf\n      3 gy\n      3 cA\n      3 bt\n      3 bs\n      3 UR\n      3 UL\n      3 Ti\n      3 Te\n      3 St\n      3 Se\n      3 SO\n      3 SE\n      3 RG\n      3 RD\n      3 Ne\n      3 Na\n      3 ND\n      3 Mc\n      3 MO\n      3 Li\n      3 Ke\n      3 Ju\n      3 Ir\n      3 IO\n      3 IG\n      3 HT\n      3 HI\n      3 Gu\n      3 Go\n      3 Ga\n      3 FE\n      3 Ed\n      3 ED\n      3 EB\n      3 CE\n      3 Br\n      3 Bl\n      3 Ac\n      2 zi\n      2 yp\n      2 yl\n      2 yh\n      2 ww\n      2 uo\n      2 tf\n      2 sb\n      2 oh\n      2 nz\n      2 nq\n      2 np\n      2 nj\n      2 mn\n      2 ku\n      2 ka\n      2 ja\n      2 iu\n      2 hw\n      2 hs\n      2 hm\n      2 gm\n      2 ek\n      2 eB\n      2 dw\n      2 dg\n      2 cy\n      2 ae\n      2 Ye\n      2 XV\n      2 WI\n      2 WE\n      2 Up\n      2 Un\n      2 UT\n      2 US\n      2 UN\n      2 UE\n      2 TS\n      2 TO\n      2 TL\n      2 Su\n      2 Sc\n      2 Sa\n      2 Ri\n      2 RY\n      2 RT\n      2 RS\n      2 RF\n      2 QU\n      2 Pu\n      2 PP\n      2 Of\n      2 OW\n      2 OC\n      2 Mu\n      2 Mo\n      2 Me\n      2 MA\n      2 LY\n      2 KE\n      2 IV\n      2 IR\n      2 IL\n      2 HO\n      2 Gi\n      2 GH\n      2 Fr\n      2 FU\n      2 ET\n      2 EE\n      2 EC\n      2 DW\n      2 Cr\n      2 Cl\n      2 CT\n      2 CK\n      2 By\n      2 At\n      2 Ah\n      2 Ad\n      1 zo\n      1 yr\n      1 yb\n      1 xu\n      1 xq\n      1 xe\n      1 wf\n      1 wd\n      1 tb\n      1 rb\n      1 nx\n      1 nh\n      1 mr\n      1 ml\n      1 ln\n      1 lg\n      1 ky\n      1 ix\n      1 iw\n      1 iq\n      1 hn\n      1 hl\n      1 hd\n      1 ez\n      1 dt\n      1 dm\n      1 cs\n      1 ax\n      1 ao\n      1 aj\n      1 YR\n      1 YO\n      1 YL\n      1 YI\n      1 YE\n      1 WN\n      1 WH\n      1 Ve\n      1 Us\n      1 UC\n      1 Tu\n      1 Tr\n      1 TR\n      1 TM\n      1 TI\n      1 TA\n      1 Sw\n      1 Sp\n      1 Sk\n      1 SM\n      1 SH\n      1 SC\n      1 SA\n      1 Ru\n      1 Ro\n      1 RR\n      1 RK\n      1 RI\n      1 Pl\n      1 PY\n      1 PO\n      1 PI\n      1 PA\n      1 Ou\n      1 Or\n      1 Ol\n      1 Ob\n      1 OY\n      1 OP\n      1 OO\n      1 OK\n      1 OJ\n      1 OI\n      1 NT\n      1 NQ\n      1 NO\n      1 NM\n      1 NK\n      1 NI\n      1 NC\n      1 NB\n      1 NA\n      1 MS\n      1 MP\n      1 ML\n      1 Lu\n      1 LU\n      1 LA\n      1 Kn\n      1 Ka\n      1 KN\n      1 JU\n      1 JE\n      1 Is\n      1 Im\n      1 IX\n      1 IM\n      1 IC\n      1 IB\n      1 Hu\n      1 HU\n      1 GU\n      1 GS\n      1 GR\n      1 GG\n      1 Fa\n      1 FL\n      1 FI\n      1 Em\n      1 Eh\n      1 EY\n      1 EW\n      1 EV\n      1 EO\n      1 EF\n      1 DR\n      1 DO\n      1 DI\n      1 DF\n      1 CI\n      1 Ba\n      1 BO\n      1 BL\n      1 BI\n      1 BE\n      1 Af\n      1 AT\n      1 AN\n      1 AK\n      1 AI\n      1 AD\n"
  },
  {
    "path": "core-tools/tests-regression/text-properties/out.ok/trigram.txt",
    "content": "    350 the\n    176 and\n    173 you\n    168 ing\n    155 hat\n    112 tha\n    107 ent\n     95 her\n     94 his\n     90 ver\n     89 was\n     89 ith\n     87 ter\n     87 all\n     86 ere\n     84 oul\n     84 ion\n     83 wit\n     82 uld\n     79 ave\n     75 man\n     70 ome\n     70 for\n     68 thi\n     68 hav\n     64 our\n     59 not\n     57 ess\n     56 tio\n     56 hin\n     55 eve\n     54 nce\n     50 res\n     50 hou\n     48 ear\n     48 The\n     46 him\n     45 ell\n     44 rea\n     43 ove\n     42 out\n     42 men\n     42 You\n     41 had\n     41 are\n     40 ted\n     40 ive\n     40 int\n     40 ers\n     40 ati\n     39 whi\n     39 one\n     38 ous\n     37 und\n     37 ugh\n     37 ich\n     37 ght\n     37 can\n     36 ore\n     36 hic\n     35 who\n     35 som\n     35 rou\n     35 nge\n     35 ery\n     35 cou\n     35 ble\n     35 ate\n     34 han\n     34 but\n     34 aid\n     33 sta\n     33 red\n     33 ook\n     33 nte\n     32 ure\n     32 tur\n     32 sai\n     32 per\n     32 oug\n     32 est\n     32 ect\n     31 tte\n     30 wou\n     30 sho\n     30 pos\n     30 oun\n     30 ine\n     30 hal\n     30 ger\n     30 enc\n     30 con\n     29 ust\n     29 pro\n     29 ned\n     29 len\n     29 hea\n     29 cha\n     29 ard\n     28 ssi\n     28 own\n     28 nde\n     28 ind\n     28 ica\n     28 ead\n     28 ast\n     27 sor\n     27 see\n     27 pon\n     27 mor\n     27 ked\n     27 ake\n     27 ace\n     26 kin\n     26 hen\n     26 der\n     25 wor\n     25 upo\n     25 uch\n     25 sti\n     25 lle\n     25 lea\n     25 ist\n     25 ien\n     25 ide\n     25 fro\n     25 eri\n     24 wha\n     24 tin\n     24 tho\n     24 rie\n     24 ons\n     24 ely\n     24 com\n     24 ant\n     24 Pro\n     23 wer\n     23 ven\n     23 ste\n     23 ort\n     23 ope\n     23 nti\n     23 igh\n     23 den\n     23 ath\n     23 anc\n     22 rom\n     22 ost\n     22 nes\n     22 ish\n     22 een\n     21 tic\n     21 sio\n     21 rof\n     21 rat\n     21 ice\n     21 ful\n     21 eat\n     21 cal\n     21 abo\n     20 whe\n     20 ten\n     20 sso\n     20 sen\n     20 pre\n     20 ose\n     20 led\n     20 ill\n     20 ike\n     20 eng\n     20 end\n     20 eal\n     20 art\n     20 ack\n     20 abl\n     19 war\n     19 tan\n     19 ran\n     19 oth\n     19 now\n     19 nin\n     19 low\n     19 lik\n     19 ite\n     19 har\n     19 fes\n     19 ese\n     19 ame\n     19 air\n     19 ain\n     18 she\n     18 sel\n     18 ofe\n     18 nly\n     18 lly\n     18 lin\n     18 fac\n     18 ett\n     18 eas\n     18 dow\n     18 any\n     18 act\n     18 Wha\n     18 Wel\n     18 Cha\n     17 tle\n     17 tal\n     17 str\n     17 sir\n     17 ppe\n     17 ood\n     17 ont\n     17 oke\n     17 met\n     17 loo\n     17 iti\n     17 ins\n     17 fic\n     17 exp\n     17 elf\n     17 don\n     17 bou\n     17 app\n     16 way\n     16 use\n     16 sin\n     16 rit\n     16 rin\n     16 rel\n     16 pen\n     16 onl\n     16 lon\n     16 lit\n     16 lat\n     16 lad\n     16 ity\n     16 hai\n     16 eye\n     16 cri\n     16 bee\n     16 ass\n     16 age\n     16 ady\n     15 win\n     15 vie\n     15 ull\n     15 thr\n     15 suc\n     15 ord\n     15 ond\n     15 oin\n     15 off\n     15 nal\n     15 min\n     15 llo\n     15 ink\n     15 ime\n     15 ied\n     15 how\n     15 fte\n     15 eth\n     15 erv\n     15 ens\n     15 eem\n     15 eed\n     15 ces\n     15 att\n     15 ang\n     15 THE\n     15 But\n     14 tak\n     14 ple\n     14 ped\n     14 oss\n     14 nto\n     14 mos\n     14 mer\n     14 lov\n     14 lic\n     14 las\n     14 ire\n     14 goo\n     14 esi\n     14 ene\n     14 eme\n     14 dis\n     14 cie\n     14 atu\n     13 too\n     13 tel\n     13 son\n     13 sci\n     13 ron\n     13 pla\n     13 nev\n     13 mat\n     13 lis\n     13 iou\n     13 inc\n     13 iew\n     13 get\n     13 ero\n     13 dly\n     13 din\n     13 des\n     13 cul\n     13 ber\n     13 alo\n     13 alk\n     13 She\n     12 won\n     12 wom\n     12 urs\n     12 urn\n     12 tra\n     12 tly\n     12 sit\n     12 sha\n     12 rst\n     12 pec\n     12 orl\n     12 ong\n     12 olo\n     12 old\n     12 nst\n     12 nsi\n     12 nat\n     12 mus\n     12 may\n     12 lac\n     12 kno\n     12 ile\n     12 ibl\n     12 gre\n     12 fer\n     12 era\n     12 eli\n     12 ded\n     12 cte\n     12 ait\n     12 ade\n     11 yet\n     11 wil\n     11 uth\n     11 ute\n     11 ung\n     11 tif\n     11 sma\n     11 say\n     11 rth\n     11 rld\n     11 ree\n     11 rac\n     11 ppo\n     11 par\n     11 oma\n     11 oll\n     11 ole\n     11 mak\n     11 log\n     11 lie\n     11 imp\n     11 ign\n     11 hap\n     11 ffe\n     11 eet\n     11 bla\n     11 bel\n     11 bac\n     11 ark\n     11 ali\n     11 Tha\n     10 yes\n     10 wan\n     10 wai\n     10 ved\n     10 ttl\n     10 tim\n     10 sur\n     10 sub\n     10 spe\n     10 sib\n     10 rso\n     10 rse\n     10 ric\n     10 ren\n     10 poi\n     10 ori\n     10 ona\n     10 ogi\n     10 oes\n     10 nts\n     10 let\n     10 les\n     10 jec\n     10 ifi\n     10 hro\n     10 hes\n     10 has\n     10 giv\n     10 gen\n     10 fin\n     10 fel\n     10 eti\n     10 erf\n     10 ema\n     10 edi\n     10 ean\n     10 dle\n     10 did\n     10 dee\n     10 day\n     10 ctl\n     10 cke\n     10 bro\n     10 ays\n     10 ask\n     10 arg\n     10 ara\n     10 ans\n      9 upp\n      9 ult\n      9 tru\n      9 tre\n      9 tor\n      9 ton\n      9 tiv\n      9 tat\n      9 tac\n      9 sup\n      9 sto\n      9 siv\n      9 sid\n      9 ser\n      9 sed\n      9 rvi\n      9 rne\n      9 rep\n      9 ral\n      9 qui\n      9 pol\n      9 pea\n      9 pas\n      9 ote\n      9 osi\n      9 oor\n      9 oli\n      9 nve\n      9 ntu\n      9 nse\n      9 ner\n      9 mpo\n      9 med\n      9 lif\n      9 itt\n      9 iss\n      9 ini\n      9 hed\n      9 ert\n      9 ern\n      9 eni\n      9 ele\n      9 dys\n      9 dre\n      9 cti\n      9 cen\n      9 cat\n      9 bre\n      9 ann\n      9 ank\n      9 ail\n      9 aft\n      9 Thi\n      9 Gla\n      9 And\n      8 xpe\n      8 wen\n      8 usi\n      8 urt\n      8 ude\n      8 two\n      8 til\n      8 ssa\n      8 rti\n      8 row\n      8 rop\n      8 roo\n      8 rna\n      8 rly\n      8 ris\n      8 rfe\n      8 rem\n      8 rec\n      8 rai\n      8 ool\n      8 nor\n      8 ngs\n      8 ngl\n      8 ndo\n      8 mys\n      8 mig\n      8 mea\n      8 mar\n      8 mad\n      8 itu\n      8 its\n      8 ism\n      8 iol\n      8 hum\n      8 hey\n      8 gra\n      8 gin\n      8 fou\n      8 fir\n      8 ffi\n      8 fee\n      8 evi\n      8 erm\n      8 eno\n      8 eep\n      8 doo\n      8 dif\n      8 dan\n      8 cre\n      8 ced\n      8 bet\n      8 awa\n      8 ape\n      8 ani\n      8 adv\n      7 yth\n      7 yse\n      7 vio\n      7 vin\n      7 ves\n      7 vel\n      7 uti\n      7 unt\n      7 uit\n      7 uck\n      7 ubl\n      7 ubj\n      7 tro\n      7 tis\n      7 tar\n      7 tai\n      7 tab\n      7 sol\n      7 sis\n      7 shi\n      7 scr\n      7 rte\n      7 rov\n      7 rni\n      7 rds\n      7 rdl\n      7 pin\n      7 opo\n      7 oom\n      7 omp\n      7 ock\n      7 nou\n      7 ngt\n      7 ndl\n      7 ndi\n      7 muc\n      7 mpl\n      7 mon\n      7 mom\n      7 lar\n      7 jus\n      7 irs\n      7 ift\n      7 ife\n      7 iev\n      7 ies\n      7 hor\n      7 hop\n      7 hol\n      7 ged\n      7 elp\n      7 efo\n      7 eel\n      7 duc\n      7 doe\n      7 dit\n      7 del\n      7 dea\n      7 dde\n      7 dar\n      7 cle\n      7 cin\n      7 che\n      7 cau\n      7 bra\n      7 bli\n      7 bje\n      7 bef\n      7 bea\n      7 aut\n      7 arr\n      7 arn\n      7 aps\n      7 alt\n      7 Som\n      7 Mal\n      7 How\n      7 CHA\n      7 Ame\n      6 yon\n      6 vid\n      6 ura\n      6 ula\n      6 uff\n      6 try\n      6 tri\n      6 thy\n      6 tes\n      6 tee\n      6 swe\n      6 stu\n      6 ssm\n      6 spo\n      6 ske\n      6 sig\n      6 sea\n      6 sat\n      6 rus\n      6 run\n      6 rta\n      6 rot\n      6 rio\n      6 rge\n      6 rew\n      6 ref\n      6 por\n      6 pli\n      6 pap\n      6 owe\n      6 onv\n      6 ono\n      6 ntl\n      6 nta\n      6 nne\n      6 nit\n      6 new\n      6 nds\n      6 mou\n      6 mil\n      6 mes\n      6 mbe\n      6 mas\n      6 mal\n      6 lwa\n      6 los\n      6 lor\n      6 lia\n      6 lec\n      6 lai\n      6 ken\n      6 ize\n      6 ita\n      6 isc\n      6 ina\n      6 iff\n      6 icu\n      6 ick\n      6 iar\n      6 hre\n      6 hos\n      6 hel\n      6 gic\n      6 gai\n      6 fri\n      6 fra\n      6 fol\n      6 fec\n      6 ews\n      6 ete\n      6 env\n      6 ega\n      6 ecu\n      6 ece\n      6 cia\n      6 cem\n      6 bes\n      6 aze\n      6 aus\n      6 ase\n      6 alw\n      6 alm\n      6 aci\n      6 Sou\n      6 Now\n      6 Don\n      5 zed\n      5 xpr\n      5 wis\n      5 wel\n      5 vor\n      5 van\n      5 unc\n      5 tud\n      5 tir\n      5 tch\n      5 sse\n      5 spr\n      5 spi\n      5 smi\n      5 san\n      5 sag\n      5 rwa\n      5 rve\n      5 ros\n      5 rmi\n      5 rig\n      5 rfu\n      5 ret\n      5 raw\n      5 rab\n      5 put\n      5 oub\n      5 oti\n      5 ory\n      5 ors\n      5 odi\n      5 nyt\n      5 nsw\n      5 nna\n      5 nio\n      5 nfe\n      5 nee\n      5 ncl\n      5 nam\n      5 mpa\n      5 mem\n      5 mee\n      5 mag\n      5 lun\n      5 luc\n      5 lse\n      5 lki\n      5 liv\n      5 lip\n      5 lim\n      5 ley\n      5 lev\n      5 ler\n      5 ket\n      5 isi\n      5 ima\n      5 ili\n      5 ici\n      5 iat\n      5 ial\n      5 hon\n      5 gue\n      5 gth\n      5 glo\n      5 gli\n      5 gav\n      5 fif\n      5 fea\n      5 fav\n      5 fai\n      5 esc\n      5 enn\n      5 emb\n      5 ela\n      5 eit\n      5 eis\n      5 ein\n      5 eca\n      5 eau\n      5 eak\n      5 dia\n      5 dam\n      5 cur\n      5 cro\n      5 cop\n      5 col\n      5 clu\n      5 cio\n      5 cce\n      5 bus\n      5 boy\n      5 boo\n      5 bod\n      5 bly\n      5 bei\n      5 avo\n      5 avi\n      5 aug\n      5 arm\n      5 arl\n      5 ari\n      5 alf\n      5 aki\n      5 aga\n      5 add\n      5 acc\n      5 Zoo\n      5 Wei\n      5 WOR\n      5 Vie\n      5 Sir\n      5 RLD\n      5 Pre\n      5 PRO\n      5 ORL\n      5 HAP\n      5 Eng\n      5 Dea\n      5 Con\n      5 Aus\n      5 Any\n      5 ALL\n      4 yed\n      4 yea\n      4 xpl\n      4 wro\n      4 wri\n      4 why\n      4 wev\n      4 wee\n      4 wal\n      4 vit\n      4 vil\n      4 val\n      4 vag\n      4 ump\n      4 ume\n      4 umb\n      4 uma\n      4 udd\n      4 ual\n      4 twi\n      4 tut\n      4 tou\n      4 tog\n      4 tme\n      4 tit\n      4 tep\n      4 tem\n      4 sus\n      4 sud\n      4 sts\n      4 ssu\n      4 spa\n      4 sil\n      4 sev\n      4 set\n      4 sam\n      4 rwi\n      4 rup\n      4 rsi\n      4 roi\n      4 roc\n      4 roa\n      4 rms\n      4 riv\n      4 rim\n      4 rha\n      4 rch\n      4 rap\n      4 que\n      4 pte\n      4 pri\n      4 plo\n      4 pir\n      4 peo\n      4 ows\n      4 owi\n      4 oud\n      4 ouc\n      4 oto\n      4 orn\n      4 orm\n      4 ora\n      4 opy\n      4 opl\n      4 olu\n      4 oic\n      4 ody\n      4 oci\n      4 nyw\n      4 nvi\n      4 ntr\n      4 nth\n      4 nsc\n      4 nno\n      4 nis\n      4 net\n      4 nea\n      4 nct\n      4 nci\n      4 nch\n      4 nbe\n      4 mur\n      4 mod\n      4 mid\n      4 mbl\n      4 lut\n      4 lue\n      4 lth\n      4 lte\n      4 lou\n      4 lop\n      4 lmo\n      4 lli\n      4 leg\n      4 lay\n      4 lau\n      4 lan\n      4 kes\n      4 ipp\n      4 inn\n      4 inf\n      4 imi\n      4 ily\n      4 ibe\n      4 ian\n      4 hem\n      4 hei\n      4 gon\n      4 gla\n      4 fil\n      4 ext\n      4 erw\n      4 erh\n      4 erg\n      4 ept\n      4 epr\n      4 eop\n      4 ena\n      4 ems\n      4 els\n      4 elo\n      4 ebo\n      4 eav\n      4 dve\n      4 dva\n      4 dri\n      4 dou\n      4 doi\n      4 dne\n      4 dal\n      4 cra\n      4 cov\n      4 cli\n      4 ckl\n      4 cer\n      4 cee\n      4 bul\n      4 bot\n      4 big\n      4 beh\n      4 bec\n      4 bal\n      4 ash\n      4 ary\n      4 ars\n      4 arp\n      4 arc\n      4 aph\n      4 ane\n      4 amp\n      4 agu\n      4 adl\n      4 adi\n      4 acr\n      4 ach\n      4 abi\n      4 Wor\n      4 Why\n      4 TER\n      4 Per\n      4 PTE\n      4 OST\n      4 Los\n      4 III\n      4 His\n      4 Her\n      4 HAV\n      4 HAL\n      4 For\n      4 FOR\n      4 EST\n      4 ESS\n      4 Did\n      4 Boo\n      4 Ass\n      4 AVE\n      4 APT\n      3 zet\n      3 ywh\n      3 yst\n      3 voi\n      3 vis\n      3 utt\n      3 utl\n      3 uss\n      3 usp\n      3 ush\n      3 uns\n      3 una\n      3 umo\n      3 uli\n      3 uin\n      3 ues\n      3 udi\n      3 uar\n      3 twe\n      3 tua\n      3 top\n      3 tne\n      3 thu\n      3 teb\n      3 sui\n      3 sou\n      3 sms\n      3 sly\n      3 sla\n      3 sim\n      3 sia\n      3 sda\n      3 scu\n      3 sco\n      3 sca\n      3 saw\n      3 sau\n      3 rue\n      3 rto\n      3 rsu\n      3 rsa\n      3 rry\n      3 rre\n      3 rra\n      3 rol\n      3 roj\n      3 rod\n      3 rid\n      3 rib\n      3 rgu\n      3 rer\n      3 reg\n      3 rde\n      3 ray\n      3 ram\n      3 rag\n      3 qua\n      3 pul\n      3 pub\n      3 pra\n      3 ppr\n      3 pit\n      3 pat\n      3 pan\n      3 owl\n      3 owa\n      3 orw\n      3 orr\n      3 opi\n      3 onf\n      3 onc\n      3 omm\n      3 omi\n      3 oje\n      3 ois\n      3 oil\n      3 ogr\n      3 oge\n      3 odu\n      3 ode\n      3 odd\n      3 oce\n      3 oar\n      3 nyo\n      3 nut\n      3 ntm\n      3 nsl\n      3 nry\n      3 nob\n      3 nni\n      3 nmo\n      3 nke\n      3 nig\n      3 nic\n      3 ngu\n      3 nec\n      3 nda\n      3 nar\n      3 nan\n      3 nac\n      3 nab\n      3 mse\n      3 mpe\n      3 mme\n      3 mis\n      3 mic\n      3 map\n      3 mai\n      3 lve\n      3 lud\n      3 loc\n      3 lke\n      3 lig\n      3 lib\n      3 ldn\n      3 lde\n      3 lam\n      3 kle\n      3 kee\n      3 ito\n      3 ise\n      3 irl\n      3 ify\n      3 ifu\n      3 ier\n      3 idn\n      3 ida\n      3 ibb\n      3 hus\n      3 hur\n      3 hun\n      3 hts\n      3 hom\n      3 hit\n      3 hip\n      3 hfu\n      3 gri\n      3 got\n      3 goi\n      3 gno\n      3 gis\n      3 ghe\n      3 ges\n      3 gat\n      3 gar\n      3 gan\n      3 foo\n      3 fig\n      3 fie\n      3 fen\n      3 fat\n      3 far\n      3 fan\n      3 fad\n      3 exc\n      3 ewa\n      3 eta\n      3 esu\n      3 esp\n      3 esd\n      3 err\n      3 epe\n      3 epa\n      3 enr\n      3 enb\n      3 emp\n      3 emo\n      3 elt\n      3 eir\n      3 eig\n      3 efu\n      3 efl\n      3 efi\n      3 eff\n      3 eds\n      3 edn\n      3 edl\n      3 ede\n      3 ecr\n      3 eci\n      3 dra\n      3 det\n      3 dep\n      3 dem\n      3 ddr\n      3 ctu\n      3 cla\n      3 cki\n      3 cit\n      3 cho\n      3 chi\n      3 cei\n      3 car\n      3 cam\n      3 cAr\n      3 bri\n      3 bov\n      3 blu\n      3 bit\n      3 bed\n      3 bbe\n      3 aul\n      3 atc\n      3 aso\n      3 asn\n      3 asi\n      3 arw\n      3 apt\n      3 anl\n      3 als\n      3 aim\n      3 agi\n      3 afe\n      3 ada\n      3 Wit\n      3 Whe\n      3 Wed\n      3 Was\n      3 Wad\n      3 WAS\n      3 Tar\n      3 THI\n      3 SSI\n      3 REA\n      3 Par\n      3 One\n      3 ORE\n      3 Not\n      3 Ned\n      3 Nat\n      3 NGE\n      3 McA\n      3 Loo\n      3 LOS\n      3 LLE\n      3 LEN\n      3 Iri\n      3 Ins\n      3 ION\n      3 ING\n      3 Hen\n      3 Had\n      3 HER\n      3 Gaz\n      3 GER\n      3 Eve\n      3 Enm\n      3 ENG\n      3 Dar\n      3 Com\n      3 Bri\n      3 Blu\n      3 Ard\n      2 ype\n      2 ymp\n      2 yle\n      2 yin\n      2 yho\n      2 xtr\n      2 xpo\n      2 xce\n      2 xac\n      2 woo\n      2 wly\n      2 wic\n      2 vol\n      2 vey\n      2 uty\n      2 usl\n      2 usb\n      2 urm\n      2 upt\n      2 upe\n      2 unp\n      2 unn\n      2 une\n      2 uly\n      2 uls\n      2 ulo\n      2 uis\n      2 uid\n      2 ugg\n      2 uge\n      2 uci\n      2 uce\n      2 uca\n      2 ubt\n      2 uat\n      2 typ\n      2 tun\n      2 tuf\n      2 tti\n      2 tta\n      2 tom\n      2 tol\n      2 tmo\n      2 tli\n      2 thf\n      2 tfu\n      2 tea\n      2 taf\n      2 sum\n      2 sul\n      2 sug\n      2 suf\n      2 sua\n      2 stn\n      2 spl\n      2 sph\n      2 soc\n      2 sne\n      2 slo\n      2 sli\n      2 siz\n      2 shu\n      2 sfi\n      2 sex\n      2 sba\n      2 saf\n      2 ryt\n      2 rva\n      2 rum\n      2 rud\n      2 rts\n      2 rru\n      2 rri\n      2 rok\n      2 rmu\n      2 rmo\n      2 rme\n      2 rma\n      2 rip\n      2 rik\n      2 ria\n      2 rgs\n      2 reh\n      2 rcu\n      2 rav\n      2 ras\n      2 rad\n      2 pti\n      2 pru\n      2 pok\n      2 poc\n      2 plu\n      2 pic\n      2 phs\n      2 pho\n      2 phi\n      2 phe\n      2 pha\n      2 pee\n      2 pac\n      2 oyl\n      2 oye\n      2 ova\n      2 ott\n      2 ota\n      2 osp\n      2 oro\n      2 ork\n      2 org\n      2 orf\n      2 opp\n      2 oop\n      2 oon\n      2 oof\n      2 onz\n      2 onn\n      2 oni\n      2 ola\n      2 oks\n      2 ofo\n      2 oed\n      2 obo\n      2 nze\n      2 nyh\n      2 nty\n      2 nsu\n      2 nsp\n      2 nso\n      2 nqu\n      2 non\n      2 nod\n      2 nle\n      2 nki\n      2 nju\n      2 nim\n      2 nia\n      2 nfi\n      2 nex\n      2 nel\n      2 ndr\n      2 nco\n      2 mpi\n      2 mph\n      2 mot\n      2 mma\n      2 mit\n      2 meb\n      2 luf\n      2 lub\n      2 lot\n      2 lls\n      2 liz\n      2 lab\n      2 kul\n      2 kne\n      2 ker\n      2 kel\n      2 jum\n      2 jud\n      2 jou\n      2 jac\n      2 ivi\n      2 iso\n      2 isk\n      2 isf\n      2 iri\n      2 ira\n      2 ips\n      2 inj\n      2 ims\n      2 iet\n      2 idd\n      2 ict\n      2 icr\n      2 hug\n      2 hot\n      2 hok\n      2 hma\n      2 hio\n      2 het\n      2 hee\n      2 hau\n      2 ham\n      2 hak\n      2 hab\n      2 gut\n      2 gum\n      2 gui\n      2 gua\n      2 gto\n      2 goe\n      2 gns\n      2 gni\n      2 gne\n      2 gna\n      2 gma\n      2 gly\n      2 gle\n      2 gir\n      2 ghi\n      2 gge\n      2 gaz\n      2 gas\n      2 gal\n      2 fus\n      2 fur\n      2 flu\n      2 flo\n      2 fle\n      2 fla\n      2 fis\n      2 fid\n      2 few\n      2 fei\n      2 fas\n      2 fam\n      2 fal\n      2 fak\n      2 eyo\n      2 exa\n      2 eut\n      2 ets\n      2 eto\n      2 etc\n      2 esk\n      2 esh\n      2 erl\n      2 erc\n      2 epu\n      2 eps\n      2 epo\n      2 eou\n      2 eor\n      2 emy\n      2 elv\n      2 eiv\n      2 eho\n      2 ehi\n      2 ehe\n      2 eha\n      2 egr\n      2 ees\n      2 eer\n      2 eek\n      2 eec\n      2 edu\n      2 eag\n      2 eac\n      2 eBo\n      2 dor\n      2 die\n      2 dic\n      2 dge\n      2 def\n      2 dec\n      2 ddl\n      2 ddi\n      2 cus\n      2 cts\n      2 cto\n      2 cos\n      2 cor\n      2 coc\n      2 clo\n      2 cid\n      2 cep\n      2 cas\n      2 cad\n      2 bte\n      2 bso\n      2 bow\n      2 bor\n      2 bin\n      2 bey\n      2 ben\n      2 beg\n      2 bat\n      2 bar\n      2 ban\n      2 bad\n      2 aym\n      2 awl\n      2 aud\n      2 atm\n      2 ata\n      2 asp\n      2 asm\n      2 asa\n      2 ano\n      2 amo\n      2 ama\n      2 alu\n      2 ald\n      2 ala\n      2 agr\n      2 ago\n      2 aff\n      2 abs\n      2 Yes\n      2 XII\n      2 WON\n      2 WAR\n      2 VII\n      2 VER\n      2 UES\n      2 Tel\n      2 TLY\n      2 Sta\n      2 Soc\n      2 Sha\n      2 SSO\n      2 SOR\n      2 SIR\n      2 SIO\n      2 SEE\n      2 Res\n      2 ROF\n      2 ROC\n      2 RGE\n      2 RES\n      2 QUE\n      2 PPE\n      2 PER\n      2 OUR\n      2 ORG\n      2 OND\n      2 OFE\n      2 OCE\n      2 NDE\n      2 MOR\n      2 Lor\n      2 Lon\n      2 Lar\n      2 Ken\n      2 IGH\n      2 HIN\n      2 Gut\n      2 Got\n      2 Geo\n      2 GHT\n      2 Fre\n      2 FUL\n      2 FES\n      2 Exp\n      2 Evo\n      2 ERS\n      2 ERO\n      2 ERF\n      2 ERE\n      2 EEN\n      2 EDW\n      2 ECT\n      2 EBo\n      2 EAR\n      2 Doy\n      2 DWA\n      2 DER\n      2 Cam\n      2 CON\n      2 CES\n      2 Bur\n      2 Bes\n      2 Art\n      2 All\n      2 Aca\n      2 ART\n      2 ARD\n      2 APP\n      1 zoo\n      1 zio\n      1 zin\n      1 zem\n      1 ywa\n      1 yri\n      1 yme\n      1 yma\n      1 yis\n      1 yer\n      1 ybe\n      1 xua\n      1 xqu\n      1 xis\n      1 xio\n      1 xic\n      1 xed\n      1 xch\n      1 xal\n      1 www\n      1 wsp\n      1 wol\n      1 wli\n      1 wle\n      1 wir\n      1 wif\n      1 wid\n      1 wfu\n      1 wed\n      1 wea\n      1 wdl\n      1 wav\n      1 wat\n      1 wak\n      1 wab\n      1 viv\n      1 vic\n      1 vet\n      1 vem\n      1 veg\n      1 vat\n      1 vas\n      1 vac\n      1 uts\n      1 utc\n      1 uta\n      1 usu\n      1 usa\n      1 ury\n      1 urv\n      1 uri\n      1 urg\n      1 urd\n      1 upu\n      1 uou\n      1 uot\n      1 unr\n      1 uni\n      1 unb\n      1 umm\n      1 ulk\n      1 ulf\n      1 ule\n      1 uir\n      1 uic\n      1 ugi\n      1 uft\n      1 uer\n      1 uel\n      1 uee\n      1 ued\n      1 udy\n      1 udg\n      1 uda\n      1 uct\n      1 ucc\n      1 uas\n      1 uag\n      1 uab\n      1 tuo\n      1 tum\n      1 tue\n      1 tto\n      1 tso\n      1 tsm\n      1 tow\n      1 tot\n      1 tok\n      1 toe\n      1 tnu\n      1 tma\n      1 tig\n      1 tie\n      1 tid\n      1 tia\n      1 thw\n      1 thm\n      1 thd\n      1 tex\n      1 tev\n      1 teo\n      1 tef\n      1 tec\n      1 tba\n      1 tax\n      1 tas\n      1 tap\n      1 tag\n      1 syr\n      1 sym\n      1 swi\n      1 swa\n      1 sty\n      1 stm\n      1 sth\n      1 stf\n      1 ssy\n      1 ssn\n      1 ssl\n      1 spu\n      1 sop\n      1 soo\n      1 soe\n      1 sna\n      1 sku\n      1 sks\n      1 ski\n      1 shr\n      1 shn\n      1 sfy\n      1 seu\n      1 ses\n      1 sep\n      1 sem\n      1 sec\n      1 sce\n      1 saz\n      1 sav\n      1 sar\n      1 sap\n      1 sad\n      1 ryo\n      1 ryi\n      1 rwe\n      1 rut\n      1 rul\n      1 rui\n      1 rty\n      1 rtw\n      1 rtu\n      1 rtm\n      1 rtl\n      1 rsm\n      1 rsh\n      1 rro\n      1 rpo\n      1 rob\n      1 rlo\n      1 rks\n      1 riz\n      1 riu\n      1 rif\n      1 rgy\n      1 rgi\n      1 rgh\n      1 rei\n      1 rdn\n      1 rdi\n      1 rda\n      1 rco\n      1 rce\n      1 rbe\n      1 rau\n      1 rar\n      1 rao\n      1 quo\n      1 pus\n      1 pur\n      1 pun\n      1 ptu\n      1 pth\n      1 pse\n      1 ppl\n      1 ppi\n      1 pow\n      1 pou\n      1 pot\n      1 poo\n      1 ply\n      1 pio\n      1 pil\n      1 pie\n      1 pia\n      1 phy\n      1 pel\n      1 pay\n      1 pad\n      1 oys\n      1 oyi\n      1 owd\n      1 otc\n      1 otb\n      1 oso\n      1 osm\n      1 osc\n      1 osa\n      1 orc\n      1 oph\n      1 oot\n      1 ooe\n      1 ony\n      1 onq\n      1 omr\n      1 omn\n      1 olt\n      1 olk\n      1 oit\n      1 ogy\n      1 ogm\n      1 ogg\n      1 oft\n      1 ofi\n      1 oev\n      1 ods\n      1 oco\n      1 occ\n      1 obl\n      1 oba\n      1 oal\n      1 oaf\n      1 oad\n      1 nxi\n      1 num\n      1 nui\n      1 nsh\n      1 nsf\n      1 nre\n      1 npr\n      1 npl\n      1 noy\n      1 nom\n      1 nog\n      1 nli\n      1 nkl\n      1 niv\n      1 niu\n      1 nip\n      1 nif\n      1 nhe\n      1 ngr\n      1 ngi\n      1 ney\n      1 neo\n      1 nen\n      1 neg\n      1 ndw\n      1 ndu\n      1 ncy\n      1 ncr\n      1 nbu\n      1 naw\n      1 nau\n      1 nap\n      1 nak\n      1 nai\n      1 mul\n      1 mra\n      1 mpt\n      1 mpr\n      1 mov\n      1 mni\n      1 mne\n      1 mly\n      1 mir\n      1 mew\n      1 mel\n      1 meh\n      1 meg\n      1 mbi\n      1 maz\n      1 maj\n      1 lym\n      1 lyi\n      1 lus\n      1 lum\n      1 lua\n      1 lty\n      1 lts\n      1 lta\n      1 lso\n      1 lpi\n      1 lph\n      1 lpe\n      1 loy\n      1 lom\n      1 loi\n      1 loa\n      1 lnu\n      1 lmu\n      1 llu\n      1 lla\n      1 lka\n      1 liq\n      1 lge\n      1 lfi\n      1 lew\n      1 lem\n      1 lef\n      1 ldi\n      1 law\n      1 lap\n      1 lae\n      1 kso\n      1 kly\n      1 kli\n      1 kis\n      1 kat\n      1 kan\n      1 jur\n      1 jun\n      1 joy\n      1 job\n      1 jes\n      1 ixe\n      1 iwo\n      1 iva\n      1 ius\n      1 ium\n      1 itl\n      1 isp\n      1 isn\n      1 isa\n      1 irr\n      1 irm\n      1 irk\n      1 irc\n      1 iqu\n      1 ipo\n      1 ior\n      1 iog\n      1 inv\n      1 inu\n      1 inq\n      1 inl\n      1 inh\n      1 inb\n      1 imu\n      1 imo\n      1 imm\n      1 iml\n      1 imb\n      1 ilv\n      1 ils\n      1 ilo\n      1 iki\n      1 igu\n      1 igm\n      1 igi\n      1 ige\n      1 iga\n      1 ieu\n      1 iel\n      1 ief\n      1 idy\n      1 idi\n      1 ico\n      1 icl\n      1 ias\n      1 iam\n      1 iag\n      1 iac\n      1 iab\n      1 hwo\n      1 hwa\n      1 hut\n      1 hul\n      1 htf\n      1 hte\n      1 hri\n      1 hov\n      1 hog\n      1 hod\n      1 hne\n      1 hly\n      1 hir\n      1 hig\n      1 hie\n      1 heo\n      1 hec\n      1 hdr\n      1 gur\n      1 gul\n      1 gru\n      1 giz\n      1 git\n      1 gib\n      1 ghl\n      1 ggy\n      1 ggr\n      1 gap\n      1 gam\n      1 fug\n      1 fty\n      1 fts\n      1 fth\n      1 fre\n      1 fog\n      1 fly\n      1 fix\n      1 ffy\n      1 ffo\n      1 fev\n      1 feu\n      1 ezi\n      1 eys\n      1 exu\n      1 exq\n      1 exi\n      1 ewo\n      1 ewh\n      1 eva\n      1 eur\n      1 eum\n      1 ety\n      1 etw\n      1 etr\n      1 etn\n      1 erp\n      1 erk\n      1 erd\n      1 epp\n      1 epl\n      1 epi\n      1 eos\n      1 eon\n      1 enu\n      1 enl\n      1 emi\n      1 elg\n      1 eld\n      1 egs\n      1 ego\n      1 egl\n      1 egi\n      1 egg\n      1 ege\n      1 eft\n      1 efr\n      1 eez\n      1 eeb\n      1 eea\n      1 edg\n      1 eda\n      1 eco\n      1 eck\n      1 ech\n      1 ebt\n      1 ebr\n      1 ebl\n      1 eab\n      1 dwr\n      1 dwa\n      1 dut\n      1 dur\n      1 dul\n      1 dth\n      1 dsh\n      1 dry\n      1 dog\n      1 dmi\n      1 dli\n      1 diw\n      1 dir\n      1 dio\n      1 dim\n      1 dig\n      1 dib\n      1 dex\n      1 dev\n      1 dei\n      1 deg\n      1 deb\n      1 dat\n      1 dap\n      1 dac\n      1 dab\n      1 cut\n      1 cun\n      1 cue\n      1 ctr\n      1 ctn\n      1 cta\n      1 cry\n      1 cru\n      1 cot\n      1 coo\n      1 coe\n      1 cod\n      1 coa\n      1 cky\n      1 cka\n      1 cis\n      1 cir\n      1 chy\n      1 chw\n      1 chm\n      1 chf\n      1 cel\n      1 cco\n      1 cca\n      1 cab\n      1 bye\n      1 bur\n      1 buc\n      1 bts\n      1 bse\n      1 bru\n      1 bos\n      1 bom\n      1 bol\n      1 blo\n      1 bio\n      1 bim\n      1 bil\n      1 bbl\n      1 bag\n      1 bab\n      1 azi\n      1 aye\n      1 ayb\n      1 axi\n      1 awn\n      1 awi\n      1 awf\n      1 awe\n      1 ava\n      1 aum\n      1 auf\n      1 aty\n      1 ats\n      1 ato\n      1 asy\n      1 asu\n      1 asc\n      1 aro\n      1 arf\n      1 arb\n      1 apo\n      1 apa\n      1 aor\n      1 anx\n      1 ana\n      1 ams\n      1 amn\n      1 ami\n      1 amb\n      1 aln\n      1 ale\n      1 aks\n      1 aje\n      1 ais\n      1 aic\n      1 ags\n      1 agn\n      1 agg\n      1 afr\n      1 aer\n      1 aeo\n      1 adt\n      1 adn\n      1 adm\n      1 acy\n      1 acs\n      1 acl\n      1 abu\n      1 abb\n      1 YRI\n      1 YOU\n      1 YLE\n      1 YIN\n      1 YES\n      1 XVI\n      1 XIV\n      1 Wou\n      1 Win\n      1 Wig\n      1 Wes\n      1 Wen\n      1 Wal\n      1 Wai\n      1 WIT\n      1 WIL\n      1 WHO\n      1 WER\n      1 Ver\n      1 Upr\n      1 Upo\n      1 Uni\n      1 Und\n      1 UTL\n      1 UTE\n      1 UST\n      1 UNK\n      1 UND\n      1 ULD\n      1 UCK\n      1 Tut\n      1 Try\n      1 Tit\n      1 Tim\n      1 Tic\n      1 Thr\n      1 Ter\n      1 Tal\n      1 TRY\n      1 TML\n      1 TIO\n      1 THU\n      1 THO\n      1 TEN\n      1 TAR\n      1 Swo\n      1 Sup\n      1 Suc\n      1 Ste\n      1 Spi\n      1 Sku\n      1 Sev\n      1 Ser\n      1 Sec\n      1 Sco\n      1 Sci\n      1 Sav\n      1 Sat\n      1 STS\n      1 STI\n      1 STA\n      1 SON\n      1 SMS\n      1 SIG\n      1 SIB\n      1 SHA\n      1 SCI\n      1 SAP\n      1 Rus\n      1 Rou\n      1 Rig\n      1 Ric\n      1 Reu\n      1 Rem\n      1 Rel\n      1 Rec\n      1 RTH\n      1 RSO\n      1 RRO\n      1 ROW\n      1 ROU\n      1 ROJ\n      1 ROI\n      1 RIG\n      1 RFU\n      1 RFE\n      1 Put\n      1 Pub\n      1 Pra\n      1 Pla\n      1 Pal\n      1 PYR\n      1 POS\n      1 PIC\n      1 PEN\n      1 PEA\n      1 PAR\n      1 Out\n      1 Onc\n      1 Oly\n      1 Obs\n      1 OYL\n      1 OWN\n      1 OUT\n      1 OUN\n      1 OUL\n      1 OSS\n      1 OSE\n      1 ORR\n      1 ORD\n      1 OPY\n      1 OOK\n      1 ONQ\n      1 ONE\n      1 ONC\n      1 ONA\n      1 OJE\n      1 OIS\n      1 Nov\n      1 NTO\n      1 NQU\n      1 NOW\n      1 NMO\n      1 NKN\n      1 NIT\n      1 NGS\n      1 NEW\n      1 NEV\n      1 NED\n      1 NCE\n      1 NBE\n      1 NAN\n      1 Mus\n      1 Mun\n      1 Mov\n      1 Mos\n      1 Mem\n      1 Med\n      1 May\n      1 Mas\n      1 Mac\n      1 MPO\n      1 MOS\n      1 MAL\n      1 MAK\n      1 Luc\n      1 Liv\n      1 Lic\n      1 Lia\n      1 Lan\n      1 Lad\n      1 LYI\n      1 LUC\n      1 LOR\n      1 LON\n      1 LAI\n      1 Kno\n      1 Kee\n      1 Kal\n      1 KNO\n      1 KET\n      1 Jus\n      1 Jun\n      1 Jud\n      1 JUS\n      1 JEC\n      1 Ind\n      1 Imp\n      1 ITH\n      1 ITE\n      1 ISM\n      1 ISA\n      1 INT\n      1 INI\n      1 IMP\n      1 ILL\n      1 IGG\n      1 ICK\n      1 IBL\n      1 Hun\n      1 Hav\n      1 Has\n      1 Hal\n      1 Hai\n      1 HUR\n      1 HTM\n      1 HOS\n      1 HIS\n      1 Gul\n      1 Goo\n      1 Giv\n      1 Gib\n      1 Get\n      1 Gen\n      1 GUT\n      1 GRE\n      1 GGE\n      1 GET\n      1 GES\n      1 GEO\n      1 Fol\n      1 Fat\n      1 FLA\n      1 FIN\n      1 FEC\n      1 Exa\n      1 Ent\n      1 Emp\n      1 Edw\n      1 Edu\n      1 Edi\n      1 EYE\n      1 EVE\n      1 ETS\n      1 ESE\n      1 ERY\n      1 ERG\n      1 EOR\n      1 ENM\n      1 ENE\n      1 ENB\n      1 EFI\n      1 EBO\n      1 EAT\n      1 EAL\n      1 EAD\n      1 Dep\n      1 Dat\n      1 Dai\n      1 DRE\n      1 DOY\n      1 DIS\n      1 DFU\n      1 DEF\n      1 DEA\n      1 Cre\n      1 Cra\n      1 Clu\n      1 Cli\n      1 Chi\n      1 Che\n      1 Cat\n      1 Can\n      1 Cab\n      1 CTL\n      1 COU\n      1 COP\n      1 CKE\n      1 CII\n      1 Bos\n      1 Bor\n      1 Bel\n      1 Beh\n      1 Beg\n      1 Bea\n      1 Bal\n      1 BOO\n      1 BLE\n      1 BIG\n      1 BER\n      1 Aut\n      1 Are\n      1 Ant\n      1 Alp\n      1 Aft\n      1 Ade\n      1 Add\n      1 Act\n      1 ASC\n      1 ARK\n      1 ARE\n      1 ALO\n      1 AKE\n      1 AIL\n      1 ADF\n"
  },
  {
    "path": "core-tools/tests-regression/text-properties/out.ok/words.txt",
    "content": "    275 the\n    258 I\n    175 a\n    166 to\n    156 of\n    146 and\n    127 you\n    113 it\n     99 that\n     99 in\n     87 was\n     75 with\n     74 he\n     70 my\n     64 me\n     64 his\n     64 have\n     52 is\n     48 for\n     48 at\n     43 him\n     41 s\n     40 man\n     40 had\n     39 You\n     38 not\n     37 t\n     36 which\n     35 be\n     35 as\n     34 your\n     34 It\n     31 said\n     31 but\n     30 an\n     30 all\n     30 He\n     29 The\n     28 would\n     28 who\n     27 do\n     27 could\n     27 can\n     26 so\n     25 upon\n     25 or\n     25 are\n     22 on\n     21 what\n     21 very\n     21 this\n     20 some\n     20 should\n     20 from\n     18 up\n     18 if\n     18 by\n     18 What\n     18 Well\n     18 Professor\n     17 there\n     17 more\n     17 down\n     16 were\n     16 like\n     16 face\n     16 been\n     15 out\n     15 only\n     15 about\n     15 Challenger\n     15 But\n     14 such\n     14 sir\n     14 her\n     14 good\n     14 am\n     14 THE\n     13 we\n     13 she\n     13 never\n     13 ll\n     13 into\n     13 She\n     12 take\n     12 no\n     12 must\n     12 love\n     12 There\n     11 yet\n     11 when\n     11 than\n     11 over\n     11 may\n     11 know\n     11 come\n     11 chair\n     11 That\n     10 will\n     10 say\n     10 round\n     10 looked\n     10 has\n     10 get\n     10 don\n     10 If\n      9 ve\n      9 us\n      9 something\n      9 see\n      9 one\n      9 m\n      9 last\n      9 head\n      9 Gladys\n      9 And\n      8 two\n      8 really\n      8 rather\n      8 nothing\n      8 most\n      8 might\n      8 little\n      8 interview\n      8 give\n      8 eyes\n      8 door\n      8 any\n      8 after\n      8 Mr\n      8 A\n      7 world\n      7 word\n      7 woman\n      7 want\n      7 time\n      7 through\n      7 think\n      7 they\n      7 tell\n      7 subject\n      7 seem\n      7 room\n      7 own\n      7 off\n      7 myself\n      7 moment\n      7 make\n      7 letter\n      7 does\n      7 did\n      7 cried\n      7 better\n      7 before\n      7 back\n      7 We\n      7 This\n      7 Malone\n      6 young\n      6 went\n      6 way\n      6 wait\n      6 try\n      6 took\n      6 thought\n      6 sort\n      6 shall\n      6 scientific\n      6 policeman\n      6 our\n      6 old\n      6 now\n      6 much\n      6 men\n      6 life\n      6 how\n      6 here\n      6 hand\n      6 great\n      6 full\n      6 first\n      6 eye\n      6 ever\n      6 always\n      6 Now\n      6 My\n      6 How\n      6 Don\n      6 Do\n      5 won\n      5 then\n      5 talk\n      5 suppose\n      5 read\n      5 re\n      5 quite\n      5 place\n      5 person\n      5 perfectly\n      5 mind\n      5 mean\n      5 matter\n      5 made\n      5 least\n      5 kind\n      5 just\n      5 hour\n      5 hope\n      5 help\n      5 gave\n      5 fellow\n      5 every\n      5 enough\n      5 done\n      5 dangerous\n      5 call\n      5 black\n      5 believe\n      5 being\n      5 asked\n      5 Zoological\n      5 WORLD\n      5 Vienna\n      5 Then\n      5 South\n      5 Sir\n      5 Oh\n      5 No\n      5 English\n      5 Austin\n      4 women\n      4 within\n      4 why\n      4 well\n      4 violent\n      4 use\n      4 understand\n      4 under\n      4 too\n      4 three\n      4 thing\n      4 these\n      4 sure\n      4 still\n      4 short\n      4 seemed\n      4 same\n      4 red\n      4 put\n      4 people\n      4 paper\n      4 opening\n      4 office\n      4 look\n      4 long\n      4 lady\n      4 kindly\n      4 its\n      4 infernal\n      4 impossible\n      4 heart\n      4 hardly\n      4 hard\n      4 half\n      4 go\n      4 found\n      4 find\n      4 favor\n      4 evening\n      4 envelope\n      4 entirely\n      4 doing\n      4 day\n      4 course\n      4 copy\n      4 business\n      4 boy\n      4 big\n      4 because\n      4 ask\n      4 answer\n      4 almost\n      4 World\n      4 Why\n      4 Weissmann\n      4 To\n      4 Some\n      4 Lost\n      4 His\n      4 HAVE\n      4 E\n      4 Dear\n      4 CHAPTER\n      4 As\n      4 America\n      3 yourself\n      3 wrong\n      3 wonderful\n      3 wonder\n      3 whole\n      3 where\n      3 voice\n      3 vitality\n      3 views\n      3 until\n      3 turn\n      3 true\n      3 touch\n      3 thoughts\n      3 though\n      3 those\n      3 things\n      3 them\n      3 their\n      3 table\n      3 sudden\n      3 sub\n      3 strange\n      3 statement\n      3 stand\n      3 smile\n      3 set\n      3 sentence\n      3 self\n      3 seems\n      3 science\n      3 saw\n      3 sat\n      3 run\n      3 real\n      3 propose\n      3 point\n      3 please\n      3 personal\n      3 perhaps\n      3 passage\n      3 opened\n      3 open\n      3 offensive\n      3 night\n      3 name\n      3 met\n      3 merely\n      3 meeting\n      3 master\n      3 luck\n      3 liar\n      3 keep\n      3 insisted\n      3 idea\n      3 human\n      3 however\n      3 house\n      3 honor\n      3 heard\n      3 hear\n      3 hands\n      3 hair\n      3 got\n      3 gone\n      3 glad\n      3 general\n      3 gathered\n      3 front\n      3 frank\n      3 forward\n      3 follow\n      3 fifteen\n      3 felt\n      3 feel\n      3 fear\n      3 far\n      3 expression\n      3 evidence\n      3 entered\n      3 end\n      3 else\n      3 dark\n      3 dare\n      3 d\n      3 critical\n      3 comes\n      3 claim\n      3 character\n      3 chances\n      3 chance\n      3 came\n      3 bull\n      3 brain\n      3 both\n      3 blue\n      3 best\n      3 beautiful\n      3 away\n      3 aware\n      3 appointment\n      3 appearance\n      3 anywhere\n      3 anything\n      3 anyone\n      3 age\n      3 against\n      3 adventures\n      3 across\n      3 above\n      3 With\n      3 Wednesday\n      3 Wadley\n      3 WAS\n      3 Tarp\n      3 So\n      3 President\n      3 Park\n      3 One\n      3 OF\n      3 Ned\n      3 McArdle\n      3 Look\n      3 LOST\n      3 Irish\n      3 Institute\n      3 IT\n      3 Henry\n      3 Had\n      3 Gazette\n      3 G\n      3 Even\n      3 Enmore\n      3 Did\n      3 CHALLENGER\n      3 British\n      3 Blundell\n      3 American\n      2 yes\n      2 years\n      2 year\n      2 write\n      2 wouldn\n      2 worthy\n      2 words\n      2 without\n      2 wish\n      2 wind\n      2 whose\n      2 whom\n      2 white\n      2 week\n      2 wasn\n      2 walked\n      2 violence\n      2 view\n      2 version\n      2 ventured\n      2 vague\n      2 type\n      2 twenty\n      2 turning\n      2 turned\n      2 trouble\n      2 translation\n      2 together\n      2 thrown\n      2 thin\n      2 terms\n      2 talking\n      2 taken\n      2 suit\n      2 student\n      2 strongly\n      2 street\n      2 story\n      2 stopped\n      2 steps\n      2 station\n      2 staff\n      2 sprung\n      2 spoke\n      2 spaces\n      2 soul\n      2 somebody\n      2 small\n      2 slowly\n      2 size\n      2 sit\n      2 since\n      2 simple\n      2 silly\n      2 show\n      2 shoulders\n      2 severely\n      2 send\n      2 seen\n      2 seated\n      2 scandal\n      2 row\n      2 romance\n      2 risk\n      2 right\n      2 result\n      2 rested\n      2 reporters\n      2 remember\n      2 remark\n      2 regard\n      2 received\n      2 realized\n      2 ready\n      2 reading\n      2 public\n      2 prove\n      2 proud\n      2 profound\n      2 proceedings\n      2 presents\n      2 present\n      2 presence\n      2 possible\n      2 position\n      2 plunged\n      2 play\n      2 pity\n      2 pink\n      2 photographs\n      2 peculiar\n      2 past\n      2 passion\n      2 particular\n      2 part\n      2 ought\n      2 other\n      2 opinion\n      2 oh\n      2 notebook\n      2 nodded\n      2 nobody\n      2 news\n      2 need\n      2 nearly\n      2 nature\n      2 natural\n      2 narrative\n      2 murmured\n      2 motive\n      2 morning\n      2 month\n      2 modify\n      2 modern\n      2 mine\n      2 middle\n      2 message\n      2 menacing\n      2 memory\n      2 meesion\n      2 marry\n      2 map\n      2 making\n      2 makes\n      2 madam\n      2 lost\n      2 longer\n      2 lived\n      2 lips\n      2 liked\n      2 lie\n      2 let\n      2 less\n      2 length\n      2 led\n      2 leaned\n      2 laughing\n      2 laughed\n      2 later\n      2 knew\n      2 jacket\n      2 isolated\n      2 interest\n      2 insufferable\n      2 indeed\n      2 inclined\n      2 imposing\n      2 ideal\n      2 husband\n      2 hundred\n      2 huge\n      2 hold\n      2 himself\n      2 heroisms\n      2 heavily\n      2 hall\n      2 going\n      2 goes\n      2 girl\n      2 friends\n      2 forth\n      2 forehead\n      2 fire\n      2 fingers\n      2 filled\n      2 fight\n      2 few\n      2 feet\n      2 feeling\n      2 father\n      2 fashion\n      2 famous\n      2 failed\n      2 faddist\n      2 explosion\n      2 evident\n      2 everything\n      2 etc\n      2 envied\n      2 enormous\n      2 eleven\n      2 either\n      2 education\n      2 editor\n      2 each\n      2 eBook\n      2 driving\n      2 drew\n      2 distrust\n      2 difficult\n      2 different\n      2 didn\n      2 determination\n      2 desk\n      2 desire\n      2 definite\n      2 deeds\n      2 deed\n      2 dear\n      2 days\n      2 covered\n      2 control\n      2 consent\n      2 conscious\n      2 connection\n      2 confidence\n      2 compliments\n      2 clear\n      2 chest\n      2 chapter\n      2 care\n      2 cantankerous\n      2 cannot\n      2 called\n      2 brown\n      2 broke\n      2 break\n      2 book\n      2 blank\n      2 blame\n      2 beyond\n      2 behind\n      2 beard\n      2 bald\n      2 bad\n      2 bacteriologist\n      2 atmosphere\n      2 assure\n      2 arms\n      2 argument\n      2 appeal\n      2 another\n      2 aloud\n      2 alone\n      2 ago\n      2 again\n      2 advance\n      2 address\n      2 absolutely\n      2 Your\n      2 Yes\n      2 When\n      2 Was\n      2 W\n      2 Think\n      2 Shall\n      2 SIR\n      2 Project\n      2 PROFESSOR\n      2 PROCESSION\n      2 Of\n      2 Not\n      2 Nature\n      2 Lord\n      2 London\n      2 Largs\n      2 Kensington\n      2 In\n      2 IN\n      2 III\n      2 II\n      2 Gutenberg\n      2 Got\n      2 George\n      2 Evolution\n      2 EDWARD\n      2 EBook\n      2 Doyle\n      2 Darwin\n      2 D\n      2 Conan\n      2 Come\n      2 C\n      2 By\n      2 Besides\n      2 At\n      2 Assistant\n      2 Arthur\n      2 Anything\n      2 Anyhow\n      2 All\n      2 Ah\n      2 Academy\n      1 zoologist\n      1 youthful\n      1 youth\n      1 yours\n      1 www\n      1 wrought\n      1 written\n      1 worth\n      1 worst\n      1 worship\n      1 work\n      1 wore\n      1 wooden\n      1 wondering\n      1 womanly\n      1 wits\n      1 withdrawn\n      1 wistful\n      1 wisp\n      1 wire\n      1 windows\n      1 wincing\n      1 wife\n      1 wide\n      1 wicked\n      1 whim\n      1 whether\n      1 wheezing\n      1 wheel\n      1 whatsoever\n      1 whatever\n      1 wealth\n      1 waving\n      1 watchful\n      1 warning\n      1 warned\n      1 warm\n      1 wants\n      1 wanted\n      1 walnut\n      1 wall\n      1 wakens\n      1 waiting\n      1 waited\n      1 wail\n      1 vivacious\n      1 visits\n      1 visitors\n      1 visit\n      1 vile\n      1 victory\n      1 versus\n      1 vermin\n      1 ventures\n      1 venture\n      1 velvet\n      1 vegetarian\n      1 value\n      1 valuable\n      1 vaguely\n      1 usually\n      1 upturned\n      1 untidy\n      1 unshrinking\n      1 unsexual\n      1 unscrupulous\n      1 unreservedly\n      1 unprintable\n      1 unpleasant\n      1 unit\n      1 uneasy\n      1 undoubtedly\n      1 understanding\n      1 underlying\n      1 uncertain\n      1 unbend\n      1 unawares\n      1 unable\n      1 twinkled\n      1 twilight\n      1 twice\n      1 tut\n      1 tufts\n      1 trust\n      1 truly\n      1 trotted\n      1 triumphantly\n      1 tried\n      1 trend\n      1 tremendous\n      1 treason\n      1 translate\n      1 transfixed\n      1 tram\n      1 towards\n      1 touchy\n      1 top\n      1 tome\n      1 told\n      1 token\n      1 toes\n      1 timidity\n      1 till\n      1 tickling\n      1 tickled\n      1 thousand\n      1 thoughtfully\n      1 thoroughly\n      1 thinking\n      1 thesis\n      1 theosophist\n      1 themselves\n      1 thanked\n      1 terrible\n      1 tension\n      1 tended\n      1 ten\n      1 telegony\n      1 teetotal\n      1 taxicab\n      1 tap\n      1 tall\n      1 talked\n      1 tactlessness\n      1 tactless\n      1 tact\n      1 taciturn\n      1 sympathy\n      1 swine\n      1 sweetness\n      1 swarthy\n      1 suspicion\n      1 suspense\n      1 suspect\n      1 surely\n      1 suppressed\n      1 supposeetion\n      1 support\n      1 superman\n      1 summary\n      1 suggestions\n      1 suggestion\n      1 suddenly\n      1 succession\n      1 stunted\n      1 stuff\n      1 study\n      1 students\n      1 striking\n      1 strikes\n      1 strengthens\n      1 strengthen\n      1 strength\n      1 stooping\n      1 stoop\n      1 stone\n      1 stigmata\n      1 sterner\n      1 stepped\n      1 steely\n      1 stealthy\n      1 statue\n      1 state\n      1 startled\n      1 starting\n      1 started\n      1 staring\n      1 stare\n      1 standards\n      1 stairs\n      1 spun\n      1 springing\n      1 spread\n      1 sprang\n      1 sportsman\n      1 spoiled\n      1 spoil\n      1 split\n      1 splendid\n      1 spite\n      1 spirit\n      1 speech\n      1 speculations\n      1 speculation\n      1 spectacles\n      1 special\n      1 speak\n      1 spade\n      1 sound\n      1 sorry\n      1 sorely\n      1 soon\n      1 somewhat\n      1 somersault\n      1 solitary\n      1 soldier\n      1 sneer\n      1 snapped\n      1 smiling\n      1 smiled\n      1 smaller\n      1 slipped\n      1 slip\n      1 skull\n      1 skin\n      1 skeleton\n      1 situation\n      1 sinned\n      1 sinister\n      1 single\n      1 simultaneously\n      1 silver\n      1 silence\n      1 signs\n      1 signals\n      1 signal\n      1 sight\n      1 side\n      1 shut\n      1 shunned\n      1 shouldn\n      1 shoulder\n      1 shield\n      1 sharp\n      1 shaped\n      1 shape\n      1 shaking\n      1 shaken\n      1 sex\n      1 severe\n      1 several\n      1 settled\n      1 serve\n      1 servant\n      1 seriously\n      1 serious\n      1 series\n      1 separate\n      1 sent\n      1 sense\n      1 selfishness\n      1 seempathy\n      1 secret\n      1 seat\n      1 searching\n      1 scribblers\n      1 scrawled\n      1 says\n      1 save\n      1 satisfy\n      1 satisfied\n      1 sanely\n      1 sanctum\n      1 safely\n      1 safe\n      1 sadly\n      1 rushed\n      1 rush\n      1 rupee\n      1 rumbling\n      1 rumbled\n      1 ruined\n      1 rudeness\n      1 rough\n      1 rotating\n      1 rolled\n      1 roaring\n      1 roared\n      1 river\n      1 rippling\n      1 ring\n      1 righteous\n      1 rideeculous\n      1 rewards\n      1 reward\n      1 retracted\n      1 resumed\n      1 restrictions\n      1 restraint\n      1 respect\n      1 reserve\n      1 research\n      1 rescued\n      1 repulsed\n      1 repulse\n      1 reproved\n      1 reproof\n      1 representative\n      1 reply\n      1 remind\n      1 remain\n      1 relented\n      1 relations\n      1 refused\n      1 refuse\n      1 refresh\n      1 reflects\n      1 reflected\n      1 recriminations\n      1 record\n      1 recently\n      1 reasonable\n      1 reader\n      1 raven\n      1 rational\n      1 rascals\n      1 rarefied\n      1 rank\n      1 railings\n      1 railing\n      1 rage\n      1 radiated\n      1 race\n      1 quote\n      1 quickly\n      1 questions\n      1 quest\n      1 queer\n      1 quarter\n      1 quarrelsome\n      1 quality\n      1 putting\n      1 pushed\n      1 pursuing\n      1 publication\n      1 proves\n      1 proved\n      1 protest\n      1 prosaic\n      1 proposition\n      1 proposed\n      1 proportion\n      1 proper\n      1 projecting\n      1 profile\n      1 producing\n      1 produced\n      1 probable\n      1 primitive\n      1 pride\n      1 pressed\n      1 presentiment\n      1 prepared\n      1 precaution\n      1 praise\n      1 practise\n      1 pound\n      1 postmark\n      1 possibly\n      1 possessed\n      1 porticoed\n      1 poor\n      1 police\n      1 points\n      1 pointing\n      1 pockets\n      1 pocketed\n      1 pleasure\n      1 pleasant\n      1 pleaded\n      1 played\n      1 plastered\n      1 plasm\n      1 plan\n      1 plain\n      1 pilot\n      1 pick\n      1 persuasive\n      1 personality\n      1 permission\n      1 peculiarly\n      1 payment\n      1 pathetically\n      1 passing\n      1 pass\n      1 parts\n      1 parthenogenetic\n      1 papers\n      1 panted\n      1 oyster\n      1 overpowering\n      1 oval\n      1 outlined\n      1 otherwise\n      1 others\n      1 original\n      1 oriental\n      1 order\n      1 online\n      1 oneself\n      1 once\n      1 omnipotent\n      1 oily\n      1 often\n      1 official\n      1 odious\n      1 odd\n      1 occasion\n      1 o\n      1 numerous\n      1 notorious\n      1 notions\n      1 noticed\n      1 notice\n      1 notes\n      1 note\n      1 nonsense\n      1 none\n      1 noble\n      1 nine\n      1 nicer\n      1 next\n      1 newspaper\n      1 new\n      1 net\n      1 neglected\n      1 needs\n      1 needed\n      1 necessary\n      1 nearer\n      1 natured\n      1 namely\n      1 named\n      1 naked\n      1 nails\n      1 mystic\n      1 move\n      1 mouth\n      1 moustache\n      1 morrow\n      1 monotonous\n      1 money\n      1 mission\n      1 minutes\n      1 miles\n      1 microscope\n      1 microcosm\n      1 methods\n      1 mere\n      1 mentioned\n      1 mend\n      1 menaces\n      1 megalomaniac\n      1 meaty\n      1 meant\n      1 meaning\n      1 maybe\n      1 mature\n      1 matters\n      1 mate\n      1 matchwood\n      1 match\n      1 masterly\n      1 masterful\n      1 massive\n      1 mark\n      1 margin\n      1 maps\n      1 malice\n      1 majesty\n      1 mail\n      1 maid\n      1 magnetism\n      1 mad\n      1 lucky\n      1 lucid\n      1 lover\n      1 loved\n      1 lot\n      1 lose\n      1 looks\n      1 lonely\n      1 locked\n      1 loafers\n      1 live\n      1 listened\n      1 list\n      1 liquid\n      1 link\n      1 line\n      1 limit\n      1 likely\n      1 light\n      1 lifted\n      1 lift\n      1 lieutenant\n      1 liberty\n      1 libel\n      1 levity\n      1 level\n      1 legs\n      1 leg\n      1 left\n      1 lecture\n      1 leave\n      1 leathery\n      1 leather\n      1 learned\n      1 leaning\n      1 lead\n      1 layman\n      1 law\n      1 latter\n      1 latest\n      1 late\n      1 largest\n      1 large\n      1 land\n      1 lamp\n      1 laid\n      1 knows\n      1 kiss\n      1 justify\n      1 justifies\n      1 jumped\n      1 jump\n      1 judice\n      1 judged\n      1 joy\n      1 journalists\n      1 journalist\n      1 job\n      1 isn\n      1 irksome\n      1 invent\n      1 intrusive\n      1 intruded\n      1 intertwined\n      1 interrupted\n      1 international\n      1 intercourse\n      1 intelligence\n      1 instincts\n      1 instinct\n      1 instead\n      1 instantly\n      1 inspirer\n      1 inspiration\n      1 insolent\n      1 insignificant\n      1 inquirer\n      1 inner\n      1 injured\n      1 injunction\n      1 inherited\n      1 inexpressibly\n      1 indication\n      1 index\n      1 incredible\n      1 including\n      1 included\n      1 inches\n      1 impression\n      1 imposter\n      1 impediment\n      1 immediate\n      1 imagined\n      1 imagine\n      1 image\n      1 ill\n      1 ignore\n      1 ignorance\n      1 ignominious\n      1 id\n      1 hurting\n      1 humorous\n      1 humor\n      1 humbly\n      1 humble\n      1 humanity\n      1 hulking\n      1 howl\n      1 hovering\n      1 hours\n      1 hopelessly\n      1 hoped\n      1 honored\n      1 honest\n      1 homicidal\n      1 holes\n      1 hog\n      1 historical\n      1 higher\n      1 hers\n      1 heroic\n      1 heritage\n      1 herd\n      1 helped\n      1 height\n      1 heaves\n      1 heated\n      1 hearted\n      1 health\n      1 heading\n      1 headed\n      1 having\n      1 haven\n      1 hated\n      1 hat\n      1 hardness\n      1 harder\n      1 happiest\n      1 happened\n      1 happen\n      1 handwriting\n      1 handling\n      1 handled\n      1 handiwork\n      1 handed\n      1 halls\n      1 hadn\n      1 habitual\n      1 habit\n      1 gutter\n      1 gutenberg\n      1 guidance\n      1 guaranteed\n      1 grunt\n      1 gripped\n      1 grinning\n      1 grimly\n      1 gregarious\n      1 greater\n      1 gray\n      1 grasp\n      1 gracious\n      1 goings\n      1 glowing\n      1 glow\n      1 glorification\n      1 glories\n      1 gloried\n      1 glared\n      1 gives\n      1 given\n      1 gingery\n      1 gibberish\n      1 germ\n      1 genuine\n      1 gentleman\n      1 gentle\n      1 genius\n      1 generations\n      1 gazed\n      1 gaze\n      1 gasp\n      1 gas\n      1 gaps\n      1 game\n      1 gale\n      1 gaiters\n      1 fury\n      1 furniture\n      1 fugitive\n      1 fronting\n      1 frontiersman\n      1 fringed\n      1 friendship\n      1 friendly\n      1 friend\n      1 fraud\n      1 frame\n      1 fourth\n      1 four\n      1 fortunately\n      1 formidable\n      1 former\n      1 forlorn\n      1 forfeit\n      1 forewarned\n      1 force\n      1 football\n      1 foolish\n      1 fool\n      1 follows\n      1 followed\n      1 folk\n      1 foggy\n      1 fluffy\n      1 fluff\n      1 florid\n      1 flock\n      1 flatter\n      1 flashed\n      1 fists\n      1 finished\n      1 fine\n      1 filed\n      1 figure\n      1 fifty\n      1 fifth\n      1 fever\n      1 fell\n      1 feeble\n      1 feathery\n      1 fearful\n      1 favorable\n      1 fatuous\n      1 fang\n      1 fancies\n      1 fanatic\n      1 faltering\n      1 fallacy\n      1 faking\n      1 fakes\n      1 faithfully\n      1 fairly\n      1 fair\n      1 fad\n      1 factor\n      1 fact\n      1 eyed\n      1 extreme\n      1 extraordinary\n      1 exquisite\n      1 express\n      1 exposing\n      1 exposed\n      1 exploits\n      1 explained\n      1 experiences\n      1 experienced\n      1 experience\n      1 expense\n      1 expedeetion\n      1 expect\n      1 exists\n      1 exchange\n      1 excellent\n      1 exceeding\n      1 exalted\n      1 exactly\n      1 evidently\n      1 everyone\n      1 even\n      1 evasion\n      1 establishing\n      1 established\n      1 especially\n      1 enthusiasm\n      1 energy\n      1 endorsement\n      1 endorse\n      1 encouraging\n      1 encoding\n      1 emphatic\n      1 em\n      1 electric\n      1 elasticity\n      1 elapse\n      1 elaborated\n      1 elaborate\n      1 eh\n      1 egg\n      1 effort\n      1 effervescing\n      1 effervescence\n      1 edge\n      1 ease\n      1 earth\n      1 ears\n      1 earnestness\n      1 earnest\n      1 early\n      1 eager\n      1 duty\n      1 during\n      1 duly\n      1 dry\n      1 driven\n      1 dried\n      1 dressing\n      1 dress\n      1 drawing\n      1 drawer\n      1 doubly\n      1 dogmatic\n      1 distinguish\n      1 distasteful\n      1 distance\n      1 discussion\n      1 discuss\n      1 discretion\n      1 discreditable\n      1 discovery\n      1 discovered\n      1 disapproval\n      1 directness\n      1 dining\n      1 dignity\n      1 difficulty\n      1 differences\n      1 diameter\n      1 diagrams\n      1 devil\n      1 detached\n      1 destined\n      1 desires\n      1 described\n      1 descreeptive\n      1 depth\n      1 depreciation\n      1 dependent\n      1 demonstrate\n      1 delicately\n      1 delicate\n      1 deliberate\n      1 deigns\n      1 degree\n      1 deeper\n      1 deep\n      1 deception\n      1 decency\n      1 debts\n      1 date\n      1 danger\n      1 dancing\n      1 damp\n      1 damnedest\n      1 damaged\n      1 cuticura\n      1 curving\n      1 curtained\n      1 curtain\n      1 curtail\n      1 cunning\n      1 crying\n      1 criticism\n      1 crisis\n      1 creatures\n      1 creature\n      1 crawling\n      1 cranial\n      1 crabbed\n      1 court\n      1 cost\n      1 correspondence\n      1 cooed\n      1 convinces\n      1 convinced\n      1 conveyed\n      1 convey\n      1 conversaziones\n      1 conversation\n      1 context\n      1 contents\n      1 contentious\n      1 content\n      1 constant\n      1 considerate\n      1 conscience\n      1 conquered\n      1 confession\n      1 conducted\n      1 conditions\n      1 conditioned\n      1 conclusions\n      1 conceited\n      1 comradeship\n      1 composition\n      1 compliment\n      1 company\n      1 companions\n      1 comments\n      1 comment\n      1 command\n      1 coloring\n      1 colliery\n      1 collected\n      1 colleagues\n      1 cold\n      1 cockatoo\n      1 cock\n      1 coal\n      1 clumped\n      1 club\n      1 closed\n      1 clock\n      1 clipped\n      1 climbing\n      1 clever\n      1 clerk\n      1 clearly\n      1 circulation\n      1 chosen\n      1 choked\n      1 choke\n      1 chirrup\n      1 checking\n      1 chauffeur\n      1 charged\n      1 charge\n      1 champion\n      1 certainly\n      1 certain\n      1 centered\n      1 center\n      1 censor\n      1 caused\n      1 caught\n      1 case\n      1 carried\n      1 calm\n      1 calling\n      1 bye\n      1 butt\n      1 butlers\n      1 butcher\n      1 bully\n      1 bucking\n      1 brutal\n      1 brows\n      1 brought\n      1 brother\n      1 bronzed\n      1 bronze\n      1 broad\n      1 bring\n      1 bright\n      1 briefly\n      1 brethren\n      1 breathed\n      1 breath\n      1 breast\n      1 breaks\n      1 breaking\n      1 breadth\n      1 brave\n      1 brackets\n      1 brace\n      1 boyish\n      1 bowdlerized\n      1 bow\n      1 bounded\n      1 bounced\n      1 bottom\n      1 boss\n      1 books\n      1 bolted\n      1 bodies\n      1 blowing\n      1 blew\n      1 blast\n      1 blackened\n      1 bit\n      1 biography\n      1 bimetallism\n      1 between\n      1 bestial\n      1 besides\n      1 beside\n      1 bent\n      1 bellowing\n      1 bellow\n      1 bell\n      1 believes\n      1 believed\n      1 behavior\n      1 behaved\n      1 begins\n      1 began\n      1 beauty\n      1 beast\n      1 battles\n      1 battery\n      1 barrel\n      1 barbed\n      1 balloon\n      1 bags\n      1 backing\n      1 backed\n      1 awfully\n      1 awaits\n      1 averted\n      1 averaged\n      1 authority\n      1 audacity\n      1 attitude\n      1 attention\n      1 attempt\n      1 attacked\n      1 attack\n      1 asthmatic\n      1 assured\n      1 assurances\n      1 associate\n      1 assertion\n      1 assaults\n      1 assault\n      1 asks\n      1 ashamed\n      1 article\n      1 around\n      1 arnica\n      1 arm\n      1 argue\n      1 ardent\n      1 architecture\n      1 approve\n      1 appears\n      1 appeared\n      1 appear\n      1 apologize\n      1 apart\n      1 anxious\n      1 answered\n      1 annoyed\n      1 announced\n      1 animals\n      1 animal\n      1 angular\n      1 anger\n      1 amplification\n      1 amiss\n      1 amazement\n      1 although\n      1 alternating\n      1 aloof\n      1 alluded\n      1 allowances\n      1 alive\n      1 alarmed\n      1 air\n      1 agreeable\n      1 aggressive\n      1 afterwards\n      1 afraid\n      1 aeronaut\n      1 adventure\n      1 advancing\n      1 advanced\n      1 admirable\n      1 added\n      1 adapt\n      1 action\n      1 acting\n      1 act\n      1 acrimonious\n      1 account\n      1 accessible\n      1 accepted\n      1 accentuated\n      1 accent\n      1 abusive\n      1 abominably\n      1 able\n      1 Yours\n      1 YOUR\n      1 XVI\n      1 XV\n      1 XIV\n      1 XIII\n      1 XII\n      1 XI\n      1 X\n      1 Would\n      1 Winner\n      1 Wigan\n      1 Where\n      1 West\n      1 Went\n      1 Weissmannism\n      1 Wasn\n      1 Walking\n      1 Wait\n      1 WONDERS\n      1 WONDERFUL\n      1 WITH\n      1 WILL\n      1 WHO\n      1 WERE\n      1 WE\n      1 Vertebrate\n      1 VIII\n      1 VII\n      1 VI\n      1 VERY\n      1 V\n      1 Us\n      1 Uproar\n      1 Upon\n      1 University\n      1 Undoubtedly\n      1 US\n      1 UNKNOWN\n      1 Tut\n      1 Try\n      1 Title\n      1 Time\n      1 Tickled\n      1 Three\n      1 They\n      1 These\n      1 Terrace\n      1 Tell\n      1 Telegraph\n      1 Talking\n      1 TRY\n      1 TO\n      1 THOSE\n      1 THIS\n      1 THINGS\n      1 THING\n      1 THERE\n      1 Swollen\n      1 Suppose\n      1 Such\n      1 Step\n      1 Stanleys\n      1 Stanley\n      1 Spirited\n      1 Southwark\n      1 Sometimes\n      1 Something\n      1 Somehow\n      1 Society\n      1 Societe\n      1 Skulls\n      1 Several\n      1 Series\n      1 Section\n      1 Scotch\n      1 Sciences\n      1 Savage\n      1 Saturday\n      1 START\n      1 SIGHT\n      1 SHALL\n      1 SEEN\n      1 S\n      1 Russia\n      1 Round\n      1 Right\n      1 Richard\n      1 Reuter\n      1 Resigned\n      1 Research\n      1 Remember\n      1 Release\n      1 Recreations\n      1 ROUND\n      1 REAL\n      1 QUESTION\n      1 Put\n      1 Publications\n      1 Protests\n      1 Protest\n      1 Produced\n      1 Proceedings\n      1 Pretend\n      1 Pressman\n      1 Pray\n      1 Plata\n      1 Person\n      1 Persian\n      1 Perhaps\n      1 Perfectly\n      1 Palaeontological\n      1 PROJECT\n      1 PICKETS\n      1 PERSON\n      1 PERFECTLY\n      1 PARK\n      1 Outlines\n      1 Or\n      1 Once\n      1 Olympian\n      1 Observations\n      1 OUTLYING\n      1 OUR\n      1 ONCE\n      1 November\n      1 Nothing\n      1 Naturally\n      1 NEW\n      1 NEVER\n      1 N\n      1 Museum\n      1 Munchausen\n      1 Move\n      1 Most\n      1 Member\n      1 Medal\n      1 May\n      1 Masonic\n      1 Macs\n      1 MOST\n      1 MORROW\n      1 MALONE\n      1 MAKE\n      1 Luck\n      1 Lively\n      1 License\n      1 Liability\n      1 Language\n      1 Lady\n      1 La\n      1 LUCK\n      1 LORD\n      1 Knowable\n      1 Keeper\n      1 Kalmuck\n      1 Just\n      1 June\n      1 Judith\n      1 JUST\n      1 Is\n      1 India\n      1 Impossible\n      1 IX\n      1 IV\n      1 IS\n      1 INTO\n      1 IMPOSSIBLE\n      1 Hungerton\n      1 However\n      1 Heroisms\n      1 Here\n      1 Hercules\n      1 Her\n      1 Have\n      1 Has\n      1 Half\n      1 Haines\n      1 HTML\n      1 HEROISMS\n      1 HERO\n      1 HE\n      1 HAPPENED\n      1 H\n      1 Gulf\n      1 Good\n      1 Give\n      1 Gibberish\n      1 Get\n      1 General\n      1 GUTENBERG\n      1 GREAT\n      1 GEORGE\n      1 Frenchman\n      1 French\n      1 Forfeit\n      1 Foreword\n      1 Foreign\n      1 For\n      1 Following\n      1 Fate\n      1 FORGET\n      1 FOREST\n      1 FORESEEN\n      1 FOR\n      1 FLAIL\n      1 Expensive\n      1 Expected\n      1 Exactly\n      1 Ex\n      1 Entirely\n      1 Employers\n      1 Eh\n      1 Edward\n      1 Educ\n      1 Edinburgh\n      1 EYES\n      1 ENMORE\n      1 EBOOK\n      1 Didn\n      1 Department\n      1 Death\n      1 Date\n      1 Darwinism\n      1 Daily\n      1 DREADFUL\n      1 DOYLE\n      1 DISAPPEAR\n      1 DEFINITE\n      1 DEAR\n      1 Creeping\n      1 Crayston\n      1 Continental\n      1 Contents\n      1 Congress\n      1 Comparative\n      1 Club\n      1 Clive\n      1 Chinese\n      1 Chestnuts\n      1 Character\n      1 Chairman\n      1 Chain\n      1 Catharine\n      1 Can\n      1 Came\n      1 Camberwell\n      1 Cabinet\n      1 COULD\n      1 COPYRIGHT\n      1 CONQUESTS\n      1 CONAN\n      1 Burtons\n      1 Burton\n      1 Boss\n      1 Born\n      1 Belge\n      1 Behold\n      1 Began\n      1 Beaumont\n      1 Balkans\n      1 BIGGEST\n      1 B\n      1 Author\n      1 Assyrian\n      1 Association\n      1 Are\n      1 Anyway\n      1 Anthropology\n      1 An\n      1 Alpine\n      1 Al\n      1 Afterwards\n      1 Adelphi\n      1 Address\n      1 Act\n      1 ASCII\n      1 ARTHUR\n      1 ARE\n      1 ALL\n"
  },
  {
    "path": "core-tools/tests-regression/web-log-report/logfile",
    "content": "204.249.225.59 - - [28/Aug/1995:00:00:34 -0400] \"GET /pub/rmharris/catalogs/dawsocat/intro.html HTTP/1.0\" 200 3542\npc23-slip.ccs-stug.deakin.edu.au - - [28/Aug/1995:00:06:54 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nsl06.chrysalis.org - - [28/Aug/1995:00:13:01 -0400] \"GET /pub/sshay/images/crthumb5.jpg HTTP/1.0\" 200 4495\nuaf-du-02-14.alaska.edu - - [28/Aug/1995:00:19:51 -0400] \"GET /atomicbk/images/shemale1.gif HTTP/1.0\" 200 43665\nminerva.athenet.net - - [28/Aug/1995:00:27:13 -0400] \"GET /pub/job/vk/view17.jpg\" 200 5944\npc25.acrs-helm.wku.edu - - [28/Aug/1995:00:36:53 -0400] \"GET /pub/sshay/images/chrsbutn.gif HTTP/1.0\" 200 1070\nHuwawa.async.smsu.edu - - [28/Aug/1995:00:43:18 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 304 -\n204.101.181.14 - - [28/Aug/1995:00:50:09 -0400] \"GET /pub/jeffd/grayball.gif HTTP/1.0\" 200 995\nix-sfe-nm1-05.ix.netcom.com - - [28/Aug/1995:00:56:50 -0400] \"GET /pub/sshay/images/gallery.gif HTTP/1.0\" 200 8010\ndialin33448.slip.nts.uci.edu - - [28/Aug/1995:01:05:15 -0400] \"GET /atomicbk/new/catalog.gif HTTP/1.0\" 200 693\nS143A-quadra.Stanford.EDU - - [28/Aug/1995:01:15:20 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nix-ftl2-09.ix.netcom.com - - [28/Aug/1995:01:24:21 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\nmpdpc01448.nneco.nu.com - - [28/Aug/1995:01:34:21 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\nasync110.zrz.TU-Berlin.DE - - [28/Aug/1995:01:42:10 -0400] \"GET /pub/cardman/1curious.gif HTTP/1.0\" 200 1281\n133.225.internal.radian.com - - [28/Aug/1995:01:52:52 -0400] \"GET /pub/job/vk/view17.jpg HTTP/1.0\" 200 5944\nsundial.sundial.net - - [28/Aug/1995:02:01:52 -0400] \"GET /pub/mbrophy/pix/thing.jpg HTTP/1.0\" 200 3606\ntuna.hooked.net - - [28/Aug/1995:02:09:55 -0400] \"GET /pub/journalism/awesome.html/ HTTP/1.0\" 404 207\nCust15.Max1.San-Diego.CA.MS.UU.NET - - [28/Aug/1995:02:19:38 -0400] \"GET /pub/sinkers/introsp2.gif HTTP/1.0\" 200 22960\nip-pdx11-20.teleport.com - - [28/Aug/1995:02:29:14 -0400] \"GET /pub/rmharris/alldlrs/dlrimage/books.gif HTTP/1.0\" 304 -\nclark.net - - [28/Aug/1995:02:38:50 -0400] \"GET /pub/kolesar/turtle.gif HTTP/1.0\" 304 -\nhumfact2.mac.ccad.uiowa.edu - - [28/Aug/1995:02:48:38 -0400] \"GET /pub/job/vk/view21.jpg HTTP/1.0\" 200 5228\nppp178.scott.net - - [28/Aug/1995:02:57:14 -0400] \"GET /pub/aztec/shesails/ HTTP/1.0\" 200 1533\nmac27.phlab.missouri.edu - - [28/Aug/1995:03:07:50 -0400] \"GET /pub/mbrophy/pix/about.jpg HTTP/1.0\" 200 5674\ngate.tsh.cae.ntt.jp - - [28/Aug/1995:03:18:12 -0400] \"GET /pub/job/vk/view30.jpg HTTP/1.0\" 200 5991\ninter3.ytol.fi - - [28/Aug/1995:03:29:29 -0400] \"GET /pub/job/vk/view33.jpg HTTP/1.0\" 200 5903\nlks.covd.se - - [28/Aug/1995:03:39:18 -0400] \"GET /pub/job/b-back.jpg HTTP/1.0\" 200 4195\nendBb.laurel.us.net - - [28/Aug/1995:03:49:46 -0400] \"GET /pub/craver/surreal/anim7.htm HTTP/1.0\" 200 391\npc1078.psi.ch - - [28/Aug/1995:03:59:01 -0400] \"GET /pub/job/vk/view18.jpg HTTP/1.0\" 200 6578\ncc7sun-d6.cc.au.ac.th - - [28/Aug/1995:04:10:43 -0400] \"GET /pub/mbrophy/pix/arling.jpg HTTP/1.0\" 200 7905\nsunlab9.essex.ac.uk - - [28/Aug/1995:04:25:16 -0400] \"GET /pub/job/vk/view34.jpg HTTP/1.0\" 200 5156\ndum28.interserve.com.hk - - [28/Aug/1995:04:37:17 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\ninterlock.turner.com - - [28/Aug/1995:04:51:11 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\nelara.horizon.bc.ca - - [28/Aug/1995:05:04:26 -0400] \"GET /pub/sshay/about.html HTTP/1.0\" 200 18751\ngeneral.sbceo.k12.ca.us - - [28/Aug/1995:05:19:36 -0400] \"GET /pub/cosmic/joyce1.gif HTTP/1.0\" 200 29751\ndal01-10.ppp.iadfw.net - - [28/Aug/1995:05:34:25 -0400] \"GET /pub/ecn/Newton.gif HTTP/1.0\" 200 2724\nrelay02.jpmorgan.com - - [28/Aug/1995:05:45:35 -0400] \"GET /pub/job/swim/v-54.jpg HTTP/1.0\" 200 2817\npm013.bby.wis.net - - [28/Aug/1995:05:54:30 -0400] \"GET /atomicbk/images/tart.gif HTTP/1.0\" 200 38555\nextra.ucc.su.OZ.AU - - [28/Aug/1995:06:05:28 -0400] \"GET /pub/menswear/redball.gif HTTP/1.0\" 200 326\ngaudi.ac.upc.es - - [28/Aug/1995:06:18:36 -0400] \"GET /pub/rjgula/os/linux/lpr1.txt HTTP/1.0\" 200 2229\nLei56.pi.net - - [28/Aug/1995:06:29:36 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nwww-e1b.gnn.com - - [28/Aug/1995:06:42:25 -0400] \"GET /pub/mmuller/uel_email.html HTTP/1.0\" 200 7205\ngk-east.usps.gov - - [28/Aug/1995:06:55:36 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\n166.42.216.37 - - [28/Aug/1995:07:05:59 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\nppp-dc-1-4.ios.com - - [28/Aug/1995:07:16:51 -0400] \"GET /pub/gen/fas/ HTTP/1.0\" 200 7893\nicpmac16.epfl.ch - - [28/Aug/1995:07:28:43 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nzephyr.aub.auc.dk - - [28/Aug/1995:07:37:43 -0400] \"GET /graphics/bar.gif HTTP/1.0\" 200 2857\n152.123.194.3 - - [28/Aug/1995:07:46:39 -0400] \"GET /pub/usenet-b/www/home.html HTTP/1.0\" 200 1710\ngk-east.usps.gov - - [28/Aug/1995:07:56:44 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nindy32.sfc.keio.ac.jp - - [28/Aug/1995:08:05:42 -0400] \"GET /pub/jeffd/speaker.gif HTTP/1.0\" 200 2646\nspectrum.xerox.com - - [28/Aug/1995:08:13:59 -0400] \"GET /pub/ibos/iback.gif HTTP/1.0\" 304 -\npoppy.hensa.ac.uk - - [28/Aug/1995:08:22:48 -0400] \"GET /pub/madsox/ma-links.html HTTP/1.0\" 200 3765\n199.128.20.35 - - [28/Aug/1995:08:32:44 -0400] \"GET /pub/jeffd/sm_eaghd.gif HTTP/1.0\" 200 2866\n128.178.83.41 - - [28/Aug/1995:08:38:23 -0400] \"GET /atomicbk/seanc.gif HTTP/1.0\" 200 734\ngraal.cril-ing.fr - - [28/Aug/1995:08:46:24 -0400] \"GET /pub/pribut/email2.gif HTTP/1.0\" 304 -\nhel.fi - - [28/Aug/1995:08:54:12 -0400] \"GET /pub/heroes/wavs/sheen.wav HTTP/1.0\" 200 173690\nakash.CV.COM - - [28/Aug/1995:09:01:27 -0400] \"GET /pub/howie/OO/H.GIF HTTP/1.0\" 200 989\nad07-024.compuserve.com - - [28/Aug/1995:09:07:50 -0400] \"GET /ntp/ecit/ecitlog1.gif HTTP/1.0\" 200 4952\nintgate.raleigh.ibm.com - - [28/Aug/1995:09:14:51 -0400] \"GET /pub/job/vk/view36.jpg HTTP/1.0\" 200 3522\npppdroth.ari.net - - [28/Aug/1995:09:22:02 -0400] \"GET /mpt/ttc/female.gif HTTP/1.0\" 200 493\npiweba2y.prodigy.com - - [28/Aug/1995:09:28:53 -0400] \"GET /pub/jumpsam/line_yel.gif HTTP/1.0\" 200 1243\npinta.kolumbus.fi - - [28/Aug/1995:09:35:28 -0400] \"GET /pub/job/vk/view05.jpg HTTP/1.0\" 200 5012\nyin.nj.nec.com - - [28/Aug/1995:09:41:58 -0400] \"GET /ccentral/npbutton.gif HTTP/1.0\" 200 2062\npc105104.shef.ac.uk - - [28/Aug/1995:09:46:44 -0400] \"GET /pub/sshay/galybutn.map?210,15 HTTP/1.0\" 302 227\neehpx26.cen.uiuc.edu - - [28/Aug/1995:09:54:14 -0400] \"GET /atomicbk/catalog/new.gif HTTP/1.0\" 200 744\ngrndserver.library.gatech.edu - - [28/Aug/1995:09:59:44 -0400] \"GET /pub/lschank/web/line.gif HTTP/1.0\" 200 1131\nbeta.Xerox.COM - - [28/Aug/1995:10:05:29 -0400] \"GET /pub/linda/cody.html HTTP/1.0\" 200 664\n130.160.248.23 - - [28/Aug/1995:10:11:36 -0400] \"GET /pub/jeffd/rush&et.gif HTTP/1.0\" 200 15412\n155.229.34.2 - - [28/Aug/1995:10:17:08 -0400] \"GET /pub/jgbustam/heritage/heritage.html HTTP/1.0\" 200 2324\nstortek1.stortek.com - - [28/Aug/1995:10:21:14 -0400] \"GET /pub/k2/am4x44u/whats_new/4wa2.htm HTTP/1.0\" 200 1262\nftp.delmarva.com - - [28/Aug/1995:10:25:20 -0400] \"GET /pub/job/vk/bam.gif HTTP/1.0\" 200 9076\n131.115.140.66 - - [28/Aug/1995:10:30:38 -0400] \"GET /pub/job/vk/kathy.jpg HTTP/1.0\" 200 7450\n128.206.15.192 - - [28/Aug/1995:10:35:15 -0400] \"GET /pub/jrinker/redball.gif HTTP/1.0\" 200 326\nad22-011.compuserve.com - - [28/Aug/1995:10:40:05 -0400] \"GET /pub/jumpsam/logogosp.jpg HTTP/1.0\" 200 15227\npipe3.nyc.pipeline.com - - [28/Aug/1995:10:44:22 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 200 11610\nggb3334-mac1.engin.umich.edu - - [28/Aug/1995:10:49:35 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nmic5.hudk.hokudai.ac.jp - - [28/Aug/1995:10:53:44 -0400] \"GET /pub/atomicbk/images/bpqueen.gif HTTP/1.0\" 200 24160\n194.51.81.248 - - [28/Aug/1995:10:59:13 -0400] \"GET /pub/lupine/images/tlk/timon.gif HTTP/1.0\" 304 -\n128.255.196.188 - - [28/Aug/1995:11:04:39 -0400] \"GET /pub/job/vk/bam.gif HTTP/1.0\" 200 9076\n147.74.10.26 - - [28/Aug/1995:11:08:21 -0400] \"GET /pub/global/index1.html HTTP/1.0\" 200 1065\npayday.cc.vt.edu - - [28/Aug/1995:11:11:41 -0400] \"GET /pub/mbrophy/pix/washlee.jpg HTTP/1.0\" 200 1203\nvagrant.vf.mmc.com - - [28/Aug/1995:11:16:04 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\n153.74.191.27 - - [28/Aug/1995:11:20:17 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\nclark.net - - [28/Aug/1995:11:23:58 -0400] \"GET /pub/job/vk/view26.jpg HTTP/1.0\" 304 -\nwww-relay.pa-x.dec.com - - [28/Aug/1995:11:28:49 -0400] \"GET /pub/k2/am4x44u/gifs/BGPRCHM2.JPG HTTP/1.0\" 404 318\namf99-0.Amersfoort.NL.net - - [28/Aug/1995:11:33:53 -0400] \"GET /pub/networx/autopage/exotic/ex002_1s.gif HTTP/1.0\" 200 17130\n155.225.12.25 - - [28/Aug/1995:11:37:31 -0400] \"GET /theme/demockracy/logo3.gif HTTP/1.0\" 200 9565\nmcdowell-12.mcdowell.udel.edu - - [28/Aug/1995:11:42:26 -0400] \"GET /pub/jgbustam/gifs/coloico2.gif HTTP/1.0\" 200 4298\nremws01.who.ch - - [28/Aug/1995:11:46:58 -0400] \"GET /atomicbk/new/newaug25.html HTTP/1.0\" 200 6407\nbouchon-ppp.clark.net - - [28/Aug/1995:11:51:34 -0400] \"GET /pub/bouchon/meter.gif HTTP/1.0\" 304 -\ngatekeeper.bridge.com - - [28/Aug/1995:11:56:03 -0400] \"GET /pub/job/vk/view24.jpg HTTP/1.0\" 200 6209\nx242-16.cla.umn.edu - - [28/Aug/1995:11:59:57 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nCOMPC1.COMP.PANAM.EDU - - [28/Aug/1995:12:05:14 -0400] \"GET /pub/job/vk/view08.jpg HTTP/1.0\" 200 6476\nix-orl1-08.ix.netcom.com - - [28/Aug/1995:12:09:27 -0400] \"GET /pub/job/vk/view30.jpg HTTP/1.0\" 200 5991\nisr0973.urh.uiuc.edu - - [28/Aug/1995:12:12:45 -0400] \"GET /pub/job/vk/view10.jpg HTTP/1.0\" 200 5303\n144.30.1.220 - - [28/Aug/1995:12:16:31 -0400] \"GET /pub/nih/fig_5A.jpg HTTP/1.0\" 200 23156\nZEBRA.ENGR.UTK.EDU - - [28/Aug/1995:12:21:04 -0400] \"GET /pub/alweiner/w3-bg-1.gif HTTP/1.0\" 200 3495\ntazman.mindspring.com - - [28/Aug/1995:12:26:05 -0400] \"GET /atomicbk/orders.gif HTTP/1.0\" 200 800\nuser32.lightside.com - - [28/Aug/1995:12:29:41 -0400] \"GET /pub/ibos/buslinks.html HTTP/1.0\" 304 -\npshelton.northstar.k12.ak.us - - [28/Aug/1995:12:34:07 -0400] \"GET /pub/networx/autopage/dealers/de001_3b.gif HTTP/1.0\" 200 70257\nrm503-3.inn.usu.edu - - [28/Aug/1995:12:38:13 -0400] \"GET /pub/job/vk/view27.jpg HTTP/1.0\" 200 6611\neurocent.clark.net - - [28/Aug/1995:12:42:00 -0400] \"GET /pub/eurocent/inquiry.htm HTTP/1.0\" 200 1988\nheather.eee.strath.ac.uk - - [28/Aug/1995:12:46:06 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nwww-b6.proxy.aol.com - - [28/Aug/1995:12:50:44 -0400] \"GET /pub/heroes/gifs/heston.gif HTTP/1.0\" 304 -\nenterprise.nettrek.com.au - - [28/Aug/1995:12:53:56 -0400] \"GET /atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6688\n161.106.1.2 - - [28/Aug/1995:12:57:54 -0400] \"GET /atomicbk/new/new.html HTTP/1.0\" 200 2914\nmagicall.dacom.co.kr - - [28/Aug/1995:13:02:24 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\nvenus.aacc.cc.md.us - - [28/Aug/1995:13:06:03 -0400] \"GET /pub/tblake/www/home.gif HTTP/1.0\" 304 -\nwww-a1.proxy.aol.com - - [28/Aug/1995:13:10:20 -0400] \"GET /pub/atomicbk/new/new.html HTTP/1.0\" 200 2914\nCust20.Max7.San-Francisco.CA.MS.UU.NET - - [28/Aug/1995:13:13:46 -0400] \"GET /atomicbk/new/logo2.gif HTTP/1.0\" 200 12871\njschultz-pc.chronicle.com - - [28/Aug/1995:13:17:05 -0400] \"GET /pub/lschank/web/line2.gif HTTP/1.0\" 200 267\nslip01.hrz.uni-giessen.de - - [28/Aug/1995:13:21:44 -0400] \"GET /atomicbk/images/hbslut.gif HTTP/1.0\" 200 43138\nwww-b4.proxy.aol.com - - [28/Aug/1995:13:25:26 -0400] \"GET /pub/networx/autopage/dealers.html HTTP/1.0\" 200 1201\nad12-021.compuserve.com - - [28/Aug/1995:13:29:03 -0400] \"GET /pub/sshay/interact.html HTTP/1.0\" 200 2694\n192.72.107.107 - - [28/Aug/1995:13:35:13 -0400] \"GET /pub/atomicbk/images/nudistbk.gif HTTP/1.0\" 404 335\n141.161.119.116 - - [28/Aug/1995:13:39:36 -0400] \"GET /pub/jgbustam/gifs/at-work.gif HTTP/1.0\" 200 373\nio.is.co.za - - [28/Aug/1995:13:44:37 -0400] \"GET /pub/murple/home.html HTTP/1.0\" 200 3676\n192.239.92.145 - - [28/Aug/1995:13:48:44 -0400] \"GET /pub/fbc/www/image/md.gif HTTP/1.0\" 200 1373\nwebgate1.mot.com - - [28/Aug/1995:13:52:57 -0400] \"GET /atomicbk/seanc.gif HTTP/1.0\" 200 734\npc1-195.health.org - - [28/Aug/1995:13:56:55 -0400] \"GET /pub/michele/backgrds/zag-zig.gif HTTP/1.0\" 200 10016\nwww-a1.proxy.aol.com - - [28/Aug/1995:14:00:47 -0400] \"GET /pub/job/vk/view36.jpg HTTP/1.0\" 304 -\nbuckman.com - - [28/Aug/1995:14:04:01 -0400] \"GET /pub/sgs/usdotsaf.htm HTTP/1.0\" 200 615030\n165.134.64.150 - - [28/Aug/1995:14:07:53 -0400] \"GET /pub/sshay/images/nrcthumb.jpg HTTP/1.0\" 200 4215\nwww-c3.proxy.aol.com - - [28/Aug/1995:14:11:37 -0400] \"GET /pub/jeffd/grad_lin.gif HTTP/1.0\" 200 3346\n130.163.112.144 - - [28/Aug/1995:14:16:00 -0400] \"GET /pub/job/vk/view17.jpg HTTP/1.0\" 200 5944\nph20324.cpmc.columbia.edu - - [28/Aug/1995:14:20:26 -0400] \"GET /pub/ibos/fishform.html HTTP/1.0\" 200 1750\nasp.erinet.com - - [28/Aug/1995:14:25:00 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 304 -\npk21010.bwi.wec.com - - [28/Aug/1995:14:28:16 -0400] \"GET /graphics/clark5.gif HTTP/1.0\" 200 39568\ngort.byu.edu - - [28/Aug/1995:14:31:45 -0400] \"GET /pub/job/vk/view06.jpg HTTP/1.0\" 200 6553\na42.mor.itesm.mx - - [28/Aug/1995:14:35:24 -0400] \"GET /pub/jgbustam/toros/bullarts.html HTTP/1.0\" 200 507\nwoobie.UU.NET - - [28/Aug/1995:14:39:16 -0400] \"GET /pub/jgbustam/paises/peruic.gif HTTP/1.0\" 304 -\nsgs.clark.net - - [28/Aug/1995:14:43:16 -0400] \"GET /pub/sgs/spr/l_arrow.gif HTTP/1.0\" 200 1003\ninterlock.turner.com - - [28/Aug/1995:14:46:19 -0400] \"GET /pub/sshay/images/linkbutn.gif HTTP/1.0\" 200 1080\ncolt.mais.hydro.qc.ca - - [28/Aug/1995:14:50:59 -0400] \"GET /pub/k2/am4x44u/events/clubs/jcoa.htm HTTP/1.0\" 200 1878\nindy4.ecf.toronto.edu - - [28/Aug/1995:14:57:50 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 14969\n204.70.239.154 - - [28/Aug/1995:15:01:23 -0400] \"GET /pub/robert/rain_l~1.gif HTTP/1.0\" 200 2243\n140.150.91.197 - - [28/Aug/1995:15:04:53 -0400] \"GET /pub/job/vk/view23.jpg HTTP/1.0\" 200 5165\navarice.obsolete.com - - [28/Aug/1995:15:08:23 -0400] \"GET /pub/murple/home.html HTTP/1.0\" 304 -\nlabg2.comer.wvu.edu - - [28/Aug/1995:15:11:29 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\ngwa.ericsson.com - - [28/Aug/1995:15:14:37 -0400] \"GET /pub/job/canyon.jpg HTTP/1.0\" 200 9125\nexinos.ms.com - - [28/Aug/1995:15:18:28 -0400] \"GET /pub/jridgely/dc/wash.gif HTTP/1.0\" 200 1034\nppru-lj-w3.ucsd.edu - - [28/Aug/1995:15:23:13 -0400] \"GET /pub/ashp/grafx\\acrobatg.gif HTTP/1.0\" 404 323\nwww-b3.proxy.aol.com - - [28/Aug/1995:15:26:43 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\n199.212.26.36 - - [28/Aug/1995:15:30:19 -0400] \"GET /pub/lupine/www/images/support/mickey.gif HTTP/1.0\" 200 2383\n204.160.213.159 - - [28/Aug/1995:15:34:24 -0400] \"GET /pub/k2/am4x44u/gifs/jyj.gif HTTP/1.0\" 200 2241\nslip145-44.ut.nl.ibm.net - - [28/Aug/1995:15:37:45 -0400] \"GET /pub/rsjdfg/ HTTP/1.0\" 200 2109\ncsc005.cas.usf.edu - - [28/Aug/1995:15:40:26 -0400] \"GET /pub/jeffd/grad_lin.gif HTTP/1.0\" 200 3346\ngateway.rsinc.com - - [28/Aug/1995:15:44:14 -0400] \"GET /mc-icons/back.gif HTTP/1.0\" 200 174\nsku-pc17.esu3.k12.ne.us - - [28/Aug/1995:15:47:39 -0400] \"GET /pub/k2/am4x44u/gifs/netscape.gif HTTP/1.0\" 200 1050\nfnugget.intel.com - - [28/Aug/1995:15:50:58 -0400] \"GET /pub/peace/grball.gif HTTP/1.0\" 304 -\nvenus.ivic.ve - - [28/Aug/1995:15:54:27 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nflynnpc.sunydutchess.edu - - [28/Aug/1995:15:58:17 -0400] \"GET /pub/eclipse/home/telegraph-key.xbm HTTP/1.0\" 200 7011\ndd19-004.compuserve.com - - [28/Aug/1995:16:02:07 -0400] \"GET /pub/sshay/images/rainlin2.gif HTTP/1.0\" 200 1229\nshelvik_ibmpc.slc.mke.ab.com - - [28/Aug/1995:16:06:55 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 14969\ncumac.truevision.com - - [28/Aug/1995:16:11:08 -0400] \"GET /pub/shelby/imaglogo.gif HTTP/1.0\" 200 3662\ncs1-13.eph.ptd.net - - [28/Aug/1995:16:13:31 -0400] \"GET /pub/job/swim/v-47.jpg HTTP/1.0\" 200 2964\n136.205.143.61 - - [28/Aug/1995:16:16:22 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\nervinper.natinst.com - - [28/Aug/1995:16:19:33 -0400] \"GET /pub/job/vk/view12.jpg HTTP/1.0\" 200 5966\n194.170.2.41 - - [28/Aug/1995:16:22:29 -0400] \"GET /pub/listserv/listserv.html HTTP/1.0\" 200 1138\n128.204.73.68 - - [28/Aug/1995:16:25:36 -0400] \"GET /pub/job/swim/swim.jpg HTTP/1.0\" 200 15234\nnews.stucen.gatech.edu - - [28/Aug/1995:16:29:39 -0400] \"GET /pub/job/vk/view08.jpg HTTP/1.0\" 200 6476\ngesg51.geo.census.gov - - [28/Aug/1995:16:33:54 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\norange.ge.com - - [28/Aug/1995:16:38:03 -0400] \"GET /pub/job/vk/cindy.jpg HTTP/1.0\" 200 4267\nzeke.gov.yk.ca - - [28/Aug/1995:16:41:41 -0400] \"GET / HTTP/1.0\" 200 1834\n143.166.148.44 - - [28/Aug/1995:16:46:15 -0400] \"GET /pub/cargui/ctpltmst.gif HTTP/1.0\" 200 13757\nLaplace.CL.UH.EDU - - [28/Aug/1995:16:49:43 -0400] \"GET /pub/fan/albumpics/overdose.jpg HTTP/1.0\" 200 3152\nemeldir.dd.chalmers.se - - [28/Aug/1995:16:55:17 -0400] \"GET /pub/alweiner/cgi-bin/homepage.html?wall-kidfun HTTP/1.0\" 200 959\np2151_01.ifmt.nf.ca - - [28/Aug/1995:16:58:27 -0400] \"GET /atomicbk/new/new.html HTTP/1.0\" 200 2914\n155.234.241.41 - - [28/Aug/1995:17:01:52 -0400] \"GET /mpt/motorwk.gif HTTP/1.0\" 200 6008\nwagnerjh.norand.com - - [28/Aug/1995:17:05:28 -0400] \"GET /pub/jeffd/rushpage.html HTTP/1.0\" 304 -\n137.53.22.115 - - [28/Aug/1995:17:09:27 -0400] \"GET /pub/job/vk/cindy.jpg HTTP/1.0\" 200 4267\nosiris.gsfc.nasa.gov - - [28/Aug/1995:17:13:42 -0400] \"GET /pub/sandy/chromatics/chrom3.gif HTTP/1.0\" 200 15422\nAvauca.usae.bah.com - - [28/Aug/1995:17:17:30 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\n198.232.176.77 - - [28/Aug/1995:17:22:02 -0400] \"GET /pub/job/vk/view17.jpg HTTP/1.0\" 200 5944\np827229.lanl.gov - - [28/Aug/1995:17:25:57 -0400] \"GET /pub/k2/am4x44u/gifs/spacer.gif HTTP/1.0\" 200 833\nuser61.ef.com - - [28/Aug/1995:17:30:45 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\n136.183.44.40 - - [28/Aug/1995:17:34:15 -0400] \"GET /pub/job/vk/view09.jpg HTTP/1.0\" 200 6011\njeremy.leitess.com - - [28/Aug/1995:17:37:48 -0400] \"GET /pub/ HTTP/1.0\" 200 419\n156.80.138.125 - - [28/Aug/1995:17:41:25 -0400] \"GET /pub/alweiner/work/_0153T.gif HTTP/1.0\" 200 813\nichthus.stsci.edu - - [28/Aug/1995:17:46:03 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\nadvising.life.uiuc.edu - - [28/Aug/1995:17:50:24 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\n192.139.10.109 - - [28/Aug/1995:17:54:38 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nschwesig.lib.uchicago.edu - - [28/Aug/1995:17:59:54 -0400] \"GET /pub/lschank/web/gpo.gif HTTP/1.0\" 200 3866\nbeach.sctc.com - - [28/Aug/1995:18:04:09 -0400] \"GET /pub/rjgula/network.htm HTTP/1.0\" 200 2017\nuser.8.30.dcccd.edu - - [28/Aug/1995:18:08:14 -0400] \"GET /atomicbk/promo/promo.html HTTP/1.0\" 200 1657\nstout.Stanford.EDU - - [28/Aug/1995:18:13:09 -0400] \"GET /khem/cgi-bin/odometer.xbm HTTP/1.0\" 500 305\nsopines210.nando.net - - [28/Aug/1995:18:18:00 -0400] \"GET /pub/sshay/about.html HTTP/1.0\" 200 18751\nnwchi-d153.net.interaccess.com - - [28/Aug/1995:18:21:33 -0400] \"GET /pub/k2/am4x44u/gifs/jzj.gif HTTP/1.0\" 200 2351\nfciris9.NCIFCRF.GOV - - [28/Aug/1995:18:24:55 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\nhamelwp1.nu.com - - [28/Aug/1995:18:29:14 -0400] \"GET /pub/sshay/images/jaseeddy.gif HTTP/1.0\" 200 9455\nelizabeth.lighthouse.com - - [28/Aug/1995:18:33:27 -0400] \"GET /pub/ahasuer/heinlein/stinkeroos.html HTTP/1.0\" 200 1096\nprpayne-ppp.clark.net - - [28/Aug/1995:18:37:21 -0400] \"GET /pub/shows/starback.gif HTTP/1.0\" 200 2053\nngriffin.itc.gu.edu.au - - [28/Aug/1995:18:42:37 -0400] \"GET /pub/amacks/Pages/misc/hot.gif HTTP/1.0\" 200 1007\nlagrange.pnl.gov - - [28/Aug/1995:18:46:51 -0400] \"GET /pub/job/vk/view27.jpg HTTP/1.0\" 200 6611\nfs-jupiter.fvh.csc.com - - [28/Aug/1995:18:51:46 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\npilot4.clark.net - - [28/Aug/1995:18:56:58 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 304 -\npeg1-ts1.peganet.com - - [28/Aug/1995:19:02:40 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\nsucceed.engnet.ufl.edu - - [28/Aug/1995:19:07:02 -0400] \"GET /pub/jeffd/cgi-bin/dodger.html HTTP/1.0\" 200 76656\nbfas02.fas.okstate.edu - - [28/Aug/1995:19:12:59 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\ncla-jvirts.unl.edu - - [28/Aug/1995:19:17:18 -0400] \"GET /pub/lupine/images/tlk/pride-rock.gif HTTP/1.0\" 200 51600\nline106.worldweb.net - - [28/Aug/1995:19:21:22 -0400] \"GET /pub/robert/rain_l~1.gif HTTP/1.0\" 200 2243\ndoenx-452-2.Lib.Berkeley.EDU - - [28/Aug/1995:19:25:09 -0400] \"GET /pub/jgbustam/toros/toroglos.html HTTP/1.0\" 200 20302\ninfo1.lancs.ac.uk - - [28/Aug/1995:19:29:02 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nwww-a1.proxy.aol.com - - [28/Aug/1995:19:33:45 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\nuranus40.terraport.net - - [28/Aug/1995:19:37:56 -0400] \"GET /pub/atomicbk/images/tease.gif HTTP/1.0\" 200 43516\ntrusty.lmsc.lockheed.com - - [28/Aug/1995:19:43:40 -0400] \"GET /pub/howie/OO/construc.gif HTTP/1.0\" 200 252\nhawaii-5.u.aloha.net - - [28/Aug/1995:19:48:28 -0400] \"GET /pub/jeffd/cgi-bin/ngquote.html HTTP/1.0\" 200 1564\nbeauty.fnet.cs.mci.com - - [28/Aug/1995:19:54:37 -0400] \"GET /pub/atomicbk/catalog/pinup.html HTTP/1.0\" 200 8316\nslip-14-9.ots.utexas.edu - - [28/Aug/1995:19:59:17 -0400] \"GET /pub/job/vk/view06.jpg HTTP/1.0\" 200 6553\norpheus.amdahl.com - - [28/Aug/1995:20:05:03 -0400] \"GET /pub/job/swim/v-44.jpg HTTP/1.0\" 200 2483\nyukon.econ.ucsb.edu - - [28/Aug/1995:20:10:58 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\n128.102.143.208 - - [28/Aug/1995:20:15:37 -0400] \"GET /pub/job/swim/v-45.jpg HTTP/1.0\" 200 2531\n205.133.11.40 - - [28/Aug/1995:20:22:01 -0400] \"GET /network/graphics/sps.logo.gif HTTP/1.0\" 200 3134\npanopticon.vnet.net - - [28/Aug/1995:20:27:09 -0400] \"GET /pub/rasputin/www/buttons/DocsRightArrow.gif HTTP/1.0\" 200 1273\nlh023-776102.ucs.indiana.edu - - [28/Aug/1995:20:32:02 -0400] \"GET /pub/jeffd/grayball.gif HTTP/1.0\" 200 995\nchrivb01.cch.com - - [28/Aug/1995:20:36:12 -0400] \"GET /pub/jumpsam/index.htm HTTP/1.0\" 200 3107\nwww-b1.proxy.aol.com - - [28/Aug/1995:20:42:42 -0400] \"GET /pub/k2/am4x44u/gifs/redball.gif HTTP/1.0\" 200 206\nwww-c4.proxy.aol.com - - [28/Aug/1995:20:49:01 -0400] \"GET /pub/networx/autopage/autopage.html HTTP/1.0\" 304 -\nsaturn202.terraport.net - - [28/Aug/1995:20:54:21 -0400] \"GET /ntp/ecit/ecitlog1.gif HTTP/1.0\" 200 4952\nin27.inetnebr.com - - [28/Aug/1995:20:59:48 -0400] \"GET /pub/jeffd/feedback.html HTTP/1.0\" 200 1911\n204.119.181.214 - - [28/Aug/1995:21:05:23 -0400] \"GET /pub/job/vk/vk-ad-32.jpg HTTP/1.0\" 200 59411\n204.119.181.214 - - [28/Aug/1995:21:11:15 -0400] \"GET /pub/job/swim/v-57.jpg HTTP/1.0\" 200 2717\n204.255.177.3 - - [28/Aug/1995:21:16:08 -0400] \"GET /pub/russadam/cgi-bin/textbase.cgi?COMMAND=DOSEARCH&FIELDS=Company%2CAddress%2CCity%2CState%2CZip%2CPhone%2CFax%0A&FILENAME=idname2.txt&TITLE=BarCode+1+Company+Name+Search&HTMLFILE=%2Fhomea%2Fftp%2Fpub%2Frussadam%2Fcobase.html&HTMLURL=http%3A%2F%2Fwww.adams1.com%2Fpub%2Frussadam%2Fcobase.html&PAGENAME=test.html&DISPLAYKEY=0%2C1%2C2%2C3%2C4%2C5%2C6%2C&ENDINGKEY=BR%2CBR%2CCS%2CS%2CBR%2CS%2CBR%2C&SEARCHKEY=0%2C3%2C&PROMPTKEY=Company+Name%2CState%2C&DPROMPTKEY=%2C%2C%2C%2C%2CPhone%2CFax%2C&TYPEKEY=T%2CL2%2C&CHKVALUEKEY=YES%2CYES%2C&L1VALUEKEY=%2C%2C&ANDOR=OR&FS0=Y&SV0=&FS3=Y&SV3=NY HTTP/1.0\" 200 450\nwww-b5.proxy.aol.com - - [28/Aug/1995:21:21:05 -0400] \"GET /pub/rj/INDEX.HTM HTTP/1.0\" 200 146936\nSTLGATE.ALMADEN.IBM.COM - - [28/Aug/1995:21:25:12 -0400] \"GET /pub/sshay/partner.html HTTP/1.0\" 200 7065\nRSC535.smumn.edu - - [28/Aug/1995:21:29:12 -0400] \"GET /pub/job/vk/v-line.gif HTTP/1.0\" 200 1254\npc2571.Princeton.EDU - - [28/Aug/1995:21:35:26 -0400] \"GET /pub/job/swim/v-51.jpg HTTP/1.0\" 200 2574\n202.24.142.160 - - [28/Aug/1995:21:41:06 -0400] \"GET /pub/job/vk/view29.jpg HTTP/1.0\" 200 6695\nslip34-211.il.us.ibm.net - - [28/Aug/1995:21:46:15 -0400] \"GET /pub/atomicbk/email.gif HTTP/1.0\" 200 756\ndip-24.mbay.net - - [28/Aug/1995:21:51:17 -0400] \"GET /printing/ HTTP/1.0\" 200 669\nmsp7-8.nas.MR.Net - - [28/Aug/1995:21:57:07 -0400] \"GET /pub/lupine/www/other-disney.html HTTP/1.0\" 200 17386\nhlm03.itc.uiowa.edu - - [28/Aug/1995:22:02:10 -0400] \"GET /pub/aztec/hans/hc43-03z.gif HTTP/1.0\" 200 5602\n199.199.168.44 - - [28/Aug/1995:22:07:52 -0400] \"GET /pub/ashp/grafx/guest.gif HTTP/1.0\" 200 1171\ndal17.onramp.net - - [28/Aug/1995:22:13:26 -0400] \"GET /graphics/lh7.gif HTTP/1.0\" 200 23642\nathena.veritas.com - - [28/Aug/1995:22:18:03 -0400] \"GET /pub/ibos/dollar.gif HTTP/1.0\" 200 1014\nitg.itg.net - - [28/Aug/1995:22:22:36 -0400] \"GET /pub/alweiner/cgi-bin/homepage.html?viewsrc2 HTTP/1.0\" 200 2565\nwww-a1.proxy.aol.com - - [28/Aug/1995:22:28:04 -0400] \"GET /atomicbk/orderform.html HTTP/1.0\" 200 4540\nix-lou-ky1-03.ix.netcom.com - - [28/Aug/1995:22:35:03 -0400] \"GET /pub/jeffd/header.gif HTTP/1.0\" 200 24376\n164.110.101.235 - - [28/Aug/1995:22:41:03 -0400] \"GET /pub/listserv/lsedu1.html HTTP/1.0\" 200 49944\n131.115.140.171 - - [28/Aug/1995:22:45:40 -0400] \"GET /pub/job/vk/view36.jpg HTTP/1.0\" 200 3522\ntgif.bradley.edu - - [28/Aug/1995:22:51:54 -0400] \"GET /pub/job/vk/view31.jpg HTTP/1.0\" 200 5611\npiweba4y.prodigy.com - - [28/Aug/1995:22:57:54 -0400] \"GET /pub/mbrophy/pix/address.jpg HTTP/1.0\" 304 -\nCust11.Max1.San-Francisco.CA.MS.UU.NET - - [28/Aug/1995:23:03:12 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\npppa095.compuserve.com - - [28/Aug/1995:23:09:46 -0400] \"GET /pub/mbrophy/pix/holly.jpg HTTP/1.0\" 200 4840\nad03-023.compuserve.com - - [28/Aug/1995:23:15:01 -0400] \"GET /pub/lwallach/me.html HTTP/1.0\" 200 719\nlimnos.wes.army.mil - - [28/Aug/1995:23:21:37 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\nict56.southwind.net - - [28/Aug/1995:23:25:47 -0400] \"GET /pub/rsjdfg/Images/MissSaigon.gif HTTP/1.0\" 200 21560\nindy1.indy.net - - [28/Aug/1995:23:31:18 -0400] \"GET /pub/job/swim/v-51.jpg HTTP/1.0\" 200 2574\ncs125-11.u.washington.edu - - [28/Aug/1995:23:35:45 -0400] \"GET /pub/k2/cgi-bin/imagemap/events?251,93 HTTP/1.0\" 302 102\nPC11134.GSIA.CMU.EDU - - [28/Aug/1995:23:40:27 -0400] \"GET /atomicbk/logo2.gif HTTP/1.0\" 200 12871\n130.127.26.67 - - [28/Aug/1995:23:46:23 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\nDIALIP128.GOV.BC.CA - - [28/Aug/1995:23:51:33 -0400] \"GET /atomicbk/catalog/emboss.jpg HTTP/1.0\" 200 4741\nppp20.tcs.tulane.edu - - [28/Aug/1995:23:57:47 -0400] \"HEAD /pub/robert/ HTTP/1.0\" 200 1992\nforth.microserve.com - - [29/Aug/1995:00:05:26 -0400] \"GET /pub/rarnold/firesign/passport.wav HTTP/1.0\" 200 53390\namf3.res.Lehigh.EDU - - [29/Aug/1995:00:11:19 -0400] \"GET /pub/job/swim/swim.jpg HTTP/1.0\" 200 15234\nmiriworld.its.unimelb.EDU.AU - - [29/Aug/1995:00:17:29 -0400] \"GET /pub/job/vk/view01.jpg HTTP/1.0\" 304 -\nwww-d3.proxy.aol.com - - [29/Aug/1995:00:25:31 -0400] \"GET /pub/mikebilt/feldie.jpg HTTP/1.0\" 200 6808\npiweba3y.prodigy.com - - [29/Aug/1995:00:32:08 -0400] \"GET /pub/downin/cgi-bin/arlonet.html HTTP/1.0\" 200 4339\n137.112.203.144 - - [29/Aug/1995:00:39:34 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\nwww-b2.proxy.aol.com - - [29/Aug/1995:00:45:33 -0400] \"GET /pub/edseiler/WWW/asimov_FAQ.html HTTP/1.0\" 304 -\ngarlic.cchem.berkeley.edu - - [29/Aug/1995:00:52:05 -0400] \"GET /pub/sshay/images/chris1.jpg HTTP/1.0\" 200 13306\ndialup8.woodtech.com - - [29/Aug/1995:00:59:19 -0400] \"GET /pub/job/swim/v-50.jpg HTTP/1.0\" 200 3369\ns330250.slip.cc.uq.oz.au - - [29/Aug/1995:01:05:37 -0400] \"GET /pub/global/search.html HTTP/1.0\" 304 -\nhost29.cyberg8t.com - - [29/Aug/1995:01:11:47 -0400] \"GET /pub/rsjdfg/Links.html HTTP/1.0\" 200 1632\ncs13port.netvoyage.net - - [29/Aug/1995:01:19:23 -0400] \"GET /pub/wilsey/cat31.html HTTP/1.0\" 200 62906\nF182-077.net.wisc.edu - - [29/Aug/1995:01:27:07 -0400] \"GET /pub/rsjdfg/Images/Saigon.gif HTTP/1.0\" 200 16721\ncrosslnk.cts.com - - [29/Aug/1995:01:34:35 -0400] \"GET /pub/alweiner/color_sw.gif HTTP/1.0\" 200 1645\npm59.ilhawaii.net - - [29/Aug/1995:01:42:31 -0400] \"GET /pub/sshay/images/rainlin2.gif HTTP/1.0\" 200 1229\n165.113.187.61 - - [29/Aug/1995:01:50:15 -0400] \"GET /pub/job/swim/s-back3.jpg HTTP/1.0\" 200 5118\n200.23.36.61 - - [29/Aug/1995:01:57:44 -0400] \"GET /atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6688\nTS9-41.UPENN.EDU - - [29/Aug/1995:02:07:03 -0400] \"POST /pub/alweiner/cgi-bin/w3magic.cgi?-f|color HTTP/1.0\" 200 121\n204.112.94.55 - - [29/Aug/1995:02:15:30 -0400] \"GET /atomicbk/images/angie.gif HTTP/1.0\" 200 33638\npm82.sonic.net - - [29/Aug/1995:02:24:12 -0400] \"GET /pub/atomicbk/catalog/adultcom.html HTTP/1.0\" 200 8705\nz06125.iie.org.mx - - [29/Aug/1995:02:29:45 -0400] \"GET /atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nwww-b3.proxy.aol.com - - [29/Aug/1995:02:36:54 -0400] \"GET /pub/job/vk/view22.jpg HTTP/1.0\" 304 -\nklothos.crl.research.digital.com - - [29/Aug/1995:02:46:13 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\nn115.solano.community.net - - [29/Aug/1995:02:54:26 -0400] \"GET /pub/quaker/web/archive.html HTTP/1.0\" 200 8865\nThomas6-12.FandM.edu - - [29/Aug/1995:03:04:57 -0400] \"GET /atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\nhopi2.ResComp.Arizona.EDU - - [29/Aug/1995:03:18:46 -0400] \"GET /atomicbk/new/logo2.gif HTTP/1.0\" 200 12871\nwww-b2.proxy.aol.com - - [29/Aug/1995:03:29:52 -0400] \"GET /pub/sshay/gallery.html HTTP/1.0\" 200 2101\nkb1165.konbib.nl - - [29/Aug/1995:03:41:32 -0400] \"GET /pub/lschank/web/fwd.gif HTTP/1.0\" 200 275\ntuz.isf.ru - - [29/Aug/1995:03:53:10 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 14969\nclient23.sct.fr - - [29/Aug/1995:04:06:23 -0400] \"GET /pub/murple/gifs/button.www.gif HTTP/1.0\" 200 358\nslip-48-8.ots.utexas.edu - - [29/Aug/1995:04:18:38 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nmpngate1.ny.us.ibm.net - - [29/Aug/1995:04:33:40 -0400] \"GET /pub/job/swim/swim.jpg HTTP/1.0\" 200 15234\nnttcsa.tas.NTT.JP - - [29/Aug/1995:04:48:25 -0400] \"GET /pub/fan/pics/ManyMakiS.jpg HTTP/1.0\" 200 6792\nalweiner.clark.net - - [29/Aug/1995:05:01:37 -0400] \"GET /pub/alweiner/home.gif HTTP/1.0\" 200 372\n194.170.2.47 - - [29/Aug/1995:05:16:47 -0400] \"GET /atomicbk/catalog/zines.html HTTP/1.0\" 200 2968\n194.170.2.47 - - [29/Aug/1995:05:26:39 -0400] \"GET /pub/atomicbk/userlink.gif HTTP/1.0\" 200 816\n194.20.202.222 - - [29/Aug/1995:05:39:28 -0400] \"GET /atomicbk/catalog/new.gif HTTP/1.0\" 200 744\nnovi.auc.dk - - [29/Aug/1995:05:51:29 -0400] \"GET /pub/job/vk/vk-ad-10.jpg HTTP/1.0\" 200 53676\npearl.cs.umu.se - - [29/Aug/1995:06:03:24 -0400] \"GET /pub/howie/OO/oo_home.html HTTP/1.0\" 200 989\n199.100.193.14 - - [29/Aug/1995:06:17:37 -0400] \"GET /pub/peace/PC1.map?116,53 HTTP/1.0\" 302 226\nix-gra2-09.ix.netcom.com - - [29/Aug/1995:06:30:32 -0400] \"GET /pub/jeffd/question.html HTTP/1.0\" 200 56585\nchiak.kaist.ac.kr - - [29/Aug/1995:06:43:00 -0400] \"GET /pub/sshay/images/btthumb.jpg HTTP/1.0\" 200 4624\nhardy.ocs.mq.edu.au - - [29/Aug/1995:06:52:04 -0400] \"GET /pub/rsjdfg/ HTTP/1.0\" 200 2109\n130.237.148.200 - - [29/Aug/1995:07:00:37 -0400] \"GET /pub/job/vk/view27.jpg HTTP/1.0\" 200 6611\nlotte.lmaster.u-bordeaux.fr - - [29/Aug/1995:07:09:41 -0400] \"GET /pub/aztec/shesails/sslogo2.gif HTTP/1.0\" 200 7214\nigate.nrc.gov - - [29/Aug/1995:07:21:11 -0400] \"GET /pub/job/vk/view24.jpg HTTP/1.0\" 200 6209\nisr1101.urh.uiuc.edu - - [29/Aug/1995:07:29:58 -0400] \"GET /atomicbk/shocked/shocked.jpg HTTP/1.0\" 200 43819\neast.ge.com - - [29/Aug/1995:07:38:31 -0400] \"GET /pub/networx/autopage/dealers/de002_ba.gif HTTP/1.0\" 200 62639\nkaz2.chem.s.u-tokyo.ac.jp - - [29/Aug/1995:07:47:45 -0400] \"GET /pub/atomicbk/images/axfords.gif\" 200 47332\nannap2.jsc.mil - - [29/Aug/1995:07:56:55 -0400] \"GET /home.html HTTP/1.0\" 304 -\n131.85.81.10 - - [29/Aug/1995:08:05:21 -0400] \"GET /pub/mmathai/mls/dcmls.html HTTP/1.0\" 200 3831\n164.9.127.22 - - [29/Aug/1995:08:13:16 -0400] \"GET /pub/job/vk/view11.jpg HTTP/1.0\" 200 5001\n133.50.75.49 - - [29/Aug/1995:08:20:27 -0400] \"GET /atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6688\n140.112.52.180 - - [29/Aug/1995:08:27:25 -0400] \"GET /pub/phil/WinonaRyder/articles/EntertainmentWeekly.27Jan95.html HTTP/1.0\" 200 1205\ngatekeeper.mitre.org - - [29/Aug/1995:08:32:54 -0400] \"GET /pub/gen/fas/irp/offdocs.htm HTTP/1.0\" 200 2654\nedslink.eds.com - - [29/Aug/1995:08:39:51 -0400] \"GET /pub/job/vk/view18.jpg HTTP/1.0\" 200 6578\nroland.univ-rennes1.fr - - [29/Aug/1995:08:44:16 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 304 -\nns.sis.steria.fr - - [29/Aug/1995:08:50:50 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 14969\nosk0155.bekkoame.or.jp - - [29/Aug/1995:08:56:45 -0400] \"GET /pub/sshay/images/home6.gif HTTP/1.0\" 200 58652\n194.17.131.6 - - [29/Aug/1995:09:01:56 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 304 -\n165.13.35.100 - - [29/Aug/1995:09:07:23 -0400] \"GET /pub/job/vk/view33.jpg HTTP/1.0\" 200 5903\nmacsim1.sim.ucm.es - - [29/Aug/1995:09:13:48 -0400] \"GET /pub/jgbustam/coloquio/jb.html HTTP/1.0\" 200 338\nmaine.sdi.agate.net - - [29/Aug/1995:09:19:30 -0400] \"GET /pub/robert/past99.gif HTTP/1.0\" 200 4993\ngandalf2.ccm.itesm.mx - - [29/Aug/1995:09:26:35 -0400] \"GET /pub/gorbachev/gorbglobe.jpg HTTP/1.0\" 200 4646\nentek1.entek.chalmers.se - - [29/Aug/1995:09:32:17 -0400] \"GET /pub/job/vk/view20.jpg HTTP/1.0\" 200 5070\nwww.its.it - - [29/Aug/1995:09:36:45 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\njwolff.clark.net - - [29/Aug/1995:09:41:21 -0400] \"GET /pub/jwolff/cki/secret/secret.html HTTP/1.0\" 403 142\nrosamond.tacsim.com - - [29/Aug/1995:09:45:45 -0400] \"GET /pub/wsg/html/jan/ HTTP/1.0\" 200 476\nfourier.civil.gla.ac.uk - - [29/Aug/1995:09:51:20 -0400] \"GET /pub/alweiner/snip.gif HTTP/1.0\" 200 369\n165.173.39.252 - - [29/Aug/1995:09:57:57 -0400] \"GET /pub/wmcbrine/html/Madonna.html HTTP/1.0\" 200 13440\ncrockett1d.its.rpi.edu - - [29/Aug/1995:10:03:41 -0400] \"GET /pub/atomicbk/images/sorayama.gif HTTP/1.0\" 404 335\nh_adept.roanoke.infi.net - - [29/Aug/1995:10:08:15 -0400] \"GET /html/usage/usage.graph.small.gif HTTP/1.0\" 200 145\nyarrow.wt.com.au - - [29/Aug/1995:10:13:29 -0400] \"GET /pub/job/vk/view32.jpg HTTP/1.0\" 200 4852\nix-sj28-02.ix.netcom.com - - [29/Aug/1995:10:17:37 -0400] \"POST /theme/cgi-bin/serchstr.html HTTP/1.0\" 200 999\nkalv99.ubt.unit.no - - [29/Aug/1995:10:22:24 -0400] \"GET /pub/job/vk/vk-ad-28.jpg HTTP/1.0\" 200 44081\nsun20.ccd.bnl.gov - - [29/Aug/1995:10:26:34 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\nmtrsppp49.epix.net - - [29/Aug/1995:10:31:51 -0400] \"GET /pub/alweiner/blue.gif HTTP/1.0\" 200 148\nbettong.client.uq.oz.au - - [29/Aug/1995:10:37:24 -0400] \"GET /pub/wick/other_queer.html HTTP/1.0\" 200 2498\ngsv.gu.se - - [29/Aug/1995:10:42:22 -0400] \"GET /pub/job/vk/view34.jpg HTTP/1.0\" 200 5156\nharold.nrl.navy.mil - - [29/Aug/1995:10:46:22 -0400] \"GET /pub/wick/misc/clarknet.gif HTTP/1.0\" 200 3937\nHEPHP02.PHYS.UTK.EDU - - [29/Aug/1995:10:49:35 -0400] \"GET /pub/job/vk/view24.jpg HTTP/1.0\" 200 6209\n193.12.239.220 - - [29/Aug/1995:10:53:19 -0400] \"GET /pub/phil/images/jh21.gif HTTP/1.0\" 200 3021\nstanbk.pr.mcs.net - - [29/Aug/1995:10:57:02 -0400] \"GET /pub/lschank/web/redball.gif HTTP/1.0\" 200 326\nwebb.pc.uamont.edu - - [29/Aug/1995:11:01:34 -0400] \"GET /pub/linda/fcr/mouthful.jpg HTTP/1.0\" 200 31963\npiweba3y.prodigy.com - - [29/Aug/1995:11:06:36 -0400] \"GET /pub/jgbustam/gifs/coloico2.gif HTTP/1.0\" 304 -\nmencel.healthspan.edu - - [29/Aug/1995:11:11:48 -0400] \"GET /pub/mjoneill/links.html HTTP/1.0\" 404 346\nwalters.aiss.uiuc.edu - - [29/Aug/1995:11:15:53 -0400] \"GET /pub/pribut/spsport.html HTTP/1.0\" 200 3589\nin116.brann.co.uk - - [29/Aug/1995:11:19:59 -0400] \"GET /pub/k2/am4x44u/gifs/jjbg2.jpg HTTP/1.0\" 200 169367\nmacomb.lib.mi.us - - [29/Aug/1995:11:24:55 -0400] \"GET /pub/cargui/search.html HTTP/1.0\" 200 2848\ntongkey.kol.co.kr - - [29/Aug/1995:11:30:20 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\n149.157.246.44 - - [29/Aug/1995:11:35:31 -0400] \"GET /pub/k2/am4x44u/gifs/jjbg2.jpg HTTP/1.0\" 200 169367\n194.170.2.64 - - [29/Aug/1995:11:39:28 -0400] \"GET /pub/job/vk/claudia.jpg HTTP/1.0\" 200 7225\nturbodog.edoc.com - - [29/Aug/1995:11:44:30 -0400] \"GET /pub/craver/surreal/surreal.html HTTP/1.0\" 200 1479\nwww.npd.com - - [29/Aug/1995:11:49:08 -0400] \"GET /pub/k2/am4x44u/gifs/scut.gif HTTP/1.0\" 200 1404\ndatan.sk.uppsala.se - - [29/Aug/1995:11:52:50 -0400] \"GET /pub/job/vk/view20.jpg HTTP/1.0\" 200 5070\nsndaniel.reston.ingr.com - - [29/Aug/1995:11:56:58 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 14969\nleithaus.leitess.com - - [29/Aug/1995:12:02:04 -0400] \"GET /graphics/winerack.gif HTTP/1.0\" 200 21475\n136.181.50.23 - - [29/Aug/1995:12:06:10 -0400] \"GET /pub/job/vk/view28.jpg HTTP/1.0\" 200 4594\ndresden.bmc.com - - [29/Aug/1995:12:11:18 -0400] \"GET /pub/alweiner/backgrounds/brushedy.gif HTTP/1.0\" 404 335\n140.218.3.63 - - [29/Aug/1995:12:15:28 -0400] \"GET /pub/job/swim/v-44.jpg HTTP/1.0\" 200 2483\nG7257.258.InterLink.NET - - [29/Aug/1995:12:19:14 -0400] \"GET /pub/peace/note.gif HTTP/1.0\" 200 565\nl2-24.en.net - - [29/Aug/1995:12:22:44 -0400] \"GET /pub/sshay/images/home6.gif HTTP/1.0\" 200 58652\n128.192.114.66 - - [29/Aug/1995:12:26:36 -0400] \"GET /pub/jeffd/header.gif HTTP/1.0\" 200 24376\nwww-b4.proxy.aol.com - - [29/Aug/1995:12:31:18 -0400] \"GET /atomicbk/images/girlvsgir.gif HTTP/1.0\" 200 28352\nix-sac5-02.ix.netcom.com - - [29/Aug/1995:12:35:18 -0400] \"GET /pub/jeffd/smreagan.gif HTTP/1.0\" 200 18018\nrheo.matse.fukui-u.ac.jp - - [29/Aug/1995:12:38:45 -0400] \"GET /atomicbk/catalog/adultcom.html HTTP/1.0\" 200 8705\n204.217.208.177 - - [29/Aug/1995:12:42:31 -0400] \"GET /pub/howie/OO/home.gif HTTP/1.0\" 200 1040\nnewsgw.mentorg.com - - [29/Aug/1995:12:46:12 -0400] \"GET /pub/job/vk/view24.jpg HTTP/1.0\" 200 6209\narajkuma.worldbank.org - - [29/Aug/1995:12:49:37 -0400] \"GET /pub/alweiner/cgi-bin/homepage.html?game+0 HTTP/1.0\" 200 2159\naria.softlab.is.tsukuba.ac.jp - - [29/Aug/1995:12:53:18 -0400] \"GET /pub/sshay/images/galybutn.gif HTTP/1.0\" 200 1080\ncharlotte.anu.edu.au - - [29/Aug/1995:12:56:28 -0400] \"GET /pub/temonk/heavwww.htm HTTP/1.0\" 200 2005\nna1.dow.com - - [29/Aug/1995:13:00:18 -0400] \"GET /pub/jeffd/95-61.gif HTTP/1.0\" 200 31982\n130.134.32.30 - - [29/Aug/1995:13:03:33 -0400] \"GET /pub/job/theman.jpg HTTP/1.0\" 200 8905\n204.156.15.7 - - [29/Aug/1995:13:07:21 -0400] \"GET /pub/lemat/i/excom3.gif HTTP/1.0\" 200 76371\n206.25.44.45 - - [29/Aug/1995:13:10:55 -0400] \"GET /pub/atomicbk/artgal.gif HTTP/1.0\" 200 823\nrheo.matse.fukui-u.ac.jp - - [29/Aug/1995:13:14:13 -0400] \"GET /pub/atomicbk/images/forcedw.gif HTTP/1.0\" 200 77512\ncluster-61.cluster.brown.edu - - [29/Aug/1995:13:18:30 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nad15-045.compuserve.com - - [29/Aug/1995:13:21:50 -0400] \"GET /pub/rmharris/alldlrs/mw/60657bea.html HTTP/1.0\" 200 2074\nGATEKEEPER.HCC.COM - - [29/Aug/1995:13:25:53 -0400] \"GET /pub/jeffd/grad_lin.gif HTTP/1.0\" 200 3346\nvccnw11.its.rpi.edu - - [29/Aug/1995:13:29:14 -0400] \"GET /pub/job/swim/v-50.jpg HTTP/1.0\" 200 3369\ngatekeeper.mitre.org - - [29/Aug/1995:13:33:04 -0400] \"GET /atomicbk/catalog/catalog.html HTTP/1.0\" 200 4654\ncmgraham.nexus.olemiss.edu - - [29/Aug/1995:13:37:14 -0400] \"GET /pub/cardman/1curious.gif HTTP/1.0\" 200 1281\nvoliver.adp.iastate.edu - - [29/Aug/1995:13:41:01 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\nnd015181.global.medtronic.COM - - [29/Aug/1995:13:44:47 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\ngateway.amoco.com - - [29/Aug/1995:13:48:08 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\nhpws92.hctg.SAIC.COM - - [29/Aug/1995:13:52:08 -0400] \"GET /pub/jeffd/dole.gif HTTP/1.0\" 200 4364\nts-h08-15-17.ucc.su.OZ.AU - - [29/Aug/1995:13:55:37 -0400] \"GET /pub/jeffd/paper.gif HTTP/1.0\" 200 20354\noirp-pc3.admin.umass.edu - - [29/Aug/1995:13:59:09 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nbaloo.dc.luth.se - - [29/Aug/1995:14:03:21 -0400] \"GET /pub/bell/review/bullet/grn_bullet_half.gif HTTP/1.0\" 200 546\nkmims.mindspring.com - - [29/Aug/1995:14:06:56 -0400] \"GET /pub/alweiner/castle_w.gif HTTP/1.0\" 200 1082\nwwwproxy2.ca.sandia.gov - - [29/Aug/1995:14:10:46 -0400] \"GET /pub/rjgula/os/windows/nasaccml.txt HTTP/1.0\" 200 766\nba_bowers.pnl.gov - - [29/Aug/1995:14:13:59 -0400] \"GET /pub/k2/am4x44u/maps/truck_stop.gif HTTP/1.0\" 200 37573\neuro.sunbee.co.kr - - [29/Aug/1995:14:17:06 -0400] \"GET /pub/atomicbk/promo.gif HTTP/1.0\" 200 849\ntheoris.rz.uni-konstanz.de - - [29/Aug/1995:14:20:22 -0400] \"GET /atomicbk/seanc.gif HTTP/1.0\" 200 734\nwebgate1.mot.com - - [29/Aug/1995:14:23:33 -0400] \"GET /pub/k2/am4x44u/gifs/yellbut.gif HTTP/1.0\" 200 1160\nwebgate1.mot.com - - [29/Aug/1995:14:27:44 -0400] \"GET /pub/lschank/web/up.gif HTTP/1.0\" 200 264\nr-wilson.estates.gla.ac.uk - - [29/Aug/1995:14:31:28 -0400] \"GET /pub/atomicbk/catalog/pinup.html HTTP/1.0\" 304 -\npiweba1y.prodigy.com - - [29/Aug/1995:14:34:46 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\neblaese.stx.com - - [29/Aug/1995:14:37:53 -0400] \"GET /pub/blaese/image/small_kids.gif HTTP/1.0\" 304 -\npc242.dev.esoc.esa.de - - [29/Aug/1995:14:41:07 -0400] \"GET /pub/lupine/www/images/lines/tan.gif HTTP/1.0\" 304 -\nnetcom9.netcom.com - - [29/Aug/1995:14:43:55 -0400] \"GET /pub/alweiner/work/_0231C.gif HTTP/1.0\" 200 6232\nts-03.marin.k12.ca.us - - [29/Aug/1995:14:47:13 -0400] \"GET /pub/sshay/images/blaksped.gif HTTP/1.0\" 200 3681\n155.229.78.26 - - [29/Aug/1995:14:49:35 -0400] \"GET /graphics/b.gif HTTP/1.0\" 200 1145\nts-03.marin.k12.ca.us - - [29/Aug/1995:14:54:00 -0400] \"GET /pub/sshay/images/tom1.jpg HTTP/1.0\" 200 21336\nnetwork.clark.net - - [29/Aug/1995:14:58:24 -0400] \"GET /network/graphics/ypaper.gif HTTP/1.0\" 200 10782\n141.211.73.171 - - [29/Aug/1995:15:01:41 -0400] \"GET /atomicbk/images/buffy.gif HTTP/1.0\" 200 59956\nmodem014.offcampus.calpoly.edu - - [29/Aug/1995:15:05:34 -0400] \"GET /pub/k2/am4x44u/gifs/scut.gif HTTP/1.0\" 200 1404\n131.218.10.40 - - [29/Aug/1995:15:09:05 -0400] \"GET /pub/downin/html/Graphics/mac.gif HTTP/1.0\" 200 143\nagh008h-1.forestry.okstate.edu - - [29/Aug/1995:15:12:23 -0400] \"GET /pub/peace/PeaceCorps.html HTTP/1.0\" 304 -\ntrout.os.varian.com - - [29/Aug/1995:15:16:57 -0400] \"GET /pub/lschank/web/myguides.html HTTP/1.0\" 200 9435\nst0857.infonet.tufts.edu - - [29/Aug/1995:15:20:21 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nannex-ariel.libraries.psu.edu - - [29/Aug/1995:15:24:04 -0400] \"GET /pub/wmcbrine/html/Madonna.html HTTP/1.0\" 200 13440\npc7069.corp.dialog.com - - [29/Aug/1995:15:28:25 -0400] \"GET /pub/alweiner/reddot.gif HTTP/1.0\" 200 886\nnagy.cs.Colorado.EDU - - [29/Aug/1995:15:32:09 -0400] \"GET /pub/k2/jeep/jxj.htm HTTP/1.0\" 304 -\n134.243.230.103 - - [29/Aug/1995:15:36:42 -0400] \"GET /pub/job/vk/view05.jpg HTTP/1.0\" 200 5012\ngatekeeper.mitre.org - - [29/Aug/1995:15:39:21 -0400] \"GET /atomicbk/catalog/wimmens.html HTTP/1.0\" 200 2612\nMudd169-PC2.ACNS.Carleton.edu - - [29/Aug/1995:15:42:18 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\npfizergate.pfizer.com - - [29/Aug/1995:15:45:56 -0400] \"GET /pub/job/vk/view23.jpg HTTP/1.0\" 200 5165\ngatekeeper.us.oracle.com - - [29/Aug/1995:15:49:23 -0400] \"GET /atomicbk/contest.gif HTTP/1.0\" 200 669\nmty0108.infosel.com.mx - - [29/Aug/1995:15:52:15 -0400] \"GET /pub/k2/am4x44u/maps/truck_stop.gif HTTP/1.0\" 200 37573\ncs500-9.sl013.cns.vt.edu - - [29/Aug/1995:15:55:26 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\n147.234.11.8 - - [29/Aug/1995:15:58:39 -0400] \"GET /atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nmustang.pica.army.mil - - [29/Aug/1995:16:01:52 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\nna3.dow.com - - [29/Aug/1995:16:05:27 -0400] \"GET /pub/job/swim/v-59.jpg HTTP/1.0\" 200 2947\nwavopt431.tbe.com - - [29/Aug/1995:16:09:15 -0400] \"GET /pub/job/vk/view30.jpg HTTP/1.0\" 200 5991\nmcga03.med.nyu.edu - - [29/Aug/1995:16:12:02 -0400] \"GET /pub/sshay/images/partbutn.gif HTTP/1.0\" 200 1085\n137.57.10.239 - - [29/Aug/1995:16:14:48 -0400] \"GET /theme/vrml/media/hr.gif HTTP/1.0\" 404 313\n136.204.3.33 - - [29/Aug/1995:16:17:51 -0400] \"GET /atomicbk/bizlink.gif HTTP/1.0\" 200 726\nlangmuir.engin.umich.edu - - [29/Aug/1995:16:21:05 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\n198.77.113.40 - - [29/Aug/1995:16:24:30 -0400] \"GET /pub/mglamb/ranch/gungifs/paraord.gif HTTP/1.0\" 200 4478\nfas.clark.net - - [29/Aug/1995:16:27:30 -0400] \"GET /pub/gen/mswg/stealth/sky.jpg HTTP/1.0\" 200 1044\nproxy.bellatlantic.com - - [29/Aug/1995:16:30:55 -0400] \"GET /pub/downin/html/arlonet/icons/rbr.GIF HTTP/1.0\" 200 1634\nSOL08.AMS.ORG - - [29/Aug/1995:16:33:07 -0400] \"GET /pub/keating/ri-hs.html HTTP/1.0\" 200 23932\nsndaniel.reston.ingr.com - - [29/Aug/1995:16:36:18 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\nrorke.com - - [29/Aug/1995:16:40:27 -0400] \"GET /pub/rjgula/rongula.gif HTTP/1.0\" 200 22150\nkeyhole.es.dupont.com - - [29/Aug/1995:16:44:29 -0400] \"GET /pub/jeffd/grayball.gif HTTP/1.0\" 304 -\nhalsun.umsl.edu - - [29/Aug/1995:16:47:38 -0400] \"GET /pub/listserv/new.gif HTTP/1.0\" 200 911\nl9.cslab.unf.edu - - [29/Aug/1995:16:50:59 -0400] \"GET /pub/sshay/images/tywetsut.jpg HTTP/1.0\" 200 21652\nddd.tel.kutztown.edu - - [29/Aug/1995:16:54:33 -0400] \"GET /pub/atomicbk/email.gif HTTP/1.0\" 200 756\nra.isy.liu.se - - [29/Aug/1995:16:57:51 -0400] \"GET /pub/job/vk/babe.jpg HTTP/1.0\" 200 8235\n192.127.151.13 - - [29/Aug/1995:17:01:25 -0400] \"GET /html/clarknet.html HTTP/1.0\" 304 -\n20.4.92.52 - - [29/Aug/1995:17:05:12 -0400] \"GET /pub/reichera/rcp.html HTTP/1.0\" 200 5522\nhyh207.phys.andrews.edu - - [29/Aug/1995:17:08:33 -0400] \"GET /pub/job/vk/view18.jpg HTTP/1.0\" 200 6578\nnbdclab-pc02.unomaha.edu - - [29/Aug/1995:17:12:18 -0400] \"GET /pub/jeffd/grayball.gif HTTP/1.0\" 304 -\nnagik.cs.colorado.edu - - [29/Aug/1995:17:15:41 -0400] \"GET /pub/k2/am4x44u/gifs/jxj.gif HTTP/1.0\" 304 -\nAtrium-PC15.INRE.ASU.EDU - - [29/Aug/1995:17:18:50 -0400] \"GET /pub/k2/am4x44u/gifs/greenball.gif HTTP/1.0\" 200 326\nfuller.lance.colostate.edu - - [29/Aug/1995:17:21:56 -0400] \"GET /pub/k2/am4x44u/gifs/netscape.gif HTTP/1.0\" 200 1050\nppp077-stdkn2.ulaval.ca - - [29/Aug/1995:17:24:56 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nwww-b5.proxy.aol.com - - [29/Aug/1995:17:28:56 -0400] \"GET /pub/wick/photos/chair_mini.gif HTTP/1.0\" 200 12589\nxyplex3-5-2.ucs.indiana.edu - - [29/Aug/1995:17:32:12 -0400] \"GET /pub/sshay/interact.html HTTP/1.0\" 200 2732\ne012.unitedway.org - - [29/Aug/1995:17:36:12 -0400] \"GET /pub/pwalker/Internet_in_General/Catalogues_of_Resources/ HTTP/1.0\" 200 6616\nkbt27.library.yale.edu - - [29/Aug/1995:17:40:06 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 14969\n155.82.105.107 - - [29/Aug/1995:17:44:06 -0400] \"GET /pub/atomicbk/new/emboss.jpg HTTP/1.0\" 200 4741\n164.106.121.146 - - [29/Aug/1995:17:48:23 -0400] \"GET /pub/atomicbk/iamges/erotuniv.gif HTTP/1.0\" 404 335\nath-gw7.hol.gr - - [29/Aug/1995:17:52:10 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nU104.ucs.indiana.edu - - [29/Aug/1995:17:56:21 -0400] \"GET /pub/jeffd/bg2.gif HTTP/1.0\" 200 1343\ngorbadoc.leeds.ac.uk - - [29/Aug/1995:17:59:55 -0400] \"GET /pub/job/vk/view01.jpg HTTP/1.0\" 200 5733\nwww-ea.proxy.aol.com - - [29/Aug/1995:18:03:08 -0400] \"GET /pub/wsg/html/jan/ HTTP/1.0\" 200 476\nac079.du.pipex.com - - [29/Aug/1995:18:07:28 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\ndialup10.Bloomington.mci.net - - [29/Aug/1995:18:11:39 -0400] \"GET /pub/jeffd/smreagan.gif HTTP/1.0\" 200 18018\nasd01-21.dial.xs4all.nl - - [29/Aug/1995:18:15:35 -0400] \"GET /pub/networx/autopage/dealers/de001_3b.gif HTTP/1.0\" 200 70257\ndal09-25.ppp.iadfw.net - - [29/Aug/1995:18:20:00 -0400] \"GET /pub/wick/misc/newsign.gif HTTP/1.0\" 200 20279\nwebgate1.mot.com - - [29/Aug/1995:18:23:29 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nsmartwall.acuson.com - - [29/Aug/1995:18:26:48 -0400] \"GET /pub/job/swim/v-56.jpg HTTP/1.0\" 304 -\n142.36.134.52 - - [29/Aug/1995:18:31:44 -0400] \"GET /pub/abaa-booknet/images/at_work.gif HTTP/1.0\" 200 244\nn73h003.nlnet.nf.ca - - [29/Aug/1995:18:35:57 -0400] \"GET /pub/atomicbk/direct.gif HTTP/1.0\" 200 833\n128.196.127.24 - - [29/Aug/1995:18:40:34 -0400] \"GET /pub/jeffd/header.gif HTTP/1.0\" 200 24376\n138.92.11.26 - - [29/Aug/1995:18:44:59 -0400] \"GET /pub/jgbustam/gifs/coloico2.gif HTTP/1.0\" 200 4298\nreapc.b20.ingr.com - - [29/Aug/1995:18:49:20 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 14969\nmartini-1.ics.Hawaii.Edu - - [29/Aug/1995:18:53:42 -0400] \"GET /pub/BlackMagic/ses/snake.gif HTTP/1.0\" 200 51324\nsmcvax.smcvt.edu - - [29/Aug/1995:18:58:09 -0400] \"GET / HTTP/1.0\" 200 1834\nnoir.kpnw.org - - [29/Aug/1995:19:02:17 -0400] \"GET /home/oncrhome.gif HTTP/1.0\" 200 12126\nMCNPPP157.MCN.NET - - [29/Aug/1995:19:05:48 -0400] \"GET /pub/job/vk/view36.jpg HTTP/1.0\" 200 3522\n156.39.124.71 - - [29/Aug/1995:19:09:06 -0400] \"GET /pub/bell/review/image/5percsmt.gif HTTP/1.0\" 200 2321\n128.180.113.1 - - [29/Aug/1995:19:12:46 -0400] \"GET /pub/atomicbk/kathman/nra5.gif HTTP/1.0\" 200 10127\nfrogfoot.dsto.defence.gov.au - - [29/Aug/1995:19:17:06 -0400] \"GET /pub/rmharris/catalogs.html HTTP/1.0\" 200 6164\nwww-tdo.lanl.gov - - [29/Aug/1995:19:21:19 -0400] \"GET /pub/wine/spinbt.gif HTTP/1.0\" 200 1050\ntlaloc.nb.com - - [29/Aug/1995:19:26:11 -0400] \"GET /pub/job/swim/v-52.jpg HTTP/1.0\" 200 2886\nh_adherent.roanoke.infi.net - - [29/Aug/1995:19:30:48 -0400] \"GET /pub/k2/am4x44u/gifs/bggrey.jpg HTTP/1.0\" 304 -\nmn00170w-726419.mcnutt.indiana.edu - - [29/Aug/1995:19:34:51 -0400] \"GET /pub/jeffd/paper.gif HTTP/1.0\" 200 20354\nalweiner.clark.net - - [29/Aug/1995:19:39:18 -0400] \"GET /pub/alweiner/cgi-bin/squiggle.cgi?w3magic1 HTTP/1.0\" 200 4467\nkebab.infomatch.com - - [29/Aug/1995:19:45:09 -0400] \"GET /pub/sshay/images/tywetsut.jpg HTTP/1.0\" 200 21652\ndd19-045.compuserve.com - - [29/Aug/1995:19:50:27 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\ngate.tv2.no - - [29/Aug/1995:19:55:17 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\nslip4.pixel.com.mx - - [29/Aug/1995:20:00:18 -0400] \"GET /pub/fervor/bob3.gif HTTP/1.0\" 200 20679\ncragateway.cra.com.au - - [29/Aug/1995:20:05:53 -0400] \"GET /pub/job/vk/view32.jpg HTTP/1.0\" 200 4852\n200.0.156.15 - - [29/Aug/1995:20:11:43 -0400] \"GET /pub/atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6688\n128.187.42.21 - - [29/Aug/1995:20:16:24 -0400] \"GET /pub/mbrophy/pix/weh.jpg HTTP/1.0\" 200 3045\npinole.os.varian.com - - [29/Aug/1995:20:20:40 -0400] \"GET /pub/job/vk/view18.jpg HTTP/1.0\" 200 6578\n204.73.81.71 - - [29/Aug/1995:20:27:11 -0400] \"GET /pub/k2/am4x44u/gifs/superwin.gif HTTP/1.0\" 200 2263\n159.142.95.163 - - [29/Aug/1995:20:32:06 -0400] \"GET /pub/lupine/www/images/icons/news.gif HTTP/1.0\" 200 1202\npdxgp1.intel.com - - [29/Aug/1995:20:37:58 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nproxy.austin.ibm.com - - [29/Aug/1995:20:42:20 -0400] \"GET /pub/job/swim/v-53.jpg HTTP/1.0\" 200 2421\nslip2.cafe.net - - [29/Aug/1995:20:48:42 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\n192.84.112.145 - - [29/Aug/1995:20:53:29 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\nwww-d3.proxy.aol.com - - [29/Aug/1995:20:59:29 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 304 -\n160.227.101.63 - - [29/Aug/1995:21:03:32 -0400] \"GET /pub/epchurch/bottom_2.gif HTTP/1.0\" 200 7224\nnet181.metronet.com - - [29/Aug/1995:21:08:33 -0400] \"GET /pub/lupine/www/images/support/sig.jpg HTTP/1.0\" 200 17480\nGATEWAY-2.WTI.COM - - [29/Aug/1995:21:14:41 -0400] \"GET /pub/jeffd/header.gif HTTP/1.0\" 200 24376\npiweba5y.prodigy.com - - [29/Aug/1995:21:20:44 -0400] \"GET /pub/atomicbk/images/nataliec.gif HTTP/1.0\" 404 207\npoppy.hensa.ac.uk - - [29/Aug/1995:21:26:14 -0400] \"GET /atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nwww-a1.proxy.aol.com - - [29/Aug/1995:21:30:40 -0400] \"GET /pub/wick/misc/queer.gif HTTP/1.0\" 200 1015\n152.97.1.118 - - [29/Aug/1995:21:36:34 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\nNATHALIE.remote.ualberta.ca - - [29/Aug/1995:21:42:51 -0400] \"GET /pub/mbrophy/pix/address.jpg HTTP/1.0\" 200 2956\nmarion3.midwest.net - - [29/Aug/1995:21:47:28 -0400] \"GET /pub/theme/demockracy/ HTTP/1.0\" 200 1378\npelican.ucsd.edu - - [29/Aug/1995:21:53:11 -0400] \"GET /pub/job/vk/claudia.jpg HTTP/1.0\" 200 7225\nlcc_g50.lanecc.edu - - [29/Aug/1995:21:59:23 -0400] \"GET /pub/chivato/littleprog.gif HTTP/1.0\" 200 973\nonet2.cup.hp.com - - [29/Aug/1995:22:04:58 -0400] \"GET /pub/job/vk/view06.jpg HTTP/1.0\" 200 6553\ncsscdrom.css.beckman.com - - [29/Aug/1995:22:10:11 -0400] \"GET /pub/job/vk/2-page-2.gif HTTP/1.0\" 200 2527\nix-den11-27.ix.netcom.com - - [29/Aug/1995:22:17:01 -0400] \"GET /pub/micros/rmi/listen.gif HTTP/1.0\" 200 353\nix-bal1-23.ix.netcom.com - - [29/Aug/1995:22:23:07 -0400] \"GET /pub/jeffd/grayball.gif HTTP/1.0\" 200 995\ncclamp.Colorado.EDU - - [29/Aug/1995:22:29:57 -0400] \"GET /pub/mpowers/j4j/web/Tablegifs/LibraryIcon.gif HTTP/1.0\" 200 6914\nsanantonio-1-14.i-link.net - - [29/Aug/1995:22:34:22 -0400] \"GET /pub/networx/autopage/autopage.gif HTTP/1.0\" 200 57900\n128.18.44.62 - - [29/Aug/1995:22:40:02 -0400] \"GET /pub/job/swim/v-46.jpg HTTP/1.0\" 200 2439\nix-den6-28.ix.netcom.com - - [29/Aug/1995:22:46:26 -0400] \"GET /atomicbk/catalog/catalog.html HTTP/1.0\" 200 4654\n159.57.25.49 - - [29/Aug/1995:22:51:43 -0400] \"GET /atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\n163.226.7.130 - - [29/Aug/1995:22:57:20 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nphyun5.ucr.edu - - [29/Aug/1995:23:02:45 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nlink103.txdirect.net - - [29/Aug/1995:23:08:27 -0400] \"GET /pub/lupine/www/werewolf.html HTTP/1.0\" 200 1041\nelsun156.cc.purdue.edu - - [29/Aug/1995:23:13:00 -0400] \"GET /pub/job/vk/arrow-r.gif HTTP/1.0\" 200 3042\n129.130.211.102 - - [29/Aug/1995:23:18:08 -0400] \"GET /pub/sshay/images/links.gif HTTP/1.0\" 304 -\nwww-c3.proxy.aol.com - - [29/Aug/1995:23:23:04 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 304 -\npetrides-ppp.clark.net - - [29/Aug/1995:23:28:19 -0400] \"GET /pub/TMC/image/globe.gif HTTP/1.0\" 304 -\nopenlab99.mty.itesm.mx - - [29/Aug/1995:23:34:55 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\nsnoopy.vlsi.com - - [29/Aug/1995:23:40:38 -0400] \"GET /pub/job/vk/view33.jpg HTTP/1.0\" 200 5903\nh-langoliers.norfolk.infi.net - - [29/Aug/1995:23:47:10 -0400] \"GET /pub/bdalzell/borzoiinfo.html HTTP/1.0\" 200 1659\nmon2-07.planete.net - - [29/Aug/1995:23:54:21 -0400] \"GET /pub/alweiner/cgi-bin/homepage.html?w3magic12 HTTP/1.0\" 200 1396\nbelize.lrcc.vichosp.london.on.ca - - [30/Aug/1995:00:02:10 -0400] \"GET /atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6688\nppp7.cm.worldlinx.com - - [30/Aug/1995:00:10:06 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nusr16-dialup51.Atlanta.mci.net - - [30/Aug/1995:00:15:02 -0400] \"GET /pub/atomicbk/images/tease.gif HTTP/1.0\" 200 43516\nts9-11.westwood.ts.ucla.edu - - [30/Aug/1995:00:21:40 -0400] \"GET /pub/terra/pics/purpleball.gif HTTP/1.0\" 200 322\namanda.dorsai.org - - [30/Aug/1995:00:27:47 -0400] \"GET /pub/ceallach/bill.gif HTTP/1.0\" 200 7886\nwww-b3.proxy.aol.com - - [30/Aug/1995:00:33:47 -0400] \"GET /pub/networx/autopage/autoicon.gif HTTP/1.0\" 304 -\nppp0e-05.rns.tamu.edu - - [30/Aug/1995:00:39:40 -0400] \"GET /pub/job/vk/view09.jpg HTTP/1.0\" 200 6011\nbugfix.ikos2.iao.fhg.de - - [30/Aug/1995:00:46:04 -0400] \"GET /pub/mbrophy/pix/yahoo.jpg HTTP/1.0\" 200 7570\nwww-a1.proxy.aol.com - - [30/Aug/1995:00:52:39 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nppp31.cac.psu.edu - - [30/Aug/1995:01:00:32 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 304 -\nwww-c9.proxy.aol.com - - [30/Aug/1995:01:08:23 -0400] \"GET /pub/sknightly/babash.html HTTP/1.0\" 404 207\nppp020.st.rim.or.jp - - [30/Aug/1995:01:14:07 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nn00026-103sul.unity.ncsu.edu - - [30/Aug/1995:01:21:16 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\n192.121.54.163 - - [30/Aug/1995:01:27:42 -0400] \"GET /pub/job/swim/swim.jpg HTTP/1.0\" 304 -\nromulus.ultranet.com - - [30/Aug/1995:01:34:58 -0400] \"GET /pub/job/vk/page1.gif HTTP/1.0\" 200 1960\ndana.lw.com - - [30/Aug/1995:01:44:52 -0400] \"GET /pub/job/vk/view22.jpg HTTP/1.0\" 200 6281\nquandong.itd.adelaide.edu.au - - [30/Aug/1995:01:51:12 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\nwww-c9.proxy.aol.com - - [30/Aug/1995:02:00:52 -0400] \"GET /pub/networx/autopage/classic/cl003_1s.gif HTTP/1.0\" 200 16250\nwww-c8.proxy.aol.com - - [30/Aug/1995:02:08:27 -0400] \"GET /pub/sshay/images/peley.gif HTTP/1.0\" 200 31745\nmontana-max.inoc.dl.nec.com - - [30/Aug/1995:02:17:57 -0400] \"GET /pub/job/vk/view05.jpg HTTP/1.0\" 304 -\nip061.lax.primenet.com - - [30/Aug/1995:02:26:45 -0400] \"GET /pub/heroes/ HTTP/1.0\" 200 12396\nas2511-1.sl004.cns.vt.edu - - [30/Aug/1995:02:33:51 -0400] \"GET /pub/lori/friends.html HTTP/1.0\" 200 1049\n204.97.215.103 - - [30/Aug/1995:02:44:33 -0400] \"GET /pub/job/vk/view23.jpg HTTP/1.0\" 304 -\nnetcom16.netcom.com - - [30/Aug/1995:02:54:12 -0400] \"GET /pub/job/vk/view08.jpg HTTP/1.0\" 200 6476\nkeyhole.es.dupont.com - - [30/Aug/1995:03:03:11 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nucxy08_03.slip.uc.edu - - [30/Aug/1995:03:15:23 -0400] \"GET /pub/atomicbk/bobk.gif HTTP/1.0\" 200 816\njentzsch-slip.usa.net - - [30/Aug/1995:03:23:34 -0400] \"GET /pub/jeffd/header.gif HTTP/1.0\" 200 24376\nproxy0.research.att.com - - [30/Aug/1995:03:33:42 -0400] \"GET /pub/ecn/fastfruit.gif HTTP/1.0\" 200 115\nCust37.Max3.Orlando.FL.MS.UU.NET - - [30/Aug/1995:03:46:26 -0400] \"GET /atomicbk/logo2.gif HTTP/1.0\" 200 12871\npuppydog.clark.net - - [30/Aug/1995:04:00:39 -0400] \"GET /pub/rant/rant/text1b.gif HTTP/1.0\" 304 -\nmailhost.cdn.fr - - [30/Aug/1995:04:11:22 -0400] \"GET /pub/atomicbk/images/earlyero.gif HTTP/1.0\" 404 335\n161.98.20.106 - - [30/Aug/1995:04:23:18 -0400] \"GET /pub/sshay/images/crthumb6.jpg HTTP/1.0\" 200 5733\nitasempara.mes.co.jp - - [30/Aug/1995:04:36:29 -0400] \"GET /mc-icons/blank.gif HTTP/1.0\" 200 60\nhwins.uia.ac.be - - [30/Aug/1995:04:45:59 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\nbeta.Xerox.COM - - [30/Aug/1995:04:58:45 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\nz008.euronet.nl - - [30/Aug/1995:05:08:35 -0400] \"GET /atomicbk/orders.gif HTTP/1.0\" 200 800\nmerc23.calon.com - - [30/Aug/1995:05:19:43 -0400] \"GET /pub/sshay/images/scotname.gif HTTP/1.0\" 200 27064\nbam.nuri.net - - [30/Aug/1995:05:30:13 -0400] \"GET /pub/sshay/images/scotface.gif HTTP/1.0\" 200 12100\nheather.eee.strath.ac.uk - - [30/Aug/1995:05:44:41 -0400] \"GET /atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\npmekisic.mikom.csir.co.za - - [30/Aug/1995:05:59:01 -0400] \"GET /pub/k2/am4x44u/gifs/ambut.gif HTTP/1.0\" 304 -\nhagi-76.kuentos.guam.net - - [30/Aug/1995:06:14:17 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nstoossz.ethz.ch - - [30/Aug/1995:06:28:16 -0400] \"GET /pub/job/vk/view22.jpg HTTP/1.0\" 200 6281\necker.vir.univie.ac.at - - [30/Aug/1995:06:39:41 -0400] \"GET /pub/job/vk/view05.jpg HTTP/1.0\" 200 5012\nvan06171.direct.ca - - [30/Aug/1995:06:51:26 -0400] \"GET /pub/wick/misc/redbg.gif HTTP/1.0\" 200 878\nRJEPC.MSFC.NASA.GOV - - [30/Aug/1995:07:02:14 -0400] \"GET /pub/howie/OO/E.GIF HTTP/1.0\" 200 977\nbobbmac.base.bellcore.com - - [30/Aug/1995:07:14:00 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\n158.39.79.122 - - [30/Aug/1995:07:24:04 -0400] \"GET /pub/networx/autopage/automisc.gif HTTP/1.0\" 200 47927\nlbb22.HUB.ofthe.NET - - [30/Aug/1995:07:33:10 -0400] \"GET /atomicbk/catalog/home.gif HTTP/1.0\" 200 813\n192.176.149.18 - - [30/Aug/1995:07:40:49 -0400] \"GET /pub/atomicbk/images/blondes.gif HTTP/1.0\" 200 21173\nsetup-1.math.ethz.ch - - [30/Aug/1995:07:47:31 -0400] \"GET /pub/job/swim/v-42.jpg HTTP/1.0\" 304 -\n202.44.216.20 - - [30/Aug/1995:07:55:16 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nsgigate.SGI.COM - - [30/Aug/1995:08:03:04 -0400] \"GET /pub/conquest/one/contents.gif HTTP/1.0\" 200 39330\n165.90.141.20 - - [30/Aug/1995:08:12:05 -0400] \"GET /atomicbk/new/email.gif HTTP/1.0\" 200 756\npc0578.iapc.bbsrc.ac.uk - - [30/Aug/1995:08:18:05 -0400] \"GET /atomicbk/seanc.gif HTTP/1.0\" 200 734\nt345.chem.tue.nl - - [30/Aug/1995:08:26:34 -0400] \"GET /pub/jumpsam/minilogo.gif HTTP/1.0\" 200 1368\nres.WPI.EDU - - [30/Aug/1995:08:33:57 -0400] \"GET /pub/kevina/sl/ HTTP/1.0\" 200 10536\nip5.dialup.paltech.com - - [30/Aug/1995:08:41:43 -0400] \"GET /pub/cargui/catapul2.gif HTTP/1.0\" 200 28411\nix-akr-oh2-05.ix.netcom.com - - [30/Aug/1995:08:47:59 -0400] \"GET /pub/aztec/mariner/ HTTP/1.0\" 200 1993\nagora.carleton.ca - - [30/Aug/1995:08:53:18 -0400] \"GET /mpt/mdstate.gif HTTP/1.0\" 200 7505\n203.2.83.121 - - [30/Aug/1995:08:58:34 -0400] \"GET /pub/job/vk/view10.jpg HTTP/1.0\" 200 5303\n158.22.69.109 - - [30/Aug/1995:09:03:51 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\ndatw235.seinf.abb.se - - [30/Aug/1995:09:09:37 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\n198.53.235.136 - - [30/Aug/1995:09:14:51 -0400] \"GET /pub/wine/purch.html HTTP/1.0\" 200 1643\nekm116.jsc.nasa.gov - - [30/Aug/1995:09:21:53 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\nwww-d4.proxy.aol.com - - [30/Aug/1995:09:27:10 -0400] \"GET /pub/networks/l.gif HTTP/1.0\" 200 1097\nkeyring.aecom.yu.edu - - [30/Aug/1995:09:32:31 -0400] \"GET /pub/job/vk/kathy.jpg HTTP/1.0\" 200 7450\n131.218.10.40 - - [30/Aug/1995:09:37:06 -0400] \"GET /pub/jwolff/home/bluedot.gif HTTP/1.0\" 200 153\n128.253.75.157 - - [30/Aug/1995:09:41:27 -0400] \"GET /pub/job/vk/arrow-r.gif HTTP/1.0\" 200 3042\ngate.bmgmusic.com - - [30/Aug/1995:09:47:25 -0400] \"GET /pub/lschank/web/note.gif HTTP/1.0\" 200 264\nwww-d1.proxy.aol.com - - [30/Aug/1995:09:54:58 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 200 11610\nnephthys.egr.uri.edu - - [30/Aug/1995:10:00:13 -0400] \"GET /pub/job/vk/view32.jpg HTTP/1.0\" 200 4852\n199.79.206.35 - - [30/Aug/1995:10:04:11 -0400] \"GET /atomicbk/logo2.gif HTTP/1.0\" 200 12871\n147.138.100.25 - - [30/Aug/1995:10:08:34 -0400] \"GET /pub/jeffd/wall-6.html HTTP/1.0\" 404 323\n165.127.98.68 - - [30/Aug/1995:10:13:56 -0400] \"GET /pub/TMC/image/euromideast.gif HTTP/1.0\" 200 2221\n196.3.72.64 - - [30/Aug/1995:10:18:03 -0400] \"GET /pub/pribut/idea.gif HTTP/1.0\" 200 909\ndialup-3-241.gw.umn.edu - - [30/Aug/1995:10:22:35 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\np40.euronet.nl - - [30/Aug/1995:10:28:06 -0400] \"GET /pub/russadam/share.html HTTP/1.0\" 200 8154\n130.207.65.13 - - [30/Aug/1995:10:32:25 -0400] \"GET /pub/k2/cgi-bin/imagemap/events?252,171 HTTP/1.0\" 302 107\n192.190.9.56 - - [30/Aug/1995:10:36:48 -0400] \"GET /pub/global/search.html HTTP/1.0\" 200 6602\nwww-c9.proxy.aol.com - - [30/Aug/1995:10:41:58 -0400] \"GET /pub/atomicbk/images/tattoow.gif HTTP/1.0\" 200 29519\nbulwark.switch.com - - [30/Aug/1995:10:46:14 -0400] \"GET /pub/jeffd/grad_lin.gif HTTP/1.0\" 200 3346\nnovix.ncaur.gov - - [30/Aug/1995:10:51:14 -0400] \"GET /pub/rmharris/images/note.gif HTTP/1.0\" 200 565\ngail.dialup.inch.com - - [30/Aug/1995:10:55:30 -0400] \"GET /graphics/BUTTON1.GIF HTTP/1.0\" 200 1434\nnonpro.clark.net - - [30/Aug/1995:11:00:07 -0400] \"GET /pub/stimson/stimson/sites.htm HTTP/1.0\" 200 1370\nWS63.CC.YSU.EDU - - [30/Aug/1995:11:05:35 -0400] \"GET /pub/sshay/images/rainback.gif HTTP/1.0\" 200 2541\nnpt1.netspace.or.jp - - [30/Aug/1995:11:10:33 -0400] \"GET /pub/atomicbk/catalog/erotica.html HTTP/1.0\" 200 11362\nppp121.moscow.com - - [30/Aug/1995:11:14:27 -0400] \"GET /pub/alweiner/work/spacer10.gif HTTP/1.0\" 304 -\nmurray.cnwl.igs.net - - [30/Aug/1995:11:18:23 -0400] \"GET /pub/lschank/web/exclamw.gif HTTP/1.0\" 200 187\nplc.clark.net - - [30/Aug/1995:11:22:38 -0400] \"GET /pub/plc/return.gif HTTP/1.0\" 304 -\ncary113.its.rpi.edu - - [30/Aug/1995:11:25:50 -0400] \"GET /atomicbk/new/logo2.gif HTTP/1.0\" 200 12871\nwww-c5.proxy.aol.com - - [30/Aug/1995:11:29:28 -0400] \"GET /atomicbk/artgal.gif HTTP/1.0\" 304 -\nwww-b6.proxy.aol.com - - [30/Aug/1995:11:33:31 -0400] \"GET /pub/jbl/apple_small.gif HTTP/1.0\" 200 173\nwww-d1.proxy.aol.com - - [30/Aug/1995:11:37:58 -0400] \"GET /pub/robert/current.html HTTP/1.0\" 200 30337\ncrc2-fddi.cris.com - - [30/Aug/1995:11:42:23 -0400] \"GET /pub/jrinker/news.jpg HTTP/1.0\" 200 4471\n204.245.159.8 - - [30/Aug/1995:11:46:46 -0400] \"GET /pub/clw/clwblue2.gif HTTP/1.0\" 304 -\n131.116.19.243 - - [30/Aug/1995:11:51:25 -0400] \"GET /pub/job/vk/view19.jpg HTTP/1.0\" 200 3915\nnyssa.swt.edu - - [30/Aug/1995:11:55:06 -0400] \"GET /pub/job/mpegs/util.html HTTP/1.0\" 200 8531\nuser11x48.lacoe.edu - - [30/Aug/1995:11:58:13 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\nlo-pc2015.HITC.COM - - [30/Aug/1995:12:02:17 -0400] \"GET /pub/atomicbk/images/fetdream.gif HTTP/1.0\" 200 30850\ndyna-09.bart.nl - - [30/Aug/1995:12:06:11 -0400] \"GET /pub/lupine/www/images/support/mickey.gif HTTP/1.0\" 304 -\n129.219.49.55 - - [30/Aug/1995:12:10:23 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\nosorno.dim.uchile.cl - - [30/Aug/1995:12:13:34 -0400] \"GET /pub/job/vk/page2.gif HTTP/1.0\" 200 2056\nbox705.labs.cis.pitt.edu - - [30/Aug/1995:12:17:27 -0400] \"GET /pub/ajc-dc/regions.html HTTP/1.0\" 200 865\nfapc68.far.intg.telia.se - - [30/Aug/1995:12:20:56 -0400] \"GET /pub/job/swim/v-53.jpg HTTP/1.0\" 200 2421\nFPM-Eros.Stanford.EDU - - [30/Aug/1995:12:24:45 -0400] \"GET /pub/network/jobs/01063095CPB2.html HTTP/1.0\" 200 1057\nToucan.CS.UCLA.EDU - - [30/Aug/1995:12:28:23 -0400] \"GET /pub/alweiner/jet_2.gif HTTP/1.0\" 200 616\n199.20.17.192 - - [30/Aug/1995:12:32:27 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\ncirt_153.unm.edu - - [30/Aug/1995:12:35:53 -0400] \"GET /pub/lupine/images/tlk/mufasa-simba.gif HTTP/1.0\" 200 26330\nclaude.ifi.unizh.ch - - [30/Aug/1995:12:39:31 -0400] \"GET /pub/alweiner/beta.gif HTTP/1.0\" 200 294\nlfsgate.lfs.loral.com - - [30/Aug/1995:12:43:25 -0400] \"GET /pub/pgarrett/trash.gif HTTP/1.0\" 200 248\ndialup96-110.swipnet.se - - [30/Aug/1995:12:47:32 -0400] \"GET /pub/job/vk/note.gif HTTP/1.0\" 200 9413\n161.187.201.138 - - [30/Aug/1995:12:50:55 -0400] \"GET /pub/sshay/images/brwthumb.jpg HTTP/1.0\" 200 3306\nlearn129.gestalt-sys.com - - [30/Aug/1995:12:54:51 -0400] \"GET /pub/cargui/net_apps.html HTTP/1.0\" 200 7735\nhalon.sybase.com - - [30/Aug/1995:12:58:46 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\npc116.imt.hist.no - - [30/Aug/1995:13:02:39 -0400] \"GET /pub/job/swim/v-42.jpg HTTP/1.0\" 200 2506\nj11.kl2.jaring.my - - [30/Aug/1995:13:06:10 -0400] \"GET /atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nhalon.sybase.com - - [30/Aug/1995:13:10:40 -0400] \"GET /pub/wick/misc/clarknet.gif HTTP/1.0\" 200 3937\neagle.uis.edu - - [30/Aug/1995:13:14:21 -0400] \"GET /pub/gen/ada/ HTTP/1.0\" 200 3754\nsundial.cs.cuhk.hk - - [30/Aug/1995:13:18:36 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nad19-037.compuserve.com - - [30/Aug/1995:13:22:56 -0400] \"GET /pub/sshay/links.html HTTP/1.0\" 200 2992\nmab-146.umd.edu - - [30/Aug/1995:13:26:31 -0400] \"GET /pub/TMC/image/raiisaleading.gif HTTP/1.0\" 200 2209\ngasparrofp.med.yale.edu - - [30/Aug/1995:13:29:53 -0400] \"GET /pub/sshay/images/brwthumb.jpg HTTP/1.0\" 200 3306\nws16.csblab.uncwil.edu - - [30/Aug/1995:13:33:02 -0400] \"GET /pub/lschank/web/up.gif HTTP/1.0\" 200 264\ninter014.internet.com.mx - - [30/Aug/1995:13:36:53 -0400] \"GET /pub/job/swim/v-41.jpg HTTP/1.0\" 200 2721\nrelay02.jpmorgan.com - - [30/Aug/1995:13:40:59 -0400] \"GET /pub/job/swim/v-57.jpg HTTP/1.0\" 200 2717\npiweba3y.prodigy.com - - [30/Aug/1995:13:45:02 -0400] \"GET /pub/job/vk/view18.jpg HTTP/1.0\" 200 6578\ncomserv-b-24.usc.edu - - [30/Aug/1995:13:48:31 -0400] \"GET /pub/wine/arrowrt.gif HTTP/1.0\" 200 216\nssmtpva1.slma.com - - [30/Aug/1995:13:52:08 -0400] \"GET /pub/artsci/boat.gif HTTP/1.0\" 304 -\n129.193.164.81 - - [30/Aug/1995:13:55:08 -0400] \"GET /pub/govimag/overview.html HTTP/1.0\" 200 1478\n198.243.61.152 - - [30/Aug/1995:13:58:02 -0400] \"GET /pub/k2/am4x44u/gifs/camtrol2.gif HTTP/1.0\" 200 1865\nsynerget.demon.co.uk - - [30/Aug/1995:14:00:42 -0400] \"GET /pub/howie/OO/ooheader.gif HTTP/1.0\" 200 2631\nad05-009.compuserve.com - - [30/Aug/1995:14:03:14 -0400] \"GET /pub/atomicbk/catalog.gif HTTP/1.0\" 200 693\n198.83.140.62 - - [30/Aug/1995:14:07:06 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nix-al10-26.ix.netcom.com - - [30/Aug/1995:14:10:34 -0400] \"GET /infouser/endidc.htm HTTP/1.0\" 200 2146\nbruny.cc.utas.edu.au - - [30/Aug/1995:14:13:50 -0400] \"GET /pub/job/vk/view10.jpg HTTP/1.0\" 200 5303\nix-wc1-21.ix.netcom.com - - [30/Aug/1995:14:16:58 -0400] \"GET /pub/sshay/images/btthumb.jpg HTTP/1.0\" 200 4624\n146.186.69.35 - - [30/Aug/1995:14:20:42 -0400] \"GET /pub/k2/am4x44u/maps/trails.gif HTTP/1.0\" 200 41962\nCPCD.cam.muskingum.edu - - [30/Aug/1995:14:24:07 -0400] \"GET /pub/job/vk/v-line.gif HTTP/1.0\" 200 1254\n134.20.235.250 - - [30/Aug/1995:14:26:58 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\nbigtexan.clark.net - - [30/Aug/1995:14:30:10 -0400] \"GET /pub/batman/hline.gif HTTP/1.0\" 200 2424\nslip1137.rmii.com - - [30/Aug/1995:14:33:16 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nrkln9.quiknet.com - - [30/Aug/1995:14:36:38 -0400] \"GET /pub/k2/am4x44u/maps/trails.gif HTTP/1.0\" 200 41962\nlab44.fas.yorku.ca - - [30/Aug/1995:14:39:53 -0400] \"GET /atomicbk/new/logo.gif HTTP/1.0\" 200 1942\n204.191.33.129 - - [30/Aug/1995:14:42:24 -0400] \"GET /pub/cargui/autos.html HTTP/1.0\" 200 7748\nbeta.Xerox.COM - - [30/Aug/1995:14:45:18 -0400] \"GET /pub/bell/review/religion/miller_complete_gospels.shtml HTTP/1.0\" 200 4309\nE04GUSER.MNSFLD.EDU - - [30/Aug/1995:14:49:11 -0400] \"GET /pub/lschank/web/line.gif HTTP/1.0\" 200 1131\npizza.INnet.net - - [30/Aug/1995:14:52:45 -0400] \"GET /pub/job/vk/view01.jpg HTTP/1.0\" 200 5733\nmpdgw2.hmpd.com - - [30/Aug/1995:14:56:25 -0400] \"GET /graphics/cgi.gif HTTP/1.0\" 200 11499\n144.18.8.44 - - [30/Aug/1995:15:00:51 -0400] \"GET /pub/k2/am4x44u/gifs/scut.gif HTTP/1.0\" 200 1404\nbootstrap.agcs.com - - [30/Aug/1995:15:04:32 -0400] \"GET /pub/jeffd/spcornr.gif HTTP/1.0\" 200 7584\nsf-124.sfo.com - - [30/Aug/1995:15:07:11 -0400] \"GET /pub/ibos/home.html HTTP/1.0\" 200 2755\npetey.bwi.wec.com - - [30/Aug/1995:15:10:26 -0400] \"GET /pub/gen/fas/spp/ HTTP/1.0\" 304 -\n168.18.135.109 - - [30/Aug/1995:15:14:02 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nlearn129.gestalt-sys.com - - [30/Aug/1995:15:17:43 -0400] \"GET /pub/globe1.gif HTTP/1.0\" 404 306\nlkolker-ppp.clark.net - - [30/Aug/1995:15:21:07 -0400] \"GET /html/usage/usage.graph.small.gif HTTP/1.0\" 200 144\n198.88.162.54 - - [30/Aug/1995:15:24:37 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\ngrda.csi.uottawa.ca - - [30/Aug/1995:15:27:45 -0400] \"GET /pub/job/vk/view10.jpg HTTP/1.0\" 200 5303\nMTM1IP.usia.gov - - [30/Aug/1995:15:31:03 -0400] \"GET /pub/lschank/web/fwd.gif HTTP/1.0\" 200 275\nmsabouri.gtis.gc.ca - - [30/Aug/1995:15:34:59 -0400] \"GET /pub/job/swim/swimline.jpg HTTP/1.0\" 200 2641\nvictoria.phar.cam.ac.uk - - [30/Aug/1995:15:39:04 -0400] \"GET /pub/job/vk/view11.jpg HTTP/1.0\" 200 5001\nwww-d4.proxy.aol.com - - [30/Aug/1995:15:41:29 -0400] \"GET /atomicbk/images/cherry.gif HTTP/1.0\" 304 -\nisr-m28-18.urh.uiuc.edu - - [30/Aug/1995:15:44:53 -0400] \"GET /pub/lupine/www/pixs/backgrounds/beige.gif HTTP/1.0\" 404 318\nvaxb.isc.rit.edu - - [30/Aug/1995:15:48:45 -0400] \"GET /pub/phil/JulianaHatfield/stories/jh16.txt HTTP/1.0\" 200 5194\nsamc04.dne.bnl.gov - - [30/Aug/1995:15:52:06 -0400] \"GET /pub/jeffd/cicgbtn.gif HTTP/1.0\" 304 -\nyacht.ee.fit.edu - - [30/Aug/1995:15:55:19 -0400] \"GET /pub/jcase/fspscan.tar.gz HTTP/1.0\" 200 5337\n204.180.189.28 - - [30/Aug/1995:15:58:48 -0400] \"GET /pub/rjamesd/images/foxpro.gif HTTP/1.0\" 304 -\ndd15-012.compuserve.com - - [30/Aug/1995:16:02:33 -0400] \"GET /pub/jeffd/culture.html HTTP/1.0\" 200 3934\nmann.miracle.net - - [30/Aug/1995:16:06:05 -0400] \"GET /atomicbk/catalog/emboss.jpg HTTP/1.0\" 200 4741\na038.dayt.tasc.com - - [30/Aug/1995:16:10:11 -0400] \"GET /pub/jeffd/cicgbtn.gif HTTP/1.0\" 304 -\nts22p14.NetVision.net.il - - [30/Aug/1995:16:13:27 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\nrothplan.demon.co.uk - - [30/Aug/1995:16:16:35 -0400] \"GET /atomicbk/images/atomgirl.jpg HTTP/1.0\" 200 34164\naccess.rrd.com - - [30/Aug/1995:16:19:36 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nwebgate1.mot.com - - [30/Aug/1995:16:22:45 -0400] \"GET /pub/mpowers/j4j/web/Tablegifs/TorahIcon.gif HTTP/1.0\" 200 2664\ndh1.tt.umist.ac.uk - - [30/Aug/1995:16:26:09 -0400] \"GET /pub/atomicbk/catalog/pinup.html HTTP/1.0\" 200 8316\ndialup97-106.swipnet.se - - [30/Aug/1995:16:29:14 -0400] \"GET /atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\n204.62.25.144 - - [30/Aug/1995:16:32:53 -0400] \"GET /pub/rmharris/catalogs/bookwcat/282-5.html HTTP/1.0\" 200 26018\nzen.com - - [30/Aug/1995:16:36:13 -0400] \"GET /pub/mmathai/images/halfmls.gif HTTP/1.0\" 304 -\ninferno.dbna.com - - [30/Aug/1995:16:40:08 -0400] \"GET /pub/jgbustam/toros/garrochi.gif HTTP/1.0\" 200 5675\nlondon.Informatik.Uni-Oldenburg.DE - - [30/Aug/1995:16:43:48 -0400] \"GET /pub/pgarrett/cycle.gif HTTP/1.0\" 200 108564\npth7.ioo.bpmf.ac.uk - - [30/Aug/1995:16:47:25 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nip201-179.wiu.bgu.edu - - [30/Aug/1995:16:50:54 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\n142.139.235.178 - - [30/Aug/1995:16:54:37 -0400] \"GET /pub/job/swim/v-57.jpg HTTP/1.0\" 200 2717\nrmiller.vip.best.com - - [30/Aug/1995:16:57:55 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\nkg.msc.edu - - [30/Aug/1995:17:02:14 -0400] \"GET /pub/job/swim/v-46.jpg HTTP/1.0\" 200 2439\nastralb.clark.net - - [30/Aug/1995:17:05:47 -0400] \"GET /pub/paulgame HTTP/1.0\" 302 220\nstonewall.sra.com - - [30/Aug/1995:17:09:45 -0400] \"GET /atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\n204.96.226.84 - - [30/Aug/1995:17:13:21 -0400] \"GET /pub/job/vk/page2.gif HTTP/1.0\" 200 2056\n192.112.102.166 - - [30/Aug/1995:17:17:24 -0400] \"GET /pub/rsjdfg/Pictures/Finale2.jpg HTTP/1.0\" 200 36744\nwww-e1b.gnn.com - - [30/Aug/1995:17:20:55 -0400] \"GET /pub/ibos/iback.gif HTTP/1.0\" 200 9326\njd_jensen.pnl.gov - - [30/Aug/1995:17:24:29 -0400] \"GET /pub/heroes/ HTTP/1.0\" 200 12396\nspectrum.xerox.com - - [30/Aug/1995:17:28:04 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 304 -\nhplabs.hpl.hp.com - - [30/Aug/1995:17:32:16 -0400] \"GET /pub/job/vk/view01.jpg HTTP/1.0\" 200 5733\n128.97.52.52 - - [30/Aug/1995:17:37:11 -0400] \"GET /pub/arthur/gamebank.html HTTP/1.0\" 200 12910\nonet2.cup.hp.com - - [30/Aug/1995:17:41:27 -0400] \"GET /pub/job/vk/view17.jpg HTTP/1.0\" 304 -\npv041f.vincent.iastate.edu - - [30/Aug/1995:17:45:13 -0400] \"GET /pub/job/vk/vk-ad-09.jpg HTTP/1.0\" 200 70678\nelp.div-cc.firn.edu - - [30/Aug/1995:17:49:02 -0400] \"GET /pub/paulgame/paulface.gif HTTP/1.0\" 200 13774\natomicbk-ppp.clark.net - - [30/Aug/1995:17:53:25 -0400] \"GET /atomicbk/new/new.gif HTTP/1.0\" 200 744\ntec207ws30.st.usm.edu - - [30/Aug/1995:17:57:17 -0400] \"GET /pub/sshay/images/crthumb5.jpg HTTP/1.0\" 200 4495\nlv-050.internext.com - - [30/Aug/1995:18:01:03 -0400] \"GET /pub/atomicbk/catalog/erotica.html HTTP/1.0\" 200 11362\ninterlock.lexmark.com - - [30/Aug/1995:18:03:48 -0400] \"GET /pub/job/vk/2-page-2.gif HTTP/1.0\" 200 2527\nh-hanuman.norfolk.infi.net - - [30/Aug/1995:18:07:11 -0400] \"GET /pub/jeffd/martin.gif HTTP/1.0\" 200 4551\n205.219.29.21 - - [30/Aug/1995:18:10:51 -0400] \"GET /pub/atomicbk/images/reguide.gif HTTP/1.0\" 200 39861\nrain.ccg.uoknor.edu - - [30/Aug/1995:18:15:09 -0400] \"GET /pub/job/vk/view22.jpg HTTP/1.0\" 200 6281\ncassini.gsfc.nasa.gov - - [30/Aug/1995:18:18:25 -0400] \"GET /pub/job/vk/claudia.jpg HTTP/1.0\" 200 7225\nMARK.BTS.EARLHAM.EDU - - [30/Aug/1995:18:23:35 -0400] \"GET /pub/wick/misc/speaker.gif HTTP/1.0\" 200 956\n129.81.26.24 - - [30/Aug/1995:18:27:00 -0400] \"GET /pub/cosmic/garcia2a.gif HTTP/1.0\" 200 17578\n130.17.6.131 - - [30/Aug/1995:18:30:22 -0400] \"GET /pub/bdalzell/Borzoi/zoipics.html HTTP/1.0\" 200 1961\ngbol13.dct.com - - [30/Aug/1995:18:35:15 -0400] \"GET /pub/sshay/images/rainback.gif HTTP/1.0\" 200 2541\n163.236.251.33 - - [30/Aug/1995:18:39:10 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\n192.152.149.230 - - [30/Aug/1995:18:43:27 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\nclark.net - - [30/Aug/1995:18:46:42 -0400] \"GET /pub/job/utils.jpg HTTP/1.0\" 304 -\nipt002.rdyne.rockwell.com - - [30/Aug/1995:18:51:13 -0400] \"GET /pub/sshay/defbutn.map?42,42?99,13 HTTP/1.0\" 302 227\nwww-d3.proxy.aol.com - - [30/Aug/1995:18:54:41 -0400] \"GET /atomicbk/images/alfetish.gif HTTP/1.0\" 200 33094\nvan04098.direct.ca - - [30/Aug/1995:18:58:15 -0400] \"GET /pub/sshay/images/hrdthumb.jpg HTTP/1.0\" 200 5094\nwww-d2.proxy.aol.com - - [30/Aug/1995:19:02:59 -0400] \"GET /pub/mglamb/ranch/gifs/ranchbnr.gif HTTP/1.0\" 200 36257\n130.204.251.96 - - [30/Aug/1995:19:08:24 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\n142.139.203.6 - - [30/Aug/1995:19:12:58 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\nwww-b2.proxy.aol.com - - [30/Aug/1995:19:17:43 -0400] \"GET /pub/networx/autopage/autodeal.gif HTTP/1.0\" 200 48029\nhpbs100.boi.hp.com - - [30/Aug/1995:19:21:23 -0400] \"GET /pub/journalism/5percsmt.gif HTTP/1.0\" 200 2321\nppp050.inreach.com - - [30/Aug/1995:19:24:47 -0400] \"GET /pub/jeffd/grayball.gif HTTP/1.0\" 200 995\nnode1.heritage.com - - [30/Aug/1995:19:29:09 -0400] \"GET /pub/sshay/images/chrsbutn.gif HTTP/1.0\" 200 1070\nTRFPC07.okladot.state.ok.us - - [30/Aug/1995:19:33:31 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\nnorth-110-10.dorm.duke.edu - - [30/Aug/1995:19:38:05 -0400] \"GET /pub/job/vk/vendela2.html HTTP/1.0\" 200 8267\nmpngate1.ny.us.ibm.net - - [30/Aug/1995:19:42:13 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\n159.242.115.53 - - [30/Aug/1995:19:46:44 -0400] \"GET /pub/wick/photos/grass_mini.gif HTTP/1.0\" 200 11378\noak.citicorp.com - - [30/Aug/1995:19:50:52 -0400] \"GET /pub/job/vk/view20.jpg HTTP/1.0\" 200 5070\nmiriworld.its.unimelb.EDU.AU - - [30/Aug/1995:19:55:32 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 304 -\nSUNPHY1.PHY.UIC.EDU - - [30/Aug/1995:20:00:02 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\npicasso.ccad.uiowa.edu - - [30/Aug/1995:20:05:52 -0400] \"GET /pub/jeffd/sm_eaghd.gif HTTP/1.0\" 304 -\ncalator.adp.wisc.edu - - [30/Aug/1995:20:10:58 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\nworf.qntm.com - - [30/Aug/1995:20:15:24 -0400] \"GET /pub/job/vk/view11.jpg HTTP/1.0\" 200 5001\nwww.neocom.ca - - [30/Aug/1995:20:19:06 -0400] \"GET /pub/global/russia.html HTTP/1.0\" 200 1599\n164.154.28.4 - - [30/Aug/1995:20:23:06 -0400] \"GET /pub/job/swim/v-58.jpg HTTP/1.0\" 200 3577\nsolomon.syrres.com - - [30/Aug/1995:20:27:33 -0400] \"GET /pub/job/vk/view09.jpg HTTP/1.0\" 200 6011\nwebmaker.clark.net - - [30/Aug/1995:20:32:02 -0400] \"GET /pub/webmaker/glimpse/glimpsehttp/wwwlib/ HTTP/1.0\" 403 142\nclark.net - - [30/Aug/1995:20:37:24 -0400] \"GET /pub/job/swim/v-02.jpg HTTP/1.0\" 200 2928\nclient31.sct.fr - - [30/Aug/1995:20:43:17 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\nacs4.acs.ucalgary.ca - - [30/Aug/1995:20:48:15 -0400] \"GET /atomicbk/new/emboss.jpg HTTP/1.0\" 200 4741\nnawlns.monsanto.com - - [30/Aug/1995:20:53:13 -0400] \"GET /pub/networx/autopage/classic/cl003_1s.gif HTTP/1.0\" 200 16250\nwww-c9.proxy.aol.com - - [30/Aug/1995:20:57:54 -0400] \"GET /pub/sshay/partner.html HTTP/1.0\" 200 7065\nts1-and-4.iquest.net - - [30/Aug/1995:21:02:59 -0400] \"GET /pub/downin/html/Graphics/contact-infot.gif HTTP/1.0\" 200 7060\nm06.leba.net - - [30/Aug/1995:21:08:56 -0400] \"GET /pub/russadam/wnew.html HTTP/1.0\" 200 4653\nZEBRA.ENGR.UTK.EDU - - [30/Aug/1995:21:15:11 -0400] \"GET /pub/alweiner/work/spacer25.gif HTTP/1.0\" 200 45\nline179.worldweb.net - - [30/Aug/1995:21:19:29 -0400] \"GET /winfield/gifs/navy_mar.jpg HTTP/1.0\" 200 2228\nslip37-254-99.ibm.net - - [30/Aug/1995:21:23:46 -0400] \"GET /atomicbk/images/knockers.gif HTTP/1.0\" 200 41213\npool73.maple.net - - [30/Aug/1995:21:28:11 -0400] \"GET /pub/sshay/gallery.html HTTP/1.0\" 200 2101\nneptune.pharm.hiroshima-u.ac.jp - - [30/Aug/1995:21:33:17 -0400] \"GET /pub/job/swim/v-18.jpg HTTP/1.0\" 200 2838\nalweiner.clark.net - - [30/Aug/1995:21:38:43 -0400] \"POST /pub/alweiner/cgi-bin/w3magic.cgi?-f|beta-register@__00 HTTP/1.0\" 200 234\ngin.obspm.fr - - [30/Aug/1995:21:43:46 -0400] \"GET /pub/rjgula/attacks/mail/sml3128a.txt HTTP/1.0\" 200 2615\nbdmgate.bdm.com - - [30/Aug/1995:21:47:59 -0400] \"GET /pub/sshay/images/rainback.gif HTTP/1.0\" 200 2541\nnvcon26.pcsub9.db.erau.edu - - [30/Aug/1995:21:52:10 -0400] \"GET /pub/gen/fas/irp/arrowlf.gif HTTP/1.0\" 200 496\nnx20.mik.uky.edu - - [30/Aug/1995:21:56:18 -0400] \"GET /pub/job/vk/note.gif HTTP/1.0\" 200 9413\nh-abyss.annap.infi.net - - [30/Aug/1995:22:00:43 -0400] \"GET /graphics/cgi.gif HTTP/1.0\" 200 11499\ngateway.Kwantlen.BC.CA - - [30/Aug/1995:22:06:11 -0400] \"GET /pub/alweiner/owl.gif HTTP/1.0\" 200 1285\n205.133.22.104 - - [30/Aug/1995:22:10:50 -0400] \"GET /pub/job/vk/note.gif HTTP/1.0\" 304 -\ncrc-selq10.unl.edu - - [30/Aug/1995:22:16:08 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\n131.90.144.58 - - [30/Aug/1995:22:21:28 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nbrian.cs.moc.govt.nz - - [30/Aug/1995:22:26:57 -0400] \"HEAD /pub/aztec/mariner/ HTTP/1.0\" 200 1993\nscopen.sc.hp.com - - [30/Aug/1995:22:33:02 -0400] \"GET /pub/wmcbrine/Madonna/punk-bw.jpg HTTP/1.0\" 200 63843\nix-war-mi4-06.ix.netcom.com - - [30/Aug/1995:22:38:45 -0400] \"GET /atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\nwww-d4.proxy.aol.com - - [30/Aug/1995:22:43:45 -0400] \"GET /pub/mbrophy/pix/interv.jpg HTTP/1.0\" 200 5047\nip190.boi.primenet.com - - [30/Aug/1995:22:48:05 -0400] \"GET /pub/jeffd/bbs.gif HTTP/1.0\" 200 6715\nwt10.library.luc.edu - - [30/Aug/1995:22:53:46 -0400] \"GET /pub/phil/images/jh63.gif HTTP/1.0\" 200 3371\n205.199.120.184 - - [30/Aug/1995:22:59:56 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\ndial3.ecua.net.ec - - [30/Aug/1995:23:07:19 -0400] \"GET /pub/networx/autopage/autopage.html HTTP/1.0\" 200 1413\nlinc.dialup.access.net - - [30/Aug/1995:23:13:24 -0400] \"GET /pub/wsg/html/web/home.html HTTP/1.0\" 200 950\nGatordyn15.ac.hillsdale.edu - - [30/Aug/1995:23:19:59 -0400] \"GET /pub/jeffd/speaker.gif HTTP/1.0\" 200 2646\ncw8.ppp.ornl.gov - - [30/Aug/1995:23:26:02 -0400] \"GET /pub/job/vk/view05.jpg HTTP/1.0\" 200 5012\nisr1104.urh.uiuc.edu - - [30/Aug/1995:23:30:46 -0400] \"GET /atomicbk/promo.gif HTTP/1.0\" 200 849\npiweba3y.prodigy.com - - [30/Aug/1995:23:35:57 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 304 -\nslip-156.california.com - - [30/Aug/1995:23:41:49 -0400] \"GET /pub/cardman/tinyidrm.gif HTTP/1.0\" 200 4284\n192.206.65.126 - - [30/Aug/1995:23:46:45 -0400] \"GET /atomicbk/email.gif HTTP/1.0\" 200 756\ncs29-75.usafa.af.mil - - [30/Aug/1995:23:52:57 -0400] \"GET /pub/wsg/html/jan/vespers.html HTTP/1.0\" 200 476\nix-pas11-26.ix.netcom.com - - [30/Aug/1995:23:59:12 -0400] \"GET /pub/moncomm/html/ft.jpg HTTP/1.0\" 200 62501\npukatea.its.vuw.ac.nz - - [31/Aug/1995:00:04:13 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\ncs1-09.haz.ptd.net - - [31/Aug/1995:00:10:12 -0400] \"GET /pub/epchurch/push/push3.html HTTP/1.0\" 200 363\nts2-08.InfoRamp.Net - - [31/Aug/1995:00:15:35 -0400] \"GET /pub/sshay/images/davthumb.jpg HTTP/1.0\" 200 3914\ncs08-30.usafa.af.mil - - [31/Aug/1995:00:22:51 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\nts4-11.westwood.ts.ucla.edu - - [31/Aug/1995:00:27:37 -0400] \"GET /pub/lupine/images/fantasia/fantasia.gif HTTP/1.0\" 200 28795\nwww-a1.proxy.aol.com - - [31/Aug/1995:00:34:15 -0400] \"GET /pub/atomicbk/catalog/erotica.html HTTP/1.0\" 200 11362\nport26.lnd.com - - [31/Aug/1995:00:40:16 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 304 -\np00.slip.pad.MKS.COM - - [31/Aug/1995:00:46:10 -0400] \"GET /pub/job/swim/v-09.jpg HTTP/1.0\" 200 3755\nSLIPROCK-01.DIALIN.UIC.EDU - - [31/Aug/1995:00:59:53 -0400] \"GET /pub/aztec/mariner/images/mnlognew.gif HTTP/1.0\" 200 12193\nedgar.cs.washington.edu - - [31/Aug/1995:01:11:01 -0400] \"GET /pub/rothman/telhome.html HTTP/1.0\" 200 35887\nstar65.hkstar.com - - [31/Aug/1995:01:22:16 -0400] \"GET /pub/sshay/images/greysped.gif HTTP/1.0\" 200 4542\n163.135.205.237 - - [31/Aug/1995:01:34:27 -0400] \"GET /pub/job/vk/vk-ad-19.jpg HTTP/1.0\" 200 44323\nppp076-stdkn2.ulaval.ca - - [31/Aug/1995:01:43:01 -0400] \"GET /pub/lupine/www/werewolf.html HTTP/1.0\" 200 1041\n158.122.1.191 - - [31/Aug/1995:01:51:48 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\nasm_19.unm.edu - - [31/Aug/1995:02:00:17 -0400] \"GET /pub/peace/line1.gif HTTP/1.0\" 304 -\nvan08240.direct.ca - - [31/Aug/1995:02:08:51 -0400] \"GET /pub/lazarus/citadel/karenpic.gif HTTP/1.0\" 200 3709\nlabpc33.acs.uci.edu - - [31/Aug/1995:02:18:47 -0400] \"GET /pub/job/vk/view11.jpg HTTP/1.0\" 200 5001\nmac_yfr.chem.ucla.edu - - [31/Aug/1995:02:26:53 -0400] \"GET /atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nip220.pom.primenet.com - - [31/Aug/1995:02:35:13 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\nslip23.island.net - - [31/Aug/1995:02:44:13 -0400] \"GET /atomicbk/email.gif HTTP/1.0\" 200 756\nbrother.cc.monash.edu.au - - [31/Aug/1995:02:53:40 -0400] \"GET /pub/job/vk/babe.jpg HTTP/1.0\" 200 8235\nsfsp73.slip.net - - [31/Aug/1995:03:04:30 -0400] \"GET /pub/wine/home.html HTTP/1.0\" 200 1526\nztivax.zfe.siemens.de - - [31/Aug/1995:03:14:47 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\nmadonna.dep.no - - [31/Aug/1995:03:24:37 -0400] \"GET /pub/job/vk/cindy.jpg HTTP/1.0\" 200 4267\n169.140.209.207 - - [31/Aug/1995:03:36:27 -0400] \"GET /pub/k2/am4x44u/maps/4x4_home.gif HTTP/1.0\" 200 43750\ntlrouter.motctl.gov.tw - - [31/Aug/1995:03:46:28 -0400] \"GET /pub/k2/am4x44u/gifs/netscape.gif HTTP/1.0\" 200 1050\nlaurel.yorku.ca - - [31/Aug/1995:03:54:39 -0400] \"GET /pub/job/vk/vk-ad-10.jpg HTTP/1.0\" 200 53676\n194.14.81.162 - - [31/Aug/1995:04:05:02 -0400] \"GET /pub/pgarrett/rad.gif HTTP/1.0\" 200 216\n128.39.174.54 - - [31/Aug/1995:04:14:05 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\n205.208.30.107 - - [31/Aug/1995:04:22:58 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\n192.65.228.97 - - [31/Aug/1995:04:30:55 -0400] \"GET /pub/networx/autopage/exotic/ex001s.gif HTTP/1.0\" 200 15418\nr221pc16.vtyh.fi - - [31/Aug/1995:04:45:09 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\nvigour2.univ-lyon1.fr - - [31/Aug/1995:04:56:25 -0400] \"GET /pub/atomicbk/images/centur.gif HTTP/1.0\" 200 52508\npoppy.hensa.ac.uk - - [31/Aug/1995:05:07:56 -0400] \"GET /pub/lupine/www/images/balls/blue.gif HTTP/1.0\" 200 326\nmacb4.sj.sg.cnrs-dir.fr - - [31/Aug/1995:05:20:00 -0400] \"GET /pub/job/vk/view24.jpg HTTP/1.0\" 200 6209\n131.11.32.164 - - [31/Aug/1995:05:31:46 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nquandong.itd.adelaide.edu.au - - [31/Aug/1995:05:43:00 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 304 -\nslx.cc.kumamoto-u.ac.jp - - [31/Aug/1995:05:54:47 -0400] \"GET /pub/job/vk/view13.jpg HTTP/1.0\" 200 6219\nbonanno.pisoft.it - - [31/Aug/1995:06:06:29 -0400] \"GET /atomicbk/seanc.gif HTTP/1.0\" 200 734\n194.89.170.103 - - [31/Aug/1995:06:17:30 -0400] \"GET /pub/job/vk/view22.jpg HTTP/1.0\" 200 6281\nuryu.elsip.hokudai.ac.jp - - [31/Aug/1995:06:31:23 -0400] \"GET /pub/job/vk/view22.jpg HTTP/1.0\" 200 6281\n193.38.83.152 - - [31/Aug/1995:06:43:42 -0400] \"GET /pub/atomicbk/news.gif HTTP/1.0\" 200 912\nball.uunet.ca - - [31/Aug/1995:06:54:58 -0400] \"GET /pub/mjoneill/links.html HTTP/1.0\" 404 207\nnhhs-1.nhh.no - - [31/Aug/1995:07:07:08 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\n130.41.37.138 - - [31/Aug/1995:07:19:48 -0400] \"GET /pub/badger/schedule.html HTTP/1.0\" 304 -\n194.18.98.78 - - [31/Aug/1995:07:29:34 -0400] \"GET /pub/phil/images/jh6.gif HTTP/1.0\" 200 9534\n151.104.20.81 - - [31/Aug/1995:07:39:19 -0400] \"GET /pub/job/vk/2-page-2.gif HTTP/1.0\" 200 2527\ndialup7-hugin.oden.se - - [31/Aug/1995:07:50:57 -0400] \"GET /pub/job/vk/view23.jpg HTTP/1.0\" 200 5165\nintgate.raleigh.ibm.com - - [31/Aug/1995:07:58:05 -0400] \"GET /pub/sshay/images/brwthumb.jpg HTTP/1.0\" 200 3306\n194.72.160.77 - - [31/Aug/1995:08:05:15 -0400] \"GET /pub/wmcbrine/html/encyc1s.gif HTTP/1.0\" 200 4701\n143.217.50.14 - - [31/Aug/1995:08:12:55 -0400] \"GET /pub/lupine/images/batb/batb.gif HTTP/1.0\" 200 7913\ninetg1.Arco.COM - - [31/Aug/1995:08:20:45 -0400] \"GET /pub/sshay/gallery.html HTTP/1.0\" 200 2101\n151.208.31.66 - - [31/Aug/1995:08:27:48 -0400] \"GET /pub/ibos/ibos2.gif HTTP/1.0\" 200 7889\nterm19.vol.net - - [31/Aug/1995:08:34:46 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\nannex2000-01.open.ac.uk - - [31/Aug/1995:08:42:42 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 304 -\nrscibm01.sagus.com - - [31/Aug/1995:08:47:05 -0400] \"GET /theme/rule.gif HTTP/1.0\" 200 8728\nscott.hris.msu.edu - - [31/Aug/1995:08:53:03 -0400] \"GET /pub/jeffd/question.html HTTP/1.0\" 200 60823\ngw3.att.com - - [31/Aug/1995:09:00:14 -0400] \"GET /pub/job/swim/v-03.jpg HTTP/1.0\" 200 5882\nslmel4p33.ozemail.com.au - - [31/Aug/1995:09:06:13 -0400] \"GET /atomicbk/images/atomgirl.jpg HTTP/1.0\" 200 34164\nsmr144.montrouge.smr.slb.com - - [31/Aug/1995:09:12:14 -0400] \"GET /atomicbk/direct.gif HTTP/1.0\" 200 833\npiweba2y.prodigy.com - - [31/Aug/1995:09:17:04 -0400] \"GET /atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\nfin002.urmc.rochester.edu - - [31/Aug/1995:09:23:15 -0400] \"GET /pub/rsjdfg/ HTTP/1.0\" 200 2109\nalweiner.clark.net - - [31/Aug/1995:09:29:13 -0400] \"GET /pub/alweiner/cgi-bin/homepage.html?test HTTP/1.0\" 200 744\n131.115.183.104 - - [31/Aug/1995:09:34:44 -0400] \"GET /pub/atomicbk/images/spicy2.gif HTTP/1.0\" 200 29018\n130.207.65.13 - - [31/Aug/1995:09:40:16 -0400] \"GET /pub/k2/am4x44u/gifs/bgrivit2.gif HTTP/1.0\" 304 -\n199.34.140.200 - - [31/Aug/1995:09:45:46 -0400] \"GET /atomicbk/new/logo.gif HTTP/1.0\" 200 1942\nweb.kyoto-inet.or.jp - - [31/Aug/1995:09:51:07 -0400] \"GET /pub/job/vaca-02.jpg HTTP/1.0\" 200 8589\nsuske.nikhef.nl - - [31/Aug/1995:09:55:55 -0400] \"GET /pub/peace/VRSFoot.GIF HTTP/1.0\" 200 16052\ngrail616.nando.net - - [31/Aug/1995:10:01:29 -0400] \"GET /pub/alweiner/string.gif HTTP/1.0\" 200 503\nobara.gw.tohoku.ac.jp - - [31/Aug/1995:10:07:21 -0400] \"GET /pub/sshay/home.html HTTP/1.0\" 200 3149\ndutnsi0.tn.tudelft.nl - - [31/Aug/1995:10:12:31 -0400] \"GET /pub/job/swim/v-01.jpg HTTP/1.0\" 200 2839\nandromeda.cselt.stet.it - - [31/Aug/1995:10:17:42 -0400] \"GET /pub/mairhart/ HTTP/1.0\" 200 3257\npiweba1y.prodigy.com - - [31/Aug/1995:10:22:15 -0400] \"GET /pub/sgs/gifs/bann01.gif HTTP/1.0\" 200 2203\nwww-c3.proxy.aol.com - - [31/Aug/1995:10:26:50 -0400] \"GET /pub/job/vk/babe.jpg HTTP/1.0\" 200 8235\nkwoods.clark.net - - [31/Aug/1995:10:31:29 -0400] \"GET /pub/kwoods/kens.html HTTP/1.0\" 200 2772\n204.213.224.109 - - [31/Aug/1995:10:36:20 -0400] \"GET /pub/listserv/diamond.gif HTTP/1.0\" 404 328\nwebgate1.mot.com - - [31/Aug/1995:10:41:07 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 304 -\nas2511-3.sl013.cns.vt.edu - - [31/Aug/1995:10:45:23 -0400] \"GET /pub/sshay/images/justin.jpg HTTP/1.0\" 200 3489\nwww-b2.proxy.aol.com - - [31/Aug/1995:10:49:52 -0400] \"GET /pub/sshay/images/gallery.gif HTTP/1.0\" 200 8010\nmpngate4.ny.us.ibm.net - - [31/Aug/1995:10:54:59 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\ndns.uni-trier.de - - [31/Aug/1995:10:58:36 -0400] \"GET /pub/sinkers/whatsnew.gif HTTP/1.0\" 200 7708\nconnex.ip.holonet.net - - [31/Aug/1995:11:02:16 -0400] \"GET /pub/russadam/share.html HTTP/1.0\" 304 -\nhelser57.res.iastate.edu - - [31/Aug/1995:11:07:10 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\n130.127.212.44 - - [31/Aug/1995:11:12:04 -0400] \"GET /pub/job/vk/note.gif HTTP/1.0\" 200 9413\n204.252.201.173 - - [31/Aug/1995:11:16:33 -0400] \"GET /pub/sshay/images/homebutn.gif HTTP/1.0\" 200 1071\ndlp49.erinet.com - - [31/Aug/1995:11:21:27 -0400] \"GET /pub/listserv/diamond.gif HTTP/1.0\" 404 328\nport1.one.se - - [31/Aug/1995:11:25:41 -0400] \"GET /pub/jeffd/sm_eaghd.gif HTTP/1.0\" 200 2866\n148.136.113.211 - - [31/Aug/1995:11:29:46 -0400] \"GET /pub/job/vk/view14.jpg HTTP/1.0\" 200 4733\nnile.finance.tisc.titan.com - - [31/Aug/1995:11:33:07 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\ngate.mmd.com - - [31/Aug/1995:11:37:10 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\npc41.cen.bris.ac.uk - - [31/Aug/1995:11:40:32 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\nslhp22.ug.eds.com - - [31/Aug/1995:11:43:37 -0400] \"GET /pub/jeffd/sm_eaghd.gif HTTP/1.0\" 200 2866\n129.120.107.197 - - [31/Aug/1995:11:47:43 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\n130.226.35.189 - - [31/Aug/1995:11:51:25 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\npubl-2.Lib.Berkeley.EDU - - [31/Aug/1995:11:54:24 -0400] \"GET /pub/sshay/images/tywetsut.jpg HTTP/1.0\" 200 21652\n199.1.111.4 - - [31/Aug/1995:11:57:33 -0400] \"GET /pub/menswear/colorbar.gif HTTP/1.0\" 200 1087\n128.158.129.169 - - [31/Aug/1995:12:01:33 -0400] \"GET /pub/jumpsam/logogosp.jpg HTTP/1.0\" 200 15227\npc-3948.safb.af.mil - - [31/Aug/1995:12:05:12 -0400] \"GET /pub/rmharris/images/tpointbt.gif HTTP/1.0\" 200 1743\nMichael-ISDN.Stanford.EDU - - [31/Aug/1995:12:09:39 -0400] \"GET /pub/iz/Books/Top100/top100.html  HTTP/1.0\" 200 3096\nthompson.urel.wsu.edu - - [31/Aug/1995:12:14:10 -0400] \"GET /pub/jeffd/index.html HTTP/1.0\" 200 11428\ngopher.ic.ac.uk - - [31/Aug/1995:12:17:44 -0400] \"GET /pub/job/vk/view06.jpg HTTP/1.0\" 200 6553\nlondon.scsn.net - - [31/Aug/1995:12:22:29 -0400] \"GET /pub/job/vk/note.gif HTTP/1.0\" 200 9413\nwww-e4.proxy.aol.com - - [31/Aug/1995:12:26:43 -0400] \"GET /theme/cgi-bin/serchrnd.html HTTP/1.0\" 200 6052\nad01-021.compuserve.com - - [31/Aug/1995:12:31:00 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\n198.17.29.244 - - [31/Aug/1995:12:34:31 -0400] \"GET /pub/gregd/dude3c.jpg HTTP/1.0\" 200 15305\n132.156.33.197 - - [31/Aug/1995:12:37:31 -0400] \"GET /pub/job/vk/view09.jpg HTTP/1.0\" 200 6011\nstudent37.cba.ua.edu - - [31/Aug/1995:12:40:54 -0400] \"GET /pub/jeffd/95-60.gif HTTP/1.0\" 200 23583\n198.209.101.76 - - [31/Aug/1995:12:45:06 -0400] \"GET /pub/k2/am4x44u/gifs/redball.gif HTTP/1.0\" 200 206\nryp92.ryp.umu.se - - [31/Aug/1995:12:48:22 -0400] \"GET /pub/job/vk/note.gif HTTP/1.0\" 200 9413\n157.99.120.122 - - [31/Aug/1995:12:51:53 -0400] \"GET /atomicbk/images/atomgirl.jpg HTTP/1.0\" 200 34164\ncindy.nocom.se - - [31/Aug/1995:12:55:25 -0400] \"GET /pub/job/vk/cindy.jpg HTTP/1.0\" 200 4267\nrcwusr.bp.com - - [31/Aug/1995:12:59:37 -0400] \"GET /pub/mpowers/j4j/web/Tablegifs/MailIcon.gif HTTP/1.0\" 200 2129\ncrystal.kues.kyoto-u.ac.jp - - [31/Aug/1995:13:04:31 -0400] \"GET /pub/job/swim/swim.jpg HTTP/1.0\" 200 17401\n204.101.3.32 - - [31/Aug/1995:13:08:10 -0400] \"GET /pub/micros/mr/microall.html HTTP/1.0\" 200 3645\nrab.clark.net - - [31/Aug/1995:13:12:05 -0400] \"GET /pub/gorbachev/home.html HTTP/1.0\" 200 2228\nannex3-60.dial.umd.edu - - [31/Aug/1995:13:16:31 -0400] \"GET /pub/downin/html/arlonet/arlo.html HTTP/1.0\" 200 730\nRELABB8.RE.UOKHSC.EDU - - [31/Aug/1995:13:20:40 -0400] \"GET /pub/atomicbk/news.gif HTTP/1.0\" 200 912\nwhitey.near.net - - [31/Aug/1995:13:24:01 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nix-smx-ca1-07.ix.netcom.com - - [31/Aug/1995:13:27:49 -0400] \"GET /pub/job/vk/note.gif HTTP/1.0\" 200 9413\nworld236.worldaccess.COM - - [31/Aug/1995:13:31:27 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nCSACL30.SALSEM.AC.AT - - [31/Aug/1995:13:35:05 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\nws25-07.dev.oclc.org - - [31/Aug/1995:13:39:12 -0400] \"GET /pub/global/toc.html HTTP/1.0\" 200 1696\n149.123.63.80 - - [31/Aug/1995:13:42:41 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 200 11610\nwebgate1.mot.com - - [31/Aug/1995:13:46:54 -0400] \"GET /atomicbk/contest.gif HTTP/1.0\" 200 669\nunknown.atms.be - - [31/Aug/1995:13:50:39 -0400] \"GET /pub/murple/html/propaganda.html HTTP/1.0\" 200 1795\nzappa.ilx.com - - [31/Aug/1995:13:54:34 -0400] \"GET /pub/job/vk/babe.jpg HTTP/1.0\" 200 8235\npeacock.tcinc.com - - [31/Aug/1995:13:58:05 -0400] \"GET /atomicbk/new.gif HTTP/1.0\" 200 744\nAlstonk.er.doe.gov - - [31/Aug/1995:14:01:35 -0400] \"GET /pub/cybersoft/home.html HTTP/1.0\" 200 918\nwww.westpub.com - - [31/Aug/1995:14:05:35 -0400] \"GET /pub/kevina/sl/7signals/apology.gif HTTP/1.0\" 200 1222\nfw1.torolab.ibm.com - - [31/Aug/1995:14:10:07 -0400] \"GET /pub/job/swim/v-20.jpg HTTP/1.0\" 200 2510\ngate.chips.ibm.com - - [31/Aug/1995:14:14:22 -0400] \"GET /pub/job/vk/arrow-r.gif HTTP/1.0\" 200 3042\n169.147.155.104 - - [31/Aug/1995:14:17:38 -0400] \"GET /pub/mikebilt/dchome.gif HTTP/1.0\" 200 7041\ndummy241.library.pitt.edu - - [31/Aug/1995:14:21:01 -0400] \"GET /pub/job/vk/view12.jpg HTTP/1.0\" 200 5966\ngk-east.usps.gov - - [31/Aug/1995:14:24:19 -0400] \"GET /pub/cmp/netguide/free.gif HTTP/1.0\" 304 -\norion.lasierra.edu - - [31/Aug/1995:14:28:23 -0400] \"GET /pub/rsjdfg/ HTTP/1.0\" 200 2109\nOOPS.NCSL.NIST.GOV - - [31/Aug/1995:14:32:54 -0400] \"GET /html/usage/index.html HTTP/1.0\" 200 994\nkellyn.nwscc.sea06.navy.mil - - [31/Aug/1995:14:36:42 -0400] \"GET /pub/job/vk/view21.jpg HTTP/1.0\" 200 5228\npiweba2y.prodigy.com - - [31/Aug/1995:14:40:08 -0400] \"GET /pub/lupine/images/batb/beast-bw.gif HTTP/1.0\" 200 37584\nvagrant.vf.mmc.com - - [31/Aug/1995:14:44:16 -0400] \"GET /pub/lupine/www/lionking.html HTTP/1.0\" 200 1962\nunogate.unocal.com - - [31/Aug/1995:14:48:08 -0400] \"GET /pub/job/vk/kathy.jpg HTTP/1.0\" 200 7450\npc2.mrree.cl - - [31/Aug/1995:14:51:43 -0400] \"GET /pub/diplonet/los-schd.gif HTTP/1.0\" 200 7504\nWEDMONDS.econ.ag.gov - - [31/Aug/1995:14:55:57 -0400] \"GET /pub/atomicbk/catalog/emboss.jpg HTTP/1.0\" 200 4741\nmail.rogers.com - - [31/Aug/1995:14:59:01 -0400] \"GET /pub/networx/autopage/exotic.html HTTP/1.0\" 200 1274\nottgate2.bnr.ca - - [31/Aug/1995:15:03:16 -0400] \"GET /pub/lschank/web/up.gif HTTP/1.0\" 200 264\nproximity.cs.purdue.edu - - [31/Aug/1995:15:07:13 -0400] \"GET /pub/alweiner/cgi-bin/homepage.html?beta-login HTTP/1.0\" 200 1319\n204.120.230.198 - - [31/Aug/1995:15:10:32 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nrose_ip178.efn.org - - [31/Aug/1995:15:15:00 -0400] \"GET /pub/sshay/images/galybutn.gif HTTP/1.0\" 200 1080\nmetrix.metrobbs.com - - [31/Aug/1995:15:18:20 -0400] \"GET /atomicbk/catalog/new.gif HTTP/1.0\" 200 744\ngate.chips.ibm.com - - [31/Aug/1995:15:21:49 -0400] \"GET /pub/atomicbk/images/tease.gif HTTP/1.0\" 200 43516\ncombsds.image.uky.edu - - [31/Aug/1995:15:25:16 -0400] \"GET /pub/sshay/images/partner.gif HTTP/1.0\" 200 14363\nG-PC-009.TAMU.EDU - - [31/Aug/1995:15:28:32 -0400] \"GET /pub/lupine/www/images/icons/note.gif HTTP/1.0\" 200 565\n129.108.32.28 - - [31/Aug/1995:15:32:04 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\neast-9-36.dorm.duke.edu - - [31/Aug/1995:15:35:21 -0400] \"GET /atomicbk/emboss.jpg HTTP/1.0\" 200 4741\n160.205.101.14 - - [31/Aug/1995:15:38:37 -0400] \"GET /pub/k2/am4x44u/gifs/alum1.gif HTTP/1.0\" 200 457\nad16-019.compuserve.com - - [31/Aug/1995:15:42:31 -0400] \"GET /pub/sshay/images/tyusvest.jpg HTTP/1.0\" 200 26791\nnebula7.clark.net - - [31/Aug/1995:15:46:49 -0400] \"GET /pub/k2/am4x44u/gifs/ametal.gif HTTP/1.0\" 200 10335\nmglamb.clark.net - - [31/Aug/1995:15:51:24 -0400] \"GET /pub/mglamb/homebar.map?74,48 HTTP/1.0\" 302 227\n165.95.48.240 - - [31/Aug/1995:15:55:04 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\nfaculty8.mps.org - - [31/Aug/1995:15:58:44 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nthalie.imag.fr - - [31/Aug/1995:16:01:22 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\npar-m104a-2.urh.uiuc.edu - - [31/Aug/1995:16:04:30 -0400] \"GET /pub/k2/am4x44u/gifs/clubline.gif HTTP/1.0\" 200 1254\ngtx.com - - [31/Aug/1995:16:08:27 -0400] \"GET /pub/howie/OO/methods.html HTTP/1.0\" 200 558\ntdb.datatel.com - - [31/Aug/1995:16:12:51 -0400] \"GET /pub/sshay/images/chris3.jpg HTTP/1.0\" 200 50739\ngorgon.pwgsc.gc.ca - - [31/Aug/1995:16:16:15 -0400] \"GET /pub/k2/am4x44u/gifs/slgmc.gif HTTP/1.0\" 200 106074\n198.3.50.158 - - [31/Aug/1995:16:19:28 -0400] \"GET /pub/job/vk/vk-ad-14.jpg HTTP/1.0\" 200 67441\nwww00.Btx.DTAG.DE - - [31/Aug/1995:16:23:00 -0400] \"GET /pub/micros/note01.gif HTTP/1.0\" 200 1719\nwww-e7.proxy.aol.com - - [31/Aug/1995:16:28:15 -0400] \"GET /pub/fan/albumpics/sweetsoul.jpg HTTP/1.0\" 200 2552\nbgumail.bgu.ac.il - - [31/Aug/1995:16:31:50 -0400] \"GET /pub/rant/rant/ HTTP/1.0\" 200 5049\nserver1-2.durham.net - - [31/Aug/1995:16:35:48 -0400] \"GET /atomicbk/catalog/emboss.jpg HTTP/1.0\" 200 4741\nfoglernt06.ursus.maine.edu - - [31/Aug/1995:16:39:05 -0400] \"GET /pub/listserv/lsmus1.html HTTP/1.0\" 200 2713\nmro2577.pclan.ets.org - - [31/Aug/1995:16:42:50 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\nedelman.his.com - - [31/Aug/1995:16:46:38 -0400] \"GET /pub/robert/current.html HTTP/1.0\" 200 30337\nHRSB741.RESNET.UPENN.EDU - - [31/Aug/1995:16:49:30 -0400] \"GET /pub/job/vk/vk-ad-03.jpg HTTP/1.0\" 200 97751\nreach.com - - [31/Aug/1995:16:53:08 -0400] \"GET /pub/atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6688\npc51ms108-f.cislabs.okstate.edu - - [31/Aug/1995:16:56:40 -0400] \"GET /pub/rsjdfg/Reprise.html HTTP/1.0\" 200 234\nPC_joemu.compu.com - - [31/Aug/1995:17:00:27 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\n129.219.40.121 - - [31/Aug/1995:17:04:10 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\nh-nain.nr.infi.net - - [31/Aug/1995:17:09:02 -0400] \"GET /pub/k2/suv/suv1.htm HTTP/1.0\" 200 4859\ngateway.senate.gov - - [31/Aug/1995:17:13:36 -0400] \"GET /pub/jeffd/jfk.au HTTP/1.0\" 200 105716\nMATHSUN15.MATH.UTK.EDU - - [31/Aug/1995:17:16:53 -0400] \"GET /pub/job/vk/view09.jpg HTTP/1.0\" 200 6011\nbox708.labs.cis.pitt.edu - - [31/Aug/1995:17:20:27 -0400] \"GET /pub/rsjdfg/Images/Sean.McDermott.gif HTTP/1.0\" 200 18090\n203.4.167.3 - - [31/Aug/1995:17:24:12 -0400] \"GET /atomicbk/catalog/erotica.html HTTP/1.0\" 200 11362\nwww-c3.proxy.aol.com - - [31/Aug/1995:17:27:55 -0400] \"GET /pub/robert/current.html HTTP/1.0\" 200 30337\nix-sf9-21.ix.netcom.com - - [31/Aug/1995:17:32:12 -0400] \"GET /pub/rmharris/images/books.gif HTTP/1.0\" 200 2253\nbouchon-ppp.clark.net - - [31/Aug/1995:17:36:39 -0400] \"GET /pub/bouchon/dragon.gif HTTP/1.0\" 304 -\nH306A-Performa636.Stanford.EDU - - [31/Aug/1995:17:40:53 -0400] \"GET /pub/fervor/bob6.gif HTTP/1.0\" 200 12142\npc06ben.stflabs.okstate.edu - - [31/Aug/1995:17:44:11 -0400] \"GET /pub/job/swim/v-09.jpg HTTP/1.0\" 200 3755\nedslink3.eds.com - - [31/Aug/1995:17:48:20 -0400] \"GET /pub/pribut/5percmdt.gif HTTP/1.0\" 200 3678\nsshirk.orem.novell.com - - [31/Aug/1995:17:52:34 -0400] \"GET /pub/k2/am4x44u/gifs/superwin.gif HTTP/1.0\" 200 2263\n162.38.183.250 - - [31/Aug/1995:17:56:07 -0400] \"GET /pub/job/mail.jpg HTTP/1.0\" 200 4282\nPort30.TS1.MsState.Edu - - [31/Aug/1995:18:00:16 -0400] \"GET /atomicbk/catalog/pinup.html HTTP/1.0\" 200 8316\ntrvl.magnet.ca - - [31/Aug/1995:18:04:44 -0400] \"GET /pub/sshay/images/chris3.jpg HTTP/1.0\" 200 50739\n132.68.21.60 - - [31/Aug/1995:18:09:39 -0400] \"GET /pub/job/swim/v-02.jpg HTTP/1.0\" 200 2928\nwww-b2.proxy.aol.com - - [31/Aug/1995:18:14:25 -0400] \"GET /pub/job/swim/ss-05.jpg HTTP/1.0\" 200 47937\nnameless.house.gov - - [31/Aug/1995:18:18:11 -0400] \"GET /pub/wick/photos.html HTTP/1.0\" 200 1482\n192.190.252.20 - - [31/Aug/1995:18:23:32 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\n198.188.250.175 - - [31/Aug/1995:18:27:36 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nlapphp.in2p3.fr - - [31/Aug/1995:18:32:33 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\n131.100.160.24 - - [31/Aug/1995:18:36:37 -0400] \"GET /pub/league/sweats1.jpg HTTP/1.0\" 200 32523\n206.27.236.3 - - [31/Aug/1995:18:39:54 -0400] \"GET /pub/jeffd/grad_lin.gif HTTP/1.0\" 200 3346\nmorti.eng2.uconn.edu - - [31/Aug/1995:18:43:01 -0400] \"GET /pub/job/swim/swim.jpg HTTP/1.0\" 200 17401\nwww-c5.proxy.aol.com - - [31/Aug/1995:18:46:07 -0400] \"GET /pub/brendan/suspectm.gif HTTP/1.0\" 200 30603\ngk-west.usps.gov - - [31/Aug/1995:18:50:34 -0400] \"GET /pub/job/vk/vendela2.html HTTP/1.0\" 200 8267\nnewsgw.mentorg.com - - [31/Aug/1995:18:54:26 -0400] \"GET /pub/theme/ HTTP/1.0\" 200 799\n130.68.26.52 - - [31/Aug/1995:18:58:35 -0400] \"GET /pub/phil/images/jh61.gif HTTP/1.0\" 200 2456\nfnugget.intel.com - - [31/Aug/1995:19:01:51 -0400] \"GET /pub/job/swim/v-05.jpg HTTP/1.0\" 200 2957\nppp04.vestnett.no - - [31/Aug/1995:19:07:06 -0400] \"GET /pub/alweiner/new.gif HTTP/1.0\" 200 313\n128.171.46.72 - - [31/Aug/1995:19:11:55 -0400] \"GET /pub/pribut/sb-1-2.gif HTTP/1.0\" 200 1253\nad01-026.compuserve.com - - [31/Aug/1995:19:16:09 -0400] \"GET /pub/networx/autopage/exotic/ex002_1.gif HTTP/1.0\" 200 71366\nmall24.tiac.net - - [31/Aug/1995:19:20:26 -0400] \"GET /pub/lupine/www/tlk/cast.html HTTP/1.0\" 200 3150\n129.219.51.118 - - [31/Aug/1995:19:25:07 -0400] \"GET /pub/wmcbrine/html/Madonna.html HTTP/1.0\" 200 13440\n158.68.225.182 - - [31/Aug/1995:19:30:36 -0400] \"GET /pub/jellybn/back.gif HTTP/1.0\" 200 883\n192.43.248.56 - - [31/Aug/1995:19:35:44 -0400] \"GET /pub/job/vk/view13.jpg HTTP/1.0\" 200 6219\nwww-e5.proxy.aol.com - - [31/Aug/1995:19:40:26 -0400] \"GET /mc-icons/back.gif HTTP/1.0\" 200 174\ncepc4.swan.ac.uk - - [31/Aug/1995:19:46:43 -0400] \"GET /pub/job/vk/vk-page2.jpg HTTP/1.0\" 200 10302\ndunn.nmt.edu - - [31/Aug/1995:19:51:29 -0400] \"GET /pub/peace/VRSBUS.html HTTP/1.0\" 200 2093\nstimpy.clark.net - - [31/Aug/1995:19:56:53 -0400] \"GET /pub/phil/images/jh22.gif HTTP/1.0\" 304 -\nDarcy.islandnet.com - - [31/Aug/1995:20:00:39 -0400] \"GET /pub/rmharris/images/clark.gif HTTP/1.0\" 200 5823\n205.237.236.36 - - [31/Aug/1995:20:05:21 -0400] \"GET /atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nmed-bcmm-kstar-node.med.yale.edu - - [31/Aug/1995:20:10:55 -0400] \"GET /pub/job/vk/view31.jpg HTTP/1.0\" 200 5611\ncs0.dasd.honeywell.com - - [31/Aug/1995:20:16:16 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\nad22-022.compuserve.com - - [31/Aug/1995:20:22:22 -0400] \"GET /pub/sshay/images/brwthumb.jpg HTTP/1.0\" 200 3306\nbway-slip7.dynamic.usit.net - - [31/Aug/1995:20:26:55 -0400] \"GET /pub/k2/am4x44u/gifs/yellwpin.gif HTTP/1.0\" 304 -\n192.100.197.125 - - [31/Aug/1995:20:33:08 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\ngw3.att.com - - [31/Aug/1995:20:38:08 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\n204.157.204.210 - - [31/Aug/1995:20:42:22 -0400] \"GET /pub/abaa-booknet/images/clark.gif HTTP/1.0\" 200 5823\ndal04-05.ppp.iadfw.net - - [31/Aug/1995:20:47:31 -0400] \"GET /pub/alweiner/a27.gif HTTP/1.0\" 200 4594\ndialup10.wdbg.va.qnet.com - - [31/Aug/1995:20:54:47 -0400] \"GET /printing HTTP/1.0\" 302 216\n165.152.162.22 - - [31/Aug/1995:21:01:10 -0400] \"GET /pub/job/vk/view12.jpg HTTP/1.0\" 200 5966\npppcib119.asahi-net.or.jp - - [31/Aug/1995:21:08:08 -0400] \"GET /pub/journalism/awesome.htmli HTTP/1.0\" 404 318\nkuts10p08.cc.ukans.edu - - [31/Aug/1995:21:13:34 -0400] \"GET /pub/job/vk/view01.jpg HTTP/1.0\" 304 -\n199.4.102.43 - - [31/Aug/1995:21:19:30 -0400] \"GET /pub/alweiner/spacer.gif HTTP/1.0\" 200 810\nxenon.chem.ucla.edu - - [31/Aug/1995:21:26:13 -0400] \"GET /pub/atomicbk/images/busty.gif HTTP/1.0\" 200 73609\n205.144.62.141 - - [31/Aug/1995:21:31:36 -0400] \"GET /pub/job/swim/v-12.jpg HTTP/1.0\" 200 2625\nnoyce.caere.com - - [31/Aug/1995:21:35:55 -0400] \"GET /pub/sshay/images/partner.gif HTTP/1.0\" 200 14363\naha401.ccs.itd.umich.edu - - [31/Aug/1995:21:42:03 -0400] \"GET /pub/downin/html/backgrounds/iceblue.gif HTTP/1.0\" 200 2301\nts1-9.net.netbistro.com - - [31/Aug/1995:21:49:09 -0400] \"GET /atomicbk/shocked/shocked.jpg HTTP/1.0\" 200 43819\nbarb.wchat.on.ca - - [31/Aug/1995:21:55:18 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\ncl196042.callutheran.edu - - [31/Aug/1995:22:00:57 -0400] \"GET /pub/networx/autopage/dealers/de001_cs.gif HTTP/1.0\" 200 1995\nvern-a2.ip.realtime.net - - [31/Aug/1995:22:07:27 -0400] \"GET /pub/hutchens/chicksquawk.aiff HTTP/1.0\" 200 25980\ncamille.amgen.com - - [31/Aug/1995:22:13:17 -0400] \"GET /pub/job/vk/view10.jpg HTTP/1.0\" 200 5303\npiweba3y.prodigy.com - - [31/Aug/1995:22:18:31 -0400] \"GET /pub/k2/am4x44u/gifs/ppcat800.gif HTTP/1.0\" 200 2883\ndd01-021.compuserve.com - - [31/Aug/1995:22:23:50 -0400] \"GET /pub/mrosen/usta.html HTTP/1.0\" 200 5192\nyorick.umd.edu - - [31/Aug/1995:22:29:20 -0400] \"GET /larouche/nigeria.html HTTP/1.0\" 200 10303\ncentral17.onramp.net - - [31/Aug/1995:22:35:45 -0400] \"GET /pub/robert/home.html HTTP/1.0\" 200 1992\nBIO.BU.EDU - - [31/Aug/1995:22:42:03 -0400] \"GET /pub/job/vk/view33.jpg HTTP/1.0\" 200 5903\ndpi-gw.ind.dpi.qld.gov.au - - [31/Aug/1995:22:47:56 -0400] \"GET /pub/atomicbk/images/taste.gif HTTP/1.0\" 200 32694\n198.248.98.86 - - [31/Aug/1995:22:53:36 -0400] \"GET /pub/howieb/howie2.gif HTTP/1.0\" 200 31464\nwww-a2.proxy.aol.com - - [31/Aug/1995:22:57:57 -0400] \"GET /pub/k2/am4x44u/events/adventure/sfnc2.htm HTTP/1.0\" 200 3677\ndial66.phoenix.net - - [31/Aug/1995:23:02:43 -0400] \"GET /pub/sshay/images/narcisis.jpg HTTP/1.0\" 200 39523\nXR01-A9.citenet.net - - [31/Aug/1995:23:07:43 -0400] \"GET /pub/atomicbk/images/tease.gif HTTP/1.0\" 200 43516\nslip104-85.mn.us.ibm.net - - [31/Aug/1995:23:14:15 -0400] \"GET /pub/job/vk/view01.jpg HTTP/1.0\" 200 5733\n161.69.133.57 - - [31/Aug/1995:23:20:48 -0400] \"GET /pub/job/vk/view33.jpg HTTP/1.0\" 200 5903\nlan104.rocktel.com - - [31/Aug/1995:23:26:05 -0400] \"GET /pub/k2/am4x44u/gifs/redball.gif HTTP/1.0\" 200 206\nwww.ottawa.net - - [31/Aug/1995:23:32:20 -0400] \"GET /pub/pribut/idea.gif HTTP/1.0\" 200 909\n156.50.118.36 - - [31/Aug/1995:23:38:54 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\ncomserv-i-26.usc.edu - - [31/Aug/1995:23:44:47 -0400] \"GET /pub/mbrophy/pix/imgsite.jpg HTTP/1.0\" 200 11636\ndd22-021.compuserve.com - - [31/Aug/1995:23:50:19 -0400] \"GET /pub/jeffd/final.html HTTP/1.0\" 200 66219\npiweba4y.prodigy.com - - [31/Aug/1995:23:56:50 -0400] \"GET /pub/k2/am4x44u/gifs/vidlib.gif HTTP/1.0\" 200 2138\n150.216.65.55 - - [01/Sep/1995:00:02:08 -0400] \"GET /pub/job/vk/v-sig.gif HTTP/1.0\" 200 4864\nsukiyaki.nri.com - - [01/Sep/1995:00:07:25 -0400] \"GET /pub/howie/OO/construc.gif HTTP/1.0\" 200 252\nJH220-D327.Student-Lab.Butler.EDU - - [01/Sep/1995:00:13:06 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\n199.74.248.32 - - [01/Sep/1995:00:20:21 -0400] \"GET /pub/k2/am4x44u/maps/events.gif HTTP/1.0\" 304 -\nSEC007.spu.edu - - [01/Sep/1995:00:26:37 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nbfld-21.rust.net - - [01/Sep/1995:00:31:27 -0400] \"GET /pub/sshay/images/jaseeddy.gif HTTP/1.0\" 304 -\ndu139-222.cc.iastate.edu - - [01/Sep/1995:00:36:28 -0400] \"GET /pub/job/vk/vk-ad-02.jpg HTTP/1.0\" 200 82972\nkali.me.ksu.edu - - [01/Sep/1995:00:42:44 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\nrvlink.rvlink.com - - [01/Sep/1995:00:48:57 -0400] \"GET /pub/k2/am4x44u/gifs/alum1.gif HTTP/1.0\" 304 -\nad02-032.compuserve.com - - [01/Sep/1995:00:54:44 -0400] \"GET /pub/rsjdfg/ProTic.html HTTP/1.0\" 200 2453\nbitnaut.wat.hookup.net - - [01/Sep/1995:01:02:30 -0400] \"GET /pub/k2/am4x44u/maps/truck_tech.gif HTTP/1.0\" 200 41160\ngondola.ipc.otaru-uc.ac.jp - - [01/Sep/1995:01:08:52 -0400] \"GET /pub/lupine/images/tlk/pride-rock.gif HTTP/1.0\" 200 51600\nlabpc40.acs.uci.edu - - [01/Sep/1995:01:15:57 -0400] \"GET /pub/kboahene/photoa.gif HTTP/1.0\" 200 16963\nalfred.uib.no - - [01/Sep/1995:01:21:23 -0400] \"GET /pub/job/vk/note.gif HTTP/1.0\" 200 9413\nmassif.helix.net - - [01/Sep/1995:01:26:51 -0400] \"GET /pub/alweiner/spacer.gif HTTP/1.0\" 304 -\ndmouton.amgen.com - - [01/Sep/1995:01:34:44 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\nad01-027.compuserve.com - - [01/Sep/1995:01:43:18 -0400] \"GET /pub/pgarrett/sober.wav HTTP/1.0\" 200 60176\nPELLEW.NTU.EDU.AU - - [01/Sep/1995:01:52:18 -0400] \"GET /pub/networx/cris2.gif HTTP/1.0\" 200 8473\npipe3.h1.usa.pipeline.com - - [01/Sep/1995:02:01:11 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\nfirefly.prairienet.org - - [01/Sep/1995:02:10:59 -0400] \"GET /pub/sshay/links.html HTTP/1.0\" 200 2992\nmozart.forest.dnj.ynu.ac.jp - - [01/Sep/1995:02:19:20 -0400] \"GET /pub/fan/discog.html HTTP/1.0\" 200 3266\ncbriggs.interlog.com - - [01/Sep/1995:02:27:04 -0400] \"GET /pub/alweiner/eye.gif HTTP/1.0\" 304 -\n193.13.222.40 - - [01/Sep/1995:02:37:18 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\ndialup1.qnis.net - - [01/Sep/1995:02:43:32 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nnikhefh.nikhef.nl - - [01/Sep/1995:02:52:23 -0400] \"GET /pub/wick/photos/chair_mini.gif HTTP/1.0\" 200 12589\nkema.vxo.telub.se - - [01/Sep/1995:03:00:51 -0400] \"GET /pub/atomicbk/catalog/pinup.html HTTP/1.0\" 200 8316\nnet-5.pix.za - - [01/Sep/1995:03:09:36 -0400] \"GET /atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6688\nad10-005.compuserve.com - - [01/Sep/1995:03:19:17 -0400] \"GET /pub/wsg/html/web/portfoli.html HTTP/1.0\" 200 2341\nix-la24-28.ix.netcom.com - - [01/Sep/1995:03:28:58 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\noume-gate.meisei-u.ac.jp - - [01/Sep/1995:03:36:54 -0400] \"GET /pub/job/vk/arrow-r.gif HTTP/1.0\" 200 3042\nCust45.Max2.San-Francisco.CA.MS.UU.NET - - [01/Sep/1995:03:46:27 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\ndd05-020.compuserve.com - - [01/Sep/1995:03:56:56 -0400] \"GET /pub/networx/autopage/exotic.html HTTP/1.0\" 200 1274\nproxy.umu.se - - [01/Sep/1995:04:08:54 -0400] \"GET /pub/job/mail.jpg HTTP/1.0\" 200 4282\n199.183.254.10 - - [01/Sep/1995:04:22:41 -0400] \"GET /pub/WWIV/PLANETB.GIF HTTP/1.0\" 200 5008\ngregal.uji.es - - [01/Sep/1995:04:35:08 -0400] \"GET /pub/rjgula/ HTTP/1.0\" 200 -\n192.101.124.43 - - [01/Sep/1995:04:46:33 -0400] \"GET /pub/ashp/grafx/phone6.jpg HTTP/1.0\" 200 10607\nts900-1021.singnet.com.sg - - [01/Sep/1995:05:00:01 -0400] \"GET /atomicbk/images/emboss.jpg HTTP/1.0\" 200 4741\n161.142.15.180 - - [01/Sep/1995:05:14:15 -0400] \"GET /pub/ashp/grafx/globe.gif HTTP/1.0\" 403 142\ndialup42.geko.com.au - - [01/Sep/1995:05:27:27 -0400] \"GET /pub/atomicbk/new/email.gif HTTP/1.0\" 200 756\n130.99.86.92 - - [01/Sep/1995:05:42:12 -0400] \"GET /pub/job/vk/view29.jpg HTTP/1.0\" 200 6695\nrzsuna.rrze.uni-erlangen.de - - [01/Sep/1995:05:54:46 -0400] \"GET /pub/mbrophy/pix/arling.jpg HTTP/1.0\" 200 7905\nfaith.waikato.ac.nz - - [01/Sep/1995:06:07:42 -0400] \"GET /pub/zilla/sick.html HTTP/1.0\" 200 2359\nbombasto.Informatik.RWTH-Aachen.DE - - [01/Sep/1995:06:23:12 -0400] \"GET /pub/mbrophy/interviews.html HTTP/1.0\" 200 1279\nslip36-78.il.us.ibm.net - - [01/Sep/1995:06:39:27 -0400] \"GET /pub/wick/otherpages.html HTTP/1.0\" 200 1024\nmiller.cad.cea.fr - - [01/Sep/1995:06:50:33 -0400] \"GET /pub/job/vk/note.gif HTTP/1.0\" 200 9413\nts900-1201.singnet.com.sg - - [01/Sep/1995:07:03:03 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\n145.2.134.83 - - [01/Sep/1995:07:14:31 -0400] \"GET /pub/job/vk/view18.jpg HTTP/1.0\" 200 6578\n164.117.161.206 - - [01/Sep/1995:07:25:36 -0400] \"GET /pub/peace/VRSAA.GIF HTTP/1.0\" 200 30837\n204.101.53.170 - - [01/Sep/1995:07:34:03 -0400] \"GET /pub/alweiner/thin_gre.gif HTTP/1.0\" 200 78\numav115.verwaltung.uni-mannheim.de - - [01/Sep/1995:07:40:30 -0400] \"GET /pub/k2/am4x44u/maps/4x4_home.gif HTTP/1.0\" 200 43750\n202.252.76.14 - - [01/Sep/1995:07:47:30 -0400] \"GET /pub/job/vk/2-page-1.gif HTTP/1.0\" 200 2733\naspen.plexus.com - - [01/Sep/1995:07:53:41 -0400] \"GET /pub/k2/jeep/jeep.htm HTTP/1.0\" 200 1047\nlab11.civil.dundee.ac.uk - - [01/Sep/1995:08:02:59 -0400] \"GET /pub/job/vk/view23.jpg HTTP/1.0\" 200 5165\nmersey.hursley.ibm.com - - [01/Sep/1995:08:10:22 -0400] \"GET /pub/atomicbk/images/venusinf.gif HTTP/1.0\" 200 53308\nwww-b4.proxy.aol.com - - [01/Sep/1995:08:18:41 -0400] \"GET /pub/job/vk/view11.jpg HTTP/1.0\" 200 5001\nsunsite.nus.sg - - [01/Sep/1995:08:25:03 -0400] \"GET /pub/sshay/interact.html HTTP/1.0\" 304 -\nnews.ti.com - - [01/Sep/1995:08:30:53 -0400] \"GET /pub/job/vk/view27.jpg HTTP/1.0\" 200 6611\ngatekeeper.ray.com - - [01/Sep/1995:08:37:22 -0400] \"GET /pub/stc/www/gifs/home_sm.gif HTTP/1.0\" 200 273\ncsgps1.leeds.ac.uk - - [01/Sep/1995:08:43:29 -0400] \"GET /pub/job/vk/view26.jpg HTTP/1.0\" 200 6186\nkaarna.cc.jyu.fi - - [01/Sep/1995:08:50:15 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nas2.cs.gmr.com - - [01/Sep/1995:08:58:05 -0400] \"GET /pub/global/globe.gif HTTP/1.0\" 200 703\nh-dracula.nr.infi.net - - [01/Sep/1995:09:04:12 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\n128.206.21.213 - - [01/Sep/1995:09:09:48 -0400] \"GET /pub/abaa-booknet/whatsnew.html HTTP/1.0\" 200 13586\ninfo.telenor.no - - [01/Sep/1995:09:16:28 -0400] \"GET /pub/job/vk/arrow-r.gif HTTP/1.0\" 200 3042\n213123.nhn.navair.navy.mil - - [01/Sep/1995:09:21:45 -0400] \"GET /pub/peace/PeaceCorps.html HTTP/1.0\" 200 510\nscrimal.camp.org - - [01/Sep/1995:09:26:51 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\ncinnamon.spice.com - - [01/Sep/1995:09:30:59 -0400] \"GET /pub/alweiner/work/spacer10.gif HTTP/1.0\" 200 44\n170.142.8.139 - - [01/Sep/1995:09:34:55 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nfad4f7fe.fad.okstate.edu - - [01/Sep/1995:09:38:31 -0400] \"GET /pub/russadam/bbsbut.gif HTTP/1.0\" 304 -\nix-stl3-21.ix.netcom.com - - [01/Sep/1995:09:43:01 -0400] \"GET /pub/cardman/ask.htm HTTP/1.0\" 200 1269\nrelay.tqs.iunet.it - - [01/Sep/1995:09:47:42 -0400] \"GET /pub/kiaman/sound03.gif HTTP/1.0\" 200 1201\nwww-b6.proxy.aol.com - - [01/Sep/1995:09:52:42 -0400] \"GET /pub/job/vk/arrow-l.gif HTTP/1.0\" 200 3031\n193.131.192.35 - - [01/Sep/1995:09:57:45 -0400] \"GET /atomicbk/new/logo2.gif HTTP/1.0\" 200 12871\nbox255.labs.cis.pitt.edu - - [01/Sep/1995:10:03:21 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nppp-hck-1-17.ios.com - - [01/Sep/1995:10:08:15 -0400] \"GET /pub/wine/portbtn.gif HTTP/1.0\" 200 764\nsabre21.sasknet.sk.ca - - [01/Sep/1995:10:12:47 -0400] \"GET /pub/rsjdfg HTTP/1.0\" 302 218\ngatekeeper.tv2.no - - [01/Sep/1995:10:17:57 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\n147.134.225.168 - - [01/Sep/1995:10:22:49 -0400] \"GET /pub/mbrophy/pix/interv.jpg HTTP/1.0\" 200 5047\n156.40.174.153 - - [01/Sep/1995:10:26:00 -0400] \"GET /pub/cybersoft/graphics/colorbar.gif HTTP/1.0\" 200 479\nmhoolboo.worldbank.org - - [01/Sep/1995:10:29:24 -0400] \"GET /infouser/logsnap.txt HTTP/1.0\" 304 -\nGayle-Gaston.tenet.edu - - [01/Sep/1995:10:33:11 -0400] \"GET /pub/robert/home.html HTTP/1.0\" 200 1992\nusr12-dialup34.Atlanta.mci.net - - [01/Sep/1995:10:37:42 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 200 11610\nexlsun.epm.ornl.gov - - [01/Sep/1995:10:41:38 -0400] \"GET /pub/job/mail.jpg HTTP/1.0\" 200 4282\ngator01.iit.edu - - [01/Sep/1995:10:45:19 -0400] \"GET /pub/networx/autopage/dealers/de001_3.html HTTP/1.0\" 200 541\n146.186.65.26 - - [01/Sep/1995:10:49:42 -0400] \"GET /pub/lupine/www/images/icons/note.gif HTTP/1.0\" 200 565\nalweiner.clark.net - - [01/Sep/1995:10:53:44 -0400] \"GET /pub/alweiner/reddot.gif HTTP/1.0\" 200 886\ndd24-003.compuserve.com - - [01/Sep/1995:10:58:08 -0400] \"GET /atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\n146.13.185.67 - - [01/Sep/1995:11:01:55 -0400] \"GET /pub/mbrophy/pix/sbpromo.jpg HTTP/1.0\" 200 14185\np2.ts1.walrus.com - - [01/Sep/1995:11:06:37 -0400] \"GET /pub/mpowers/j4j/web/ HTTP/1.0\" 200 1735\nNUBS35.ccs.itd.umich.edu - - [01/Sep/1995:11:10:42 -0400] \"GET /pub/lupine/www/images/icons/roundbtn.gif HTTP/1.0\" 200 1077\nfad4f7fe.fad.okstate.edu - - [01/Sep/1995:11:14:46 -0400] \"GET /pub/russadam/tblite.gif HTTP/1.0\" 200 8066\nwatt.oedison.com - - [01/Sep/1995:11:18:23 -0400] \"GET /pub/pribut/backgrou.gif HTTP/1.0\" 304 -\nrm003a63.brookes.ac.uk - - [01/Sep/1995:11:22:08 -0400] \"GET /pub/job/theman.jpg HTTP/1.0\" 200 8905\nslip101.gamemaster.qc.ca - - [01/Sep/1995:11:26:32 -0400] \"GET /pub/mbrophy/pix/louie.jpg HTTP/1.0\" 200 4544\ngsi32.gestalt-sys.com - - [01/Sep/1995:11:30:04 -0400] \"GET /pub/cargui/btn_prev.gif HTTP/1.0\" 304 -\nwww-c3.proxy.aol.com - - [01/Sep/1995:11:33:50 -0400] \"GET /pub/job/swim/v-13.jpg HTTP/1.0\" 200 2985\nbus2_2.bus.misu.NoDak.edu - - [01/Sep/1995:11:38:16 -0400] \"GET /pub/cargui/links.html HTTP/1.0\" 200 6417\nPCEAS4.SAS.UPENN.EDU - - [01/Sep/1995:11:41:47 -0400] \"GET /atomicbk/catalog/home.gif HTTP/1.0\" 200 813\njstone.clark.net - - [01/Sep/1995:11:45:44 -0400] \"GET /pub/gen/mswg/seawolf/ HTTP/1.0\" 304 -\niglou2.iglou.com - - [01/Sep/1995:11:49:35 -0400] \"GET /pub/macgyver/VidGames/Vidgames.html HTTP/1.0\" 200 29810\n199.78.230.18 - - [01/Sep/1995:11:53:41 -0400] \"GET /pub/theme/cgi-bin/ign.html/l/Frankie Ybanez/n/citationx/ HTTP/1.0\" 200 588\nmempc103.unibe.ch - - [01/Sep/1995:11:57:47 -0400] \"GET /pub/pribut/email2.gif HTTP/1.0\" 200 1209\nwph-pc11.usc.edu - - [01/Sep/1995:12:02:56 -0400] \"GET /pub/rsjdfg HTTP/1.0\" 302 218\ndial-30.win.net - - [01/Sep/1995:12:07:11 -0400] \"GET /pub/ibos/watkins/hands4.gif HTTP/1.0\" 200 22770\nmersey.hursley.ibm.com - - [01/Sep/1995:12:10:33 -0400] \"GET /atomicbk/scotth.gif HTTP/1.0\" 200 790\nhamlet.fokus.gmd.de - - [01/Sep/1995:12:13:28 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\nhucomgw.hucom.co.jp - - [01/Sep/1995:12:17:03 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\nmacbeth.umd.edu - - [01/Sep/1995:12:21:03 -0400] \"GET /html/phones.html HTTP/1.0\" 200 8840\n165.247.243.4 - - [01/Sep/1995:12:25:32 -0400] \"GET /pub/job/swim/ss-10.jpg HTTP/1.0\" 200 74315\ncherubim.rp.org - - [01/Sep/1995:12:29:47 -0400] \"GET /pub/atomicbk/contest.gif HTTP/1.0\" 200 669\nppptky132.asahi-net.or.jp - - [01/Sep/1995:12:33:38 -0400] \"GET /pub/sinkers/signicon.gif HTTP/1.0\" 200 4911\nbutchp2.si.univ-compiegne.fr - - [01/Sep/1995:12:37:32 -0400] \"GET /pub/atomicbk/home.html HTTP/1.0\" 200 4051\nDTNET43-170.dt.navy.mil - - [01/Sep/1995:12:41:24 -0400] \"GET /pub/job/vk/2-page-2.gif HTTP/1.0\" 200 2527\ngalileo.thp.univie.ac.at - - [01/Sep/1995:12:45:09 -0400] \"GET /pub/jeffd/header.gif HTTP/1.0\" 200 24376\narh_gate-pm.winternet.com - - [01/Sep/1995:12:48:47 -0400] \"GET /atomicbk/images/atomgirl.jpg HTTP/1.0\" 200 34164\nts5-03.InfoRamp.Net - - [01/Sep/1995:12:52:06 -0400] \"GET /pub/nractive/images/wbtic.gif HTTP/1.0\" 200 15873\n141.233.134.22 - - [01/Sep/1995:12:54:57 -0400] \"GET /pub/listserv/yellowli.gif HTTP/1.0\" 200 905\nhamlet.fokus.gmd.de - - [01/Sep/1995:12:58:54 -0400] \"GET /pub/job/vk/view26.jpg HTTP/1.0\" 200 6186\n128.95.51.215 - - [01/Sep/1995:13:02:42 -0400] \"GET /pub/lupine/images/tlk/tlk-card.gif HTTP/1.0\" 200 15142\nwww-b3.proxy.aol.com - - [01/Sep/1995:13:07:03 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 200 11610\n192.100.197.102 - - [01/Sep/1995:13:10:19 -0400] \"GET /pub/k2/am4x44u/truck_stop/truck_stop.htm HTTP/1.0\" 200 1467\npc.chem.sc.edu - - [01/Sep/1995:13:14:24 -0400] \"GET /pub/theme/demockracy/thanks.html HTTP/1.0\" 200 497\ncorrigan-ppp.clark.net - - [01/Sep/1995:13:17:18 -0400] \"GET /pub/corrigan/czech.gif HTTP/1.0\" 304 -\nunknown-181.soe.umich.edu - - [01/Sep/1995:13:20:36 -0400] \"GET /tara/sacpl10k.htm HTTP/1.0\" 200 800\nproxy.austin.ibm.com - - [01/Sep/1995:13:24:44 -0400] \"GET /pub/heroes/wldtrade.html HTTP/1.0\" 200 1342\nts900-1408.singnet.com.sg - - [01/Sep/1995:13:28:36 -0400] \"GET /pub/sshay/interact.html HTTP/1.0\" 200 2541\n129.174.32.36 - - [01/Sep/1995:13:31:38 -0400] \"GET /pub/jrinker/cbutun1.gif HTTP/1.0\" 200 2638\nftp-relay.mv.us.adobe.com - - [01/Sep/1995:13:35:11 -0400] \"GET /pub/job/vk/view34.jpg HTTP/1.0\" 200 5156\nrajeesh.WPI.EDU - - [01/Sep/1995:13:38:44 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\nloon.house.leg.state.mn.us - - [01/Sep/1995:13:42:51 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\nmac3141.affymax.com - - [01/Sep/1995:13:47:34 -0400] \"GET /pub/k2/am4x44u/gifs/redball.gif HTTP/1.0\" 200 206\nr14s2.nswc.navy.mil - - [01/Sep/1995:13:51:51 -0400] \"GET /pub/job/vk/view12.jpg HTTP/1.0\" 200 5966\nvan11313.direct.ca - - [01/Sep/1995:13:55:09 -0400] \"GET /pub/rsjdfg/Pictures/Heat.jpg HTTP/1.0\" 304 -\nimperial.rp1.sdl.usu.edu - - [01/Sep/1995:13:58:36 -0400] \"GET /pub/k2/am4x44u/gifs/ttiplin2.gif HTTP/1.0\" 200 2958\n192.5.63.93 - - [01/Sep/1995:14:01:22 -0400] \"GET /pub/atomicbk/images/adbaby.gif HTTP/1.0\" 200 72807\npc1419.utdallas.edu - - [01/Sep/1995:14:04:31 -0400] \"GET /pub/kiaman/or_ball.gif HTTP/1.0\" 200 967\nasm4-3.sl115.cns.vt.edu - - [01/Sep/1995:14:08:25 -0400] \"GET /pub/sshay/images/brwthumb.jpg HTTP/1.0\" 200 3306\n198.29.27.10 - - [01/Sep/1995:14:13:10 -0400] \"GET /pub/mackall/home.html HTTP/1.0\" 200 331\n152.120.105.199 - - [01/Sep/1995:14:16:41 -0400] \"GET /pub/tmphoto/rmd.homicide.pages/homicide.3.rmd.gif HTTP/1.0\" 200 28603\nhamlet.fokus.gmd.de - - [01/Sep/1995:14:19:15 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\npiweba5y.prodigy.com - - [01/Sep/1995:14:22:02 -0400] \"GET /pub/lschank/web/census.html HTTP/1.0\" 200 13912\nmercury.image.ctt.com - - [01/Sep/1995:14:25:04 -0400] \"GET /nrlc/btn1.gif HTTP/1.0\" 200 407\neuropa.sunlab.ece.usu.edu - - [01/Sep/1995:14:27:25 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\necn1521925.gsfc.nasa.gov - - [01/Sep/1995:14:30:33 -0400] \"GET /pub/jeffd/back.gif HTTP/1.0\" 404 331\ngateway.senate.gov - - [01/Sep/1995:14:33:32 -0400] \"GET /pub/jeffd/unchkbox.gif HTTP/1.0\" 200 855\nstsim.interax.net - - [01/Sep/1995:14:38:09 -0400] \"GET /pub/listserv/listserv.html HTTP/1.0\" 200 1138\ndts.rrddts.donnelley.com - - [01/Sep/1995:14:41:44 -0400] \"GET /pub/shelby/yellowli.gif HTTP/1.0\" 200 905\nAL207H1.MNSFLD.EDU - - [01/Sep/1995:14:46:47 -0400] \"GET /pub/lschank/web/new.gif HTTP/1.0\" 304 -\n199.234.151.14.du.nauticom.net - - [01/Sep/1995:14:51:02 -0400] \"GET /pub/cardman/1vote.gif HTTP/1.0\" 200 1284\nstore.lutz.com - - [01/Sep/1995:14:54:05 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nbader.moc.kw - - [01/Sep/1995:14:57:35 -0400] \"GET /pub/jeffd/header.gif HTTP/1.0\" 200 24376\npentium22.ee.umr.edu - - [01/Sep/1995:15:01:11 -0400] \"GET /pub/k2/am4x44u/gifs/clwild.gif HTTP/1.0\" 200 1227\nhickory.cad.clarkson.edu - - [01/Sep/1995:15:04:26 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nnmpch.nokia.com - - [01/Sep/1995:15:07:47 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\ndobrien.clark.net - - [01/Sep/1995:15:10:43 -0400] \"GET /pub/sshay/images/rgblack.jpg HTTP/1.0\" 304 -\ne659229.boeing.com - - [01/Sep/1995:15:14:02 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\nhpux.nis.za - - [01/Sep/1995:15:17:38 -0400] \"GET /pub/k2/cgi-bin/imagemap/4x4_home?77,85 HTTP/1.0\" 200 1298\nlaw-pc28.law.utexas.edu - - [01/Sep/1995:15:21:11 -0400] \"GET /pub/peace/casset.gif HTTP/1.0\" 200 1071\neels11.ee.surrey.ac.uk - - [01/Sep/1995:15:24:26 -0400] \"GET /pub/job/vk/2-page-1.gif HTTP/1.0\" 200 2733\n151.186.72.43 - - [01/Sep/1995:15:26:54 -0400] \"GET /pub/job/theman.jpg HTTP/1.0\" 200 8905\ngateway.TPP.com - - [01/Sep/1995:15:29:25 -0400] \"GET /pub/job/swim/v-11.jpg HTTP/1.0\" 200 2419\nserver03.zrz.TU-Berlin.DE - - [01/Sep/1995:15:32:50 -0400] \"GET /pub/heroes/gifs/language.gif HTTP/1.0\" 200 29097\npme000.awinc.com - - [01/Sep/1995:15:35:34 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nr1001326.mayo.edu - - [01/Sep/1995:15:39:02 -0400] \"GET /pub/atomicbk/artgal.gif HTTP/1.0\" 200 823\napci.com - - [01/Sep/1995:15:42:19 -0400] \"GET /pub/watc/gifs/LINE.GIF HTTP/1.0\" 404 308\n128.206.98.205 - - [01/Sep/1995:15:45:28 -0400] \"GET /pub/lupine/www/images/icons/paint.gif HTTP/1.0\" 200 516\n157.136.21.194 - - [01/Sep/1995:15:48:18 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\n166.41.232.99 - - [01/Sep/1995:15:51:48 -0400] \"GET /pub/mmathai/mls/images/halfmls.gif HTTP/1.0\" 200 5483\njlehett.iag.net - - [01/Sep/1995:15:55:29 -0400] \"GET /pub/pwalker/ball.gif HTTP/1.0\" 200 953\nengn-6.olivet.edu - - [01/Sep/1995:15:59:35 -0400] \"GET /atomicbk/logo2.gif HTTP/1.0\" 200 12871\nppp08-17.rns.tamu.edu - - [01/Sep/1995:16:03:42 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\n128.231.232.101 - - [01/Sep/1995:16:06:24 -0400] \"GET /pub/wine/sauterne.gif HTTP/1.0\" 200 16992\n132.235.105.46 - - [01/Sep/1995:16:09:31 -0400] \"GET /pub/sshay/images/tyusvest.jpg HTTP/1.0\" 200 26791\natom.terranet.com - - [01/Sep/1995:16:13:53 -0400] \"GET /pub/jgbustam/gifs/at-work.gif HTTP/1.0\" 200 373\n128.160.55.8 - - [01/Sep/1995:16:17:45 -0400] \"GET /pub/job/vk/view11.jpg HTTP/1.0\" 200 5001\n132.236.113.193 - - [01/Sep/1995:16:21:32 -0400] \"GET /pub/rsjdfg/Pictures/AmericanMan.jpg HTTP/1.0\" 200 44118\ncomp.uark.edu - - [01/Sep/1995:16:24:23 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\nix-rea-pa1-22.ix.netcom.com - - [01/Sep/1995:16:27:15 -0400] \"GET /atomicbk/catalog/catalog.html HTTP/1.0\" 200 4654\n137.91.85.202 - - [01/Sep/1995:16:31:18 -0400] \"GET /pub/fervor/meet.htm HTTP/1.0\" 200 787\nptpm002.olympus.net - - [01/Sep/1995:16:34:55 -0400] \"GET /pub/mharding/Ragedoc23.GIF HTTP/1.0\" 200 32467\n139.87.20.145 - - [01/Sep/1995:16:39:06 -0400] \"GET /pub/alweiner/home.gif HTTP/1.0\" 200 372\ndirectweb.com - - [01/Sep/1995:16:42:01 -0400] \"GET /pub/pgarrett/redball.gif HTTP/1.0\" 200 925\ncsmac1.ucsf.EDU - - [01/Sep/1995:16:45:38 -0400] \"GET /atomicbk/new/orders.gif HTTP/1.0\" 200 800\ntnygreen.remote.Princeton.EDU - - [01/Sep/1995:16:48:51 -0400] \"GET /pub/jeffd/back.gif HTTP/1.0\" 404 207\nwww-b5.proxy.aol.com - - [01/Sep/1995:16:52:00 -0400] \"GET /pub/k2/am4x44u/gifs/ambut.gif HTTP/1.0\" 200 213\n140.175.22.107 - - [01/Sep/1995:16:55:25 -0400] \"GET /pub/jeffd/spkrnewt.gif HTTP/1.0\" 200 45247\n163.185.21.182 - - [01/Sep/1995:16:58:58 -0400] \"GET /pub/job/vk/2-page-1.gif HTTP/1.0\" 200 2733\nsabre20.sasknet.sk.ca - - [01/Sep/1995:17:02:47 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\n137.240.150.204 - - [01/Sep/1995:17:06:31 -0400] \"GET /pub/k2/am4x44u/trails/books/books.htm HTTP/1.0\" 200 298\nchrivb01.cch.com - - [01/Sep/1995:17:10:00 -0400] \"GET /pub/murple/drugs.html HTTP/1.0\" 404 329\nprpayne-ppp.clark.net - - [01/Sep/1995:17:13:59 -0400] \"GET /pub/show/usboat2s.gif HTTP/1.0\" 304 -\n134.121.164.107 - - [01/Sep/1995:17:17:21 -0400] \"GET /pub/job/vk/2-page-2.gif HTTP/1.0\" 200 2527\n167.83.197.20 - - [01/Sep/1995:17:21:13 -0400] \"GET /pub/macgyver/VidGames/gifs/supernes.gif HTTP/1.0\" 200 15329\n161.31.66.37 - - [01/Sep/1995:17:26:04 -0400] \"GET /pub/rmharris/catalogs/detercat/17w-2.html HTTP/1.0\" 200 22941\nalfa.ist.utl.pt - - [01/Sep/1995:17:30:03 -0400] \"GET /pub/micros/mnet.html HTTP/1.0\" 200 1309\ngjc.delphi.com - - [01/Sep/1995:17:33:21 -0400] \"GET /pub/alweiner/work/_01711T.gif HTTP/1.0\" 200 77\nwww-d2.proxy.aol.com - - [01/Sep/1995:17:36:29 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 304 -\nhomer.SAIC.COM - - [01/Sep/1995:17:39:49 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\natomicbk-ppp.clark.net - - [01/Sep/1995:17:43:22 -0400] \"GET /graphics/wsglogo.gif HTTP/1.0\" 200 4586\nwww-e6.proxy.aol.com - - [01/Sep/1995:17:48:42 -0400] \"GET /pub/jgbustam/famosos/famei.gif HTTP/1.0\" 304 -\nnana.eunet.no - - [01/Sep/1995:17:52:52 -0400] \"GET /pub/sshay/images/swet.gif HTTP/1.0\" 200 43341\n204.249.224.107 - - [01/Sep/1995:17:56:11 -0400] \"GET /pub/atomicbk/catalog/adultcom.html HTTP/1.0\" 200 16578\n128.149.51.44 - - [01/Sep/1995:18:00:21 -0400] \"GET /pub/lupine/www/images/lines/leaves.gif HTTP/1.0\" 200 4044\nlrl0.lis.uiuc.edu - - [01/Sep/1995:18:05:05 -0400] \"GET /larouche/larouche_welcome.gif HTTP/1.0\" 200 16362\ntmrotek.bevc.blacksburg.va.us - - [01/Sep/1995:18:08:38 -0400] \"GET /pub/k2/am4x44u/4x4.htm HTTP/1.0\" 200 2788\ndisarray.demon.co.uk - - [01/Sep/1995:18:13:12 -0400] \"GET /pub/hutchens/budgies.html HTTP/1.0\" 200 1617\nsahp315.sandia.gov - - [01/Sep/1995:18:17:42 -0400] \"GET /pub/rsjdfg/Images/5.gif HTTP/1.0\" 200 2321\n198.109.136.6 - - [01/Sep/1995:18:22:26 -0400] \"GET /pub/sshay/images/scotswet.jpg HTTP/1.0\" 200 58027\ngamma.cleaf.com - - [01/Sep/1995:18:27:09 -0400] \"GET /atomicbk/catalog/drugs.html HTTP/1.0\" 200 23006\n199.77.68.5 - - [01/Sep/1995:18:32:03 -0400] \"GET /pub/sshay/images/nrcthumb.jpg HTTP/1.0\" 200 4215\npiweba3y.prodigy.com - - [01/Sep/1995:18:36:36 -0400] \"GET /pub/jeffd/cyberrt.gif HTTP/1.0\" 304 -\nposter.ptc.com - - [01/Sep/1995:18:41:03 -0400] \"GET /atomicbk/promo.gif HTTP/1.0\" 200 849\nGSB-MLonergan.Stanford.EDU - - [01/Sep/1995:18:44:42 -0400] \"GET /pub/aztec/mariner/marnet.html HTTP/1.0\" 200 9787\nCal046061.student.utwente.nl - - [01/Sep/1995:18:49:24 -0400] \"GET /pub/job/vk/view19.jpg HTTP/1.0\" 200 3915\ngeorgepc.tsb-intl.ca - - [01/Sep/1995:18:53:09 -0400] \"GET /pub/atomicbk/catalog/catalog.html HTTP/1.0\" 200 4654\natomicbk-ppp.clark.net - - [01/Sep/1995:18:56:42 -0400] \"GET /pub/atomicbk/home.html HTTP/1.0\" 304 -\npiweba5y.prodigy.com - - [01/Sep/1995:19:00:51 -0400] \"GET /pub/sshay/images/tywetsut.jpg HTTP/1.0\" 200 21652\nagric-bo.srv.gov.ab.ca - - [01/Sep/1995:19:05:24 -0400] \"GET /pub/atomicbk/direct.gif HTTP/1.0\" 304 -\nrichardr.nursing.arizona.edu - - [01/Sep/1995:19:09:53 -0400] \"GET /atomicbk/images/atomgirl.jpg HTTP/1.0\" 200 34164\ndavidt_pc.orem.novell.com - - [01/Sep/1995:19:14:14 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\nvan13367.direct.ca - - [01/Sep/1995:19:18:17 -0400] \"GET /atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nmsiu.res.WPI.EDU - - [01/Sep/1995:19:22:55 -0400] \"GET /pub/job/vk/v-line.gif HTTP/1.0\" 200 1254\nvisitor1.Berkeley.EDU - - [01/Sep/1995:19:28:08 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 200 11610\nwww-b1.proxy.aol.com - - [01/Sep/1995:19:33:03 -0400] \"GET /pub/lupine/www/images/icons/news.gif HTTP/1.0\" 200 1202\ngiaeb.cc.monash.edu.au - - [01/Sep/1995:19:37:43 -0400] \"GET /pub/sshay/images/hardtodd.jpg HTTP/1.0\" 200 39303\nwww-b2.proxy.aol.com - - [01/Sep/1995:19:42:32 -0400] \"GET /atomicbk/home.gif HTTP/1.0\" 200 813\n204.243.29.199 - - [01/Sep/1995:19:46:59 -0400] \"GET /pub/murple/drugs.html HTTP/1.0\" 404 313\npasyn-46.rice.edu - - [01/Sep/1995:19:51:52 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\nad22-020.compuserve.com - - [01/Sep/1995:19:58:11 -0400] \"GET /pub/mbrophy/the_scoop.html HTTP/1.0\" 200 390\nsco.clark.net - - [01/Sep/1995:20:02:34 -0400] \"GET /pub/sco/blue.gif HTTP/1.0\" 304 -\nbigred.ncsa.uiuc.edu - - [01/Sep/1995:20:07:41 -0400] \"GET /pub/howie/new.gif HTTP/1.0\" 200 116\ncmp8.ucr.edu - - [01/Sep/1995:20:13:43 -0400] \"GET /atomicbk/catalog/catalog.html HTTP/1.0\" 200 4654\ninternal003144.NeXT.COM - - [01/Sep/1995:20:18:39 -0400] \"GET /atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\ninet1.nsc.com - - [01/Sep/1995:20:24:44 -0400] \"GET /pub/cargui/btn_home.gif HTTP/1.0\" 304 -\nwww-c1.proxy.aol.com - - [01/Sep/1995:20:30:53 -0400] \"GET /pub/sshay/images/chris1.jpg HTTP/1.0\" 200 13306\nbenjy.lvision.com - - [01/Sep/1995:20:36:14 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nns1.faseb.org - - [01/Sep/1995:20:41:22 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 304 -\nppp1.itw.com - - [01/Sep/1995:20:49:16 -0400] \"GET /atomicbk/direct.gif HTTP/1.0\" 200 833\nlarmor.newton.cam.ac.uk - - [01/Sep/1995:20:54:47 -0400] \"GET /pub/job/swim/v-12.jpg HTTP/1.0\" 200 2625\nwww-b4.proxy.aol.com - - [01/Sep/1995:21:00:22 -0400] \"GET /pub/sshay/images/justin.jpg HTTP/1.0\" 304 -\n198.49.169.79 - - [01/Sep/1995:21:06:09 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\n204.245.156.1 - - [01/Sep/1995:21:11:47 -0400] \"GET /pub/evins/Icons/Nameplates/chrome-people.gif HTTP/1.0\" 200 2120\nacops.cat.csiro.au - - [01/Sep/1995:21:17:01 -0400] \"GET /pub/sshay/images/chrsbutn.gif HTTP/1.0\" 200 1070\nkrlee.demon.co.uk - - [01/Sep/1995:21:21:50 -0400] \"GET /pub/job/vk/view01.jpg HTTP/1.0\" 200 5733\n138.112.195.30 - - [01/Sep/1995:21:28:09 -0400] \"GET /pub/gen/fas/asmp/asm30.html HTTP/1.0\" 200 44652\nasm4-3.sl114.cns.vt.edu - - [01/Sep/1995:21:32:56 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nline107.nwm.mindlink.net - - [01/Sep/1995:21:39:05 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nphilosophers.execpc.com - - [01/Sep/1995:21:44:36 -0400] \"GET /pub/heroes/gifs/sheen.gif HTTP/1.0\" 200 10161\ncmlds5.ME.Berkeley.EDU - - [01/Sep/1995:21:50:51 -0400] \"GET /pub/sshay/images/rainlin2.gif HTTP/1.0\" 200 1229\nCust21.Max5.New-York.NY.MS.UU.NET - - [01/Sep/1995:21:56:34 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nndlc.occ.uky.edu - - [01/Sep/1995:22:02:04 -0400] \"GET /pub/jeffd/smreagan.gif HTTP/1.0\" 200 18018\nsbpc8.rdg.ac.uk - - [01/Sep/1995:22:07:14 -0400] \"GET /pub/sshay/partbutn.map?261,20 HTTP/1.0\" 302 229\npm2e1-30.valleynet.com - - [01/Sep/1995:22:12:19 -0400] \"GET /atomicbk/images/buffy.gif HTTP/1.0\" 200 59956\nMUA44.MARSHALL.EDU - - [01/Sep/1995:22:17:10 -0400] \"GET /pub/sshay/images/links.gif HTTP/1.0\" 200 6171\ndialup44.Washington.mci.net - - [01/Sep/1995:22:24:03 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\nwww-b4.proxy.aol.com - - [01/Sep/1995:22:29:48 -0400] \"GET /atomicbk/logo2.gif HTTP/1.0\" 200 12871\nwww-e9.proxy.aol.com - - [01/Sep/1995:22:35:55 -0400] \"GET /pub/rebel/stuff.gif HTTP/1.0\" 200 1589\ncuster.umt.edu - - [01/Sep/1995:22:41:48 -0400] \"GET /pub/jeffd/liealot.html HTTP/1.0\" 200 3742\nmmfw.macromedia.com - - [01/Sep/1995:22:48:06 -0400] \"GET /pub/sshay/images/bksh.gif HTTP/1.0\" 200 13112\n140.107.22.15 - - [01/Sep/1995:22:55:03 -0400] \"GET /pub/sshay/images/rainlin2.gif HTTP/1.0\" 200 1229\nix-aug-ga1-01.ix.netcom.com - - [01/Sep/1995:23:00:26 -0400] \"GET /pub/job/swim/v-05.jpg HTTP/1.0\" 200 2957\n128.220.62.147 - - [01/Sep/1995:23:08:06 -0400] \"GET /pub/job/theman.jpg HTTP/1.0\" 200 8905\nsabre3.sasknet.sk.ca - - [01/Sep/1995:23:13:52 -0400] \"GET /atomicbk/scotth.gif HTTP/1.0\" 200 790\nkfps-Old-Union-A-dynamic-37.Stanford.EDU - - [01/Sep/1995:23:19:37 -0400] \"GET /pub/sshay/images/greysped.gif HTTP/1.0\" 200 4542\ndrjo002A089.embratel.net.br - - [01/Sep/1995:23:26:35 -0400] \"GET /atomicbk/catalog/emboss.jpg HTTP/1.0\" 200 4741\npiweba3y.prodigy.com - - [01/Sep/1995:23:33:55 -0400] \"GET /aztec/iso9000/mant.gif HTTP/1.0\" 304 -\nip150.vivanet.com - - [01/Sep/1995:23:40:34 -0400] \"GET /pub/jeffd/plnlhedr.gif HTTP/1.0\" 200 9445\nlearn102.gestalt-sys.com - - [01/Sep/1995:23:48:14 -0400] \"GET /pub/cargui/cool_til.gif HTTP/1.0\" 304 -\nLIBRARY4.HOSP.UTK.EDU - - [01/Sep/1995:23:56:47 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\ndialin-192.wustl.edu - - [02/Sep/1995:00:04:47 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\n202.21.16.120 - - [02/Sep/1995:00:11:41 -0400] \"GET /pub/sshay/images/chris3.jpg HTTP/1.0\" 200 50739\n205.177.33.4 - - [02/Sep/1995:00:17:52 -0400] \"GET /pub/alweiner/cgi-bin/homepage.html?alive HTTP/1.0\" 200 469\nFleming-John.collins.indiana.edu - - [02/Sep/1995:00:24:57 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nwww-b6.proxy.aol.com - - [02/Sep/1995:00:33:31 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nix-tam4-25.ix.netcom.com - - [02/Sep/1995:00:41:29 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\nmandyk.pr.mcs.net - - [02/Sep/1995:00:46:36 -0400] \"GET /pub/abaa-booknet/research/librar.html HTTP/1.0\" 200 5339\nad05-027.compuserve.com - - [02/Sep/1995:00:55:37 -0400] \"GET /pub/listserv/lsrel1b.html HTTP/1.0\" 200 21120\nCust45.Max1.New-Orleans.LA.MS.UU.NET - - [02/Sep/1995:01:04:14 -0400] \"GET /pub/atomicbk/iamges/erotuniv.gif HTTP/1.0\" 404 335\nkierkegaard.helios.nd.edu - - [02/Sep/1995:01:11:10 -0400] \"GET /pub/job/vk/view11.jpg HTTP/1.0\" 200 5001\nport4.den1-annex.usa.net - - [02/Sep/1995:01:18:21 -0400] \"GET /atomicbk/new/new.html HTTP/1.0\" 200 3025\nbootp-232-84.bootp.Virginia.EDU - - [02/Sep/1995:01:26:33 -0400] \"GET /pub/job/vk/view09.jpg HTTP/1.0\" 200 6011\nClam.Stanford.EDU - - [02/Sep/1995:01:37:51 -0400] \"GET /devtools/gonew.gif HTTP/1.0\" 200 1624\nppp52-148.gol.com - - [02/Sep/1995:01:47:32 -0400] \"GET /atomicbk/catalog/home.gif HTTP/1.0\" 200 813\npeterd.midcoast.com.au - - [02/Sep/1995:01:57:41 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 200 11610\nrmassoc.seanet.com - - [02/Sep/1995:02:05:57 -0400] \"GET /pub/phil/images/WinonaSheets-little.gif HTTP/1.0\" 200 33454\nabba.ccs.neu.edu - - [02/Sep/1995:02:13:27 -0400] \"GET /pub/sshay/images/hardtodd.jpg HTTP/1.0\" 200 39303\nnet-1-224.eden.com - - [02/Sep/1995:02:21:59 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\n167.216.5.63 - - [02/Sep/1995:02:29:44 -0400] \"GET /pub/alweiner/work/_0271T.gif HTTP/1.0\" 200 813\ndaalia.vtkk.fi - - [02/Sep/1995:02:36:07 -0400] \"GET /pub/job/swim/v-19.jpg HTTP/1.0\" 200 2912\n204.166.233.151 - - [02/Sep/1995:02:43:44 -0400] \"GET /pub/cargui/img2002.gif HTTP/1.0\" 200 18827\nbuchanan31.res.iastate.edu - - [02/Sep/1995:02:54:38 -0400] \"GET /pub/atomicbk/images/earlyero.gif HTTP/1.0\" 404 335\nflotsam.ee.pdx.edu - - [02/Sep/1995:03:06:59 -0400] \"GET /pub/atomicbk/images/nudistbk.gif HTTP/1.0\" 404 335\nnetcom14.netcom.com - - [02/Sep/1995:03:18:42 -0400] \"GET /pub/robert/home.html HTTP/1.0\" 200 1992\n155.142.200.1 - - [02/Sep/1995:03:32:55 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nbriant.reslife.okstate.edu - - [02/Sep/1995:03:45:13 -0400] \"GET /pub/job/swim/v-14.jpg HTTP/1.0\" 200 2615\ngn2.getnet.com - - [02/Sep/1995:03:57:04 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nccs.sogang.ac.kr - - [02/Sep/1995:04:12:46 -0400] \"GET /pub/wmcbrine/html/wmcbrine.html HTTP/1.0\" 200 538\nemf2-208.emf.net - - [02/Sep/1995:04:26:17 -0400] \"GET /pub/atomicbk/new.gif HTTP/1.0\" 200 744\nn00122-104afc.unity.ncsu.edu - - [02/Sep/1995:04:42:13 -0400] \"GET /pub/sshay/images/scott1.jpg HTTP/1.0\" 200 18102\nwww-b5.proxy.aol.com - - [02/Sep/1995:04:56:18 -0400] \"GET /pub/k2/am4x44u/gifs/cj2.gif HTTP/1.0\" 200 36798\nebrady.clark.net - - [02/Sep/1995:05:15:01 -0400] \"GET /www.clark.net/pub/green/friends.htm HTTP/1.0\" 404 312\nlanesplc.MT.net - - [02/Sep/1995:05:31:41 -0400] \"GET /pub/sshay/chris.html HTTP/1.0\" 200 7172\nCust21.Max1.Seattle.WA.MS.UU.NET - - [02/Sep/1995:05:50:56 -0400] \"GET /pub/peace/PC1.map?49,55 HTTP/1.0\" 302 226\n198.165.3.2 - - [02/Sep/1995:06:18:57 -0400] \"GET /pub/wick/photos/lay.jpg HTTP/1.0\" 200 20923\nma4ppp.tinet.ch - - [02/Sep/1995:06:39:18 -0400] \"GET /pub/atomicbk/contest.gif HTTP/1.0\" 200 669\n203.15.32.1 - - [02/Sep/1995:06:53:01 -0400] \"GET /pub/gen/fas/irp/nsa/ HTTP/1.0\" 200 91372\n133.28.55.143 - - [02/Sep/1995:07:08:45 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\ndyna-ge-2.dial.eunet.ch - - [02/Sep/1995:07:26:40 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\ne2b202.bri.enternet.com.au - - [02/Sep/1995:07:41:13 -0400] \"GET /pub/eurocent/home.htm HTTP/1.0\" 200 2432\nppp062.yo.rim.or.jp - - [02/Sep/1995:07:56:02 -0400] \"GET /atomicbk/catalog/erotica.html HTTP/1.0\" 200 11362\nvccnw09.its.rpi.edu - - [02/Sep/1995:08:10:31 -0400] \"GET /atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nppp228.aix.or.jp - - [02/Sep/1995:08:23:27 -0400] \"GET /pub/fan/albumpics/expo.jpg HTTP/1.0\" 200 2744\nad14-029.compuserve.com - - [02/Sep/1995:08:36:15 -0400] \"GET /pub/sshay/images/scott1.jpg HTTP/1.0\" 200 18102\nmaggie.mame.mu.OZ.AU - - [02/Sep/1995:08:50:10 -0400] \"GET /pub/job/swim/v-09.jpg HTTP/1.0\" 200 3755\n196.3.132.15 - - [02/Sep/1995:09:01:27 -0400] \"GET /pub/atomicbk/catalog/new.gif HTTP/1.0\" 200 744\np102.infolink.co.za - - [02/Sep/1995:09:12:19 -0400] \"GET /pub/job/swim/ss-01.jpg HTTP/1.0\" 200 51524\n139.230.2.39 - - [02/Sep/1995:09:21:07 -0400] \"GET /pub/phil/VerucaSalt.html HTTP/1.0\" 200 3954\nsophocles.algonet.se - - [02/Sep/1995:09:31:18 -0400] \"GET /pub/job/vk/view05.jpg HTTP/1.0\" 200 5012\nwww-e5.proxy.aol.com - - [02/Sep/1995:09:40:22 -0400] \"GET /pub/jeffd/smrushnw.gif HTTP/1.0\" 200 23351\ndd06-036.compuserve.com - - [02/Sep/1995:09:51:30 -0400] \"GET /pub/wine/btnchamp.gif HTTP/1.0\" 200 845\nprpayne-ppp.clark.net - - [02/Sep/1995:10:00:05 -0400] \"GET /pub/shows/images/pblogrt1.gif HTTP/1.0\" 304 -\ncontinental.com - - [02/Sep/1995:10:12:35 -0400] \"GET /pub/k2/am4x44u/gifs/4x4_small.gif HTTP/1.0\" 200 9401\nwww-c2.proxy.aol.com - - [02/Sep/1995:10:21:51 -0400] \"GET /pub/jeffd/castww.html HTTP/1.0\" 200 37184\njazz.iinet.com.au - - [02/Sep/1995:10:31:28 -0400] \"GET /pub/csamsi/ HTTP/1.0\" 304 -\n147.56.61.5 - - [02/Sep/1995:10:38:05 -0400] \"GET /atomicbk/images/buffy.gif HTTP/1.0\" 200 59956\nmatt.qmi.mei.com - - [02/Sep/1995:10:47:01 -0400] \"GET /pub/mmathai/mls HTTP/1.0\" 302 223\nbfwspc33.forwiss.uni-erlangen.de - - [02/Sep/1995:10:51:59 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\ngenmac14.gen.gu.se - - [02/Sep/1995:11:00:29 -0400] \"GET /pub/macgyver/VidGames/fo/gifs/fo7small.jpg HTTP/1.0\" 404 334\nwww-c3.proxy.aol.com - - [02/Sep/1995:11:07:14 -0400] \"GET /pub/wick/photos/beavers_mini.gif HTTP/1.0\" 304 -\nwpbfl2-26.gate.net - - [02/Sep/1995:11:15:18 -0400] \"GET /pub/job/vk/v-line.gif HTTP/1.0\" 200 1254\nwww.rrz.Uni-Koeln.DE - - [02/Sep/1995:11:23:06 -0400] \"GET /pub/job/swim/s-back2.jpg HTTP/1.0\" 200 4653\nwsmac02.acs.nmu.edu - - [02/Sep/1995:11:29:42 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\nhusserl.sbu.edu - - [02/Sep/1995:11:37:35 -0400] \"GET /pub/sshay/images/davthumb.jpg HTTP/1.0\" 200 3914\n206.42.112.218 - - [02/Sep/1995:11:45:53 -0400] \"GET /atomicbk/images/youngw.gif HTTP/1.0\" 404 338\n141.42.1.145 - - [02/Sep/1995:11:55:06 -0400] \"GET /pub/sshay/images/updated.gif HTTP/1.0\" 200 168\ntplawton.is.marist.edu - - [02/Sep/1995:12:05:24 -0400] \"GET /pub/sshay/images/sglt.gif HTTP/1.0\" 200 19929\nwww-c3.proxy.aol.com - - [02/Sep/1995:12:12:54 -0400] \"GET /pub/jeffd/spkrnewt.gif HTTP/1.0\" 304 -\ngate0.ftech.net - - [02/Sep/1995:12:19:07 -0400] \"GET /pub/mikebilt/mikeb.jpg HTTP/1.0\" 200 10311\nlumts-1-02.luminet.net - - [02/Sep/1995:12:25:44 -0400] \"GET /pub/atomicbk/catalog/erotica.html HTTP/1.0\" 200 11362\ndcs-79.umd.edu - - [02/Sep/1995:12:33:00 -0400] \"GET /pub/atomicbk/images/pagepix.gif HTTP/1.0\" 200 35635\nppp221.gol.com - - [02/Sep/1995:12:40:13 -0400] \"GET /pub/wine/favbtn.gif HTTP/1.0\" 200 955\nvolt.elab.ece.ntua.gr - - [02/Sep/1995:12:46:26 -0400] \"GET /pub/iz/cgi-bin/counter?doc=Books/books.html HTTP/1.0\" 200 654\nppp29.sbbs.se - - [02/Sep/1995:12:53:29 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nENV-HP5970.TAMU.EDU - - [02/Sep/1995:13:00:29 -0400] \"GET /pub/phil/images/jh11.gif HTTP/1.0\" 200 9407\nnswenson-mac.qualcomm.com - - [02/Sep/1995:13:07:18 -0400] \"GET /atomicbk/shocked/shocked.jpg HTTP/1.0\" 200 43819\npsm101-1.agsc.ttu.edu - - [02/Sep/1995:13:13:27 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\nW20-575-61.MIT.EDU - - [02/Sep/1995:13:19:41 -0400] \"GET /pub/job/vk/view29.jpg HTTP/1.0\" 200 6695\nW20-575-61.MIT.EDU - - [02/Sep/1995:13:24:11 -0400] \"GET /pub/job/mail.jpg HTTP/1.0\" 200 4282\ndial6.netrix.net - - [02/Sep/1995:13:31:36 -0400] \"GET /pub/shelby/scroll.gif HTTP/1.0\" 200 999\ncamil44.music.uiuc.edu - - [02/Sep/1995:13:40:20 -0400] \"GET /pub/rmharris/catalogs/blksncat/intro.html HTTP/1.0\" 200 2821\n130.206.110.6 - - [02/Sep/1995:13:47:14 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nW20-575-61.MIT.EDU - - [02/Sep/1995:13:52:27 -0400] \"GET /pub/job/vk/view03.jpg HTTP/1.0\" 200 8506\nwintermute.synergy.net - - [02/Sep/1995:13:59:04 -0400] \"GET /theme/factinfo.html HTTP/1.0\" 200 2420\ntheatre104.scales.wfu.edu - - [02/Sep/1995:14:05:05 -0400] \"GET /pub/sshay/images/galybutn.gif HTTP/1.0\" 200 1080\nmariana.rsvs.ulaval.ca - - [02/Sep/1995:14:13:04 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 304 -\nstudpc04.uio.no - - [02/Sep/1995:14:20:36 -0400] \"GET /pub/pribut/new.gif HTTP/1.0\" 200 147\n192.228.240.51 - - [02/Sep/1995:14:27:13 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\nwww-e6.proxy.aol.com - - [02/Sep/1995:14:34:05 -0400] \"GET /pub/pribut/new.gif HTTP/1.0\" 304 -\nsylviepaul.cnwl.igs.net - - [02/Sep/1995:14:40:48 -0400] \"GET /mc-icons/blank.gif HTTP/1.0\" 200 60\n129.30.50.37 - - [02/Sep/1995:14:46:12 -0400] \"GET /atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6786\npae1.monmouth.army.mil - - [02/Sep/1995:14:52:15 -0400] \"GET /pub/job/vk/view09.jpg HTTP/1.0\" 200 6011\nsmtp.inet.fi - - [02/Sep/1995:14:59:28 -0400] \"GET /atomicbk/seanc.gif HTTP/1.0\" 200 734\nFindlay-IBMPC45.cac-labs.psu.edu - - [02/Sep/1995:15:06:50 -0400] \"GET /pub/job/vk/page1.gif HTTP/1.0\" 200 1960\nwww-e4.proxy.aol.com - - [02/Sep/1995:15:14:08 -0400] \"GET /atomicbk/images/hbslut.gif HTTP/1.0\" 304 -\npiweba3y.prodigy.com - - [02/Sep/1995:15:20:50 -0400] \"GET /pub/networx/autopage/classic/cl001s.gif HTTP/1.0\" 200 19347\nbox775.labs.cis.pitt.edu - - [02/Sep/1995:15:28:57 -0400] \"GET /pub/mbrophy/pix/interv.jpg HTTP/1.0\" 200 5047\nB3.cyberspy.com - - [02/Sep/1995:15:35:04 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\nts1-s1.adeptcom.com - - [02/Sep/1995:15:40:34 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\ngemsgw.med.ge.com - - [02/Sep/1995:15:47:32 -0400] \"GET /pub/jeffd/pjb.gif HTTP/1.0\" 200 4849\nchaos.idirect.com - - [02/Sep/1995:15:54:09 -0400] \"GET /pub/shelby/creambox.gif HTTP/1.0\" 200 856\n198.105.193.95 - - [02/Sep/1995:15:59:05 -0400] \"GET /pub/job/swim/v-07.jpg HTTP/1.0\" 200 5703\nacme.clark.net - - [02/Sep/1995:16:04:42 -0400] \"GET /pub/mirko/web/images/Buttons/dir_W.gif HTTP/1.0\" 200 276\nad03-033.compuserve.com - - [02/Sep/1995:16:09:53 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\njimw.macon.tec.ga.us - - [02/Sep/1995:16:15:15 -0400] \"GET /pub/alweiner/a27.gif HTTP/1.0\" 200 4594\nslc91.xmission.com - - [02/Sep/1995:16:20:51 -0400] \"GET /pub/mikebilt/ruffbear.jpg HTTP/1.0\" 200 13188\ndirectweb.com - - [02/Sep/1995:16:26:21 -0400] \"GET /pub/evins/Icons/Misc/ HTTP/1.0\" 200 -\nip215.phx.primenet.com - - [02/Sep/1995:16:32:56 -0400] \"GET /pub/sshay/images/scotbksh.jpg HTTP/1.0\" 200 19141\npm2-48.TVS.NET - - [02/Sep/1995:16:38:55 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\npanel-pc.cba.uh.edu - - [02/Sep/1995:16:47:50 -0400] \"GET /pub/job/vk/vk-ad-09.jpg HTTP/1.0\" 200 70678\n205.208.58.46 - - [02/Sep/1995:16:52:59 -0400] \"GET /pub/job/vk/view07.jpg HTTP/1.0\" 200 7057\n137.99.19.5 - - [02/Sep/1995:16:59:47 -0400] \"GET /pub/networx/fusion.html HTTP/1.0\" 200 1806\nyellow54.nada.kth.se - - [02/Sep/1995:17:06:10 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\noahu-54.u.aloha.net - - [02/Sep/1995:17:12:58 -0400] \"GET /pub/alweiner/up_red.gif HTTP/1.0\" 200 218\nrelay02.jpmorgan.com - - [02/Sep/1995:17:20:08 -0400] \"GET /pub/job/vk/view10.jpg HTTP/1.0\" 200 5303\n204.245.163.3 - - [02/Sep/1995:17:25:47 -0400] \"GET /pub/cheebie/graphics/pen.gif HTTP/1.0\" 200 541\nenm324a-17.engl.ttu.edu - - [02/Sep/1995:17:29:44 -0400] \"GET /pub/listserv/purpleba.gif HTTP/1.0\" 200 900\nPsychstat-12.Psych.UH.EDU - - [02/Sep/1995:17:36:22 -0400] \"GET /larouche/strategic.html HTTP/1.0\" 200 756\nsdt.com - - [02/Sep/1995:17:42:51 -0400] \"GET /pub/job/vk/view34.jpg HTTP/1.0\" 200 5156\nad06-027.compuserve.com - - [02/Sep/1995:17:48:44 -0400] \"GET /pub/sshay/images/resume.gif HTTP/1.0\" 200 8760\n128.84.38.10 - - [02/Sep/1995:17:54:25 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nmars.ark.com - - [02/Sep/1995:17:59:32 -0400] \"GET /pub/k2/am4x44u/gifs/bgpaper.gif HTTP/1.0\" 200 5960\n204.251.2.200 - - [02/Sep/1995:18:04:39 -0400] \"GET /pub/RAI/links.html HTTP/1.0\" 200 4847\nosf1.gmu.edu - - [02/Sep/1995:18:11:30 -0400] \"GET /pub/jeffd/sm_eaghd.gif HTTP/1.0\" 200 2866\nslc76.xmission.com - - [02/Sep/1995:18:18:52 -0400] \"GET /pub/mjoneill/links.html HTTP/1.0\" 404 336\nwww-b5.proxy.aol.com - - [02/Sep/1995:18:26:20 -0400] \"GET /pub/atomicbk/catalog/erotica.html HTTP/1.0\" 200 11362\npc180010.dit.co.fairfax.va.us - - [02/Sep/1995:18:33:42 -0400] \"GET /pub/sshay/images/crthumb5.jpg HTTP/1.0\" 200 4495\nhacknet.demon.co.uk - - [02/Sep/1995:18:41:18 -0400] \"GET /pub/rjgula/hack/ HTTP/1.0\" 403 142\nlovely.tiac.net - - [02/Sep/1995:18:47:27 -0400] \"GET /pub/sknight/t_whitem.gif HTTP/1.0\" 200 5708\nJEDI.TAMU.EDU - - [02/Sep/1995:18:55:03 -0400] \"GET /pub/sshay/interact.html HTTP/1.0\" 200 2541\npm192.smartlink.net - - [02/Sep/1995:19:02:16 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\n204.137.204.229 - - [02/Sep/1995:19:09:23 -0400] \"GET /pub/journalism/hate.html HTTP/1.0\" 200 4602\nnswenson-mac.qualcomm.com - - [02/Sep/1995:19:17:35 -0400] \"GET /pub/job/vk/view01.jpg HTTP/1.0\" 200 5733\njeffery.clark.net - - [02/Sep/1995:19:25:47 -0400] \"GET /pub/pribut/email2.gif HTTP/1.0\" 200 1209\njbddup-a-5.rmt.net.pitt.edu - - [02/Sep/1995:19:31:53 -0400] \"GET /pub/phil/images/jh26.gif HTTP/1.0\" 304 -\nstudpc04.uio.no - - [02/Sep/1995:19:39:54 -0400] \"GET /pub/pribut/upbtn.gif HTTP/1.0\" 200 145\nstealth.FOUR.net - - [02/Sep/1995:19:48:34 -0400] \"GET /pub/alweiner/work/_0291A.gif HTTP/1.0\" 200 450\nTrestle.AI.SRI.COM - - [02/Sep/1995:19:55:28 -0400] \"GET /pub/job/swim/v-18.jpg HTTP/1.0\" 200 2838\nplease.re.open.de - - [02/Sep/1995:20:04:53 -0400] \"GET /pub/job/vk/view15.jpg HTTP/1.0\" 200 6036\ncd-37.continuum.net - - [02/Sep/1995:20:12:12 -0400] \"GET /pub/rebel/stuff.gif HTTP/1.0\" 200 1589\n153.104.13.90 - - [02/Sep/1995:20:18:22 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nsn22e025.resnet.drexel.edu - - [02/Sep/1995:20:25:54 -0400] \"GET /pub/job/vk/view12.jpg HTTP/1.0\" 200 5966\ndialup1.logical.net - - [02/Sep/1995:20:31:41 -0400] \"GET /pub/atomicbk/emboss.jpg HTTP/1.0\" 200 4741\n204.255.215.47 - - [02/Sep/1995:20:38:09 -0400] \"GET /pub/aztec/shesails/butover.gif HTTP/1.0\" 200 1761\nmpngate6.ny.us.ibm.net - - [02/Sep/1995:20:45:08 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\ncardio-mac1.ucsf.EDU - - [02/Sep/1995:20:52:46 -0400] \"GET /atomicbk/images/comic75.gif HTTP/1.0\" 200 444\nix-ir5-13.ix.netcom.com - - [02/Sep/1995:21:01:21 -0400] \"GET /pub/job/vk/flowers1.gif HTTP/1.0\" 200 4288\n204.191.195.105 - - [02/Sep/1995:21:09:52 -0400] \"GET /pub/networx/autopage/autobar.gif HTTP/1.0\" 200 2751\n138.26.196.178 - - [02/Sep/1995:21:16:41 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\nport56.annex4.net.ubc.ca - - [02/Sep/1995:21:24:53 -0400] \"GET /pub/ibos/moto/star.gif HTTP/1.0\" 200 1901\nebrady.clark.net - - [02/Sep/1995:21:33:47 -0400] \"GET /pub/green/more.gif HTTP/1.0\" 200 6030\nephedra.psych.indiana.edu - - [02/Sep/1995:21:40:53 -0400] \"GET /pub/atomicbk/orders.gif HTTP/1.0\" 200 800\nwww-d1.proxy.aol.com - - [02/Sep/1995:21:48:28 -0400] \"GET /pub/jrinker/editors.htm HTTP/1.0\" 200 467\nana1056.deltanet.com - - [02/Sep/1995:21:57:33 -0400] \"GET /pub/atomicbk/iamges/vargas.gif HTTP/1.0\" 404 335\nzeus.towson.edu - - [02/Sep/1995:22:04:56 -0400] \"GET /pub/atomicbk/direct.gif HTTP/1.0\" 200 833\ndialup03.wdbg.va.qnet.com - - [02/Sep/1995:22:12:38 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\n148.61.231.32 - - [02/Sep/1995:22:18:19 -0400] \"GET /pub/peace/VRSFoot.GIF HTTP/1.0\" 200 16052\nkuts7p04.cc.ukans.edu - - [02/Sep/1995:22:25:40 -0400] \"GET /pub/k2/cgi-bin/imagemap/4x4_home?242,52 HTTP/1.0\" 200 1892\nwww-c4.proxy.aol.com - - [02/Sep/1995:22:33:04 -0400] \"GET /pub/job/vk/view12.jpg HTTP/1.0\" 200 5966\ngiaec.cc.monash.edu.au - - [02/Sep/1995:22:39:47 -0400] \"GET /atomicbk/images/angie.gif HTTP/1.0\" 200 33638\nslip-9-10.ots.utexas.edu - - [02/Sep/1995:22:46:04 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\nmn00170w-726421.mcnutt.indiana.edu - - [02/Sep/1995:22:53:27 -0400] \"GET /pub/atomicbk/catalog/home.gif HTTP/1.0\" 200 813\nlindsay.midland.co.nz - - [02/Sep/1995:23:01:11 -0400] \"GET /pub/atomicbk/catalog/tattoo.html HTTP/1.0\" 200 3073\nstar39.hkstar.com - - [02/Sep/1995:23:08:11 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\nqueen.ua.pt - - [02/Sep/1995:23:14:50 -0400] \"GET /pub/alweiner/blue_sha.gif HTTP/1.0\" 200 991\nAlice-Thurman.tenet.edu - - [02/Sep/1995:23:20:36 -0400] \"GET /pub/journalism/kid.html HTTP/1.0\" 200 5343\nacme.clark.net - - [02/Sep/1995:23:28:43 -0400] \"GET /graphics/bar.gif HTTP/1.0\" 304 -\nacme.clark.net - - [02/Sep/1995:23:35:16 -0400] \"GET /pub/mirko/web/images/Buttons/gopher_page.gif HTTP/1.0\" 200 369\n205.218.190.33 - - [02/Sep/1995:23:42:12 -0400] \"GET /aztec/ccyc/stern.gif HTTP/1.0\" 200 14241\nbuzzr.earthlink.net - - [02/Sep/1995:23:47:33 -0400] \"GET /pub/ibos/link.gif HTTP/1.0\" 304 -\nip239.tokyo.jp.interramp.com - - [02/Sep/1995:23:53:23 -0400] \"GET /pub/abaa-booknet/images/abaabutt.gif HTTP/1.0\" 200 1041\n129.237.115.30 - - [03/Sep/1995:00:00:01 -0400] \"GET /pub/theme/ HTTP/1.0\" 200 799\npiweba5y.prodigy.com - - [03/Sep/1995:00:06:40 -0400] \"GET /pub/shelby/yellowli.gif HTTP/1.0\" 200 905\nCust10.Max1.Houston.TX.MS.UU.NET - - [03/Sep/1995:00:15:06 -0400] \"GET /pub/sshay/images/brnthumb.jpg HTTP/1.0\" 200 2775\nablake.bevb.blacksburg.va.us - - [03/Sep/1995:00:22:25 -0400] \"GET /pub/cybersoft/ HTTP/1.0\" 200 918\nsuefew.sc.scruznet.com - - [03/Sep/1995:00:29:38 -0400] \"GET /pub/listserv/lsmus1.html HTTP/1.0\" 200 2713\ndialupS31.ici.net - - [03/Sep/1995:00:35:35 -0400] \"GET /pub/job/vk/arrow-r.gif HTTP/1.0\" 200 3042\nport01.gateway2.ic.net - - [03/Sep/1995:00:43:29 -0400] \"GET /theme/cgi-bin/ig.wrl HTTP/1.0\" 200 4280\nhuey.met.fsu.edu - - [03/Sep/1995:00:48:41 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\nmzmo1.ResComp.Arizona.EDU - - [03/Sep/1995:00:53:35 -0400] \"GET /pub/mikebilt/gaydc.html HTTP/1.0\" 200 6485\n204.101.163.101 - - [03/Sep/1995:00:59:59 -0400] \"GET /atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6786\nwww-d2.proxy.aol.com - - [03/Sep/1995:01:05:07 -0400] \"GET /pub/mpowers/j4j/web/Balls/greengem.gif HTTP/1.0\" 200 110\npiweba4y.prodigy.com - - [03/Sep/1995:01:11:28 -0400] \"GET /pub/jeffd/cicgbtn.gif HTTP/1.0\" 304 -\nppp4.cowan.edu.au - - [03/Sep/1995:01:17:14 -0400] \"GET /pub/job/swim/swim.html HTTP/1.0\" 200 4429\n146.155.89.20 - - [03/Sep/1995:01:24:13 -0400] \"GET /atomicbk/emboss.jpg HTTP/1.0\" 200 4741\nparadox.ncsa.uiuc.edu - - [03/Sep/1995:01:30:12 -0400] \"GET /atomicbk/direct.gif HTTP/1.0\" 200 833\nslip8-205.beta.delphi.com - - [03/Sep/1995:01:38:00 -0400] \"GET /pub/phil/winonaryder.html HTTP/1.0\" 200 19870\npma27.loop.com - - [03/Sep/1995:01:47:22 -0400] \"GET /pub/jeffd/95-63.gif HTTP/1.0\" 200 31640\npiweba3y.prodigy.com - - [03/Sep/1995:01:54:26 -0400] \"GET /pub/job/vk/vk-page2.jpg HTTP/1.0\" 200 10302\npiweba1y.prodigy.com - - [03/Sep/1995:02:01:21 -0400] \"GET /pub/job/vk/kathy.jpg HTTP/1.0\" 200 7450\npbd-m35-15.urh.uiuc.edu - - [03/Sep/1995:02:09:41 -0400] \"GET /atomicbk/news.gif HTTP/1.0\" 200 912\ndynip28.efn.org - - [03/Sep/1995:02:18:31 -0400] \"GET /pub/sshay/images/rainback.gif HTTP/1.0\" 200 2541\nstockyard16.onramp.net - - [03/Sep/1995:02:26:50 -0400] \"GET /pub/k2/am4x44u/maps/usamap.map?242,230 HTTP/1.0\" 302 245\nyak-ts1-p21.wolfe.net - - [03/Sep/1995:02:35:03 -0400] \"GET /pub/abaa-booknet/images/search.gif HTTP/1.0\" 200 938\nslip017.loa.com - - [03/Sep/1995:02:43:17 -0400] \"GET /atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\n203.251.191.9 - - [03/Sep/1995:02:51:19 -0400] \"GET /pub/k2/am4x44u/trails/locations/locations.htm HTTP/1.0\" 200 904\nflores.msm.com - - [03/Sep/1995:03:00:39 -0400] \"GET /pub/wine/flgausta.gif HTTP/1.0\" 200 203\npp7.westdat.com - - [03/Sep/1995:03:12:39 -0400] \"GET /pub/atomicbk/userlink.gif HTTP/1.0\" 200 816\nad07-008.compuserve.com - - [03/Sep/1995:03:20:51 -0400] \"GET /pub/winfield/brian.html HTTP/1.0\" 200 1514\ne1s110.syd.enternet.com.au - - [03/Sep/1995:03:33:15 -0400] \"GET /pub/networx/autopage/dealers/de001_3b.gif HTTP/1.0\" 200 70257\nd12.itsnet.com - - [03/Sep/1995:03:43:24 -0400] \"GET /pub/sshay/images/scott1.jpg HTTP/1.0\" 200 18102\nCust10.Max1.Seattle.WA.MS.UU.NET - - [03/Sep/1995:03:55:27 -0400] \"GET /pub/job/vk/page1.gif HTTP/1.0\" 200 1960\nwww-e9.proxy.aol.com - - [03/Sep/1995:04:10:58 -0400] \"GET /pub/sshay/images/rainlin2.gif HTTP/1.0\" 304 -\nslip-5-11.shore.net - - [03/Sep/1995:04:28:17 -0400] \"GET /pub/pgarrett/award.gif HTTP/1.0\" 200 5385\nnetcom15.netcom.com - - [03/Sep/1995:04:41:25 -0400] \"GET /pub/macgyver HTTP/1.0\" 302 220\nCust47.Max6.Los-Angeles.CA.MS.UU.NET - - [03/Sep/1995:04:58:16 -0400] \"GET /pub/job/theman.jpg HTTP/1.0\" 200 8905\nwipro.wipsys.soft.net - - [03/Sep/1995:05:15:21 -0400] \"GET /pub/mbrophy/sandras_home.html HTTP/1.0\" 200 1260\ndust3.dur.ac.uk - - [03/Sep/1995:05:32:33 -0400] \"GET /pub/job/vk/vk-bk.jpg HTTP/1.0\" 200 4569\nwww-c5.proxy.aol.com - - [03/Sep/1995:05:48:54 -0400] \"GET /pub/wick/misc/redbg.gif HTTP/1.0\" 200 878\nmat12.cip.uni-regensburg.de - - [03/Sep/1995:06:12:36 -0400] \"GET /pub/atomicbk/catalog/mini.gif HTTP/1.0\" 200 360\nsw25-158.iol.it - - [03/Sep/1995:06:33:55 -0400] \"GET /atomicbk/catalog/home.gif HTTP/1.0\" 200 813\ndialup98-102.swipnet.se - - [03/Sep/1995:06:51:13 -0400] \"GET /pub/job/vk/view31.jpg HTTP/1.0\" 200 5611\nvicsd209.DIAL.GOV.BC.CA - - [03/Sep/1995:07:10:54 -0400] \"GET /pub/conquest/one/books/noiz.html HTTP/1.0\" 200 6369\nix-sf18-07.ix.netcom.com - - [03/Sep/1995:07:28:58 -0400] \"GET /pub/sshay/images/bigtoed.jpg HTTP/1.0\" 200 31158\nad11-011.compuserve.com - - [03/Sep/1995:07:44:20 -0400] \"GET /pub/job/vk/view08.jpg HTTP/1.0\" 200 6476\nA113030.sna1.as.crl.com - - [03/Sep/1995:07:59:34 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\ntechp755.naruto-u.ac.jp - - [03/Sep/1995:08:14:21 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\ngluon.phys.hokudai.ac.jp - - [03/Sep/1995:08:27:58 -0400] \"GET /pub/fan/discog.html HTTP/1.0\" 304 -\n138.103.112.242 - - [03/Sep/1995:08:42:04 -0400] \"GET /pub/job/vk/view16.jpg HTTP/1.0\" 200 6808\nztivax.zfe.siemens.de - - [03/Sep/1995:09:00:01 -0400] \"GET /atomicbk/new/home.gif HTTP/1.0\" 200 813\niteck2.infoteck.qc.ca - - [03/Sep/1995:09:13:07 -0400] \"GET /atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\ngd.neuro.aau.dk - - [03/Sep/1995:09:23:08 -0400] \"GET /pub/sshay/images/pthumb.jpg HTTP/1.0\" 200 1302\ndial-1.t1.ncshlt.sunbelt.net - - [03/Sep/1995:09:34:15 -0400] \"GET /pub/pwalker/new.gif HTTP/1.0\" 200 153\nl2-29.en.net - - [03/Sep/1995:09:46:29 -0400] \"GET /pub/ibos/company/delaware.html HTTP/1.0\" 200 3362\nsida.ifi.uio.no - - [03/Sep/1995:09:55:48 -0400] \"GET /pub/job/vk/page1.gif HTTP/1.0\" 200 1960\nmjens.Cadence.COM - - [03/Sep/1995:10:08:20 -0400] \"GET /pub/sshay/home.html HTTP/1.0\" 200 3141\nisgate.is - - [03/Sep/1995:10:17:41 -0400] \"GET /pub/job/vk/bam.gif HTTP/1.0\" 304 -\nad15-025.compuserve.com - - [03/Sep/1995:10:30:13 -0400] \"GET /pub/wick/photos/lay_mini.gif HTTP/1.0\" 200 13272\nskpc1.rdg.ac.uk - - [03/Sep/1995:10:40:44 -0400] \"GET /pub/job/vendela.jpg HTTP/1.0\" 200 36746\nssomad.pp.fi - - [03/Sep/1995:10:49:27 -0400] \"GET /pub/atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\nQUERY1.LYCOS.CS.CMU.EDU - - [03/Sep/1995:10:59:02 -0400] \"GET /pub/luthardt/ HTTP/1.0\" 200 4328\npiweba3y.prodigy.com - - [03/Sep/1995:11:07:35 -0400] \"GET /pub/robert/robert7.gif HTTP/1.0\" 304 -\nfall.psyber.com - - [03/Sep/1995:11:18:52 -0400] \"GET /pub/rmharris/images/search.gif HTTP/1.0\" 200 938\nclark.net - - [03/Sep/1995:11:27:22 -0400] \"GET /pub/bars.gif HTTP/1.0\" 404 207\nix-dc9-11.ix.netcom.com - - [03/Sep/1995:11:36:46 -0400] \"GET /pub/mikebilt/dchome.gif HTTP/1.0\" 304 -\narhppp13.uni-c.dk - - [03/Sep/1995:11:44:01 -0400] \"GET /pub/russadam/thund03.gif HTTP/1.0\" 200 6906\nJ301855432.RESNET.CORNELL.EDU - - [03/Sep/1995:11:53:15 -0400] \"GET /pub/jeffd/grad_lin.gif HTTP/1.0\" 200 3346\nduxbury30.pcix.com - - [03/Sep/1995:12:04:29 -0400] \"GET /pub/atomicbk/home.html HTTP/1.0\" 200 4051\naristotle.algonet.se - - [03/Sep/1995:12:14:37 -0400] \"GET /pub/phil/WinonaRyder.html HTTP/1.0\" 200 19870\n199.78.224.27 - - [03/Sep/1995:12:23:22 -0400] \"GET /pub/job/vk/view24.jpg HTTP/1.0\" 200 6209\ndyn51-140.biosci.wayne.edu - - [03/Sep/1995:12:32:24 -0400] \"GET /atomicbk/images/tart.gif HTTP/1.0\" 200 38555\nxkplace.monsanto.com - - [03/Sep/1995:12:40:14 -0400] \"GET /pub/sshay/gallery.html HTTP/1.0\" 304 -\ndolphin-29.netrunner.net - - [03/Sep/1995:12:47:34 -0400] \"GET /atomicbk/catalog/home.gif HTTP/1.0\" 200 813\ndial004.future.net - - [03/Sep/1995:12:55:55 -0400] \"GET /pub/conquest/one/bfr.gif HTTP/1.0\" 200 74981\nwww-c4.proxy.aol.com - - [03/Sep/1995:13:03:07 -0400] \"GET /pub/robert/current.html HTTP/1.0\" 200 30337\nspinne.web.net - - [03/Sep/1995:13:10:38 -0400] \"GET /pub/listserv/top40.html HTTP/1.0\" 200 3009\nix-pat1-09.ix.netcom.com - - [03/Sep/1995:13:18:36 -0400] \"GET /pub/k2/am4x44u/gifs/4xflogo.gif HTTP/1.0\" 200 4719\nvolkswagon.europa.com - - [03/Sep/1995:13:26:44 -0400] \"GET /pub/bell/review/newage/image/strieber_breakthrough.gif HTTP/1.0\" 200 11471\n130.14.25.216 - - [03/Sep/1995:13:35:22 -0400] \"GET /pub/mikebilt/feldie.jpg HTTP/1.0\" 200 6808\nsmf-c14.facsmf.utexas.edu - - [03/Sep/1995:13:43:17 -0400] \"GET /pub/atomicbk/promo/people.html HTTP/1.0\" 200 2328\nbootp-123-53.bootp.Virginia.EDU - - [03/Sep/1995:13:52:45 -0400] \"GET /atomicbk/new/newsep01.html HTTP/1.0\" 200 11324\nufcsb1.health.ufl.edu - - [03/Sep/1995:14:00:50 -0400] \"GET /pub/job/vk/view08.jpg HTTP/1.0\" 200 6476\ngovannon.cee.hw.ac.uk - - [03/Sep/1995:14:10:28 -0400] \"GET /pub/job/vk/arrow-r.gif HTTP/1.0\" 304 -\nad11-031.compuserve.com - - [03/Sep/1995:14:17:54 -0400] \"GET /pub/terra/nba.html HTTP/1.0\" 200 2402\nbox785.labs.cis.pitt.edu - - [03/Sep/1995:14:25:15 -0400] \"GET /pub/mbrophy/pix/pbquote2.jpg HTTP/1.0\" 200 9507\nenigma.kbbsnet.com - - [03/Sep/1995:14:32:43 -0400] \"GET /atomicbk/images/buffy.gif HTTP/1.0\" 200 59956\ncola74.scsn.net - - [03/Sep/1995:14:41:30 -0400] \"GET /pub/listserv/lsvl1.html HTTP/1.0\" 304 -\nSOLSTADP.hqpacaf.af.mil - - [03/Sep/1995:14:49:26 -0400] \"GET /pub/jeffd/mr_newt.html HTTP/1.0\" 304 -\ndal08-15.ppp.iadfw.net - - [03/Sep/1995:14:56:27 -0400] \"GET /atomicbk/new/logo.gif HTTP/1.0\" 200 1942\ndcc05227.slip.digex.net - - [03/Sep/1995:15:01:35 -0400] \"GET /html/usage/usage.graph.gif HTTP/1.0\" 200 1727\nts32p14.NetVision.net.il - - [03/Sep/1995:15:09:15 -0400] \"GET /pub/rmd/success2.html HTTP/1.0\" 200 4977\nwww-b5.proxy.aol.com - - [03/Sep/1995:15:16:01 -0400] \"GET /atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\ntheoris.rz.uni-konstanz.de - - [03/Sep/1995:15:22:25 -0400] \"GET /atomicbk/catalog/sleazmag.html HTTP/1.0\" 200 6786\ncrl10.crl.com - - [03/Sep/1995:15:28:05 -0400] \"GET /pub/sshay/images/galybutn.gif HTTP/1.0\" 200 1080\npoppy.hensa.ac.uk - - [03/Sep/1995:15:34:20 -0400] \"GET /pub/murple/local/head-explode.html HTTP/1.0\" 200 4465\nslip4059.sirius.com - - [03/Sep/1995:15:41:38 -0400] \"GET /pub/job/swim/v-08.jpg HTTP/1.0\" 200 2155\n3dweb.vip.best.com - - [03/Sep/1995:15:49:40 -0400] \"GET /theme/cgi-bin/veewf.wrl HTTP/1.0\" 200 919\n199.190.77.158 - - [03/Sep/1995:15:57:21 -0400] \"GET /pub/downin/html/arlonet/icons/video.GIF HTTP/1.0\" 200 1644\n137.104.136.201 - - [03/Sep/1995:16:05:22 -0400] \"GET /pub/job/theman.jpg HTTP/1.0\" 200 8905\nwalker.amcc.com - - [03/Sep/1995:16:12:46 -0400] \"GET /pub/job/vk/view04.jpg HTTP/1.0\" 200 4847\ndd14-071.compuserve.com - - [03/Sep/1995:16:19:26 -0400] \"GET /pub/mbrophy/other_sites.html HTTP/1.0\" 200 2175\nix-nyc11-21.ix.netcom.com - - [03/Sep/1995:16:26:26 -0400] \"GET /pub/rsjdfg/Guilt.html HTTP/1.0\" 200 724\neuler.dcc.unicamp.br - - [03/Sep/1995:16:34:09 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nppp-66-61.dialup.winternet.com - - [03/Sep/1995:16:41:28 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nrover7.microsoft.com - - [03/Sep/1995:16:47:57 -0400] \"GET /pub/wick/misc/newgray.gif HTTP/1.0\" 200 17085\n137.219.80.52 - - [03/Sep/1995:16:56:21 -0400] \"GET /pub/atomicbk/images/library.gif HTTP/1.0\" 200 10696\nbalu.sch.bme.hu - - [03/Sep/1995:17:04:00 -0400] \"GET /pub/job/vk/view02.jpg HTTP/1.0\" 200 7290\nisglcr.sherritt.CA - - [03/Sep/1995:17:10:35 -0400] \"GET /pub/atomicbk/catalog/logo2.gif HTTP/1.0\" 200 12871\nrathlee.internet-eireann.ie - - [03/Sep/1995:17:17:24 -0400] \"GET /atomicbk/images/alfetish.gif HTTP/1.0\" 200 33094\nBasque.Stanford.EDU - - [03/Sep/1995:17:23:35 -0400] \"GET /pub/royfc/graphics/red_rt.gif HTTP/1.0\" 200 846\n131.115.147.204 - - [03/Sep/1995:17:31:13 -0400] \"GET /pub/job/vk/page1.gif HTTP/1.0\" 200 1960\nbluestem.prairienet.org - - [03/Sep/1995:17:38:41 -0400] \"GET /pub/lschank/explore/aboutme.html HTTP/1.0\" 200 4244\nschuller-pc1.ucsd.edu - - [03/Sep/1995:17:46:01 -0400] \"GET /pub/atomicbk/catalog/emboss.jpg HTTP/1.0\" 200 4741\nhasle.oslonett.no - - [03/Sep/1995:17:53:06 -0400] \"GET /pub/networx/autopage/autoadv.gif HTTP/1.0\" 200 33457\nwho.AFTAC.GOV - - [03/Sep/1995:18:00:16 -0400] \"GET /pub/job/vk/vendela.html HTTP/1.0\" 200 9084\n153.11.210.163 - - [03/Sep/1995:18:08:28 -0400] \"GET /pub/sshay/images/justin.jpg HTTP/1.0\" 200 3489\npiweba3y.prodigy.com - - [03/Sep/1995:18:14:14 -0400] \"GET /pub/robert/current.html HTTP/1.0\" 200 30337\n204.174.112.53 - - [03/Sep/1995:18:20:37 -0400] \"GET /pub/micros/forbes/bo-17-4.html HTTP/1.0\" 200 6115\npm1-42.inx.net - - [03/Sep/1995:18:26:49 -0400] \"GET /pub/pribut/idea.gif HTTP/1.0\" 200 909\ndialup-pkr-7-13.network.umr.edu - - [03/Sep/1995:18:33:49 -0400] \"GET /pub/wsg/html/jan/ HTTP/1.0\" 200 476\nchaos.idirect.com - - [03/Sep/1995:18:41:37 -0400] \"GET /pub/pribut/back.gif HTTP/1.0\" 200 713\nsvin09.win.tue.nl - - [03/Sep/1995:18:48:01 -0400] \"GET /pub/job/vk/view21.jpg HTTP/1.0\" 200 5228\n129.96.207.154 - - [03/Sep/1995:18:57:50 -0400] \"GET /pub/job/vk/view09.jpg HTTP/1.0\" 200 6011\nwww-d2.proxy.aol.com - - [03/Sep/1995:19:04:39 -0400] \"GET /pub/robert/past99.gif HTTP/1.0\" 200 4993\nmodem023.offcampus.calpoly.edu - - [03/Sep/1995:19:13:48 -0400] \"GET /pub/jumpsam/new_icon.gif HTTP/1.0\" 200 99\nholli-ko-017.holli.com - - [03/Sep/1995:19:21:43 -0400] \"GET /pub/journalism/busncard.html HTTP/1.0\" 200 1432\ndnet033.sat.texas.net - - [03/Sep/1995:19:29:51 -0400] \"GET /pub/grneyedl/in2.htm HTTP/1.0\" 200 4642\nchapman.ICSI.Net - - [03/Sep/1995:19:37:27 -0400] \"GET /pub/job/vk/view12.jpg HTTP/1.0\" 200 5966\ndial5-8.midwest.net - - [03/Sep/1995:19:44:23 -0400] \"GET /pub/peace/NEW1.html HTTP/1.0\" 200 1411\n131.144.82.190 - - [03/Sep/1995:19:52:33 -0400] \"GET /pub/jeffd/spkrnewt.gif HTTP/1.0\" 200 45247\nscihum07.uqtr.uquebec.ca - - [03/Sep/1995:20:02:13 -0400] \"GET /atomicbk/catalog/catalog.html HTTP/1.0\" 200 4654\nice.on.ca.ibm.net - - [03/Sep/1995:20:10:02 -0400] \"GET /pub/job/vk/view36.jpg HTTP/1.0\" 200 3522\ncornflower.cord.edu - - [03/Sep/1995:20:17:24 -0400] \"GET /atomicbk/catalog/adultcom.html HTTP/1.0\" 200 18673\n141.209.3.228 - - [03/Sep/1995:20:23:45 -0400] \"GET /pub/job/vk/view31.jpg HTTP/1.0\" 200 5611\nix-dgr-il1-20.ix.netcom.com - - [03/Sep/1995:20:32:28 -0400] \"GET /atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nfreenet2.carleton.ca - - [03/Sep/1995:20:40:11 -0400] \"GET /pub/macgyver/ HTTP/1.0\" 200 11337\nsnug.caltech.edu - - [03/Sep/1995:20:48:50 -0400] \"GET /ccentral/thinline.gif HTTP/1.0\" 200 1142\nhella.stm.it - - [03/Sep/1995:20:56:00 -0400] \"GET /pub/atomicbk/catalog/sleazbk.html HTTP/1.0\" 200 18338\nchegd40.che.utexas.edu - - [03/Sep/1995:21:03:02 -0400] \"GET /pub/atomicbk/catalog/catalog.gif HTTP/1.0\" 200 693\nppp3.blackhills.com - - [03/Sep/1995:21:09:12 -0400] \"GET /atomicbk/new/emboss.jpg HTTP/1.0\" 200 4741\ndcn68.dcn.davis.ca.us - - [03/Sep/1995:21:15:23 -0400] \"GET /pub/peace/Country1.GIF HTTP/1.0\" 200 55856\nS16.IC.Owatonna.MN.US - - [03/Sep/1995:21:23:44 -0400] \"GET /atomicbk/new/emboss.jpg HTTP/1.0\" 304 -\nix-tam1-13.ix.netcom.com - - [03/Sep/1995:21:30:17 -0400] \"GET /pub/lupine/www/disney.html HTTP/1.0\" 200 410\n134.124.43.218 - - [03/Sep/1995:21:37:14 -0400] \"GET /rtside/smreagan.gif HTTP/1.0\" 200 18018\nad15-014.compuserve.com - - [03/Sep/1995:21:45:02 -0400] \"GET /pub/lschank/web/foreign.html HTTP/1.0\" 200 8765\nbrianb.FASTech.Com - - [03/Sep/1995:21:53:06 -0400] \"GET /atomicbk/images/diarydom.gif HTTP/1.0\" 200 26849\nbernice23.pixi.com - - [03/Sep/1995:22:00:36 -0400] \"GET /pub/sshay/images/sglt.gif HTTP/1.0\" 200 19929\nnetcom5.netcom.com - - [03/Sep/1995:22:06:06 -0400] \"GET /pub/sshay/images/bigtoed.jpg HTTP/1.0\" 200 31158\nzuul.lcp.com - - [03/Sep/1995:22:12:48 -0400] \"POST /pub/theme/cgi-bin/virtwf.pl/l/mxd/n/mkultra/ HTTP/1.0\" 200 1315\nnetblazer1-s24.telalink.net - - [03/Sep/1995:22:19:00 -0400] \"GET /pub/sshay/images/sglt.gif HTTP/1.0\" 200 19929\n149.171.166.13 - - [03/Sep/1995:22:27:17 -0400] \"GET /pub/rsjdfg/Finale.html HTTP/1.0\" 200 564\nsud106.vianet.on.ca - - [03/Sep/1995:22:33:43 -0400] \"GET /pub/sshay/images/tyusvest.jpg HTTP/1.0\" 200 26791\ndial30.ppp.iastate.edu - - [03/Sep/1995:22:39:22 -0400] \"GET /pub/job/job-bk2.jpg HTTP/1.0\" 200 6947\nsmf-e9.facsmf.utexas.edu - - [03/Sep/1995:22:45:33 -0400] \"GET /atomicbk/catalog/orders.gif HTTP/1.0\" 200 800\npasyn-43.rice.edu - - [03/Sep/1995:22:52:35 -0400] \"GET /pub/networx/autopage/autopage.gif HTTP/1.0\" 200 57900\ndragon.com - - [03/Sep/1995:22:59:33 -0400] \"GET /pub/jeffd/gramm.gif HTTP/1.0\" 200 4364\nFindlay-Mac16.cac-labs.psu.edu - - [03/Sep/1995:23:06:13 -0400] \"GET /pub/atomicbk/images/bpann.gif HTTP/1.0\" 200 52405\ndal1318.computek.net - - [03/Sep/1995:23:12:55 -0400] \"GET /pub/sshay/images/scotface.gif HTTP/1.0\" 200 12100\nwww-c1.proxy.aol.com - - [03/Sep/1995:23:20:19 -0400] \"GET /pub/atomicbk/new/newjul15.html HTTP/1.0\" 304 -\nrose_ip162.efn.org - - [03/Sep/1995:23:27:48 -0400] \"GET /pub/atomicbk/email.gif HTTP/1.0\" 200 756\npslip005.mia-fl.ids.net - - [03/Sep/1995:23:34:05 -0400] \"GET /pub/alweiner/cgi-bin/homepage.html?pass HTTP/1.0\" 200 1753\nwww-b5.proxy.aol.com - - [03/Sep/1995:23:40:00 -0400] \"GET /pub/journalism/awesome.html HTTP/1.0\" 304 -\nebrady.clark.net - - [03/Sep/1995:23:47:00 -0400] \"GET /pub/green/ftp/cbm/games HTTP/1.0\" 302 231\nbadguy.clark.net - - [03/Sep/1995:23:53:40 -0400] \"GET /html/usage/usage.graph.small.gif HTTP/1.0\" 200 144\n"
  },
  {
    "path": "core-tools/tests-regression/web-log-report/out.ok",
    "content": "\t\t\tWWW server statistics\n\t\t\t=====================\n\nSummary\n-------\nNumber of accesses: 1655\nNumber of Gbytes transferred: 0.0142005\nNumber of hosts: 1507\nNumber of domains: 922\nNumber of top level domains: 58\nNumber of different pages: 948\nAccesses per day: 236.429\nMBytes per day: 2.07733\nMBytes log file size: 0.163606\n\nTop 10 Hosts\n------------\n     11 piweba3y.prodigy.com\n      7 www-c3.proxy.aol.com\n      7 www-b5.proxy.aol.com\n      7 www-a1.proxy.aol.com\n      7 webgate1.mot.com\n      6 www-b2.proxy.aol.com\n      5 www-b4.proxy.aol.com\n      5 clark.net\n      5 alweiner.clark.net\n      4 www-d2.proxy.aol.com\n\n\nTop 20 Level Domain Accesses\n----------------------------\n    452 com\n    224 edu\n    181 net\n     59 EDU\n     38 ca\n     35 uk\n     28 gov\n     27 jp\n     25 au\n     24 se\n     21 org\n     18 COM\n     16 de\n     16 NET\n     14 us\n     14 no\n     14 fr\n     13 mil\n     11 nl\n      9 ch\n\n\nTop 10 Domains\n--------------\n     80 .proxy.aol.com\n     44 .clark.net\n     34 .compuserve.com\n     29 .ix.netcom.com\n     24 .prodigy.com\n     11 .com\n      9 .Stanford.EDU\n      7 .mot.com\n      6 .urh.uiuc.edu\n      5 .netcom.com\n\n\nTop 10 Hosts by Transfer\n------------------------\n615030 buckman.com\n208591 www-b5.proxy.aol.com\n173690 hel.fi\n169367 in116.brann.co.uk\n169367 149.157.246.44\n108564 london.Informatik.Uni-Oldenburg.DE\n106890 www-b2.proxy.aol.com\n106571 gateway.senate.gov\n106074 gorgon.pwgsc.gc.ca\n97751 HRSB741.RESNET.UPENN.EDU\n\nTop 20 Area Requests\n--------------------\n   1461 pub\n    136 atomicbk\n     10 graphics\n      8 theme\n      7 html\n      4 mc-icons\n      3 mpt\n      3 larouche\n      2 printing\n      2 ntp\n      2 network\n      2 infouser\n      2 ccentral\n      2 aztec\n      2 \n      1 www.clark.net\n      1 winfield\n      1 tara\n      1 rtside\n      1 nrlc\n\n\nTop 20 Requests\n---------------\n     24 /pub/atomicbk/catalog/catalog.gif\n     18 /pub/atomicbk/catalog/logo2.gif\n     17 /pub/job/vk/vendela.html\n     17 /pub/atomicbk/catalog/sleazbk.html\n     17 /pub/atomicbk/catalog/home.gif\n     15 /pub/job/vk/view02.jpg\n     15 /pub/atomicbk/catalog/orders.gif\n     14 /pub/job/vk/view07.jpg\n     13 /pub/journalism/awesome.html\n     13 /pub/job/vk/view16.jpg\n     12 /pub/job/vk/view03.jpg\n     12 /pub/job/vk/flowers1.gif\n     12 /pub/job/vendela.jpg\n     12 /pub/atomicbk/catalog/new.gif\n     11 /pub/job/vk/vk-bk.jpg\n     11 /pub/job/vk/view14.jpg\n     11 /pub/atomicbk/catalog/mini.gif\n     10 /pub/job/vk/view15.jpg\n     10 /pub/job/vk/view04.jpg\n     10 /pub/job/vk/v-sig.gif\n\n\nAccesses by Date\n----------------\n    252 28/Aug/1995\n    267 29/Aug/1995\n    274 30/Aug/1995\n    259 31/Aug/1995\n    269 01/Sep/1995\n    171 02/Sep/1995\n    163 03/Sep/1995\n\nAccesses by Day of Week\n-----------------------\n    274 Wed\n    269 Fri\n    267 Tue\n    259 Thu\n    252 Mon\n    171 Sat\n    163 Sun\n\nAccesses by Local Hour\n----------------------\n     64 00\n     50 01\n     49 02\n     40 03\n     32 04\n     31 05\n     29 06\n     41 07\n     49 08\n     66 09\n     78 10\n     86 11\n     92 12\n     95 13\n    100 14\n    105 15\n    102 16\n     95 17\n     89 18\n     79 19\n     73 20\n     71 21\n     72 22\n     67 23\n"
  },
  {
    "path": "core-tools/tests-regression/word-properties/LostWorldChap1-3",
    "content": "The Project Gutenberg EBook of The Lost World, by Arthur Conan Doyle\n\nThis eBook is for the use of anyone anywhere at no cost and with\nalmost no restrictions whatsoever.  You may copy it, give it away or\nre-use it under the terms of the Project Gutenberg License included\nwith this eBook or online at www.gutenberg.net\n\n\nTitle: The Lost World\n\nAuthor: Arthur Conan Doyle\n\nRelease Date: June 19, 2008 [EBook #139]\n\nLanguage: English\n\nCharacter set encoding: ASCII\n\n*** START OF THIS PROJECT GUTENBERG EBOOK THE LOST WORLD ***\n\n\n\n\nProduced by Judith Boss.  HTML version by Al Haines.\n\n\n\n\n\n\n\n\n\n\n                          THE LOST WORLD\n\n                   I have wrought my simple plan\n                    If I give one hour of joy\n                  To the boy who's half a man,\n                    Or the man who's half a boy.\n\n\n\n                          The Lost World\n\n\n                                By\n\n                     SIR ARTHUR CONAN DOYLE\n\n                         COPYRIGHT, 1912\n\n\n\n                             Foreword\n\n            Mr. E. D. Malone desires to state that\n          both the injunction for restraint and the\n          libel action have been withdrawn unreservedly\n          by Professor G. E. Challenger, who, being\n          satisfied that no criticism or comment in\n          this book is meant in an offensive spirit,\n          has guaranteed that he will place no\n          impediment to its publication and circulation.\n\n\n\n\n\n                             Contents\n\nCHAPTER\n\n    I.  \"THERE ARE HEROISMS ALL ROUND US\"\n   II.  \"TRY YOUR LUCK WITH PROFESSOR CHALLENGER\"\n  III.  \"HE IS A PERFECTLY IMPOSSIBLE PERSON\"\n   IV.  \"IT'S JUST THE VERY BIGGEST THING IN THE WORLD\"\n    V.  \"QUESTION!\"\n   VI.  \"I WAS THE FLAIL OF THE LORD\"\n  VII.  \"TO-MORROW WE DISAPPEAR INTO THE UNKNOWN\"\n VIII.  \"THE OUTLYING PICKETS OF THE NEW WORLD\"\n   IX.  \"WHO COULD HAVE FORESEEN IT?\"\n    X.  \"THE MOST WONDERFUL THINGS HAVE HAPPENED\"\n   XI.  \"FOR ONCE I WAS THE HERO\"\n  XII.  \"IT WAS DREADFUL IN THE FOREST\"\n XIII.  \"A SIGHT I SHALL NEVER FORGET\"\n  XIV.  \"THOSE WERE THE REAL CONQUESTS\"\n   XV.  \"OUR EYES HAVE SEEN GREAT WONDERS\"\n  XVI.  \"A PROCESSION!  A PROCESSION!\"\n\n\n\n\n                          THE LOST WORLD\n\n\n\n\n                          The Lost World\n\n                            CHAPTER I\n\n                \"There Are Heroisms All Round Us\"\n\nMr. Hungerton, her father, really was the most tactless person upon\nearth,--a fluffy, feathery, untidy cockatoo of a man, perfectly\ngood-natured, but absolutely centered upon his own silly self.  If\nanything could have driven me from Gladys, it would have been the\nthought of such a father-in-law.  I am convinced that he really\nbelieved in his heart that I came round to the Chestnuts three days a\nweek for the pleasure of his company, and very especially to hear his\nviews upon bimetallism, a subject upon which he was by way of being an\nauthority.\n\nFor an hour or more that evening I listened to his monotonous chirrup\nabout bad money driving out good, the token value of silver, the\ndepreciation of the rupee, and the true standards of exchange.\n\n\"Suppose,\" he cried with feeble violence, \"that all the debts in the\nworld were called up simultaneously, and immediate payment insisted\nupon,--what under our present conditions would happen then?\"\n\nI gave the self-evident answer that I should be a ruined man, upon\nwhich he jumped from his chair, reproved me for my habitual levity,\nwhich made it impossible for him to discuss any reasonable subject in\nmy presence, and bounced off out of the room to dress for a Masonic\nmeeting.\n\nAt last I was alone with Gladys, and the moment of Fate had come!  All\nthat evening I had felt like the soldier who awaits the signal which\nwill send him on a forlorn hope; hope of victory and fear of repulse\nalternating in his mind.\n\nShe sat with that proud, delicate profile of hers outlined against the\nred curtain.  How beautiful she was!  And yet how aloof!  We had been\nfriends, quite good friends; but never could I get beyond the same\ncomradeship which I might have established with one of my\nfellow-reporters upon the Gazette,--perfectly frank, perfectly kindly,\nand perfectly unsexual.  My instincts are all against a woman being too\nfrank and at her ease with me.  It is no compliment to a man.  Where\nthe real sex feeling begins, timidity and distrust are its companions,\nheritage from old wicked days when love and violence went often hand in\nhand.  The bent head, the averted eye, the faltering voice, the wincing\nfigure--these, and not the unshrinking gaze and frank reply, are the\ntrue signals of passion.  Even in my short life I had learned as much\nas that--or had inherited it in that race memory which we call instinct.\n\nGladys was full of every womanly quality.  Some judged her to be cold\nand hard; but such a thought was treason.  That delicately bronzed\nskin, almost oriental in its coloring, that raven hair, the large\nliquid eyes, the full but exquisite lips,--all the stigmata of passion\nwere there.  But I was sadly conscious that up to now I had never found\nthe secret of drawing it forth.  However, come what might, I should\nhave done with suspense and bring matters to a head to-night.  She\ncould but refuse me, and better be a repulsed lover than an accepted\nbrother.\n\nSo far my thoughts had carried me, and I was about to break the long\nand uneasy silence, when two critical, dark eyes looked round at me,\nand the proud head was shaken in smiling reproof.  \"I have a\npresentiment that you are going to propose, Ned.  I do wish you\nwouldn't; for things are so much nicer as they are.\"\n\nI drew my chair a little nearer.  \"Now, how did you know that I was\ngoing to propose?\" I asked in genuine wonder.\n\n\"Don't women always know?  Do you suppose any woman in the world was\never taken unawares?  But--oh, Ned, our friendship has been so good and\nso pleasant!  What a pity to spoil it!  Don't you feel how splendid it\nis that a young man and a young woman should be able to talk face to\nface as we have talked?\"\n\n\"I don't know, Gladys.  You see, I can talk face to face with--with the\nstation-master.\"  I can't imagine how that official came into the\nmatter; but in he trotted, and set us both laughing.  \"That does not\nsatisfy me in the least.  I want my arms round you, and your head on my\nbreast, and--oh, Gladys, I want----\"\n\nShe had sprung from her chair, as she saw signs that I proposed to\ndemonstrate some of my wants.  \"You've spoiled everything, Ned,\" she\nsaid.  \"It's all so beautiful and natural until this kind of thing\ncomes in!  It is such a pity!  Why can't you control yourself?\"\n\n\"I didn't invent it,\" I pleaded.  \"It's nature.  It's love.\"\n\n\"Well, perhaps if both love, it may be different.  I have never felt\nit.\"\n\n\"But you must--you, with your beauty, with your soul!  Oh, Gladys, you\nwere made for love!  You must love!\"\n\n\"One must wait till it comes.\"\n\n\"But why can't you love me, Gladys?  Is it my appearance, or what?\"\n\nShe did unbend a little.  She put forward a hand--such a gracious,\nstooping attitude it was--and she pressed back my head.  Then she\nlooked into my upturned face with a very wistful smile.\n\n\"No it isn't that,\" she said at last.  \"You're not a conceited boy by\nnature, and so I can safely tell you it is not that.  It's deeper.\"\n\n\"My character?\"\n\nShe nodded severely.\n\n\"What can I do to mend it?  Do sit down and talk it over.  No, really,\nI won't if you'll only sit down!\"\n\nShe looked at me with a wondering distrust which was much more to my\nmind than her whole-hearted confidence.  How primitive and bestial it\nlooks when you put it down in black and white!--and perhaps after all\nit is only a feeling peculiar to myself.  Anyhow, she sat down.\n\n\"Now tell me what's amiss with me?\"\n\n\"I'm in love with somebody else,\" said she.\n\nIt was my turn to jump out of my chair.\n\n\"It's nobody in particular,\" she explained, laughing at the expression\nof my face: \"only an ideal.  I've never met the kind of man I mean.\"\n\n\"Tell me about him.  What does he look like?\"\n\n\"Oh, he might look very much like you.\"\n\n\"How dear of you to say that!  Well, what is it that he does that I\ndon't do?  Just say the word,--teetotal, vegetarian, aeronaut,\ntheosophist, superman.  I'll have a try at it, Gladys, if you will only\ngive me an idea what would please you.\"\n\nShe laughed at the elasticity of my character.  \"Well, in the first\nplace, I don't think my ideal would speak like that,\" said she.  \"He\nwould be a harder, sterner man, not so ready to adapt himself to a\nsilly girl's whim.  But, above all, he must be a man who could do, who\ncould act, who could look Death in the face and have no fear of him, a\nman of great deeds and strange experiences.  It is never a man that I\nshould love, but always the glories he had won; for they would be\nreflected upon me.  Think of Richard Burton!  When I read his wife's\nlife of him I could so understand her love!  And Lady Stanley!  Did you\never read the wonderful last chapter of that book about her husband?\nThese are the sort of men that a woman could worship with all her soul,\nand yet be the greater, not the less, on account of her love, honored\nby all the world as the inspirer of noble deeds.\"\n\nShe looked so beautiful in her enthusiasm that I nearly brought down\nthe whole level of the interview.  I gripped myself hard, and went on\nwith the argument.\n\n\"We can't all be Stanleys and Burtons,\" said I; \"besides, we don't get\nthe chance,--at least, I never had the chance.  If I did, I should try\nto take it.\"\n\n\"But chances are all around you.  It is the mark of the kind of man I\nmean that he makes his own chances.  You can't hold him back.  I've\nnever met him, and yet I seem to know him so well.  There are heroisms\nall round us waiting to be done.  It's for men to do them, and for\nwomen to reserve their love as a reward for such men.  Look at that\nyoung Frenchman who went up last week in a balloon.  It was blowing a\ngale of wind; but because he was announced to go he insisted on\nstarting.  The wind blew him fifteen hundred miles in twenty-four\nhours, and he fell in the middle of Russia.  That was the kind of man I\nmean.  Think of the woman he loved, and how other women must have\nenvied her!  That's what I should like to be,--envied for my man.\"\n\n\"I'd have done it to please you.\"\n\n\"But you shouldn't do it merely to please me.  You should do it because\nyou can't help yourself, because it's natural to you, because the man\nin you is crying out for heroic expression.  Now, when you described\nthe Wigan coal explosion last month, could you not have gone down and\nhelped those people, in spite of the choke-damp?\"\n\n\"I did.\"\n\n\"You never said so.\"\n\n\"There was nothing worth bucking about.\"\n\n\"I didn't know.\"  She looked at me with rather more interest.  \"That\nwas brave of you.\"\n\n\"I had to.  If you want to write good copy, you must be where the\nthings are.\"\n\n\"What a prosaic motive!  It seems to take all the romance out of it.\nBut, still, whatever your motive, I am glad that you went down that\nmine.\"  She gave me her hand; but with such sweetness and dignity that\nI could only stoop and kiss it.  \"I dare say I am merely a foolish\nwoman with a young girl's fancies.  And yet it is so real with me, so\nentirely part of my very self, that I cannot help acting upon it.  If I\nmarry, I do want to marry a famous man!\"\n\n\"Why should you not?\" I cried.  \"It is women like you who brace men up.\nGive me a chance, and see if I will take it!  Besides, as you say, men\nought to MAKE their own chances, and not wait until they are given.\nLook at Clive--just a clerk, and he conquered India!  By George!  I'll\ndo something in the world yet!\"\n\nShe laughed at my sudden Irish effervescence.  \"Why not?\" she said.\n\"You have everything a man could have,--youth, health, strength,\neducation, energy.  I was sorry you spoke.  And now I am glad--so\nglad--if it wakens these thoughts in you!\"\n\n\"And if I do----\"\n\nHer dear hand rested like warm velvet upon my lips.  \"Not another word,\nSir!  You should have been at the office for evening duty half an hour\nago; only I hadn't the heart to remind you.  Some day, perhaps, when\nyou have won your place in the world, we shall talk it over again.\"\n\nAnd so it was that I found myself that foggy November evening pursuing\nthe Camberwell tram with my heart glowing within me, and with the eager\ndetermination that not another day should elapse before I should find\nsome deed which was worthy of my lady.  But who--who in all this wide\nworld could ever have imagined the incredible shape which that deed was\nto take, or the strange steps by which I was led to the doing of it?\n\nAnd, after all, this opening chapter will seem to the reader to have\nnothing to do with my narrative; and yet there would have been no\nnarrative without it, for it is only when a man goes out into the world\nwith the thought that there are heroisms all round him, and with the\ndesire all alive in his heart to follow any which may come within sight\nof him, that he breaks away as I did from the life he knows, and\nventures forth into the wonderful mystic twilight land where lie the\ngreat adventures and the great rewards.  Behold me, then, at the office\nof the Daily Gazette, on the staff of which I was a most insignificant\nunit, with the settled determination that very night, if possible, to\nfind the quest which should be worthy of my Gladys!  Was it hardness,\nwas it selfishness, that she should ask me to risk my life for her own\nglorification?  Such thoughts may come to middle age; but never to\nardent three-and-twenty in the fever of his first love.\n\n\n\n\n                            CHAPTER II\n\n            \"Try Your Luck with Professor Challenger\"\n\nI always liked McArdle, the crabbed, old, round-backed, red-headed news\neditor, and I rather hoped that he liked me.  Of course, Beaumont was\nthe real boss; but he lived in the rarefied atmosphere of some Olympian\nheight from which he could distinguish nothing smaller than an\ninternational crisis or a split in the Cabinet.  Sometimes we saw him\npassing in lonely majesty to his inner sanctum, with his eyes staring\nvaguely and his mind hovering over the Balkans or the Persian Gulf.  He\nwas above and beyond us.  But McArdle was his first lieutenant, and it\nwas he that we knew.  The old man nodded as I entered the room, and he\npushed his spectacles far up on his bald forehead.\n\n\"Well, Mr. Malone, from all I hear, you seem to be doing very well,\"\nsaid he in his kindly Scotch accent.\n\nI thanked him.\n\n\"The colliery explosion was excellent.  So was the Southwark fire.  You\nhave the true descreeptive touch.  What did you want to see me about?\"\n\n\"To ask a favor.\"\n\nHe looked alarmed, and his eyes shunned mine. \"Tut, tut!  What is it?\"\n\n\"Do you think, Sir, that you could possibly send me on some mission for\nthe paper?  I would do my best to put it through and get you some good\ncopy.\"\n\n\"What sort of meesion had you in your mind, Mr. Malone?\"\n\n\"Well, Sir, anything that had adventure and danger in it.  I really\nwould do my very best.  The more difficult it was, the better it would\nsuit me.\"\n\n\"You seem very anxious to lose your life.\"\n\n\"To justify my life, Sir.\"\n\n\"Dear me, Mr. Malone, this is very--very exalted.  I'm afraid the day\nfor this sort of thing is rather past.  The expense of the 'special\nmeesion' business hardly justifies the result, and, of course, in any\ncase it would only be an experienced man with a name that would command\npublic confidence who would get such an order.  The big blank spaces in\nthe map are all being filled in, and there's no room for romance\nanywhere.  Wait a bit, though!\" he added, with a sudden smile upon his\nface.  \"Talking of the blank spaces of the map gives me an idea.  What\nabout exposing a fraud--a modern Munchausen--and making him\nrideeculous?  You could show him up as the liar that he is!  Eh, man,\nit would be fine.  How does it appeal to you?\"\n\n\"Anything--anywhere--I care nothing.\"\n\nMcArdle was plunged in thought for some minutes.\n\n\"I wonder whether you could get on friendly--or at least on talking\nterms with the fellow,\" he said, at last.  \"You seem to have a sort of\ngenius for establishing relations with people--seempathy, I suppose, or\nanimal magnetism, or youthful vitality, or something.  I am conscious\nof it myself.\"\n\n\"You are very good, sir.\"\n\n\"So why should you not try your luck with Professor Challenger, of\nEnmore Park?\"\n\nI dare say I looked a little startled.\n\n\"Challenger!\" I cried.  \"Professor Challenger, the famous zoologist!\nWasn't he the man who broke the skull of Blundell, of the Telegraph?\"\n\nThe news editor smiled grimly.\n\n\"Do you mind?  Didn't you say it was adventures you were after?\"\n\n\"It is all in the way of business, sir,\" I answered.\n\n\"Exactly.  I don't suppose he can always be so violent as that.  I'm\nthinking that Blundell got him at the wrong moment, maybe, or in the\nwrong fashion.  You may have better luck, or more tact in handling him.\nThere's something in your line there, I am sure, and the Gazette should\nwork it.\"\n\n\"I really know nothing about him,\" said I.  \"I only remember his name\nin connection with the police-court proceedings, for striking Blundell.\"\n\n\"I have a few notes for your guidance, Mr. Malone.  I've had my eye on\nthe Professor for some little time.\"  He took a paper from a drawer.\n\"Here is a summary of his record.  I give it you briefly:--\n\n\"'Challenger, George Edward.  Born: Largs, N. B., 1863.  Educ.: Largs\nAcademy; Edinburgh University.  British Museum Assistant, 1892.\nAssistant-Keeper of Comparative Anthropology Department, 1893.\nResigned after acrimonious correspondence same year.  Winner of\nCrayston Medal for Zoological Research.  Foreign Member of'--well,\nquite a lot of things, about two inches of small type--'Societe Belge,\nAmerican Academy of Sciences, La Plata, etc., etc.  Ex-President\nPalaeontological Society.  Section H, British Association'--so on, so\non!--'Publications: \"Some Observations Upon a Series of Kalmuck\nSkulls\"; \"Outlines of Vertebrate Evolution\"; and numerous papers,\nincluding \"The underlying fallacy of Weissmannism,\" which caused heated\ndiscussion at the Zoological Congress of Vienna.  Recreations: Walking,\nAlpine climbing.  Address: Enmore Park, Kensington, W.'\n\n\"There, take it with you.  I've nothing more for you to-night.\"\n\nI pocketed the slip of paper.\n\n\"One moment, sir,\" I said, as I realized that it was a pink bald head,\nand not a red face, which was fronting me.  \"I am not very clear yet\nwhy I am to interview this gentleman.  What has he done?\"\n\nThe face flashed back again.\n\n\"Went to South America on a solitary expedeetion two years ago.  Came\nback last year.  Had undoubtedly been to South America, but refused to\nsay exactly where.  Began to tell his adventures in a vague way, but\nsomebody started to pick holes, and he just shut up like an oyster.\nSomething wonderful happened--or the man's a champion liar, which is\nthe more probable supposeetion.  Had some damaged photographs, said to\nbe fakes.  Got so touchy that he assaults anyone who asks questions,\nand heaves reporters down the stairs.  In my opinion he's just a\nhomicidal megalomaniac with a turn for science.  That's your man, Mr.\nMalone.  Now, off you run, and see what you can make of him.  You're\nbig enough to look after yourself.  Anyway, you are all safe.\nEmployers' Liability Act, you know.\"\n\nA grinning red face turned once more into a pink oval, fringed with\ngingery fluff; the interview was at an end.\n\nI walked across to the Savage Club, but instead of turning into it I\nleaned upon the railings of Adelphi Terrace and gazed thoughtfully for\na long time at the brown, oily river.  I can always think most sanely\nand clearly in the open air.  I took out the list of Professor\nChallenger's exploits, and I read it over under the electric lamp.\nThen I had what I can only regard as an inspiration.  As a Pressman, I\nfelt sure from what I had been told that I could never hope to get into\ntouch with this cantankerous Professor.  But these recriminations,\ntwice mentioned in his skeleton biography, could only mean that he was\na fanatic in science.  Was there not an exposed margin there upon which\nhe might be accessible?  I would try.\n\nI entered the club.  It was just after eleven, and the big room was\nfairly full, though the rush had not yet set in.  I noticed a tall,\nthin, angular man seated in an arm-chair by the fire.  He turned as I\ndrew my chair up to him.  It was the man of all others whom I should\nhave chosen--Tarp Henry, of the staff of Nature, a thin, dry, leathery\ncreature, who was full, to those who knew him, of kindly humanity.  I\nplunged instantly into my subject.\n\n\"What do you know of Professor Challenger?\"\n\n\"Challenger?\" He gathered his brows in scientific disapproval.\n\"Challenger was the man who came with some cock-and-bull story from\nSouth America.\"\n\n\"What story?\"\n\n\"Oh, it was rank nonsense about some queer animals he had discovered.\nI believe he has retracted since.  Anyhow, he has suppressed it all.\nHe gave an interview to Reuter's, and there was such a howl that he saw\nit wouldn't do.  It was a discreditable business.  There were one or\ntwo folk who were inclined to take him seriously, but he soon choked\nthem off.\"\n\n\"How?\"\n\n\"Well, by his insufferable rudeness and impossible behavior.  There was\npoor old Wadley, of the Zoological Institute.  Wadley sent a message:\n'The President of the Zoological Institute presents his compliments to\nProfessor Challenger, and would take it as a personal favor if he would\ndo them the honor to come to their next meeting.'  The answer was\nunprintable.\"\n\n\"You don't say?\"\n\n\"Well, a bowdlerized version of it would run:  'Professor Challenger\npresents his compliments to the President of the Zoological Institute,\nand would take it as a personal favor if he would go to the devil.'\"\n\n\"Good Lord!\"\n\n\"Yes, I expect that's what old Wadley said.  I remember his wail at the\nmeeting, which began:  'In fifty years experience of scientific\nintercourse----'  It quite broke the old man up.\"\n\n\"Anything more about Challenger?\"\n\n\"Well, I'm a bacteriologist, you know.  I live in a\nnine-hundred-diameter microscope.  I can hardly claim to take serious\nnotice of anything that I can see with my naked eye.  I'm a\nfrontiersman from the extreme edge of the Knowable, and I feel quite\nout of place when I leave my study and come into touch with all you\ngreat, rough, hulking creatures.  I'm too detached to talk scandal, and\nyet at scientific conversaziones I HAVE heard something of Challenger,\nfor he is one of those men whom nobody can ignore.  He's as clever as\nthey make 'em--a full-charged battery of force and vitality, but a\nquarrelsome, ill-conditioned faddist, and unscrupulous at that.  He had\ngone the length of faking some photographs over the South American\nbusiness.\"\n\n\"You say he is a faddist.  What is his particular fad?\"\n\n\"He has a thousand, but the latest is something about Weissmann and\nEvolution.  He had a fearful row about it in Vienna, I believe.\"\n\n\"Can't you tell me the point?\"\n\n\"Not at the moment, but a translation of the proceedings exists.  We\nhave it filed at the office.  Would you care to come?\"\n\n\"It's just what I want.  I have to interview the fellow, and I need\nsome lead up to him.  It's really awfully good of you to give me a\nlift.  I'll go with you now, if it is not too late.\"\n\n\nHalf an hour later I was seated in the newspaper office with a huge\ntome in front of me, which had been opened at the article \"Weissmann\nversus Darwin,\" with the sub heading, \"Spirited Protest at Vienna.\nLively Proceedings.\"  My scientific education having been somewhat\nneglected, I was unable to follow the whole argument, but it was\nevident that the English Professor had handled his subject in a very\naggressive fashion, and had thoroughly annoyed his Continental\ncolleagues.  \"Protests,\" \"Uproar,\" and \"General appeal to the Chairman\"\nwere three of the first brackets which caught my eye.  Most of the\nmatter might have been written in Chinese for any definite meaning that\nit conveyed to my brain.\n\n\"I wish you could translate it into English for me,\" I said,\npathetically, to my help-mate.\n\n\"Well, it is a translation.\"\n\n\"Then I'd better try my luck with the original.\"\n\n\"It is certainly rather deep for a layman.\"\n\n\"If I could only get a single good, meaty sentence which seemed to\nconvey some sort of definite human idea, it would serve my turn.  Ah,\nyes, this one will do.  I seem in a vague way almost to understand it.\nI'll copy it out.  This shall be my link with the terrible Professor.\"\n\n\"Nothing else I can do?\"\n\n\"Well, yes; I propose to write to him.  If I could frame the letter\nhere, and use your address it would give atmosphere.\"\n\n\"We'll have the fellow round here making a row and breaking the\nfurniture.\"\n\n\"No, no; you'll see the letter--nothing contentious, I assure you.\"\n\n\"Well, that's my chair and desk.  You'll find paper there.  I'd like to\ncensor it before it goes.\"\n\nIt took some doing, but I flatter myself that it wasn't such a bad job\nwhen it was finished.  I read it aloud to the critical bacteriologist\nwith some pride in my handiwork.\n\n\n\"DEAR PROFESSOR CHALLENGER,\" it said, \"As a humble student of Nature, I\nhave always taken the most profound interest in your speculations as to\nthe differences between Darwin and Weissmann.  I have recently had\noccasion to refresh my memory by re-reading----\"\n\n\n\"You infernal liar!\" murmured Tarp Henry.\n\n\n--\"by re-reading your masterly address at Vienna.  That lucid and\nadmirable statement seems to be the last word in the matter.  There is\none sentence in it, however--namely:  'I protest strongly against the\ninsufferable and entirely dogmatic assertion that each separate id is a\nmicrocosm possessed of an historical architecture elaborated slowly\nthrough the series of generations.' Have you no desire, in view of\nlater research, to modify this statement?  Do you not think that it is\nover-accentuated?  With your permission, I would ask the favor of an\ninterview, as I feel strongly upon the subject, and have certain\nsuggestions which I could only elaborate in a personal conversation.\nWith your consent, I trust to have the honor of calling at eleven\no'clock the day after to-morrow (Wednesday) morning.\n\n\"I remain, Sir, with assurances of profound respect, yours very truly,\n\nEDWARD D. MALONE.\"\n\n\n\"How's that?\" I asked, triumphantly.\n\n\"Well if your conscience can stand it----\"\n\n\"It has never failed me yet.\"\n\n\"But what do you mean to do?\"\n\n\"To get there.  Once I am in his room I may see some opening.  I may\neven go the length of open confession.  If he is a sportsman he will be\ntickled.\"\n\n\"Tickled, indeed!  He's much more likely to do the tickling.  Chain\nmail, or an American football suit--that's what you'll want.  Well,\ngood-bye.  I'll have the answer for you here on Wednesday morning--if\nhe ever deigns to answer you.  He is a violent, dangerous, cantankerous\ncharacter, hated by everyone who comes across him, and the butt of the\nstudents, so far as they dare take a liberty with him.  Perhaps it\nwould be best for you if you never heard from the fellow at all.\"\n\n\n\n\n                           CHAPTER III\n\n              \"He is a Perfectly Impossible Person\"\n\nMy friend's fear or hope was not destined to be realized.  When I\ncalled on Wednesday there was a letter with the West Kensington\npostmark upon it, and my name scrawled across the envelope in a\nhandwriting which looked like a barbed-wire railing.  The contents were\nas follows:--\n\n\n                              \"ENMORE PARK, W.\n\n\"SIR,--I have duly received your note, in which you claim to endorse my\nviews, although I am not aware that they are dependent upon endorsement\neither from you or anyone else.  You have ventured to use the word\n'speculation' with regard to my statement upon the subject of\nDarwinism, and I would call your attention to the fact that such a word\nin such a connection is offensive to a degree.  The context convinces\nme, however, that you have sinned rather through ignorance and\ntactlessness than through malice, so I am content to pass the matter\nby.  You quote an isolated sentence from my lecture, and appear to have\nsome difficulty in understanding it.  I should have thought that only a\nsub-human intelligence could have failed to grasp the point, but if it\nreally needs amplification I shall consent to see you at the hour\nnamed, though visits and visitors of every sort are exceeding\ndistasteful to me.  As to your suggestion that I may modify my opinion,\nI would have you know that it is not my habit to do so after a\ndeliberate expression of my mature views.  You will kindly show the\nenvelope of this letter to my man, Austin, when you call, as he has to\ntake every precaution to shield me from the intrusive rascals who call\nthemselves 'journalists.'\n\n                          \"Yours faithfully,\n                            \"GEORGE EDWARD CHALLENGER.\"\n\n\nThis was the letter that I read aloud to Tarp Henry, who had come down\nearly to hear the result of my venture.  His only remark was, \"There's\nsome new stuff, cuticura or something, which is better than arnica.\"\nSome people have such extraordinary notions of humor.\n\nIt was nearly half-past ten before I had received my message, but a\ntaxicab took me round in good time for my appointment.  It was an\nimposing porticoed house at which we stopped, and the heavily-curtained\nwindows gave every indication of wealth upon the part of this\nformidable Professor.  The door was opened by an odd, swarthy, dried-up\nperson of uncertain age, with a dark pilot jacket and brown leather\ngaiters.  I found afterwards that he was the chauffeur, who filled the\ngaps left by a succession of fugitive butlers.  He looked me up and\ndown with a searching light blue eye.\n\n\"Expected?\" he asked.\n\n\"An appointment.\"\n\n\"Got your letter?\"\n\nI produced the envelope.\n\n\"Right!\"  He seemed to be a person of few words.  Following him down\nthe passage I was suddenly interrupted by a small woman, who stepped\nout from what proved to be the dining-room door.  She was a bright,\nvivacious, dark-eyed lady, more French than English in her type.\n\n\"One moment,\" she said.  \"You can wait, Austin.  Step in here, sir.\nMay I ask if you have met my husband before?\"\n\n\"No, madam, I have not had the honor.\"\n\n\"Then I apologize to you in advance.  I must tell you that he is a\nperfectly impossible person--absolutely impossible.  If you are\nforewarned you will be the more ready to make allowances.\"\n\n\"It is most considerate of you, madam.\"\n\n\"Get quickly out of the room if he seems inclined to be violent.  Don't\nwait to argue with him.  Several people have been injured through doing\nthat.  Afterwards there is a public scandal and it reflects upon me and\nall of us.  I suppose it wasn't about South America you wanted to see\nhim?\"\n\nI could not lie to a lady.\n\n\"Dear me!  That is his most dangerous subject.  You won't believe a\nword he says--I'm sure I don't wonder.  But don't tell him so, for it\nmakes him very violent.  Pretend to believe him, and you may get\nthrough all right.  Remember he believes it himself.  Of that you may\nbe assured.  A more honest man never lived.  Don't wait any longer or\nhe may suspect.  If you find him dangerous--really dangerous--ring the\nbell and hold him off until I come.  Even at his worst I can usually\ncontrol him.\"\n\nWith these encouraging words the lady handed me over to the taciturn\nAustin, who had waited like a bronze statue of discretion during our\nshort interview, and I was conducted to the end of the passage.  There\nwas a tap at a door, a bull's bellow from within, and I was face to\nface with the Professor.\n\nHe sat in a rotating chair behind a broad table, which was covered with\nbooks, maps, and diagrams.  As I entered, his seat spun round to face\nme.  His appearance made me gasp.  I was prepared for something\nstrange, but not for so overpowering a personality as this.  It was his\nsize which took one's breath away--his size and his imposing presence.\nHis head was enormous, the largest I have ever seen upon a human being.\nI am sure that his top-hat, had I ever ventured to don it, would have\nslipped over me entirely and rested on my shoulders.  He had the face\nand beard which I associate with an Assyrian bull; the former florid,\nthe latter so black as almost to have a suspicion of blue, spade-shaped\nand rippling down over his chest.  The hair was peculiar, plastered\ndown in front in a long, curving wisp over his massive forehead.  The\neyes were blue-gray under great black tufts, very clear, very critical,\nand very masterful.  A huge spread of shoulders and a chest like a\nbarrel were the other parts of him which appeared above the table, save\nfor two enormous hands covered with long black hair.  This and a\nbellowing, roaring, rumbling voice made up my first impression of the\nnotorious Professor Challenger.\n\n\"Well?\" said he, with a most insolent stare.  \"What now?\"\n\nI must keep up my deception for at least a little time longer,\notherwise here was evidently an end of the interview.\n\n\"You were good enough to give me an appointment, sir,\" said I, humbly,\nproducing his envelope.\n\nHe took my letter from his desk and laid it out before him.\n\n\"Oh, you are the young person who cannot understand plain English, are\nyou?  My general conclusions you are good enough to approve, as I\nunderstand?\"\n\n\"Entirely, sir--entirely!\"  I was very emphatic.\n\n\"Dear me!  That strengthens my position very much, does it not?  Your\nage and appearance make your support doubly valuable.  Well, at least\nyou are better than that herd of swine in Vienna, whose gregarious\ngrunt is, however, not more offensive than the isolated effort of the\nBritish hog.\"  He glared at me as the present representative of the\nbeast.\n\n\"They seem to have behaved abominably,\" said I.\n\n\"I assure you that I can fight my own battles, and that I have no\npossible need of your sympathy.  Put me alone, sir, and with my back to\nthe wall.  G. E. C. is happiest then.  Well, sir, let us do what we can\nto curtail this visit, which can hardly be agreeable to you, and is\ninexpressibly irksome to me.  You had, as I have been led to believe,\nsome comments to make upon the proposition which I advanced in my\nthesis.\"\n\nThere was a brutal directness about his methods which made evasion\ndifficult.  I must still make play and wait for a better opening.  It\nhad seemed simple enough at a distance.  Oh, my Irish wits, could they\nnot help me now, when I needed help so sorely?  He transfixed me with\ntwo sharp, steely eyes.  \"Come, come!\" he rumbled.\n\n\"I am, of course, a mere student,\" said I, with a fatuous smile,\n\"hardly more, I might say, than an earnest inquirer.  At the same time,\nit seemed to me that you were a little severe upon Weissmann in this\nmatter.  Has not the general evidence since that date tended to--well,\nto strengthen his position?\"\n\n\"What evidence?\"  He spoke with a menacing calm.\n\n\"Well, of course, I am aware that there is not any what you might call\nDEFINITE evidence.  I alluded merely to the trend of modern thought and\nthe general scientific point of view, if I might so express it.\"\n\nHe leaned forward with great earnestness.\n\n\"I suppose you are aware,\" said he, checking off points upon his\nfingers, \"that the cranial index is a constant factor?\"\n\n\"Naturally,\" said I.\n\n\"And that telegony is still sub judice?\"\n\n\"Undoubtedly.\"\n\n\"And that the germ plasm is different from the parthenogenetic egg?\"\n\n\"Why, surely!\" I cried, and gloried in my own audacity.\n\n\"But what does that prove?\" he asked, in a gentle, persuasive voice.\n\n\"Ah, what indeed?\" I murmured.  \"What does it prove?\"\n\n\"Shall I tell you?\" he cooed.\n\n\"Pray do.\"\n\n\"It proves,\" he roared, with a sudden blast of fury, \"that you are the\ndamnedest imposter in London--a vile, crawling journalist, who has no\nmore science than he has decency in his composition!\"\n\nHe had sprung to his feet with a mad rage in his eyes.  Even at that\nmoment of tension I found time for amazement at the discovery that he\nwas quite a short man, his head not higher than my shoulder--a stunted\nHercules whose tremendous vitality had all run to depth, breadth, and\nbrain.\n\n\"Gibberish!\" he cried, leaning forward, with his fingers on the table\nand his face projecting.  \"That's what I have been talking to you,\nsir--scientific gibberish!  Did you think you could match cunning with\nme--you with your walnut of a brain?  You think you are omnipotent, you\ninfernal scribblers, don't you?  That your praise can make a man and\nyour blame can break him?  We must all bow to you, and try to get a\nfavorable word, must we?  This man shall have a leg up, and this man\nshall have a dressing down!  Creeping vermin, I know you!  You've got\nout of your station.  Time was when your ears were clipped.  You've\nlost your sense of proportion.  Swollen gas-bags!  I'll keep you in\nyour proper place.  Yes, sir, you haven't got over G. E. C.  There's\none man who is still your master.  He warned you off, but if you WILL\ncome, by the Lord you do it at your own risk.  Forfeit, my good Mr.\nMalone, I claim forfeit!  You have played a rather dangerous game, and\nit strikes me that you have lost it.\"\n\n\"Look here, sir,\" said I, backing to the door and opening it; \"you can\nbe as abusive as you like.  But there is a limit.  You shall not\nassault me.\"\n\n\"Shall I not?\"  He was slowly advancing in a peculiarly menacing way,\nbut he stopped now and put his big hands into the side-pockets of a\nrather boyish short jacket which he wore.  \"I have thrown several of\nyou out of the house.  You will be the fourth or fifth.  Three pound\nfifteen each--that is how it averaged.  Expensive, but very necessary.\nNow, sir, why should you not follow your brethren?  I rather think you\nmust.\"  He resumed his unpleasant and stealthy advance, pointing his\ntoes as he walked, like a dancing master.\n\nI could have bolted for the hall door, but it would have been too\nignominious.  Besides, a little glow of righteous anger was springing\nup within me.  I had been hopelessly in the wrong before, but this\nman's menaces were putting me in the right.\n\n\"I'll trouble you to keep your hands off, sir.  I'll not stand it.\"\n\n\"Dear me!\"  His black moustache lifted and a white fang twinkled in a\nsneer.  \"You won't stand it, eh?\"\n\n\"Don't be such a fool, Professor!\" I cried.  \"What can you hope for?\nI'm fifteen stone, as hard as nails, and play center three-quarter\nevery Saturday for the London Irish.  I'm not the man----\"\n\nIt was at that moment that he rushed me.  It was lucky that I had\nopened the door, or we should have gone through it.  We did a\nCatharine-wheel together down the passage.  Somehow we gathered up a\nchair upon our way, and bounded on with it towards the street.  My\nmouth was full of  his beard, our arms were locked, our bodies\nintertwined, and that infernal chair radiated its legs all round us.\nThe watchful Austin had thrown open the hall door.  We went with a back\nsomersault down the front steps.  I have seen the two Macs attempt\nsomething of the kind at the halls, but it appears to take some\npractise to do it without hurting oneself.  The chair went to matchwood\nat the bottom, and we rolled apart into the gutter.  He sprang to his\nfeet, waving his fists and wheezing like an asthmatic.\n\n\"Had enough?\" he panted.\n\n\"You infernal bully!\" I cried, as I gathered myself together.\n\nThen and there we should have tried the thing out, for he was\neffervescing with fight, but fortunately I was rescued from an odious\nsituation.  A policeman was beside us, his notebook in his hand.\n\n\"What's all this?  You ought to be ashamed\" said the policeman.  It was\nthe most rational remark which I had heard in Enmore Park.  \"Well,\" he\ninsisted, turning to me, \"what is it, then?\"\n\n\"This man attacked me,\" said I.\n\n\"Did you attack him?\" asked the policeman.\n\nThe Professor breathed hard and said nothing.\n\n\"It's not the first time, either,\" said the policeman, severely,\nshaking his head.  \"You were in trouble last month for the same thing.\nYou've blackened this young man's eye.  Do you give him in charge, sir?\"\n\nI relented.\n\n\"No,\" said I, \"I do not.\"\n\n\"What's that?\" said the policeman.\n\n\"I was to blame myself.  I intruded upon him.  He gave me fair warning.\"\n\nThe policeman snapped up his notebook.\n\n\"Don't let us have any more such goings-on,\" said he.  \"Now, then!\nMove on, there, move on!\"  This to a butcher's boy, a maid, and one or\ntwo loafers who had collected.  He clumped heavily down the street,\ndriving this little flock before him.  The Professor looked at me, and\nthere was something humorous at the back of his eyes.\n\n\"Come in!\" said he.  \"I've not done with you yet.\"\n\nThe speech had a sinister sound, but I followed him none the less into\nthe house.  The man-servant, Austin, like a wooden image, closed the\ndoor behind us.\n"
  },
  {
    "path": "core-tools/tests-regression/word-properties/out.ok",
    "content": "Anthropology\t\tc: nthr\t\nFollowing\tp: ol-lo\t\t\nFrenchman\t\tc: nchm\t\nGazette\tp: et-te\t\t\nHTML\t\tc: HTML\t\nMORROW\tp: OR-RO\t\t\nPalaeontological\t\t\tl: 16\namplification\t\t\tl: 13\nassault\tp: as-sa\t\t\nassaults\tp: as-sa\t\t\nasthmatic\t\tc: sthm\t\nattack\tp: at-ta\t\t\nattacked\tp: at-ta\t\t\nbacteriologist\t\t\tl: 14\nbetter\tp: et-te\t\t\nbottom\tp: ot-to\t\t\nconversaziones\t\t\tl: 14\ncorrespondence\t\t\tl: 14\ndeed\tp: de-ed\t\t\ndeeds\tp: de-ed\t\t\ndemonstrate\t\tc: nstr\t\ndetermination\t\t\tl: 13\ndifficult\tp: if-fi\t\t\ndifficulty\tp: if-fi\t\t\ndiscreditable\t\t\tl: 13\neffervescence\tp: ef-fe\t\tl: 13\neffervescing\tp: ef-fe\t\t\nexcellent\tp: el-le\t\t\nextraordinary\t\t\tl: 13\nfallacy\tp: al-la\t\t\nfollow\tp: ol-lo\t\t\nfollowed\tp: ol-lo\t\t\nfollows\tp: ol-lo\t\t\nfriendship\t\tc: ndsh\t\nglorification\t\t\tl: 13\ngrinning\tp: in-ni\t\t\nhandwriting\t\tc: ndwr\t\nindeed\tp: de-ed\t\t\ninexpressibly\t\t\tl: 13\ninsignificant\t\t\tl: 13\ninstincts\t\tc: ncts\t\ninternational\t\t\tl: 13\nlength\t\tc: ngth\t\nletter\tp: et-te\t\t\nmatchwood\t\tc: tchw\t\nmission\tp: is-si\t\t\nmorrow\tp: or-ro\t\t\nnarrative\tp: ar-ra\t\t\nparthenogenetic\t\t\tl: 15\npassage\tp: as-sa\t\t\npermission\tp: is-si\t\t\npossessed\tp: es-se\t\t\npressed\tp: es-se\t\t\nrecriminations\t\t\tl: 14\nrepresentative\t\t\tl: 14\nsimultaneously\t\t\tl: 14\nsportsman\t\tc: rtsm\t\nstepped\tp: ep-pe\t\t\nstrength\t\tc: ngth\t\nstrengthen\t\tc: ngth\t\nstrengthens\t\tc: ngth\t\nsuppressed\tp: es-se\t\t\nteetotal\tp: te-et\t\t\nthoughtfully\t\tc: ghtf\t\nthoughts\t\tc: ghts\t\nunderstanding\t\t\tl: 13\nunscrupulous\t\tc: nscr\t\nunshrinking\t\tc: nshr\t\nwatchful\t\tc: tchf\t\nwithdrawn\t\tc: thdr\t\n"
  },
  {
    "path": "eval/.gitignore",
    "content": "*.class\naccess-small.log\naccess.log\nbooks.txt\nbooks1.txt\ncharacter.txt\nemptydir\nemptygit\nhier\nlinux.new\nlinux.old\nlinux\nout\ntime\n"
  },
  {
    "path": "eval/Makefile",
    "content": "include ../.config\n\nall: data WebStats.class TextProperties.class\n\tsh perf-eval.sh\n\ndata: books.txt linux access.log linux.new linux.old emptydir access-small.log\n\n# To ensure repeatability use specific hash for an old and a new Linux commit\nLOLD=1da177e4c3f41524e886b7f1b8a0c1fc7321cac2\nLNEW=899552d6e84babd24611fd36ac7051068cb1eb2d\nELOLD:=$(LOLD)\nexport ELOLD\nELNEW:=$(LNEW)\nexport ELNEW\n\n# History of the United States by Charles A. Beard and Mary Ritter Beard\n# The Adventures of Sherlock Holmes by Arthur Conan Doyle\n# Les Misérables by Victor Hugo\nbooks1.txt:\n\tcurl http://www.gutenberg.org/files/16960/16960.txt \\\n\thttp://www.gutenberg.org/files/1661/1661.txt \\\n\thttp://www.gutenberg.org/files/135/135.txt >books1.txt\n\nbooks.txt: books1.txt\n\tfor i in `seq 1 10` ; do cat $? ; done >$@\n\naccess.log:\n\tcurl ftp://ita.ee.lbl.gov/traces/clarknet_access_log_Aug28.gz |\\\n\tgzip -dc >$@\n\naccess-small.log: access.log\n\thead -10 $? >$@\n\nlinux:\n\tgit clone https://github.com/torvalds/linux.git\n\nlinux.new: linux\n\t(cd linux && git checkout $(LNEW))\n\tmkdir $@\n\ttar -C linux --exclude .git -cf - . | tar -C $@ -xf -\n\t(cd linux && git checkout master)\n\ttouch $@\n\nlinux.old: linux\n\t(cd linux && git checkout $(LOLD))\n\tmkdir $@\n\ttar -C linux --exclude .git -cf - . | tar -C $@ -xf -\n\t(cd linux && git checkout master)\n\ttouch $@\n\nemptydir: linux\n\tmkdir $@\n\tcp linux/kernel/up.c $@/\n\nemptygit:\n\tmkdir $@\n\tcd $@ ; git init ; echo hello >hello ; git add hello ; git commit -am 'Add hello'\n\nWebStats.class: WebStats.java\n\tjavac $?\n\nTextProperties.class: TextProperties.java\n\tjavac $?\n\nclean:\n\trm -rf `cat .gitignore`\n"
  },
  {
    "path": "eval/README.md",
    "content": "The evaluation method for the classic shell performance is based\non an earlier version of *dgsh*, *sgsh*,\nwhich can translate its input into plain shell scripts.\nTo measure the classic shell performance, checkout a release containing *sgsh*,\nsuch as `46b1aec`, run `make`, and then run the baseline measurements.\n"
  },
  {
    "path": "eval/SConstruct",
    "content": "# ft2d example souped up to compare with dgsh\n\nfrom rsf.proj import *\n\nFlow('pulse',None,\n     '''\n     spike n1=10000 n2=10000 d1=1 d2=1 nsp=2 k1=16,17 k2=5,5 mag=16,16\n     label1='time' label2='space' unit1= unit2= |\n     smooth rect2=2 | smooth rect2=2\n     ''')\nPlot('pulse','grey pclip=100 wanttitle=n')\n\nFlow('ft2d','pulse','fft1 | fft3 axis=2 pad=1 | real')\nFlow('ft2d2','ft2d','window f1=1 | reverse which=3 | cat axis=1 $SOURCE')\nPlot('ft2d','ft2d2',\n     'grey pclip=100 wanttitle=n label1=\"1/time\" label2=\"1/space\" ')\n\nResult('ft2dofpulse','pulse ft2d','SideBySideIso',vppen='yscale=1.25')\n\nFlow('air',None,\n     '''\n     spike n1=10000 d1=1 o1=5000 nsp=4 k1=1,2,3,4 mag=1,3,3,1\n     label1='time' unit1= |\n     spray n=32 d=1 o=0 | put label2=space |\n     lmostretch delay=0 v0=-1\n     ''')\nFlow('air2','air','window f2=1 | reverse which=2 | cat axis=2 $SOURCE')\nPlot('airtx','air2','grey pclip=100 wanttitle=n')\n\nFlow('airft','air2','fft1 | fft3 sign=1')\nFlow('airft1 airftr airfti','airft',\n     '''\n     real > ${TARGETS[1]} &&\n     imag < $SOURCE > ${TARGETS[2]} &&\n     math re=${TARGETS[1]} im=${TARGETS[2]} output=\"sqrt(re*re+im*im)\"\n     ''')\nFlow('airft2','airft1','window f1=1 | reverse which=3 | cat axis=1 $SOURCE')\nPlot('airfk','airft2',\n     'grey pclip=100 wanttitle=n label1=\"1/time\" label2=\"1/space\" ')\n\nResult('airwave','airtx airfk','SideBySideIso',vppen='yscale=1.25')\n\nEnd()\n"
  },
  {
    "path": "eval/TextProperties.java",
    "content": "/*-\n *\n * Collect and print text frequency statistics from the text\n * read from the standard input.\n *\n * Copyright 2014 Diomidis Spinellis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.FileOutputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.io.PrintWriter;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.TreeSet;\n\nclass TextProperties {\n\n    /** Increment the map's member by one */\n    static void increment(Map<String, Integer> map, String member) {\n\tInteger i = map.get(member);\n\tif (i == null)\n\t    i = new Integer(1);\n\telse\n\t    i = new Integer(i.intValue() + 1);\n\tmap.put(member, i);\n    }\n\n    /** Increment in the map all n-grams in the specified word */\n    static void ngramIncrement(Map<String, Integer> map, StringBuffer word, int n) {\n\tfor (int i = 0; i <= word.length() - n; i++)\n\t    increment(map, word.substring(i, i + n));\n    }\n\n    /** Save the contents of the given map ordered by their values.  */\n    static void sortedList(Map<String, Integer> map, String fileName) {\n\t// Sort by value\n\tTreeSet <Map.Entry<String, Integer>> valueOrder\n\t    = new TreeSet<Map.Entry<String, Integer>>(new\n\t    Comparator<Map.Entry<String, Integer>>() {\n\t\tpublic int compare(Map.Entry<String, Integer> a,\n\t\t\tMap.Entry<String, Integer> b) {\n\t\t    int c = -a.getValue().compareTo(b.getValue());\n\t\t    if (c != 0)\n\t\t\treturn (c);\n\t\t    else\n\t\t\treturn -a.getKey().compareTo(b.getKey());\n\t\t}\n\t    }\n\t);\n\tvalueOrder.addAll(map.entrySet());\n\n\ttry {\n\t    PrintWriter out = new PrintWriter(new BufferedWriter(new\n\t\t\tOutputStreamWriter(new FileOutputStream(fileName))));\n\n\t    // Print entries\n\t    for (Map.Entry e : valueOrder)\n\t\tout.println(e.getValue() + \" \" + e.getKey());\n\t    out.close();\n\t} catch (Exception e) {\n\t    System.err.println(\"Error writing to file: \" + e);\n\t    System.exit(1);\n\t}\n    }\n\n    public static void main(String args[]) {\n\t// Data structures for gathering the results\n\tHashMap<String, Integer> countCharacter = new HashMap<String, Integer>();\n\tHashMap<String, Integer> countDigram = new HashMap<String, Integer>();\n\tHashMap<String, Integer> countTrigram = new HashMap<String, Integer>();\n\tHashMap<String, Integer> countWord = new HashMap<String, Integer>();\n\n\tBufferedReader in = new BufferedReader(new InputStreamReader(System.in));\n\n\ttry {\n\t    int c;\n\t    StringBuffer word = new StringBuffer();\n\n\t    while ((c = System.in.read()) != -1) {\n\t\tif (Character.isLetter(c))\n\t\t    word.append((char)c);\n\t\telse {\n\t\t    if (word.length() > 0) {\n\t\t\tincrement(countWord, word.toString());\n\t\t\tngramIncrement(countCharacter, word, 1);\n\t\t\tngramIncrement(countDigram, word, 2);\n\t\t\tngramIncrement(countTrigram, word, 3);\n\t\t\tword.setLength(0);\n\t\t    }\n\t\t}\n\t    }\n\n\t} catch (Exception e) {\n\t    System.err.println(\"Error reading character: \" + e);\n\t    System.exit(1);\n\t}\n\tsortedList(countWord, \"words.txt\");\n\tsortedList(countCharacter, \"character.txt\");\n\tsortedList(countDigram, \"digram.txt\");\n\tsortedList(countTrigram, \"trigram.txt\");\n    }\n}\n"
  },
  {
    "path": "eval/WebStats.java",
    "content": "/*-\n *\n * Collect and print Web statistics from common log format data\n * read from the standard input.\n *\n * Copyright 2004-2013 Diomidis Spinellis\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.util.Calendar;\nimport java.util.Comparator;\nimport java.util.GregorianCalendar;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.TreeSet;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\nimport javax.management.openmbean.InvalidKeyException;\n\nclass WebStats {\n\n    /** Print header with an underline of the same length */\n    static void header(String s) {\n\tSystem.out.println();\n\tSystem.out.println(s);\n\tfor (int i = 0; i < s.length(); i++)\n\t    System.out.print('-');\n\tSystem.out.println();\n    }\n\n    /** Add to the map's member the specified value */\n    static void add(Map<String, Integer> map, String member, int value) {\n\tInteger i = map.get(member);\n\tif (i == null)\n\t    i = new Integer(value);\n\telse\n\t    i = new Integer(i.intValue() + value);\n\tmap.put(member, i);\n    }\n\n    /** List the contents of the given map */\n    static void list(String title, Map<String, Integer> map) {\n\theader(title);\n\tfor (Map.Entry e : map.entrySet())\n\t    System.out.println(e.getValue() + \" \" + e.getKey());\n    }\n\n    /** List the n-top contents of the given map ordered by their values.  */\n    static void sortedList(String title, Map<String, Integer> map, int n) {\n\theader(title);\n\t// Sort by value\n\tTreeSet <Map.Entry<String, Integer>> valueOrder\n\t    = new TreeSet<Map.Entry<String, Integer>>(new\n\t    Comparator<Map.Entry<String, Integer>>() {\n\t\tpublic int compare(Map.Entry<String, Integer> a,\n\t\t\tMap.Entry<String, Integer> b) {\n\t\t    int c = -a.getValue().compareTo(b.getValue());\n\t\t    if (c != 0)\n\t\t\treturn (c);\n\t\t    else\n\t\t\treturn -a.getKey().compareTo(b.getKey());\n\t\t}\n\t    }\n\t);\n\tvalueOrder.addAll(map.entrySet());\n\n\t// Print top n entries\n\tint i = 0;\n\tfor (Map.Entry e : valueOrder) {\n\t    System.out.println(e.getValue() + \" \" + e.getKey());\n\t    if (++i == n)\n\t\tbreak;\n\t}\n    }\n\n    public static void main(String args[]) {\n\n\t// Compile regular expressions\n\tPattern logLinePattern = null;\n\tPattern areaPattern = null;\n\tPattern numericIPPattern = null;\n\tPattern domainPattern = null;\n\tPattern topDomainPattern = null;\n\ttry {\n\t    // A standard log line is a line like:\n\t    // 192.168.136.16 - - [26/Jan/2004:19:45:48 +0200] \"GET /c136.html HTTP/1.1\" 200 1674\n\t    logLinePattern = Pattern.compile(\n\t    \"(?<host>[-\\\\w.]+)\\\\s+\" +\t// Host\n\t    \"([-\\\\w]+)\\\\s+\" +\t\t// Logname\n\t    \"([-\\\\w]+)\\\\s+\" +\t\t// User\n\t    \"\\\\[(?<day>\\\\d+)/\" +\t// Day of month\n\t    \"(?<month>\\\\w+)/\" +\t\t// Month\n\t    \"(?<year>\\\\d+):\" +\t\t// Year\n\t    \"(?<hour>\\\\d+):\" +\t\t// Hour\n\t    \"(?<min>\\\\d+)\" +\t\t// Minute\n\t    \"([^]]+?)\\\\]\\\\s+\" +\t\t// Rest of time\n\t    \"\\\"([-\\\\w]+)\\\\s*\" +\t\t// Request verb\n\t    \"(?<url>[^\\\\s]*)\" +\t\t// Request URL\n\t    \"([^\\\"]*?)\\\"\\\\s+\" +\t\t// Request protocol etc.\n\t    \"(\\\\d+)\\\\s+\" +\t\t// Status\n\t    \"(?<bytes>[-\\\\d]+)\"\t\t// Bytes\n\t    );\n\n\t    // The first part of a request\n\t    areaPattern = Pattern.compile(\"^/?([^/]+)\");\n\n\t    // Host names\n\t    numericIPPattern = Pattern.compile(\"\\\\.\\\\d+$\");\n\t    domainPattern = Pattern.compile(\"[^.]\\\\.(.*)\");\n\t    topDomainPattern = Pattern.compile(\".*\\\\.(.*)\");\n\t} catch (PatternSyntaxException e) {\n\t    System.err.println(\"Invalid RE syntax: \" + e);\n\t    System.exit(1);\n\t}\n\n\t// A Gregorian calendar, used for converting dates to day of week\n\tGregorianCalendar cal = new GregorianCalendar();\n\n\t// Map from month name to month value\n\tLocale english = new Locale(\"EN\");\n\tMap<String, Integer> monthValue = cal.getDisplayNames(Calendar.MONTH, Calendar.SHORT, english);\n\n\t// Data structures for gathering the results\n\tHashMap<String, Integer> hostCount = new HashMap<String, Integer>();\n\tHashMap<String, Integer> hourCount = new HashMap<String, Integer>();\n\tHashMap<String, Integer> requestCount = new HashMap<String, Integer>();\n\tHashMap<String, Integer> areaCount = new HashMap<String, Integer>();\n\tHashMap<String, Integer> transferVolume = new HashMap<String, Integer>();\n\tHashMap<String, Integer> topDomainCount = new HashMap<String, Integer>();\n\tHashMap<String, Integer> domainCount = new HashMap<String, Integer>();\n\tTreeMap<String, Integer> dateCount = new TreeMap<String, Integer>();\n\tHashMap<String, Integer> dowCount = new HashMap<String, Integer>();\n\n\tlong accessCount = 0;\n\tlong byteCount = 0;\n\tlong logByteCount = 0;\n\n\tBufferedReader in = new BufferedReader(new InputStreamReader(System.in));\n\n\ttry {\n\t    String line;\n\t    while ((line = in.readLine()) != null) {\n\n\t\tlogByteCount += line.length() + 1;\n\t\taccessCount++;\n\n\t\tMatcher logLineMatched = logLinePattern.matcher(line);\n\t\tif (!logLineMatched.matches())\n\t\t    continue;\n\n\t\tadd(hourCount, logLineMatched.group(\"hour\"), 1);\n\n\t\t// Remote host\n\t\tString host = logLineMatched.group(\"host\");\n\t\tadd(hostCount, host, 1);\n\n\t\t// Transfer bytes by remote host\n\t\ttry {\n\t\t    int bytes = Integer.parseInt(logLineMatched.group(\"bytes\"));\n\t\t    byteCount += bytes;\n\t\t    add(transferVolume, host, bytes);\n\t\t} catch (NumberFormatException e) {\n\t\t}\n\n\t\t// Remote domains and top domains\n\t\tMatcher numericIPMatched = numericIPPattern.matcher(host);\n\t\tif (!numericIPMatched.find()) {\n\t\t    Matcher topDomainMatched = topDomainPattern.matcher(host);\n\t\t    if (topDomainMatched.find())\n\t\t\tadd(topDomainCount, topDomainMatched.group(1), 1);\n\n\t\t    Matcher domainMatched = domainPattern.matcher(host);\n\t\t    if (domainMatched.find())\n\t\t\tadd(domainCount, domainMatched.group(1), 1);\n\t\t}\n\n\t\t// Request\n\t\tString url = logLineMatched.group(\"url\");\n\t\tadd(requestCount, url, 1);\n\n\t\t// Area part of the URL\n\t\tMatcher areaMatched = areaPattern.matcher(url);\n\t\tif (areaMatched.find())\n\t\t    add(areaCount, areaMatched.group(1), 1);\n\n\t\t// Date\n\t\tString date = logLineMatched.group(\"day\") + \"/\" +\n\t\t    logLineMatched.group(\"month\") + \"/\" +\n\t\t    logLineMatched.group(\"year\");\n\t\tadd(dateCount, date, 1);\n\n\t\t// Day of week\n\t\ttry {\n\t\t    Integer month = monthValue.get(logLineMatched.group(\"month\"));\n\t\t    if (month == null)\n\t\t\tthrow new InvalidKeyException();\n\t\t    int day = Integer.parseInt(logLineMatched.group(\"day\"));\n\t\t    int year = Integer.parseInt(logLineMatched.group(\"year\"));\n\t\t    cal.set(year, month, day);\n\t\t    cal.get(Calendar.DAY_OF_WEEK);\n\t\t    String dayOfWeek = cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, english);\n\t\t    add(dowCount, dayOfWeek, 1);\n\t\t} catch (NumberFormatException | InvalidKeyException e) {\n\t\t    ;\n\t\t}\n\t    }\n\t} catch (Exception e) {\n\t    System.err.println(\"Error reading line: \" + e);\n\t    System.exit(1);\n\t}\n\n\tSystem.out.println(\"\t\t\tWWW server statistics\");\n\tSystem.out.println(\"\t\t\t=====================\");\n\n\theader(\"Summary\");\n\tSystem.out.println(\"Number of accesses: \" + accessCount);\n\tSystem.out.println(\"Number of Gbytes transferred: \" + byteCount / 1024 / 1024 / 1024);\n\tSystem.out.println(\"Number of hosts: \" + hostCount.size());\n\tSystem.out.println(\"Number of domains: \" + domainCount.size());\n\tSystem.out.println(\"Number of top level domains: \" + topDomainCount.size());\n\tSystem.out.println(\"Number of different pages: \" + requestCount.size());\n\tSystem.out.println(\"Accesses per day: \" + accessCount / dateCount.size());\n\tSystem.out.println(\"Mbytes per day: \" + byteCount / dateCount.size() / 1024 / 1024);\n\tSystem.out.println(\"Mbytes log file size: \" + logByteCount / 1024 / 1024);\n\n\tsortedList(\"Top 20 Requests\", requestCount, 20);\n\tsortedList(\"Top 20 Area Requests\", areaCount, 20);\n\tsortedList(\"Top 10 Hosts\", hostCount, 10);\n\tsortedList(\"Top 10 Hosts by Transfer\", transferVolume, 10);\n\tsortedList(\"Top 10 Domains\", domainCount, 10);\n\tsortedList(\"Top 20 Top Level Domain Accesses\", topDomainCount, 20);\n\tsortedList(\"Accesses by Day of Week\", dowCount, -1);\n\tsortedList(\"Accesses by Local Hour\", hourCount, -1);\n\tlist(\"Accesses by Date\", dateCount);\n    }\n}\n"
  },
  {
    "path": "eval/eval-lib.sh",
    "content": "#!/bin/sh\n#\n# Portable time function\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Run the command with the specified description\n# logging the output and time to {out,err,time} directories\ntimerun()\n{\n\tlocal -r DESC=\"$1\"\n\tshift\n\tcase `uname` in\n\tFreeBSD|Darwin)\n\t\t/usr/bin/time -l sh -c \"$@ >out/$DESC 2>err/$DESC\" 2>time/$DESC\n\t\t;;\n\tLinux|CYGWIN*)\n\t\t/usr/bin/time -v -o time/$DESC \"$@\" >out/$DESC 2>err/$DESC\n\t\t;;\n\tesac\n}\n\n# Download the specified URL, if needed, to a file of its last component\ndownload()\n{\n\tlocal -r URL=\"$1\"\n\tFILENAME=\"`basename $URL`\"\n\tif ! [ -f \"$FILENAME\" ]\n\tthen\n\t\twget $URL 2>/dev/null ||\n\t\tcurl $URL >$FILENAME\n\tfi\n}\n\n# Output the specified URL to standard output\ndownload_stdout()\n{\n\tlocal -r URL=\"$1\"\n\tcurl $URL 2>/dev/null ||\n\twget -O - $URL\n}\n"
  },
  {
    "path": "eval/ft2d.sh",
    "content": "#!/usr/local/bin/dgsh\n#\n# Modified version of the example with the same name, to test performance\n# on larger data sets\n\nmkdir -p Fig\n\n# The SConstruct SideBySideIso \"Result\" method\nside_by_side_iso()\n{\n\tvppen size=r vpstyle=n gridnum=2,1 $*\n}\n\n# A broadened pulse and the real part of its 2D Fourier transform\nscatter |{\n\n     .| sfspike n1=10000 n2=10000 d1=1 d2=1 nsp=2 k1=16,17 k2=5,5 mag=16,16 \\\n        label1='time' label2='space' unit1= unit2= |\n        sfsmooth rect2=2 |\n\tsfsmooth rect2=2 |{\n\t\t-| sfgrey pclip=100 wanttitle=n |>/stream/pulse.vpl\n\t\t-| sffft1 | sffft3 axis=2 pad=1 | sfreal |{\n\t\t\t-| dgsh-tee -I |>/stream/ft2d\n\t\t\t-| sfwindow f1=1 |\n\t\t\t    sfreverse which=3 |\n\t\t\t    sfcat axis=1 /stream/ft2d |\n\t\t\t    sfgrey pclip=100 wanttitle=n \\\n\t\t\t     label1=\"1/time\" label2=\"1/space\" |>/stream/ft2d.vpl\n\t\t|}\n\t|}\n\n\t.| side_by_side_iso /stream/pulse.vpl /stream/ft2d.vpl \\\n\t   yscale=1.25 >Fig/ft2dofpulse.vpl |.\n\n|}\n\n# A simulated air wave and the amplitude of its 2D Fourier transform\nscatter |{\n\t.| sfspike n1=10000 d1=1 o1=5000 nsp=4 k1=1,2,3,4 mag=1,3,3,1 \\\n\t\tlabel1='time' unit1= |\n\t   sfspray n=32 d=1 o=0 |\n\t   sfput label2=space |\n\t   sflmostretch delay=0 v0=-1 |{\n\t   \t-| dgsh-tee -I |>/stream/air\n\t\t-| sfwindow f2=1 |\n\t\t   sfreverse which=2 |\n\t\t   sfcat axis=2 /stream/air |{\n\t\t   \t-| sfgrey pclip=100 wanttitle=n |>/stream/airtx.vpl\n\t\t\t-| sffft1 |\n\t\t\t   sffft3 sign=1 |{\n\t\t\t   \t-| sfreal |>/stream/airftr\n\t\t\t   \t-| sfimag |>/stream/airfti\n\t\t\t|}\n\t\t|}\n\t|}\n\n\t.| sfmath re=/stream/airftr im=/stream/airfti output=\"sqrt(re*re+im*im)\" |{\n\t\t-| dgsh-tee -I |>/stream/airft1\n\t\t-| sfwindow f1=1 |\n\t\t   sfreverse which=3 |\n\t\t   sfcat axis=1 /stream/airft1 |\n\t\t   sfgrey pclip=100 wanttitle=n label1=\"1/time\" \\\n\t\t   \tlabel2=\"1/space\" |>/stream/airfk.vpl\n\t|}\n\n\t.| side_by_side_iso /stream/airtx.vpl /stream/airfk.vpl \\\n\t   yscale=1.25 >Fig/airwave.vpl |.\n|}\n"
  },
  {
    "path": "eval/log-grow.pl",
    "content": "#!/usr/bin/perl\n#\n# Grow the size of a web server log file by a factor of N,\n# which is specified as the first argument, by repeating each\n# line N times.  The host name and the request are changed by\n# substituting them with a random pick form a list of 1000 entries.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nuse strict;\nuse warnings;\n\n# Reproducable results\nsrand(0);\n\nmy $x = $ARGV[0];\nshift;\nmy @host;\nmy @request;\n\nwhile (<>) {\n\tprint;\n\n\tmy ($host, $time, $request, $rest) = ($_ =~ m/^([^\\s]+)(\\s+[^\"]+)(\\\"[^\"]*\\\")(.*)$/);\n\t$host[int(rand() * 1000)] = $host;\n\t$request[int(rand() * 1000)] = $request;\n        for (my $i = 0; $i < $x - 1; $i++) {\n\t\tmy $hpos = int(rand() * 1000);\n\t\tmy $nhost;\n\t\t$host = $nhost if ($nhost = $host[$hpos]);\n\t\tmy $ppos = int(rand() * 1000);\n\t\tmy $nrequest;\n\t\t$request = $nrequest if ($nrequest = $request[$ppos]);\n\t\tprint $host, $time, $request, $rest, \"\\n\";\n\t}\n}\n"
  },
  {
    "path": "eval/perf-eval.sh",
    "content": "#!/bin/sh\n#\n# Benchamrk the performance of alternative implementations of the\n# provided example files\n#\n#  Copyright 2014 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nmkdir -p time out\nrm -f time/*\n\nRESULTS='*.rsf *.vpl Fig *.rsf\\@ .sconsign.dbhash hier words.txt trigram.txt digram.txt character.txt'\nPERFDIR=`pwd`\n\n# Run the specified command twice, in order to minimize caching effects\nrun_twice()\n{\n\tlocal input=$1\n\tshift\n\n\trm -rf $RESULTS\n\t\"$@\" <$input\n\trm -rf $RESULTS\n\t\"$@\" <$input\n\trm -rf $RESULTS\n}\n\nmeasure()\n{\n\tlocal flags=$1\n\tlocal script=$2\n\tlocal size=$3\n\tlocal input=$4\n\tlocal name=\"$PERFDIR/time/$script:$size:$flags\"\n\n\tshift 4\n\n\techo 1>&2 \"Running for $name\"\n\n\trun_twice $input /usr/bin/time -p -o $name $PERFDIR/../dgsh -p $PERFDIR/.. $flags \\\n\t\t$PERFDIR/../example/$script \"$@\"\n}\n\nrun_examples()\n{\n\tlocal flags=\"$1\"\n\tlocal size=$2\n\tlocal text=$3\n\tlocal old=$4\n\tlocal new=$5\n\tlocal weblog=$6\n\tlocal git=$7\n\tlocal range=$8\n\n\t( cd $git ; measure \"$flags\" commit-stats.sh $size /dev/null ) >out/commit-stats.out\n\n\tmeasure \"$flags\" spell-highlight.sh $size $text >out/spell.out\n\n\tmeasure \"$flags\" map-hierarchy.sh $size /dev/null $old $new hier\n\n\n\tmeasure \"$flags\" code-metrics.sh $size /dev/null $new >out/metrics.out\n\tmeasure \"$flags\" duplicate-files.sh $size /dev/null $new >out/dup.out\n\tmeasure \"$flags\" word-properties.sh $size $text >out/word-properties.out\n\tmeasure \"$flags\" compress-compare.sh $size $text >out/compress.out\n\tmeasure \"$flags\" web-log-report.sh $size $weblog >out/weblog.out\n\n\tmeasure \"$flags\" text-properties.sh $size $text\n}\n\n# Alternative implementations of (modified) ft2d\n/usr/bin/time -p -o time/ft2d.sh:large: ../dgsh -p `pwd`/.. ft2d.sh\n/usr/bin/time -p -o time/ft2d.sh:large:-S ../dgsh -p `pwd`/.. -S ft2d.sh\n\n# Compare with native tool\nrun_twice /dev/null /usr/bin/time -p -o time/ft2d.scons:large: scons\n\n# Alternative implementation of text statistics\nrun_twice books.txt /usr/bin/time -p -o time/TextProperties:large: java TextProperties\n\n# Alternative implementations of web log statistics\nrun_twice access.log /usr/bin/time -p -o time/WebStats:large: java WebStats >out/webstats-java.out\nrun_twice access.log /usr/bin/time -p -o time/web-log-report.pl:large: perl web-log-report.pl >out/webstats-pl.out\n\n# sh and dgsh implementations of other examples\nfor flags in '' -S\ndo\n\trun_examples \"$flags\" small /dev/null emptydir emptydir access-small.log emptygit HEAD\n\trun_examples \"$flags\" large books.txt linux.old linux.new access.log linux $ELOLD..$ELNEW\ndone\n"
  },
  {
    "path": "eval/web-log-report.pl",
    "content": "#!/usr/bin/perl\n#\n#  Copyright 1995-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nuse Time::Local;\n\n# LogFormat \"%h %l %u %t \\\"%r\\\" %s %b\n# %...h:  remote host\n# %...l:  remote logname (from identd, if supplied)\n# %...u:  remote user (from auth; may be bogus if return status (%s) is 401)\n# %...t:  time, in common log format time format\n# %...r:  first line of request\n# %...s:  status.  For requests that got internally redirected, this\n#         is status of the *original* request --- %...>s for the last.\n# %...b:  bytes sent.\n# %...{Foobar}i:  The contents of Foobar: header line(s) in the request\n#                 sent to the client.\n# %...{Foobar}o:  The contents of Foobar: header line(s) in the reply.\n#\n\n$monthcard{'Jan'} = '01';\n$monthcard{'Feb'} = '02';\n$monthcard{'Mar'} = '03';\n$monthcard{'Apr'} = '04';\n$monthcard{'May'} = '05';\n$monthcard{'Jun'} = '06';\n$monthcard{'Jul'} = '07';\n$monthcard{'Aug'} = '08';\n$monthcard{'Sep'} = '09';\n$monthcard{'Oct'} = '10';\n$monthcard{'Nov'} = '11';\n$monthcard{'Dec'} = '12';\n\n$downame{1} = 'Mon';\n$downame{2} = 'Tue';\n$downame{3} = 'Wed';\n$downame{4} = 'Thu';\n$downame{5} = 'Fri';\n$downame{6} = 'Sat';\n$downame{0} = 'Sun';\n\nwhile (<>) {\n\t$logbytecount += length($_);\n\tchop;\n\tif (!(\n# ifweb.dimi.uniud.it - - [11/Mar/2002:22:31:30 +0200] \"GET /pubs/conf/1999-ESREL-SoftRel/html/chal.html HTTP/1.1\" 404 322\n\t\t($host,\n\t\t$logname, $user,\n\t\t$day, $month, $year,\n\t\t$hour, $minute,\n\t\t$verb, $url,\n\t\t$status, $bytes) = /\n\t\t([-\\w.]+)\\s+\t(?# Host)\n\t\t([-\\w]+)\\s+\t(?# Logname)\n\t\t([-\\w]+)\\s+\t(?# User)\n\t\t\\[(\\d+)\\/\t(?# Date)\n\t\t(\\w+)\\/\t\t(?# Month)\n\t\t(\\d+)\\:\t\t(?# Year)\n\t\t(\\d+)\\:\t\t(?# Hour)\n\t\t(\\d+)\t\t(?# Minute)\n\t\t[^]]+?\\]\\s+\t(?# Rest of time)\n\t\t\\\"([-\\w]+)\\s*\t(?# Request verb)\n\t\t([^\\s]*)\t(?# Request URL)\n\t\t[^\"]*?\\\"\\s+\t(?# Request protocol etc.)\n\t\t(\\d+)\\s+\t(?# Status)\n\t\t([-\\d]+)\t(?# Bytes)\n\t\t/x)) {\n\t\t\tprint STDERR \"$ARGV($.): Unable to process: $_\\n\";\n\t\t\tnext;\n\t}\n\n\tif ($host !~ m/\\.\\d+$/) {\n\t\t($topdomain) = ($host =~ m/.*\\.(.*)/);\n\t\t$topdomaincount{$topdomain}++;\n\t\t($domain) = ($host =~ m/[^.]\\.(.*)/);\n\t\t$domaincount{$domain}++;\n\t}\n\n\t($area) = ($url =~ m/^\\/?([^\\/]+)/);\n\t$area = '/' if ($area eq '');\n\n\t$month = $monthcard{$month};\n\t$date = $year . '-' . $month . '-' . $day;\n\n\t$accesscount++;\n\t$hostcount{$host}++;\n\t$urlcount{$url}++;\n\t$datecount{$date}++;\n\t$ltime = timelocal(0, 0, 0, $day, $month - 1, $year - 1900);\n\t$daynum = (localtime $ltime)[6];\n\t$dowcount{$daynum}++;\n\t$hourcount{$hour}++;\n\t$areacount{$area}++;\n\t$bytecount += $bytes;\n\t$hostbytecount{$host} += $bytes;\n\n}\n\nprint \"\n\t\t\tWWW server statistics\n\t\t\t=====================\n\nSummary\n-------\n\";\nprintf(\"Number of accesses: %d\\n\", $accesscount);\nprintf(\"Number of Gbytes transferred: %d\\n\", $bytecount / 1024 / 1024 / 1024);\nprintf(\"Number of hosts: %d\\n\", ($hostcount = grep 1, values %hostcount));\nprintf(\"Number of domains: %d\\n\", ($domaincount = grep 1, values %domaincount));\nprintf(\"Number of top level domains: %d\\n\", ($topdomaincount = grep 1, values %topdomaincount));\nprintf(\"Number of different pages: %d\\n\", ($urlcount = grep 1, keys %urlcount));\nprintf(\"Accesses per day: %d\\n\", $accesscount / ($datecount = grep 1, values %datecount));\nprintf(\"Mbytes per day: %d\\n\", $bytecount / $datecount / 1024 / 1024);\nprintf(\"Mbytes log file size: %d\\n\", $logbytecount / 1024 / 1024);\n\n\nprint '\nTop 20 Requests\n---------------\n';\n$count = 0;\nforeach (sort {$urlcount{$b} <=> $urlcount{$a}} keys %urlcount) {\n\tlast if ($count++ == 20);\n\tprintf(\"%10d %s\\n\", $urlcount{$_}, $_);\n}\n\nprint '\nTop 20 Area Requests\n---------------\n';\n$count = 0;\nforeach (sort {$areacount{$b} <=> $areacount{$a}} keys %areacount) {\n\tlast if ($count++ == 20);\n\tprintf(\"%10d %s\\n\", $areacount{$_}, $_);\n}\n\nprint '\nTop 10 Hosts\n------------\n';\n$count = 0;\nforeach (sort {$hostcount{$b} <=> $hostcount{$a}} keys %hostcount) {\n\tlast if ($count++ == 10);\n\tprintf(\"%10d %s\\n\", $hostcount{$_}, $_);\n}\n\n\nprint '\nTop 10 Hosts by Transfer\n------------------------\n';\n$count = 0;\nforeach (sort {$hostbytecount{$b} <=> $hostbytecount{$a}} keys %hostbytecount) {\n\tlast if ($count++ == 10);\n\tprintf(\"%10d %s\\n\", $hostbytecount{$_}, $_);\n}\n\n\nprint '\nTop 10 Domains\n--------------\n';\n$count = 0;\nforeach (sort {$domaincount{$b} <=> $domaincount{$a}} keys %domaincount) {\n\tlast if ($count++ == 10);\n\tprintf(\"%10d %s\\n\", $domaincount{$_}, $_);\n}\n\nprint '\nTop 20 Level Domain Accesses\n-------------------------\n';\n$count = 0;\nforeach (sort {$topdomaincount{$b} <=> $topdomaincount{$a}} keys %topdomaincount) {\n\tprintf(\"%10d %s\\n\", $topdomaincount{$_}, $_);\n\tlast if ($count++ == 20);\n}\n\nprint '\nAccesses by Day of Week\n-----------------------\n';\nforeach (sort {$dowcount{$b} <=> $dowcount{$a}} keys %dowcount) {\n\tprintf(\"%10d %s\\n\", $dowcount{$_}, $downame{$_});\n}\n\nprint '\nAccesses by Local Hour\n----------------------\n';\nforeach (sort keys %hourcount) {\n\tprintf(\"%10d %s\\n\", $hourcount{$_}, $_);\n}\n\nprint '\nAccesses by Date\n----------------\n';\nforeach (sort keys %datecount) {\n\tprintf(\"%10d %s\\n\", $datecount{$_}, $_);\n}\n"
  },
  {
    "path": "eval/webeval.sh",
    "content": "#!/bin/sh\n#\n# Run performance evaluations\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n. 'eval-lib.sh'\n\n# See http://ita.ee.lbl.gov/html/contrib/ClarkNet-HTTP.html\ndownload ftp://ita.ee.lbl.gov/traces/clarknet_access_log_Aug28.gz\ndownload ftp://ita.ee.lbl.gov/traces/clarknet_access_log_Sep4.gz\n\n# Compile Java code if needed\nif [ ! -r WebStats.class -o WebStats.java -nt WebStats.java ]\nthen\n\tif ! javac WebStats.java\n\tthen\n\t\techo \"Unable to compile WebStats.java\" 1>&2\n\t\texit 1\n\tfi\nfi\n\n# Set machine type\nif ! [ -d /opt/aws ] ||\n   ! IID=`curl -s http://169.254.169.254/2011-01-01/meta-data/instance-id` ||\n   ! TYPE=`ec2-describe-instance-attribute $IID --instance-type | awk '{print $3}'`\nthen\n\tTYPE=`hostname`\nfi\n\nmkdir -p time out err\n\n# Log grow factor\nGROW=1\nwhile :\ndo\n\tfor PROG in dgsh perl java\n\tdo\n\t\tDESC=web-$TYPE-$PROG-$GROW\n\t\tif [ -r err/$DESC ]\n\t\tthen\n\t\t\tcontinue\n\t\tfi\n\t\tfor i in clarknet*.gz\n\t\tdo\n\t\t\tgzip -dc $i\n\t\tdone |\n\t\t/usr/bin/perl log-grow.pl $GROW |\n\t\tcase $PROG in\n\t\tperl)\n\t\t\ttimerun $DESC /usr/bin/perl web-log-report.pl\n\t\t\t;;\n\t\tdgsh)\n\t\t\ttimerun $DESC ../dgsh -p .. ../example/web-log-report.sh\n\t\t\t;;\n\t\tjava)\n\t\t\ttimerun $DESC java WebStats\n\t\t\t;;\n\t\tesac\n\tdone\n\tGROW=`expr $GROW \\* 2`\n\tif [ $GROW -gt 128 ]\n\tthen\n\t\tbreak\n\tfi\ndone\n"
  },
  {
    "path": "example/NMRPipe.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Nuclear magnetic resonance processing\n# DESCRIPTION\n# Nuclear magnetic resonance in-phase/anti-phase channel conversion and\n# processing in heteronuclear single quantum coherence spectroscopy.\n# Demonstrate processing of NMR data using the NMRPipe family of programs.\n#\n# See also F. Delaglio, S. Grzesiek, G. W. Vuister, G. Zhu, J. Pfeifer\n# and A. Bax: NMRPipe: a multidimensional spectral processing system based\n# on UNIX pipes. J. Biomol. NMR. 6, 277-293 (1995).\n# http://spin.niddk.nih.gov/NMRPipe/\n#\n\n# The conversion is configured for the following file:\n# http://www.bmrb.wisc.edu/ftp/pub/bmrb/timedomain/bmr6443/timedomain_data/c13-hsqc/june11-se-6426-CA.fid/fid\nvar2pipe -in $1            \\\n -xN            1280            -yN     256    \\\n -xT            640             -yT     128    \\\n -xMODE         Complex -yMODE  Complex      \\\n -xSW           8000    -ySW    6000      \\\n -xOBS          599.4489584     -yOBS   60.7485301      \\\n -xCAR          4.73    -yCAR   118.000      \\\n -xLAB          1H      -yLAB   15N      \\\n -ndim          2       -aq2D   States      \\\n-verb  |\ntee |\n{{\n  # IP/AP channel conversion\n  # See http://tech.groups.yahoo.com/group/nmrpipe/message/389\n  nmrPipe |\n  nmrPipe -fn SOL |\n  nmrPipe -fn SP -off 0.5 -end 0.98 -pow 2 -c 0.5 |\n  nmrPipe -fn ZF -auto |\n  nmrPipe -fn FT |\n  nmrPipe -fn PS -p0 177 -p1 0.0 -di |\n  nmrPipe -fn EXT -left -sw -verb |\n  nmrPipe -fn TP |\n  nmrPipe -fn COADD -cList 1 0 -time |\n  nmrPipe -fn SP -off 0.5 -end 0.98 -pow 1 -c 0.5 |\n  nmrPipe -fn ZF -auto |\n  nmrPipe -fn FT |\n  nmrPipe -fn PS -p0 0 -p1 0 -di |\n  nmrPipe -fn TP |\n  nmrPipe -fn POLY -auto -verb >A\n\n  nmrPipe |\n  nmrPipe -fn SOL |\n  nmrPipe -fn SP -off 0.5 -end 0.98 -pow 2 -c 0.5 |\n  nmrPipe -fn ZF -auto |\n  nmrPipe -fn FT |\n  nmrPipe -fn PS -p0 177 -p1 0.0 -di |\n  nmrPipe -fn EXT -left -sw -verb |\n  nmrPipe -fn TP |\n  nmrPipe -fn COADD -cList 0 1 -time |\n  nmrPipe -fn SP -off 0.5 -end 0.98 -pow 1 -c 0.5 |\n  nmrPipe -fn ZF -auto |\n  nmrPipe -fn FT |\n  nmrPipe -fn PS -p0 -90 -p1 0 -di |\n  nmrPipe -fn TP |\n  nmrPipe -fn POLY -auto -verb >B\n\n}}\n\n# We use temporary files rather than streams, because\n# addNMR mmaps its input files. The diagram displayed in the\n# example shows the notional data flow.\nif [ -z \"${DGSH_DRAW_EXIT}\" ]\nthen\n\taddNMR -in1 A -in2 B -out A+B.dgsh.ft2 -c1 1.0 -c2 1.25 -add\n\taddNMR -in1 A -in2 B -out A-B.dgsh.ft2 -c1 1.0 -c2 1.25 -sub\nfi\n"
  },
  {
    "path": "example/author-compare.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Venue author compare\n# DESCRIPTION\n# Given the specification of two publication venues, read a compressed\n# DBLP computer science bibliography from the standard input (e.g. piped\n# from curl -s http://dblp.uni-trier.de/xml/dblp.xml.gz or from a locally\n# cached copy) and output the number of papers published in each of the\n# two venues as well as the number of authors who have published only in\n# the first venue, the number who have published only in the second one,\n# and authors who have published in both.  The venues are specified through\n# the script's first two command-line arguments as a DBLP key prefix, e.g.\n# journals/acta/, conf/icse/, journals/software/, conf/iwpc/, or conf/msr/.\n# Demonstrates the use of dgsh-wrap -e to have sed(1) create two output\n# streams and the use of tee to copy a pair of streams into four ones.\n#\n#  Copyright 2017 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Extract and sort author names\nsorted_authors()\n{\n  sed -n 's/<author>\\([^<]*\\)<\\/author>/\\1/p' |\n  sort\n}\n\n# Escape a string to make it a valid sed(1) pattern\nescape()\n{\n  echo \"$1\" | sed 's/\\([/\\\\]\\)/\\\\\\1/g'\n}\n\nexport -f sorted_authors\n\nif [ ! \"$2\" -a ! \"$DGSH_DOT_DRAW\"] ; then\n  echo \"Usage: $0 key1 key2\" 1>&2\n  echo \"Example: $0 conf/icse/ journals/software/\" 1>&2\n  exit 1\nfi\n\ngzip -dc |\n# Output the two venue authors as two output streams\ndgsh-wrap -e sed -n \"\n/^<.*key=\\\"$(escape $1)/,/<title>/ w >|\n/^<.*key=\\\"$(escape $2)/,/<title>/ w >|\" |\n# 2 streams in 4 streams out: venue1, venue2, venue1, venue2\ntee |\n{{\n  {{\n    echo -n \"$1 papers: \"\n    grep -c '^<.* mdate=.* key='\n    echo -n \"$2 papers: \"\n    grep -c '^<.* mdate=.* key='\n  }}\n\n  {{\n    call sorted_authors\n    call sorted_authors\n  }} |\n  comm |\n  {{\n    echo -n \"Authors only in $1: \"\n    wc -l\n    echo -n \"Authors only in $2: \"\n    wc -l\n    echo -n 'Authors common in both venues: '\n    wc -l\n  }}\n}} |\ncat\n"
  },
  {
    "path": "example/code-metrics.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS C code metrics\n# DESCRIPTION\n# Process a directory containing C source code, and produce a summary\n# of various metrics.\n# Demonstrates nesting, commands without input.\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n{{\n\t# C and header code\n\tfind \"$@\" \\( -name \\*.c -or -name \\*.h \\) -type f -print0 |\n\ttee |\n\t{{\n\n\t\t# Average file name length\n\t\t# Convert to newline separation for counting\n\t\techo -n 'FNAMELEN: '\n\t\ttr \\\\0 \\\\n |\n\t\t# Remove path\n\t\tsed 's|^.*/||' |\n\t\t# Maintain average\n\t\tawk '{s += length($1); n++} END {\n\t\t\tif (n>0)\n\t\t\t\tprint s / n;\n\t\t\telse\n\t\t\t\tprint 0; }'\n\n\t\txargs -0 /bin/cat |\n\t\ttee |\n\t\t{{\n\t\t\t# Remove strings and comments\n\t\t\tsed 's/#/@/g;s/\\\\[\\\\\"'\\'']/@/g;s/\"[^\"]*\"/\"\"/g;'\"s/'[^']*'/''/g\" |\n\t\t\tcpp -P |\n\t\t\ttee |\n\t\t\t{{\n\t\t\t\t# Structure definitions\n\t\t\t\techo -n 'NSTRUCT: '\n\t\t\t\tegrep -c 'struct[   ]*{|struct[   ]*[a-zA-Z_][a-zA-Z0-9_]*[       ]*{'\n\t\t\t\t#}} (match preceding openings)\n\n\t\t\t\t# Type definitions\n\t\t\t\techo -n 'NTYPEDEF: '\n\t\t\t\tgrep -cw typedef\n\n\t\t\t\t# Use of void\n\t\t\t\techo -n 'NVOID: '\n\t\t\t\tgrep -cw void\n\n\t\t\t\t# Use of gets\n\t  \t\t\techo -n 'NGETS: '\n\t  \t\t\tgrep -cw gets\n\n\t\t\t\t# Average identifier length\n\t\t\t\techo -n 'IDLEN: '\n\t\t\t\ttr -cs 'A-Za-z0-9_' '\\n' |\n\t\t\t\tsort -u |\n\t\t\t\tawk '/^[A-Za-z]/ { len += length($1); n++ } END {\n\t\t\t\t\tif (n>0)\n\t\t\t\t\t\tprint len / n;\n\t\t\t\t\telse\n\t\t\t\t\t\tprint 0; }'\n\t\t\t}}\n\n\t\t\t# Lines and characters\n\t\t\techo -n 'CHLINESCHAR: '\n\t\t\twc -lc |\n\t\t\tawk '{OFS=\":\"; print $1, $2}'\n\n\t\t\t# Non-comment characters (rounded thousands)\n\t\t\t# -traditional avoids expansion of tabs\n\t\t\t# We round it to avoid failing due to minor\n\t\t\t# differences between preprocessors in regression\n\t\t\t# testing\n\t\t\techo -n 'NCCHAR: '\n\t\t\tsed 's/#/@/g' |\n\t\t\tcpp -traditional -P |\n\t\t\twc -c |\n\t\t\tawk '{OFMT = \"%.0f\"; print $1/1000}'\n\n\t\t\t# Number of comments\n\t\t\techo -n 'NCOMMENT: '\n\t\t\tegrep -c '/\\*|//'\n\n\t\t\t# Occurences of the word Copyright\n\t\t\techo -n 'NCOPYRIGHT: '\n\t\t\tgrep -ci copyright\n\t\t}}\n\t}}\n\n\t# C files\n\tfind \"$@\" -name \\*.c -type f -print0 |\n\ttee |\n\t{{\n\t\t# Convert to newline separation for counting\n\t\ttr \\\\0 \\\\n |\n\t\ttee |\n\t\t{{\n\t\t\t# Number of C files\n\t\t\techo -n 'NCFILE: '\n\t\t\twc -l\n\n\t\t\t# Number of directories containing C files\n\t\t\techo -n 'NCDIR: '\n\t\t\tsed 's,/[^/]*$,,;s,^.*/,,' |\n\t\t\tsort -u |\n\t\t\twc -l\n\t\t}}\n\n\t\t# C code\n\t\txargs -0 /bin/cat |\n\t\ttee |\n\t\t{{\n\t\t\t# Lines and characters\n\t\t\techo -n 'CLINESCHAR: '\n\t\t\twc -lc |\n\t\t\tawk '{OFS=\":\"; print $1, $2}'\n\n\t\t\t# C code without comments and strings\n\t\t\tsed 's/#/@/g;s/\\\\[\\\\\"'\\'']/@/g;s/\"[^\"]*\"/\"\"/g;'\"s/'[^']*'/''/g\" |\n\t\t\tcpp -P |\n\t\t\ttee |\n\t\t\t{{\n\t\t\t\t# Number of functions\n\t\t\t\techo -n 'NFUNCTION: '\n\t\t\t\tgrep -c '^{'\n\n\t\t\t\t# Number of gotos\n\t\t\t\techo -n 'NGOTO: '\n\t\t\t\tgrep -cw goto\n\n\t\t\t\t# Occurrences of the register keyword\n\t\t\t\techo -n 'NREGISTER: '\n\t\t\t\tgrep -cw register\n\n\t\t\t\t# Number of macro definitions\n\t\t\t\techo -n 'NMACRO: '\n\t\t\t\tgrep -c '@[   ]*define[   ][   ]*[a-zA-Z_][a-zA-Z0-9_]*('\n\t\t\t\t# Number of include directives\n\t\t\t\techo -n 'NINCLUDE: '\n\t\t\t\tgrep -c '@[   ]*include'\n\n\t\t\t\t# Number of constants\n\t\t\t\techo -n 'NCONST: '\n\t\t\t\tgrep -ohw '[0-9][x0-9][0-9a-f]*' | wc -l\n\n\t\t\t}}\n\t\t}}\n\t}}\n\n\t# Header files\n\techo -n 'NHFILE: '\n\tfind \"$@\" -name \\*.h -type f |\n\twc -l\n\n}} |\n# Gather and print the results\ncat\n"
  },
  {
    "path": "example/commit-stats.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Git commit statistics\n# DESCRIPTION\n# Process the Git history, and list the authors and days of the week\n# ordered by the number of their commits.\n# Demonstrates streams and piping through a function.\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nforder()\n{\n\tsort |\n\tuniq -c |\n\tsort -rn\n}\n\ngit log --format=\"%an:%ad\" --date=default \"$@\" |\ntee |\n{{\n\techo \"Authors ordered by number of commits\"\n\t# Order by frequency\n\tawk -F: '{print $1}' |\n\tforder\n\n\techo \"Days ordered by number of commits\"\n\t# Order by frequency\n\tawk -F: '{print substr($2, 1, 3)}' |\n\tforder\n}} |\ncat\n"
  },
  {
    "path": "example/committer-plot.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Plot Git committer activity over time\n# DESCRIPTION\n# Process the Git history, and create two PNG diagrams depicting\n# committer activity over time. The most active committers appear\n# at the center vertical of the diagram.\n# Demonstrates image processing, mixining of synchronous and\n# asynchronous processing in a scatter block, and the use of an\n# dgsh-compliant join command.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Commit history in the form of ascending Unix timestamps, emails\ngit log --pretty=tformat:'%at %ae' |\n# Filter records according to timestamp: keep (100000, now) seconds\nawk 'NF == 2& $1 > 100000& $1 < '`date +%s` |\nsort -n |\ntee |\n{{\n\t{{\n\t\t# Calculate number of committers\n\t\tawk '{print $2}' |\n\t\tsort -u |\n\t\twc -l |\n\t\ttee |\n\t\t{{\n\t\t\tdgsh-writeval -s committers1\n\n\t\t\tdgsh-writeval -s committers2\n\t\t\tdgsh-writeval -s committers3\n\t\t}}\n\n\t\t# Calculate last commit timestamp in seconds\n\t\ttail -1 |\n\t\tawk '{print $1}'\n\n\t\t# Calculate first commit timestamp in seconds\n\t\thead -1 |\n\t\tawk '{print $1}'\n\t}} |\n\t# Gather last and first commit timestamp\n\tcat |\n\t# Make one space-delimeted record\n\ttr '\\n' ' ' |\n\t# Compute the difference in days\n\tawk '{print int(($1 - $2) / 60 / 60 / 24)}' |\n\t# Store number of days\n\tdgsh-writeval -s days\n\n\tsort -k2\t# <timestamp, email>\n\n\t# Place committers left/right of the median\n\t# according to the number of their commits\n\tawk '{print $2}' |\n\tsort |\n\tuniq -c |\n\tsort -n |\n\tawk '\n\t\tBEGIN {\n\t\t\t\"dgsh-readval -l -x -q -s committers1\" | getline NCOMMITTERS\n\t\t\tl = 0; r = NCOMMITTERS;}\n\t\t{print NR % 2 ? l++ : --r, $2}' |\n\tsort -k2\t# <left/right, email>\n\n}} |\n# Join committer positions with commit time stamps\n# based on committer email\njoin -j 2 |\t\t# <email, timestamp, left/right>\n# Order by timestamp\nsort -k 2n |\ntee |\n{{\n\t# Create portable bitmap\n\techo 'P1'\n\n\t{{\n\t\tdgsh-readval -l -q -s committers2\n\t\tdgsh-readval -l -q -s days\n\t}} |\n\tcat |\n\ttr '\\n' ' ' |\n\tawk '{print $1, $2}'\n\n\tperl -na -e '\n\t  BEGIN {\n\t    open(my $ncf, \"-|\", \"dgsh-readval -l -x -q -s committers3\");\n\t    $ncommitters = <$ncf>;\n\t    @empty[$ncommitters - 1] = 0; @committers = @empty;\n\t  }\n\t  sub out {\n\t\t  print join(\"\", map($_ ? \"1\" : \"0\", @committers)), \"\\n\";\n\t  }\n\n\t  $day = int($F[1] / 60 / 60 / 24);\n\t  $pday = $day if (!defined($pday));\n\n\t  while ($day != $pday) {\n\t\t  out();\n\t\t  @committers = @empty;\n\t\t  $pday++;\n\t  }\n\n\t  $committers[$F[2]] = 1;\n\n\t  END { out(); }\n\t'\n}} |\ncat |\n# Enlarge points into discs through morphological convolution\npgmmorphconv -erode <(\ncat <<EOF\nP1\n7 7\n1 1 1 0 1 1 1\n1 1 0 0 0 1 1\n1 0 0 0 0 0 1\n0 0 0 0 0 0 0\n1 0 0 0 0 0 1\n1 1 0 0 0 1 1\n1 1 1 0 1 1 1\nEOF\n) |\ntee |\n{{\n\t# Full-scale image\n\tpnmtopng >large.png\n\t# A smaller image\n\tpamscale -width 640 |\n\tpnmtopng >small.png\n}}\n"
  },
  {
    "path": "example/compress-compare.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Compression benchmark\n# DESCRIPTION\n# Report file type, length, and compression performance for\n# data received from the standard input.  The data never touches the\n# disk.\n# Demonstrates the use of an output multipipe to source many commands\n# from one followed by an input multipipe to sink to one command\n# the output of many and the use of dgsh-tee that is used both to\n# propagate the same input to many commands and collect output from\n# many commands orderly in a way that is transparent to users.\n#\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http:/www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\ntee |\n{{\n\tprintf 'File type:\\t'\n\tfile -\n\n\tprintf 'Original size:\\t'\n\twc -c\n\n\tprintf 'xz:\\t\\t'\n\txz -c | wc -c\n\n\tprintf 'bzip2:\\t\\t'\n\tbzip2 -c | wc -c\n\n\tprintf 'gzip:\\t\\t'\n\tgzip -c | wc -c\n}} |\ncat\n"
  },
  {
    "path": "example/dir.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Directory listing\n# DESCRIPTION\n# Windows-like DIR command for the current directory.\n# Nothing that couldn't be done with <code>ls -l | awk</code>.\n# Demonstrates use of wrapped commands with no input (df, echo).\n#\n#  Copyright 2012-2017 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nls -n |\ntee |\n{{\n\t# Reorder fields in DIR-like way\n\tawk '!/^total/ {print $6, $7, $8, $1, sprintf(\"%8d\", $5), $9}'\n\n\t# Count number of files\n\twc -l | tr -d \\\\n\n\n\t# Print label for number of files\n\techo -n ' File(s) '\n\n\t# Tally number of bytes\n\tawk '{s += $5} END {printf(\"%d bytes\\n\", s)}'\n\n\t# Count number of directories\n\tgrep -c '^d' | tr -d \\\\n\n\n\t# Print label for number of dirs and calculate free bytes\n\tdf -h . | awk '!/Use%/{print \" Dir(s) \" $4 \" bytes free\"}'\n}} |\ncat\n"
  },
  {
    "path": "example/duplicate-files.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Find duplicate files\n# DESCRIPTION\n# List the names of duplicate files in the specified directory.\n# Demonstrates the combination of streams with a relational join.\n#\n#  Copyright 2012-2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Create list of files\nfind \"$@\" -type f |\n\n# Produce lines of the form\n# MD5(filename)= 811bfd4b5974f39e986ddc037e1899e7\nxargs openssl md5 |\n\n# Convert each line into a \"filename md5sum\" pair\nsed 's/^MD5(//;s/)= / /' |\n\n# Sort by MD5 sum\nsort -k2 |\n\ntee |\n{{\n\n\t# Print an MD5 sum for each file that appears more than once\n\tawk '{print $2}' | uniq -d\n\n\t# Promote the stream to gather it\n\tcat\n}} |\n# Join the repeated MD5 sums with the corresponding file names\n# Join expects two inputs, second will come from scatter\n# XXX make streaming input identifiers transparent to users\njoin -2 2 |\n\n# Output same files on a single line\nawk '\nBEGIN {ORS=\"\"}\n$1 != prev && prev {print \"\\n\"}\nEND {if (prev) print \"\\n\"}\n{if (prev) print \" \"; prev = $1; print $2}'\n"
  },
  {
    "path": "example/fft-block8.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS FFT calculation\n# DESCRIPTION\n# Calculate the iterative FFT for n = 8 in parallel.\n# Demonstrates combined use of permute and multipipe blocks.\n#\n#  Copyright 2016 Marios Fragkoulis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\ndgsh-fft-input $1 |\nperm 1,5,3,7,2,6,4,8 |\n{{\n\t{{\n\t\tdgsh-w 1 0\n\t\tdgsh-w 1 0\n\t}} |\n\tperm 1,3,2,4 |\n\t{{\n\t\tdgsh-w 2 0\n\t\tdgsh-w 2 1\n\t}}\n\n\t{{\n\t\tdgsh-w 1 0\n\t\tdgsh-w 1 0\n\t}} |\n\tperm 1,3,2,4 |\n\t{{\n\t\tdgsh-w 2 0\n\t\tdgsh-w 2 1\n\t}}\n}} |\nperm 1,5,3,7,2,6,4,8 |\n{{\n\tdgsh-w 3 0\n\n\tdgsh-w 3 1\n\n\tdgsh-w 3 2\n\n\tdgsh-w 3 3\n}} |\nperm 1,5,2,6,3,7,4,8 |\ncat\n"
  },
  {
    "path": "example/ft2d.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Waves: 2D Fourier transforms\n# DESCRIPTION\n# Create two graphs:\n# 1) a broadened pulse and the real part of its 2D Fourier transform, and\n# 2) a simulated air wave and the amplitude of its 2D Fourier transform.\n# Demonstrates using the tools of the Madagascar shared research environment\n# for computational data analysis in geophysics and related fields.\n# Also demonstrates the use of two scatter blocks in the same script,\n# and the used of named streams.\n#\n# Adapted from: http://www.reproducibility.org/RSF/book/bei/ft1/ft2d.html\n# Description: http://www.reproducibility.org/RSF/book/bei/ft1/paper_html/node14.html\n# Madagascar project: http://www.reproducibility.org\n#\n\nmkdir -p Fig\n\n# The SConstruct SideBySideIso \"Result\" method\nside_by_side_iso()\n{\n\tvppen size=r vpstyle=n gridnum=2,1 /dev/stdin $*\n}\n\nexport -f side_by_side_iso\n\n# A broadened pulse and the real part of its 2D Fourier transform\nsfspike n1=64 n2=64 d1=1 d2=1 nsp=2 k1=16,17 k2=5,5 mag=16,16 \\\n\tlabel1='time' label2='space' unit1= unit2= |\nsfsmooth rect2=2 |\nsfsmooth rect2=2 |\ntee |\n{{\n\tsfgrey pclip=100 wanttitle=n\n\n\tsffft1 |\n\tsffft3 axis=2 pad=1 |\n\tsfreal |\n\ttee |\n\t{{\n\t\tsfwindow f1=1 | sfreverse which=3\n\t\tcat\n\t}} |\n\tsfcat axis=1 \"<|\" |\n\tsfgrey pclip=100 wanttitle=n label1=\"1/time\" label2=\"1/space\"\n}} |\ncall_with_stdin side_by_side_iso '<|' yscale=1.25 >Fig/ft2dofpulse.vpl\n\n# A simulated air wave and the amplitude of its 2D Fourier transform\nsfspike n1=64 d1=1 o1=32 nsp=4 k1=1,2,3,4 mag=1,3,3,1 \\\n\tlabel1='time' unit1= |\nsfspray n=32 d=1 o=0 |\nsfput label2=space |\nsflmostretch delay=0 v0=-1 |\ntee |\n{{\n\tsfwindow f2=1 | sfreverse which=2\n\tcat\n}} |\nsfcat axis=2 \"<|\" |\ntee |\n{{\n\tsfgrey pclip=100 wanttitle=n\n\n\tsffft1 |\n\tsffft3 sign=1 |\n\ttee |\n\t{{\n\t\tsfreal\n\t\tsfimag\n\t}} |\n\tdgsh-wrap -e sfmath nostdin=y re=\"<|\" im=\"<|\" \\\n\t  output=\"sqrt(re*re+im*im)\" |\n\ttee |\n\t{{\n\t\tsfwindow f1=1 | sfreverse which=3\n\t\tcat\n\t}} |\n\tsfcat axis=1 \"<|\" |\n\tsfgrey pclip=100 wanttitle=n label1=\"1/time\" label2=\"1/space\"\n}} |\ncall_with_stdin side_by_side_iso '<|' yscale=1.25 >Fig/airwave.vpl\n\nwait\n"
  },
  {
    "path": "example/map-hierarchy.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Hierarchy map\n# DESCRIPTION\n# Given two directory hierarchies A and B passed as input arguments\n# (where these represent a project at different parts of its lifetime)\n# copy the files of hierarchy A to a new directory, passed as a third\n# argument, corresponding to the structure of directories in B.\n# Demonstrates the use of <em>join</em> to process results from two\n# inputs and the use of <em>gather</em> to order asynchronously\n# produced results.\n#\n#  Copyright 2012-2014 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -z \"${DGSH_DRAW_EXIT}\" -a \\( ! -d \"$1\" -o ! -d \"$2\" -o -z \"$3\" \\) ]\nthen\n  echo \"Usage: $0 dir-1 dir-2 new-dir-name\" 1>&2\n  exit 1\nfi\n\nNEWDIR=\"$3\"\n\nexport LC_ALL=C\n\nline_signatures()\n{\n  find $1 -type f -name '*.[chly]' -print |\n  # Split path name into directory and file\n  sed 's|\\(.*\\)/\\([^/]*\\)|\\1 \\2|' |\n  while read dir file\n  do\n    # Print \"directory filename content\" of lines with\n    # at least one alphabetic character\n    # The fields are separated by \u0002 and \u0003\n    sed -n \"/[a-z]/s|^|$dir\u0002$file\u0003|p\" \"$dir/$file\"\n  done |\n  # Error: multi-character tab '\\001\\001'\n  sort -T `pwd` -t\u0002 -k 2\n}\n\n\nexport -f line_signatures\n\n\n{{\n  # Generate the signatures for the two hierarchies\n  call 'line_signatures \"$1\"' -- \"$1\"\n  call 'line_signatures \"$1\"' -- \"$2\"\n}} |\n\n# Join signatures on file name and content\njoin -t\u0002 -1 2 -2 2 |\n\n# Print filename dir1 dir2\nsed 's/\u0003/\u0002/g' |\nawk -F\u0002 'BEGIN{OFS=\" \"}{print $1, $3, $4}' |\n\n# Unique occurrences\nsort -u |\ntee |\n{{\n  # Commands to copy\n  awk '{print \"mkdir -p '$NEWDIR'/\" $3 \"\"}' |\n  sort -u\n\n  awk '{print \"cp \" $2 \"/\" $1 \" '$NEWDIR'/\" $3 \"/\" $1 \"\"}'\n}} |\n# Order: first make directories, then copy files\n# TODO: dgsh-tee does not pass along first incoming stream\ncat |\nsh\n"
  },
  {
    "path": "example/parallel-word-count.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Parallel word count\n# DESCRIPTION\n# Count number of times each word appears in the specified input file(s)\n# Demonstrates parallel execution mirroring the Hadoop WordCount example\n# via the dgsh-parallel command.\n# In contrast to GNU parallel, the block generated by dgsh-parallel\n# has N input and output streams, which can be combined by any\n# dgsh-compatible tool, such as dgsh-merge-sum or sort -m.\n#\n#  Copyright 2014-2016 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Number of processes\nN=8\n\n# Collation order for sorting\nexport LC_ALL=C\n\n# Scatter input\ndgsh-tee -s |\n# Emulate Java's default StringTokenizer, sort, count\ndgsh-parallel -n $N \"tr -s ' \\t\\n\\r\\f' '\\n' | sort -S 512M | uniq -c\" |\n# Merge sorted counts by providing N input channels\ndgsh-merge-sum $(for i in $(seq $N) ; do printf '<| ' ; done)\n"
  },
  {
    "path": "example/reorder-columns.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Reorder columns\n# DESCRIPTION\n# Reorder columns in a CSV document.\n# Demonstrates the combined use of tee, cut, and paste.\n#\n#  Copyright 2016 Marios Fragkoulis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\ntee |\n{{\n\tcut -d , -f 5-6 -\n\n\tcut -d , -f 2-4 -\n}} |\npaste -d ,\n"
  },
  {
    "path": "example/spell-highlight.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Highlight misspelled words\n# DESCRIPTION\n# Highlight the words that are misspelled in the command's first\n# argument.\n# Demonstrates stream processing with multipipes and\n# the avoidance of pass-through constructs to avoid deadlocks.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nexport LC_ALL=C\n\ntee |\n{{\n\t# Find errors\n\t{{\n\t\t# Obtain list of words in text\n\t\ttr -cs A-Za-z \\\\n |\n\t\ttr A-Z a-z |\n\t\tsort -u\n\n\t\t# Ensure dictionary is compatibly sorted\n\t\tsort /usr/share/dict/words\n\t}} |\n\t# List errors as a set difference\n\tcomm -23\n\n\t# Pass through text\n\tcat\n}} |\ngrep --fixed-strings --file=- --ignore-case --color --word-regex --context=2\n"
  },
  {
    "path": "example/static-functions.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS C/C++ symbols that should be static\n# DESCRIPTION\n# Given as an argument a directory containing object files, show which\n# symbols are declared with global visibility, but should have been\n# declared with file-local (static) visibility instead.\n# Demonstrates the use of dgsh-capable comm (1) to combine data from\n# two sources.\n#\n#  Copyright 2014 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Find object files\nfind \"$1\" -name \\*.o |\n\n# Print defined symbols\nxargs nm |\n\ntee |\n{{\n\n  # List all defined (exported) symbols\n  awk 'NF == 3 && $2 ~ /[A-Z]/ {print $3}' | sort\n\n  # List all undefined (imported) symbols\n  awk '$1 == \"U\" {print $2}' | sort\n\n}} |\n# Print exports that are not imported\ncomm -23\n"
  },
  {
    "path": "example/text-properties.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Text properties\n# DESCRIPTION\n# Read text from the standard input and create files\n# containing word, character, digram, and trigram frequencies.\n#\n# Demonstrates the use of scatter blocks without output and the use\n# of stores within the scatter block.\n#\n# Example:\n# curl ftp://sunsite.informatik.rwth-aachen.de/pub/mirror/ibiblio/gutenberg/1/3/139/139.txt | text-properties\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Consistent sorting across machines\nexport LC_ALL=C\n\n\n# Convert input into a ranked frequency list\nranked_frequency()\n{\n\tawk '{count[$1]++} END {for (i in count) print count[i], i}' |\n\t# We want the standard sort here\n\tsort -rn\n}\n\n# Convert standard input to a ranked frequency list of specified n-grams\nngram()\n{\n\tlocal N=$1\n\n\tperl -ne 'for ($i = 0; $i < length($_) - '$N'; $i++) {\n\t\tprint substr($_, $i, '$N'), \"\\n\";\n\t}' |\n\tranked_frequency\n}\n\nexport -f ranked_frequency\nexport -f ngram\n\ntee |\n{{\n\t# Split input one word per line\n\ttr -cs a-zA-Z \\\\n |\n\ttee |\n\t{{\n\t\t# Digram frequency\n\t\tcall 'ngram 2 >digram.txt'\n\t\t# Trigram frequency\n\t\tcall 'ngram 3 >trigram.txt'\n\t\t# Word frequency\n\t\tcall 'ranked_frequency >words.txt'\n\t}}\n\n\t# Store number of characters to use in awk below\n\twc -c |\n\tdgsh-writeval -s nchars\n\n\t# Character frequency\n\tsed 's/./&\\\n/g' |\n\t# Print absolute\n\tcall 'ranked_frequency' |\n\tawk 'BEGIN {\n\t\t\"dgsh-readval -l -x -q -s nchars\" | getline NCHARS\n\t\tOFMT = \"%.2g%%\"}\n\t\t{print $1, $2, $1 / NCHARS * 100}' > character.txt\n}}\n"
  },
  {
    "path": "example/uniform-5x5.sh",
    "content": "#!/usr/bin/env dgsh\n\nrow()\n{\n  dgsh-parallel -n 5 'echo C{}' | paste\n}\n\nmatrix()\n{\n  dgsh-parallel -n 5 row\n}\n\nexport -f row\n\nmatrix | cat\n"
  },
  {
    "path": "example/web-log-report.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Web log reporting\n# DESCRIPTION\n# Creates a report for a fixed-size web log file read from the standard input.\n# Demonstrates the combined use of multipipe blocks, writeval and readval\n# to store and retrieve values, and functions in the scatter block.\n# Used to measure throughput increase achieved through parallelism.\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Output the top X elements of the input by the number of their occurrences\n# X is the first argument\ntoplist()\n{\n\tuniq -c | sort -rn | head -$1\n\techo\n}\n\n# Output the argument as a section header\nheader()\n{\n\techo\n\techo \"$1\"\n\techo \"$1\" | sed 's/./-/g'\n}\n\n# Consistent sorting\nexport LC_ALL=C\n\nexport -f toplist\nexport -f header\n\n\nif [ -z \"${DGSH_DRAW_EXIT}\" ]\nthen\ncat <<EOF\n\t\t\tWWW server statistics\n\t\t\t=====================\n\nSummary\n-------\nEOF\nfi\n\ntee |\n{{\n\t# Number of accesses\n\techo -n 'Number of accesses: '\n\tdgsh-readval -l -s nAccess\n\n\t# Number of transferred bytes\n\tawk '{s += $NF} END {print s}' |\n\ttee |\n\t{{\n\t\techo -n 'Number of Gbytes transferred: '\n\t\tawk '{print $1 / 1024 / 1024 / 1024}'\n\n\t\tdgsh-writeval -s nXBytes\n\t}}\n\n\techo -n 'Number of hosts: '\n\tdgsh-readval -l -q -s nHosts\n\n\techo -n 'Number of domains: '\n\tdgsh-readval -l -q -s nDomains\n\n\techo -n 'Number of top level domains: '\n\tdgsh-readval -l -q -s nTLDs\n\n\techo -n 'Number of different pages: '\n\tdgsh-readval -l -q -s nUniqPages\n\n\techo -n 'Accesses per day: '\n\tdgsh-readval -l -q -s nDayAccess\n\n\techo -n 'MBytes per day: '\n\tdgsh-readval -l -q -s nDayMB\n\n\t# Number of log file bytes\n\techo -n 'MBytes log file size: '\n\twc -c |\n\tawk '{print $1 / 1024 / 1024}'\n\n\t# Host names\n\tawk '{print $1}' |\n\ttee |\n\t{{\n\t\t# Number of accesses\n\t\twc -l | dgsh-writeval -s nAccess\n\n\t\t# Sorted hosts\n\t\tsort |\n\t\ttee |\n\t\t{{\n\n\t\t\t# Unique hosts\n\t\t\tuniq |\n\t\t\ttee |\n\t\t\t{{\n\t\t\t\t# Number of hosts\n\t\t\t\twc -l | dgsh-writeval -s nHosts\n\n\t\t\t\t# Number of TLDs\n\t\t\t\tawk -F. '$NF !~ /[0-9]/ {print $NF}' |\n\t\t\t\tsort -u |\n\t\t\t\twc -l |\n\t\t\t\tdgsh-writeval -s nTLDs\n\t\t\t}}\n\n\t\t\t# Top 10 hosts\n\t\t\t{{\n\t\t\t\t call 'header \"Top 10 Hosts\"'\n\t\t\t\t call 'toplist 10'\n\t\t\t}}\n\t\t}}\n\n\t\t# Top 20 TLDs\n\t\t{{\n\t\t\tcall 'header \"Top 20 Level Domain Accesses\"'\n\t\t\tawk -F. '$NF !~ /^[0-9]/ {print $NF}' |\n\t\t\tsort |\n\t\t\tcall 'toplist 20'\n\t\t}}\n\n\t\t# Domains\n\t\tawk -F. 'BEGIN {OFS = \".\"}\n\t\t            $NF !~ /^[0-9]/ {$1 = \"\"; print}' |\n\t\tsort |\n\t\ttee |\n\t\t{{\n\t\t\t# Number of domains\n\t\t\tuniq |\n\t\t\twc -l |\n\t\t\tdgsh-writeval -s nDomains\n\n\t\t\t# Top 10 domains\n\t\t\t{{\n\t\t\t\t call 'header \"Top 10 Domains\"'\n\t\t\t\t call 'toplist 10'\n\t\t\t}}\n\t\t}}\n\t}}\n\n\t# Hosts by volume\n\t{{\n\t\tcall 'header \"Top 10 Hosts by Transfer\"'\n\t\tawk '    {bytes[$1] += $NF}\n\t\tEND {for (h in bytes) print bytes[h], h}' |\n\t\tsort -rn |\n\t\thead -10\n\t}}\n\n\t# Sorted page name requests\n\tawk '{print $7}' |\n\tsort |\n\ttee |\n\t{{\n\n\t\t# Top 20 area requests (input is already sorted)\n\t\t{{\n\t\t\t call 'header \"Top 20 Area Requests\"'\n\t\t\t awk -F/ '{print $2}' |\n\t\t\t call 'toplist 20'\n\t\t}}\n\n\t\t# Number of different pages\n\t\tuniq |\n\t\twc -l |\n\t\tdgsh-writeval -s nUniqPages\n\n\t\t# Top 20 requests\n\t\t{{\n\t\t\t call 'header \"Top 20 Requests\"'\n\t\t\t call 'toplist 20'\n\t\t}}\n\t}}\n\n\t# Access time: dd/mmm/yyyy:hh:mm:ss\n\tawk '{print substr($4, 2)}' |\n\ttee |\n\t{{\n\n\t\t# Just dates\n\t\tawk -F: '{print $1}' |\n\t\ttee |\n\t\t{{\n\n\t\t\t# Number of days\n\t\t\tuniq |\n\t\t\twc -l |\n\t\t\ttee |\n\t\t\t{{\n\t\t\t\tawk '\n\t\t\t\t\tBEGIN {\n\t\t\t\t\t\"dgsh-readval -l -x -s nAccess\" | getline NACCESS;}\n\t\t\t\t\t{print NACCESS / $1}' |\n\t\t\t\tdgsh-writeval -s nDayAccess\n\n\t\t\t\tawk '\n\t\t\t\t\tBEGIN {\n\t\t\t\t\t\"dgsh-readval -l -x -q -s nXBytes\" | getline NXBYTES;}\n\t\t\t\t\t{print NXBYTES / $1 / 1024 / 1024}' |\n\t\t\t\tdgsh-writeval -s nDayMB\n\t\t\t}}\n\n\t\t\t{{\n\t\t\t\t call 'header \"Accesses by Date\"'\n\t\t\t\t uniq -c\n\t\t\t}}\n\n\t\t\t# Accesses by day of week\n\t\t\t{{\n\t\t\t\t call 'header \"Accesses by Day of Week\"'\n\t\t\t\t sed 's|/|-|g' |\n\t\t\t\t call '(date -f - +%a 2>/dev/null || gdate -f - +%a)' |\n\t\t\t\t sort |\n\t\t\t\t uniq -c |\n\t\t\t\t sort -rn\n\t\t\t}}\n\t\t}}\n\n\t\t# Hour\n\t\t{{\n\t\t\tcall 'header \"Accesses by Local Hour\"'\n\t\t\tawk -F: '{print $2}' |\n\t\t\tsort |\n\t\t\tuniq -c\n\t\t}}\n\t}}\n\tdgsh-readval -q -s nAccess\n}} |\ncat\n\n"
  },
  {
    "path": "example/word-properties.sh",
    "content": "#!/usr/bin/env dgsh\n#\n# SYNOPSIS Word properties\n# DESCRIPTION\n# Read text from the standard input and list words\n# containing a two-letter palindrome, words containing\n# four consonants, and words longer than 12 characters.\n#\n# Demonstrates the use of dgsh-compatible paste as a gather function\n#\n# Example:\n# curl ftp://sunsite.informatik.rwth-aachen.de/pub/mirror/ibiblio/gutenberg/1/3/139/139.txt | word-properties\n#\n#  Copyright 2013 Diomidis Spinellis\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Consistent sorting across machines\nexport LC_ALL=C\n\n# Stream input from file\ncat $1 |\n\n# Split input one word per line\ntr -cs a-zA-Z \\\\n |\n# Create list of unique words\nsort -u |\ntee |\n{{\n\t# Pass through the original words\n\tcat\n\n\t# List two-letter palindromes\n\tsed 's/.*\\(.\\)\\(.\\)\\2\\1.*/p: \\1\\2-\\2\\1/;t\n\t\tg'\n\n\t# List four consecutive consonants\n\tsed -E 's/.*([^aeiouyAEIOUY]{4}).*/c: \\1/;t\n\t\tg'\n\n\t# List length of words longer than 12 characters\n\tawk '{if (length($1) > 12) print \"l:\", length($1);\n\t\telse print \"\"}'\n}} |\n# Paste the four streams side-by-side\npaste |\n# List only words satisfying one or more properties\nfgrep :\n"
  },
  {
    "path": "png/README",
    "content": "This is the destination for auto-generated PNG files\n"
  },
  {
    "path": "simple-shell/comm_paste.dgsh",
    "content": "1 comm ../test-data/f1s ../test-data/f2s\n2 paste\n\n%\nsocketpipe 1 2\n"
  },
  {
    "path": "simple-shell/comm_paste.success",
    "content": "1\t\t3\t\t\t\n2\t\t4\t\t\t3\n6\t\t\t\t4\n\t\t\t\t5\n"
  },
  {
    "path": "simple-shell/comm_paste_join_diff.dgsh",
    "content": "1 comm ../test-data/f4ss ../test-data/f5ss\n2 dgsh-conc -o 3\n3 paste ../test-data/p1\n4 join ../test-data/j2\n5 diff ../test-data/d3\n\n%\nsocketpipe 1 2\nsocketpipe 2 3\nsocketpipe 2 4\nsocketpipe 2 5\n"
  },
  {
    "path": "simple-shell/comm_paste_join_diff.success",
    "content": "\t3\n10\t2\n2\t2\n2\t10\n3\t\n12 match\n4 match\n"
  },
  {
    "path": "simple-shell/comm_sort.dgsh",
    "content": "1 comm ../test-data/f1s ../test-data/f2s\n2 sort\n3 wc -l\n4 tr -d \" \"\n\n%\nsocketpipe 1 2\nsocketpipe 2 3\nsocketpipe 3 4\n"
  },
  {
    "path": "simple-shell/comm_sort.success",
    "content": "9\n"
  },
  {
    "path": "simple-shell/dir-plain.dgsh",
    "content": "1 dgsh-wrap ls -n\n2 dgsh-tee\n3 dgsh-conc -o 2\n4 dgsh-wrap awk '!/^total/ {print $6, $7, $8, $1, sprintf(\"%8d\", $5), $9}'\n5 dgsh-wrap awk '{s += $5} END {printf(\"%d bytes\", s)}'\n\n%\nsocketpipe 1 2\nsocketpipe 2 3\nsocketpipe 3 4\nsocketpipe 3 5\n"
  },
  {
    "path": "simple-shell/grep_comm.dgsh",
    "content": "1 grep -l -L match ../test-data/ff ../test-data/F\n2 comm\n\n%\nsocketpipe 1 2\n"
  },
  {
    "path": "simple-shell/grep_comm.success",
    "content": "../test-data/ff\t\t../test-data/F\t\n"
  },
  {
    "path": "simple-shell/grep_comm.success-bash",
    "content": "\t../test-data/F\n../test-data/ff\n"
  },
  {
    "path": "simple-shell/grep_diff.dgsh",
    "content": "1 grep -v -w match ../test-data/F ../test-data/ff\n2 diff\n\n%\nsocketpipe 1 2\n"
  },
  {
    "path": "simple-shell/grep_diff.success",
    "content": "1c1\n< F:not\n---\n> ff:match\n"
  },
  {
    "path": "simple-shell/grep_diff.success-bash",
    "content": "1c1\n< ../test-data/F:not\n---\n> ../test-data/ff:match\n"
  },
  {
    "path": "simple-shell/grep_diff_comm.dgsh",
    "content": "1 grep -l -L -w -v match ../test-data/ff ../test-data/F\n2 dgsh-conc -o 2\n3 diff\n4 comm\n\n%\nsocketpipe 1 2\nsocketpipe 2 3\nsocketpipe 2 4\n"
  },
  {
    "path": "simple-shell/grep_diff_comm.success1",
    "content": "1c1\n< ff\n---\n> F\n\tF:not\nff:match\n"
  },
  {
    "path": "simple-shell/grep_diff_comm.success1-bash",
    "content": "\t../test-data/F:not\n../test-data/ff:match\n1c1\n< ../test-data/ff\n---\n> ../test-data/F\n"
  },
  {
    "path": "simple-shell/grep_diff_comm.success2",
    "content": "\tF:not\nff:match\n1c1\n< ff\n---\n> F\n"
  },
  {
    "path": "simple-shell/grep_diff_comm.success2-bash",
    "content": "1c1\n< ../test-data/ff\n---\n> ../test-data/F\n\t../test-data/F:not\n../test-data/ff:match\n"
  },
  {
    "path": "simple-shell/grep_diff_comm.success3",
    "content": "1c1\n< ff\n---\n> F\nff:match\n\tF:not\n"
  },
  {
    "path": "simple-shell/grep_diff_comm.success3-bash",
    "content": "1c1\n< ../test-data/ff\n---\n> ../test-data/F\n../test-data/ff:match\n\t../test-data/F:not\n"
  },
  {
    "path": "simple-shell/grep_diff_comm.success4",
    "content": "ff:match\n\tF:not\n1c1\n< ff\n---\n> F\n"
  },
  {
    "path": "simple-shell/grep_diff_comm.success4-bash",
    "content": "../test-data/ff:match\n\t../test-data/F:not\n1c1\n< ../test-data/ff\n---\n> ../test-data/F\n"
  },
  {
    "path": "simple-shell/join_sort.dgsh",
    "content": "1 join ../test-data/f1s ../test-data/f2s\n2 sort\n\n%\nsocketpipe 1 2\n"
  },
  {
    "path": "simple-shell/join_sort.success",
    "content": "\n3\n3\n4\n4\n5\n"
  },
  {
    "path": "simple-shell/join_sort_diff.dgsh",
    "content": "1 join ../test-data/f1s ../test-data/f2s\n2 sort\n3 diff ../test-data/f3s\n\n%\nsocketpipe 1 2\nsocketpipe 2 3\n"
  },
  {
    "path": "simple-shell/join_sort_diff.success",
    "content": "1,7c1,6\n< \t\n< 1\t3\n< 2\t3\n< 3\t4\n< 4\t4\n< 5\t5\n< 6\t\n---\n> \n> 3\n> 3\n> 4\n> 4\n> 5\n"
  },
  {
    "path": "simple-shell/ls_wc.dgsh",
    "content": "1 ls\n2 wc -l\n\n%\nsocketpipe 1 2\n"
  },
  {
    "path": "simple-shell/paste_diff.dgsh",
    "content": "1 paste ../test-data/f1s ../test-data/f2s\n2 diff ../test-data/f1s\n\n%\nsocketpipe 1 2\n"
  },
  {
    "path": "simple-shell/paste_diff.success",
    "content": "1,7c1,7\n< \n< 1\n< 2\n< 3\n< 4\n< 5\n< 6\n---\n> \t\n> 1\t3\n> 2\t3\n> 3\t4\n> 4\t4\n> 5\t5\n> 6\t\n"
  },
  {
    "path": "simple-shell/secho_paste.dgsh",
    "content": "1 secho ../test-data/hello\n2 paste ../test-data/world\n\n%\nsocketpipe 1 2\n"
  },
  {
    "path": "simple-shell/secho_paste.success",
    "content": "hello\tworld\n"
  },
  {
    "path": "simple-shell/secho_secho_fgrep.dgsh",
    "content": "1 dgsh-conc -o -n 2\n2 secho match\n3 secho not\n4 dgsh-conc -i 2\n5 grep -F -h match\n\n%\nsocketpipe 1 2\nsocketpipe 1 3\nsocketpipe 2 4\nsocketpipe 3 4\nsocketpipe 4 5\n"
  },
  {
    "path": "simple-shell/secho_secho_fgrep.success",
    "content": "match\n"
  },
  {
    "path": "simple-shell/simple-shell.py",
    "content": "from subprocess import Popen, PIPE, STDOUT\nimport sys\nfrom socket import socketpair, AF_UNIX, SOCK_DGRAM\nfrom os import pipe, fork, close, execlp, dup, dup2, \\\n        open as osopen, O_WRONLY, O_CREAT, environ\nfrom collections import OrderedDict\nimport re\n\nprefix = '/usr/local/dgsh/bin'\noutFile = None\n\ndef debug(s):\n  if DEBUG:\n    sys.stderr.write(s)\n\n\nclass Process:\n  processes = {}\n\n  def __init__(self, command):\n    self.command = command\n    self.inputConnectors = []\n    self.outputConnectors = []\n    self.fileDescriptorsInUse = []\n\n  def selectInputFileDescriptor(self):\n    fd = -1\n    if 0 not in self.fileDescriptorsInUse:\n      fd = 0\n    elif 0 in self.fileDescriptorsInUse and \\\n         3 not in self.fileDescriptorsInUse:\n      fd = 3\n    else:\n      fd = self.fileDescriptorsInUse[-1] + 1\n    self.fileDescriptorsInUse.append(fd)\n    debug(\"input file descriptor return: %d\\n\" % fd)\n    return fd\n\n  def selectOutputFileDescriptor(self):\n    fd = -1\n    if 1 not in self.fileDescriptorsInUse:\n      fd = 1\n    elif 1 in self.fileDescriptorsInUse and \\\n         3 not in self.fileDescriptorsInUse:\n      fd = 3\n    else:\n      fd = self.fileDescriptorsInUse[-1] + 1\n    self.fileDescriptorsInUse.append(fd)\n    debug(\"output file descriptor return: %d\\n\" % fd)\n    return fd\n\ndef setupProcess(index, channel, connector):\n  debug(\"index: %d, toolDict[index]: %s, channel: %s\\n\" % \\\n            (index, toolDict[index], channel))\n  try:\n    if channel == 'output':\n      # index - 1: offset because index = 1, 2,...\n      Process.processes[index].outputConnectors.append(connector)\n    elif channel == 'input':\n      Process.processes[index].inputConnectors.append(connector)\n  except KeyError:\n    Process.processes[index] = Process(toolDict[index])\n    setupProcess(index, channel, connector)\n\ndef parse(command):\n  if '\\'' and '\"' not in command:\n    return command.split()\n  else:\n    splits = []\n    splitS = True\n    splitD = True\n    for pos, letter in enumerate(command):\n      if letter == \"'\":\n        if splitS:\n          splitS = False\n        else:\n          splitS = True\n      elif letter == '\"':\n        if splitD:\n          splitD = False\n        else:\n          splitD = True\n      elif letter is ' ' and splitS and splitD:\n        splits.append(pos)\n    print splits\n    args = []\n    prev = 0\n    for pos in splits:\n      args.append(command[prev:pos].replace(\"'\", \"\"))\n      prev = pos+1\n    args.append(command[prev:].replace(\"'\", \"\"))\n    return args\n\n# Debug configuration\nDEBUG = False\nfor arg in sys.argv[2:]:\n  if arg == \"DEBUG\":\n    DEBUG = True\n  elif arg.startswith(\"PREFIX=\"):\n    match = re.match(r'PREFIX=(.+)$', arg)\n    prefix = match.group(1)\n# Get output file name\n  elif arg.startswith(\"OUT=\"):\n    match = re.match(r'OUT=(.+)$', arg)\n    outFile = match.group(1)\n\n# Read specification of processes and their interconnections\ntry:\n  dgshGraph = sys.argv[1]\nexcept IndexError:\n  print \"Input error: please specify an input file with tool and pipe specifications.\"\n  exit(1)\nwith open(dgshGraph, 'r') as f:\n  lines = f.readlines()\n\ntoolDefsEnd = 0\nfor index, line in enumerate(lines):\n  if line == \"%\\n\":\n    toolDefsEnd = index\n    break\nif toolDefsEnd == 0:\n  print \"Failed to find tool definition end line (\\n%\\n)\"\n  exit(1)\ndebug(\"toolDefsEnd: %s\\n\" % toolDefsEnd)\n\ntoolDict = {}\nfor line in lines[:toolDefsEnd]:\n  if line == '\\n':\n    continue\n  match = re.match(r'^(\\d+) (.+)\\n$', line)\n  if not match:\n    print \"Did not match command index and description: %s\\n\" % line\n    exit(1)\n  toolIndex = match.group(1)\n  toolCommand = match.group(2)\n  if not toolCommand.startswith('/') and not toolCommand.startswith('.'):\n    toolCommand = prefix + '/' + toolCommand\n  toolDict[int(toolIndex)] = toolCommand\n  debug(\"index: %s, command: %s\\n\" % \\\n          (toolIndex, toolCommand))\n\nconnectorDict = OrderedDict()\nfor line in lines[toolDefsEnd+1:]:\n  match = re.match(r'^(\\w+) (\\d+) (\\d+)\\n$', line)\n  if not match:\n    print \"Did not match connector description and endpoints: %s\\n\" % line\n    exit(1)\n  connector = match.group(1)\n  fromIndex = match.group(2)\n  toIndex = match.group(3)\n  connectorDict[int('%s%s' % (fromIndex, toIndex))] = connector\n  debug(\"connector: %s, from index: %s, to_index: %s\\n\" % \\\n          (connector, fromIndex, toIndex))\n\n# Setup objects that represent objects along with their interconnections\nfor processPair, connector in connectorDict.iteritems():\n  # convention: connector[0]: output, connector[1]: input\n  connectorPair = [None, None]\n  if connector == 'socketpipe':\n    connectorPair[0], connectorPair[1] = socketpair(AF_UNIX, SOCK_DGRAM)\n  elif connector == 'pipe':\n    connectorPair[0], connectorPair[1] = pipe()\n  else:\n    print 'Do not understand connector %s' % connector\n    exit(1)\n  node_index_out = processPair / 10\n  node_index_inp = processPair % 10\n  debug(\"out: %d, inp: %d, connector[0]: %d, connector[1]: %d\\n\" % (node_index_out, node_index_inp, connectorPair[0].fileno(), connectorPair[1].fileno()))\n  setupProcess(node_index_out, 'output', connectorPair)\n  setupProcess(node_index_inp, 'input', connectorPair)\n\n# Open output file\nif outFile:\n  outfile_fd = osopen(outFile, O_WRONLY | O_CREAT)\n\n# Activate interconnections and execute processes\nfor index, process in Process.processes.iteritems():\n  debug('process %s, input channels: %d, output channels: %d\\n' \\\n         % (process.command, len(process.inputConnectors), \\\n            len(process.outputConnectors)))\n  pid = fork()\n  if pid:\n    debug(\"%s: inputConnectors: %d\\n\" % (process.command, len(process.inputConnectors)))\n    if process.inputConnectors:\n        environ[\"DGSH_IN\"] = \"1\"\n    else:\n        environ[\"DGSH_IN\"] = \"0\"\n    for ic in process.inputConnectors:\n      fd = process.selectInputFileDescriptor()\n      try:\n        close(fd)\n      except OSError:\n        debug(\"FAIL: close input fd %d for process %s. Discard and move on\" \\\n                % (fd, process.command))\n      fd = dup(ic[1].fileno())\n      debug(\"%s: dup %d, gives %d\\n\" % (process.command, ic[1].fileno(), fd))\n      ic[1].close()\n      ic[0].close()\n    debug(\"%s: outputConnectors: %d\\n\" % (process.command, len(process.outputConnectors)))\n    if process.outputConnectors:\n        environ[\"DGSH_OUT\"] = \"1\"\n    else:\n        environ[\"DGSH_OUT\"] = \"0\"\n    for oc in process.outputConnectors:\n      fd = process.selectOutputFileDescriptor()\n      debug(\"%s: fd selected: %d, fd brought: %d\\n\" % (process.command, process.fileDescriptorsInUse[-1], oc[0].fileno()))\n      try:\n        close(fd)\n      except OSError:\n        print \"FAIL: close output fd %d for process %s. Discard and move on\" \\\n                % (fd, process.command)\n      fd = dup(oc[0].fileno())\n      debug(\"%s: dup %d, gives %d\\n\" % (process.command, oc[0].fileno(), fd))\n      oc[0].close()\n      oc[1].close()\n    if not process.outputConnectors and outFile:\n      close(1)\n      dup(outfile_fd)\n      close(outfile_fd)\n    args = parse(process.command)\n    debug(\"\\n\\nARGS[0]: %s\\n\\n\" % args[0])\n    execlp(args[0], args[0], *args[1:])\n"
  },
  {
    "path": "simple-shell/sort_sort_comm.dgsh",
    "content": "1 dgsh-conc -o -n 2\n2 sort ../test-data/f4s\n3 sort ../test-data/f5s\n4 dgsh-conc -i 2\n5 comm\n\n%\nsocketpipe 1 2\nsocketpipe 1 3\nsocketpipe 2 4\nsocketpipe 3 4\nsocketpipe 4 5\n"
  },
  {
    "path": "simple-shell/sort_sort_comm.success",
    "content": "\n10\n2\n2\n3\n\t1\n\t12\n\t4\n\t5\n\t6\n\t\t4\n\t\t8\n\t\t9\n"
  },
  {
    "path": "simple-shell/sort_sort_comm_paste_join_diff.dgsh",
    "content": "1 dgsh-conc -o -n 2\n2 sort ../test-data/f4s\n3 sort ../test-data/f5s\n4 dgsh-conc -i 2\n5 comm\n6 dgsh-conc -o 3\n7 paste ../test-data/p1\n8 join ../test-data/j2\n9 diff ../test-data/d3\n\n%\nsocketpipe 1 2\nsocketpipe 1 3\nsocketpipe 2 4\nsocketpipe 3 4\nsocketpipe 4 5\nsocketpipe 5 6\nsocketpipe 6 7\nsocketpipe 6 8\nsocketpipe 6 9\n"
  },
  {
    "path": "simple-shell/sort_sort_comm_paste_join_diff.success",
    "content": "\t3\n10\t2\n2\t2\n2\t10\n3\t\n12 match\n4 match\n"
  },
  {
    "path": "simple-shell/tee-copy_diff_comm.dgsh",
    "content": "1 dgsh-tee -i hello\n2 dgsh-conc -o 2\n3 diff ../test-data/world\n4 comm ../test-data/hello\n\n%\nsocketpipe 1 2\nsocketpipe 2 3\nsocketpipe 2 4\n"
  },
  {
    "path": "simple-shell/tee-copy_diff_comm.success",
    "content": "1c1\n< world\n---\n> hello\n\t\thello\n"
  },
  {
    "path": "simple-shell/tee-scatter_diff_comm.dgsh",
    "content": "1 tee -i ../test-data/hello -s\n2 dgsh-conc -o 2\n3 diff ../test-data/world\n4 comm ../test-data/hello\n\n%\nsocketpipe 1 2\nsocketpipe 2 3\nsocketpipe 2 4\n"
  },
  {
    "path": "simple-shell/tee-scatter_diff_comm.success1",
    "content": "1d0\n< world\n\t\thello\n"
  },
  {
    "path": "simple-shell/tee-scatter_diff_comm.success2",
    "content": "\t\thello\n1d0\n< world\n"
  },
  {
    "path": "simple-shell/wrap-cat_comm_sort.dgsh",
    "content": "1 dgsh-wrap /bin/cat ../test-data/f1s\n2 comm ../test-data/f2s\n3 sort\n4 wc -l\n5 tr -d \" \"\n\n%\nsocketpipe 1 2\nsocketpipe 2 3\nsocketpipe 3 4\nsocketpipe 4 5\n"
  },
  {
    "path": "simple-shell/wrap-cat_comm_sort.success",
    "content": "9\n"
  },
  {
    "path": "test-data/.gitignore",
    "content": "*.err\n*.errb\nfid\nres\n"
  },
  {
    "path": "test-data/F",
    "content": "not\n"
  },
  {
    "path": "test-data/access.log",
    "content": "::1 - - [30/Sep/2016:15:04:15 +0300] \"GET / HTTP/1.1\" 200 5974 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n::1 - - [30/Sep/2016:15:04:16 +0300] \"GET /js/bootstrap.min.js HTTP/1.1\" 200 37192 \"http://okanime.com/\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:05:24 +0300] \"GET / HTTP/1.1\" 200 5974 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:05:25 +0300] \"GET /js/bootstrap.min.js HTTP/1.1\" 200 37192 \"http://9281.net/\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:07:16 +0300] \"GET / HTTP/1.1\" 200 5974 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:07:16 +0300] \"GET /js/bootstrap.min.js HTTP/1.1\" 200 37192 \"http://adsupplyads.com/\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n::1 - - [30/Sep/2016:15:37:10 +0300] \"GET / HTTP/1.1\" 200 5974 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n::1 - - [30/Sep/2016:15:37:11 +0300] \"GET /js/bootstrap.min.js HTTP/1.1\" 200 37192 \"http://okanime.com/\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:44:04 +0300] \"GET / HTTP/1.1\" 200 5974 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:44:05 +0300] \"GET /js/bootstrap.min.js HTTP/1.1\" 200 37192 \"http://9281.net/\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:48:16 +0300] \"GET / HTTP/1.1\" 200 5974 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:48:16 +0300] \"GET /js/bootstrap.min.js HTTP/1.1\" 200 37192 \"http://127.0.0.1/\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:54:43 +0300] \"GET / HTTP/1.1\" 200 5974 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n127.0.0.1 - - [30/Sep/2016:15:54:43 +0300] \"GET /js/bootstrap.min.js HTTP/1.1\" 200 37192 \"http://adsupplyads.com/\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0\"\n46.166.190.184 - - [30/Sep/2016:16:47:43 +0300] \"GET /.git/config HTTP/1.1\" 404 451 \"-\" \"fasthttp, Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36\"\n23.20.60.205 - - [30/Sep/2016:17:43:38 +0300] \"HEAD / HTTP/1.1\" 200 254 \"-\" \"Cloud mapping experiment. Contact research@pdrlabs.net\"\n141.212.122.16 - - [30/Sep/2016:17:43:54 +0300] \"GET / HTTP/1.1\" 200 2335 \"-\" \"Mozilla/5.0 zgrab/0.x\"\n185.25.148.240 - - [30/Sep/2016:19:38:46 +0300] \"GET http://testp1.piwo.pila.pl/testproxy.php HTTP/1.1\" 404 457 \"-\" \"Mozilla/5.0 (Windows NT 5.1; rv:32.0) Gecko/20100101 Firefox/31.0\"\n182.118.55.246 - - [30/Sep/2016:20:34:47 +0300] \"GET / HTTP/1.1\" 200 2335 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2251.0 Safari/537.36\"\n109.201.138.240 - - [30/Sep/2016:21:49:26 +0300] \"GET / HTTP/1.1\" 200 2391 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko\"\n213.57.114.155 - - [30/Sep/2016:22:37:45 +0300] \"GET / HTTP/1.0\" 200 5937 \"-\" \"masscan/1.0 (https://github.com/robertdavidgraham/masscan)\"\n179.210.140.22 - - [01/Oct/2016:00:10:07 +0300] \"GET /cgi/common.cgi HTTP/1.0\" 404 473 \"-\" \"Wget(linux)\"\n179.210.140.22 - - [01/Oct/2016:00:10:07 +0300] \"GET /stssys.htm HTTP/1.0\" 404 469 \"-\" \"Wget(linux)\"\n179.210.140.22 - - [01/Oct/2016:00:10:08 +0300] \"GET / HTTP/1.0\" 200 5937 \"-\" \"Wget(linux)\"\n179.210.140.22 - - [01/Oct/2016:00:10:09 +0300] \"POST /command.php HTTP/1.0\" 404 470 \"-\" \"Wget(linux)\"\n193.92.3.66 - - [01/Oct/2016:00:23:28 +0300] \"GET / HTTP/1.0\" 200 5937 \"-\" \"-\"\n159.203.168.255 - - [01/Oct/2016:02:30:55 +0300] \"GET /muieblackcat HTTP/1.1\" 404 471 \"-\" \"-\"\n159.203.168.255 - - [01/Oct/2016:02:30:55 +0300] \"GET //phpMyAdmin/scripts/setup.php HTTP/1.1\" 404 487 \"-\" \"-\"\n159.203.168.255 - - [01/Oct/2016:02:30:56 +0300] \"GET //phpmyadmin/scripts/setup.php HTTP/1.1\" 404 487 \"-\" \"-\"\n159.203.168.255 - - [01/Oct/2016:02:30:56 +0300] \"GET //pma/scripts/setup.php HTTP/1.1\" 404 480 \"-\" \"-\"\n159.203.168.255 - - [01/Oct/2016:02:30:56 +0300] \"GET //myadmin/scripts/setup.php HTTP/1.1\" 404 484 \"-\" \"-\"\n159.203.168.255 - - [01/Oct/2016:02:30:57 +0300] \"GET //MyAdmin/scripts/setup.php HTTP/1.1\" 404 484 \"-\" \"-\"\n164.132.51.91 - - [01/Oct/2016:04:30:22 +0300] \"GET / HTTP/1.1\" 200 2391 \"-\" \"Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko\"\n170.233.142.124 - - [01/Oct/2016:07:21:40 +0300] \"GET / HTTP/1.1\" 200 5918 \"-\" \"curl/7.17.1 (mips-unknown-linux-gnu) libcurl/7.17.1 OpenSSL/0.9.8i zlib/1.2.3\"\n173.208.213.195 - - [01/Oct/2016:07:22:02 +0300] \"GET / HTTP/1.1\" 200 5918 \"-\" \"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)\"\n183.129.160.229 - - [01/Oct/2016:08:10:39 +0300] \"test\" 501 287 \"-\" \"-\"\n183.129.160.229 - - [01/Oct/2016:08:10:39 +0300] \"GET / HTTP/1.1\" 200 5937 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:47.0) Gecko/20100101 Firefox/47.0\"\n"
  },
  {
    "path": "test-data/cmp0.success",
    "content": ""
  },
  {
    "path": "test-data/cmp1-same1.success",
    "content": ""
  },
  {
    "path": "test-data/cmp1-same2.success",
    "content": ""
  },
  {
    "path": "test-data/cmp2-diff.success",
    "content": ""
  },
  {
    "path": "test-data/cmp2-same.success",
    "content": ""
  },
  {
    "path": "test-data/comm_paste.success",
    "content": "1\t\t3\t\t\t\n2\t\t4\t\t\t3\n6\t\t\t\t4\n\t\t\t\t5\n"
  },
  {
    "path": "test-data/comm_paste_join_diff.success",
    "content": "\t3\n10\t2\n2\t2\n2\t10\n3\t\n12 match\n4 match\n"
  },
  {
    "path": "test-data/comm_sort.success",
    "content": "9\n"
  },
  {
    "path": "test-data/d3",
    "content": "\t\t4\n\t\t8\n\t\t9\n"
  },
  {
    "path": "test-data/data.csv",
    "content": "-1,\\N,-1,\"noproject\",\"Fake entry to indicate a previously existing but currently absent repo\",\\N,\"2016-04-18 11:45:02\",\\N,0,\"0000-00-00 00:00:00\"\n1,\"https://api.github.com/repos/tosch/ruote-kit\",1,\"ruote-kit\",\"RESTful wrapper for ruote workflow engine\",\"Ruby\",\"2009-12-08 11:17:27\",2,0,\"2016-03-05 12:23:34\"\n2,\"https://api.github.com/repos/kennethkalmer/ruote-kit\",4,\"ruote-kit\",\"RESTish wrapper for ruote workflow engine\",\"Ruby\",\"2009-06-10 20:32:21\",\\N,0,\"2016-02-24 07:33:16\"\n3,\"https://api.github.com/repos/matplotlib/basemap\",23,\"basemap\",\"\",\"C++\",\"2011-02-19 02:58:42\",\\N,0,\"2016-02-27 10:44:13\"\n4,\"https://api.github.com/repos/jswhit/basemap\",24,\"basemap\",\"\",\"C++\",\"2012-06-14 14:14:56\",3,1,\"0000-00-00 00:00:00\"\n5,\"https://api.github.com/repos/funkaster/cocos2d-x\",28,\"cocos2d-x\",\"Port of cocos2d-iphone in C++\",\"C\",\"2012-03-12 17:48:19\",6,0,\"2016-02-16 23:56:14\"\n6,\"https://api.github.com/repos/cocos2d/cocos2d-x\",31,\"cocos2d-x\",\"cocos2d-x for C++\",\"C++\",\"2010-11-18 23:17:00\",\\N,0,\"2016-02-11 05:16:59\"\n7,\"https://api.github.com/repos/pixonic/cocos2d-x\",42,\"cocos2d-x\",\"Port of cocos2d-iphone in C++\",\"C\",\"2012-04-23 12:20:29\",6,0,\"2016-03-02 01:32:24\"\n8,\"https://api.github.com/repos/NUBIC/ncs_navigator_core\",65,\"ncs_navigator_core\",\"Case management and instrument administration for NCS Navigator\",\"Ruby\",\"2012-04-19 21:45:52\",\\N,0,\"2016-03-01 07:42:14\"\n9,\"https://api.github.com/repos/sgonyea/rake-compiler\",66,\"rake-compiler\",\"Provide a standard and simplified way to build and package Ruby C and Java extensions using Rake as glue.\",\"Ruby\",\"2012-08-01 20:33:51\",14556189,0,\"2016-03-03 18:16:33\"\n10,\"https://api.github.com/repos/chapuni/llvm\",67,\"llvm\",\"Chapuni's branch based on http://llvm.org/git/llvm.git\",\"C++\",\"2011-02-01 09:11:48\",\\N,0,\"2016-02-10 07:17:58\"\n11,\"https://api.github.com/repos/heroku/heroku-buildpack-scala\",69,\"heroku-buildpack-scala\",\"Heroku buildpack: Scala\",\"Shell\",\"2011-05-16 21:41:09\",\\N,0,\"2016-02-18 23:07:41\"\n12,\"https://api.github.com/repos/rafacm/heroku-buildpack-scala\",70,\"heroku-buildpack-scala\",\"\",\"Shell\",\"2012-08-02 14:50:18\",11,0,\"2016-03-02 12:16:22\"\n13,\"https://api.github.com/repos/Fluttershy/locria\",72,\"locria\",\"Project Locria - The Beauty of Elegance\",\"JavaScript\",\"2012-07-02 04:29:21\",\\N,1,\"0000-00-00 00:00:00\"\n14,\"https://api.github.com/repos/edvorg/drash\",73,\"drash\",\"Free box2d based platformer with complete level destruction\",\"C++\",\"2012-07-24 17:17:49\",\\N,1,\"0000-00-00 00:00:00\"\n15,\"https://api.github.com/repos/abarocio80/clide\",74,\"clide\",\"A CLI project manager (not an IDE)\",\"Ruby\",\"2012-08-01 17:54:15\",\\N,1,\"0000-00-00 00:00:00\"\n16,\"https://api.github.com/repos/thorlax402/thor-cms\",75,\"thor-cms\",\"PHP-Based content management system developed off the CodeIgniter Framework.\",\\N,\"2012-07-18 17:54:08\",\\N,1,\"0000-00-00 00:00:00\"\n17,\"https://api.github.com/repos/Offsite/TaskCodes\",76,\"TaskCodes\",\"Kamtech\",\"JavaScript\",\"2012-06-11 17:21:34\",\\N,0,\"2016-03-01 09:43:27\"\n18,\"https://api.github.com/repos/markpasc/gameshake\",71,\"gameshake\",\"Post MLKSHK game trailers posts to the gameshake tumblr\",\"Python\",\"2012-08-01 20:25:36\",\\N,0,\"2016-02-27 05:44:18\"\n19,\"https://api.github.com/repos/samuelclay/NewsBlur\",78,\"NewsBlur\",\"NewsBlur is a personal news reader that brings people together to talk about the world. A new sound of an old instrument.\",\"Objective-C\",\"2009-01-05 14:00:43\",\\N,0,\"2016-03-03 09:40:25\"\n20,\"https://api.github.com/repos/chrisjaure/git-lava\",80,\"git-lava\",\"Branching metaphor for git\",\"Shell\",\"2012-02-27 03:45:44\",\\N,0,\"2016-02-10 16:49:01\"\n21,\"https://api.github.com/repos/ES-DOC/django-cim-forms\",82,\"django-cim-forms\",\"\",\"Python\",\"2012-03-23 14:20:28\",\\N,1,\"0000-00-00 00:00:00\"\n23,\"https://api.github.com/repos/adammark/Markup.js\",86,\"Markup.js\",\"Powerful JavaScript templates\",\"JavaScript\",\"2011-08-23 02:30:04\",\\N,0,\"2016-02-04 02:32:47\"\n24,\"https://api.github.com/repos/leoamigood/1stdibs_V2.1\",88,\"1stdibs_V2.1\",\"Initial setup with mule-pull project\",\"Java\",\"2012-05-03 11:43:31\",\\N,1,\"0000-00-00 00:00:00\"\n25,\"https://api.github.com/repos/pyrovski/Large-Scale-Forward-Regression-using-a-partitioned-linear-model\",87,\"Large-Scale-Forward-Regression-using-a-partitioned-linear-model\",\"\",\"C++\",\"2012-01-17 20:58:01\",\\N,0,\"2016-03-02 09:21:28\"\n26,\"https://api.github.com/repos/podarsmarty/cobertura-plugin\",90,\"cobertura-plugin\",\"Jenkins cobertura plugin\",\"Java\",\"2012-07-26 20:46:47\",193522,0,\"2016-03-02 03:15:20\"\n27,\"https://api.github.com/repos/fbettag/scala-vs-erlang\",89,\"scala-vs-erlang\",\"A performance test comparing Scala verses Erlang with simple agents to determine messaging performance\",\"Erlang\",\"2011-12-25 14:51:08\",1262879,0,\"2016-02-16 05:32:13\"\n28,\"https://api.github.com/repos/luislavena/rake-compiler\",102,\"rake-compiler\",\"Provide a standard and simplified way to build and package Ruby C and Java extensions using Rake as glue.\",\"Ruby\",\"2008-11-03 11:19:43\",\\N,1,\"0000-00-00 00:00:00\"\n29,\"https://api.github.com/repos/Itseez/opencv\",111,\"opencv\",\"Open Source Computer Vision Library\",\"C++\",\"2012-07-19 09:40:17\",\\N,0,\"2016-02-20 20:12:54\"\n30,\"https://api.github.com/repos/jkammerl/opencv\",112,\"opencv\",\"OpenCV GitHub Mirror\",\"C++\",\"2012-08-02 14:50:30\",29,0,\"2016-02-22 14:29:16\"\n31,\"https://api.github.com/repos/gpjt/webgl-lessons\",136,\"webgl-lessons\",\"https://github.com/tparisi/webgl-lessons is now the officially maintained fork for this project\",\"Python\",\"2009-10-06 12:30:19\",\\N,0,\"2016-02-17 23:53:36\"\n32,\"https://api.github.com/repos/kerolasa/lelux-utiliteetit\",139,\"lelux-utiliteetit\",\"A contributor clone of the util-linux, see link bellow for official repo\",\"C\",\"2011-01-19 11:34:14\",\\N,0,\"2016-02-24 08:38:28\"\n33,\"https://api.github.com/repos/SnowblindFatal/Glomes\",140,\"Glomes\",\"The war of balls\",\"Java\",\"2012-06-30 21:05:08\",\\N,0,\"2016-03-04 05:28:23\"\n34,\"https://api.github.com/repos/pockethub/PocketHub\",142,\"android\",\"PocketHub Android App\",\"JavaScript\",\"2011-09-08 16:52:50\",\\N,0,\"2016-02-17 15:46:56\"\n35,\"https://api.github.com/repos/Mirocow/yii-EasyAPNs\",145,\"yii-EasyAPNs\",\"\",\"PHP\",\"2012-06-24 19:08:50\",\\N,0,\"2016-02-28 10:21:21\"\n37,\"https://api.github.com/repos/angular/angular.js\",159,\"angular.js\",\"HTML enhanced for web apps\",\"JavaScript\",\"2010-01-06 00:34:37\",\\N,0,\"2016-02-05 21:29:36\"\n38,\"https://api.github.com/repos/wallysalami/yii-EasyAPNs\",154,\"yii-EasyAPNs\",\"\",\"PHP\",\"2012-08-02 14:55:50\",35,0,\"2016-03-06 05:33:28\"\n39,\"https://api.github.com/repos/macmade/OpenCV-iOS\",161,\"OpenCV-iOS\",\"OpenCV (Open Source Computer Vision) is a library of programming functions for real time computer vision. This project is a port of the OpenCV library for Apple iOS. It includes two XCode projects: one for iPhone, the other one for iPad.\",\"Makefile\",\"2011-04-02 16:38:32\",\\N,0,\"2016-02-26 18:23:18\"\n40,\"https://api.github.com/repos/powmedia/buildify\",166,\"buildify\",\"Builder for creating distributable JavaScript files from source. Concatenate, wrap, uglify.\",\"JavaScript\",\"2012-05-31 11:09:08\",\\N,0,\"2016-03-02 04:47:25\"\n41,\"https://api.github.com/repos/Liberty-Concepts/redmine_git_hosting\",169,\"redmine_git_hosting\",\"A ChiliProject/Redmine plugin which makes configuring your own git hosting easy.  \",\"Ruby\",\"2012-07-30 14:53:09\",42,0,\"2016-02-25 21:01:12\"\n42,\"https://api.github.com/repos/kubitron/redmine_git_hosting\",178,\"redmine_git_hosting\",\"A ChiliProject/Redmine plugin which makes configuring your own git hosting easy.  \",\"Ruby\",\"2011-10-27 01:17:37\",207450,0,\"2016-02-25 03:48:29\"\n43,\"https://api.github.com/repos/hpc/iptablesbuild\",181,\"iptablesbuild\",\"iptablesbuild is effectively a configuration manager for iptables. It is intended to manage iptables configurations in a centralized location for multiple systems.\",\"Perl\",\"2012-08-01 15:19:25\",\\N,0,\"2016-02-19 10:22:47\"\n44,\"https://api.github.com/repos/chenniaoc/OpenCV-iOS\",180,\"OpenCV-iOS\",\"This project is a port of the OpenCV library for Apple iOS. It includes two XCode projects: one for iPhone, the other one for iPad.\",\"Objective-C\",\"2012-08-02 12:55:52\",39,1,\"0000-00-00 00:00:00\"\n45,\"https://api.github.com/repos/tijsverkoyen/dotfiles\",173,\"dotfiles\",\"\",\"Shell\",\"2012-05-05 14:01:59\",\\N,0,\"2016-03-05 07:18:26\"\n46,\"https://api.github.com/repos/6a68/browserid\",191,\"browserid\",\"A secure, distributed, and easy to use identification system.\",\"JavaScript\",\"2012-07-01 00:35:40\",6419421,0,\"2016-02-03 18:49:12\"\n47,\"https://api.github.com/repos/samtubbax/dotfiles\",194,\"dotfiles\",\"\",\"Shell\",\"2012-08-02 14:56:32\",45,0,\"2016-03-03 09:37:33\"\n48,\"https://api.github.com/repos/jman01/customizations\",200,\"customizations\",\"Various configuration scripts, templates etc used for customizations\",\"Shell\",\"2012-08-01 19:43:55\",\\N,0,\"2016-02-22 16:19:15\"\n49,\"https://api.github.com/repos/alexgorbatchev/syntaxhighlighter\",208,\"SyntaxHighlighter\",\"The project has moved to https://github.com/syntaxhighlighter\",\\N,\"2014-10-07 13:48:58\",12363088,0,\"2016-02-04 15:47:27\"\n52,\"https://api.github.com/repos/fredwu/jquery-endless-scroll\",216,\"jquery-endless-scroll\",\"Endless/infinite scrolling/pagination.\",\"CoffeeScript\",\"2009-12-02 06:46:03\",\\N,0,\"2016-02-16 20:43:27\"\n53,\"https://api.github.com/repos/kanishkaganguly/Zero-Requiem\",240,\"Zero-Requiem\",\\N,\"PHP\",\"2012-08-01 20:03:04\",\\N,0,\"2016-02-23 23:07:29\"\n54,\"https://api.github.com/repos/Bronsa/brochure\",186,\"brochure\",\"[ABANDONED]Experimental implementation of clojure in clojure, WIP\",\"Java\",\"2012-04-14 20:08:58\",\\N,0,\"2016-02-09 03:01:52\"\n55,\"https://api.github.com/repos/yui/yui3\",272,\"yui3\",\"A library for building richly interactive web applications.\",\"JavaScript\",\"2008-12-05 19:12:24\",\\N,0,\"2016-03-07 01:30:39\"\n61,\"https://api.github.com/repos/jesperes/protobuf-cmake\",320,\"protobuf-cmake\",\"CMake build support for Google Protobufs\",\"CMake\",\"2010-06-21 18:54:50\",\\N,0,\"2016-02-22 04:13:54\"\n63,\"https://api.github.com/repos/pculture/unisubs\",394,\"unisubs\",\"Amara\",\"Python\",\"2011-08-19 22:04:08\",\\N,0,\"2016-03-01 20:09:29\"\n64,\"https://api.github.com/repos/imtapps/django-request-signer\",359,\"django-request-signer\",\"\",\"Python\",\"2012-01-25 14:52:20\",\\N,0,\"2016-02-20 08:17:54\"\n65,\"https://api.github.com/repos/nadafigment/protobuf-cmake\",496,\"protobuf-cmake\",\"CMake build support for Google Protobufs\",\\N,\"2012-08-02 16:35:08\",61,0,\"2016-02-29 09:09:12\"\n66,\"https://api.github.com/repos/libraM/django-request-signer\",504,\"django-request-signer\",\"\",\"Python\",\"2012-06-08 03:13:55\",64,1,\"0000-00-00 00:00:00\"\n67,\"https://api.github.com/repos/victorlin/loso\",537,\"loso\",\"Chinese segmentation library\",\"Python\",\"2011-04-15 14:17:20\",\\N,0,\"2016-03-06 00:08:26\"\n68,\"https://api.github.com/repos/lucas0412/loso\",616,\"loso\",\"Chinese segmentation library\",\"Python\",\"2012-08-02 12:57:02\",67,1,\"0000-00-00 00:00:00\"\n69,\"https://api.github.com/repos/apipkin/yui3\",635,\"yui3\",\"YUI 3.x Source Tree\",\"JavaScript\",\"2012-07-13 14:48:22\",55,1,\"0000-00-00 00:00:00\"\n70,\"https://api.github.com/repos/docTag/doctag_java\",650,\"doctag_java\",\"\",\"Java\",\"2012-08-02 13:31:59\",\\N,0,\"2016-02-14 03:59:00\"\n71,\"https://api.github.com/repos/llvm-mirror/llvm\",672,\"llvm\",\"Mirror of official llvm git repository located at http://llvm.org/git/llvm.  Updated every five minutes.\",\"C++\",\"2012-01-27 23:49:56\",\\N,0,\"2016-02-26 04:41:20\"\n72,\"https://api.github.com/repos/smarchive/doctag_java\",687,\"doctag_java\",\"Java library for processing docTag meta data\",\"Java\",\"2012-08-02 12:57:15\",70,1,\"0000-00-00 00:00:00\"\n74,\"https://api.github.com/repos/joyent/libuv\",705,\"libuv\",\"Go to \",\"C\",\"2011-03-29 21:10:45\",\\N,0,\"2016-02-23 07:03:20\"\n75,\"https://api.github.com/repos/schatten/schatten.github.com\",704,\"schatten.github.com\",\"\",\"CSS\",\"2011-01-18 09:06:12\",\\N,0,\"2016-03-03 13:04:20\"\n79,\"https://api.github.com/repos/gosquared/nvm-cookbook\",735,\"nvm-cookbook\",\"Chef cookbook for installing and managing nvm on Ubuntu\",\"Ruby\",\"2012-07-03 09:06:42\",\\N,0,\"2016-02-17 23:13:35\"\n80,\"https://api.github.com/repos/daveWid/legacy-php-talk\",754,\"legacy-php-talk\",\"A slide deck about updating legacy PHP code, for the August 2012 meeting of NWO PUG.\",\"JavaScript\",\"2012-07-30 20:04:59\",\\N,0,\"2016-02-12 20:25:15\"\n82,\"https://api.github.com/repos/mshk/Data-Journalism-Handbook-Ja\",820,\"Data-Journalism-Handbook-Ja\",\"\",\\N,\"2012-07-11 08:39:41\",\\N,0,\"2016-02-29 02:00:14\"\n83,\"https://api.github.com/repos/RussellSpitzer/sample_app\",831,\"sample_app\",\"Sample App from Rails Tutorial\",\"Ruby\",\"2012-08-01 17:20:12\",\\N,0,\"2016-03-03 05:12:28\"\n84,\"https://api.github.com/repos/willdurand/willdurand.github.com\",858,\"willdurand.github.com\",\"My very own blog.\",\"CSS\",\"2012-01-15 22:41:31\",\\N,0,\"2016-03-06 10:38:35\"\n85,\"https://api.github.com/repos/stof/willdurand.github.com\",859,\"willdurand.github.com\",\"My new blog!\",\"JavaScript\",\"2012-08-02 14:06:43\",84,0,\"2016-03-04 13:31:33\"\n86,\"https://api.github.com/repos/rxgx/dotfiles\",863,\"dotfiles\",\":computer: My user configuration files for OS X Mavericks\",\"Shell\",\"2012-07-25 20:59:33\",\\N,0,\"2016-03-03 05:43:19\"\n87,\"https://api.github.com/repos/Ablu/manaserv\",861,\"manaserv\",\"A flexible 2D MMORPG server\",\"C++\",\"2011-08-01 19:05:36\",90,0,\"2016-02-03 23:40:50\"\n88,\"https://api.github.com/repos/garyrussell/spring-integration\",866,\"spring-integration\",\"\",\"Java\",\"2011-08-12 15:45:00\",4952338,0,\"2016-02-17 05:46:00\"\n89,\"https://api.github.com/repos/yomoyomo/Data-Journalism-Handbook-Ja\",864,\"Data-Journalism-Handbook-Ja\",\"\",\\N,\"2012-08-02 14:57:51\",82,0,\"2016-03-06 23:54:35\"\n90,\"https://api.github.com/repos/mana/manaserv\",876,\"manaserv\",\"A flexible 2D MMORPG server\",\"C++\",\"2011-03-23 22:15:29\",\\N,0,\"2016-02-26 23:18:10\"\n91,\"https://api.github.com/repos/bjorn/manaserv\",875,\"manaserv\",\"A flexible 2D MMORPG server\",\"C++\",\"2011-03-24 18:38:40\",90,0,\"2016-02-08 10:33:30\"\n92,\"https://api.github.com/repos/fnando/i18n-js\",877,\"i18n-js\",\"It's a small library to provide the I18n translations on the Javascript. It comes with Rails support.\",\"JavaScript\",\"2009-09-02 03:35:45\",\\N,0,\"2016-02-16 15:44:58\"\n93,\"https://api.github.com/repos/olegz/spring-integration\",884,\"spring-integration\",\"\",\"Java\",\"2011-08-11 16:57:01\",4952338,0,\"2016-03-01 10:38:26\"\n94,\"https://api.github.com/repos/chapuni/llvm-project\",67,\"llvm-project\",\"Chapuni's branches for llvm-project. (See also https://github.com/llvm-project/llvm-project )\",\"C++\",\"2011-11-11 11:08:58\",\\N,0,\"2016-02-10 07:17:58\"\n95,\"https://api.github.com/repos/neverabc/libuv\",879,\"libuv\",\"platform layer for node.js\",\"C\",\"2012-08-02 14:57:13\",74,0,\"2016-02-29 18:31:17\"\n96,\"https://api.github.com/repos/blinkbox/cucumber-js\",882,\"cucumber-js\",\"Pure Javascript Cucumber\",\"JavaScript\",\"2012-05-28 15:47:12\",10457,1,\"0000-00-00 00:00:00\"\n97,\"https://api.github.com/repos/elaird/supy\",888,\"supy\",\"\",\"Python\",\"2011-09-28 16:51:36\",\\N,0,\"2016-02-15 06:20:02\"\n98,\"https://api.github.com/repos/janrain/jump.ios\",891,\"jump.ios\",\"created for Nathan Ramsey on 7/13/12\",\"Objective-C\",\"2012-07-13 17:10:38\",\\N,0,\"2016-02-21 10:21:45\"\n99,\"https://api.github.com/repos/timblinkbox/cucumber-js\",889,\"cucumber-js\",\"Pure Javascript Cucumber\",\"JavaScript\",\"2012-06-21 13:47:25\",96,0,\"2016-03-05 07:29:30\"\n100,\"https://api.github.com/repos/angular/angular-seed\",159,\"angular-seed\",\"Seed project for angular apps. \",\"HTML\",\"2010-12-24 06:07:50\",\\N,0,\"2016-02-05 21:29:36\"\n101,\"https://api.github.com/repos/mashiro/i18n-js\",915,\"i18n-js\",\"It's a small library to provide the I18n translations on the Javascript. It comes with Rails support.\",\"JavaScript\",\"2012-08-02 14:58:14\",92,0,\"2016-02-27 08:41:16\"\n102,\"https://api.github.com/repos/JakeWharton/Android-ViewPagerIndicator\",896,\"Android-ViewPagerIndicator\",\"Paging indicator widgets compatible with the ViewPager from the Android Support Library and ActionBarSherlock. Originally based on Patrik Åkerfeldt's ViewFlow.\",\"Java\",\"2011-08-04 15:13:44\",\\N,1,\"0000-00-00 00:00:00\"\n103,\"https://api.github.com/repos/Evh27/angular-seed\",900,\"angular-seed\",\"Seed project for angular apps. \",\"JavaScript\",\"2012-08-02 12:58:13\",100,1,\"0000-00-00 00:00:00\"\n104,\"https://api.github.com/repos/leon/play-salat\",947,\"play-salat\",\"MongoDB / Salat plugin for Play 2 [MOVED]\",\"Scala\",\"2012-04-10 11:01:51\",\\N,0,\"2016-02-25 17:27:09\"\n105,\"https://api.github.com/repos/bnoordhuis/libuv\",963,\"libuv\",\"Cross-platform asychronous I/O\",\"C\",\"2015-01-23 22:47:25\",6690806,0,\"2016-02-08 15:54:01\"\n106,\"https://api.github.com/repos/oftc/libuv\",971,\"libuv\",\"platform layer for node.js\",\"C\",\"2012-07-09 14:56:04\",74,0,\"2016-03-01 09:45:24\"\n107,\"https://api.github.com/repos/shepheb/jotto\",981,\"jotto\",\"Webapp for the game Jotto using AngularJs, Node.js, Socket.io and PhoneGap.\",\"JavaScript\",\"2012-07-13 23:07:31\",\\N,0,\"2016-03-03 20:42:29\"\n108,\"https://api.github.com/repos/racker/virgo\",982,\"virgo\",\"\",\"Lua\",\"2011-07-12 04:25:25\",\\N,1,\"0000-00-00 00:00:00\"\n109,\"https://api.github.com/repos/incuna/django-extensible-profiles\",985,\"django-extensible-profiles\",\"Extensible profiles\",\"Python\",\"2012-02-03 08:58:27\",\\N,1,\"0000-00-00 00:00:00\"\n110,\"https://api.github.com/repos/redaemn/angular-seed\",993,\"angular-seed\",\"Seed project for angular apps. \",\"JavaScript\",\"2012-05-19 08:30:13\",100,0,\"2016-03-02 17:20:26\"\n112,\"https://api.github.com/repos/ZorGleH/try_git\",1013,\"try_git\",\\N,\\N,\"2012-08-01 20:21:56\",\\N,0,\"2016-03-07 08:15:41\"\n114,\"https://api.github.com/repos/madrobby/zepto\",1019,\"zepto\",\"Zepto.js is a minimalist JavaScript library for modern browsers, with a jQuery-compatible API\",\"HTML\",\"2010-09-20 07:57:57\",\\N,0,\"2016-02-26 19:21:16\"\n115,\"https://api.github.com/repos/ochameau/addon-sdk\",1023,\"addon-sdk\",\"The Add-on SDK repository.\",\"JavaScript\",\"2010-11-29 14:17:32\",127,0,\"2016-03-01 09:13:22\"\n116,\"https://api.github.com/repos/brandonwamboldt/utilphp\",1024,\"utilphp\",\"util.php is a collection of useful functions and snippets that you need or could use every day, designed to avoid conflicts with existing projects\",\"PHP\",\"2012-07-25 00:11:26\",\\N,0,\"2016-02-08 22:44:02\"\n"
  },
  {
    "path": "test-data/diff0-noin.success",
    "content": ""
  },
  {
    "path": "test-data/diff0-stdin1.success",
    "content": "1d0\n< 0\n"
  },
  {
    "path": "test-data/diff0-stdin2.success",
    "content": "0a1\n> 0\n"
  },
  {
    "path": "test-data/diff0.success",
    "content": ""
  },
  {
    "path": "test-data/diff1-stdin.success",
    "content": "1c1\n< 0\n---\n> 1\n"
  },
  {
    "path": "test-data/diff1.success",
    "content": "0a1\n> 0\n"
  },
  {
    "path": "test-data/diff2.success",
    "content": "1c1\n< 0\n---\n> 1\n"
  },
  {
    "path": "test-data/diff3-0.success",
    "content": ""
  },
  {
    "path": "test-data/diff3-1.success",
    "content": "====3\n1:0a\n2:0a\n3:1c\n  a\n"
  },
  {
    "path": "test-data/diff3-2-stdin1.success",
    "content": "====\n1:1,2c\n  a\n  b\n2:0a\n3:1c\n  b\n"
  },
  {
    "path": "test-data/diff3-2-stdin2.success",
    "content": "====2\n1:1c\n3:1c\n  b\n2:1c\n  a\n"
  },
  {
    "path": "test-data/diff3-2.success",
    "content": "====2\n1:1c\n3:1c\n  b\n2:1c\n  a\n"
  },
  {
    "path": "test-data/diff3-3.success",
    "content": "====\n1:1,2c\n  a\n  c\n2:1c\n  b\n3:1c\n  c\n"
  },
  {
    "path": "test-data/diff4.success",
    "content": "1d0\n< 0\n1d0\n< 1\n1d0\n< 2\n1d0\n< 3\n"
  },
  {
    "path": "test-data/dir-plain.sh",
    "content": "ls -n |\ndgsh-tee |\n{{\n\tawk '!/^total/ {print $6, $7, $8, $1, sprintf(\"%8d\", $5), $9}' &\n\tawk '{s += $5} END {printf(\"%d bytes\", s)}' &\n}} |\ndgsh-tee\n\t\n"
  },
  {
    "path": "test-data/f1s",
    "content": "\n1\n2\n3\n4\n5\n6\n"
  },
  {
    "path": "test-data/f2s",
    "content": "\n3\n3\n4\n4\n5\n"
  },
  {
    "path": "test-data/f3s",
    "content": "\t\n1\t3\n2\t3\n3\t4\n4\t4\n5\t5\n6\t\n"
  },
  {
    "path": "test-data/f4s",
    "content": "4\n\n2\n8\n10\n3\n2\n9\n"
  },
  {
    "path": "test-data/f4ss",
    "content": "\n10\n2\n2\n3\n4\n8\n9\n"
  },
  {
    "path": "test-data/f5s",
    "content": "5\n1\n6\n12\n4\n8\n4\n9\n"
  },
  {
    "path": "test-data/f5ss",
    "content": "1\n12\n4\n4\n5\n6\n8\n9\n"
  },
  {
    "path": "test-data/ff",
    "content": "match\n"
  },
  {
    "path": "test-data/function_bash_tools.success",
    "content": ""
  },
  {
    "path": "test-data/function_dgsh_tools.success",
    "content": ""
  },
  {
    "path": "test-data/grep-Lcap-c-l-matching-lines-nomatch.success",
    "content": "(standard input)\t0\t\t\n"
  },
  {
    "path": "test-data/grep-Lcap-c-l-matching-lines.success",
    "content": "\t1\t(standard input)\thi\n"
  },
  {
    "path": "test-data/grep-Lcap-c-l-nomatch.success",
    "content": "(standard input)\t0\t\n"
  },
  {
    "path": "test-data/grep-Lcap-c-l.success",
    "content": "\t1\t(standard input)\n"
  },
  {
    "path": "test-data/grep-Lcap-c-matching-lines-l-nomatch.success",
    "content": "(standard input)\t0\t\t\n"
  },
  {
    "path": "test-data/grep-Lcap-c-matching-lines-l.success",
    "content": "\t1\thi\t(standard input)\n"
  },
  {
    "path": "test-data/grep-Lcap-c-matching-lines-nomatch.success",
    "content": "(standard input)\t0\t\n"
  },
  {
    "path": "test-data/grep-Lcap-c-matching-lines.success",
    "content": "\t1\thi\n"
  },
  {
    "path": "test-data/grep-Lcap-c-nomatch.success",
    "content": "(standard input)\n0\n"
  },
  {
    "path": "test-data/grep-Lcap-c.success",
    "content": "1\n"
  },
  {
    "path": "test-data/grep-Lcap-cat-nomatch.success",
    "content": "(standard input)\n"
  },
  {
    "path": "test-data/grep-Lcap-cat.success",
    "content": ""
  },
  {
    "path": "test-data/grep-Lcap-l-c-matching-lines-nomatch.success",
    "content": "(standard input)\t\t0\t\n"
  },
  {
    "path": "test-data/grep-Lcap-l-c-matching-lines.success",
    "content": "\t(standard input)\t1\thi\n"
  },
  {
    "path": "test-data/grep-Lcap-l-c-nomatch.success",
    "content": "(standard input)\t\t0\n"
  },
  {
    "path": "test-data/grep-Lcap-l-c.success",
    "content": "\t(standard input)\t1\n"
  },
  {
    "path": "test-data/grep-Lcap-l-matching-lines-c-nomatch.success",
    "content": "(standard input)\t\t\t0\n"
  },
  {
    "path": "test-data/grep-Lcap-l-matching-lines-c.success",
    "content": "\t(standard input)\thi\t1\n"
  },
  {
    "path": "test-data/grep-Lcap-l-matching-lines-nomatch.success",
    "content": "(standard input)\t\t\n"
  },
  {
    "path": "test-data/grep-Lcap-l-matching-lines.success",
    "content": "\t(standard input)\thi\n"
  },
  {
    "path": "test-data/grep-Lcap-l-nomatch.success",
    "content": "(standard input)\t\n"
  },
  {
    "path": "test-data/grep-Lcap-l.success",
    "content": "\t(standard input)\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines-c-l-nomatch.success",
    "content": "(standard input)\t\t0\t\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines-c-l.success",
    "content": "\thi\t1\t(standard input)\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines-c-nomatch.success",
    "content": "(standard input)\t\t0\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines-c.success",
    "content": "\thi\t1\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines-l-c-nomatch.success",
    "content": "(standard input)\t\t\t0\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines-l-c.success",
    "content": "\thi\t(standard input)\t1\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines-l-nomatch.success",
    "content": "(standard input)\t\t\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines-l.success",
    "content": "\thi\t(standard input)\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines-nomatch.success",
    "content": "(standard input)\t\n"
  },
  {
    "path": "test-data/grep-Lcap-matching-lines.success",
    "content": "\thi\n"
  },
  {
    "path": "test-data/grep-Lcap-nomatch.success",
    "content": "(standard input)\n"
  },
  {
    "path": "test-data/grep-Lcap.success",
    "content": ""
  },
  {
    "path": "test-data/grep-c-Lcap-l-matching-lines-nomatch.success",
    "content": "0\t(standard input)\t\t\n"
  },
  {
    "path": "test-data/grep-c-Lcap-l-matching-lines.success",
    "content": "1\t\t(standard input)\thi\n"
  },
  {
    "path": "test-data/grep-c-Lcap-l-nomatch.success",
    "content": "0\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-c-Lcap-l.success",
    "content": "1\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-c-Lcap-matching-lines-l-nomatch.success",
    "content": "0\t(standard input)\t\t\n"
  },
  {
    "path": "test-data/grep-c-Lcap-matching-lines-l.success",
    "content": "1\t\thi\t(standard input)\n"
  },
  {
    "path": "test-data/grep-c-Lcap-matching-lines-nomatch.success",
    "content": "0\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-c-Lcap-matching-lines.success",
    "content": "1\t\thi\n"
  },
  {
    "path": "test-data/grep-c-Lcap-nomatch.success",
    "content": "0\t(standard input)\n"
  },
  {
    "path": "test-data/grep-c-Lcap.success",
    "content": "1\t\n"
  },
  {
    "path": "test-data/grep-c-cat.success",
    "content": "1\n"
  },
  {
    "path": "test-data/grep-c-l-Lcap-matching-lines-nomatch.success",
    "content": "0\t\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-c-l-Lcap-matching-lines.success",
    "content": "1\t(standard input)\t\thi\n"
  },
  {
    "path": "test-data/grep-c-l-Lcap-nomatch.success",
    "content": "0\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-c-l-Lcap.success",
    "content": "1\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-c-l-matching-lines-Lcap-nomatch.success",
    "content": "0\t\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-c-l-matching-lines-Lcap.success",
    "content": "1\t(standard input)\thi\t\n"
  },
  {
    "path": "test-data/grep-c-l-matching-lines.success",
    "content": "1\t(standard input)\thi\n"
  },
  {
    "path": "test-data/grep-c-l.success",
    "content": "1\n(standard input)\n"
  },
  {
    "path": "test-data/grep-c-matching-lines-Lcap-l-nomatch.success",
    "content": "0\t\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-c-matching-lines-Lcap-l.success",
    "content": "1\thi\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-c-matching-lines-Lcap-nomatch.success",
    "content": "0\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-c-matching-lines-Lcap.success",
    "content": "1\thi\t\n"
  },
  {
    "path": "test-data/grep-c-matching-lines-l-Lcap-nomatch.success",
    "content": "0\t\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-c-matching-lines-l-Lcap.success",
    "content": "1\thi\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-c-matching-lines-l.success",
    "content": "1\thi\t(standard input)\n"
  },
  {
    "path": "test-data/grep-c-matching-lines.success",
    "content": "1\nhi\n"
  },
  {
    "path": "test-data/grep-c.success",
    "content": "1\n"
  },
  {
    "path": "test-data/grep-f-cat.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-f.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-l-Lcap-c-matching-lines-nomatch.success",
    "content": "\t(standard input)\t0\t\n"
  },
  {
    "path": "test-data/grep-l-Lcap-c-matching-lines.success",
    "content": "(standard input)\t\t1\thi\n"
  },
  {
    "path": "test-data/grep-l-Lcap-c-nomatch.success",
    "content": "\t(standard input)\t0\n"
  },
  {
    "path": "test-data/grep-l-Lcap-c.success",
    "content": "(standard input)\t\t1\n"
  },
  {
    "path": "test-data/grep-l-Lcap-matching-lines-c-nomatch.success",
    "content": "\t(standard input)\t\t0\n"
  },
  {
    "path": "test-data/grep-l-Lcap-matching-lines-c.success",
    "content": "(standard input)\t\thi\t1\n"
  },
  {
    "path": "test-data/grep-l-Lcap-matching-lines-nomatch.success",
    "content": "\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-l-Lcap-matching-lines.success",
    "content": "(standard input)\t\thi\n"
  },
  {
    "path": "test-data/grep-l-Lcap-nomatch.success",
    "content": "\t(standard input)\n"
  },
  {
    "path": "test-data/grep-l-Lcap.success",
    "content": "(standard input)\t\n"
  },
  {
    "path": "test-data/grep-l-c-Lcap-matching-lines-nomatch.success",
    "content": "\t0\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-l-c-Lcap-matching-lines.success",
    "content": "(standard input)\t1\t\thi\n"
  },
  {
    "path": "test-data/grep-l-c-Lcap-nomatch.success",
    "content": "\t0\t(standard input)\n"
  },
  {
    "path": "test-data/grep-l-c-Lcap.success",
    "content": "(standard input)\t1\t\n"
  },
  {
    "path": "test-data/grep-l-c-matching-lines-Lcap-nomatch.success",
    "content": "\t0\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-l-c-matching-lines-Lcap.success",
    "content": "(standard input)\t1\thi\t\n"
  },
  {
    "path": "test-data/grep-l-c-matching-lines.success",
    "content": "(standard input)\t1\thi\n"
  },
  {
    "path": "test-data/grep-l-c.success",
    "content": "(standard input)\n1\n"
  },
  {
    "path": "test-data/grep-l-cat.success",
    "content": "(standard input)\n"
  },
  {
    "path": "test-data/grep-l-matching-lines-Lcap-c-nomatch.success",
    "content": "\t\t(standard input)\t0\n"
  },
  {
    "path": "test-data/grep-l-matching-lines-Lcap-c.success",
    "content": "(standard input)\thi\t\t1\n"
  },
  {
    "path": "test-data/grep-l-matching-lines-Lcap-nomatch.success",
    "content": "\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-l-matching-lines-Lcap.success",
    "content": "(standard input)\thi\t\n"
  },
  {
    "path": "test-data/grep-l-matching-lines-c-Lcap-nomatch.success",
    "content": "\t\t0\t(standard input)\n"
  },
  {
    "path": "test-data/grep-l-matching-lines-c-Lcap.success",
    "content": "(standard input)\thi\t1\t\n"
  },
  {
    "path": "test-data/grep-l-matching-lines-c.success",
    "content": "(standard input)\thi\t1\n"
  },
  {
    "path": "test-data/grep-l-matching-lines.success",
    "content": "(standard input)\nhi\n"
  },
  {
    "path": "test-data/grep-l.success",
    "content": "(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap-c-l-nomatch.success",
    "content": "\t(standard input)\t0\t\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap-c-l.success",
    "content": "hi\t\t1\t(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap-c-nomatch.success",
    "content": "\t(standard input)\t0\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap-c.success",
    "content": "hi\t\t1\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap-l-c-nomatch.success",
    "content": "\t(standard input)\t\t0\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap-l-c.success",
    "content": "hi\t\t(standard input)\t1\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap-l-nomatch.success",
    "content": "\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap-l.success",
    "content": "hi\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap-nomatch.success",
    "content": "\t(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-Lcap.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-matching-lines-c-Lcap-l-nomatch.success",
    "content": "\t0\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-matching-lines-c-Lcap-l.success",
    "content": "hi\t1\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-c-Lcap-nomatch.success",
    "content": "\t0\t(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-c-Lcap.success",
    "content": "hi\t1\t\n"
  },
  {
    "path": "test-data/grep-matching-lines-c-l-Lcap-nomatch.success",
    "content": "\t0\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-c-l-Lcap.success",
    "content": "hi\t1\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-matching-lines-c-l.success",
    "content": "hi\t1\t(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-c.success",
    "content": "hi\n1\n"
  },
  {
    "path": "test-data/grep-matching-lines-cat.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-matching-lines-l-Lcap-c-nomatch.success",
    "content": "\t\t(standard input)\t0\n"
  },
  {
    "path": "test-data/grep-matching-lines-l-Lcap-c.success",
    "content": "hi\t(standard input)\t\t1\n"
  },
  {
    "path": "test-data/grep-matching-lines-l-Lcap-nomatch.success",
    "content": "\t\t(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-l-Lcap.success",
    "content": "hi\t(standard input)\t\n"
  },
  {
    "path": "test-data/grep-matching-lines-l-c-Lcap-nomatch.success",
    "content": "\t\t0\t(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines-l-c-Lcap.success",
    "content": "hi\t(standard input)\t1\t\n"
  },
  {
    "path": "test-data/grep-matching-lines-l-c.success",
    "content": "hi\t(standard input)\t1\n"
  },
  {
    "path": "test-data/grep-matching-lines-l.success",
    "content": "hi\n(standard input)\n"
  },
  {
    "path": "test-data/grep-matching-lines.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-noargs-cat.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-noargs.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-o-cat.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-o.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-v-cat.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep-v.success",
    "content": "hi\n"
  },
  {
    "path": "test-data/grep_comm.success",
    "content": "../test-data/ff\t\t../test-data/F\t\n"
  },
  {
    "path": "test-data/group.success",
    "content": "a\n"
  },
  {
    "path": "test-data/hello",
    "content": "hello\n"
  },
  {
    "path": "test-data/j2",
    "content": "12\tmatch\n4\tmatch\n9\tdon't match\n"
  },
  {
    "path": "test-data/join_sort.success",
    "content": "\n3\n3\n4\n4\n5\n"
  },
  {
    "path": "test-data/join_sort_diff.success",
    "content": "1,7c1,6\n< \t\n< 1\t3\n< 2\t3\n< 3\t4\n< 4\t4\n< 5\t5\n< 6\t\n---\n> \n> 3\n> 3\n> 4\n> 4\n> 5\n"
  },
  {
    "path": "test-data/last",
    "content": "\t\t4\n\t\t8\n\t\t9\n"
  },
  {
    "path": "test-data/multipipe_one_last.success",
    "content": ""
  },
  {
    "path": "test-data/multipipe_one_start.success",
    "content": ""
  },
  {
    "path": "test-data/nondgsh.success",
    "content": "0\n1\n"
  },
  {
    "path": "test-data/p1",
    "content": "3\n2\n2\n10\n\n"
  },
  {
    "path": "test-data/paste_diff.success",
    "content": "1,7c1,7\n< \n< 1\n< 2\n< 3\n< 4\n< 5\n< 6\n---\n> \t\n> 1\t3\n> 2\t3\n> 3\t4\n> 4\t4\n> 5\t5\n> 6\t\n"
  },
  {
    "path": "test-data/read_while.success",
    "content": "hi\nthere\n"
  },
  {
    "path": "test-data/recursive_multipipe_oneline_end.success",
    "content": "world\nhello\n"
  },
  {
    "path": "test-data/recursive_multipipe_oneline_start.success",
    "content": "hello\nworld\n"
  },
  {
    "path": "test-data/results",
    "content": "3\n2\n2\n10\n\n"
  },
  {
    "path": "test-data/secho_paste.success",
    "content": "hello\tworld\n"
  },
  {
    "path": "test-data/secho_secho_fgrep.success",
    "content": "match\n"
  },
  {
    "path": "test-data/sort_sort_comm.success",
    "content": "\n10\n2\n2\n3\n\t1\n\t12\n\t4\n\t5\n\t6\n\t\t4\n\t\t8\n\t\t9\n"
  },
  {
    "path": "test-data/sort_sort_comm_paste_join_diff.success",
    "content": "\t3\n10\t2\n2\t2\n2\t10\n3\t\n12 match\n4 match\n"
  },
  {
    "path": "test-data/subshell.success",
    "content": "a\n"
  },
  {
    "path": "test-data/tee-copy_diff_comm.success",
    "content": "1c1\n< world\n---\n> hello\n\t\thello\n"
  },
  {
    "path": "test-data/top",
    "content": "12\tmatch\n4\tmatch\n9\tdon't match\n"
  },
  {
    "path": "test-data/world",
    "content": "world\n"
  },
  {
    "path": "test-data/wrap-cat_comm_sort.success",
    "content": "9\n"
  },
  {
    "path": "unix-tools/.gitignore",
    "content": "bin/*\ncat\ncmp\ncoreutils/*\ndiff\ndiff3\netc/*\ngawk/*\ngnulib/*\ngrep/*\ninclude/*\nlib/*\nlibexec/*\nparallel/*\npatch/*\nsecho\nsed/*\nshare/*\ntar/*\ntee\nw\n# Test files\nA\nA+B.dgsh.ft2\nA-B.dgsh.ft2\nB\nFig/\ncharacter.txt\ndiff_last\ndigram.txt\nfft-input\ngrep-p100/\ngrep2/\ngrepp/\npecho\nresults\ntop_results\ntrigram.txt\nwords.txt\ndgsh-compat\n"
  },
  {
    "path": "unix-tools/Makefile",
    "content": "include ../.config\n\n# All but ginstall comm join paste sort\n# ginstall, renamed from install, is used to install the programs\nDISABLE_COREUTILS_PROGRAMS=\\\nwho users uptime stty stdbuf pinky nice install hostid df chroot chcon \\\ncat basename base64 base32 [ expr expand env echo du dirname dircolors \\\ndir dd date csplit cp cksum chown chmod chgrp nproc nl mv \\\nmktemp mknod mkfifo mkdir md5sum ls logname ln link kill id head \\\ngroups fold fmt false factor sha512sum sha384sum sha256sum sha224sum \\\nsha1sum seq runcon rmdir rm realpath readlink pwd ptx printf printenv \\\npr pathchk od numfmt nohup unexpand uname tty tsort truncate true \\\ntr touch timeout test tee tail tac sync sum stat split sleep shuf \\\nshred yes whoami wc vdir unlink uniq\n\nFID=http://www.bmrb.wisc.edu/ftp/pub/bmrb/timedomain/bmr6443/timedomain_data/c13-hsqc/june11-se-6426-CA.fid/fid\n\nPREFIX?=/usr/local/dgsh\nDGSHPATH=$(PREFIX)/libexec/dgsh\n\nDGSHDIR=../core-tools/src\nPSDIR=../test-data\nEGDIR=../example\nMANDUMPDIR=/var/tmp/dgsh-share-duplicates\n# TOOLDIR\nTD=unix-tools\nSTD=/usr/bin\nSCRIPTDIR=tool_scripts\n\nINCPATHS= -I$(DGSHDIR)\n\n# Color\nGR=\\033[0;32m\t# Green\nR=\\033[0;31m\t# Red\nB=\\033[0;34m\t# Blue\nEC=\\033[0m\t# End color\nS=${GR}successful${EC}\nF=${R}failed${EC}\n\nifdef DEBUG\nCFLAGS+=-DDEBUG\nendif\n\nOS = $(shell uname -s)\nifeq ($(OS), Linux)\n   BZIP2LOCATION=/bin/bzip2\n   GZIPLOCATION=/bin/gzip\n   SEDLOCATION=/bin/sed\n   XZLOCATION=/usr/bin/xz\nelse\n   ifeq ($(OS), Darwin)\n       BZIP2LOCATION=/usr/bin/bzip2\n       GZIPLOCATION=/usr/bin/gzip\n       SEDLOCATION=/usr/bin/sed\n       XZLOCATION=/usr/local/bin/xz\n   endif\nendif\n\n# If not cloned repo with --recursive use this target to\n# clone the submodule repos\nget-submodules:\n\tcd .. && git submodule update --init --recursive --depth=5000 \\\n\t\t$(TD)/bash \\\n\t\t$(TD)/coreutils \\\n\t\t$(TD)/grep\n\nconfigure:\n\tcd bash && ./configure --prefix=$(PREFIX) --bindir=$(DGSHPATH) \\\n\t\t--docdir=$(MANDUMPDIR) \\\n\t\t--mandir=$(MANDUMPDIR) \\\n\t\t--infodir=$(MANDUMPDIR) \\\n\t\t--localedir=$(MANDUMPDIR)\n\tcd coreutils && ./bootstrap && ../cygwin-sys-select-patch.sh && \\\n\t./configure --prefix=$(PREFIX) \\\n\t\t--bindir=$(DGSHPATH) \\\n\t\t--enable-no-install-program=\"$(DISABLE_COREUTILS_PROGRAMS)\" \\\n\t\t--docdir=$(MANDUMPDIR) \\\n\t\t--mandir=$(MANDUMPDIR) \\\n\t\t--infodir=$(MANDUMPDIR) \\\n\t\t--localedir=$(MANDUMPDIR)\n\tcd grep && ./bootstrap && ./configure --prefix=$(PREFIX) \\\n\t\t--bindir=$(DGSHPATH) \\\n\t\t--docdir=$(MANDUMPDIR) \\\n\t\t--mandir=$(MANDUMPDIR) \\\n\t\t--infodir=$(MANDUMPDIR) \\\n\t\t--localedir=$(MANDUMPDIR)\n\nmake:\n\t$(MAKE) -C bash CFLAGS=\"$(CFLAGS)\"\n\t$(MAKE) -C coreutils\n\t$(MAKE) -C grep\n\nbuild-install: cat cmp diff diff3 tee make\n\tmkdir -p ../build/libexec/dgsh ../build/bin\n\tcp bash/bash ../build/libexec/dgsh/\n\trm -f ../build/bin/dgsh\n\tln bash/bash ../build/bin/dgsh\n\tcp coreutils/src/comm ../build/libexec/dgsh/\n\tcp coreutils/src/cut ../build/libexec/dgsh/\n\tcp coreutils/src/join ../build/libexec/dgsh/\n\tcp coreutils/src/paste ../build/libexec/dgsh/\n\tcp coreutils/src/sort ../build/libexec/dgsh/\n\tcp grep/src/grep ../build/libexec/dgsh/\n\tcp grep/src/egrep ../build/libexec/dgsh/\n\tcp grep/src/fgrep ../build/libexec/dgsh/\n\tchmod 755 cat cmp diff diff3 tee\n\tcp -p cat cmp diff diff3 tee ../build/libexec/dgsh/\n\t./install-wrapped.sh $$(cd .. ; pwd)/build\n\ninstall: cat cmp diff diff3 tee make\n\t$(MAKE) -C bash install\n\trm -f $(DESTDIR)$(PREFIX)/bin/dgsh\n\tln $(DESTDIR)$(DGSHPATH)/bash $(DESTDIR)$(PREFIX)/bin/dgsh || install $(DESTDIR)$(DGSHPATH)/bash $(DESTDIR)$(PREFIX)/bin/dgsh\n\t$(MAKE) -C coreutils install\n\t$(MAKE) -C grep install\n\t# Install last to overwrite standard tools of coreutils\n\tinstall cat $(DESTDIR)$(DGSHPATH)\n\tinstall cmp $(DESTDIR)$(DGSHPATH)\n\tinstall diff $(DESTDIR)$(DGSHPATH)\n\tinstall diff3 $(DESTDIR)$(DGSHPATH)\n\tinstall tee $(DESTDIR)$(DGSHPATH)\n\t./install-wrapped.sh\n\trm -rf $(DESTDIR)$(MANDUMPDIR)\n\ncat: cat.sh\n\tinstall $? $@\n\ncmp: cmp.sh\n\tinstall $? $@\n\ndiff: diff.sh\n\tinstall $? $@\n\ndiff3: diff3.sh\n\tinstall $? $@\n\ntee: tee.sh\n\tinstall $? $@\n\ntest: test-bash test-compat\n\npath:\n\texport PATH\n\techo $(PATH)\n\n../test-data/fid:\n\twget -O $@ $(FID) || curl $(FID) >$@\n\ntest-compat: dgsh-compat\n\t./test-compat.sh\n\ndgsh-compat: bash/dgsh_util.c\n\tcc -o $@ $(INCPATHS) -DDGSH_COMPAT $?\n\ntest-bash: ../test-data/fid\n\n\trm -f $(PSDIR)/*.out $(PSDIR)/*.outb\n\tprintf \"$B\\nBash tests:${EC}\\n\"\n\n\t./run_all_simple_tests.sh $(PSDIR)\n\n\tprintf \" $BPaper examples under ../example:${EC}\\n\"\n\n\t# No diff, just check execution exit status\n\t./run_test.sh $(PSDIR) $(EGDIR)/dir.sh 0\n\t./run_test.sh $(PSDIR) $(EGDIR)/reorder-columns.sh pipe $(PSDIR)/data.csv\n\t# TODO reinstate after fixin it\n\t# ./run_test.sh $(PSDIR) $(EGDIR)/set-operations.sh file $(PSDIR)\n\t./run_test.sh $(PSDIR) $(EGDIR)/compress-compare.sh pipe Readme.md\n\t# TODO check that .git repo exists\n\t./run_test.sh $(PSDIR) $(EGDIR)/commit-stats.sh\n\tDGSH_TIMEOUT=20 ./run_test.sh $(PSDIR) $(EGDIR)/uniform-5x5.sh\n\t./run_test.sh $(PSDIR) $(EGDIR)/duplicate-files.sh file coreutils\n\t./run_test.sh $(PSDIR) $(EGDIR)/spell-highlight.sh pipe Readme.md\n\t./run_test.sh $(PSDIR) $(EGDIR)/static-functions.sh file coreutils\n\t./run_test.sh $(PSDIR) $(EGDIR)/word-properties.sh file Readme.md\n\t./run_test.sh $(PSDIR) $(EGDIR)/map-hierarchy.sh file ../core-tools/tests-regression/map-hierarchy/in/a ../core-tools/tests-regression/map-hierarchy/in/b c\n\t./run_test.sh $(PSDIR) $(EGDIR)/text-properties.sh pipe Readme.md\n\tcd coreutils && \\\n\t../run_test.sh ../$(PSDIR) ../$(EGDIR)/committer-plot.sh -- pnmtopng pamscale pgmmorphconv\n\tDGSH_TIMEOUT=60 ./run_test.sh $(PSDIR) $(EGDIR)/code-metrics.sh file coreutils/src\n\tKVSTORE_RETRY_LIMIT=100 DGSH_TIMEOUT=100 ./run_test.sh $(PSDIR) $(EGDIR)/web-log-report.sh pipe $(PSDIR)/access.log\n\t./run_test.sh $(PSDIR) $(EGDIR)/fft-block8.sh file $(PSDIR)/fft-input.dat\n\t./run_test.sh $(PSDIR) $(EGDIR)/ft2d.sh -- sfimag sfgrey sfspike sfput sfmath \\\n\t\t\t\t\tsfspray sffft1 sffft3 sfcat sflmostretch \\\n\t\t\t\t\tsfreverse sfwindow vppen sfsmooth\n\t# Requires file fid in $(PSDIR). See $(EGDIR)/NMRPipe.sh\n\t./run_test.sh $(PSDIR) $(EGDIR)/NMRPipe.sh file $(PSDIR)/fid -- nmrPipe addNMR\n\nclean:\n\t$(MAKE) -C bash clean\n\t$(MAKE) -C coreutils clean\n\t$(MAKE) -C grep clean\n"
  },
  {
    "path": "unix-tools/Readme.md",
    "content": "## Installation of unix tools adapted for dgsh\n\nWhile under the dgsh root directory, type the following sequence of commands:\n\n```bash\nmake libdgsh.a # compile the dgsh negotiation library\ncd unix-tools\nmake get-submodules   # download repos of Unix tools if not already cloned\n                      # with the superproject through --recursive\nmake configure        # configure tools\nmake make             # compile\nmake install          # install in ./bin\nmake -s test          # run tests\n```\n\nThe current collection of Unix tools include *coreutils, gawk, grep, parallel, sed, and tar*.\nOf those currently *comm*, *join*, *paste*, and *sort* have been adapted for use with dgsh.\n\n## Adaptation workflow\n\nHead to the tool's repo, e.g., unix-tools/coreutils and locate its source code, e.g., src/comm.c\n\nThe workflow includes the following steps:\n\n- adapt the tool for use with dgsh\n  - invoke the dgsh negotiation API similarly to the code that follows\n  - use the provided file descriptors in place of the tool's original input and output interface. You can take a look at the already adapted tools source.\n\n```C\n#include <stdio.h>\t\t/* printf() */\n#include <stdlib.h>\t\t/* exit() */\n#include \"dgsh.h\"\n\nint\nmain(int argc, char *argv[])\n{\n\tif (dgsh_negotiate(\"secho\", NULL, NULL, NULL, NULL) != 0)\n\t\texit(1);\n\n\t++argv;\n\twhile (*argv) {\n\t\t(void)printf(\"%s\", *argv);\n\t\tif (*++argv)\n\t\t\tputchar(' ');\n\t}\n\tputchar('\\n');\n\n\treturn 0;\n}\n```\n\n- contribute tests\n  - *cd simple_shell*\n  - express a graph of dgsh adapted processes with interconnected inputs and outputs, such as the example that follows. The example has the secho and paste tools connect the former's output to the latter's input. Because they are both dgsh-compatible they use a socketpipe to carry out the dgsh negotiation phase. You can find this file as *secho_paste.dgsh*.\n  - run the test with *python simple_shell.py secho_paste.dgsh secho_paste.out* to produce and store the output in file *secho_paste.out*.\n\n```bash\n1 /home/mfg/dds/dgsh/unix-tools/bin/secho hello\n2 /home/mfg/dds/dgsh/unix-tools/bin/paste - world\n\n%\nsocketpipe 1 2\n```\n\n- add tests to Makefile's *make test* recipe\n\n```Makefile\nPSEUDOSHELLDIR=../simple-shell\n\ntest:\n    cd $PSEUDOSHELLDIR && \\\n    python simple-shell.py secho_paste.dgsh secho_paste.out && \\\n    diff secho_paste.out secho_paste.success && \\\n    echo \"Test secho | paste successful.\" || \\\n    echo \"Test secho | paste failed.\"\n```\n\n- run tests\n```bash\nmake -s test\n```\n"
  },
  {
    "path": "unix-tools/cat.sh",
    "content": "#!/usr/bin/env bash\n#!dgsh\n#\n# Implementation of POSIX tee through dgsh-tee\n#\n\nusage()\n{\n  echo 'Usage: cat [-u] [file ...]' 1>&2\n  exit 2\n}\n\nwhile getopts 'u' o; do\n  case \"$o\" in\n    u)\n      ;;\n    *)\n      usage\n      ;;\n  esac\ndone\n\nshift $((OPTIND-1))\n\ndeclare -a opts\n\n# Process file arguments\nfor i; do\n    opts+=('-i' \"$i\")\n    shift\ndone\n\nexec dgsh-tee \"${opts[@]}\"\n"
  },
  {
    "path": "unix-tools/cmp.sh",
    "content": "#!/usr/bin/env bash\n#!dgsh\n#\n# Dgsh-compatible wrapping of the GNU cmp command\n# Depending on the arguments, the command can accept 0-2 inputs\n#\n\n\noopt=''\n\n# For the parsing of long options see\n# https://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-options/7680682#7680682\noptspec=\":bi:ln:sv-:\"\nwhile getopts \"$optspec\" optchar; do\n  case \"${optchar}\" in\n    -)\n      case \"${OPTARG}\" in\n        quiet)\n          oopt='-o 0'\n          ;;\n        silent)\n          oopt='-o 0'\n          ;;\n\t# Long options with mandatory arguments. In these the argument\n\t# can appear separated from the option name, and must be removed.\n\tignore-initial|bytes)\n\t  OPTIND=$(($OPTIND + 1))\n\t  ;;\n      esac\n      ;;\n    s)\n      oopt='-o 0'\n      ;;\n  esac\ndone\n\n# Examine the number of remaining (non-option) arguments\ncase $(($# - $OPTIND + 1)) in\n  0)\n    # Exactly two inputs are required\n    exec dgsh-wrap $oopt /usr/bin/cmp \"$@\" '<|' '<|'\n    ;;\n  1)\n    if [[ \"${!OPTIND}\" == '-' ]] ; then\n      # One (non-stdin) input is required\n      exec dgsh-wrap -I $oopt /usr/bin/cmp \"$@\" '<|'\n    else\n      # One (stdin) input is required\n      exec dgsh-wrap $oopt /usr/bin/cmp \"$@\" -\n    fi\n    ;;\n  *)\n    ARG2=$((OPTIND + 1))\n    if [[ \"${!OPTIND}\" == '-' ]] || [[ \"${!ARG2}\" == '-' ]] ; then\n      # One (stdin) input is required\n      exec dgsh-wrap /usr/bin/cmp $oopt \"$@\"\n    else\n      # No input is required\n      exec dgsh-wrap -i 0 /usr/bin/cmp $oopt \"$@\"\n    fi\n    ;;\nesac\n"
  },
  {
    "path": "unix-tools/cpow.c",
    "content": "/* $NetBSD: cpow.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */\n\n/*-\n * Copyright (c) 2007 The NetBSD Foundation, Inc.\n * All rights reserved.\n *\n * This code is derived from software written by Stephen L. Moshier.\n * It is redistributed by the NetBSD Foundation by permission of the author.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\n * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\n * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <complex.h>\n#include <math.h>\n\ndouble complex\ncpow(double complex a, double complex z)\n{\n\tdouble complex w;\n\tdouble x, y, r, theta, absa, arga;\n\n\tx = creal(z);\n\ty = cimag(z);\n\tabsa = cabs(a);\n\tif (absa == 0.0) {\n\t\treturn (0.0 + 0.0 * I);\n\t}\n\targa = carg(a);\n\tr = pow(absa, x);\n\ttheta = x * arga;\n\tif (y != 0.0) {\n\t\tr = r * exp(-y * arga);\n\t\ttheta = theta + y * log(absa);\n\t}\n\tw = r * cos(theta) + (r * sin(theta)) * I;\n\treturn w;\n}\n"
  },
  {
    "path": "unix-tools/cygwin-sys-select-patch.sh",
    "content": "#!/bin/sh\n#\n# Patch gnulib to compile under Cygwin\n# Must be executed after bootstrapping and before configuring gnulib\n#\n# See https://github.com/stilor/crosstool-ng/blob/f6ea9a68b26830f72f8f5242aba9b950f2e4da78/patches/gettext/0.19.7/140-Fix-Cygwin-sys-select.patch\n\n# Exit unless running under Cygwin\nuname -o | grep -q Cygwin || exit 0\n\n# Patch the bootstrapped gnulib\npatch lib/sys_select.in.h <<\\EOF\ndiff --git a/gettext-tools/gnulib-lib/sys_select.in.h b/gettext-tools/gnulib-lib/sys_select.in.h\nindex d6d3f9f..7281144 100644\n--- a/gettext-tools/gnulib-lib/sys_select.in.h\n+++ b/gettext-tools/gnulib-lib/sys_select.in.h\n@@ -81,8 +81,9 @@\n    of 'struct timeval', and no definition of this type.\n    Also, Mac OS X, AIX, HP-UX, IRIX, Solaris, Interix declare select()\n    in <sys/time.h>.\n-   But avoid namespace pollution on glibc systems.  */\n-# ifndef __GLIBC__\n+   But avoid namespace pollution on glibc systems and \"unknown type\n+   name\" problems on Cygwin.  */\n+# if !(defined __GLIBC__ || defined __CYGWIN__)\n #  include <sys/time.h>\n # endif\n \n@@ -100,10 +101,11 @@\n #endif\n \n /* Get definition of 'sigset_t'.\n-   But avoid namespace pollution on glibc systems.\n+   But avoid namespace pollution on glibc systems and \"unknown type\n+   name\" problems on Cygwin.\n    Do this after the include_next (for the sake of OpenBSD 5.0) but before\n    the split double-inclusion guard (for the sake of Solaris).  */\n-#if !(defined __GLIBC__ && !defined __UCLIBC__)\n+#if !((defined __GLIBC__ || defined __CYGWIN__) && !defined __UCLIBC__)\n # include <signal.h>\n #endif\n \nEOF\n"
  },
  {
    "path": "unix-tools/diff.sh",
    "content": "#!/usr/bin/env bash\n#!dgsh\n#\n# Dgsh-compatible wrapping of the GNU diff command\n# Depending on the arguments, the command can accept 0-N inputs\n#\n\n\n# For the parsing of long options see\n# https://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-options/7680682#7680682\noptspec=\":qscC:uU:enyW:pF:tTlrNx:X:S:iEZbwBIaD:dv-:\"\nwhile getopts \"$optspec\" optchar; do\n  case \"${optchar}\" in\n    -)\n      case \"${OPTARG}\" in\n        from-file)\n          from_file=\"${!OPTIND}\"\n\t  OPTIND=$(($OPTIND + 1))\n          ;;\n        from-file=*)\n\t  from_file=${OPTARG#*=}\n\t  ;;\n        to-file)\n          to_file=\"${!OPTIND}\"\n\t  OPTIND=$(($OPTIND + 1))\n          ;;\n        to-file=*)\n\t  to_file=${OPTARG#*=}\n\t  ;;\n\t# Long options with mandatory arguments. In these the argument\n\t# can appear separated from the option name, and must be removed.\n\twidth|show-function-line|label|tabsize|exclude|exclude-from|starting-file|ignore-matching-lines|ifdef|GTYPE-group-format|line-format|LTYPE-line-format|horizon-lines|palette)\n\t  OPTIND=$(($OPTIND + 1))\n\t  ;;\n      esac\n      ;;\n  esac\ndone\n\n# Examine the number of remaining (non-option) arguments\ncase $(($# - $OPTIND + 1)) in\n  0)\n    if [[ -n \"$from_file\" ]] || [[ -n \"$to_file\" ]] ; then\n      # An arbitrary number of inputs can be handled\n      exec dgsh-wrap -i a /usr/bin/diff \"$@\"\n    else\n      # Exactly two inputs are required\n      exec dgsh-wrap /usr/bin/diff \"$@\" '<|' '<|'\n    fi\n    ;;\n  1)\n    if [[ -n \"$from_file\" ]] || [[ -n \"$to_file\" ]] ; then\n      # No input is required\n      exec dgsh-wrap -i 0 /usr/bin/diff \"$@\"\n    elif [[ \"${!OPTIND}\" == '-' ]] ; then\n      # One (non-stdin) input is required\n      exec dgsh-wrap -I /usr/bin/diff \"$@\" '<|'\n    else\n      # One (stdin) input is required\n      exec dgsh-wrap /usr/bin/diff \"$@\" -\n    fi\n    ;;\n  *)\n    ARG2=$((OPTIND + 1))\n    if [[ \"${!OPTIND}\" == '-' ]] || [[ \"${!ARG2}\" == '-' ]] ; then\n      # One (stdin) input is required\n      exec dgsh-wrap /usr/bin/diff \"$@\"\n    else\n      # No input is required\n      exec dgsh-wrap -i 0 /usr/bin/diff \"$@\"\n    fi\n    ;;\nesac\n"
  },
  {
    "path": "unix-tools/diff3.sh",
    "content": "#!/usr/bin/env bash\n#!dgsh\n#\n# Dgsh-compatible wrapping of the GNU diff3 command\n# Depending on the arguments, the command can accept 0-3 inputs\n#\n\n\n# For the parsing of long options see\n# https://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-options/7680682#7680682\noptspec=\":AeE3xXimaTL:v-:\"\nwhile getopts \"$optspec\" optchar; do\n  case \"${optchar}\" in\n    -)\n      case \"${OPTARG}\" in\n\t# Long options with mandatory arguments. In these the argument\n\t# can appear separated from the option name, and must be removed.\n\tdiff-program|label)\n\t  OPTIND=$(($OPTIND + 1))\n\t  ;;\n      esac\n      ;;\n  esac\ndone\n\n# Examine the number of remaining (non-option) arguments\ncase $(($# - $OPTIND + 1)) in\n  0)\n    # Exactly three inputs are required\n    exec dgsh-wrap /usr/bin/diff3 \"$@\" '<|' '<|' '<|'\n    ;;\n  1)\n    if [[ \"${!OPTIND}\" = '-' ]] ; then\n      # Two inputs (excluding stdin) are required\n      exec dgsh-wrap -I /usr/bin/diff3 \"$@\" '<|' '<|'\n    else\n      # Two inputs (including stdin) are required\n      exec dgsh-wrap /usr/bin/diff3 \"$@\" '<|' '<|'\n    fi\n    ;;\n  2)\n    ARG2=$((OPTIND + 1))\n    if [[ \"${!OPTIND}\" = '-' ]] || [[ \"${!ARG2}\" = '-' ]] ; then\n      # One (non-stdin) input is required\n      exec dgsh-wrap -I /usr/bin/diff3 \"$@\" '<|'\n    else\n      # One (stdin) input is required\n      exec dgsh-wrap /usr/bin/diff3 \"$@\" -\n    fi\n    ;;\n  *)\n    ARG2=$((OPTIND + 1))\n    ARG3=$((OPTIND + 2))\n    if [[ \"${!OPTIND}\" = '-' ]] || [[ \"${!ARG2}\" = '-' ]] || [[ \"${!ARG3}\" = '-' ]] ; then\n      # One (stdin) input is required\n      exec dgsh-wrap /usr/bin/diff3 \"$@\"\n    else\n      # No input is required\n      exec dgsh-wrap -i 0 /usr/bin/diff3 \"$@\"\n    fi\n    ;;\nesac\n"
  },
  {
    "path": "unix-tools/echo_echo_dgsh-tee.sh",
    "content": "{{\n\techo hello &\n\techo world &\n}} | dgsh-tee\n"
  },
  {
    "path": "unix-tools/install-wrapped.sh",
    "content": "#!/bin/sh\n#\n# Install the commands wrapped by dgsh-wrap\n#\n\nif [ \"$1\" = \"\" ] ; then\n\tDGPATH=$DESTDIR$PREFIX/libexec/dgsh\n\tmkdir -p $DGPATH\nelse\n\tDGPATH=$1/libexec/dgsh\n\tmkdir -p $DGPATH\nfi\n\n# Remove comments and blank lines\nsed 's/[ \\t]*#.*//;/^$/d' wrapped-commands-posix wrapped-commands-tests |\nwhile read mode name ; do\n  # Continue if command is not available\n  if ! which $name 2>/dev/null >/dev/null ; then\n    continue\n  fi\n\n  # Continue if command is custom-implemented or both deaf and mute\n  if [ $mode = c -o $mode = dm ] ; then\n    continue\n  fi\n\n  # Iterate over the mode's characters creating $opt\n  opt=' -s'\n  for m in $(echo \"$mode\" | sed 's/./& /g') ; do\n    case $m in\n      m)\t# Mute\n\topt=\"$opt -o 0\"\n\t;;\n      M)\t# Mute unless - is specified (TODO)\n\t;;\n      d)\t# Deaf\n\topt=\"$opt -i 0\"\n\t;;\n      I)\t# Count stdin in channel assignments\n\topt=\"$opt -I\"\n\t;;\n      D)\t# Deaf unless - is specified or no arguments are provided (TODO)\n\t;;\n      f)\t# Filter\n\t;;\n      *)\n\techo \"Unknown I/O mode character $m for $name\" 1>&2\n\texit 1\n    esac\n  done\n  target=$DGPATH/$name\n  echo \"#!$DGPATH/dgsh-wrap$opt\" >$target\n  chmod 755 $target\ndone\n"
  },
  {
    "path": "unix-tools/run_all_simple_tests.sh",
    "content": "#!/bin/sh\n\nPSDIR=$1\n\nset -e\n\n./run_simple_test.sh $PSDIR multipipe_one_last \\\n\t'cat /dev/null | {{ cat  & }}'\n\n./run_simple_test.sh $PSDIR multipipe_one_start \\\n\t'{{ cat /dev/null & }} | cat'\n\nCAT=`which cat`\n./run_simple_test.sh $PSDIR function_bash_tools \\\n\t\"function h\n\t{\n\t\t$CAT | $CAT\n\t}\n\n\tfunction g\n\t{\n\t\t$CAT | h | $CAT\n\t}\n\n\t$CAT /dev/null | g\"\n\n./run_simple_test.sh $PSDIR function_dgsh_tools \\\n\t'function h\n\t{\n\t\tcat | cat\n\t}\n\n\tfunction g\n\t{\n\t\tcat | h | cat\n\t}\n\n\tcat /dev/null | g'\n\n./run_simple_test.sh $PSDIR read_while \\\n\t'echo \"hi\nthere\" |\n\twhile read X; do echo $X; done'\n\n./run_simple_test.sh $PSDIR subshell \\\n\t\"(echo a) |\n\tcat\"\n\n./run_simple_test.sh $PSDIR group \\\n\t\"{ echo a ;} |\n\tcat\"\n\n./run_simple_test.sh $PSDIR recursive_multipipe_oneline_start \\\n\t\"{{ {{ echo hello ; }} | cat ; echo world ; }} | cat\"\n\n./run_simple_test.sh $PSDIR recursive_multipipe_oneline_end \\\n\t\"{{ echo world ; {{ echo hello ; }} | cat ; }} | cat\"\n\n./run_simple_test.sh $PSDIR nondgsh \\\n\t\"true || false\n\tdgsh-enumerate 2 | cat\"\n\n./run_simple_test.sh $PSDIR secho_paste \\\n\t\"dgsh-pecho hello |\n\tpaste $PSDIR/world\"\n\n./run_simple_test.sh $PSDIR wrap-cat_comm_sort \\\n\t\"cat $PSDIR/f1s |\n\tcomm $PSDIR/f2s |\n\tsort |\n\twc -l |\n\ttr -d \\\" \\\"\"\n\n./run_simple_test.sh $PSDIR comm_sort \\\n\t\"comm $PSDIR/f1s $PSDIR/f2s |\n\tsort |\n\twc -l |\n\ttr -d \\\" \\\"\"\n\n./run_simple_test.sh $PSDIR comm_paste \\\n\t\"comm $PSDIR/f1s $PSDIR/f2s |\n\tpaste\"\n\n./run_simple_test.sh $PSDIR join_sort \\\n\t\"join $PSDIR/f1s $PSDIR/f2s |\n\tsort\"\n\n./run_simple_test.sh $PSDIR paste_diff \\\n\t\"paste $PSDIR/f1s $PSDIR/f2s |\n\tdiff $PSDIR/f1s |\n\tcat\"\n\n#./run_simple_test.sh $(DGSHPATH) $PSDIR grep_diff \\\n#\t\"grep -v -w match $PSDIR/F $PSDIR/ff \\\n#\t| diff\"\n\n./run_simple_test.sh $PSDIR grep_comm \\\n\t\"grep -l -L match $PSDIR/ff $PSDIR/F |\n\tcomm |\n\tpaste\"\n\n./run_simple_test.sh $PSDIR join_sort_diff \\\n\t\"join $PSDIR/f1s $PSDIR/f2s |\n\tsort |\n\tdiff $PSDIR/f3s |\n\tcat\"\n\n# `date`: Check that command substitution\n# does not mess pipe substitution\n./run_simple_test.sh $PSDIR secho_secho_fgrep \\\n\t\"{{\n\t\tdgsh-pecho match\n\t\tdgsh-pecho \\\"not `date`\\\"\n\t}} |\n\tgrep -F -h match\"\n\n./run_simple_test.sh $PSDIR tee-copy_diff_comm \\\n\t\"tee <$PSDIR/hello |\n\t{{\n\t\tdiff $PSDIR/world\n\t\tcomm $PSDIR/hello\n\t}} |\n\tcat\"\n\n# ditto\n#./run_simple_test.sh $(DGSHPATH) $PSDIR grep_diff_comm \\\n#\t\"grep -l -L -w -v match $PSDIR/ff $PSDIR/F \\\n#\t| {{ \\\n#\t\tdiff & \\\n#\t\tcomm & \\\n#\t}}\"\n\n./run_simple_test.sh $PSDIR comm_paste_join_diff \\\n\t\"comm $PSDIR/f4ss $PSDIR/f5ss |\n\t{{\n\t\tpaste $PSDIR/p1\n\t\tjoin $PSDIR/j2\n\t\tdiff $PSDIR/d3\n\t}} |\n\tcat\"\n\n./run_simple_test.sh $PSDIR sort_sort_comm \\\n\t\"{{\n\t\tsort $PSDIR/f4s 2>$PSDIR/f4s.errb\n\t\tsort $PSDIR/f5s 2>$PSDIR/f5s.errb\n\t}} |\n\tcomm |\n\tcat\"\n\n./run_simple_test.sh $PSDIR sort_sort_comm_paste_join_diff \\\n\t\"{{\n\t\tsort $PSDIR/f4s\n\t\tsort $PSDIR/f5s\n\t}} |\n\tcomm |\n\t{{\n\t\tpaste $PSDIR/p1\n\t\tjoin $PSDIR/j2\n\t\tdiff $PSDIR/d3\n\t}} |\n\tcat\"\n\n# Wrapped diff\n./run_simple_test.sh $PSDIR diff4 '! dgsh-enumerate 4 | diff -w --label foo --to-file=/dev/null'\n./run_simple_test.sh $PSDIR diff2 '! dgsh-enumerate 2 | diff -w --label foo'\n./run_simple_test.sh $PSDIR diff1 '! dgsh-enumerate 1 | diff -w --label foo /dev/null'\n./run_simple_test.sh $PSDIR diff1-stdin '! dgsh-enumerate 2 | diff -w --label foo -'\n./run_simple_test.sh $PSDIR diff0 'diff -w --label foo /dev/null /dev/null'\n./run_simple_test.sh $PSDIR diff0-stdin1 '! dgsh-enumerate 1 | diff -w --label foo - /dev/null'\n./run_simple_test.sh $PSDIR diff0-stdin2 '! dgsh-enumerate 1 | diff -w --label foo /dev/null -'\n./run_simple_test.sh $PSDIR diff0-noin '! dgsh-enumerate 1 | diff -w --label foo /dev/null /dev/null'\n\n# Wrapped cmp\n./run_simple_test.sh $PSDIR cmp2-same '{{ echo a ; echo a ; }} | cmp'\n./run_simple_test.sh $PSDIR cmp2-diff '! {{ echo a ; echo b ; }} | cmp -s'\n./run_simple_test.sh $PSDIR cmp1-same1 'echo -n | cmp - /dev/null'\n./run_simple_test.sh $PSDIR cmp1-same2 'echo -n | cmp /dev/null -'\n./run_simple_test.sh $PSDIR cmp0 'cmp /dev/null /dev/null'\n\n# Wrapped diff3\n./run_simple_test.sh $PSDIR diff3-3 '{{ echo a ; echo b ; echo c; }} | diff3'\n./run_simple_test.sh $PSDIR diff3-2 '{{ echo a ; echo b ; }} | diff3 /dev/null'\n./run_simple_test.sh $PSDIR diff3-2-stdin1 '{{ echo a ; echo b ; }} | diff3 - /dev/null'\n./run_simple_test.sh $PSDIR diff3-2-stdin2 '{{ echo a ; echo b ; }} | diff3 /dev/null -'\n./run_simple_test.sh $PSDIR diff3-1 '{{ echo a ; }} | diff3 /dev/null /dev/null'\n./run_simple_test.sh $PSDIR diff3-0 'diff3 /dev/null /dev/null /dev/null'\n\n# grep\n\n# Single arg\n./run_simple_test.sh $PSDIR grep-noargs 'echo hi | grep .'\n./run_simple_test.sh $PSDIR grep-noargs-cat 'echo hi | grep . | cat'\n./run_simple_test.sh $PSDIR grep-matching-lines 'echo hi | grep --matching-lines .'\n./run_simple_test.sh $PSDIR grep-matching-lines-cat 'echo hi | grep --matching-lines . | cat'\n./run_simple_test.sh $PSDIR grep-f 'echo hi | grep -f <(echo .)'\n./run_simple_test.sh $PSDIR grep-f-cat 'echo hi | grep -f <(echo .) | cat'\n./run_simple_test.sh $PSDIR grep-c 'echo hi | grep -c . '\n./run_simple_test.sh $PSDIR grep-c-cat 'echo hi | grep -c . | cat'\n./run_simple_test.sh $PSDIR grep-l 'echo hi | grep -l . '\n./run_simple_test.sh $PSDIR grep-l-cat 'echo hi | grep -l . | cat'\n./run_simple_test.sh $PSDIR grep-Lcap 'echo hi | grep -L hi'\n./run_simple_test.sh $PSDIR grep-Lcap-nomatch 'echo hi | grep -L hello | cat'\n./run_simple_test.sh $PSDIR grep-Lcap-cat 'echo hi | grep -L . | cat'\n./run_simple_test.sh $PSDIR grep-Lcap-cat-nomatch 'echo hi | grep -L hello | cat'\n./run_simple_test.sh $PSDIR grep-o 'echo hi | grep -o hi'\n./run_simple_test.sh $PSDIR grep-o-cat 'echo hi | grep -o hi | cat'\n./run_simple_test.sh $PSDIR grep-v 'echo hi | grep -v hello | cat'\n./run_simple_test.sh $PSDIR grep-v-cat 'echo hi | grep -v hello | cat'\n\n# Double args\n./run_simple_test.sh $PSDIR grep-matching-lines-c 'echo hi | grep --matching-lines -c . | cat'\n./run_simple_test.sh $PSDIR grep-matching-lines-l 'echo hi | grep --matching-lines -l . | cat'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap 'echo hi | grep --matching-lines -L . | cat'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap-nomatch 'echo hi | grep --matching-lines -L hello | paste'\n\n./run_simple_test.sh $PSDIR grep-c-matching-lines 'echo hi | grep -c --matching-lines . | cat'\n./run_simple_test.sh $PSDIR grep-c-l 'echo hi | grep -c -l . | cat'\n./run_simple_test.sh $PSDIR grep-c-Lcap 'echo hi | grep -c -L . | paste'\n./run_simple_test.sh $PSDIR grep-c-Lcap-nomatch 'echo hi | grep -c -L hello | paste'\n\n./run_simple_test.sh $PSDIR grep-l-matching-lines 'echo hi | grep -l --matching-lines . | cat'\n./run_simple_test.sh $PSDIR grep-l-c 'echo hi | grep -l -c . | cat'\n./run_simple_test.sh $PSDIR grep-l-Lcap 'echo hi | grep -l -L . | paste'\n./run_simple_test.sh $PSDIR grep-l-Lcap-nomatch 'echo hi | grep -l -L hello | paste'\n\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines 'echo hi | grep -L --matching-lines . | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines-nomatch 'echo hi | grep -L --matching-lines hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-c 'echo hi | grep -L -c . | cat'\n./run_simple_test.sh $PSDIR grep-Lcap-c-nomatch 'echo hi | grep -L -c hello | cat'\n./run_simple_test.sh $PSDIR grep-Lcap-l 'echo hi | grep -L -l . | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-l-nomatch 'echo hi | grep -L -l hello | paste'\n\n# Triple args\n./run_simple_test.sh $PSDIR grep-matching-lines-c-l 'echo hi | grep --matching-lines -c -l hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-c-Lcap 'echo hi | grep --matching-lines -c -L hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-c-Lcap-nomatch 'echo hi | grep --matching-lines -c -L hello | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-l-c 'echo hi | grep --matching-lines -l -c hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-l-Lcap 'echo hi | grep --matching-lines -l -L hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-l-Lcap-nomatch 'echo hi | grep --matching-lines -l -L hello | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap-c 'echo hi | grep --matching-lines -L -c hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap-c-nomatch 'echo hi | grep --matching-lines -L -c hello | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap-l 'echo hi | grep --matching-lines -L -l hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap-l-nomatch 'echo hi | grep --matching-lines -L -l hello | paste'\n\n./run_simple_test.sh $PSDIR grep-c-matching-lines-l 'echo hi | grep -c --matching-lines -l hi | paste'\n./run_simple_test.sh $PSDIR grep-c-matching-lines-Lcap 'echo hi | grep -c --matching-lines -L hi | paste'\n./run_simple_test.sh $PSDIR grep-c-matching-lines-Lcap-nomatch 'echo hi | grep -c --matching-lines -L hello | paste'\n./run_simple_test.sh $PSDIR grep-c-l-matching-lines 'echo hi | grep -c -l --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-c-l-Lcap 'echo hi | grep -c -l -L hi | paste'\n./run_simple_test.sh $PSDIR grep-c-l-Lcap-nomatch 'echo hi | grep -c -l -L hello | paste'\n./run_simple_test.sh $PSDIR grep-c-Lcap-matching-lines 'echo hi | grep -c -L --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-c-Lcap-matching-lines-nomatch 'echo hi | grep -c -L --matching-lines hello | paste'\n./run_simple_test.sh $PSDIR grep-c-Lcap-l 'echo hi | grep -c -L -l hi | paste'\n./run_simple_test.sh $PSDIR grep-c-Lcap-l-nomatch 'echo hi | grep -c -L -l hello | paste'\n\n./run_simple_test.sh $PSDIR grep-l-matching-lines-c 'echo hi | grep -l --matching-lines -c hi | paste'\n./run_simple_test.sh $PSDIR grep-l-matching-lines-Lcap 'echo hi | grep -l --matching-lines -L hi | paste'\n./run_simple_test.sh $PSDIR grep-l-matching-lines-Lcap-nomatch 'echo hi | grep -l --matching-lines -L hello | paste'\n./run_simple_test.sh $PSDIR grep-l-c-matching-lines 'echo hi | grep -l -c --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-l-c-Lcap 'echo hi | grep -l -c -L hi | paste'\n./run_simple_test.sh $PSDIR grep-l-c-Lcap-nomatch 'echo hi | grep -l -c -L hello | paste'\n./run_simple_test.sh $PSDIR grep-l-Lcap-matching-lines 'echo hi | grep -l -L --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-l-Lcap-matching-lines-nomatch 'echo hi | grep -l -L --matching-lines hello | paste'\n./run_simple_test.sh $PSDIR grep-l-Lcap-c 'echo hi | grep -l -L -c hi | paste'\n./run_simple_test.sh $PSDIR grep-l-Lcap-c-nomatch 'echo hi | grep -l -L -c hello | paste'\n\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines-c 'echo hi | grep -L --matching-lines -c hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines-c-nomatch 'echo hi | grep -L --matching-lines -c hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines-l 'echo hi | grep -L --matching-lines -l hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines-l-nomatch 'echo hi | grep -L --matching-lines -l hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-c-matching-lines 'echo hi | grep -L -c --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-c-matching-lines-nomatch 'echo hi | grep -L -c --matching-lines hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-c-l 'echo hi | grep -L -c -l hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-c-l-nomatch 'echo hi | grep -L -c -l hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-l-matching-lines 'echo hi | grep -L -l --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-l-matching-lines-nomatch 'echo hi | grep -L -l --matching-lines hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-l-c 'echo hi | grep -L -l -c hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-l-c-nomatch 'echo hi | grep -L -l -c hello | paste'\n\n# Quadraple args\n./run_simple_test.sh $PSDIR grep-matching-lines-c-l-Lcap 'echo hi | grep --matching-lines -c -l -L hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-c-Lcap-l 'echo hi | grep --matching-lines -c -L -l hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-l-c-Lcap 'echo hi | grep --matching-lines -l -c -L hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-l-Lcap-c 'echo hi | grep --matching-lines -l -L -c hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap-c-l 'echo hi | grep --matching-lines -L -c -l hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap-l-c 'echo hi | grep --matching-lines -L -l -c hi | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-c-l-Lcap-nomatch 'echo hi | grep --matching-lines -c -l -L hello | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-c-Lcap-l-nomatch 'echo hi | grep --matching-lines -c -L -l hello | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-l-c-Lcap-nomatch 'echo hi | grep --matching-lines -l -c -L hello | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-l-Lcap-c-nomatch 'echo hi | grep --matching-lines -l -L -c hello | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap-c-l-nomatch 'echo hi | grep --matching-lines -L -c -l hello | paste'\n./run_simple_test.sh $PSDIR grep-matching-lines-Lcap-l-c-nomatch 'echo hi | grep --matching-lines -L -l -c hello | paste'\n\n./run_simple_test.sh $PSDIR grep-c-matching-lines-l-Lcap 'echo hi | grep -c --matching-lines -l -L hi | paste'\n./run_simple_test.sh $PSDIR grep-c-matching-lines-Lcap-l 'echo hi | grep -c --matching-lines -L -l hi | paste'\n./run_simple_test.sh $PSDIR grep-c-l-matching-lines-Lcap 'echo hi | grep -c -l --matching-lines -L hi | paste'\n./run_simple_test.sh $PSDIR grep-c-l-Lcap-matching-lines 'echo hi | grep -c -l -L --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-c-Lcap-matching-lines-l 'echo hi | grep -c -L --matching-lines -l hi | paste'\n./run_simple_test.sh $PSDIR grep-c-Lcap-l-matching-lines 'echo hi | grep -c -L -l --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-c-matching-lines-l-Lcap-nomatch 'echo hi | grep -c --matching-lines -l -L hello | paste'\n./run_simple_test.sh $PSDIR grep-c-matching-lines-Lcap-l-nomatch 'echo hi | grep -c --matching-lines -L -l hello | paste'\n./run_simple_test.sh $PSDIR grep-c-l-matching-lines-Lcap-nomatch 'echo hi | grep -c -l --matching-lines -L hello | paste'\n./run_simple_test.sh $PSDIR grep-c-l-Lcap-matching-lines-nomatch 'echo hi | grep -c -l -L --matching-lines hello | paste'\n./run_simple_test.sh $PSDIR grep-c-Lcap-matching-lines-l-nomatch 'echo hi | grep -c -L --matching-lines -l hello | paste'\n./run_simple_test.sh $PSDIR grep-c-Lcap-l-matching-lines-nomatch 'echo hi | grep -c -L -l --matching-lines hello | paste'\n\n./run_simple_test.sh $PSDIR grep-l-matching-lines-c-Lcap 'echo hi | grep -l --matching-lines -c -L hi | paste'\n./run_simple_test.sh $PSDIR grep-l-matching-lines-Lcap-c 'echo hi | grep -l --matching-lines -L -c hi | paste'\n./run_simple_test.sh $PSDIR grep-l-c-matching-lines-Lcap 'echo hi | grep -l -c --matching-lines -L hi | paste'\n./run_simple_test.sh $PSDIR grep-l-c-Lcap-matching-lines 'echo hi | grep -l -c -L --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-l-Lcap-matching-lines-c 'echo hi | grep -l -L --matching-lines -c hi | paste'\n./run_simple_test.sh $PSDIR grep-l-Lcap-c-matching-lines 'echo hi | grep -l -L -c --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-l-matching-lines-c-Lcap-nomatch 'echo hi | grep -l --matching-lines -c -L hello | paste'\n./run_simple_test.sh $PSDIR grep-l-matching-lines-Lcap-c-nomatch 'echo hi | grep -l --matching-lines -L -c hello | paste'\n./run_simple_test.sh $PSDIR grep-l-c-matching-lines-Lcap-nomatch 'echo hi | grep -l -c --matching-lines -L hello | paste'\n./run_simple_test.sh $PSDIR grep-l-c-Lcap-matching-lines-nomatch 'echo hi | grep -l -c -L --matching-lines hello | paste'\n./run_simple_test.sh $PSDIR grep-l-Lcap-matching-lines-c-nomatch 'echo hi | grep -l -L --matching-lines -c hello | paste'\n./run_simple_test.sh $PSDIR grep-l-Lcap-c-matching-lines-nomatch 'echo hi | grep -l -L -c --matching-lines hello | paste'\n\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines-c-l 'echo hi | grep -L --matching-lines -c -l hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines-l-c 'echo hi | grep -L --matching-lines -l -c hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-c-matching-lines-l 'echo hi | grep -L -c --matching-lines -l hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-c-l-matching-lines 'echo hi | grep -L -c -l --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-l-matching-lines-c 'echo hi | grep -L -l --matching-lines -c hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-l-c-matching-lines 'echo hi | grep -L -l -c --matching-lines hi | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines-c-l-nomatch 'echo hi | grep -L --matching-lines -c -l hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-matching-lines-l-c-nomatch 'echo hi | grep -L --matching-lines -l -c hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-c-matching-lines-l-nomatch 'echo hi | grep -L -c --matching-lines -l hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-c-l-matching-lines-nomatch 'echo hi | grep -L -c -l --matching-lines hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-l-matching-lines-c-nomatch 'echo hi | grep -L -l --matching-lines -c hello | paste'\n./run_simple_test.sh $PSDIR grep-Lcap-l-c-matching-lines-nomatch 'echo hi | grep -L -l -c --matching-lines hello | paste'\n\n# The remaining (double args) combinations don't work\n# does not work: --matching-lines\n#echo hi | grep --matching-lines -v hi | paste\n#echo hi | grep --matching-lines -v hello | paste\n# does not work: -o\n#echo hi | grep --matching-lines -o hi | paste\n\n# does not work: -o\n#echo hi | grep -c -o hi | cat\n#echo hi | grep -c -v hi | paste\n# does not work: -c\n#echo hi | grep -c -v hello | paste\n\n# does not work: -o\n#echo hi | grep -l -o hi | cat\n# does not work: -l\n#echo hi | grep -l -v hi | cat\n#echo hi | grep -l -v hello | cat\n\n# does not work: -o\n#echo hi | grep -L -o hi | cat\n# does not work: -L\n#echo hi | grep -L -v hi | paste\n#echo hi | grep -L -v hello | paste\n\n# does not work: --matching-lines\n#echo hi | grep -o --matching-lines hi | paste\n# does not work: -o\n#echo hi | grep -o -c hi | cat\n# does not work: -o\n#echo hi | grep -o -l hi | paste\n# does not work: -o\n#echo hi | grep -o -L hi | cat\n# does not make sense: -o -v\n#echo hi | grep -o -v hi | paste\n# does not work: -v\n#echo hi | grep -o -v hello | paste\n\n# does not work: --matching-lines\n#echo hi | grep -v --matching-lines hi | paste\n#echo hi | grep -v --matching-lines hello | paste\n#echo hi | grep -v -c hi | paste\n# does not work -c\n#echo hi | grep -v -c hello | paste\n# does not work: -l\n#echo hi | grep -v -l hi | paste\n#echo hi | grep -v -l hello | paste\n# does not work: -L\n#echo hi | grep -v -L hi | paste\n#echo hi | grep -v -L hello | paste\n# does not make sense: -v -o\n#echo hi | grep -v -o hi | paste\n# does not make sense: -v -o\n#echo hi | grep -v -o hello | paste\n\n"
  },
  {
    "path": "unix-tools/run_simple_test.sh",
    "content": "#!/usr/bin/env bash\n\n# Color\nGR=\"\\033[0;32m\"\t# Green\nR=\"\\033[0;31m\"\t# Red\nB=\"\\033[0;34m\"\t# Blue\nEC=\"\\033[0m\"\t# End color\nS=${GR}successful${EC}\nF=${R}failed${EC}\n\nDGSH='bash/bash --dgsh'\n\nPSDIR=$1\nFILENAME=$2\nSCRIPT=$3\n\nexport DGSHPATH=\"$(pwd)/../build/libexec/dgsh\"\nPATH=\"$(pwd)/../build/bin:$PATH\"\n\n$DGSH -c \"$SCRIPT > $PSDIR/$FILENAME.outb\" \\\n2>$PSDIR/$FILENAME.errb \\\n&& diff $PSDIR/$FILENAME.outb $PSDIR/$FILENAME.success \\\n&& printf \"$FILENAME $S\\n\" \\\n|| (printf \"$FILENAME $F\\n\" \\\n&& exit 1)\n\n"
  },
  {
    "path": "unix-tools/run_test.sh",
    "content": "#!/bin/sh\n\nPSDIR=$1\nFSCRIPT=$2\nBSCRIPT=$(basename $2 .sh)\nINPUT_TYPE=$3\nINPUT1=$4\nINPUT2=$5\nINPUT3=$6\n\nTOP=$(cd $(dirname $0)/.. ; pwd)\nDGSH=\"$TOP/build/bin/dgsh\"\nPATH=\"$TOP/build/bin:$PATH\"\nexport DGSHPATH=\"$TOP/build/libexec/dgsh\"\n\nGR=\"\\033[0;32m\"\t# Green\nR=\"\\033[0;31m\"\t# Red\nB=\"\\033[0;34m\"\t# Blue\nEC=\"\\033[0m\"\t# End color\nS=${GR}successful${EC}\nF=${R}failed${EC}\n\n# Skip test if required custom commands are missing\n(\n\tiscommand=0\n\tfor arg in \"$@\"; do\n\t\tif [ \"$arg\" = \"--\" ]; then\n\t\t\tiscommand=1\n\t\t\tcontinue\n\t\tfi\n\t\tif [ $iscommand -eq 0 ]; then\n\t\t\tcontinue\n\t\tfi\n\t\tif ! which $arg >/dev/null; then\n\t\t\texit 1\n\t\tfi\n\tdone\n\texit 0\n)\n\nif [ $? -ne 0 ]; then\n\techo \"Skip test $BSCRIPT.sh\"\n\texit 0\nfi\n\nif [ \"$INPUT_TYPE\" = pipe ]; then\n  if $DGSH $FSCRIPT <$INPUT1 >$PSDIR/$BSCRIPT.outb 2>$PSDIR/$BSCRIPT.err ; then\n    printf \"$BSCRIPT.sh $S\\n\"\n  else\n    printf \"$BSCRIPT.sh $F\\n\"\n    cat $PSDIR/$BSCRIPT.err\n    exit 1\n  fi\nelse\n  if $DGSH $FSCRIPT $INPUT1 $INPUT2 $INPUT3 >$PSDIR/$BSCRIPT.outb \\\n\t  2>$PSDIR/$BSCRIPT.err ; then\n    printf \"$BSCRIPT.sh $S\\n\"\n  else\n    printf \"$BSCRIPT.sh $F\\n\"\n    cat $PSDIR/$BSCRIPT.err\n    exit 1\n  fi\nfi\n"
  },
  {
    "path": "unix-tools/tee.sh",
    "content": "#!/usr/bin/env bash\n#!dgsh\n#\n# Implementation of POSIX tee through dgsh-tee\n#\n\nusage()\n{\n  echo 'Usage: tee [-ai] [file ...]' 1>&2\n  exit 2\n}\n\ndeclare -a opts\n\n# Process flags\nwhile getopts 'ai' o; do\n  case \"$o\" in\n    a)\n      opts=(-a)\n      ;;\n    i)\n      ;;\n    *)\n      usage\n      ;;\n  esac\ndone\n\nshift $((OPTIND-1))\n\n# Process file arguments\nfor i; do\n    opts+=('-o' \"$i\")\n    shift\ndone\n\nexec dgsh-tee \"${opts[@]}\"\n"
  },
  {
    "path": "unix-tools/test-compat.sh",
    "content": "#!/bin/sh\n#\n# Test the dgsh-compatibility checking\n\necho 'Testing dgsh compatibility checker'\n\ncheck()\n{\n  local title=\"$1\"\n  local prog=\"$2\"\n  local is_dgsh=\"$3\"\n\n  echo -n \"$title: \"\n\n  case $is_dgsh in\n    F)\n      if ./dgsh-compat \"$prog\" ; then\n\techo FAIL\n\texit 1\n      else\n\techo PASS\n      fi\n      ;;\n    T)\n      if ./dgsh-compat \"$prog\" ; then\n\techo PASS\n      else\n\techo FAIL\n\texit 1\n      fi\n      ;;\n  esac\n}\n\n\ncheck 'Non-dgsh binary file' /bin/ls F\n\ncheck 'Dgsh binary file' ../build/libexec/dgsh/dgsh-tee T\n\ncheck 'Dgsh wrap script' ../build/libexec/dgsh/date T\n\ncheck 'Dgsh magic script dgsh-parallel' ../build/libexec/dgsh/dgsh-parallel T\n\ncheck 'Dgsh magic script tee' ../build/libexec/dgsh/tee T\n\ncheck 'Dgsh magic script cat' ../build/libexec/dgsh/cat T\n\ncheck 'Non-dgsh script' ./test-compat.sh F\n\nexit 0\n"
  },
  {
    "path": "unix-tools/wrapped-commands-posix",
    "content": "# Commands specified by POSIX\nd alias\nd ar\nd basename\ndm bg\nd c99\nd cal\nc cat\ndm cd\nd cflow\ndm chgrp\ndm chmod\ndm chown\nD cksum\nc cmp\nc comm\nd command\nf compress\t# TODO custom\ndm cp\nf crontab\t# TODO custom\nf csplit\t# TODO custom\nf ctags\t\t# TODO custom\nd date\nd df\nc diff\nd dirname\nd du\nd echo\ndm env\nd expr\ndm false\ndm fg\nd find\nd getopts\nc grep\nd ipcrm\nd jobs\nc join\ndm kill\ndm link\ndm ln\nd ls\nd make\nd man\ndm mesg\ndm mkdir\ndm mkfifo\ndm mv\ndm newgrp\ndm nice\ndm nohup\nc paste\nd printf\nd ps\nd pwd\nm read\ndm renice\ndm rm\nD rmdel\t\t# SCCS\ndm rmdir\ndm sleep\nc sort\nf strings\t# TODO custom\ndm strip\nc tee\ndm test\nf time\t\t# Depends on the command\ndm touch\ndm true\nf tsort\nd tty\nd type\nd ulimit\nd umask\ndm unalias\nd uname\nf uncompress\t# TODO custom\nDm unget\ndm unlink\nD val\t\t# SCCS\ndm wait\nd what\t\t# SCCS\nd who\nm write\ndm yacc\n"
  },
  {
    "path": "unix-tools/wrapped-commands-tests",
    "content": "# Commands required for running the negotiation and performance tests\nd git\nI sfcat\n"
  },
  {
    "path": "web/format-eg.sh",
    "content": "#!/bin/sh\n#\n# Format the examples into Bootstrap HTML\n#\n\nSECTION='compress-compare\n\tcommit-stats\n\tcode-metrics\n\tduplicate-files\n\tspell-highlight\n\tword-properties\n\tweb-log-report\n\ttext-properties\n\tstatic-functions\n\tmap-hierarchy\n\tcommitter-plot\n\tparallel-word-count\n\tauthor-compare\n\tft2d\n\tNMRPipe\n\tfft-block8\n\treorder-columns\n\tdir'\n\n\nfor NAME in ${SECTION}\ndo\n\tTITLE=\"`sed -n 's/^# SYNOPSIS //p;s/^# TITLE //p' example/$NAME.sh | head -1`\"\n\tif [ \"$1\" = '-c' ]\n\tthen\n\t\techo \"<li> <a href='#$NAME'>$TITLE</a></li>\"\n\telse\n\t\tcat <<EOF\n<section id=\"$NAME\"> <!-- {{{2 -->\n<h2>$TITLE</h2>\n</section>\n<img src=\"$NAME-pretty.png\" class=\"img-polaroid\" alt=\"$TITLE\" />\n<!-- Extracted description -->\n<p>\n`sed -n '/^# DESCRIPTION/,/^#$/{;/^# DESCRIPTION/d;s/^# //p;}' example/$NAME.sh`\n</p>\n<!-- Extracted code -->\n<pre class=\"prettyprint lang-bash\">\n`sed '1a\\\n\n2,/^$/d' example/$NAME.sh |\nsed 's/&/\\&amp;/g;s/</\\&lt;/g;s/>/\\&gt;/g'`\n</pre>\nEOF\n\tfi\ndone\n"
  },
  {
    "path": "web/format-syntax.sh",
    "content": "#!/bin/sh\n#\n# Extract the dgsh syntax from the manual page and format it into HTML\n#\n\nsed -n '/^<dgsh_block/,/^\\.fi/ {\n\ts/&/\\&amp;/g\n\ts/</\\&lt;/g\n\ts/>/\\&gt;/g\n\t/^\\.fi/d\n\tp\n}' core-tools/src/dgsh.1\n"
  },
  {
    "path": "web/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n<title>dgsh &mdash; directed graph shell</title>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\n<!-- Bootstrap -->\n<link href=\"../../a/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\" />\n<link href=\"../../a/bootstrap/css/bootstrap-responsive.min.css\" rel=\"stylesheet\" />\n<link href=\"../../a/prettify/prettify.css\" type=\"text/css\" rel=\"stylesheet\" />\n<link href=\"../../a/dds-bstyle.css\" rel=\"stylesheet\" />\n</head>\n<body data-spy=\"scroll\" data-target=\"#sidemenu\">\n\n<div class=\"top\">dgsh dds</div>\n<div class=\"row\">\n    <div class=\"span4\" id=\"sidemenu\" >\n    <ul class=\"nav nav-list sidenav\" data-spy=\"affix\">\n    <li ><a href=\"#intro\">Introduction</a></li>\n\t<li>\n\t<ul class=\"nav nav-list\">\n\t<li ><a href=\"#ipc\">IPC</a></li>\n\t<li ><a href=\"#syntax\">Syntax</a></li>\n\t<li ><a href=\"#tools\">Adapted tools</a></li>\n\t</ul>\n\t</li>\n    <li ><a href=\"#download\">Downloading and installation</a></li>\n\t<li>\n\t<ul class=\"nav nav-list\">\n    \t<li ><a href=\"#debian\">Debian and Ubuntu</a></li>\n    \t<li ><a href=\"#freebsd\">FreeBSD</a></li>\n\t</ul>\n\t</li>\n    <li ><a href=\"#reference\">Reference</a></li>\n    <li><a href=\"#examples\">Examples</a></li>\n\t<li>\n\t<ul class=\"nav nav-list\">\n<!-- #!sh web/format-eg.sh -c -->\n\t</ul>\n\t</li>\n    </ul>\n    </div> <!-- span4 -->\n    <div class=\"span8\">\n\n<!-- About {{{1\n================================================== -->\n<section id=\"intro\">\n  <div class=\"page-header\">\n    <h1>dgsh &mdash; directed graph shell</h1>\n  </div>\n<p>\nThe directed graph shell, <em>dgsh</em>\n(<a href=\"https://en.wiktionary.org/wiki/Appendix:English_pronunciation\">pronounced</a> /dæɡʃ/ &mdash; <em>dagsh</em>),\nprovides an expressive way to construct\nsophisticated and efficient big data set and stream processing pipelines\nusing existing Unix tools as well as custom-built components.\nIt is a Unix-style shell (based on <em>bash</em>)\nallowing the specification of pipelines\nwith non-linear non-uniform operations.\nThese form a directed acyclic process graph,\nwhich is typically executed by multiple processor cores,\nthus increasing the operation's processing throughput.\n</p>\n<p>\nIf you want to get a feeling on how <em>dgsh</em> works in practice,\nskip right down to the <a href=\"#examples\">examples</a> section.\n</p>\n<p>\nFor a more formal introduction to <em>dgsh</em> or to cite it in your work,\nsee:<br />\nDiomidis Spinellis and Marios Fragkoulis.\n<a href=\"http://dx.doi.org/10.1109%2FTC.2017.2695447\">Extending Unix Pipelines to DAGs</a>.\n<em>IEEE Transactions on Computers</em>, 2017.\ndoi: 10.1109/TC.2017.2695447\n</p>\n</section> <!-- Introduction -->\n\n<section id=\"ipc\"> <!-- {{{2 -->\n<h2>Inter-process communication</h2>\n<p>\n<em>Dgsh</em> provides two new ways\nfor expressing inter-process communication.\n\n</p>\n<dl class=\"dl-horizontal\">\n<dt>Multipipes</dt><dd> are expressed as usual Unix pipelines,\nbut can connect commands with more than one output or input channel.\nAs an example, the <code>comm</code> command supplied with <em>dgsh</em>\nexpects two input channels and produces on its output three\noutput channels: the lines appearing only in first (sorted) channel,\nthe lines appearing only in the second channel,\nand the lines appearing in both.\nConnecting the output of the <code>comm</code> command to the\n<code>cat</code> command supplied with <em>dgsh</em>\nwill make the three outputs appear in sequence,\nwhile connecting it to the\n<code>paste</code> command supplied with <em>dgsh</em>\nwill make the output appear in its customary format.\n</dd>\n\n<dt>Multipipe blocks {{ ... }}</dt><dd>\na) send (multiple) input streams\nreceived on their input side to the asynchronously-running\nprocesses that reside within the block, and,\nb) pass the output produced by the processes within the block as\n(multiple) streams on their output side.\nMultipipe blocks typically receive input from more than one channel\nand produce more than one output channel.\nFor example, a multipipe block that runs <code>md5sum</code> and <code>wc -c</code>\nreceives two inputs and produces two outputs:\nthe MD5 hash of its input and the input's size.\nData to multipipe blocks are typically provided with a\n<em>dgsh</em>-aware version of <code>tee</code> and collected by\n<em>dgsh</em>-aware versions of programs such as\n<code>cat</code> and <code>paste</code>.\n</dd>\n\n<dt>Stored values</dt> <dd>offer a convenient way for communicating\ncomputed values between arbitrary processes on the graph.\nThey allow the storage of a data stream's\nlast record into a named buffer.\nThis record can be later retrieved asynchronously by one or more readers.\nData in a stored value can be piped into a process or out of it, or it can be read\nusing the shell's command output substitution syntax.\nStored values are implemented internally through Unix-domain sockets,\na background-running store program, <code>dgsh-writeval</code>, and\na reader program, <code>dgsh-readval</code>.\nThe behavior of a stored value's IO can be modified by adding flags to\n<code>dgsh-writeval</code> and <code>dgsh-readval</code>.\n</dd>\n</dl>\n</section>\n\n<section id=\"syntax\"> <!-- {{{2 -->\n<h2>Syntax</h2>\n<p>\nA <em>dgsh</em> script follows the syntax of a <em>bash</em>(1) shell\nscript with the addition of <em>multipipe</em> blocks.\nA multipipe block contains one or more <em>dgsh</em> simple commands,\nother multipipe blocks, or pipelines of the previous two types of commands.\nThe commands in a multipipe block\nare executed asynchronously (in parallel, in the background).\nData may be redirected or piped into and out of a multipipe block.\nWith multipipe blocks <em>dgsh</em> scripts form directed acyclic process graphs.\nIt follows from the above description that\nmultipipe blocks can be recursively composed.\n</p>\n\n<p>\nAs a simple example consider running the following command\ndirectly within <em>dgsh</em>\n</p>\n<pre class=\"prettyprint lang-bash\">\n{{ echo hello & echo world & }} | paste\n</pre>\n<p>\nor by invoking <code>dgsh</code> with the command as an argument.\n</p>\n<pre class=\"prettyprint lang-bash\">\ndgsh -c '{{ echo hello & echo world & }} | paste'\n</pre>\n<p>\nThe command will run <em>paste</em> with input from the two\n<em>echo</em> processes to output <code>hello world</code>.\nThis is equivalent to running the following <em>bash</em> command,\nbut with the flow of data appearing in the natural left-to-right order.\n</p>\n<pre class=\"prettyprint lang-bash\">\npaste <(echo hello) <(echo world)\n</pre>\n\n<p>\nIn the following larger example, which compares the performance of\ndifferent compression utilities, the script's standard input\nis distributed to\nthree compression utilities (<em>xz</em>, <em>bzip2</em>, and <em>gzip</em>),\nto assess their performance, and also to\n<em>file</em> and <em>wc</em> to report the input data's type and size.\nThe <em>printf</em> commands label the data of each processing type.\nAll eight commands pass their output\nto the <code>cat</code> command, which gathers their outputs\nin order.\n</p>\n\n<pre class=\"prettyprint lang-bash\">\ntee |\n{{\n\tprintf 'File type:\\t'\n\tfile -\n\n\tprintf 'Original size:\\t'\n\twc -c\n\n\tprintf 'xz:\\t\\t'\n\txz -c | wc -c\n\n\tprintf 'bzip2:\\t\\t'\n\tbzip2 -c | wc -c\n\n\tprintf 'gzip:\\t\\t'\n\tgzip -c | wc -c\n}} |\ncat\n</pre>\n\n<p>\nFormally, <em>dgsh</em> extends the syntax of the (modified) Unix Bourne-shell\nwhen <code>bash</code> provided with the <code>--dgsh</code> argument\nas follows.\n</p>\n\n<pre class=\"prettyprint\">\n<!-- #!sh web/format-syntax.sh -->\n</pre>\n</section> <!-- syntax -->\n\n<section id=\"tools\"> <!-- {{{2 -->\n<h2>Adapted tools</h2>\n<p>\nA number of Unix tools have been adapted to support multiple inputs\nand outputs to match their natural capabilities.\nThis echoes a similar adaptation that was performed in the early\n1970s when Unix and the shell got pipes and the pipeline syntax.\nMany programs that worked with files were adjusted to work as filters.\nThe number of input and output channels of <em>dgsh</em>-compatible commands are\nas follows, based on the supplied command-line arguments.\n</p>\n<p>\n<table>\n\t<tr>\n\t\t<th>Tool</th>\n\t\t<th>Inputs</th>\n\t\t<th>Outputs</th>\n\t\t<th>Notes</th>\n\t</tr>\n\t<tr>\n\t\t<td>cat (<em>dgsh-tee</em>)</td>\n\t\t<td>0&mdash;N</td>\n\t\t<td>0&mdash;M</td>\n\t\t<td>No options are supported</td>\n\t</tr>\n\t<tr>\n\t\t<td>cmp</td>\n\t\t<td>0&mdash;2</td>\n\t\t<td>0&mdash;1</td>\n\t\t<td></td>\n\t</tr>\n\t<tr>\n\t\t<td>comm</td>\n\t\t<td>0&mdash;2</td>\n\t\t<td>0&mdash;3</td>\n\t\t<td>Output streams in order: lines only in first file, lines only in second one, and lines in both files</td>\n\t</tr>\n\t<tr>\n\t\t<td>cut</td>\n\t\t<td>0&mdash;1</td>\n\t\t<td>1&mdash;N</td>\n\t\t<td>With <code>--multistream</code> output each range into a different stream</td>\n\t</tr>\n\t<tr>\n\t\t<td>diff</td>\n\t\t<td>0&mdash;N</td>\n\t\t<td>1</td>\n\t\t<td>Typically two inputs. Compare an arbitrary number of input streams with the <code>--from-file</code> or <code>--to-file</code> options</td>\n\t</tr>\n\t<tr>\n\t\t<td>diff3</td>\n\t\t<td>0&mdash;3</td>\n\t\t<td>1</td>\n\t\t<td></td>\n\t</tr>\n\t<tr>\n\t\t<td>grep</td>\n\t\t<td>0&mdash;2</td>\n\t\t<td>0&mdash;4</td>\n\t\t<td>Available output streams (via arguments): matching files, non-matching files, matching lines, and non-matching lines</td>\n\t</tr>\n\t<tr>\n\t\t<td>join</td>\n\t\t<td>0&mdash;2</td>\n\t\t<td>1</td>\n\t\t<td></td>\n\t</tr>\n\t<tr>\n\t\t<td>paste</td>\n\t\t<td>0&mdash;N</td>\n\t\t<td>1</td>\n\t\t<td>Paste N input streams</td>\n\t</tr>\n\t<tr>\n\t\t<td>perm</td>\n\t\t<td>1&mdash;N</td>\n\t\t<td>1&mdash;N</td>\n\t\t<td>Rearrange the order of N input streams</td>\n\t</tr>\n\t<tr>\n\t\t<td>sort</td>\n\t\t<td>0&mdash;N</td>\n\t\t<td>0&mdash;1</td>\n\t\t<td>With the <code>-m</code> option, merge sort N input streams</td>\n\t</tr>\n\t<tr>\n\t\t<td>tee (<em>dgsh-tee</em>)</td>\n\t\t<td>0&mdash;N</td>\n\t\t<td>0&mdash;M</td>\n\t\t<td>Only the <code>-a</code> option is supported</td>\n\t</tr>\n\t<tr>\n\t\t<td>dgsh-readval</td>\n\t\t<td>0</td>\n\t\t<td>1</td>\n\t\t<td>Read a value from a socket</td>\n\t</tr>\n\t<tr>\n\t\t<td>dgsh-wrap</td>\n\t\t<td>0&mdash;N</td>\n\t\t<td>0&mdash;1</td>\n\t\t<td>Wrap non-dgsh commands and negotiate on their behalf</td>\n\t</tr>\n\t<tr>\n\t\t<td>dgsh-writeval</td>\n\t\t<td>1</td>\n\t\t<td>0</td>\n\t\t<td>Write a value to a socket</td>\n\t</tr>\n</table>\n</p>\n<p>\nIn addition, POSIX user commands that receive no input\nor only generate no output, when executed in a <em>dgsh</em> context\nare wrapped to specify the corresponding input or output capability.\nFor example, an <code>echo</code> command in a multipipe block\nwill appear to receive no input, but will provide one output stream.\nBy default <code>dgsh</code> automatically wraps all other\ncommands as filters.\n<dl>\n<dt> Input-only </dt><dd>\n<!-- #!sed -n '/^m /{;s/. //;s/[ \\t].*//;s/$/,/;p;}' unix-tools/wrapped-commands-posix | sed '$s/,/./' -->\n</dd>\n<dt> Output-only </dt><dd> </dd>\n<!-- #!sed -n '/^d /{;s/. //;s/[ \\t].*//;s/$/,/;p;}' unix-tools/wrapped-commands-posix | sed '$s/,/./' -->\n</dl>\n<dt> No input and output </dt><dd> </dd>\n<!-- #!sed -n '/^dm /{;s/. //;s/[ \\t].*//;s/$/,/;p;}' unix-tools/wrapped-commands-posix | sed '$s/,/./' -->\n</dl>\n</p>\n<p>\nFinally, note that any <em>dgsh</em> script will accept and generate\nthe number of inputs and outputs associated with the commands or\nmultipipe blocks at its two endpoints.\n</p>\n</section> <!-- Adapted tools -->\n\n\n<!-- Downloading and installation {{{1\n================================================== -->\n<section id=\"download\">\n  <div class=\"page-header\">\n    <h1>Downloading and installation</h1>\n  </div>\n\n<p>\nThe <em>dgsh</em> suite has been tested under\nDebian and Ubuntu Linux, FreeBSD, and Mac OS X.\nA Cygwin port is underway.\n</p>\n\n<p>\nAn installation of <a href=\"http://www.graphviz.org/\">GraphViz</a>\nwill allow you to visualize the <em>dgsh</em> graphs that you specify\nin your programs.\n</p>\n\n    <section id=\"debian\"> <!-- {{{2 -->\n    <h2>Debian and Ubuntu GNU/Linux</h2>\n    <section>\n    <h3>Prerequisites</h3>\n<p>\nTo compile and run <em>dgsh</em> you will need to have the following commands\ninstalled on your system:\n<pre class=\"prettyprint lang-bash\">\n<!-- #!sed -n -e '/\\# For installation/{n;s/sudo apt-get install -y //p}' .travis/linux-ubuntu-trusty.install.sh -->\ngit xz-utils gettext\n</pre>\n\nTo test <em>dgsh</em> you will need to have the following commands\ninstalled in your system:\n<pre class=\"prettyprint lang-bash\">\n<!-- #!sed -n -e '/\\# For testing/{n;s/sudo apt-get install -y //p}' .travis/linux-ubuntu-trusty.install.sh -->\ncurl bzip2\n</pre>\n</p>\n    <h3>Installation steps</h3>\n<p>\nGo through the following steps.\n<ol>\n<li>\nRecursively clone the project's source code through its\n<a href=\"https://github.com/dspinellis/dgsh\">GitHub page</a>.\n<pre class=\"prettyprint lang-bash\">\ngit clone --recursive https://github.com/dspinellis/dgsh.git\n</pre>\n</li>\n<li>\nConfigure <em>bash</em> and the Unix tools adapted for <em>dgsh</em>.\n<pre class=\"prettyprint lang-bash\">\nmake config\n</pre>\n</li>\n<li>\nCompile all programs.\n<pre class=\"prettyprint lang-bash\">\nmake\n</pre>\n</li>\n<li>\nInstall.\n<pre class=\"prettyprint lang-bash\">\nsudo make install\n</pre>\n</li>\n</ol>\n</p>\n<p>\nBy default, the program and its documentation are installed under\n<code>/usr/local</code>.\nYou can modify this by setting the <code>PREFIX</code> variable\nin the `config` step, for example:\n<pre class=\"prettyprint lang-bash\">\nmake PREFIX=$HOME config\nmake\nmake install\n</pre>\n</p>\n\n    <h3>Testing</h3>\n<p>\n\nIssue the following command.\n<pre class=\"prettyprint lang-bash\">\nmake test\n</pre>\n</p>\n\n    </section>\n    <section id=\"freebsd\"> <!-- {{{2 -->\n    <h2>FreeBSD</h2>\n    <section>\n    <h3>Prerequisites</h3>\n<p>\nTo compile and run <em>dgsh</em> you will need to have the following packages\ninstalled in your system:\n<pre class=\"prettyprint lang-bash\">\ndevel/automake\ndevel/bison\ndevel/check\ndevel/git\ndevel/gmake\ndevel/gperf\nmisc/help2man\nprint/texinfo\nshells/bash\n</pre>\n\nTo test <em>dgsh</em> you will need to have the following ports\ninstalled on your system:\n<pre class=\"prettyprint lang-bash\">\narchivers/bzip2\nftp/curl\n</pre>\n</p>\n    <h3>Installation steps</h3>\n<p>\nGo through the following steps.\n<ol>\n<li>\nRecursively clone the project's source code through its\n<a href=\"https://github.com/dspinellis/dgsh\">GitHub page</a>.\n<pre class=\"prettyprint lang-bash\">\ngit clone --recursive https://github.com/dspinellis/dgsh.git\n</pre>\n</li>\n<li>\nConfigure <em>bash</em> and the Unix tools adapted for <em>dgsh</em>.\n<pre class=\"prettyprint lang-bash\">\ngmake config\n</pre>\n</li>\n<li>\nCompile all programs.\n<pre class=\"prettyprint lang-bash\">\ngmake\n</pre>\n</li>\n<li>\nInstall.\n<pre class=\"prettyprint lang-bash\">\nsudo gmake install\n</pre>\n</li>\n</ol>\n</p>\n<p>\nBy default, the program and its documentation are installed under\n<code>/usr/local</code>.\nYou can modify this by setting the <code>PREFIX</code> variable\nin the `config` step, for example:\n<pre class=\"prettyprint lang-bash\">\ngmake PREFIX=$HOME config\ngmake\ngmake install\n</pre>\n</p>\n\n    <h3>Testing</h3>\n<p>\n\nIssue the following command.\n<pre class=\"prettyprint lang-bash\">\ngmake test\n</pre>\n</p>\n\n    </section>\n</section>\n</section>\n\n<!-- Reference {{{1\n================================================== -->\n<section id=\"reference\">\n  <div class=\"page-header\">\n    <h1>Reference documentation</h1>\n  </div>\n<p>\nThese are the manual pages for <em>dgsh</em>, the associated helper programs\nand the API\nin formats suitable for browsing and printing.\nThe commands are listed in the order of usefulness in everyday scenarios.\n</p>\n<dl >\n<dt> dgsh </dt><dd> directed graph shell <a href=\"dgsh.html\">HTML</a>, <a href=\"dgsh.pdf\">PDF</a></dd>\n<dt> dgsh-tee </dt><dd> buffer and copy or scatter standard input to one or more sinks <a href=\"dgsh-tee.html\">HTML</a>, <a href=\"dgsh-tee.pdf\">PDF</a></dd>\n<dt> dgsh-wrap </dt><dd> allow any filter program to participate in an dgsh pipeline <a href=\"dgsh-wrap.html\">HTML</a>, <a href=\"dgsh-wrap.pdf\">PDF</a></dd>\n<dt> dgsh-writeval </dt><dd> write values to a data store <a href=\"dgsh-writeval.html\">HTML</a>, <a href=\"dgsh-writeval.pdf\">PDF</a></dd>\n<dt> dgsh-readval </dt><dd> data store client <a href=\"dgsh-readval.html\">HTML</a>, <a href=\"dgsh-readval.pdf\">PDF</a></dd>\n<dt> dgsh-monitor </dt><dd> monitor data on a pipe <a href=\"dgsh-monitor.html\">HTML</a>, <a href=\"dgsh-monitor.pdf\">PDF</a></dd>\n<dt> dgsh-parallel </dt><dd> create a semi-homogeneous dgsh parallel processing block <a href=\"dgsh-parallel.html\">HTML</a>, <a href=\"dgsh-parallel.pdf\">PDF</a></dd>\n<dt> perm </dt><dd> permute inputs to outputs <a href=\"perm.html\">HTML</a>, <a href=\"perm.pdf\">PDF</a></dd>\n<dt> dgsh-httpval </dt><dd> provide data store values through HTTP <a href=\"dgsh-httpval.html\">HTML</a>, <a href=\"dgsh-httpval.pdf\">PDF</a></dd>\n<dt> dgsh-merge-sum </dt><dd> merge key value pairs, summing the values <a href=\"dgsh-merge-sum.html\">HTML</a>, <a href=\"dgsh-merge-sum.pdf\">PDF</a></dd>\n<dt> dgsh-conc </dt><dd> input or output pipe concentrator for <em>dgsh</em> negotiation (used internally) <a href=\"dgsh-conc.html\">HTML</a>, <a href=\"dgsh-conc.pdf\">PDF</a></dd>\n<dt> dgsh-enumerate </dt><dd> enumerate an arbitrary number of output channels (demonstration and <a href=\"http://istlab.dmst.aueb.gr/~dds/dgsh-egg.sh\" style=\"color:inherit; text-decoration:none;\">debugging</a> tool) <a href=\"dgsh-enumerate.html\">HTML</a>, <a href=\"dgsh-enumerate.pdf\">PDF</a></dd>\n<dt> dgsh_negotiate </dt><dd> API for <em>dgsh</em>-compatible\nprograms to specify and obtain dgsh I/O file descriptors\n<a href=\"dgsh_negotiate.html\">HTML</a>, <a href=\"dgsh_negotiate.pdf\">PDF</a></dd>\n</dl>\n</section>\n\n\n<!--</th>\n<th>Examples</th>\n<th>{{{1\n==================================================</th>\n<th>-->\n<section id=\"examples\">\n  <div class=\"page-header\">\n    <h1>Examples</h1>\n  </div>\n\n<!-- #!sh web/format-eg.sh -->\n\n</section> <!-- Examples -->\n\n</div> <!-- span8 -->\n</div> <!-- row -->\n\n<!-- Bootstrap -->\n<script src=\"https://code.jquery.com/jquery.js\"></script>\n<script src=\"../../a/bootstrap/js/bootstrap.min.js\"></script>\n<script type=\"text/javascript\" src=\"../../a/prettify/prettify.js\"></script>\n\n<script>\n    $(document).ready(function() {\n\tprettyPrint();\n    });\n</script>\n\n<div class=\"license\">\n<!--Creative Commons License--><a rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/3.0/gr/deed.en\">\n<img alt=\"Creative Commons License\" src=\"https://creativecommons.org/images/public/somerights20.png\"/></a>\nUnless otherwise expressly stated, all original material on this page\ncreated by Diomidis Spinellis is licensed under a\n<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/3.0/gr/deed.en\">Creative Commons Attribution-Share Alike 3.0 Greece License</a>.\n</div>\n\n</body>\n</html>\n"
  }
]