commit 5b839e0543dc1fbffd89ee656abc328948700bf6 Author: Quentin W Date: Thu Jul 18 14:09:32 2024 -0400 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dfa3815 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +.htpasswd +werc/etc/* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..21b877b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +FROM alpine:latest + +#ENV PLAN9 /usr/lib/9base +ENV PLAN9 /usr/lib/plan9 +ENV EDITOR /usr/bin/nvim + +#RUN apk add 9base --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ +#RUN apk add plan9port +RUN apk add --update --no-cache \ + lighttpd \ + lighttpd-mod_auth \ + apache2-utils \ + curl \ + discount \ + shadow \ + imagemagick \ + aspell \ + aspell-en \ + neovim \ + git build-base linux-headers libucontext-dev libxt-dev libx11-dev fontconfig-dev libxext-dev perl \ + && rm -rf /var/cache/apk/* +RUN curl http://werc.cat-v.org/download/werc-1.5.0.tar.gz | tar xzf - && mkdir -p /var/www/ && mv ../werc-*/ /var/www/werc +RUN git clone https://github.com/9fans/plan9port /usr/lib/plan9 +WORKDIR /usr/lib/plan9 +RUN ./INSTALL +WORKDIR / + +COPY etc/lighttpd/ /etc/lighttpd/ +RUN sed 's/fltr_cache md2html\.awk/fltr_cache markdown/' /var/www/werc/etc/initrc > /var/www/werc/etc/initrc.local +COPY init.sh /usr/local/bin +RUN chmod +x /usr/local/bin/init.sh + +RUN ln -s $PLAN9 /usr/local/plan9 +RUN ln -s $PLAN9/bin/rc /bin/rc +RUN ln -s $PLAN9/bin/awk /bin/awk +#RUN cp /usr/bin/sha1sum $PLAN9/bin +ENV PATH="$PLAN9/bin:${PATH}" + +EXPOSE 80 + +#RUN /var/www/werc/bin/contrib/fix-rc-scripts /var/www/werc/bin + +RUN usermod -u 1000 lighttpd +RUN chown -R lighttpd:root /var/www +RUN chmod -R g+w /var/www/werc/sites +#RUN sed '1s|^.*$|#!/usr/lib/9base/bin/rc|' /var/www/werc/bin/werc.rc > /tmp/werc.rc.tmp && mv /tmp/werc.rc.tmp /var/www/werc/bin/werc.rc && chmod 775 /var/www/werc/bin/werc.rc +#RUN sed 's/formatter=(fltr_cache md2html\.awk)/formatter=(fltr_cache markdown)/' /var/www/werc/etc/initrc > /var/www/werc/etc/initrc.local +CMD ["init.sh"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8ed391a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,32 @@ +services: + werc: + build: + dockerfile: Dockerfile + context: . + ports: + - 80:80 + environment: + - HOSTNAME=thirdculture.top + volumes: + - werc:/var/www/werc + - lighttpd:/etc/lighttpd + tty: true + gossa: + image: pldubouilh/gossa + ports: + - 8001:8001 + volumes: + - ./werc/sites/thirdculture.top/_files:/shared +volumes: + werc: + driver: local + driver_opts: + o: bind + type: none + device: "./werc" + lighttpd: + driver: local + driver_opts: + o: bind + type: none + device: "./etc/lighttpd" diff --git a/etc/lighttpd/conf.d/files.thirdculture.top.conf b/etc/lighttpd/conf.d/files.thirdculture.top.conf new file mode 100644 index 0000000..e06cd69 --- /dev/null +++ b/etc/lighttpd/conf.d/files.thirdculture.top.conf @@ -0,0 +1,21 @@ +$HTTP["host"] =~ "^files\.thirdculture\.top$" { + auth.backend = "htpasswd" + auth.backend.htpasswd.userfile = "/etc/lighttpd/.htpasswd" + + auth.require = ( "" => + ( + "method" => "basic", + "realm" => "Password protected area", + "require" => "valid-user" + ) + ) + + proxy.server = ( + "" => ( + ( + "host" => "gossa", + "port" => 8001 + ) + ) + ) +} diff --git a/etc/lighttpd/conf.d/ppl.thirdculture.top.conf b/etc/lighttpd/conf.d/ppl.thirdculture.top.conf new file mode 100644 index 0000000..7d4f204 --- /dev/null +++ b/etc/lighttpd/conf.d/ppl.thirdculture.top.conf @@ -0,0 +1,6 @@ +$HTTP["host"] =~ "^ppl\.thirdculture\.top$" { + index-file.names = ( ) + server.error-handler-404 = "/werc.rc" + alias.url += ( "/werc.rc" => "/var/www/werc/bin/werc.rc" ) + cgi.assign += ( ".rc" => "") +} \ No newline at end of file diff --git a/etc/lighttpd/conf.d/thirdculture.top.conf b/etc/lighttpd/conf.d/thirdculture.top.conf new file mode 100644 index 0000000..870db00 --- /dev/null +++ b/etc/lighttpd/conf.d/thirdculture.top.conf @@ -0,0 +1,6 @@ +$HTTP["host"] =~ "^thirdculture\.top$" { + index-file.names = ( ) + server.error-handler-404 = "/werc.rc" + alias.url += ( "/werc.rc" => "/var/www/werc/bin/werc.rc" ) + cgi.assign += ( ".rc" => "") +} \ No newline at end of file diff --git a/etc/lighttpd/lighttpd.conf b/etc/lighttpd/lighttpd.conf new file mode 100644 index 0000000..f132f28 --- /dev/null +++ b/etc/lighttpd/lighttpd.conf @@ -0,0 +1,326 @@ +############################################################################### +# Default lighttpd.conf for Gentoo. +# $Header: /var/cvsroot/gentoo-x86/www-servers/lighttpd/files/conf/lighttpd.conf,v 1.3 2005/09/01 14:22:35 ka0ttic Exp $ +############################################################################### + +# {{{ variables +var.basedir = "/var/www/localhost" +var.logdir = "/var/log/lighttpd" +var.statedir = "/var/lib/lighttpd" +# }}} + +# {{{ modules +# At the very least, mod_access and mod_accesslog should be enabled. +# All other modules should only be loaded if necessary. +# NOTE: the order of modules is important. +server.modules = ( + "mod_rewrite", +# "mod_redirect", + "mod_alias", + "mod_access", +# "mod_cml", +# "mod_trigger_b4_dl", + "mod_auth", +# "mod_status", +# "mod_setenv", + "mod_proxy", +# "mod_simple_vhost", +# "mod_evhost", +# "mod_userdir", +# "mod_deflate", +# "mod_ssi", +# "mod_usertrack", +# "mod_expire", +# "mod_secdownload", +# "mod_rrdtool", +# "mod_webdav", + "mod_accesslog" +) +# }}} + +# {{{ includes +include "mime-types.conf" +# uncomment for cgi support + include "mod_cgi.conf" +# uncomment for php/fastcgi support +# include "mod_fastcgi.conf" +# uncomment for php/fastcgi fpm support +# include "mod_fastcgi_fpm.conf" +# }}} + +# {{{ server settings +server.username = "lighttpd" +server.groupname = "lighttpd" + +server.document-root = var.basedir + "/htdocs" +server.pid-file = "/run/lighttpd.pid" + +server.errorlog = "/dev/pts/0" +#server.errorlog = var.logdir + "/error.log" +# log errors to syslog instead +# server.errorlog-use-syslog = "enable" + +server.indexfiles = ("index.php", "index.html", + "index.htm", "default.htm") + +# server.tag = "lighttpd" + +server.follow-symlink = "enable" + +# event handler (defaults to "poll") +# see performance.txt +# +# for >= linux-2.4 +# server.event-handler = "linux-rtsig" +# for >= linux-2.6 +# server.event-handler = "linux-sysepoll" +# for FreeBSD +# server.event-handler = "freebsd-kqueue" + +# chroot to directory (defaults to no chroot) +# server.chroot = "/" + +# bind to port (defaults to 80) +# server.port = 81 + +# bind to name (defaults to all interfaces) +# server.bind = "grisu.home.kneschke.de" + +# error-handler for status 404 +# server.error-handler-404 = "/error-handler.html" +# server.error-handler-404 = "/error-handler.php" + +# Format: .html +# -> ..../status-404.html for 'File not found' +# server.errorfile-prefix = var.basedir + "/error/status-" + +# FAM support for caching stat() calls +# requires that lighttpd be built with USE=fam +# server.stat-cache-engine = "fam" +# }}} + +# {{{ mod_staticfile + +# which extensions should not be handled via static-file transfer +# (extensions that are usually handled by mod_cgi, mod_fastcgi, etc). +static-file.exclude-extensions = (".php", ".pl", ".cgi", ".fcgi") +# }}} + +# {{{ mod_accesslog +accesslog.filename = "/dev/pts/0" +#accesslog.filename = var.logdir + "/access.log" +# }}} + +# {{{ mod_dirlisting +# enable directory listings +# dir-listing.activate = "enable" +# +# don't list hidden files/directories +# dir-listing.hide-dotfiles = "enable" +# +# use a different css for directory listings +# dir-listing.external-css = "/path/to/dir-listing.css" +# +# list of regular expressions. files that match any of the +# specified regular expressions will be excluded from directory +# listings. +# dir-listing.exclude = ("^\.", "~$") +# }}} + +# {{{ mod_access +# see access.txt + +url.access-deny = ("~", ".inc") +# }}} + +# {{{ mod_userdir +# see userdir.txt +# +# userdir.path = "public_html" +# userdir.exclude-user = ("root") +# }}} + +# {{{ mod_ssi +# see ssi.txt +# +# ssi.extension = (".shtml") +# }}} + +# {{{ mod_ssl +# see ssl.txt +# +# ssl.engine = "enable" +# ssl.pemfile = "server.pem" +# }}} + +# {{{ mod_status +# see status.txt +# +# status.status-url = "/server-status" +# status.config-url = "/server-config" +# }}} + +# {{{ mod_simple_vhost +# see simple-vhost.txt +# +# If you want name-based virtual hosting add the next three settings and load +# mod_simple_vhost +# +# document-root = +# virtual-server-root + virtual-server-default-host + virtual-server-docroot +# or +# virtual-server-root + http-host + virtual-server-docroot +# +# simple-vhost.server-root = "/home/weigon/wwwroot/servers/" +# simple-vhost.default-host = "grisu.home.kneschke.de" +# simple-vhost.document-root = "/pages/" +# }}} + +# {{{ mod_deflate +# see compress.txt +# +# deflate.cache-dir = var.statedir + "/cache/compress" +# deflate.mimetypes = ("text/plain", "text/html") +# }}} + +# {{{ mod_proxy +# see proxy.txt +# +# proxy.server = ( ".php" => +# ( "localhost" => +# ( +# "host" => "192.168.0.101", +# "port" => 80 +# ) +# ) +# ) +# }}} + +# {{{ mod_auth +# see authentication.txt +# +# auth.backend = "plain" +# auth.backend.plain.userfile = "lighttpd.user" +# auth.backend.plain.groupfile = "lighttpd.group" + +# auth.backend.ldap.hostname = "localhost" +# auth.backend.ldap.base-dn = "dc=my-domain,dc=com" +# auth.backend.ldap.filter = "(uid=$)" + +# auth.require = ( "/server-status" => +# ( +# "method" => "digest", +# "realm" => "download archiv", +# "require" => "user=jan" +# ), +# "/server-info" => +# ( +# "method" => "digest", +# "realm" => "download archiv", +# "require" => "valid-user" +# ) +# ) +# }}} + +# {{{ mod_rewrite +# see rewrite.txt +# +# url.rewrite = ( +# "^/$" => "/server-status" +# ) +# }}} + +# {{{ mod_redirect +# see redirect.txt +# +# url.redirect = ( +# "^/wishlist/(.+)" => "http://www.123.org/$1" +# ) +# }}} + +# {{{ mod_evhost +# define a pattern for the host url finding +# %% => % sign +# %0 => domain name + tld +# %1 => tld +# %2 => domain name without tld +# %3 => subdomain 1 name +# %4 => subdomain 2 name +# +# evhost.path-pattern = "/home/storage/dev/www/%3/htdocs/" +# }}} + +# {{{ mod_expire +# expire.url = ( +# "/buggy/" => "access 2 hours", +# "/asdhas/" => "access plus 1 seconds 2 minutes" +# ) +# }}} + +# {{{ mod_rrdtool +# see rrdtool.txt +# +# rrdtool.binary = "/usr/bin/rrdtool" +# rrdtool.db-name = var.statedir + "/lighttpd.rrd" +# }}} + +# {{{ mod_setenv +# see setenv.txt +# +# setenv.add-request-header = ( "TRAV_ENV" => "mysql://user@host/db" ) +# setenv.add-response-header = ( "X-Secret-Message" => "42" ) +# }}} + +# {{{ mod_trigger_b4_dl +# see trigger_b4_dl.txt +# +# trigger-before-download.gdbm-filename = "/home/weigon/testbase/trigger.db" +# trigger-before-download.memcache-hosts = ( "127.0.0.1:11211" ) +# trigger-before-download.trigger-url = "^/trigger/" +# trigger-before-download.download-url = "^/download/" +# trigger-before-download.deny-url = "http://127.0.0.1/index.html" +# trigger-before-download.trigger-timeout = 10 +# }}} + +# {{{ mod_cml +# see cml.txt +# +# don't forget to add index.cml to server.indexfiles +# cml.extension = ".cml" +# cml.memcache-hosts = ( "127.0.0.1:11211" ) +# }}} + +# {{{ mod_webdav +# see webdav.txt +# +# $HTTP["url"] =~ "^/dav($|/)" { +# webdav.activate = "enable" +# webdav.is-readonly = "enable" +# } +# }}} + +# {{{ extra rules +# +# set Content-Encoding and reset Content-Type for browsers that +# support decompressing on-thy-fly (requires mod_setenv) +# $HTTP["url"] =~ "\.gz$" { +# setenv.add-response-header = ("Content-Encoding" => "x-gzip") +# mimetype.assign = (".gz" => "text/plain") +# } + +# $HTTP["url"] =~ "\.bz2$" { +# setenv.add-response-header = ("Content-Encoding" => "x-bzip2") +# mimetype.assign = (".bz2" => "text/plain") +# } +# +# }}} + +# {{{ debug +# debug.log-request-header = "enable" +# debug.log-response-header = "enable" +# debug.log-request-handling = "enable" +# debug.log-file-not-found = "enable" +# }}} + +# vim: set ft=conf foldmethod=marker et : +include "/etc/lighttpd/conf.d/*.conf" \ No newline at end of file diff --git a/etc/lighttpd/mime-types.conf b/etc/lighttpd/mime-types.conf new file mode 100644 index 0000000..f24d4d8 --- /dev/null +++ b/etc/lighttpd/mime-types.conf @@ -0,0 +1,79 @@ +############################################################################### +# Default mime-types.conf for Gentoo. +# include'd from lighttpd.conf. +# $Header: /var/cvsroot/gentoo-x86/www-servers/lighttpd/files/conf/mime-types.conf,v 1.4 2010/03/14 21:45:18 bangert Exp $ +############################################################################### + +# {{{ mime types +mimetype.assign = ( + ".svg" => "image/svg+xml", + ".svgz" => "image/svg+xml", + ".pdf" => "application/pdf", + ".sig" => "application/pgp-signature", + ".spl" => "application/futuresplash", + ".class" => "application/octet-stream", + ".ps" => "application/postscript", + ".torrent" => "application/x-bittorrent", + ".dvi" => "application/x-dvi", + ".gz" => "application/x-gzip", + ".pac" => "application/x-ns-proxy-autoconfig", + ".swf" => "application/x-shockwave-flash", + ".tar.gz" => "application/x-tgz", + ".tgz" => "application/x-tgz", + ".tar" => "application/x-tar", + ".zip" => "application/zip", + ".dmg" => "application/x-apple-diskimage", + ".mp3" => "audio/mpeg", + ".m3u" => "audio/x-mpegurl", + ".wma" => "audio/x-ms-wma", + ".wax" => "audio/x-ms-wax", + ".ogg" => "application/ogg", + ".wav" => "audio/x-wav", + ".gif" => "image/gif", + ".jpg" => "image/jpeg", + ".jpeg" => "image/jpeg", + ".png" => "image/png", + ".xbm" => "image/x-xbitmap", + ".xpm" => "image/x-xpixmap", + ".xwd" => "image/x-xwindowdump", + ".css" => "text/css", + ".html" => "text/html", + ".htm" => "text/html", + ".js" => "text/javascript", + ".asc" => "text/plain", + ".c" => "text/plain", + ".h" => "text/plain", + ".cc" => "text/plain", + ".cpp" => "text/plain", + ".hh" => "text/plain", + ".hpp" => "text/plain", + ".conf" => "text/plain", + ".log" => "text/plain", + ".text" => "text/plain", + ".txt" => "text/plain", + ".diff" => "text/plain", + ".patch" => "text/plain", + ".ebuild" => "text/plain", + ".eclass" => "text/plain", + ".rtf" => "application/rtf", + ".bmp" => "image/bmp", + ".tif" => "image/tiff", + ".tiff" => "image/tiff", + ".ico" => "image/x-icon", + ".dtd" => "text/xml", + ".xml" => "text/xml", + ".mpeg" => "video/mpeg", + ".mpg" => "video/mpeg", + ".mov" => "video/quicktime", + ".qt" => "video/quicktime", + ".avi" => "video/x-msvideo", + ".asf" => "video/x-ms-asf", + ".asx" => "video/x-ms-asf", + ".wmv" => "video/x-ms-wmv", + ".bz2" => "application/x-bzip", + ".tbz" => "application/x-bzip-compressed-tar", + ".tar.bz2" => "application/x-bzip-compressed-tar" + ) +# }}} + +# vim: set ft=conf foldmethod=marker et : diff --git a/etc/lighttpd/mod_cgi.conf b/etc/lighttpd/mod_cgi.conf new file mode 100644 index 0000000..b896879 --- /dev/null +++ b/etc/lighttpd/mod_cgi.conf @@ -0,0 +1,33 @@ +############################################################################### +# mod_cgi.conf +# include'd by lighttpd.conf. +# $Header: /var/cvsroot/gentoo-x86/www-servers/lighttpd/files/conf/mod_cgi.conf,v 1.1 2005/08/27 12:36:13 ka0ttic Exp $ +############################################################################### + +# +# see cgi.txt for more information on using mod_cgi +# + +server.modules += ("mod_cgi") + +# NOTE: this requires mod_alias +alias.url = ( + "/cgi-bin/" => var.basedir + "/cgi-bin/" +) + +# +# Note that you'll also want to enable the +# cgi-bin alias via mod_alias (above). +# + +$HTTP["url"] =~ "^/cgi-bin/" { + # disable directory listings + #dir-listing.activate = "disable" + # only allow cgi's in this directory + cgi.assign = ( + ".pl" => "/usr/bin/perl", + ".cgi" => "/usr/bin/perl" + ) +} + +# vim: set ft=conf foldmethod=marker et : diff --git a/etc/lighttpd/mod_fastcgi.conf b/etc/lighttpd/mod_fastcgi.conf new file mode 100644 index 0000000..549b84c --- /dev/null +++ b/etc/lighttpd/mod_fastcgi.conf @@ -0,0 +1,17 @@ +############################################################################### +# mod_fastcgi.conf +# include'd by lighttpd.conf. +# $Header: /var/cvsroot/gentoo-x86/www-servers/lighttpd/files/conf/mod_fastcgi.conf-1.4.13-r2,v 1.1 2007/04/01 23:22:00 robbat2 Exp $ +############################################################################### + +server.modules += ("mod_fastcgi") +fastcgi.server = ( ".php" => + ( "localhost" => + ( + "socket" => "/run/lighttpd/lighttpd-fastcgi-php-" + PID + ".socket", + "bin-path" => "/usr/bin/php-cgi" + ) + ) + ) + +# vim: set ft=conf foldmethod=marker et : diff --git a/etc/lighttpd/mod_fastcgi_fpm.conf b/etc/lighttpd/mod_fastcgi_fpm.conf new file mode 100644 index 0000000..926137a --- /dev/null +++ b/etc/lighttpd/mod_fastcgi_fpm.conf @@ -0,0 +1,16 @@ +############################################################################### +# mod_fastcgi_fpm.conf +# include'd by lighttpd.conf. +############################################################################### + +server.modules += ("mod_fastcgi") +fastcgi.server = ( ".php" => + ( "localhost" => + ( + "host" => "127.0.0.1", + "port" => "9000" + ) + ) + ) + +# vim: set ft=conf foldmethod=marker et : diff --git a/init.sh b/init.sh new file mode 100644 index 0000000..daf0a5d --- /dev/null +++ b/init.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +if [ ! -d "/var/www/werc/sites/$HOSTNAME" ]; then + echo "Index directory for hostname $HOSTNAME does not exist. Creating..." + cp -r /var/www/werc/sites/werc.cat-v.org "/var/www/werc/sites/$HOSTNAME" + echo "# Hello World!" > "/var/www/werc/sites/$HOSTNAME/index.md" +fi + +CONF_FILE="/etc/lighttpd/conf.d/$HOSTNAME.conf" +if [ ! -f "$CONF_FILE" ]; then + echo "Creating new configuration file: $CONF_FILE" + cat << EOF > "$CONF_FILE" +\$HTTP["host"] =~ "^$(echo "$HOSTNAME" | sed 's/\./\\./g')$" { + index-file.names = ( ) + server.error-handler-404 = "/werc.rc" + alias.url += ( "/werc.rc" => "/var/www/werc/bin/werc.rc" ) + cgi.assign += ( ".rc" => "" ) +} +EOF +fi + +echo "Running lighttpd" +chmod a+w /dev/pts/0 +exec lighttpd -D -f /etc/lighttpd/lighttpd.conf diff --git a/werc/README b/werc/README new file mode 100644 index 0000000..b4dc773 --- /dev/null +++ b/werc/README @@ -0,0 +1,79 @@ +werc - a minimalist document management system +---------------------------------------------- + +Werc is a content management system and web (anti-)framework designed to be simple to +use, simple to setup, simple to hack on, and not get in the way while allowing +users easy customization. + +For more information see the official website: http://werc.cat-v.org/ + + +Installation +------------ + +Requirements: + +* An http server that can handle CGIs +* Plan 9 from User Space: http://swtch.com/plan9port, + Or 9base-tip: http://tools.suckless.org/9base, + Or frontbase: http://openbsd.stanleylieber.com/frontbase + +Note: Werc by default expects the Plan 9 tools to be installed under +/bin/, if you have installed them elsewhere you will need to edit the +#! line in bin/werc.rc and customize the $plan9port variable in your +etc/initrc.local. + + +Instructions: + +Untar werc at your desired location, configure httpd to use +/path-to-your-werc-installation/bin/werc.rc as a cgi-script, it is recommended +that you make werc.rc handle all non-static files (this can be done by setting +it up as your 404 handler) and setup your virtual hosts to handle static files +by setting the document root for the domain to +/path-to-werc-installation/sites/yourdomain.com/, and create a directory for +your web site under sites/ where you can start adding content right away. + +If you will want to allow updates via the web interface (eg., for wiki or +comments apps) make sure all files under sites/ are writable by the user your +cgi will run as, usually www-data, for example by doing: chown -R :www-data +sites/; chmod -R g+w sites/ + +If your Plan 9 binaries are located somewhere else than the standard /bin/ you +will need to edit the first line of bin/werc.rc (Note that p9p in particular is +picky about where it is located, once you run ./INSTALL you should *not* move +it to a different directory without running ./INSTALL again.) + +For general configuration options copy etc/initrc to etc/initrc.local and +customize it as needed. Site (and directory) specific options can be set in a +sites/example.com/_werc/config file inside the site's directory. To customize +templates and included files you can store your own version of the files in +lib/ under sites/example.com/_werc/lib. + +The source tree for the werc website is included under sites/werc.cat-v.org as +an example, feel free to use it as a template for your own site. + +For more details see the documentation section of the website: +http://werc.cat-v.org/docs/ + + +Contact +------- + +For comments, suggestions, bug reports or patches join the werc mailing list +at: http://werc.cat-v.org or the irc channel #cat-v in irc.freenode.org + +If you have a public website that uses werc I would love to hear about it and +get feedback about you experience setting it up. + +Thanks +------ + +Garbeam, Kris Maglione, sqweek, soul9, mycroftiv, maht, yiyus, cinap_lenrek, +khm and many others for their ideas, patches, testing and other contributions. + + +License +------- + +Werc is in the public domain. diff --git a/werc/apps/barf/.hg_archival.txt b/werc/apps/barf/.hg_archival.txt new file mode 100644 index 0000000..d6c1290 --- /dev/null +++ b/werc/apps/barf/.hg_archival.txt @@ -0,0 +1,6 @@ +repo: 77501160f26f7411d00111255a38267f9973ec27 +node: e422b2d51d185ecbbdb180a28fdd13cac672be03 +branch: default +latesttag: null +latesttagdistance: 25 +changessincelatesttag: 25 diff --git a/werc/apps/barf/README b/werc/apps/barf/README new file mode 100755 index 0000000..ab74443 --- /dev/null +++ b/werc/apps/barf/README @@ -0,0 +1,158 @@ +BARF - emit HTML + +DESCRIPTION + BARF utilizes rc(1) and command line tools to compile a structured + directory of files into a single page of HTML. Tagging and RSS 2.0 + feeds have been implemented. + +SETUP + To enable BARF, add: + + conf_enable_barf + + to _werc/config under the site root. + + To configure BARF, copy or create the following files under the site + root (example files have been included in this distribution): + + _werc/barf/config + A list of variables that control various site options: + + barf_type=paste # blog, image, log, paste + posts_per_page=10 + show_ascending=0 + show_footer=0 + show_header=0 + show_sidebar=0 + require_login=0 # if not logged in, redirect to /login + allow_anon=1 # allow posts without logging in + show_disqus=0 # include disqus comments template + # from _werc/barf/disqus + + _werc/barf/footer + HTML or markdown that will appear as the foot of + the BARF content area. + + _werc/barf/header + HTML or markdown that will appear at the head of + the BARF content area. + + _werc/barf/sidebar + HTML or markdown that will appear on one side of + the BARF content area. + + Finally, sample stylesheets are provided in the directory + pub/. Copy any of these to _werc/pub/style.css to try + them out. + +POSTS + Posts are stored in the directory src/ relative to the + site root. + + Directory names in src/ that do not match the regular + expression ^[0-9]*$ will not be included in the listing of + posts that are displayed in the browser. However, such + directories are still accessible when called directly via + an appropriately constructed URL. + + A post's directory contains the following files and + directories (an example post's directory has been + included in this distribution): + + body + date + img/ + link + tags/ + title + + The img/ directory contains images uploaded to the + image board, including the original image and a + thumbnail version, resized to no greater than 500 + pixels wide and 600 pixels tall. + + The tags/ directory contains one empty file named + for each tag associated with the post. + + The site root contains a file named tags that is compr- + ised of an index of the tags associated with each post. + This index is consulted when searching for a given tag in + the web browser. + +UTILS + bin/gf + Parse Livejournal and Tumblr RSS feeds into + BARF posts. (Abandoned, may no longer work.) + bin/gk + Create a list of known tags in the site root in + a file named known_tags. + bin/gr + Parse Google Reader bundles into BARF posts. + bin/gt + Create an index of tags in the site root in a file + named tags. + + For more information on these tools, read the source. + +ADMIN + Any tool that can create, alter, or delete flat files + and directories is sufficient to administer a BARF. + + Web-based login and administration utilizes werc's + built-in user authentication: + + http://domain.com/login + + After login, links to edit and delete will appear in + each post's meta data. + + Web-based administration requires that the src/ + directory and its sub-directories are writable by + the web server process. + +REQUIREMENTS + Unix + Plan9port or 9base are required. Site type + image requires ImageMagick and curl. Site + type url also requires curl if the user employs + the option to download remote URLs. These + utilities may be swapped out for others by + altering the source. + +SOURCE + http://plan9.stanleylieber.com/werc/apps/barf.tgz + https://code.9front.org/hg/barf + +EXAMPLES + blog + http://read.stanleylieber.com + RSS feeds are converted by the utility rrss[0] + and stored as individual blog posts. + image + http://img.stanleylieber.com + Hybrid public/private image board. Requires + standard werc authentication to post, but all + posts are visible to the public. + paste + http://okturing.com + Public pastebin. No authentication required + to post. + url + http://url.stanleylieber.com + Private index of URL bookmarks, similar + in functionality to the old delicious.com. + (In fact, most of the index was imported + from delicious.) + +SEE ALSO + [0] https://code.9front.org/hg/rrss + +LICENSE + Public domain. + +BUGS + On Plan 9, if the web server process is run as user + none (typically the case), directories used for entering + posts or uploading/downloading files from the browser + must be set world writable. This could prove problematic + on multiuser systems. diff --git a/werc/apps/barf/app.rc b/werc/apps/barf/app.rc new file mode 100755 index 0000000..6758a61 --- /dev/null +++ b/werc/apps/barf/app.rc @@ -0,0 +1,80 @@ +fn conf_enable_barf{ + barf_base_uri=$conf_wd + barf_root=`{pwd} + conf_enable_app barf +} + +fn barf_init{ + p=`{echo $req_path | sed 's!^'^$barf_base_uri^'!!'} + barf_dir=`{basename -d $"p | sed 's!^\.$!!'} + barf_items=`{cat $barf_root/_werc/barf/items} + . ./apps/barf/lib/core + . ./apps/barf/barf/config + . $barf_root/_werc/barf/config + . ./apps/barf/lib/$barf_type + if(test -f $barf_root/_werc/barf/lib/$barf_type) + . $barf_root/_werc/barf/lib/$barf_type + if(~ $require_login 1 && ! ~ $req_path $barf_base_uri^login){ + check_user + if(~ $#logged_user 0) + post_redirect /login + } + if(~ $REQUEST_METHOD GET && ~ $REQUEST_URI *'='*){ + load_get_args + parse_get_args + } + if(~ $REQUEST_METHOD POST) + parse_post_args + if(~ $a_func add_post){ + if(~ $allow_anon 1 || {check_user && ! ~ $#logged_user 0}) + add_post + post_redirect / + } + if(~ $a_func edit_post delete_post dsrc){ + if(check_user && ! ~ $#logged_user 0){ + switch($a_func){ + case edit_post + edit_post + case delete_post + delete_post + case dsrc + dsrc + } + } + } + get_start + get_stop + get_tags + if(~ $req_path $barf_base_uri){ + extraHeaders=$"extraHeaders ^ \ +'' + handler_body_main=(tpl_handler `{barf_template barf}) + } + if not if(~ $req_path $barf_base_uri^index.rss){ + obarf_type=$barf_type # disgusting hack. fix! + barf_type=rss + . ./apps/barf/lib/rss + barf_setup_feed_handlers barf.tpl 'text/xml; charset=utf-8' + } + if not if(~ $req_path $barf_base_uri^login){ + barf_type=login + handler_body_main=(tpl_handler `{barf_template barf}) + } +} + +fn barf_setup_feed_handlers{ + handler_body_main=NOT_USED_by_barf_feeds + res_tail=() + http_content_type=$2 + headers=() + master_template=apps/barf/lib/$1 +} + +fn barf_template{ + if(test -f $barf_root/$"barf_dir/_werc/barf/lib/$1.tpl) + echo -n $barf_root/$"barf_dir/_werc/barf/lib/$1.tpl + if not if(test -f $barf_root/_werc/barf/lib/$1.tpl) + echo -n $barf_root/_werc/barf/lib/$1.tpl + if not + get_lib_file barf/$1.tpl apps/barf/lib/$1.tpl +} diff --git a/werc/apps/barf/barf/config b/werc/apps/barf/barf/config new file mode 100755 index 0000000..fd3c0ad --- /dev/null +++ b/werc/apps/barf/barf/config @@ -0,0 +1,9 @@ +barf_type=blog # blog, image, log, paste, url +site_tmp=_tmp # used by hoc on plan 9 +posts_per_page=10 +show_ascending=0 +show_footer=0 +show_header=0 +show_sidebar=0 +require_login=0 # if not logged in, redirect to /login +allow_anon=1 # allow posts without logging in diff --git a/werc/apps/barf/barf/footer b/werc/apps/barf/barf/footer new file mode 100755 index 0000000..97a9d6c --- /dev/null +++ b/werc/apps/barf/barf/footer @@ -0,0 +1 @@ +THIS IS THE FOOTER. diff --git a/werc/apps/barf/barf/header b/werc/apps/barf/barf/header new file mode 100755 index 0000000..a446ba5 --- /dev/null +++ b/werc/apps/barf/barf/header @@ -0,0 +1 @@ +THIS IS THE HEADER. diff --git a/werc/apps/barf/barf/sidebar b/werc/apps/barf/barf/sidebar new file mode 100755 index 0000000..61c58f2 --- /dev/null +++ b/werc/apps/barf/barf/sidebar @@ -0,0 +1 @@ +THIS IS THE SIDEBAR. diff --git a/werc/apps/barf/bin/bsrc b/werc/apps/barf/bin/bsrc new file mode 100755 index 0000000..cc35197 --- /dev/null +++ b/werc/apps/barf/bin/bsrc @@ -0,0 +1,174 @@ +#!/bin/rc +# Build static pages for $site. +rfork e +fn usage{ + echo usage: $0 [ domain.com ] >[1=2] + exit usage +} +if(~ $#1 0) + usage + +fn conf_enable_barf{ } + +werc=/var/www/werc +site=$werc/sites/$1 +barf_root=$site + +. $site/_werc/config +. $site/_werc/barf/config +. $werc/apps/barf/lib/core +. $werc/apps/barf/lib/$barf_type +if(test -f $site/_werc/barf/lib/$barf_type) + . $site/_werc/barf/lib/$barf_type +if(~ $show_ascending 1) + sort=(sort -nu) +if not + sort=(sort -nru) + +fn check_user{ } + +fn display_html_footers{ + echo ' +' +} + +fn display_html_headers{ + echo ' + + + '$"siteTitle' + + + + + + + + + +' +} + +fn display_prevnext{ + if(~ $#nstart 1){ + echo ' +
+ + ' + if(test $start -lt $pstop && ! ~ $start $pstart) + echo 'prev | ' + echo ' + + ' + if(test $nstart -gt $bposts($#bposts)) + echo 'next' + echo ' + +
+ ' + } +} + +fn get_post_list{ + if(~ $#posts 0){ + if(~ $id [0-9]*) + posts=$id + if not{ + posts=`{ + if(~ $tags all) + ls -p $site/src | + grep -e '^[0-9]*$' | + eval $sort | + sed -n $start^,^$stop^p + if not + grep -e '^.*\/'$tags'$' $site/tags | + awk -F '/' '{print $1;}' | + eval $sort | + sed -n $start^,^$stop^p + } + if(! ~ $posts [0-9]*) + posts=() + } + } +} + +fn print{ + display_html_headers + if(~ $show_header 1) + display_header + display_^$barf_type + if(~ $show_sidebar 1) + display_sidebar + if(~ $show_footer 1) + display_footer + display_html_footers +} + +fn print_id{ + echo 'No.'$"a_id'' +} + +fn print_tags{ + a_tags=`{ls -p $a_dir/tags} + a_tags=`{for(t in $a_tags) echo ''$t', '} + a_tags=`{echo $a_tags | awk '{print substr($0, 1, length($0) -1)}'} + echo ''$"a_tags'' +} + +fn print_title{ + a_title=`{cat $a_dir/title} + if(! ~ $#a_title 0){ + if(~ $barf_type log url) + echo ''$"a_title'' + if not + echo ''$"a_title'' + } +} + +cd $site + +# individual posts +bposts=`{ls -p $site/src | grep -v private | grep -e '^[0-9]*$' | eval $sort} +for(b in $bposts){ + id=$b posts=() print >$b.html + echo $"b^'.html' >[1=2] +} + +# paginated posts +start=$bposts(1) +stop=`{echo $bposts(1)^-^$posts_per_page | bc} +pstart=$start +pstop=$stop +while(test $start -ge $bposts($#bposts)){ + if(test $stop -lt $bposts($#bposts)) + stop=$bposts($#bposts) + nstart=`{echo $stop^-^1 | bc} + nstop=`{echo $stop^-^$posts_per_page^-1 | bc} + pposts=`{ + for(i in `{seq $stop $start | eval $sort}) + if(test -d $site/src/$i) + echo $i + } + tags=all posts=$pposts print >$start^-^$stop.html + echo $"start^'-'^$"stop^'.html' >[1=2] + pstart=$start + pstop=$stop + start=`{echo $stop^-1 | bc} + stop=`{echo $start^-^$posts_per_page | bc} +} +cp `{ls [0-9]*-[0-9]*.html | sort -n | tail -1} index.html +if(test -x /boot/factotum) + chmod +t [0-9]*.html [0-9]*-[0-9]*.html index.html + +# tags +for(b in `{awk -F '/' '{print $3;}' tags | sort -u}){ + btags=$b + mkdir -p tag/$btags + bposts=`{grep -e '^.*\/'$btags'$' tags | awk -F '/' '{print $1;}' | eval $sort} + start=$bposts(1) + stop=$bposts($#bposts) + tags=all posts=$bposts print >tag/$btags/index.html + echo tag/$btags/index.html >[1=2] + if(test -x /boot/factotum) + chmod +t tag tag/$btags tag/$btags/index.html +} diff --git a/werc/apps/barf/bin/dsrc b/werc/apps/barf/bin/dsrc new file mode 100755 index 0000000..4601f24 --- /dev/null +++ b/werc/apps/barf/bin/dsrc @@ -0,0 +1,31 @@ +#!/bin/rc +# 2016-05-01T18:47:42-0400 +# Delete posts $low through $high. +rfork e +dhost=ur.inri.net +fn usage { + echo usage: dsrc [ -r n ] [ -t n ] >[1=2] + exit usage +} +switch($1){ +case -r + site=/usr/sl/www/werc/sites/read.stanleylieber.com +case -t + site=/usr/sl/www/werc/sites/tumblr.stanleylieber.com +case * + usage +} +if(! ~ $sysname ur){ + rcpu -h $dhost -c dsrc $* + exit +} +low=`{ls -p $site/src | sort -n | sed 1q} +high=$2 +cd $site/src && rm -rf `{seq $low $high} +{ +for(i in `{seq $low $high}) + echo ',x/^'$i'\/.*\n/d' +echo w +echo w +echo q +} | sam -d $site/tags >[2]/dev/null diff --git a/werc/apps/barf/bin/gf b/werc/apps/barf/bin/gf new file mode 100755 index 0000000..6d257fc --- /dev/null +++ b/werc/apps/barf/bin/gf @@ -0,0 +1,426 @@ +#!/bin/rc +# Parse RSS feeds from livejournal or tumblr into BARF blog posts +# for the specified site. If a post with a matching already +# exists, no new post will be created for that . Accordingly, +# the gf script may run slowly for sites with a large number of +# existing posts. Tags will be created from each . +rfork en +switch($1){ +case 1oct1993_lj + feed=http://feeds.feedburner.com/Sl/1oct1993 + site=1oct1993.com + tags=(rss) +case architecture + feed='http://pipes.yahoo.com/pipes/pipe.run?_id=6e361b590b57934fb1e7c4e29339d619&_render=rss' + site=read.stanleylieber.com + tags=(architecture) +case comics + feed='http://pipes.yahoo.com/pipes/pipe.run?_id=6bc617a6b20aafd526affafc9a28a5d5&_render=rss' + site=read.stanleylieber.com + tags=(comics) +case fg_lj + feed=http://feeds.feedburner.com/Sl/flamesgif + site=flamesgif.com + tags=(rss livejournal) +case inri_lj + feed=http://feeds.feedburner.com/Sl/itrecords + site=inri.net + tags=(rss livejournal) +case mf_lj + feed=http://feeds.feedburner.com/Sl/massivefictions + site=massivefictions.com + tags=(rss livejournal) +case other_lj + feed=http://feeds.feedburner.com/SL/other + site=other.stanleylieber.com + tags=() +case read + #feed=http://feeds.feedburner.com/SL/g/friends + #feed='http://pipes.yahoo.com/pipes/pipe.run?_id=f5d60acfd41497310d74900270192600&_render=rss' + feed='http://pipes.yahoo.com/pipes/pipe.run?_id=d1f7146306b019d96d768facf95eebd9&_render=rss' + site=test.stanleylieber.com + tags=() +case sl_lj + feed=http://feeds.feedburner.com/ImNotReallyStanleyLieber + site=stanleylieber.com + tags=(rss livejournal) +case sl_tumblr + feed=http://stanleylieber.tumblr.com/rss + site=stanleylieber.com + tags=(rss tumblr) +case ta_lj + feed=http://feeds.feedburner.com/Sl/text_adventure + site=textadventure.stanleylieber.com + tags=(rss livejournal) +case tech + feed='http://pipes.yahoo.com/pipes/pipe.run?_id=6dd49be6e34a6871db9bcfc74d4b36b1&_render=rss' + site=read.stanleylieber.com + tags=(tech) +case * + echo 'Usage: gf [ ... ]' >[1=2] + exit usage +} + +file=/tmp/gf.$1 +werc=/usr/sl/www/werc + +if(test -f /boot/factotum) + cmd=hget +if not + cmd='curl -s' + +fn get_feed{ + $"cmd $feed >$file.work + { + echo ' +,s/ //g +,s/\"/\"/g +,s/\"/\"/g +,s/\&/\&/g +,s/\&/\&/g +,s/\'/''/g +,s/\,/,/g +,s/\-/-/g +,s/\./\./g +,s/\//\//g +,s/\:/:/g +,s/\;/;/g +,s/\<//g +,s/\>/>/g +,s/\_/_/g +,s/\|/\|/g +,s/\n//g +,s/<\/item>/\n<\/item>\n/g +,s/^/\n/g +,s/^[ ]*.*<\/description>/ s/\n//g +w +q +' + echo +} | sam -d $file.work >[2]/dev/null >[1=2] + awk '/(^||||<description>|<comments>|<category>|<\/item>)/ {print $0;}' $file.work >$file +} + +fn get_tags{ + switch($a_link){ + case *1oct1993* + tags=($tags 1oct1993) + case *9front* + tags=($tags software plan9 9front) + case *amyearles* *pushedunder* *seaglass* *woolandwater* + tags=($tags amy_earles) + case *animenewsnetwork* + tags=($tags telescreen anime) + case *spikejapan* + tags=($tags japan comics manga telescreen anime) + case *ArchDaily* *archdaily* + tags=($tags archdaily architecture) + case *bldgblog* + tags=($tags bldgblog architecture) + case *kazuyosejima* + tags=($tags japan architecture) + case *Minimalissimo* + tags=($tags minimalissimo design architecture) + case *ArtFagCity* *artfagcity* + tags=($tags artfagcity art) + case *rhizome-fp* + tags=($tags rhizome-fp art) + case *rhizome* + tags=($tags rhizome art) + case *starwarsmodern* + tags=($tags starwarsmodern art) + case *tokyoartbeat* + tags=($tags tokyoartbeat japan art) + case *trendbeheer* + tags=($tags trendbeheer art) + case *ValentinaTanni* + tags=($tags valentinatanni art) + case *vvork* + tags=($tags vwork art) + case *auriea* *tale-of-tales* *taleoftales* + tags=($tags auriea) + case *basscomm* *closeoutwarrior* *crummysocks* *gamerrelocationproject* *protipoftheday* *PushButtonB* *pushbuttonb* + tags=($tags video_games basscomm) + case *benjaminmarra* + tags=($tags comics benjamin_marra) + case *boingboing* + tags=($tags boingboing) + case *bushinbooks* *henka* + tags=($tags budo) + case *alexaanddave* *CEREBUS* *Cerebus* *cerebus* *davesim* *gerhard* + tags=($tags comics cerebus gerhard) + case *coilhouse* + tags=($tags coilhouse) + case *arche-arc* + tags=($tags arche comics) + case *blaiselarmee* + tags=($tags blaise_larmee comics) + case *bleedingcool* + tags=($tags bleedingcool comics) + case *bobgreenberger* + tags=($tags bob_greengerger comics) + case *coldheatcomics* + tags=($tags coldheat comics) + case *comicbookresources* + tags=($tags cbr comics) + case *comicsbeat* + tags=($tags comicsbeat comics) + case *ComicsComics* *comicscomics* + tags=($tags comicscomics comics) + case *coveredblog* + tags=($tags coveredblog comics) + case *dcfifty-too* + tags=($tags dcfifty-too comics) + case *Destructoid* *destructoid* + tags=($tags destructoid video_games) + case *economist.com* + tags=($tags economist) + case *ferrandelgado* + tags=($tags ferran_delgado comics) + case *eddiecampbell* + tags=($tags eddie_campbell comics) + case *factualopinion* + tags=($tags factualopinion comics) + case *floating_world* *floatingworld* + tags=($tags floating_world comics) + case *frankmiller* + tags=($tags frank_miller comics) + case *humancolor* + tags=($tags humancolor comics) + case *jerkcity* + tags=($tags jerkcity comics) + case *newconstructionblog* + tags=($tags newconstruction manga comics) + case *ohdannyboy* + tags=($tags ohdannyboy comics) + case *pulphope* + tags=($tags pulphope comics) + case *pwbeat* + tags=($tags pwbeat comics) + case *reliablecomics* + tags=($tags reliablecomics comics) + case *reneefrench* + tags=($tags renee_french comics) + case *rickveitch* + tags=($tags rick_veitch comics) + case *smbc-comics* + tags=($tags smbc comics) + case *studygroup* + tags=($tags studygroup comics) + case *xkcd* + tags=($tags xkcd comics) + case *bowiesongs* *DavidBowie* *davidbowie* + tags=($tags music david_bowie) + case *designboom* + tags=($tags designboom design) + case *dezeen* + tags=($tags dezeen design) + case *infosthetics* + tags=($tags infosthetics design) + case *inhabitat* + tags=($tags inhabitat architecture design) + case *luigicolani* + tags=($tags luigicolani design) + case *mocoloco* + tags=($tags mocoloco design) + case *sydmead* + tags=($tags sydmead design) + case *dzima* + tags=($tags dzima) + case *bbcicecream* + tags=($tags bbcicecream fashion) + case *DamStyle *damstyle* + tags=($tags damstyle fashion) + case *facehunter* + tags=($tags facehunter fashion) + case *StilInBerlin* + tags=($tags germany fashion) + case *jstreets* + tags=($tags jstreets japan fashion) + case *stylefromtokyo* + tags=($tags stylefromtokyo japan fashion) + case *tokyofashion* + tags=($tags tokyofashion japan fashion) + case *flames.gif* *flamesgif* + tags=($tags flames.gif) + case *contemporary-home-computing* + tags=($tags software flames.gif) + case *kurzweil* + tags=($tags kurzweil future) + case *longnow* + tags=($tags longnow future) + case *OpenTheFuture* + tags=($tags openthefuture future) + case *golang* *blog.nella.org* + tags=($tags golang) + case *googlepluses* + tags=($tags google) + case *news.ycombinator.com* + tags=($tags hackernews hack) + case *seanbonner* + tags=($tags sean_bonner hack) + case *banriman* + tags=($tags banriman japan) + case *japansubculture* + tags=($tags japansubculture japan) + case *jeansnow* + tags=($tags jeansnow japan) + case *Kotaku* *kotaku* + tags=($tags kotaku video_games) + case *eforemario* + tags=($tags before_mario video_games) + case *nakakobooks* + tags=($tags books nakakobooks japan) + case *ozawamaria* + tags=($tags maria_ozawa japan) + case *shisaku.blogspot.com* + tags=($tags shisaku japan) + case *jimshooter* + tags=($tags comics jim_shooter) + case *LettersOfNote* *lettersofnote* + tags=($tags letters) + case *nasa*letters.rss* + tags=($tags nasa letters) + case *hellodamage* *manganews* *naokiurasawa* *samehat* + tags=($tags comics manga) + case *mangatraders* + tags=($tags p2p comics manga) + case *hortonheardawho* + tags=($tags hortonheardawho flickr nasa mars) + case *me-vs-gutenberg* *mevsgutenberg* + tags=($tags martin_sand) + case *marxy* + tags=($tags marxy) + case *etamodern* + tags=($tags metamodern) + case *aviationintel* + tags=($tags aviationintel mil) + case *aviationweek* + tags=($tags aviationweek mil) + case *codeonemagazine* + tags=($tags codeonemagazine mil) + case *geimint* + tags=($tags geimint mil) + case *momus* *mrstsk* + tags=($tags books music momus) + case *bjork* *toog* + tags=($tags music) + case *nasa.gov* + tags=($tags space nasa) + case *mongoliad* + tags=($tags neal_stephenson) + case *gaiman* + tags=($tags comics neil_gaiman) + case *nin.com* *feeds.nin.com* + tags=($tags music nin) + case *nix-os* *syssoftware* + tags=($tags plan9 nix) + case *bsdly* *OPENBSD* *OpenBSD* *openbsd* *scientist-home* *undeadly* + tags=($tags software openbsd) + case *godownmatthew* *mysticmilk* *petetoms* + tags=($tags pete_toms) + case *Pitchfork* *pitchfork* + tags=($tags music pitchfork) + case *9gridchan* *cat-v* *maht0x0r* *Plan9* *plan9* + tags=($tags software plan9) + case *FlauntTalks* *prince.org* *purpleinterviews* *wendyandlisa* + tags=($tags music prince) + case *commandcenter* *rob_pike* + tags=($tags golang plan9 rob_pike) + case *prometheus* + tags=($tags telescreen prometheus) + case *reddit.com* + tags=($tags reddit) + case *swtch.com* + tags=($tags golang plan9 rsc) + case *bunniestudios* + tags=($tags bunniestudios security) + case *jwz* + tags=($tags jwz security) + case *Krebs* *krebs* + tags=($tags krebs security) + case *scarybeastsecurity* + tags=($tags scarybeast security) + case *schneier* + tags=($tags bruce_schneier security) + case *chinchillakwak* *skwak* + tags=($tags skwak) + case *slashdot* + tags=($tags slashdot) + case *stanleylieber* + tags=($tags stanleylieber) + case *fastcompany* + tags=($tags fastcompany tech) + case *danharmon* + tags=($tags danharmon telescreen) + case *mindlessones* + tags=($tags mindlessones telescreen) + case *tcj.com* + tags=($tags comics tcj) + case *TEDblog* *ted.com* + tags=($tags ted) + case *ticom* + tags=($tags ticom security) + case *orrentfreak* + tags=($tags p2p torrentfreak) + case *ultra*culture* + tags=($tags ultraculture) + case *kleinletters* + tags=($tags comics todd_klein) + case *plaidstallions* + tags=($tags plaidstallions toys) + case *shojikawamori* + tags=($tags shojikawamori japan toys) + } + echo -n $tags +} + +fn parse_posts{ + ifs=' +' { + posts=`{cat $file} + for(i in `{seq 1 $#posts | sort -nr}){ + post=`{echo $posts($i) | sed 's/> </>\n</g' | grep -v -e '<comments>'} + if(! ~ $post ''){ + a_title=`{echo $post | grep -e 'title>' | sed 's/^.*<title>//g; s/<\/title>.*$//g'} + a_date=`{echo $post | grep -e '<pubDate>' | sed 's/^.*<pubDate>//g; s/<\/pubDate>.*$//g'} + a_link=`{echo $post | grep -e '<link>' | sed 's/^.*<link>//g; s/<\/link>.*$//g; s/^.*http/http/g'} + a_tags=`{echo $post | grep -e '<category>' | sed 's/^.*<\/comments>//g; s/^.*<description>//g; s/^.*<\/description>//g; s/^.*<\/pubDate>//g; s/<category>/ /g; s/<\/category>//g; s/<dc.*$//g; s/^ //g; s/ $//g'} + a_tags=`{for(j in $a_tags){ echo $j | sed 's/^.*(<|>).*$//g'}} + a_body=`{echo $post | grep -e '<description>' | sed 's/^.*<description>//g; s/<\/description>.*$//g'} + a_id=`{echo `{ls -p $werc/sites/$site/src | sort -n | tail -1}^+1 | bc} + if(~ $#a_id 0) + a_id=1 + while(test -d $werc/sites/$site/src/$a_id) + a_id=`{echo $a_id^+1 | bc} + if(! ~ $"a_link '' && ! ~ $"a_link `{cat $werc/sites/$site/src/*/link}){ + mkdir -p $werc/sites/$site/src/$a_id/tags # big fat race + echo $"a_title >$werc/sites/$site/src/$a_id/title + echo $"a_date >$werc/sites/$site/src/$a_id/date + echo $"a_link >$werc/sites/$site/src/$a_id/link + echo $"a_body '</a></li></ul>' >$werc/sites/$site/src/$a_id/body + ifs=' ' { + for(j in `{get_tags}){ + >$werc/sites/$site/src/$a_id/tags/$j + echo $a_id/tags/$j >>$werc/sites/$site/tags + } + } + } + if(test -f /boot/factotum && ~ $site *.stanleylieber.com) + for(i in `{f $werc/sites/$site/src/$a_id}) + chmod +t $i + } + } + } +} + +if(test -f /boot/factotum && test -f /rc/bin/hget) + webfs +get_feed +parse_posts diff --git a/werc/apps/barf/bin/gk b/werc/apps/barf/bin/gk new file mode 100755 index 0000000..06652e6 --- /dev/null +++ b/werc/apps/barf/bin/gk @@ -0,0 +1,20 @@ +#!/bin/rc +# Create an index of known_tags in $werc/sites/$site/known_tags +if(! ~ $#1 0) + base=$1 +if not if(~ $#barf_root 1 && $#barf_base 1) + base=$barf_root/$"barf_base +if not + base=`{pwd} + +if(test -f $base/_known_tags) + rm $base/_known_tags +for(i in `{cat $base/etc/tags}){ + grep -e '^.*\/'$i'$' $base/tags | + awk -F '/' '{print $3;}' | + sort | + uniq -c | + awk '{print $2 " " $1;}' >>$base/_known_tags +} +if(test -f $base/_known_tags) + cp $base/_known_tags $base/known_tags diff --git a/werc/apps/barf/bin/gr b/werc/apps/barf/bin/gr new file mode 100755 index 0000000..f24a0ca --- /dev/null +++ b/werc/apps/barf/bin/gr @@ -0,0 +1,415 @@ +#!/bin/rc +# Parse RSS feeds from Google Reader bundles into BULGE blog posts. +# If a post with a matching <link> already exists, no new post will +# be created for that <item>. Accordingly, the gr script may run +# slowly for sites with a large number of existing posts. Tags will +# be created from each <category>. +rfork en +switch($1){ +case architecture + feed='http://pipes.yahoo.com/pipes/pipe.run?_id=6e361b590b57934fb1e7c4e29339d619&_render=rss' + site=read.stanleylieber.com + tags=(architecture) +case comics + feed='http://pipes.yahoo.com/pipes/pipe.run?_id=6bc617a6b20aafd526affafc9a28a5d5&_render=rss' + site=read.stanleylieber.com + tags=(comics) +case friends + feed='https://www.google.com/reader/bundle/user%2F08193524211692385241%2Fbundle%2Ffriends' + site=read.stanleylieber.com + tags=(friends) +case tech + feed='http://pipes.yahoo.com/pipes/pipe.run?_id=6dd49be6e34a6871db9bcfc74d4b36b1&_render=rss' + site=read.stanleylieber.com + tags=(tech) +case * + echo usage: `{basename $0} '[ ... ]' >[1=2] + exit usage +} + +file=/tmp/gr.$1 +werc=/usr/sl/www/werc + +if(test -f /boot/factotum) + cmd=hget +if not + cmd='curl -s' + +fn f{ du -a $* | sed 's/^.* //g' } + +fn get_feed{ + $"cmd $feed >$file.work + { + echo ' +,s/\"/\"/g +,s/\"/\"/g +,s/\&/\&/g +,s/\&/\&/g +,s/\'/\''/g +,s/\,/,/g +,s/\-/-/g +,s/\./\./g +,s/\//\//g +,s/\:/:/g +,s/\;/;/g +,s/\</</g +,s/\</</g +,s/\=/=/g +,s/\>/>/g +,s/\>/>/g +,s/\_/_/g +,s/\|/\|/g +,/<div id="items">/d +/<div id="sidebar">/,d +,s/<h2 class="item-title">/\n<h2 class="item-title">/g +,s/<div class="item">.*$/HJDIVIDER/g +,s/\n//g +,s/HJDIVIDER/\n/g +1d +w +q +' + echo +} | sam -d $file.work >[2]/dev/null >[1=2] +} + +fn get_tags{ + switch($a_link){ + case *1oct1993* + tags=($tags 1oct1993) + case *9front* + tags=($tags software plan9 9front) + case *amyearles* *pushedunder* *seaglass* *woolandwater* + tags=($tags amy_earles) + case *animenewsnetwork* + tags=($tags telescreen anime) + case *spikejapan* + tags=($tags japan comics manga telescreen anime) + case *ArchDaily* *archdaily* + tags=($tags archdaily architecture) + case *bldgblog* + tags=($tags bldgblog architecture) + case *kazuyosejima* + tags=($tags japan architecture) + case *Minimalissimo* + tags=($tags minimalissimo design architecture) + case *ArtFCity* *ArtFagCity* *artfagcity* + tags=($tags artfagcity art) + case *rhizome-fp* + tags=($tags rhizome-fp art) + case *rhizome* + tags=($tags rhizome art) + case *starwarsmodern* + tags=($tags starwarsmodern art) + case *tokyoartbeat* + tags=($tags tokyoartbeat japan art) + case *trendbeheer* + tags=($tags trendbeheer art) + case *ValentinaTanni* + tags=($tags valentinatanni art) + case *vvork* + tags=($tags vwork art) + case *auriea* *tale-of-tales* *taleoftales* + tags=($tags auriea) + case *basscomm* *closeoutwarrior* *crummysocks* *gamerrelocationproject* *protipoftheday* *PushButtonB* *pushbuttonb* + tags=($tags video_games basscomm) + case *benjaminmarra* + tags=($tags comics benjamin_marra) + case *boingboing* + tags=($tags boingboing) + case *bushinbooks* *henka* + tags=($tags budo) + case *alexaanddave* *CEREBUS* *Cerebus* *cerebus* *davesim* *gerhard* + tags=($tags comics cerebus gerhard) + case *coilhouse* + tags=($tags coilhouse) + case *arche-arc* + tags=($tags arche comics) + case *blaiselarmee* + tags=($tags blaise_larmee comics) + case *bleedingcool* + tags=($tags bleedingcool comics) + case *bobgreenberger* + tags=($tags bob_greengerger comics) + case *coldheatcomics* + tags=($tags coldheat comics) + case *comicbookresources* + tags=($tags cbr comics) + case *comicsbeat* + tags=($tags comicsbeat comics) + case *ComicsComics* *comicscomics* + tags=($tags comicscomics comics) + case *coveredblog* + tags=($tags coveredblog comics) + case *dcfifty-too* + tags=($tags dcfifty-too comics) + case *Destructoid* *destructoid* + tags=($tags destructoid video_games) + case *economist.com* + tags=($tags economist) + case *ferrandelgado* + tags=($tags ferran_delgado comics) + case *eddiecampbell* + tags=($tags eddie_campbell comics) + case *factualopinion* + tags=($tags factualopinion comics) + case *floating_world* *floatingworld* + tags=($tags floating_world comics) + case *frankmiller* + tags=($tags frank_miller comics) + case *humancolor* + tags=($tags humancolor comics) + case *jerkcity* + tags=($tags jerkcity comics) + case *newconstructionblog* + tags=($tags newconstruction manga comics) + case *ohdannyboy* + tags=($tags ohdannyboy comics) + case *pulphope* + tags=($tags pulphope comics) + case *pwbeat* + tags=($tags pwbeat comics) + case *reliablecomics* + tags=($tags reliablecomics comics) + case *reneefrench* + tags=($tags renee_french comics) + case *rickveitch* + tags=($tags rick_veitch comics) + case *smbc-comics* + tags=($tags smbc comics) + case *studygroup* + tags=($tags studygroup comics) + case *xkcd* + tags=($tags xkcd comics) + case *bowiesongs* *DavidBowie* *davidbowie* + tags=($tags music david_bowie) + case *designboom* + tags=($tags designboom design) + case *dezeen* + tags=($tags dezeen design) + case *infosthetics* + tags=($tags infosthetics design) + case *inhabitat* + tags=($tags inhabitat architecture design) + case *luigicolani* + tags=($tags luigicolani design) + case *mocoloco* + tags=($tags mocoloco design) + case *sydmead* + tags=($tags sydmead design) + case *dzima* + tags=($tags dzima) + case *bbcicecream* + tags=($tags bbcicecream fashion) + case *DamStyle *damstyle* + tags=($tags damstyle fashion) + case *facehunter* + tags=($tags facehunter fashion) + case *StilInBerlin* + tags=($tags germany fashion) + case *jstreets* + tags=($tags jstreets japan fashion) + case *Stilinberlin* + tags=($tags stilinberlin germany fashion) + case *stylefromtokyo* + tags=($tags stylefromtokyo japan fashion) + case *tokyofashion* + tags=($tags tokyofashion japan fashion) + case *flames.gif* *flamesgif* + tags=($tags flames.gif) + case *contemporary-home-computing* + tags=($tags software flames.gif) + case *kurzweil* + tags=($tags kurzweil future) + case *longnow* + tags=($tags longnow future) + case *OpenTheFuture* + tags=($tags openthefuture future) + case *golang* *blog.nella.org* + tags=($tags golang) + case *googlepluses* + tags=($tags google) + case *news.ycombinator.com* + tags=($tags hackernews hack) + case *seanbonner* + tags=($tags sean_bonner hack) + case *banriman* + tags=($tags banriman japan) + case *japansubculture* + tags=($tags japansubculture japan) + case *jeansnow* + tags=($tags jeansnow japan) + case *Kotaku* *kotaku* + tags=($tags kotaku video_games) + case *eforemario* + tags=($tags before_mario video_games) + case *nakakobooks* + tags=($tags books nakakobooks japan) + case *ozawamaria* + tags=($tags maria_ozawa japan) + case *ibuya246* + tags=($tags shibuya246 japan) + case *shisaku.blogspot.com* + tags=($tags shisaku japan) + case *jimshooter* + tags=($tags comics jim_shooter) + case *LettersOfNote* *lettersofnote* + tags=($tags letters) + case *nasa*letters.rss* + tags=($tags nasa letters) + case *hellodamage* *manganews* *naokiurasawa* *samehat* + tags=($tags comics manga) + case *mangatraders* + tags=($tags p2p comics manga) + case *hortonheardawho* + tags=($tags hortonheardawho flickr nasa mars) + case *me-vs-gutenberg* *mevsgutenberg* + tags=($tags martin_sand) + case *marxy* + tags=($tags marxy) + case *etamodern* + tags=($tags metamodern) + case *aviationintel* + tags=($tags aviationintel mil) + case *aviationweek* + tags=($tags aviationweek mil) + case *codeonemagazine* + tags=($tags codeonemagazine mil) + case *geimint* + tags=($tags geimint mil) + case *bjork* + tags=($tags bjork music) + case *momus* *mrstsk* + tags=($tags books momus music) + case *toog* + tags=($tags toog music) + case *nasa.gov* + tags=($tags space nasa) + case *mongoliad* + tags=($tags neal_stephenson) + case *gaiman* + tags=($tags comics neil_gaiman) + case *nin.com* *feeds.nin.com* + tags=($tags music nin) + case *nix-os* *syssoftware* + tags=($tags plan9 nix) + case *bsdly* *OPENBSD* *OpenBSD* *openbsd* *scientist-home* *undeadly* + tags=($tags software openbsd) + case *godownmatthew* *mysticmilk* *petetoms* + tags=($tags pete_toms) + case *Pitchfork* *pitchfork* + tags=($tags music pitchfork) + case *9gridchan* *cat-v* *maht0x0r* *Plan9* *plan9* + tags=($tags software plan9) + case *FlauntTalks* *prince.org* *purpleinterviews* *wendyandlisa* + tags=($tags music prince) + case *commandcenter* *rob_pike* + tags=($tags golang plan9 rob_pike) + case *prometheus* + tags=($tags telescreen prometheus) + case *reddit.com* + tags=($tags reddit) + case *swtch.com* + tags=($tags golang plan9 rsc) + case *bunniestudios* + tags=($tags bunniestudios security) + case *jwz* + tags=($tags jwz security) + case *Krebs* *krebs* + tags=($tags krebs security) + case *scarybeastsecurity* + tags=($tags scarybeast security) + case *schneier* + tags=($tags bruce_schneier security) + case *chinchillakwak* *skwak* + tags=($tags skwak) + case *slashdot* + tags=($tags slashdot) + case *stanleylieber* + tags=($tags stanleylieber) + case *fastcompany* + tags=($tags fastcompany tech) + case *danharmon* + tags=($tags danharmon telescreen) + case *mindlessones* + tags=($tags mindlessones telescreen) + case *tcj.com* + tags=($tags comics tcj) + case *TEDblog* *ted.com* + tags=($tags ted) + case *ticom* + tags=($tags ticom security) + case *orrentfreak* + tags=($tags p2p torrentfreak) + case *ultra*culture* + tags=($tags ultraculture) + case *kleinletters* + tags=($tags comics todd_klein) + case *kennercollector* + tags=($tags kennercollector toys) + case *plaidstallions* + tags=($tags plaidstallions toys) + case *shojikawamori* + tags=($tags shojikawamori japan toys) + case *ruinedcartridge* + tags=($tags basscomm video_games) + } + echo -n $tags +} + +fn parse_posts{ + ifs=' +' { + for(post in `{sort -r $file.work}){ + if(! ~ $post ''){ + a_title=`{echo $post | sed 's/^.*<h2 class="item-title"><div class="">//g' | sed 's/<div class="item-info">.*$//g' | htmlfmt} + if(~ $#a_title 0) + a_title=`{echo $post | sed 's/^.*<div class="item-info">//g' | sed 's/<div class="item-annotations">.*$//g' | htmlfmt} + if(~ $#a_title 0) + a_title=fake + a_link=`{echo $post | sed 's/^.*<h2 class="item-title"><div class="">//g' | sed 's/<div class="item-info">.*$//g' | htmlfmt -a | sed 's/^.*\[//g' | sed 's/\].*$//g' | sed 's/ .*$//g'} + if(~ $#a_link 0 || ! ~ $"a_link http*) + a_link=`{echo $post | sed 's/^.*<h2 class="item-title"><div class="">//g' | sed 's/<div class="item-info">.*$//g' | sed 's/^.*<a href="//g' | sed 's/\".*$//g' | sed 's/^.*http/http/g' | sed 's/ .*$//g'} + if(~ $#a_link 0 || ! ~ $"a_link http*) + a_link=`{echo $post | sed 's/^.*<div class="item-info">//g' | sed 's/<div class="item-annotations">.*$//g' | htmlfmt -a | sed 's/^.*\[//g' | sed 's/\].*$//g' | sed 's/ .*$//g'} + if(~ $#a_link 0 || ! ~ $"a_link http*) + a_link=`{echo $post | sed 's/^.*<div class="item-info">//g' | sed 's/<div class="item-annotations">.*$//g' | sed 's/^.*<a href="//g' | sed 's/" class="f">.*$//g' | sed 's/\".*$//g' | sed 's/^.*http/http/g' | sed 's/ .*$//g'} + a_link=$a_link(1) + if(~ $#a_link 0 || ~ $"a_link '' || ! ~ $"a_link http*) + a_link=fake + if(! ~ $#a_link 1) + a_link=`{echo $a_link | awk '{print $1;}'} + a_date=`{date -n} + a_body=`{echo $post | sed 's/^.*<div class="item-body">//g' | sed 's/<div class="clear">.*$//g'} + if(~ $#a_body 0) + a_body=fake + a_id=`{echo `{ls -p $werc/sites/$site/src | sort -n | tail -1}^+1 | bc} + if(~ $#a_id 0) + a_id=1 + while(test -d $werc/sites/$site/src/$a_id) + a_id=`{echo $a_id^+1 | bc} + if(! ~ $"a_link `{cat $werc/sites/$site/src/*/link}){ + mkdir -p $werc/sites/$site/src/$a_id/tags # big fat race + echo $"a_title >$werc/sites/$site/src/$a_id/title + echo $"a_date >$werc/sites/$site/src/$a_id/date + echo $"a_link >$werc/sites/$site/src/$a_id/link + echo $"a_body '</a></li></ul>' >$werc/sites/$site/src/$a_id/body + ifs=' ' { + for(j in `{get_tags}){ + >$werc/sites/$site/src/$a_id/tags/$j + echo $a_id/tags/$j >>$werc/sites/$site/tags + } + } + } + if(test -f /boot/factotum) + for(i in `{f $werc/sites/$site/src/$a_id}) + chmod +t $i + } + } + } +} + +if(test -f /boot/factotum && test -f /rc/bin/hget) + webfs +get_feed +parse_posts diff --git a/werc/apps/barf/bin/gt b/werc/apps/barf/bin/gt new file mode 100755 index 0000000..ff330a7 --- /dev/null +++ b/werc/apps/barf/bin/gt @@ -0,0 +1,23 @@ +#!/bin/rc +# Create an index of tags in $werc/sites/$site/tags. BULGE +# greps this index when running a search on a given tag. +# This file is also maintained by the bin/g* commands, or +# when adding posts through the web interface. +if(! ~ $#1 0) + base=$1 +if not if(~ $#barf_root 1 && $#barf_base 1) + base=$barf_root/$"barf_base +if not + base=`{pwd} + +if(test -f $base/_tags) + rm $base/_tags +builtin cd $base/src +ls -p | +sort -n | +xargs du -a | +sed 's/^.* //g' | +grep -e '^[0-9]*\/tags' | +grep -v -e '^.*\/tags$' >>$base/_tags +if(test -s $base/_tags) + cp $base/_tags $base/tags diff --git a/werc/apps/barf/bin/gy b/werc/apps/barf/bin/gy new file mode 100755 index 0000000..9cbebdf --- /dev/null +++ b/werc/apps/barf/bin/gy @@ -0,0 +1,455 @@ +#!/bin/rc +# Parse XML RSS feeds from Yahoo Pipes into BARF blog posts +# for the specified site. If a post with a matching _link_ already +# exists, no new post will be created for that item. Accordingly, +# the gy script may run slowly for sites with a large number of +# existing posts. Tags will be created according to the rules +# defined in the get_tags() function. +# +# Requires 20h's xmlpull and rssread. +rfork en +switch($1){ +case read + feed='http://pipes.yahoo.com/pipes/pipe.run?_id=d1f7146306b019d96d768facf95eebd9&_render=rss' + site=read.stanleylieber.com + tags=() +case * + echo 'Usage: gy [ ... ]' >[1=2] + exit usage +} + +file=/tmp/gy.$1 +werc=/usr/sl/www/werc + +if(test -f /boot/factotum) + cmd=hget +if not + cmd='curl -s' + +fn cram{ + ssam ' +,s/^link:.*$/HJDIVIDER&HJDIVIDER/g +,s/^title:.*$/HJDIVIDER&HJDIVIDER/g +,s/\n//g +,s/HJDIVIDERtitle:/\n&/g + ' +} + +fn scape{ + ssam ' +,s/ //g +,s/\"/\"/g +,s/\"/\"/g +,s/\&/\&/g +,s/\&/\&/g +,s/\'/''/g +,s/\,/,/g +,s/\-/-/g +,s/\./\./g +,s/\//\//g +,s/\:/:/g +,s/\;/;/g +,s/\</</g +,s/\</</g +,s/\=/=/g +,s/\>/>/g +,s/\>/>/g +,s/\_/_/g +,s/\|/\|/g + ' +} + +fn get_posts{ + $"cmd $feed | rssread | cram | scape >$file + echo >>$file +} + +fn get_tags{ + switch($a_link){ + case *1oct1993* + tags=($tags 1oct1993) + case *9front* + tags=($tags software plan9 9front) + case *organicmentalcore* + tags=($tags aleks) + case *amyearles* *etsy.com* *pushedunder* *seaglass* *woolandwater* + tags=($tags amy_earles) + case *animenewsnetwork* + tags=($tags telescreen anime) + case *spikejapan* + tags=($tags japan comics manga telescreen anime) + case *augmented.org* + tags=($tags augmented.org ar) + case *ArchDaily* *archdaily* + tags=($tags archdaily architecture) + case *bldgblog* + tags=($tags bldgblog architecture) + case *kazuyosejima* + tags=($tags japan architecture) + case *Minimalissimo* + tags=($tags minimalissimo design architecture) + case *ArtFagCity* *ArtFCity* *artfagcity* + tags=($tags artfagcity art) + case *rhizome-fp* + tags=($tags rhizome-fp art) + case *rhizome* + tags=($tags rhizome art) + case *starwarsmodern* + tags=($tags starwarsmodern art) + case *tokyoartbeat* + tags=($tags tokyoartbeat japan art) + case *trendbeheer* + tags=($tags trendbeheer art) + case *ValentinaTanni* + tags=($tags valentinatanni art) + case *vvork* + tags=($tags vwork art) + case *auriea* *tale-of-tales* *taleoftales* + tags=($tags auriea) + case *basscomm* *closeoutwarrior* *crummysocks* *gamerrelocationproject* *protipoftheday* *PushButtonB* *pushbuttonb* + tags=($tags video_games basscomm) + case *benjaminmarra* + tags=($tags comics benjamin_marra) + case *boingboing* + tags=($tags boingboing) + case *bushinbooks* *henka* + tags=($tags budo) + case *alexaanddave* *CEREBUS* *Cerebus* *cerebus* *davesim* *gerhard* + tags=($tags comics cerebus gerhard) + case *coilhouse* + tags=($tags coilhouse) + case *arche-arc* + tags=($tags arche comics) + case *bitolithic.com* + tags=($tags bitolithic comics) + case *blaiselarmee* + tags=($tags blaise_larmee comics) + case *bleedingcool* + tags=($tags bleedingcool comics) + case *bobgreenberger* + tags=($tags bob_greengerger comics) + case *coldheatcomics* + tags=($tags coldheat comics) + case *comicbookresources* + tags=($tags cbr comics) + case *comicsbeat* + tags=($tags comicsbeat comics) + case *ComicsComics* *comicscomics* + tags=($tags comicscomics comics) + case *coveredblog* + tags=($tags coveredblog comics) + case *dcfifty-too* + tags=($tags dcfifty-too comics) + case *Destructoid* *destructoid* + tags=($tags destructoid video_games) + case *economist.com* + tags=($tags economist) + case *brucesterling.tumblr.com* + tags=($tags bruce_sterling) + case *thecreatorsproject* + tags=($tags thecreatorsproject) + case *ferrandelgado* + tags=($tags ferran_delgado comics) + case *eddiecampbell* + tags=($tags eddie_campbell comics) + case *factualopinion* + tags=($tags factualopinion comics) + case *floating_world* *floatingworld* + tags=($tags floating_world comics) + case *frankmiller* + tags=($tags frank_miller comics) + case *humancolor* + tags=($tags humancolor comics) + case *jerkcity* + tags=($tags jerkcity comics) + case *maakies.com* + tags=($tags tony_millionaire maakies comics) + case *newconstructionblog* + tags=($tags newconstruction manga comics) + case *ohdannyboy* + tags=($tags ohdannyboy comics) + case *pulphope* + tags=($tags pulphope comics) + case *pwbeat* + tags=($tags pwbeat comics) + case *reliablecomics* + tags=($tags reliablecomics comics) + case *reneefrench* + tags=($tags renee_french comics) + case *rickveitch* + tags=($tags rick_veitch comics) + case *royalboiler* + tags=($tags royalboiler comics) + case *smbc-comics* + tags=($tags smbc comics) + case *studygroup* + tags=($tags studygroup comics) + case *xkcd* + tags=($tags xkcd comics) + case *bowiesongs* *DavidBowie* *davidbowie* + tags=($tags music david_bowie) + case *designboom* + tags=($tags designboom design) + case *dezeen* + tags=($tags dezeen design) + case *infosthetics* + tags=($tags infosthetics design) + case *inhabitat* + tags=($tags inhabitat architecture design) + case *luigicolani* + tags=($tags luigicolani design) + case *mocoloco* + tags=($tags mocoloco design) + case *sydmead* + tags=($tags sydmead design) + case *dzima* + tags=($tags dzima) + case *bbcicecream* + tags=($tags bbcicecream fashion) + case *DamStyle *damstyle* + tags=($tags damstyle fashion) + case *facehunter* + tags=($tags facehunter fashion) + case *StilInBerlin* *Stilinberlin* + tags=($tags germany fashion) + case *jstreets* + tags=($tags jstreets japan fashion) + case *stylefromtokyo* + tags=($tags stylefromtokyo japan fashion) + case *tokyofashion* + tags=($tags tokyofashion japan fashion) + case *flames.gif* *flamesgif* + tags=($tags flames.gif) + case *contemporary-home-computing* + tags=($tags software flames.gif) + case *acceler8or.com* + tags=($tags acceler8or future) + case *afrocyberpunk.wordpress.com* + tags=($tags afrocyberpunk future) + case *hyperallergic.com* + tags=($tags hyperallergic future) + case *kurzweil* + tags=($tags kurzweil future) + case *longnow* + tags=($tags longnow future) + case *OpenTheFuture* + tags=($tags openthefuture future) + case *theverge.com* + tags=($tags theverge future) + case *golang* *blog.nella.org* + tags=($tags golang) + case *googlepluses* + tags=($tags google) + case *news.ycombinator.com* + tags=($tags hackernews hack) + case *seanbonner* + tags=($tags sean_bonner hack) + case *banriman* + tags=($tags banriman japan) + case *japansubculture* + tags=($tags japansubculture japan) + case *jeansnow* + tags=($tags jeansnow japan) + case *Kotaku* *kotaku* + tags=($tags kotaku video_games) + case *eforemario* + tags=($tags before_mario video_games) + case *instagram* *web.stagram.com* + tags=($tags instagram) + case *nakakobooks* + tags=($tags books nakakobooks japan) + case *ozawamaria* + tags=($tags maria_ozawa japan) + case *Shibuya246* + tags=($tags shibuya246 japan) + case *shisaku.blogspot.com* + tags=($tags shisaku japan) + case *jimshooter* + tags=($tags comics jim_shooter) + case *LettersOfNote* *lettersofnote* + tags=($tags letters) + case *nasa*letters.rss* + tags=($tags nasa letters) + case *kore.livejournal.com* + tags=($tags kore livejournal) + case *real-funny-lady.livejournal.com* + tags=($tags rea_funny_lady livejournal) + case *vintage-ads.livejournal.com* + tags=($tags vintage_ads livejournal) + case *hellodamage* + tags=($tags comics hellodamage manga) + case *manganews* + tags=($tags comics manganews manga) + case *naokiurasawa* + tags=($tags comics naokiurasawa manga) + case *samehat* + tags=($tags comics samehat manga) + case *mangatraders* + tags=($tags p2p comics manga) + case *hortonheardawho* + tags=($tags hortonheardawho flickr nasa mars) + case *marstoday.com* + tags=($tags marstoday mars) + case *kielbryant* + tags=($tags kiel_bryant flickr) + case *flickr*paoru* + tags=($tags paoru flickr) + case *me-vs-gutenberg* *mevsgutenberg* + tags=($tags martin_sand) + case *marxy* + tags=($tags marxy) + case *etamodern* + tags=($tags metamodern) + case *aviationintel* + tags=($tags aviationintel mil) + case *aviationweek* + tags=($tags aviationweek mil) + case *codeonemagazine* + tags=($tags codeonemagazine mil) + case *geimint* + tags=($tags geimint mil) + case *momus* *mrstsk* + tags=($tags books music momus) + case *bjork* + tags=($tags bjork music) + case *c-h-r-i-s-c-a-r-t-e-r* + tags=($tags chris_carter music) + case *toog* + tags=($tags toog music) + case *nasa.gov* + tags=($tags space nasa) + case *mongoliad* + tags=($tags neal_stephenson) + case *gaiman* + tags=($tags comics neil_gaiman) + case *111567547782666546187* + tags=($tags daniel_rehn gplus) + case *114408853762245370512* + tags=($tags francesco_cardi gplus) + case *106673611724400311137* + tags=($tags mark_jondahl gplus) + case *113974084460235989118* + tags=($tags jose_nazario gplus) + case *102089697005520721324* + tags=($tags zaki_hasan gplus) + case *nin.com* *feeds.nin.com* + tags=($tags music nin.com nin) + case *ninofficialnews.tumblr.com* + tags=($tags music tumblr nin) + case *nix-os* *syssoftware* + tags=($tags plan9 nix) + case *bsdly* *OPENBSD* *OpenBSD* *openbsd* *scientist-home* *undeadly* + tags=($tags software openbsd) + case *godownmatthew* *mysticmilk* *petetoms* + tags=($tags pete_toms) + case *Pitchfork* *pitchfork* + tags=($tags music pitchfork) + case *9gridchan* *cat-v* *maht0x0r* *Plan9* *plan9* + tags=($tags software plan9) + case *FlauntTalks* *prince.org* *purpleinterviews* *wendyandlisa* + tags=($tags music prince) + case *101960720994009339267* + tags=($tags gplus rob_pike) + case *commandcenter* *rob_pike* + tags=($tags blogger rob_pike) + case *prometheus* + tags=($tags telescreen prometheus) + case *reddit.com* + tags=($tags reddit) + case *swtch.com* + tags=($tags golang plan9 rsc) + case *bunniestudios* + tags=($tags bunniestudios security) + case *jwz* + tags=($tags jwz security) + case *Krebs* *krebs* + tags=($tags krebs security) + case *scarybeastsecurity* + tags=($tags scarybeast security) + case *schneier* + tags=($tags bruce_schneier security) + case *chinchillakwak* *skwak* + tags=($tags skwak) + case *slashdot* + tags=($tags slashdot) + case *spaceref.com* + tags=($tags space spaceref) + case *StanleyLieber* *stanleylieber* + tags=($tags stanleylieber) + case *fastcompany* + tags=($tags fastcompany tech) + case *gizchina.com* + tags=($tags gizchina tech) + case *danharmon* + tags=($tags danharmon telescreen) + case *mindlessones* + tags=($tags mindlessones telescreen) + case *tcj.com* + tags=($tags comics tcj) + case *TEDBlog* *TEDblog* *ted.com* + tags=($tags ted) + case *ticom* + tags=($tags ticom security) + case *orrentfreak* + tags=($tags p2p torrentfreak) + case *ultra*culture* + tags=($tags ultraculture) + case *kleinletters* + tags=($tags comics todd_klein) + case *collectiondx.com* + tags=($tags collectiondx toys) + case *kennercollector.com* + tags=($tags kennercollector toys) + case *plaidstallions* + tags=($tags plaidstallions toys) + case *shojikawamori* + tags=($tags shojikawamori japan toys) + case *tumblr* + tags=($tags tumblr) + case *ruinedcartridge* + tags=($tags ruinedcartridge basscomm video_games) + } + echo -n $tags +} + +fn parse_posts{ + ifs=' +' { + posts=`{cat $file} + for(i in `{seq 1 $#posts | sort -nr}){ + post=$posts($i) + if(! ~ $post ''){ + a_title=`{echo $post | sed 's/^.*HJDIVIDERtitle: //g; s/HJDIVIDER.*$//g'} + a_date=`{date} + a_link=`{echo $post | sed 's/^.*HJDIVIDERlink: //g; s/HJDIVIDER.*$//g'} + a_body=`{echo $post | sed 's/^.*HJDIVIDER//g; s/^.*HJDIVIDER//g; s/^.*HJDIVIDER//g'} + a_id=`{echo `{ls -p $werc/sites/$site/src | sort -n | tail -1}^+1 | bc} + if(~ $#a_id 0) + a_id=1 + while(test -d $werc/sites/$site/src/$a_id) + a_id=`{echo $a_id^+1 | bc} + if(! ~ $"a_link '' && ! grep -s `{echo $"a_link | md5sum} $werc/sites/$site/links){ + mkdir -p $werc/sites/$site/src/$a_id/tags # big fat race + echo $"a_title >$werc/sites/$site/src/$a_id/title + echo $"a_date >$werc/sites/$site/src/$a_id/date + echo $a_link(1) >$werc/sites/$site/src/$a_id/link + echo $a_link(1) | md5sum >>$werc/sites/$site/links + echo $"a_body '</a></li></ul>' >$werc/sites/$site/src/$a_id/body + ifs=' ' { + for(j in `{get_tags}){ + >$werc/sites/$site/src/$a_id/tags/$j + echo $a_id/tags/$j >>$werc/sites/$site/tags + } + } + } + if(test -f /boot/factotum && ~ $site *.stanleylieber.com && test -d $werc/sites/$site/src/$a_id) + chmod +t $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id/* $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id/tags/* + } + } + } +} + +if(test -f /boot/factotum && test -f /rc/bin/hget) + webfs +get_posts +parse_posts diff --git a/werc/apps/barf/bin/gz b/werc/apps/barf/bin/gz new file mode 100755 index 0000000..450d0a6 --- /dev/null +++ b/werc/apps/barf/bin/gz @@ -0,0 +1,119 @@ +#!/bin/rc +# Parse XML RSS feeds into BARF blog posts for the specified site. +# If a post with a matching _link_ already exists, no new post will +# be created for that item. Tags will be created according to the rules +# defined in the get_tags() function. +# +# The file argument should point to a file containing one line per feed, +# with fields separated by the | character, in the following format: +# +# http://feeds.feedburner.com/ImNotReallyStanleyLieber|stanleylieber +# +# where the first field is the feed URL and each addition field is a tag. +# +# Requires 20h's xmlpull and rssread. +rfork en +switch($1){ +case /* + feeds=$1 + site=read.stanleylieber.com + tags=() +case * + echo 'Usage: gz file' >[1=2] + exit usage +} + +file=/tmp/gz.$pid +werc=/usr/sl/www/werc + +if(test -f /boot/factotum) + cmd=hget +if not + cmd='curl -s' + +fn cram{ + ssam ' +,s/^link:.*$/HJDIVIDER&HJDIVIDER/g +,s/^title:.*$/HJDIVIDER&HJDIVIDER/g +,s/\n//g +,s/HJDIVIDERtitle:/\n&/g + ' +} + +fn scape{ + ssam ' +,s/ //g +,s/\"/\"/g +,s/\"/\"/g +,s/\&/\&/g +,s/\&/\&/g +,s/\'/''/g +,s/\,/,/g +,s/\-/-/g +,s/\./\./g +,s/\//\//g +,s/\:/:/g +,s/\;/;/g +,s/\</</g +,s/\</</g +,s/\=/=/g +,s/\>/>/g +,s/\>/>/g +,s/\_/_/g +,s/\|/\|/g + ' +} + +fn get_posts{ + $"cmd $"feed | rssread | cram | scape >$file + echo >>$file +} + +fn parse_posts{ + ifs=' +' { + posts=`{cat $file} + for(i in `{seq 1 $#posts | sort -nr}){ + post=$posts($i) + if(! ~ $post ''){ + a_title=`{echo $post | sed 's/^.*HJDIVIDERtitle: //g; s/HJDIVIDER.*$//g'} + a_date=`{date} + a_link=`{echo $post | sed 's/^.*HJDIVIDERlink: //g; s/HJDIVIDER.*$//g'} + a_body=`{echo $post | sed 's/^.*HJDIVIDER//g; s/^.*HJDIVIDER//g; s/^.*HJDIVIDER//g'} + a_id=`{echo `{ls -p $werc/sites/$site/src | sort -n | tail -1}^+1 | bc} + if(~ $#a_id 0) + a_id=1 + while(test -d $werc/sites/$site/src/$a_id) + a_id=`{echo $a_id^+1 | bc} + if(! ~ $"a_link '' && ! grep -s `{echo $"a_link | md5sum} $werc/sites/$site/links){ + mkdir -p $werc/sites/$site/src/$a_id/tags # big fat race + echo $"a_title >$werc/sites/$site/src/$a_id/title + echo $"a_date >$werc/sites/$site/src/$a_id/date + echo $a_link(1) >$werc/sites/$site/src/$a_id/link + echo $a_link(1) | md5sum >>$werc/sites/$site/links + if(~ $a_link(1) *staticflickr.com*) + echo '<img src="'$"a_link'">' >$werc/sites/$site/src/$a_id/body + echo $"a_body '</a></li></ul>' >>$werc/sites/$site/src/$a_id/body + ifs=' ' { + for(j in $tags){ + >$werc/sites/$site/src/$a_id/tags/$j + echo $a_id/tags/$j >>$werc/sites/$site/tags + } + } + } + if(test -f /boot/factotum && ~ $site *.stanleylieber.com && test -d $werc/sites/$site/src/$a_id) + chmod +t $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id/* $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id/tags/* + } + } + } +} + +if(test -f /boot/factotum && test -f /rc/bin/hget) + webfs +for(i in `{grep -v -e '^#' $feeds}){ + feed=`{echo $"i | sed 's/\|.*$//g'} + tags=`{echo $"i | sed 's/\|/ /g'} + tags=$tags(2-) + get_posts + parse_posts +} diff --git a/werc/apps/barf/bin/gz.read b/werc/apps/barf/bin/gz.read new file mode 100755 index 0000000..450d0a6 --- /dev/null +++ b/werc/apps/barf/bin/gz.read @@ -0,0 +1,119 @@ +#!/bin/rc +# Parse XML RSS feeds into BARF blog posts for the specified site. +# If a post with a matching _link_ already exists, no new post will +# be created for that item. Tags will be created according to the rules +# defined in the get_tags() function. +# +# The file argument should point to a file containing one line per feed, +# with fields separated by the | character, in the following format: +# +# http://feeds.feedburner.com/ImNotReallyStanleyLieber|stanleylieber +# +# where the first field is the feed URL and each addition field is a tag. +# +# Requires 20h's xmlpull and rssread. +rfork en +switch($1){ +case /* + feeds=$1 + site=read.stanleylieber.com + tags=() +case * + echo 'Usage: gz file' >[1=2] + exit usage +} + +file=/tmp/gz.$pid +werc=/usr/sl/www/werc + +if(test -f /boot/factotum) + cmd=hget +if not + cmd='curl -s' + +fn cram{ + ssam ' +,s/^link:.*$/HJDIVIDER&HJDIVIDER/g +,s/^title:.*$/HJDIVIDER&HJDIVIDER/g +,s/\n//g +,s/HJDIVIDERtitle:/\n&/g + ' +} + +fn scape{ + ssam ' +,s/ //g +,s/\"/\"/g +,s/\"/\"/g +,s/\&/\&/g +,s/\&/\&/g +,s/\'/''/g +,s/\,/,/g +,s/\-/-/g +,s/\./\./g +,s/\//\//g +,s/\:/:/g +,s/\;/;/g +,s/\</</g +,s/\</</g +,s/\=/=/g +,s/\>/>/g +,s/\>/>/g +,s/\_/_/g +,s/\|/\|/g + ' +} + +fn get_posts{ + $"cmd $"feed | rssread | cram | scape >$file + echo >>$file +} + +fn parse_posts{ + ifs=' +' { + posts=`{cat $file} + for(i in `{seq 1 $#posts | sort -nr}){ + post=$posts($i) + if(! ~ $post ''){ + a_title=`{echo $post | sed 's/^.*HJDIVIDERtitle: //g; s/HJDIVIDER.*$//g'} + a_date=`{date} + a_link=`{echo $post | sed 's/^.*HJDIVIDERlink: //g; s/HJDIVIDER.*$//g'} + a_body=`{echo $post | sed 's/^.*HJDIVIDER//g; s/^.*HJDIVIDER//g; s/^.*HJDIVIDER//g'} + a_id=`{echo `{ls -p $werc/sites/$site/src | sort -n | tail -1}^+1 | bc} + if(~ $#a_id 0) + a_id=1 + while(test -d $werc/sites/$site/src/$a_id) + a_id=`{echo $a_id^+1 | bc} + if(! ~ $"a_link '' && ! grep -s `{echo $"a_link | md5sum} $werc/sites/$site/links){ + mkdir -p $werc/sites/$site/src/$a_id/tags # big fat race + echo $"a_title >$werc/sites/$site/src/$a_id/title + echo $"a_date >$werc/sites/$site/src/$a_id/date + echo $a_link(1) >$werc/sites/$site/src/$a_id/link + echo $a_link(1) | md5sum >>$werc/sites/$site/links + if(~ $a_link(1) *staticflickr.com*) + echo '<img src="'$"a_link'">' >$werc/sites/$site/src/$a_id/body + echo $"a_body '</a></li></ul>' >>$werc/sites/$site/src/$a_id/body + ifs=' ' { + for(j in $tags){ + >$werc/sites/$site/src/$a_id/tags/$j + echo $a_id/tags/$j >>$werc/sites/$site/tags + } + } + } + if(test -f /boot/factotum && ~ $site *.stanleylieber.com && test -d $werc/sites/$site/src/$a_id) + chmod +t $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id/* $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id/tags/* + } + } + } +} + +if(test -f /boot/factotum && test -f /rc/bin/hget) + webfs +for(i in `{grep -v -e '^#' $feeds}){ + feed=`{echo $"i | sed 's/\|.*$//g'} + tags=`{echo $"i | sed 's/\|/ /g'} + tags=$tags(2-) + get_posts + parse_posts +} diff --git a/werc/apps/barf/bin/gz.tumblr b/werc/apps/barf/bin/gz.tumblr new file mode 100755 index 0000000..b9f4061 --- /dev/null +++ b/werc/apps/barf/bin/gz.tumblr @@ -0,0 +1,119 @@ +#!/bin/rc +# Parse XML RSS feeds into BARF blog posts for the specified site. +# If a post with a matching _link_ already exists, no new post will +# be created for that item. Tags will be created according to the rules +# defined in the get_tags() function. +# +# The file argument should point to a file containing one line per feed, +# with fields separated by the | character, in the following format: +# +# http://feeds.feedburner.com/ImNotReallyStanleyLieber|stanleylieber +# +# where the first field is the feed URL and each addition field is a tag. +# +# Requires 20h's xmlpull and rssread. +rfork en +switch($1){ +case /* + feeds=$1 + site=tumblr.stanleylieber.com + tags=() +case * + echo 'Usage: gz file' >[1=2] + exit usage +} + +file=/tmp/gz.$pid +werc=/usr/sl/www/werc + +if(test -f /boot/factotum) + cmd=hget +if not + cmd='curl -s' + +fn cram{ + ssam ' +,s/^link:.*$/HJDIVIDER&HJDIVIDER/g +,s/^title:.*$/HJDIVIDER&HJDIVIDER/g +,s/\n//g +,s/HJDIVIDERtitle:/\n&/g + ' +} + +fn scape{ + ssam ' +,s/ //g +,s/\"/\"/g +,s/\"/\"/g +,s/\&/\&/g +,s/\&/\&/g +,s/\'/''/g +,s/\,/,/g +,s/\-/-/g +,s/\./\./g +,s/\//\//g +,s/\:/:/g +,s/\;/;/g +,s/\</</g +,s/\</</g +,s/\=/=/g +,s/\>/>/g +,s/\>/>/g +,s/\_/_/g +,s/\|/\|/g + ' +} + +fn get_posts{ + $"cmd $"feed | rssread | cram | scape >$file + echo >>$file +} + +fn parse_posts{ + ifs=' +' { + posts=`{cat $file} + for(i in `{seq 1 $#posts | sort -nr}){ + post=$posts($i) + if(! ~ $post ''){ + a_title=`{echo $post | sed 's/^.*HJDIVIDERtitle: //g; s/HJDIVIDER.*$//g'} + a_date=`{date} + a_link=`{echo $post | sed 's/^.*HJDIVIDERlink: //g; s/HJDIVIDER.*$//g'} + a_body=`{echo $post | sed 's/^.*HJDIVIDER//g; s/^.*HJDIVIDER//g; s/^.*HJDIVIDER//g'} + a_id=`{echo `{ls -p $werc/sites/$site/src | sort -n | tail -1}^+1 | bc} + if(~ $#a_id 0) + a_id=1 + while(test -d $werc/sites/$site/src/$a_id) + a_id=`{echo $a_id^+1 | bc} + if(! ~ $"a_link '' && ! grep -s `{echo $"a_link | md5sum} $werc/sites/$site/links){ + mkdir -p $werc/sites/$site/src/$a_id/tags # big fat race + echo $"a_title >$werc/sites/$site/src/$a_id/title + echo $"a_date >$werc/sites/$site/src/$a_id/date + echo $a_link(1) >$werc/sites/$site/src/$a_id/link + echo $a_link(1) | md5sum >>$werc/sites/$site/links + if(~ $a_link(1) *staticflickr.com*) + echo '<img src="'$"a_link'">' >$werc/sites/$site/src/$a_id/body + echo $"a_body '</a></li></ul>' >>$werc/sites/$site/src/$a_id/body + ifs=' ' { + for(j in $tags){ + >$werc/sites/$site/src/$a_id/tags/$j + echo $a_id/tags/$j >>$werc/sites/$site/tags + } + } + } + if(test -f /boot/factotum && ~ $site *.stanleylieber.com && test -d $werc/sites/$site/src/$a_id) + chmod +t $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id/* $werc/sites/$site/src/$a_id $werc/sites/$site/src/$a_id/tags/* + } + } + } +} + +if(test -f /boot/factotum && test -f /rc/bin/hget) + webfs +for(i in `{grep -v -e '^#' $feeds}){ + feed=`{echo $"i | sed 's/\|.*$//g'} + tags=`{echo $"i | sed 's/\|/ /g'} + tags=$tags(2-) + get_posts + parse_posts +} diff --git a/werc/apps/barf/bin/rsrc b/werc/apps/barf/bin/rsrc new file mode 100755 index 0000000..50d2f0f --- /dev/null +++ b/werc/apps/barf/bin/rsrc @@ -0,0 +1,3 @@ +#!/bin/rc +# Remove static files. +rm -r [0-9]*.html [0-9]*-[0-9]*.html tag diff --git a/werc/apps/barf/bin/srct b/werc/apps/barf/bin/srct new file mode 100755 index 0000000..cc1dffd --- /dev/null +++ b/werc/apps/barf/bin/srct @@ -0,0 +1,4 @@ +#!/bin/rc +# do not store these files in the worm +fn f{ du -a $* | sed 's/^.* //g' } +for(i in `{f $1}){ chmod +t $i } diff --git a/werc/apps/barf/lib/barf.tpl b/werc/apps/barf/lib/barf.tpl new file mode 100755 index 0000000..63ee45d --- /dev/null +++ b/werc/apps/barf/lib/barf.tpl @@ -0,0 +1,14 @@ +% if(~ $show_header 1 && ! ~ $barf_type login rss) +% display_header +% if(~ $a_func edit_form){ +% if(check_user && ! ~ $#logged_user 0) +% edit_form +% if not +% display_^$barf_type +% } +% if not +% display_^$barf_type +% if(~ $show_sidebar 1 && ~ $#a_func 0 && ! ~ $barf_type login rss) +% display_sidebar +% if(~ $show_footer 1 && ~ $#a_func 0 && ! ~ $barf_type login rss) +% display_footer diff --git a/werc/apps/barf/lib/blog b/werc/apps/barf/lib/blog new file mode 100755 index 0000000..a880f44 --- /dev/null +++ b/werc/apps/barf/lib/blog @@ -0,0 +1,43 @@ +fn display_blog{ + echo '<div id="center"> + <div id="posts">' + get_post_list + for(i in `{seq 1 $#posts}){ + a_id=$posts($i) + a_dir=$barf_root/$"barf_dir/src/$a_id + echo '<div id="post"> + <div id="post_title">' + print_title + echo '</div> + <div id="post_meta">' + link=`{cat $a_dir/link} + echo '<span id="post_link"> + <a href="'$"link'" target="_b">link</a> + </span> + | <span id="post_tags">' + print_tags + echo '</span> + | <span id="post_date">' + cat $a_dir/date + echo '</span>' + print_id + if(check_user && ! ~ $#logged_user 0){ + echo ' | <span id="post_edit">' + print_edit + echo '</span>' + } + echo '</div> + <div id="post_body">' + cat $a_dir/body + if(~ $show_disqus 1 && ! ~ $#id 0) + cat $barf_root/_werc/barf/disqus + echo '</div> + </div> + <br>' + } + display_prevnext + echo '<br><br><br> + </div> + </div> + </div>' +} diff --git a/werc/apps/barf/lib/core b/werc/apps/barf/lib/core new file mode 100755 index 0000000..335dab5 --- /dev/null +++ b/werc/apps/barf/lib/core @@ -0,0 +1,414 @@ +fn delete_post{ + a_dir=$barf_root/$"barf_dir/src/$a_id + if(test -d $a_dir){ + rm -rf $a_dir && + {echo ',x/^'$a_id'\/.*\n/d'; echo w; echo q} | sam -d $barf_root/$"barf_dir/tags >[2]/dev/null + } + post_redirect $base_url^$barf_base_uri +} + +fn display_footer{ + if(test -f $barf_root/$"barf_dir/_werc/barf/footer) + cat $barf_root/$"barf_dir/_werc/barf/footer + if not if(test -f $barf_root/_werc/barf/footer) + cat $barf_root/_werc/barf/footer + if not + cat apps/barf/barf/footer +} + +fn display_header{ + if(test -f $barf_root/$"barf_dir/_werc/barf/header) + cat $barf_root/$"barf_dir/_werc/barf/header + if not if(test -f $barf_root/_werc/barf/header) + cat $barf_root/_werc/barf/header + if not + cat apps/barf/barf/header +} + +fn display_login{ + echo '<div id="login"> + <form method="post" action="/"> + <input type="hidden" name="a_func" value="login"> + username: <input type="text" name="user_name"><br> + password: <input type="password" name="user_password"><br> + <input name="s" type="submit" value="login"> + </form> + </div>' +} + +fn display_prevnext{ + if(test $stop -gt `{echo 1+^$posts_per_page | bc}){ + nprev=`{echo $start^-1-^$posts_per_page | bc} + prev='<span> + <a href="'$base_url^$barf_base_uri'?tags='$"tags'&start='$"nprev'">prev</a> | + </span>' + } + if(test $#posts -gt $posts_per_page){ + nnext=`{echo $stop^+1 | bc} + next='<span> + <a href="'$base_url^$barf_base_uri'?tags='$"tags'&start='$"nnext'">next</a> + </span>' + } + echo '<div id="page_list"> + '$"prev' + '$"next' + </div>' +} + +fn display_sidebar{ + if(test -f $barf_root/$"barf_dir/_werc/barf/sidebar) + cat $barf_root/$"barf_dir/_werc/barf/sidebar + if not if(test -f $barf_root/_werc/barf/sidebar) + cat $barf_root/_werc/barf/sidebar + if not + cat apps/barf/barf/sidebar +} + +fn dsrc{ + low=`{ls -p $barf_root/$"barf_dir/src | sort -n | sed 1q} + high=$a_id + if(~ $#low 1 && ~ $#high 1){ + cd $barf_root/$"barf_dir/src && rm -rf `{seq $low $high} && + { + for(i in `{seq $low $high}) + echo ',x/^'$i'\/.*\n/d' + echo w + echo w + echo q + } | sam -d $barf_root/$"barf_dir/tags >[2]/dev/null + } + post_redirect $base_url^$barf_base_uri +} + +fn edit_form{ + if(~ $#a_id 0) + name=add + if not{ + name=update + a_dir=$barf_root/$"barf_dir/src/$a_id + for(x in $barf_items){ + if(~ $x img) + a_img=`{ls -p $a_dir/img | sed 1q} + if(~ $x tags) + a_tags=`{ls -p $a_dir/tags} + if not + $x=`{cat $a_dir/$x} + } + } + echo '<div id="list"> + <form action="/" method="post" name="edit" id="button"> + <input type="hidden" name="fake" value="fake"> + <input type="text" name="url" style="display: none;"> + <input type="hidden" name="a_func" value="edit_post">' + if(~ $name update) + echo '<input type="hidden" name="a_id" value="'$"a_id'">' + for(x in $barf_items){ + if(~ $x body){ + echo '<div id="edit_body">' \ + 'body:<br>' \ + '<textarea name="a_body">' + if(~ $name update) + cat $a_dir/body + echo '</textarea></div>' + } + if not if(~ $x img){ + echo '<div id="edit_img">' \ + 'image:<br>' \ + '<input name="a_img" type="text" value="'$"a_img'" id="edit">   ' \ + 'download: <input name="a_download" type="checkbox" value="1">' \ + '</div>' + } + if not if(~ $x tags){ + echo '<div id="edit_tags">' \ + 'tags:   (space separated list of tags)<br>' \ + '<input name="a_tags" type="text" value="'$"a_tags'" id="edit">' \ + '</div>' + } + if not{ + echo '<div id="edit_'$"x'">' \ + $"x':<br>' \ + '<input name="a_'$"x'" type="text" value="'$"$x'" id="edit">' \ + '</div>' + } + } + echo '<div id="edit_submit">' \ + '<input type="submit" name="'$name'" value="'$name'">' \ + '</div> + </form> + </div>' +} + +fn edit_post{ + if(~ $#a_id 0){ + a_id=`{echo `{ls -p $barf_root/$"barf_dir/src | sort -n | tail -1}^+1 | bc} + if(~ $#a_id 0) + a_id=1 + while(test -d $barf_root/$"barf_dir/src/$a_id) + a_id=`{echo $a_id^+1 | bc} + } + a_dir=$barf_root/$"barf_dir^src/$a_id + mkdir -p $a_dir/img $a_dir/tags + rm -f $a_dir/tags/* + for(x in $barf_items){ + if(~ $x date){ + if(! ~ $#a_date 0) + echo $"a_date >$a_dir/date + if not + date >$a_dir/date + } + if not if(~ $x tags){ + if(! ~ $#a_tags 0){ + a_tags=`{echo $"a_tags | sed 's/[^A-Za-z0-9_\- ]//g'} + ifs=' '{a_tags=`{echo -n $a_tags}} + { + t=1 + while(test $t -le $#a_tags){ + >$a_dir/tags/$a_tags($t) + t=`{echo $t^+1 | bc} + } + } + for(i in $a_tags) + echo $a_id'/tags/'$i >>$barf_root/$"barf_dir/tags + } + } + if not if(! ~ $x img tags){ + item='a_'$"x + if(! ~ $$item ''){ + >$a_dir/$x + echo $$item >$a_dir/$x + } + } + } + if(~ $a_download 1){ + switch($barf_type){ + case image + rm -f $a_dir/img/* + img=$a_dir/img/^`{date -n}^.^`{echo $"a_img | + sed 's/^.*\.(gif|GIF)$/gif/g; + s/^.*\.(jpg|jpeg|JPG|JPEG)$/jpg/g; + s/^.*\.(png|PNG)$/png/g; + s/^.*\.(tif|TIF|tiff|TIFF)$/tif/g' + } + thumb=$a_dir/img/small.^`{basename $img | sed 's/\..*$//g'}^.png + if(test -f /boot/factotum){ + @{ + rfork n + if(test -f /rc/bin/hget) + webfs + hget $"a_img >$img + #magick/convert $img -resize 500x600 $thumb + switch($img){ + case *.bmp + cmd=bmp + case *.gif + cmd=gif + case *.ico + cmd=ico + case *.jpg + cmd=jpg + case *.png + cmd=png + case *.tif + cmd=tif + case *.tga + cmd=tga + } + $cmd -9et <$img | resample -x 500 | topng >$thumb + } + } + if not{ + curl -s -o $"a_img >$img + convert $img -resize 500x600 $thumb + } + case url + if(test -f /boot/factotum){ + @{ + rfork n + if(test -f /rc/bin/hget) + webfs + hget $"a_link | htmlfmt | fmt >$a_dir/body + } + } + if not + curl -s $"a_link | htmlfmt | fmt >$a_dir/body + } + } + if(! ~ $gp 1) + post_redirect $base_url^$barf_base_uri +} + +fn get_post_list{ + if(~ $id [0-9]*) + posts=$id + if not{ + posts=`{ + if(~ $show_ascending 1) + sort=(sort -n) + if not + sort=(sort -nr) + if(~ $tags all) + ls -p $barf_root/$"barf_dir/src | + grep -e '^[0-9]*$' | + eval $sort | + sed -n $start^,^$stop^p # awk 'NR=='$start',NR=='$stop' {print;}' + if not + grep -e '^.*\/'$tags'$' $barf_root/$"barf_dir/tags | + awk -F '/' '{print $1;}' | + eval $sort | + uniq | + sed -n $start^,^$stop^p + } + if(! ~ $posts [0-9]*) + posts=() + } +} + +fn get_start{ + if(~ $#start 0) + start=1 +} + +fn get_stop{ + if(~ $#stop 0) + stop=`{echo $start^+^$posts_per_page | bc} +} + +fn get_tags{ + if(~ $#tags 0) + tags=all +} + +fn load_get_args{ + if(~ $REQUEST_METHOD GET && ~ $#get_args 0 && ~ $REQUEST_URI *'='*){ + ifs='&' { + a=`{echo $"REQUEST_URI | sed 's/(^\/|#.*$)//g'} + for(pair in $a){ + ifs='=' { pair=`{echo -n $pair} } + n='get_arg_'^`{echo $pair(1) | urldecode | tr -cd 'a-zA-Z0-9_'} + get_args=( $get_args $n ) + ifs=() { $n=`{echo -n $pair(2) | urldecode | tr -d ' '} } + } + } + pair=() + } +} + +fn parse_get_args{ + if(! ~ $#get_arg_a_func 0) + a_func=$get_arg_a_func + if(! ~ $#get_arg_a_id 0) + a_id=$get_arg_a_id + if(! ~ $#get_arg_id 0) + id=$get_arg_id + if(! ~ $#get_arg_start 0) + start=$get_arg_start + if(! ~ $#get_arg_stop 0) + stop=$get_arg_stop + if(! ~ $#get_arg_reply 0) + reply=$get_arg_reply + if(! ~ $#get_arg_tags 0) + tags=$get_arg_tags +} + +fn parse_post_args{ + for(x in $barf_items){ + a='a_'$"x + p='post_arg_'$"a + $a=$$p + } + if(! ~ $#post_arg_a_download 0) + a_download=$post_arg_a_download + if(! ~ $#post_arg_a_func 0) + a_func=$post_arg_a_func + if(! ~ $#post_arg_fake 0) + fake=$post_arg_fake + if(! ~ $#post_arg_a_id 0) + a_id=$post_arg_a_id + if(! ~ $#post_arg_url 0) + url=$post_arg_url +} + +fn print_edit{ + edit='<a href="'$base_url^$barf_base_uri'?a_func=edit_form&a_id='$"a_id'">edit</a>' + delete='<a href="'$base_url^$barf_base_uri'?a_func=delete_post&a_id='$"a_id'" onclick="return confirm(''are you sure you want to delete?'');">delete</a>' + dsrc='<a href="'$base_url^$barf_base_uri'?a_func=dsrc&a_id='$"a_id'" onclick="return confirm(''are you sure you want to dsrc?'');">dsrc</a>' + echo $"edit' | '$"delete' | '$"dsrc +} + +fn print_id{ + echo '<span id="post_id"><a href="/?id='$"a_id'">No.'$"a_id'</a></span>' +} + +fn print_img{ + a_img=`{ls -p $a_dir/img/[0-9]*} + a_thumb=`{ls -p $a_dir/img/small*} + if(! ~ $#a_img 0) + if(~ $#a_thumb 0) + a_thumb=$a_img + echo '<a href="'$base_url^$barf_base_uri'src/'$a_id'/img/'$a_img'" target="_b"><img src="'$base_url^$barf_base_uri'src/'$a_id'/img/'$a_thumb'" border="0"></a>' +} + +fn print_tags{ + a_tags=`{ls -p $a_dir/tags} + a_tags=`{for(t in $a_tags) echo '<a href="'$base_url^$barf_base_uri'?tags='$t'">'$t'</a>, '} + a_tags=`{echo $a_tags | awk '{print substr($0, 1, length($0) -1)}'} + echo '<span id="post_tags">'$"a_tags'</span>' +} + +fn print_title{ + a_title=`{cat $a_dir/title} + if(! ~ $#a_title 0){ + if(~ $barf_type log url) + echo '<a href="'`{cat $a_dir/link}'">'$"a_title'</a>' + if not + echo '<a href="'$base_url^$barf_base_uri'?id='$"a_id'">'$"a_title'</a>' + } +} + +fn redirect_bots{ + if(! ~ $fake fake || ! ~ $url '') + post_redirect http://google.com +} + +fn urldecode { +awk ' +BEGIN { + hextab ["0"] = 0; hextab ["8"] = 8; + hextab ["1"] = 1; hextab ["9"] = 9; + hextab ["2"] = 2; hextab ["A"] = hextab ["a"] = 10 + hextab ["3"] = 3; hextab ["B"] = hextab ["b"] = 11; + hextab ["4"] = 4; hextab ["C"] = hextab ["c"] = 12; + hextab ["5"] = 5; hextab ["D"] = hextab ["d"] = 13; + hextab ["6"] = 6; hextab ["E"] = hextab ["e"] = 14; + hextab ["7"] = 7; hextab ["F"] = hextab ["f"] = 15; +} +{ + decoded = "" + i = 1 + len = length ($0) + while ( i <= len ) { + c = substr ($0, i, 1) + if ( c == "%" ) { + if ( i+2 <= len ) { + c1 = substr ($0, i+1, 1) + c2 = substr ($0, i+2, 1) + if ( hextab [c1] == "" || hextab [c2] == "" ) { + print "WARNING: invalid hex encoding: %" c1 c2 | "cat >&2" + } else { + code = 0 + hextab [c1] * 16 + hextab [c2] + 0 + c = sprintf ("%c", code) + i = i + 2 + } + } else { + print "WARNING: invalid % encoding: " substr ($0, i, len - i) + } + } else if ( c == "+" ) { + c = " " + } + decoded = decoded c + ++i + } + printf "%s", decoded +} +' +} diff --git a/werc/apps/barf/lib/default_master.tpl b/werc/apps/barf/lib/default_master.tpl new file mode 100755 index 0000000..a9c81ee --- /dev/null +++ b/werc/apps/barf/lib/default_master.tpl @@ -0,0 +1 @@ +% run_handler $handler_body_main diff --git a/werc/apps/barf/lib/image b/werc/apps/barf/lib/image new file mode 100755 index 0000000..2af6324 --- /dev/null +++ b/werc/apps/barf/lib/image @@ -0,0 +1,68 @@ +fn add_post{ + redirect_bots + a_download=1 + edit_post +} + +fn display_image{ + echo '<div id="center">' + if(~ $allow_anon 1 || {check_user && ! ~ $#logged_user 0}){ + echo '<div id="upload"> + <form method="post" action="/"> + <input type="hidden" name="fake" value="fake"> + <input type="text" name="url" style="display: none;"> + <input type="hidden" name="a_func" value="add_post"> + <div id="upload_heading">/'$tags'/</div> + <table id="upload_table"> + <tr><td id="upload_label">Image</td><td><input type="text" name="a_img" id="upload_input"></td></tr> + <tr><td id="upload_label">Link</td><td><input type="text" name="a_link" id="upload_input"></td></tr> + <tr><td id="upload_label">Tags</td><td><input type="text" name="a_tags" id="upload_tags"> + <input type="submit" name="submit" value="add" id="upload_submit"></td></tr> + </table> + </form> + <table align="center"> + <tr> + <td> + <p> + <li id="upload_meta">Supported file types are: GIF, JPG, PNG</li> + <li id="upload_meta">Images greater than 500x600 pixels will be thumbnailed.</li> + </td> + </tr> + </table> + </div>' + } + echo '<div id="center_body">' + get_post_list + for(i in `{seq 1 $#posts}){ + a_id=$posts($i) + a_dir=$barf_root/$"barf_dir/src/$a_id + echo '<div id="post"> + <div id="post_meta"> + <span id="post_link">' + link=`{cat $a_dir/link} + echo '<a href="'$"link'">link</a> + </span> | + <span id="post_tags">' + print_tags + echo '</span> | + <span id="post_date">' + cat $a_dir/date + echo '</span>' + if(check_user && ! ~ $#logged_user 0){ + echo '| <span id="post_edit">' + print_edit + echo '</span>' + } + echo '</div> + <div id="post_img">' + print_img + echo '</div> + </div> + <br><br>' + } + display_prevnext + echo '<br><br><br><br> + </div> + </div> + </div>' +} diff --git a/werc/apps/barf/lib/log b/werc/apps/barf/lib/log new file mode 100755 index 0000000..923cd6e --- /dev/null +++ b/werc/apps/barf/lib/log @@ -0,0 +1,55 @@ +fn display_log{ + if(~ $#logged_user 0) + a='<a href="'$base_url^$barf_base_uri'login">login</a>' + if not + a='<a href="'$base_url^$barf_base_uri'?a_func=edit_form">add</a>' + echo '<div> + <span id="add">'$"a'</span> + <span id="search"> + <form method="get" action="/"> + <input type="text" name="tags" size="28"> + <input type="submit" value="search"> + </form> + </span> + </div> + </div> + <div id="list"> + <table id="post_table"> + <tbody> + <tr id="blank"> + <th style="display: none;"> </th> + <th style="display: none;"> </th> + <th style="display: none;"> </th>' + if(check_user && ! ~ $#logged_user 0) + echo '<th style="display: none;"> </th>' + echo '</tr>' + get_post_list + for(i in `{seq 1 $#posts}){ + a_id=$posts($i) + a_dir=$barf_root/$"barf_dir/src/$a_id + echo '<tr>' + for(j in $barf_items){ + echo '<td id="post_'$"j'">' + if(~ $j img) + print_img + if not if(~ $j tags) + print_tags + if not if(~ $j title) + print_title + if not + cat $a_dir/$j + echo '</td>' + } + if(check_user && ! ~ $#logged_user 0){ + echo '<td id="post_edit">' + print_edit + echo '</td>' + } + echo '</tr>' + } + echo '</tbody> + </table>' + display_prevnext + echo '<br><br><br><br> + </div>' +} diff --git a/werc/apps/barf/lib/paste b/werc/apps/barf/lib/paste new file mode 100755 index 0000000..5ef55e3 --- /dev/null +++ b/werc/apps/barf/lib/paste @@ -0,0 +1,50 @@ +fn add_post{ + redirect_bots + a_date=`{date} + edit_post +} + +fn display_paste{ + echo '<div id="center">' + if(~ $allow_anon 1 || {check_user && ! ~ $#logged_user 0}){ + echo '<div id="paste"> + <p> + <form method="post" action="/"> + <input type="hidden" name="fake" value="fake"> + <input type="text" name="url" style="display: none;"> + <input type="hidden" name="a_func" value="add_post"> + <textarea name="a_body" id="paste_box"></textarea><br> + <input type="submit" name="submit" value="submit" id="paste_submit"> + </form> + </div>' + } + echo '<p> + <div id="posts">' + get_post_list + for(i in `{seq 1 $#posts}){ + a_id=$posts($i) + a_dir=$barf_root/$"barf_dir/src/$a_id + echo '<div id="post"> + <div id="post_meta">' + date=`{cat $a_dir/date} + echo '<span id="post_date"> + <a href="/src/'$"a_id'/body" target="_b">'$"date'</a> + </span>' + if(check_user && ! ~ $#logged_user 0){ + echo ' | <span id="post_edit">' + print_edit + echo '</span>' + } + echo '</div> + <div id="post_body">' + txt_handler $barf_root/$"barf_dir/src/$a_id/body + echo '</div> + </div> + <br>' + } + display_prevnext + echo '<br><br><br><br> + </div> + </div> + </div>' +} diff --git a/werc/apps/barf/lib/rss b/werc/apps/barf/lib/rss new file mode 100755 index 0000000..7a3cd18 --- /dev/null +++ b/werc/apps/barf/lib/rss @@ -0,0 +1,56 @@ +fn display_rss{ + echo '<?xml version="1.0" encoding="UTF-8"?>' + echo '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">' + echo '<channel>' + echo '<atom:link href="'$base_url^$req_path'" rel="self" type="application/rss+xml" />' + echo '<title><![CDATA['$"siteTitle']]>' + echo ''$base_url^$barf_base_uri'' + echo '' + echo '' + echo '' + ndate -m `{date `{mtime $barf_root/$"barf_dir/src | awk '{print $1}'}} # rfc2822 last time channel content changed. + echo -n '' + echo 'en-us' + date=`{ndate -m} # rfc2822 publication date for content in the channel. + get_post_list + for(i in `{seq 1 $#posts}){ + a_id=$posts($i) + a_dir=$barf_root/$"barf_dir/src/$a_id + echo '' + echo ''$base_url^$barf_base_uri'?id='$"a_id'' + echo ''$"date'' + title=`{cat $a_dir/title} + if(~ $title '') + ntitle=($siteTitle $"a_id) + if not + ntitle=$title + echo ''$"ntitle'' + echo ''$base_url^$barf_base_uri'?id='$"a_id'' + echo 'source: link

' + } + a_tags=`{ls -p $a_dir/tags} + if(! ~ $#a_tags 0){ + echo '

tags: ' + print_tags + echo '

' + echo '

' + } + # begin ugly if statements + if(~ $obarf_type paste) + echo '

'
+		if(! ~ $obarf_type image)
+		cat $a_dir/body
+		if(~ $obarf_type paste)
+			echo '
' + if(~ $obarf_type image) + print_img + echo '

]]>
' + } + echo '' +} diff --git a/werc/apps/barf/lib/url b/werc/apps/barf/lib/url new file mode 100755 index 0000000..3079ff2 --- /dev/null +++ b/werc/apps/barf/lib/url @@ -0,0 +1,52 @@ +fn display_url{ + if(~ $#logged_user 0) + a='login' + if not + a='add' + echo '
+ '$"a' + +
+ + +
+
+
+ +
+ + + + + + ' + if(check_user && ! ~ $#logged_user 0) + echo '' + echo '' + get_post_list + for(i in `{seq 1 $#posts}){ + a_id=$posts($i) + a_dir=$barf_root/$"barf_dir/src/$a_id + echo ' + + + ' + if(check_user && ! ~ $#logged_user 0){ + echo '' + } + echo '' + } + echo ' +
    
' + print_title + echo '' + print_tags + echo '' + cat $a_dir/date + echo '' + print_edit + echo '
' + display_prevnext + echo '



+
' +} diff --git a/werc/apps/barf/mkfile b/werc/apps/barf/mkfile new file mode 100755 index 0000000..9ecc731 --- /dev/null +++ b/werc/apps/barf/mkfile @@ -0,0 +1,10 @@ +WERC=/usr/sl/www/werc +PLAN9=$WERC/sites/plan9.stanleylieber.com + +web:V: + src=`{basename `{pwd}} + rm -rf $PLAN9/werc/apps/$src + cd $WERC/apps + tar zcvf $PLAN9/werc/apps/$src.tgz $src + cd $PLAN9/werc/apps + tar zxvf $src.tgz diff --git a/werc/apps/barf/pub/1995.css b/werc/apps/barf/pub/1995.css new file mode 100755 index 0000000..fdea8de --- /dev/null +++ b/werc/apps/barf/pub/1995.css @@ -0,0 +1,344 @@ +/* 1995 */ + +body { + color: black; + background-color: silver; + font-family: Helvetica, Verdana, Arial, 'Liberation Sans', FreeSans, sans-serif; + font-size: 84%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} + + +/* # Header # */ +.superHeader { + color: black; + background-color: silver; + height: 1.6em; +} + +.superHeader img { vertical-align: bottom; } + +.superHeader a { + color: blue; + background-color: transparent; + font-size: 91%; + margin: 0; + padding: 0 0.5ex 0 0.25ex; + text-decoration: underline; } +} + +a { text-decoration: underline; } +a:hover { text-decoration: underline; } + +.superHeader div { + position: absolute; + top: 0.40ex; +} + +.superHeader .left { left: 0.4em; } +.superHeader .right { right: 0.4em; } + +.midHeader { + color: black; + background-color: silver; + border: solid 0 black; + border-width: 1px 0; +} + +.headerTitle { + color: black; + font-size: 233%; + font-weight: normal; + margin: 0 0 0 4mm; + padding: 0.25ex 0; +} +#headerSubTitle { + font-size: 50%; + font-style: italic; + margin-left: 1em; +} + +.headerTitle a { color: black; } +.headerTitle a:hover { text-decoration: none; } + +.subHeader { + display: none; + color: white; + background-color: rgb(0,51,153); + margin: 0; + padding: 1ex 1ex 1ex 1.5mm; +} + +.subHeader a { + color: white; + background-color: transparent; + font-weight: bold; + margin: 0; + padding: 0 0.75ex 0 0.5ex; +} + +.superHeader .highlight, .subHeader .highlight { + color: rgb(253,160,91); + background-color: transparent; +} + + +/* # Side # */ +#side-bar { + width: 16em; + float: left; + clear: left; + border-right: 1px solid black; +} + +#side-bar div { + border-bottom: 1px solid black; +} + +.sideBarTitle { + font-weight: bold; + margin: 0 0 0.5em 2mm; + padding: 1em 0 0 0; +} + +#side-bar ul { + list-style-type: none; + list-style-position: outside; + margin: 0; + padding: 0 0 0.3em 0; +} + +li ul { + padding-left: 0.6em !important; +} + +#side-bar li { + margin: 0; + padding: 0.1ex 0; /* Circumvents a rendering bug (?) in MSIE 6.0 XXX should move to iehacks.css, this causes an ugly gap */ +} + +#side-bar a { + color: black; + background-color: transparent; + margin: 0; + padding: 0.25em 1ex 0.25em 2mm; + display: block; + text-transform: capitalize; + font-weight: bold!important; + font-size: 102%; + border-left: blue solid 0.2em; +} + +.thisPage, .thisPage a { + color: black!important; + background-color: white; + padding-left: 5mm; +} + +#side-bar a:hover { + color: white; + background-color: blue; + border-left: black solid 0.2em; + text-decoration: none; +} + +.sideBarText { + line-height: 1.5em; + margin: 0 0 1em 0; + padding: 0 1.5ex 0 2.5mm; + display: block; +} + +#side-bar .sideBarText a { + margin: 0; + padding: 0; + display: inline; +} + +#side-bar .sideBarText a:hover { + color: black; + background-color: transparent; + text-decoration: none; +} + + +/* # Main Copy # */ +#main-copy { + max-width: 70em; + color: black; + background-color: transparent; + text-align: justify; + line-height: 1.5em; + margin: 0em 0 0 16em; + padding: 0.5mm 5mm 5mm 5mm; + border-left: 1px solid black; +} + +#bodyText { + margin: 0 0 0 15.5em; + padding: 2mm 5mm 2mm 5mm; +} + +#main-copy p { + margin: 1em 1ex 1em 1ex !important; /* Need !important so troff-generated pages don't look totally squezed */ + padding: 0; +} + +#main-copy a { + color: blue; + background-color: transparent; + text-decoration: underline; +} + +#main-copy a:hover { + color: blue; + background-color: transparent; + text-decoration: underline; +} + +#main-copy h1, #main-copy h2 { + color: black; + background-color: transparent; + font-size: 145.5%; + font-weight: bold; + margin: 2em 0 0 0; + padding: 0.5ex 0 0.5ex 0.6ex; + border-bottom: 2px solid black; +} + +#main-copy h2 { + font-size: 115.5%; + border-bottom: 1px solid black; +} + +#main-copy .topOfPage { + color: black; + background-color: transparent; + font-size: 91%; + font-weight: bold; + text-decoration: none; + margin: 3ex 1ex 0 0; + padding: 0; + float: right; +} + +dl { + margin: 1em 1ex 2em 1ex; + padding: 0; +} + +dt { + font-weight: bold; + margin: 0 0 0 0; + padding: 0; +} + +dd { + margin: 0 0 2em 2em; + padding: 0; +} + + +/* # Footer # */ +#footer { + color: black; + background-color: silver; + padding: 1em; + clear: both; + border-color: black; + border-width: 1px 0; +} + +#footer .left { + text-align: left; + line-height: 1.55em; + float: left; + clear: left; +} + +#footer .right { + text-align: right; + line-height: 1.45em; +} + +#footer a { + color: blue; + background-color: transparent; +} + + +/* GENERAL */ + +table { + background-color: transparent; + padding: 0px; + border: 0px; + border-collapse: collapse; +} + +td { + padding: 10px; + border-width: 1px; + border-style: solid; + border-collapse: collapse; + border-color: #000000; + background: silver; +} + +tr { + border-width: 1px; + border-style: solid; + border-collapse: collapse; + border-color: #000000; +} +hr { + border-width: 0px 0px 0.1em 0px; + border-color: black; +} + +acronym, .titleTip { + border-bottom: 1px solid black; + cursor: help; + margin: 0; + padding: 0 0 0.4px 0; +} + +pre { + margin-left: 2em; + font-size: 1.2em; +} + +blockquote { + border-left: 1px solid blue; + font-style: italic; +} + +.smallCaps { + font-size: 110%; + font-variant: small-caps; +} + +.doNotDisplay { display: none; } + + +.notify_errors, +.notify_notes, +.notify_success { padding: .8em; margin-bottom: 1em; border: 2px solid black; } + +.notify_errors { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; } +.notify_notes { background: #FFF6BF; color: #514721; border-color: #FFD324; } +.notify_success { background: #E6EFC2; color: #264409; border-color: #C6D880; } +.notify_errors a { color: #8a1f11; } +.notify_notes a { color: #514721; } +.notify_success a { color: #264409; } + + +/* # Page/Handler specific # */ +h1.dir-list-head, ul.dir-list { + text-transform: capitalize; + font-weight: bold; +} +ul.sitemap-list a { + text-transform: capitalize; +} diff --git a/werc/apps/barf/pub/1oct1993.css b/werc/apps/barf/pub/1oct1993.css new file mode 100755 index 0000000..3413a52 --- /dev/null +++ b/werc/apps/barf/pub/1oct1993.css @@ -0,0 +1,63 @@ +/* 1oct1993 */ +body { + color: #FFFFFF; + background-color: #000000; + font-family: 'Lucida Sans Unicode', 'Lucida Sans', 'Lucida Grande', 'Bitstream Sans Vera', Sans-Serif; + font-size: 84%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} +a { text-decoration: none; color: #00ADEF; } +a:hover { color: #00ADEF; text-decoration: none; } +li:hover { color: #00ADEF; text-decoration: none; } +li a { color: #00ADEF } +li a:hover { color: #00ADEF; text-decoration: none; } +li ul { padding-left: 0.6em !important; } +h1 { font-size: 10pt; font-weight: normal; } +h2 { font-size: 9pt; font-weight: normal; } +input , textarea, select, option { background-color: #00ADEF; border: none; } +table { border: none; } +tr { background-color: transparent; } +th { + background-color: transparent; + border: none; + text-align: center; +} +td { + background-color: transparent; + border: none; +} + +hr { + border-width: 0px 0px 0.1em 0px; + border-color: transparent; +} +pre, code, blockquote { + font-family: Courier, 'Lucida Console','Courier New', Serif; + margin-left: 2em; + font-size: 1.2em; +} +blockquote { + border-left: none; + font-style: none; + background-color: #00ADEF; +} +#header { flex-basis: 100%; } +#header tr { background-color: transparent; } +#center { + width: 500px; + margin-left: auto; + margin-right: auto; +} +#center h1 { font-size 9pt; } +#footer { + font-size: 8pt; + background-color: #000000; + color: #00ADEF; + margin-left: auto; + margin-right: auto; +} +#footer a { color: #00ADEF; text-decoration: none; } +#footer a:hover { color: #00ADEF; text-decoration: none; } +#footer table { font-size: 8pt; } +#footer tr { background-color: transparent; } diff --git a/werc/apps/barf/pub/flamesgif.css b/werc/apps/barf/pub/flamesgif.css new file mode 100755 index 0000000..a335717 --- /dev/null +++ b/werc/apps/barf/pub/flamesgif.css @@ -0,0 +1,77 @@ +/* flamesgif.com */ +body { + color: black; + background-color: silver; + font-family: 'Lucida Sans Unicode', 'Lucida Sans', 'Lucida Grande', 'Bitstream Sans Vera', Sans-Serif; + font-size: 84%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} +a { text-decoration: none; color: blue; } +a:hover { color: purple;} +blockquote { + border-left: none; + font-style: none; + background-color: silver; +} +li:hover { color: purple } +li a { color: blue } +li a:hover { color: purple; } +h1 { font-size: 10pt; } +h2, h3, h1, h4 { color : blue; } +hr { + border-width: 0px 0px 0.1em 0px; + border-color: transparent; +} +input , textarea, select, option { background-color: blue; border: none; } +pre, code, blockquote { + font-family: Courier, 'Lucida Console','Courier New', Serif; + margin-left: 2em; + font-size: 1.2em; +} +table { border: none; } +th { + background-color: transparent; + border: none; + text-align: center; +} +td { + background-color: transparent; + border: none; +} +ul { list-style: none; padding-left: 0px; margin: 0px } +#center { + width: 600px; + margin-left: auto; + margin-right: auto; +} +#center h1 { font-size 9pt; } +#footer { + font-size: 8pt; + background-color: silver; + color: blue; + margin-left: auto; + margin-right: auto; +} +#footer a { color: blue; text-decoration: none; } +#footer a:hover { color: purple; text-decoration: none; } +#footer table { font-size: 8pt; } +#right { + float: right; + position: absolute; + top: 210px; + right: 1px; + width: 25%; + height: 100%; + list-style: none; +} +#sidebar { + position: relative; + z-index: 100; + width: 95%; + top: 10px; + right: 10px; + left: 10px; + margin: 2px; + background: silver; +} diff --git a/werc/apps/barf/pub/img.css b/werc/apps/barf/pub/img.css new file mode 100755 index 0000000..2e4debe --- /dev/null +++ b/werc/apps/barf/pub/img.css @@ -0,0 +1,53 @@ +/* img.stanleylieber.com */ +body { display: flex; flex-wrap: wrap; font-family: sans; } +header { flex-basis: 99%; flex-shrink: 0; padding-left: 1em; padding-bottom: 1em; } +article { flex-basis: 99%; padding: 0; } +footer { flex-basis: 99%; flex-shrink: 0; } +header nav { display: flex; justify-content: space-between; } +footer { display: flex; justify-content: space-between; } + +body { margin:0; padding: 0; font-size: 10pt; font-family: Helvetica, Verdana, Arial, 'Liberation Sans', FreeSans, sans-serif; background-color: #000000; color: #FFFFFF; } +a { text-decoration: none; color: #FFFFFF; background-color: #000000; font-weight: bold; } +a:hover { text-decoration: none; background-color: #FFFFFF; color: #000000; } + +/* header and top bar */ +header h3 { padding-bottom: 2px; } +header a img { vertical-align: bottom; padding-top: 1em; } + +/* main copy */ +article { padding-left: 1em; padding-right: 1em; } +article nav { padding-bottom: 2px; } +article div { padding-top: 2px; padding-bottom: 2px; } +article h1, article h2, article h3, article h4, article h5, article h6, article h7, article h8 { + font-weight: bold; margin: 0; padding-bottom: 2px; +} +article a img { vertical-align: bottom; } +article img { max-width: 100%!important; } +article iframe { max-width: 100%!important; } +article video { max-width: 100%!important; } +article fieldset { color: #FFFFFF; border-color: #FFFFFF; } +article legend { color: #FFFFFF; border-color: #FFFFFF; } + +/* footer */ +footer > nav { margin-left: auto; padding: 1em; } + +/* fixed-width fonts */ +pre, code { white-space: pre-wrap!important; } +pre, code, blockquote { + max-width: 100%!important; + font-family: Courier, 'Lucida Console','Courier New', Serif; +} + +/* input */ +input, textarea, select, option { + font-family: Sans-Serif; + font-size: 100%; + padding: 2px; + border-top: solid 1px #FFFFFF; + border-bottom: solid 1px #FFFFFF; + border-left: solid 1px #FFFFFF; + border-right: solid 1px #FFFFFF; + background-color: #000000; + color: #FFFFFF; + margin: 2px; +} diff --git a/werc/apps/barf/pub/inri.css b/werc/apps/barf/pub/inri.css new file mode 100755 index 0000000..3c6a26d --- /dev/null +++ b/werc/apps/barf/pub/inri.css @@ -0,0 +1,417 @@ +/* inri.net */ +body { + font-family :'Lucida Sans Unicode','Lucida Sans', 'Trebuchet MS', 'Lucida Grande', 'Bitstream Sans Vera', Verdana, Arial, Tahoma, Helvetica, Sans-Serif; + font-style : normal; + padding: 2px 2em; + line-height: 1.5em; + font-size: 70%; + background: #FFF; + color: #111; +} + + +/* # Header # */ +.superHeader { + color: white; + background-color: gray; + height: 1.6em; +} + +.superHeader img { vertical-align: bottom; } + +.superHeader a { + color: white; + background-color: transparent; + font-size: 91%; + margin: 0; + padding: 0 0.5ex 0 0.25ex; +} + +a { text-decoration: none; } +a:hover { text-decoration: underline; } + +.superHeader div { + position: absolute; + top: 0.40ex; +} + +.superHeader .left { left: 0.4em; } +.superHeader .right { right: 0.4em; } + +.midHeader { + color: gray; + background-color: gray; + background-color: #ff6d06; + border: solid 0 black; + border-width: 2px 0; +} + +.headerTitle { + color: black; + font-size: 233%; + font-weight: normal; + margin: 0 0 0 4mm; + padding: 0.25ex 0; +} +#headerSubTitle { + font-size: 50%; + font-style: italic; + margin-left: 1em; +} + +.headerTitle a { color: black; } +.headerTitle a:hover { text-decoration: none; } + +.subHeader { + display: none; + color: white; + background-color: gray; + margin: 0; + padding: 1ex 1ex 1ex 1.5mm; +} + +.subHeader a { + color: white; + background-color: transparent; + font-weight: bold; + margin: 0; + padding: 0 0.75ex 0 0.5ex; +} + +.superHeader .highlight, .subHeader .highlight { + color: gray; + background-color: transparent; +} + + +/* # Side # */ +#side-bar { + width: 16em; + float: left; + clear: left; + border-right: 1px solid white; +} + +#side-bar div { + border-bottom: 1px solid white; +} + +.sideBarTitle { + font-weight: bold; + margin: 0 0 0.5em 2mm; + padding: 1em 0 0 0; +} + +#side-bar ul { + list-style-type: none; + list-style-position: outside; + margin: 0; + padding: 0 0 0.3em 0; +} + +li ul { + padding-left: 0.6em !important; +} + +#side-bar li { + margin: 0; + padding: 0.1ex 0; /* Circumvents a rendering bug (?) in MSIE 6.0 XXX should move to iehacks.css, this causes an ugly gap */ +} + +#side-bar a { + color: gray; + background-color: transparent; + margin: 0; + padding: 0.25em 1ex 0.25em 2mm; + display: block; + text-transform: capitalize; + font-weight: bold!important; + font-size: 102%; + border-left: white solid 0.2em; +} + +.thisPage, .thisPage a { + color: black!important; + background-color: white; + padding-left: 5mm; +} + +#side-bar a:hover { + color: black; + background-color: gray; + border-left: gray solid 0.2em; + text-decoration: none; +} + +.sideBarText { + line-height: 1.5em; + margin: 0 0 1em 0; + padding: 0 1.5ex 0 2.5mm; + display: block; +} + +#side-bar .sideBarText a { + margin: 0; + padding: 0; + display: inline; +} + +#side-bar .sideBarText a:hover { + color: gray; + background-color: transparent; + text-decoration: none; +} + + +/* # Main Copy # */ +#main-copy { + max-width: 70em; + color: black; + background-color: transparent; + text-align: justify; + line-height: 1.5em; + margin: 0em 0 0 16em; + padding: 0.5mm 5mm 5mm 5mm; + border-left: 1px solid white; +} + +#bodyText { + margin: 0 0 0 15.5em; + padding: 2mm 5mm 2mm 5mm; +} + +#main-copy p { + margin: 1em 1ex 1em 1ex !important; /* Need !important so troff-generated pages don't look totally squezed */ + padding: 0; +} + +#main-copy a { + color: gray; + background-color: transparent; +} + +#main-copy a:hover { + color: gray; +} + +#main-copy h1, #main-copy h2 { + color: gray; + background-color: transparent; + font-size: 145.5%; + font-weight: bold; + margin: 2em 0 0 0; + padding: 0.5ex 0 0.5ex 0.6ex; + border-bottom: 2px solid gray; +} + +#main-copy h2 { + font-size: 115.5%; + border-bottom: 1px solid gray; +} + +#main-copy .topOfPage { + color: gray; + background-color: transparent; + font-size: 91%; + font-weight: bold; + text-decoration: none; + margin: 3ex 1ex 0 0; + padding: 0; + float: right; +} + +#post { + position: relative; + left: 23%; + width: 76%; + padding-top: 25px; + padding-bottom: 25px; +} + +#post tr { background-color: transparent; } + +#center { + position: absolute; + top: 210px; + left: 1%; + width: 65%; + height: 100%; +} +#center h1 { font-size 8pt; font-family :'Lucida Sans Unicode','Lucida Sans', 'Trebuchet MS', 'Lucida Grande', 'Bitstream Sans Vera', Verdana, Arial, Tahoma, Helvetica, Sans-Serif; } + +a { text-decoration: none; color: #000000; } +a:hover { color: #111;} +li:hover { color: #111 } +li a { color: #000000 } +li a:hover { color: #111; } +ul { list-style: none; padding-left: 0px; margin: 0px } + +h1 { font-size: 8pt; font-weight: normal; } +h2 { font-size : 140%; } +h3 { font-size: 120%; } +h4 { font-size: 100%; } +h2, h3, h1, h4 { + font-family: Georgia,'Trebuchet MS', 'Lucida Sans', 'Lucida Grande', 'Bitstream Sans Vera', Verdana, Arial, Tahoma, Helvetica, Sans-Serif; + color : #000000; + margin: 0px 0px; + padding: 2px 0px; + clear: both; +} + +input , textarea, select, option { background-color: #eee; border: none; } + +dl { + margin: 1em 1ex 2em 1ex; + padding: 0; +} + +dt { + font-weight: bold; + margin: 0 0 0 0; + padding: 0; +} + +dd { + margin: 0 0 2em 2em; + padding: 0; +} + +#right { + float: right; + position: absolute; + top: 210px; + right: 1px; + width: 34%; + height: 100%; + list-style: none; +} + +/* sidebar */ +#sidebar { + position: relative; + z-index: 100; + width: 95%; + top: 10px; + right: 10px; + left: 10px; + margin: 2px; + background: #FFFFFF; +} +#sidebar h2 { + margin: 5px 0px 0px; + padding: 4px 0px; + font-size:100%; +} +#sidebar li { font-size: 8.5pt; } +#sidebar ul { margin: 2px; } + +/*searchform*/ +#searchform label { font-weight:bold; } +#searchform input { width: 20%; } +#searchform input.submit { width: 16%; } + +#top { + float: top; + position: absolute; + top: 0px; + left: 0px; + right: 0px; + height: 10%; + width: 100% + overflow: auto; +} + + +/* # Footer # */ +#footer { + font-size: 8pt; + background-color: white; + color: black; +} +#footer a { color: gray; text-decoration: none; } +#footer a:hover { color: #111; text-decoration: none; } +#footer table { font-size: 8pt; } + +#footer .left { + text-align: left; + line-height: 1.55em; + float: left; + clear: left; +} + +#footer .right { + text-align: right; + line-height: 1.45em; +} + +/* GENERAL */ + +table { + background-color: transparent; + border: none; +} +tr { + background-color: transparent; + border: none; +} +th { + background-color: transparent; + border: none; + text-align: center; +} +td { + background-color: transparent; + border: none; +} + +hr { + border-width: 0px 0px 0.1em 0px; + border-color: transparent; +} + +acronym, .titleTip { + border-bottom: 1px solid #ddd; + cursor: help; + margin: 0; + padding: 0 0 0.4px 0; +} + +pre { + margin-left: 2em; + font-size: 1.2em; +} + +blockquote { + border-left: none; + font-style: none; + background-color: silver; +} + +.smallCaps { + font-size: 110%; + font-variant: small-caps; +} + +.doNotDisplay { display: none; } + + +.notify_errors, +.notify_notes, +.notify_success { padding: .8em; margin-bottom: 1em; border: 2px solid #ddd; } + +.notify_errors { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; } +.notify_notes { background: #FFF6BF; color: #514721; border-color: #FFD324; } +.notify_success { background: #E6EFC2; color: #264409; border-color: #C6D880; } +.notify_errors a { color: #8a1f11; } +.notify_notes a { color: #514721; } +.notify_success a { color: #264409; } + + +/* # Page/Handler specific # */ +h1.dir-list-head, ul.dir-list { + text-transform: capitalize; + font-weight: bold; +} +ul.sitemap-list a { + text-transform: capitalize; +} diff --git a/werc/apps/barf/pub/massivefictions.css b/werc/apps/barf/pub/massivefictions.css new file mode 100755 index 0000000..0fe572f --- /dev/null +++ b/werc/apps/barf/pub/massivefictions.css @@ -0,0 +1,62 @@ +/* mf */ +body { + color: #a6a6a6; + background-color: #626060; + font-family: 'Lucida Sans Unicode', 'Lucida Sans', 'Lucida Grande', 'Bitstream Sans Vera', Sans-Serif; + font-size: 84%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} +a { text-decoration: none; color: #a6a6a6; } +a:hover { background-color: #a6a6a6; color: #626060; text-decoration: none; } +a img { display: block; border: 0 none; } +li:hover { background-color: #a6a6a6; color: #626060; text-decoration: none; } +li a { color: #a6a6a6 } +li a:hover { background-color: #a6a6a6; color: #626060; text-decoration: none; } +li ul { padding-left: 0.6em !important; } +h1 { font-size: 10pt; font-weight: normal; } +h2 { font-size: 9pt; font-weight: normal; } +input , textarea, select, option { background-color: #a6a6a6; border: none; } +table { border: none; background-color: transparent; } +th { + background-color: transparent; + border: none; + text-align: center; +} +tr:nth-child(odd) { background-color: transparent; } +td { + background-color: transparent; + border: none; +} +hr { + border-width: 0px 0px 0.1em 0px; + border-color: transparent; +} +pre, code, blockquote { + font-family: Courier, 'Lucida Console','Courier New', Serif; + margin-left: 2em; + font-size: 1.2em; +} +blockquote { + border-left: none; + font-style: none; + background-color: #a6a6a6; +} +#header { + margin-left: auto; + margin-right: auto; +} +#center { + width: 500px; + margin-left: auto; + margin-right: auto; +} +#center h1 { font-size 9pt; } +#footer { + font-size: 8pt; + background-color: #626060; + color: #a6a6a6; +} +#footer a { color: #a6a6a6; text-decoration: none; } +#footer a:hover { color: #626060; text-decoration: none; } +#footer table { font-size: 8pt; } diff --git a/werc/apps/barf/pub/okturing.css b/werc/apps/barf/pub/okturing.css new file mode 100755 index 0000000..76b5d69 --- /dev/null +++ b/werc/apps/barf/pub/okturing.css @@ -0,0 +1,58 @@ +/* okturing.com */ +body { display: flex; flex-wrap: wrap; font-family: sans; } +header { flex-basis: 100%; flex-shrink: 0; } +article { flex-basis: 100%; padding: 1em; } +footer { flex-basis: 100%; flex-shrink: 0; } +header nav { display: flex; justify-content: space-between; } +nav a, header a { text-decoration: none ; color: inherit; } +header h1 span { margin-left: 1em; font-size: 50%; font-style: italic; } +body > nav { flex-basis: content; padding-right: 1vw; min-width: 16em; } +nav ul { display: flex; flex-direction: column; list-style-type: none; list-style-position: outside; padding-left: 0; } +nav li ul { padding-left: 0.6em } +footer { display: flex; justify-content: space-between; } + +/* cut here to leave vanity behind */ + +body { margin:0; padding: 0; font-size: 84%; font-family: 'Lucida Sans Unicode', 'Lucida Sans', 'Lucida Grande', 'Bitstream Sans Vera', Sans-Serif; background-color: #FFFFFF; color: #000000; } +a:hover { text-decoration: none; background-color: #FFFFFF; color: #000000; } + +/* header and top bar */ +header nav { background-color: #FFFFFF; color: #000000; padding: 0em; border-bottom: 2px solid #FFFFFF; font-size: 91%; } +header h1 { background-color: #FFFFFF; color: #000000; margin: 0; border-bottom: 2px solid #FFFFFF; font-weight: normal; padding: 0.25ex; font-size: 233%; } + +/* sidebar */ +body > nav { border-right: 1px solid #FFFFFF; padding: 0; } +body > nav > div { border-bottom: 1px solid #FFFFFF; } +body > nav > div a { background-color: #00ff00; color: #000000; display: block; text-transform: capitalize; font-weight: bold; padding: 0.25em 1ex 0.25em 2mm; font-size: 102%} +body > nav > div a:hover { color: #FFFFFF; background-color: #000000 border-left: #FFFFFF solid 0.2em; text-decoration: none; } +body > nav > div p { font-weight: bold; margin: 0 0 0.5em 2mm; padding: 1em 0 0 0; } + +/* main copy */ +article { padding: 1em; } +article h1, article h2 { color: #000000; font-weight: bold; margin: 2em 0 0 0; border-bottom: 2px solid #FFFFFF; } +article h3, article h4, article h5 { #000000; font-weight: bold; margin: 2em 0 0 0; } +article h6, article h7, article h8 { color: #000000; font-weight: bold; margin: 2em 0 0 0; } +article a { background-color: #FFFFFF; color: #000000; text-decoration: none; } +article a:hover { text-decoration: none; background-color: #000000; color: #FFFFFF; } +article a img { display: block; border: 0 none; } + +/* footer */ +footer { color: #000000; background-color: #FFFFFF; } +footer a { background-color: #FFFFFF; color: #000000; } +footer div { padding: 1em; } + +input, textarea, select, option { + font-family: 'Lucida Sans Unicode', 'Lucida Sans', 'Lucida Grande', 'Bitstream Sans Vera', Sans-Serif; + font-size:100%; + padding: 2px; + background : #eee; + color : #111; + border: 1px solid #fff; + margin: 2px; +} + +pre, code, blockquote { + white-space: pre-wrap; + padding-left: 2em; + font-family: Courier, 'Lucida Console','Courier New', Serif; +} diff --git a/werc/apps/barf/pub/osx.css b/werc/apps/barf/pub/osx.css new file mode 100755 index 0000000..914c4c7 --- /dev/null +++ b/werc/apps/barf/pub/osx.css @@ -0,0 +1,345 @@ +/* osx.stanleylieber.com */ + +body { +font-family :Helvetica, Verdana, Arial, Sans-Serif; +font-style : normal; +padding: 2px 2em; +line-height: 1.5em; +font-size: 70%; +background: #FFF; +color: #111; +} + +/* font styles */ +a { text-decoration: none; color: #000000; } +a:hover { background: #7600FC; color: #fff; } +li:hover { color: #000000; } +li a { color: #000000; } +li a:hover { background: #7600FC; color: #fff; } +ul { list-style: none; padding-left: 0px; margin: 0px } +p { +font-size : 100%; +font-style : normal; +padding: 0px; +} +h2 { +font-size : 140%; +} +h3 { +font-size: 120%; +} +h4 { +font-size: 100%; +} +h2, h3, h1, h4 { +font-family: Helvetica, Verdana, Arial, Sans-Serif; +color : #000000; +margin: 0px 0px; +padding: 2px 0px; +clear: both; +} +/* end font styles */ + +hr { +border: 1px solid #fff; +} + +blockquote, code { +background : #eee; +padding: 6px; +border-left: 3px solid #eee; +} + +code, pre { +font-family: Courier, 'Lucida Console','Courier New', Sans-Serif; +} + +#admin_banner { +position: relative; +text-align: center; +} + +#admin_body { +position: relative; +top: 100px; +left: 10px; +width: 90%; +} + +#admin_frames { +height: 100%; +float: top; + +/* for ie */ +margin: 0; +overflow: auto; +/* end for ie */ + +} + +#admin_index_body { +position: relative; +top: 100px; +margin-left: auto; +margin-right: auto; +} + + +#admin_menu { +position: relative; +left: 10px; +width: 90%; +text-align: left; +} + +#admin_table { +margin-left: auto; +margin-right: auto; +width: 90%; +border-collapse: collapse; +border-color: #111; +font-family: sans-serif; +font-size: 9pt; +} + +#admin_table td { +vertical-align: middle; +text-align: center; +} + +#admin_table th { +background: #111; +color: gray; +} + +#bottom { +float: bottom; +position: absolute; +bottom: 10px; +} + +#button input.submit { +background: #111; +color: gray; +border-top: solid 1px #111; +border-bottom: solid 1px #111; +border-left: solid 1px #111; +border-right: solid 1px #111; +width: 15%; +} + +#center { +position: absolute; +top: 155px; +left: 1%; +width: 65%; +height: 100%; +} + +#divider { +background: #111; +height: 1px; +} + +/*forms*/ +input , textarea, select, option { +font-family : Helvetica, Verdana, Arial, Sans-Serif; +font-size:100%; +padding: 2px; +background : #eee; +color : #111; +border: 1px solid #fff; +margin: 2px; +} +fieldset, legend { +background:transparent; +color : #111; +border: none; +padding: 5px; +} +label, legend { +font-weight:normal; +} + +#header { +float: top; +position: absolute; +top: 0px; +left: 17%; +height: 100%; +font-size: 24pt; +background: #7600FC; +height: 50px; +} + +#header a { +background: #7600FC; +color: #fff; +} + +#left { +float: left; +position: absolute; +top: 0px; +left: 10%; +width: 15%; +height: 100%; +list-style: none; +overflow: auto; +} + +#meta { +font-size: 8pt; +} + +#page_frames { +width: 100%; +float: left; + +/* for ie */ +margin: 0; +overflow: auto; +/* end for ie */ + +} + +#page_category { +position: relative; +text-align: center; +} + +#page_list { +text-align: right; +font-size: 9pt; +} + +#page_login { +position: relative; +text-align: right; +font-size: 8pt; +} + +#page_upload { +background: #111; color: #444; font-weight: bold +} + +#post { +position: relative; +left: 13%; +width: 86%; +padding-bottom: 100px; +} + +#post_body { +position: relative; +top: 10px; +bottom: 10px; +left: 10px;; +} + +#post_date { +font-size: 8pt; +} + +#post_meta { +margin-left: 2px; +color: #111; +font-size: 8pt; +} + +#post_tags { +font-size: 8pt; +} + +#post_thumb { +margin-top: 5px; +margin-bottom: 5px; +} + +#post_title { +border: 1px; +line-height: 1.5em; +} + +#post_title a { +background: red; +color: #fff; +} + +#post_title a:hover { +background: #7600FC; +color: #fff; +} + +#post_title h2 { +font-weight: 100; +} + +#registration_body { +left: 10px; +text-align: left; +} + +#right { +float: right; +position: absolute; +top: 150px; +right: 1%; +width: 33%; +height: 100%; +list-style: none; +} + +#rss { +margin-left: auto; +margin-right: auto; +text-align: center; +font-size: 8pt; +} + +/* sidebar */ +#sidebar { +position: relative; +z-index: 100; +width: 90%; +top: 10px; +right: 10px; +left: 10px; +margin: 2px; +background: #FFFFFF; +} +#sidebar h2 { +margin: 5px 0px 0px; +padding: 4px 0px; +font-size:100%; +} +#sidebar ul { +margin: 2px; +} + +/*searchform*/ +#searchform label { +font-weight:bold; +} +#searchform input#s { +width: 40%; +} +#searchform input.submit { +width: 16%; +} + +#top { +float: top; +position: absolute; +top: 0px; +left: 0px; +right: 0px; +height: 10%; +width: 100% +overflow: auto; +} + +.warning { +color: #111; +font-weight: bold; +} diff --git a/werc/apps/barf/pub/other.css b/werc/apps/barf/pub/other.css new file mode 100755 index 0000000..002fd5a --- /dev/null +++ b/werc/apps/barf/pub/other.css @@ -0,0 +1,67 @@ +/* other */ +body { + color: blue; + background-color: white; + font-family: 'Lucida Sans Unicode', 'Lucida Sans', 'Lucida Grande', 'Bitstream Sans Vera', Sans-Serif; + font-size: 84%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} +a { text-decoration: none; color: blue; } +a:hover { color: purple; background-color: white; text-decoration: none; } +li:hover { color: purple; background-color: white; text-decoration: none; } +li a { color: blue; } +li a:hover { color: purple; background-color: white; text-decoration: none; } +h1 { font-size: 10pt; font-weight: normal; } +h2 { font-size: 9pt; font-weight: normal; } +input , textarea, select, option { background-color: #eee; border: none; } +li ul { + padding-left: 0.6em !important; +} +table { border: none; background-color: transparent; } +th { + background-color: transparent; + border: none; + text-align: center; +} +tr:nth-child(odd) { background-color: transparent; } +td { + background-color: transparent; + border: none; +} +hr { + border-width: 0px 0px 0.1em 0px; + border-color: transparent; +} +pre, code, blockquote { + Courier, 'Lucida Console','Courier New', Serif; + margin-left: 2em; + font-size: 1.2em; +} +blockquote { + border-left: none; + font-style: none; + background-color: #eee; +} +#center { + width: 500px; + margin-left: auto; + margin-right: auto; + line-height: 0; +} +/* #center p { + line-height: 1; + -webkit-margin-before: 0px; + -webkit-margin-after: 0px; +} */ +#footer { + font-size: 8pt; + background-color: white; + color: blue; + margin-left: auto; + margin-right: auto; +} +#footer a { color: blue; text-decoration: none; } +#footer a:hover { color: purple; background-color: white; text-decoration: none; } +#footer table { font-size: 8pt; } +#text { line-height: 1; } diff --git a/werc/apps/barf/pub/read.css b/werc/apps/barf/pub/read.css new file mode 100755 index 0000000..4262701 --- /dev/null +++ b/werc/apps/barf/pub/read.css @@ -0,0 +1,29 @@ +/* black */ +header { flex-basis: 99%; flex-shrink: 0; padding-left: 1em; padding-bottom: 1em; } +header h3 { padding-bottom: 2px; } +header a img { vertical-align: bottom; padding-top: 1em; } +body { font-family: Helvetica, Verdana, Arial, 'Liberation Sans', FreeSans, sans-serif; background-color: #000000; color: #FFFFFF; } +a { text-decoration: none; color: #FFFFFF; background-color: #000000; font-weight: bold; } +a:hover { text-decoration: none; background-color: #FFFFFF; color: #000000; } +/* footer */ +footer > nav { margin-left: auto; padding: 1em; } + +/* fixed-width fonts */ +pre, code { white-space: pre-wrap!important; } +pre, code, blockquote { + max-width: 100%!important; + font-family: Courier, 'Lucida Console','Courier New', Serif; +} +/* input */ +input, textarea, select, option { + font-family: Sans-Serif; + font-size: 100%; + padding: 2px; + border-top: solid 1px #FFFFFF; + border-bottom: solid 1px #FFFFFF; + border-left: solid 1px #FFFFFF; + border-right: solid 1px #FFFFFF; + background-color: #000000; + color: #FFFFFF; + margin: 2px; +} diff --git a/werc/apps/barf/pub/stanleylieber.css b/werc/apps/barf/pub/stanleylieber.css new file mode 100755 index 0000000..e79591a --- /dev/null +++ b/werc/apps/barf/pub/stanleylieber.css @@ -0,0 +1,64 @@ +/* nothing */ +body { + display: flex; + flex-wrap: wrap; + color: black; + background-color: white; + font-family: 'Lucida Sans Unicode', 'Lucida Sans', 'Lucida Grande', 'Bitstream Sans Vera', Sans-Serif; + font-size: 84%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} +header, article, footer { flex-basis: 100%; } +a { text-decoration: none; color: gray; } +a:hover { color: #111; text-decoration: none; } +a img { display: block; border: 0 none; } +li:hover { color: #111; text-decoration: none; } +li a { color: gray } +li a:hover { color: #111; text-decoration: none; } +li ul { padding-left: 0.6em !important; } +h1 { font-size: 10pt; font-weight: normal; } +h2 { font-size: 9pt; font-weight: normal; } +input , textarea, select, option { background-color: gray; border: none; } +table { border: none; background-color: transparent; } +th { + background-color: transparent; + border: none; + text-align: center; +} +tr:nth-child(odd) { background-color: transparent; } +td { + background-color: transparent; + border: none; +} + +hr { + border-width: 0px 0px 0.1em 0px; + border-color: transparent; +} +pre, code, blockquote { + font-family: Courier, 'Lucida Console','Courier New', Serif; + margin-left: 2em; + font-size: 1.2em; +} +blockquote { + border-left: none; + font-style: none; + background-color: gray; +} +#center { + width: 500px; + margin-left: auto; + margin-right: auto; +} +#center h1 { font-size 9pt; } +#footer { + font-size: 8pt; + background-color: white; + color: gray; + margin-left: auto; + margin-right: auto; +} +#footer a { color: gray; text-decoration: none; } +#footer a:hover { color: #111; text-decoration: none; } +#footer table { font-size: 8pt; } diff --git a/werc/apps/barf/pub/url.css b/werc/apps/barf/pub/url.css new file mode 100755 index 0000000..b8d0e5b --- /dev/null +++ b/werc/apps/barf/pub/url.css @@ -0,0 +1,195 @@ +/* url.stanleylieber.com */ + +body { + font-family: Vera, Helvetica, Verdana, Arial, Sans-Serif; + font-style: normal; + padding: 2px 2em; + line-height: 1.5em; + font-size: 70%; + background: #FFFFFF; + color: #000000; +} + +a { text-decoration: none; color: #000000; } +a:hover { background: #EEEEEE;} +li:hover { background: #EEEEEE; } +li a:hover { background: #EEEEEE; } +ul { list-style: none; } + +p { + font-size : 100%; + font-style : normal; + padding: 0px; +} + +h2 { font-size : 140%; } +h3 { font-size: 120%; } +h4 { font-size: 100%; } +h2, h3, h1, h4 { + margin: 0px 0px; + padding: 2px 0px; + clear: both; +} + +hr { border: 1px solid #fff; } + +input { + background-color: #EEEEEE; +} + +code, pre { font-family: Courier, 'Lucida Console','Courier New', Sans-Serif; } +blockquote, code { + background : #eee; + padding: 6px; + border-left: 3px solid #eee; +} + +td { + padding: 10px; + border-width: 1px; + border-style: solid; + border-collapse: collapse; + border-color: #000000; + background: #FFFFFF; +} + +textarea { + height: 300px; + background-color: #EEEEEE; +} + +tr { + border-width: 1px; + border-style: solid; + border-collapse: collapse; + border-color: #000000; +} + +#add { + position: relative; + top: 65px; + left: 9%; + font-size: 10pt; +} + +#blank { + border-width: 1px; + border-style: solid; + border-collapse: collapse; + border-color: #FFFFFF; +} + +#bottom { + float: bottom; + position: absolute; + bottom: 0px; + left: 0px; + right: 0px; + width: 100%; +} + +#center { + position: relative; + margin-left: auto; + margin-right: auto; + top: 130px; + width: 90%; + height: 100%; +} + +#edit { + width: 750px; + font-size: 10pt; +} + +#footer { + position: relative; + margin-left: auto; + margin-right: auto; + bottom: 100px; +} + +#header { + position: relative; + margin-left: auto; + margin-right: auto; + top: 40px; + width: 83%; +} + +#logo { font-size: 40pt; color: #DDDDDD; } +#logo a { font-size: 40pt; color: #CCCCCC; } +#logo a:hover { background: #EEEEEE;} + +#list { + position: relative; + margin-left: auto; + margin-right: auto; + top: 90px; + width: 90%; + height: 100%; +} + +#meta { font-size: 8pt; } + +#page_list { + margin: 20px; + text-align: right; + font-size: 9pt; +} + +#post { + position: relative; + padding: 20px; +} + +#post_meta { text-align: center; } + +#post_date { + width: 200px; + text-align: center; + font-size: 8pt; +} + +#post_edit { + width: 100px; + text-align: center; + font-size: 8pt; +} + +#post_table { + position: relative; + margin-left: auto; + margin-right: auto; + padding: 0px; + width: 100%; + border-collapse: collapse; +} + +#post_tags { + text-align: left; + font-size: 8pt; +} + +#post_title { + text-align: left; + font-size: 10pt; +} + +#search { + position: absolute; + top: 90px; + right: 9%; + font-size: 10pt; +} + +#top { + float: top; + position: absolute; + top: 0px; + left: 0px; + right: 0px; + height: 100px; + width: 100%; +} + diff --git a/werc/apps/barf/src/1/body b/werc/apps/barf/src/1/body new file mode 100644 index 0000000..8023cd7 --- /dev/null +++ b/werc/apps/barf/src/1/body @@ -0,0 +1 @@ +Trust, but verify. diff --git a/werc/apps/barf/src/1/date b/werc/apps/barf/src/1/date new file mode 100644 index 0000000..d72158e --- /dev/null +++ b/werc/apps/barf/src/1/date @@ -0,0 +1 @@ +Thu Aug 25 18:35:52 CDT 2011 diff --git a/werc/apps/barf/src/1/link b/werc/apps/barf/src/1/link new file mode 100644 index 0000000..4c592f1 --- /dev/null +++ b/werc/apps/barf/src/1/link @@ -0,0 +1 @@ +http://plan9.stanleylieber.com/9front diff --git a/werc/apps/barf/src/1/tags/demo b/werc/apps/barf/src/1/tags/demo new file mode 100644 index 0000000..e69de29 diff --git a/werc/apps/barf/src/1/tags/random b/werc/apps/barf/src/1/tags/random new file mode 100644 index 0000000..e69de29 diff --git a/werc/apps/barf/src/1/tags/theory b/werc/apps/barf/src/1/tags/theory new file mode 100644 index 0000000..e69de29 diff --git a/werc/apps/barf/src/1/title b/werc/apps/barf/src/1/title new file mode 100644 index 0000000..a4600f9 --- /dev/null +++ b/werc/apps/barf/src/1/title @@ -0,0 +1 @@ +This is a BULGE demo post. diff --git a/werc/apps/barf/tags b/werc/apps/barf/tags new file mode 100755 index 0000000..aff680d --- /dev/null +++ b/werc/apps/barf/tags @@ -0,0 +1,3 @@ +1/tags/theory +1/tags/random +1/tags/demo diff --git a/werc/apps/blagh/app.rc b/werc/apps/blagh/app.rc new file mode 100644 index 0000000..6cd82b1 --- /dev/null +++ b/werc/apps/blagh/app.rc @@ -0,0 +1,148 @@ +fn conf_enable_blog { + blagh_uri=$conf_wd + blagh_dirs=$* + if(~ $#blagh_dirs 0) + blagh_dirs=( . ) + conf_enable_app blagh + + if(~ $"conf_blog_editors '') + conf_blog_editors=blog-editors + + if(~ $"conf_blog_only_pull '') + conf_blog_only_pull=0 + + if(~ $"conf_max_posts_per_page '') + conf_max_posts_per_page=32 +} + +fn blagh_init { + if(~ $#blagh_dirs 0 && ~ $req_path */[bB]log/*) { + blagh_uri=`{echo $req_path | sed 's,(/[bB]log/).*,\1,'} + blagh_dirs=( . ) + } + + # Should not match sub-dirs! + if(! ~ $#blagh_dirs 0) { + # && test -d / `{echo '-a -d '^$blagh_root^$blagh_dirs} + blagh_url=$base_url^$blagh_uri + blagh_root=$sitedir^$blagh_uri + if(check_user $conf_blog_editors && ! ~ $"conf_blog_only_pull '1') { + editor_mode=on + if(~ $"post_arg_date '') + post_date=`{/bin/date -I|sed 's,-,/,g'} + if not + post_date=$post_arg_date + ll_add handlers_bar_left echo 'Make a new post' + } + + if(~ $req_path $blagh_uri) { + handler_body_main=blagh_body + u=$blagh_uri'index' + extraHeaders=$"extraHeaders ^ \ +' + +' + } + if not if(~ $req_path $blagh_uri^index.atom) + blagh_setup_feed_handlers atom.tpl 'application/atom+xml' + + if not if(~ $req_path $blagh_uri^index.rss) + blagh_setup_feed_handlers rss20.tpl 'text/xml; charset=utf-8' + + if not if(~ $req_path $blagh_uri^feed.json) + blagh_setup_feed_handlers jsonfeed.tpl 'application/json; charset=utf-8' + + if not if(~ $req_path $blagh_uri^new_post && ! ~ $#editor_mode 0) { + handler_body_main=( tpl_handler `{get_lib_file blagh/new_post.tpl apps/blagh/new_post.tpl} ) + if(~ $REQUEST_METHOD POST) { + if(mkbpost $"post_arg_body $"post_date $"post_arg_title $post_arg_id) + post_redirect $blagh_uri + if not + notify_errors=$status + } + } + + } +} + +fn blagh_setup_feed_handlers { + handler_body_main=NOT_USED_by_blagh_feeds + res_tail=() + http_content_type=$2 + headers=() + master_template=apps/blagh/$1 # Should we allow tempalte override? +} + +fn blagh_body { + echo '
' + if (! ~ $"blogTitle '') + echo '

'$"blogTitle'

' + + # Direct links to feeds are disabled because they are not very useful, add clutter and might waste pagerank. + # An user can add this on their own using handlers_body_head anyway. + #echo '' + + # XXX Not sure why this fixes issues with blog setup, probably bug in fltr_cache! + for(p in `{get_post_list $blagh_root^$blagh_dirs}) { + l=`{echo -n $p|sed 's!'$sitedir^'/?(.*)([0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9])(/[^/]+/)!\2 /\1\2\3!'} + sed '1s!.*![&]('^$l(2)^') ('^$l(1)^')!' < $p/index.md | + sed 's!\([0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]\)!
&
!' + echo # Needed extra \n so markdown doesn't mess up the formatting, probably can be done in sed. + } | $formatter + # XXX BUG! Markdown [references] break because multiple markdown documents are merged. Should format each blog post independently. + # TODO: use fltr_cache directly, that can fix the previous bug plus provide a perf boost by caching title generation. + echo '
' +} + +fn get_post_list { + # /./->/|/ done to sort -t| and order by date + # Note: $paths in blagh_dirs should not contain '/./' or '|' + ls -F $*^/./[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/ >[2]/dev/null | sed -n '/'^$forbidden_uri_chars^'/d; s,/\./,/|/,; /\/$/p' | sort -r '-t|' +1 | sed -e 's,/+\|/+,/,' -e $conf_max_posts_per_page^'q' +} + +fn mkbpost { + bptext=$1 + bpdate=$2 + bptitle=$3 + bpid=$4 + _status=() + if(~ $"bptext '') + _status=($_status 'You need to provide a post body.') + if(! ~ $"bpdate [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]) + _status=($_status 'Invalid date: '''^$"bpdate^'''') # XXX Should make semantic check. + + if(~ $#_status 0) { + umask 002 # Let group write + if(! ~ $"bpid '') + bpid=`{echo -n '-'^$bpid | sed 's/'$forbidden_uri_chars'+/_/g; 1q'} + + ddir=$blagh_root^$bpdate^'/' + n=`{ls $ddir >[2]/dev/null |wc -l} + + mkdir -p $ddir/$"n^$"bpid/ + { + if(! ~ $"bptitle '') { + echo $bptitle + echo '-------------------------------------' + } + # TODO: Enable metadata + #echo '* Posted:' `{date} + #if(! ~ $#logged_user 0) + # echo '* Author: '$logged_user + echo + echo $bptext + }> $ddir/$"n^$"bpid/index.md + + # Experimental support for http://pubsubhubbub.googlecode.com/ + if(! ~ $"conf_blog_pubsubdub_hub '') { + ifs='' { p=`{echo $req_url|sed 's/new_post$/index.atom/'|url_encode } } + dprint hget -p 'hub.mode=publish&hub.url='^$"p $conf_blog_pubsubdub_hub + hget -d -h -p 'hub.mode=publish&hub.url='^$"p $conf_blog_pubsubdub_hub >[1=2] & + } + } + status=$_status +} + +fn strip_title_from_md_file { + sed '1N; /^.*\n===*$/N; /.*\n===*\n$/d' +} diff --git a/werc/apps/blagh/atom.tpl b/werc/apps/blagh/atom.tpl new file mode 100644 index 0000000..97c665f --- /dev/null +++ b/werc/apps/blagh/atom.tpl @@ -0,0 +1,58 @@ + + +%{ +# See for more info:http://www.tbray.org/ongoing/When/200x/2005/07/27/Atomic-RSS +fn statpost { + f = $1 + + post_uri=$base_url^`{cleanname `{echo $f | sed -e 's!^'$sitedir'!!'}}^'/' + title=`{read $f/index.md} + by=`{ls -m $f | sed 's/^\[//g; s/].*$//g' >[2]/dev/null} + ifs=() { summary=`{cat $f/index.md | strip_title_from_md_file | ifs=$difs {$formatter} } } +} +# rfc3339 date when feed was last updated. +fupdated = `{ndate -a `{date `{mtime `{ls $blagh_root$blagh_dirs/[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/[0-9] | tail -1} | awk '{print $1}'}}} +%} + + + +% if(! ~ $"conf_blog_pubsubdub_hub '') { +% echo '' +% } + + + %($base_url^$req_path%) + + + <![CDATA[%($siteTitle%)]]> + + + %($fupdated%) + + +% for(f in `{get_post_list $blagh_root$blagh_dirs}) { +% statpost $f + + +% # Maybe we should be smarter, see: http://diveintomark.org/archives/2004/05/28/howto-atom-id, example: tag:intertwingly.net,2004:2899 + %($post_uri%) + + <![CDATA[%($title%)]]> +% # + + +
+ +
+ +% # rfc3339 date when entry was last updated. +% eupdated=`{ndate -a `{date `{mtime $f | awk '{print $1}'}}} + %($eupdated%) +
+ +% } + +
+ +% exit diff --git a/werc/apps/blagh/convert.rc b/werc/apps/blagh/convert.rc new file mode 100755 index 0000000..0640805 --- /dev/null +++ b/werc/apps/blagh/convert.rc @@ -0,0 +1,20 @@ +#!/usr/bin/env rc + +path=($PLAN9/bin/ $path) + +for(p in *.md) { + echo + echo '=========================' + echo p $p + pp=`{echo $p | sed 's/^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])[\-_](.*).md$/\1 \2 \3 \4/' } + echo pp $pp + + d=$pp(1)^'/'^$pp(2)^'/'^$pp(3)^'/'^$pp(4)^'/' + + mkdir -p $d + echo $pp(4) | sed -e 's/^[0-9]_//; s/_/ /g;' > $d/index.md + echo '=================================' >> $d/index.md + echo >> $d/index.md + cat $p >> $d/index.md + +} diff --git a/werc/apps/blagh/jsonfeed.tpl b/werc/apps/blagh/jsonfeed.tpl new file mode 100644 index 0000000..fd97ed4 --- /dev/null +++ b/werc/apps/blagh/jsonfeed.tpl @@ -0,0 +1,35 @@ +{ +"version": "https://jsonfeed.org/version/1", +"title": "%($siteTitle%)", +"home_page_url": "%($"base_url%)", +"feed_url": "%($"base_url^$"req_path%)", +"items": [ +%{ +fn statpost { + f = $1 + post_uri=$base_url^`{cleanname `{echo $f | sed -e 's!^'$sitedir'!!'}}^'/' + title=`{read $f/index.md} + #ifs=() { summary=`{cat $f/index.md | crop_text 1024 ... | $formatter } } + ifs=() { summary=`{cat $f/index.md | strip_title_from_md_file | ifs=$difs {$formatter| sed 's/"/\\"/g' | tr -d '\012' } } } +} +%} +% #for(f in `{get_post_list $blagh_root$blagh_dirs}) { +% +% postlist=`{get_post_list $blagh_root$blagh_dirs} +% postcount=0 +% for(f in $postlist) { +% statpost $f + { + "id": "%($post_uri%)", + "url": "%($post_uri%)", + "title": "%($title%)", + "content_html": "%($summary%)" + } +% postcount = `{echo $postcount 1+p | dc} +% if (! ~ $#postlist $postcount) { echo , } +% } +] +} + +% exit + diff --git a/werc/apps/blagh/new_post.tpl b/werc/apps/blagh/new_post.tpl new file mode 100644 index 0000000..bd521c4 --- /dev/null +++ b/werc/apps/blagh/new_post.tpl @@ -0,0 +1,11 @@ +
+% notices_handler +
+ Submit a new blog post +
+ + + + +
+
diff --git a/werc/apps/blagh/rss20.tpl b/werc/apps/blagh/rss20.tpl new file mode 100644 index 0000000..0cba818 --- /dev/null +++ b/werc/apps/blagh/rss20.tpl @@ -0,0 +1,43 @@ + + +%{ +fn statpost { + f = $1 + post_uri = `{echo $f | sed 's,^'$sitedir',,'} + title=`{read $f/index.md} + post_uri=$base_url^`{cleanname `{echo $f | sed -e 's!^'$sitedir'!!'}}^'/' + by=`{ls -m $f | sed 's/^\[//g; s/].*$//g' >[2]/dev/null} + ifs=() {summary=`{ cat $f/index.md |strip_title_from_md_file| ifs=$difs {$formatter | escape_html} }} +} + +%} + + + + + <![CDATA[%($siteTitle%)]]> + %($base_url^$req_path%) + + en-us + +%{ + # uriel99+rss@gmail.com (Uriel) + # rfc2822 last time channel content changed. + lbd=`{ndate -m `{date `{mtime `{ls $blagh_root$blagh_dirs/[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/[0-9] | tail -1} | awk '{print $1}'}}} + echo ''$"lbd'' + # rfc2822 publication date for content in the channel. + pubdate=`{ndate -m} + for(f in `{get_post_list $blagh_root$blagh_dirs}){ + statpost $f +%} + + <![CDATA[%($title%)]]> + + %($post_uri%) + %($post_uri%) + %($pubdate%) + %($summary%) + +% } + + diff --git a/werc/apps/bridge/app.rc b/werc/apps/bridge/app.rc new file mode 100755 index 0000000..40477ba --- /dev/null +++ b/werc/apps/bridge/app.rc @@ -0,0 +1,103 @@ +comment_file_types=(md html) + +fn conf_enable_comments { + if(~ $1 -n) { + allow_new_user_comments=yes + shift + } + if not if(~ $1 -a) { + bridge_anon_comments=yes + } + enable_comments=yes + groups_allowed_comments=$* + conf_enable_app bridge +} + +fn bridge_init { + if(~ $#enable_comments 1 && ! ~ `{ls $local_path.$comment_file_types >[2]/dev/null|wc -l} 0) { + + comments_dir=$sitedir$req_path'_werc/comments' + if(~ $REQUEST_METHOD GET && test -d $comments_dir) + ll_add handlers_body_foot template apps/bridge/comments_list.tpl + + if(check_user $groups_allowed_comments || {~ $#logged_user 0 && ~ 1 $#allow_new_user_comments $#bridge_anon_comments}) { + + if(~ $#post_arg_bridge_post 1) { + ll_add handlers_body_foot template apps/bridge/foot.tpl + + if(mk_new_comment $comments_dir) + post_redirect $base_url^$req_path + if not + saved_comment_text=$post_arg_comment_text + } + if not if(~ $REQUEST_METHOD GET) + ll_add handlers_body_foot template apps/bridge/foot.tpl + } + if not if(~ $REQUEST_METHOD GET) + ll_add handlers_body_foot echo '

To post a comment you need to login first.

' + } +} + +fn validate_new_user { + usr=$1; pass=$2; pass2=$3 + _status=() + + if(~ $"usr '' || ! echo $usr |sed 1q|grep -s '^'$allowed_user_chars'+$') + _status='Requested user name is invalid, must match: '^$allowed_user_chars^'+' + if not if(test -d etc/users/$usr) + _status='Sorry, user name '''^$usr^''' already taken, please pick a different one.' + + if(~ $"pass '' || ! ~ $"pass $"pass2) + _status=($_status 'Provided passwords don''t match.') + + status=$_status +} + + +fn mk_new_comment { + _status=() + dir=$1 + if(~ $"post_arg_comment_text '') + _status='Provide a comment!' + if not if(~ $#logged_user 0) { + if(! ~ $#allow_new_user_comments 0) { + if(validate_new_user $"post_arg_comment_user $post_arg_comment_passwd $post_arg_comment_passwd2) { + u=$post_arg_comment_user':'$post_arg_comment_passwd + dir=$comments_dir^'_pending' + # XXX: This doesn't work because we then do a redirect. + notify_notes='Saved comment and registration info, they will be enabled when approved by an admin.' + } + if not + _status=$status + } + if not if(! ~ $#bridge_anon_comments 0) { + if(~ $"post_arg_ima_robot 'not') + u='Glenda' # Anonymous + if not + _status='You are a robot!' + } + if not + _status='You need to log in to comment.' + } + if not if(check_user $groups_allowed_comments) + u=$logged_user + if not + _status='You are not a member of a group allowed to comment.' + + if(~ $#_status 0) { + umask 002 + + dir=$dir'/'`{date -n} # FIXME Obvious race + mkdir -m 775 -p $dir && + echo $u > $dir/user && + echo $current_date_time > $dir/posted && + echo $post_arg_comment_text > $dir/body + _s=$status + if(! ~ $"_s '') { + dprint 'ERROR XXX: Could not create comment: ' $_s + _status='Could not post comment due internal error, sorry.' + } + } + notify_errors=$_status + status=$_status +} diff --git a/werc/apps/bridge/comments_list.tpl b/werc/apps/bridge/comments_list.tpl new file mode 100755 index 0000000..03e0ddc --- /dev/null +++ b/werc/apps/bridge/comments_list.tpl @@ -0,0 +1,13 @@ +
+

Comments

+ +% for(c in `{ls $comments_dir/}) { +% if(test -s $c/body) { +
+
By: %(`{cat $c/user}%) (%(`{cat $c/posted}%)) +
+% cat $c/body | escape_html | sed 's,$,
,' +
+% } +% } + diff --git a/werc/apps/bridge/foot.tpl b/werc/apps/bridge/foot.tpl new file mode 100755 index 0000000..0dad21d --- /dev/null +++ b/werc/apps/bridge/foot.tpl @@ -0,0 +1,37 @@ +
+ +% notices_handler +
+ +
+ + +% if(~ $#logged_user 0) { +% if(~ $#allow_new_user_comments 1) { + + + + + +
+ Enter your desired user name/password and after your comment has been reviewed by an admin it will be posted and your account will be enabled. If you are already registered please login before posting. +
+% } +% if not if(~ $#bridge_anon_comments 1) { + +% } +% } +
diff --git a/werc/apps/dirdir/app.rc b/werc/apps/dirdir/app.rc new file mode 100755 index 0000000..1aa9cbd --- /dev/null +++ b/werc/apps/dirdir/app.rc @@ -0,0 +1,40 @@ +fn conf_enable_wiki { + enable_wiki=yes + wiki_editors_groups=$* + conf_enable_app dirdir +} + +fn dirdir_init { + if(! ~ $#enable_wiki 0 && check_user $wiki_editors_groups) { + lp=$local_path + # werc.rc doesn't append /index when $local_path doesn't exist + # maybe it should, but for now we can fix it up here. + if(~ $lp */) + lp=$lp^'index' + dirdir_file=$lp.md + dirdir_dir=$dirdir_file^'_werc/dirdir/' + + if(~ 1 $#post_arg_dirdir_edit $#post_arg_dirdir_preview) + handler_body_main=(tpl_handler `{get_lib_file dirdir/edit.tpl apps/dirdir/edit.tpl}) + + if not if(! ~ '' $"post_arg_dirdir_save $"post_arg_edit_text) + save_page + + if not if(~ $"handler_body_main '' || {~ $REQUEST_METHOD GET && test -f $local_path.md}) + ll_add handlers_bar_left tpl_handler apps/dirdir/sidebar_controls.tpl + } +} + +fn save_page { + dirdir_verdir=$dirdir_dir/^`{date -n}^/ + mkdir -p $dirdir_verdir + umask 002 + + # XXX Use a tmp file and mv(1) to ensure updates are atomic? + echo $logged_user > $dirdir_verdir/author + echo $post_arg_edit_text > $dirdir_verdir/data + echo $post_arg_edit_text > $dirdir_file + + post_redirect $base_url^$req_path + #notify_notes='Saved '$"req_path'!' +} diff --git a/werc/apps/dirdir/edit.tpl b/werc/apps/dirdir/edit.tpl new file mode 100755 index 0000000..1a5b206 --- /dev/null +++ b/werc/apps/dirdir/edit.tpl @@ -0,0 +1,25 @@ +
+

Editing: %($req_path%)

+
+
+ +
+ + + DirDir documents are written using Markdown syntax. +
+
+ +% if(! ~ $"post_arg_dirdir_preview '') { +

Preview:

+
+% echo $post_arg_edit_text | $formatter +
+% } diff --git a/werc/apps/dirdir/sidebar_controls.tpl b/werc/apps/dirdir/sidebar_controls.tpl new file mode 100755 index 0000000..a897fc1 --- /dev/null +++ b/werc/apps/dirdir/sidebar_controls.tpl @@ -0,0 +1,3 @@ +
+ +
diff --git a/werc/apps/duckduckgo/HOWTO b/werc/apps/duckduckgo/HOWTO new file mode 100644 index 0000000..8bb952c --- /dev/null +++ b/werc/apps/duckduckgo/HOWTO @@ -0,0 +1,20 @@ +The default path for site search is /_search/. Assuming you want to keep +that default, you could enable site search like so: + + +mkdir -p /www/werc/sites/MYSITE/_search/_werc/ +echo 'conf_enable_duckduckgo' > /www/werc/sites/MYSITE/_search/_werc/config +mkdir -p /www/werc/sites/MYSITE/_werc/lib/ +cp /www/werc/apps/duckduckgo/footer.inc.sample /www/werc/sites/MYSITE/_werc/lib/footer.inc + +Searches will POST to /_search/ and from there get redirected to Duck Duck +Go with a site:$SERVER_NAME prefix. To have the search path URL be some- +thing different, you'll have to edit line 23 of app.rc to point to the new +path. + +TODO: +* Make it automatically work no matter which directory the app is enabled in. +* OR make the search path a configuration option. +* Provide a template for non-footer deployment +* Enable the search path itself to serve a search form to GET requests + diff --git a/werc/apps/duckduckgo/app.rc b/werc/apps/duckduckgo/app.rc new file mode 100755 index 0000000..72dd0ec --- /dev/null +++ b/werc/apps/duckduckgo/app.rc @@ -0,0 +1,30 @@ +fn conf_enable_duckduckgo { + enable_duckduckgo=yes + conf_enable_app duckduckgo + pageTitle='Site Search' +} + + +fn duckduckgo_init { + get_post_args q + if (! ~ $#q 0) { + redirect_string = 'https://duckduckgo.com/?q=site:'$SERVER_NAME^'+'^$"q + http_redirect $redirect_string '302 Found' + } + if not { + handler_body_main='duckduckgo_body' + } +} + +fn duckduckgo_body { + echo ' +

Site search

+

using DuckDuckGo

+
+ + + +
' + +} + diff --git a/werc/apps/duckduckgo/footer.inc.sample b/werc/apps/duckduckgo/footer.inc.sample new file mode 100644 index 0000000..4dd671d --- /dev/null +++ b/werc/apps/duckduckgo/footer.inc.sample @@ -0,0 +1,3 @@ + + +
diff --git a/werc/apps/hello/app.rc b/werc/apps/hello/app.rc new file mode 100755 index 0000000..e6faaa8 --- /dev/null +++ b/werc/apps/hello/app.rc @@ -0,0 +1,10 @@ +fn hello_init { + if(~ $req_path /hello) { + handler_body_main='hello_body' + pageTitle='Hi title!' + } +} + +fn hello_body { + echo 'Hello world!' +} diff --git a/werc/apps/paste/app.rc b/werc/apps/paste/app.rc new file mode 100755 index 0000000..af0c76d --- /dev/null +++ b/werc/apps/paste/app.rc @@ -0,0 +1,45 @@ +fn conf_enable_wercpaste { + paste_url=$conf_wd + if (~ $#paste_dir 0) { paste_dir=`{pwd} } + conf_enable_app wercpaste +} + +fn wercpaste_init { + if (~ $REQUEST_METHOD POST && ~ $post_arg_url url && ~ $req_path $paste_url ) { # incoming paste + now=`{ date -n } + cksum=`{ echo $"post_arg_paste | sum | awk '{ print $1 }' } + if (~ $cksum '1715a8eb' ) { # empty paste; discard + post_redirect $base_url^$paste_url + } + if not { # save and redirect + # TODO: stop using echo + # env var size limit is 16kb, this thing dies with larger input. + echo $"post_arg_paste > $paste_dir^/^$now^.^$cksum + # uncomment the following line to redirect to the pasted file + #post_redirect $base_url^$paste_url^$now^.^$cksum + # uncomment the following line instead to just return the url + echo 'Content-type: text/plain'; echo ''; exec echo $base_url^$paste_url^$now^.^$cksum + } + } + if not { # show a paste if there is one + if (test -r $werc_root/$local_path && ~ $QUERY_STRING raw ) { + echo 'Content-type: text/plain'; echo ''; exec cat $werc_root/$local_path + } + } + +# drop a textbox + if (~ $REQUEST_METHOD GET ) { handler_body_main='begforpaste' } + +} + +fn begforpaste { + echo '
+

pasted data is not publically indexed

+
+
+

+ (do not change) +
+
+ ' +} diff --git a/werc/apps/wman/app.rc b/werc/apps/wman/app.rc new file mode 100755 index 0000000..8f0a150 --- /dev/null +++ b/werc/apps/wman/app.rc @@ -0,0 +1,89 @@ +fn conf_enable_wman { + wman_tmac=an + wman_base_uri=$conf_wd + wman_man_path=$* + if(~ $#wman_man_path 0) + wman_man_path=$wman_base_uri + conf_enable_app wman +} + +wman_junk_filter='/(\/(INDEX|\.cvsignore|_.*)|\.9p|\.html)$/d; s!/man([0-9]+/[^/]+)$!/\1!; ' +fn wman_ls_pages { + ls $* \ + | sed $dirfilter^$wman_junk_filter^' s/\.([0-9]|9p)$//; s!/0intro$!/intro!' \ + | sort -u +} +fn wman_init { + ifs=$ifs^'/' { p=`{echo $req_path | sed 's!^'^$wman_base_uri^'!!'} } + wman_cat=$p(1) + wman_page=$p(2) + if(~ $#wman_unix_mode 1) { + wman_cp='man' + wman_pe=.^$"wman_cat + } + + if(! ~ $"wman_cat '') { + wman_cat_path=$wman_man_path^/^$"wman_cp^$p(1) + if(! ~ $"wman_page '') { + wman_page_file=$wman_page^$"wman_pe + # Hack to handle 0intro files. + if(~ $wman_page intro && test -f $wman_cat_path^/0^$"wman_page_file) + wman_page_file=0^$"wman_page_file + wman_page_file=$wman_cat_path^/^$"wman_page_file + x=`{echo $"req_path|sed 's%.*/([^/]+)/'$"wman_cat'/'^$"wman_page^'%\1%; s%_% %g'} + pageTitle=$wman_page' page from Section '$wman_cat' of the '^$"x' manual' + } + } + + wman_cat_list=`{ls -F $wman_man_path/*/ \ + | sed -e $wman_junk_filter -e 's!.*/([^/]+)/[^/]+$!\1!; /[0-9]+/!d' \ + | sort -un} + + synth_paths=($wman_base_uri$wman_cat_list'/') + + if(~ $req_path $wman_base_uri && ~ $"handler_body_main '') + handler_body_main=(tpl_handler apps/wman/section_list.tpl) + if not if(~ $req_path $wman_base_uri^*) { + #^*/[a-z0-9]*[a-z]* $wman_base_uri^*/*[a-z]*[a-z0-9] $wman_base_uri^*/[a-z]) + if(echo $req_path | grep -s '^'^$wman_base_uri^'/*[0-9]+/[0-9a-z\-\+\.]+$') + if(test -f $wman_page_file) # Check for 404 + handler_body_main=(tpl_handler apps/wman/man_page.tpl) + if not if(~ $req_path $wman_base_uri^*/) + handler_body_main=(tpl_handler apps/wman/page_list.tpl) + if not if(~ $p(2) [A-Z]* [0-9][A-Z]*) # Correct badly capitalized links + perm_redirect $wman_base_uri^$p(1)^/^`{echo $p(2) |tr 'A-Z' 'a-z'} + } + + # Search + ll_add handlers_body_head tpl_handler apps/wman/search.tpl + if(! ~ $"post_arg_wman_search '') { + s=`{echo $post_arg_wman_search | sed 's/[^a-zA-Z0-9\-\.]+//g; s/\.+/./g; 1q'} + ifs='' { wman_search_results=`{wman_ls_pages $wman_man_path/*/*^$"s^*} } + if(! ~ $"post_arg_go '' && ~ `{echo -n $wman_search_results|wc -l} 1) + post_redirect $wman_base_uri^`{echo $wman_search_results|awk -F/ '{print $(NF-1)"/"$NF}'} + } + +} + +fn wman_get_section_desc { + cat $wman_man_path/^$"wman_cp^$1/0intro* >[2]/dev/null| sed '1,2d; s!intro \\- [Ii]ntroduction to !!; 3q;' +} + +fn wman_page_gen { + #troff -manhtml $1| troff2html -t 'Plan 9 from User Space' + troff -N -m$wman_tmac $1 | wman_out_filter +} + +fn wman_out_filter { + wman_default_out_filter +} + +fn wman_default_out_filter { + # col -x syntax is the same for UNIX and Plan 9. + escape_html \ + | sed 's!([\.\-a-zA-Z0-9]+)\(('^`{echo $wman_cat_list|tr ' ' '|'}^')\)!&!g' \ + | awk '/^$/ {if(n != 1) print; n=1; next} /./ {n=0; print}' \ + | col -x +} + + diff --git a/werc/apps/wman/man_page.tpl b/werc/apps/wman/man_page.tpl new file mode 100755 index 0000000..945e23a --- /dev/null +++ b/werc/apps/wman/man_page.tpl @@ -0,0 +1,3 @@ +
+% wman_page_gen $wman_page_file
+
diff --git a/werc/apps/wman/page_list.tpl b/werc/apps/wman/page_list.tpl new file mode 100755 index 0000000..b98600d --- /dev/null +++ b/werc/apps/wman/page_list.tpl @@ -0,0 +1,11 @@ +% d=`{wman_get_section_desc $wman_cat} +

Manual pages - Section %($wman_cat%): %($"d%)

+ +
    +%{ +wman_ls_pages $wman_cat_path \ + | awk -F/ '{ print "
  • "$(NF)"
  • " } + NR%20 == 0 { print "
    " }' +%} +
+ diff --git a/werc/apps/wman/search.tpl b/werc/apps/wman/search.tpl new file mode 100755 index 0000000..a6c59e4 --- /dev/null +++ b/werc/apps/wman/search.tpl @@ -0,0 +1,20 @@ +
+
+ + + + +% if(! ~ $"post_arg_wman_search '') { +% if(~ $"wman_search_results '') { + No matches found for '%($post_arg_wman_search%)'. +% } +% if not { +
    +% echo $wman_search_results|awk -F/ '$(NF-1) ~ "^[0-9]+$" {printf "
  • %s(%s)
  • ", $(NF-1),$NF, $NF, $(NF-1)}' +
+% } +% } + +
+
+ diff --git a/werc/apps/wman/section_list.tpl b/werc/apps/wman/section_list.tpl new file mode 100755 index 0000000..299d613 --- /dev/null +++ b/werc/apps/wman/section_list.tpl @@ -0,0 +1,11 @@ +

Manual Sections

+ +
    +% for(c in $wman_cat_list) { +
  • Section: %($c%) +% wman_get_section_desc $c +% if(~ $status '' '|') +% echo '(intro)' +
  • +% } +
diff --git a/werc/apps/xibit/README b/werc/apps/xibit/README new file mode 100644 index 0000000..c4170b7 --- /dev/null +++ b/werc/apps/xibit/README @@ -0,0 +1,45 @@ +Xibit (tibix) - the image gallery generator for werc +Xibit can: + - generate thumbnails from almost any picture format + - generate preview images with captions + - display them (rather brokenly for now) + + + Dependencies: + - Plan9port + - Imagemagick + - werc + + + To make it work: + 1, clone the git repo at git://home.9souldier.org/xibit into $werc_root/apps + 2, pick a directory to serve the gallery from + 3, create an _werc and _werc/xibit directory in there, the xibit directory needs to be writable by the webserver to generate the thumbnails (at one point i'll probably make a cronjob, and then this will be optional) + 4, create an _werc/config file (readable by the webserver), that contains the options for xibit + 5, add xibit to the enabled_apps in initrc.local (or the local per-directory config file) +That should get you going. + +to use captions just create a directory in GALLERY/_werc/xibit called captions, make it readable by the weberver and add the captions as files, using the following naming convention: + image.imageextension.md + the caption handler accepts markdown formatting + +to enable comments add the comments handler (bridge) to the enabled apps, it'll (should) automatically work with xibit + +Config options: + - fmts: + file extensions recognised + ex. fmts=(jpg gif png svg) + - thumbsize: + size of thumbnails to generate, accepts + ex. thumbsize='140x' + - previewsize: + size of the previews to generate + ex. previewsize='x460' + +check_user: + Enforce authentication + This has been ripped out of the xibit code, if you want to enable perms enforcing, you should add the following to your config: +if ( ! check_user) { #if fyou want to enforce per-group permissions, do "if( ! check_user $group) {" + enabled_apps=() #maybe you want to leave some apps on, i just do this on a per-directory besis + handler_body_main=(echo 'please log in') +} \ No newline at end of file diff --git a/werc/apps/xibit/TODO b/werc/apps/xibit/TODO new file mode 100644 index 0000000..bc69153 --- /dev/null +++ b/werc/apps/xibit/TODO @@ -0,0 +1,5 @@ +features: + - details list index - filenames with creation, etc.. + - if format is image format but not one recognised by browsers, convert it to png for preview and thumbnail viewing + +nice css @ http://www.area17.com/03_work/nove/photography/ and http://www.sergiojuncos.com/usa2008/large-2.html and http://jmcpherson.org/photoblog/index.php \ No newline at end of file diff --git a/werc/apps/xibit/app.rc b/werc/apps/xibit/app.rc new file mode 100755 index 0000000..190418d --- /dev/null +++ b/werc/apps/xibit/app.rc @@ -0,0 +1,91 @@ +#xibit is an app that generates image galeries for werc. +#the license the mit license, see the license file in the distribution's root directory +#until the time i change my mind +#comments and suggestions can come to http://redmine.9souldier.org/projects/xibit0/issues/new or johnny@9souldier.org + +fn conf_enable_xibit { + xibit_uri=$conf_wd + conf_enable_app xibit +} + +fn xibit_init { + xibit_root=$sitedir$"xibit_uri +#SOMEONE PLEASE FIXME if(! ~ $#xibit_uri 0 && test '( -d '^$"xibit_root^'/_werc/xibit ) -a ( -w '^$"xibit_root^'/_werc/xibit )' && convert -help > /dev/null) { + if(! ~ $#xibit_uri 0 && test -d $"xibit_root/_werc/xibit && test -w $"xibit_root/_werc/xibit && which convert > /dev/null) { + xibitdir=$xibit_root^/_werc/xibit + xibit_uri_file=`{echo $req_path |sed 's,^.*/([^/]+)$,\1,g'} + mkdir -p $"xibitdir/previews + mkdir -p $"xibitdir/thumbs + extraHeaders=($extraHeaders '') + if( ~ $"req_path */index */) + handler_body_main=xibit_thumb_handler + if not { + xibit_img=`{echo $req_path |sed 's,^.*/([^/]+)(\.[^\.]+)?$,\1,g'} + for(pic in $xibit_img.^$fmts){ + if(test -f $xibit_root/^$pic) + handler_body_main=xibit_img_handler + } + if ( ~ $#handler_body_main 0 ) + status='xibit cant to anything here' + } + } +} + +fn xibit_thumb_handler { + cd $xibit_root + xibitdir=_werc/xibit + rm $"xibitdir/dirstat.md5.tmp > /dev/null >[2] /dev/null + if( ! ~ `{ls -l |md5sum |tee $xibitdir/dirstat.md5.tmp} `{cat $xibitdir/dirstat.md5}) { + mv $xibitdir/dirstat.md5.tmp $xibitdir/dirstat.md5 + for(pic in `{ls *.^$fmts >[2] /dev/null}) { + if( ! test -f $"xibitdir/thumbs/^$"pic ) + convert $pic -resize $thumbsize $xibitdir/thumbs/^$pic + if( ! test -f $"xibitdir/previews/^$"pic ) + convert $pic -resize $previewsize $xibitdir/previews/^$pic + + xibit_pics=($xibit_pics $pic) + } + } + if not + for(pic in `{ls *.^$fmts >[2] /dev/null}) + xibit_pics=($xibit_pics $pic) + rm $xibitdir/dirstat.md5.tmp > /dev/null >[2] /dev/null + cd $werc_root + + if( ! ~ $req_path */details ) + template apps/xibit/thumbs.tpl + if not + template apps/xibit/details.tpl +} + + +fn xibit_img_handler { + cd $xibit_root + for(file in $xibit_uri_file.^$fmts) { + if( test -f $file) { + xibit_img=`{echo $file |sed 's,^.*/([^/]+),\1,g'} + xibit_preview=_werc/xibit/previews/^$xibit_img + if (test -r _werc/xibit/captions/^$xibit_img^.md) + xibit_caption_file=$xibitdir^/captions/^$xibit_img^.md + xibit_nextpic=`{next_pic $xibit_img} + xibit_prevpic=`{prev_pic $xibit_img} + dprint $xibit_nextpic $xibit_prevpic + cd $werc_root + } + } + cd $werc_root + xibit_thumb_handler +} + +fn prev_pic { + findre='/^'^$1^'$/!h; /^'^$1^'$/!d; /^'^$1^'$/g;' + if( ! ls -F |sed 1q |grep -s $1 ) + ls -F |grep -v '_werc' | sed 's,\*$,,g; /\$/d; s,'',,g' | sed $"findre^'; s,\.[^\.]+$,,' +} + +fn next_pic { + findre='/^'^$1^'$/!d; /^'^$1^'/n; p' + if( ! ls -F |tail -1 |grep -s $1 ) + ls -F |grep -v '_werc' | sed 's,\*$,,g; /\/$/d; s,'',,g' | sed -n $"findre |sed 's,\.[^\.]+$,,' +} + diff --git a/werc/apps/xibit/details.tpl b/werc/apps/xibit/details.tpl new file mode 100644 index 0000000..df08451 --- /dev/null +++ b/werc/apps/xibit/details.tpl @@ -0,0 +1,14 @@ +
+
    +% for (pic in $xibit_pics) { +
  • + + + +% identify $xibit_urlroot/^$pic |awk '{print $4}' +
  • +% } +
+
diff --git a/werc/apps/xibit/image.tpl b/werc/apps/xibit/image.tpl new file mode 100644 index 0000000..0289fa1 --- /dev/null +++ b/werc/apps/xibit/image.tpl @@ -0,0 +1,21 @@ +
+% if ( ! ~ $#xibit_prevpic 0) { + Previous +% } +% if ( ! ~ $#xibit_nextpic 0 && ! ~ $#xibit_prevpic 0 ) { +/ +% } +% if ( ! ~ $#xibit_nextpic 0) { +Next +% } +
+ + + +
+% if ( ! ~ $#xibit_caption_file 0) { +
+% md_handler $xibit_caption_file +
+% } +
diff --git a/werc/apps/xibit/license b/werc/apps/xibit/license new file mode 100644 index 0000000..7730ccc --- /dev/null +++ b/werc/apps/xibit/license @@ -0,0 +1,19 @@ +Copyright (c) 2009 John Soros + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/werc/apps/xibit/thumbs.tpl b/werc/apps/xibit/thumbs.tpl new file mode 100644 index 0000000..2b81d69 --- /dev/null +++ b/werc/apps/xibit/thumbs.tpl @@ -0,0 +1,11 @@ +% for (pic in $xibit_pics){ +% picnoext=`{echo $pic |sed 's,(.*)\..+$,\1,g'} +% if(! ~ $pic $xibit_img) { + + + +% } +% if not { +% template apps/xibit/image.tpl +% } +% } \ No newline at end of file diff --git a/werc/apps/xibit/xibit.css b/werc/apps/xibit/xibit.css new file mode 100644 index 0000000..b83d8a9 --- /dev/null +++ b/werc/apps/xibit/xibit.css @@ -0,0 +1,17 @@ +.thumbs-index { + float: right; + clear: none; + white-space: nowrap; +} +.thumb { + clear: none; + width: auto; + height: auto; + padding: 5px; + border: 2px; + display: inline; +} +#main-img { + text-align: center; + clear: none; +} \ No newline at end of file diff --git a/werc/bin/aux/addwuser.rc b/werc/bin/aux/addwuser.rc new file mode 100755 index 0000000..9364d39 --- /dev/null +++ b/werc/bin/aux/addwuser.rc @@ -0,0 +1,33 @@ +#!/bin/rc + +if(! ~ $#werc_root 0) + cd $werc_root + +fn usage { + if(! ~ $#* 0) + echo $0: $* >[1=2] + echo 'Usage:' $0 'user_name user_password [groups ...]' >[1=2] + exit usage +} + +if(! test -d etc/users/) + usage 'Run for root of werc installation or set $werc_root' + +user_name=$1 +shift +user_pass=$1 +shift +user_groups=$* + +if(~ $"user_name '' || ~ $"user_pass '') + usage + +mkdir etc/users/$user_name +echo $user_pass > etc/users/$user_name/password + +if(! ~ $#user_groups 0) + for(g in $user_groups) { + mkdir -p etc/users/$g + echo $user_name >> etc/users/$g/members + } + diff --git a/werc/bin/aux/bpst.rc b/werc/bin/aux/bpst.rc new file mode 100755 index 0000000..54d31c2 --- /dev/null +++ b/werc/bin/aux/bpst.rc @@ -0,0 +1,64 @@ +#!/bin/rc + +path=( $PLAN9/bin $path ) +base=. + +if(~ $#user 0) + user=`{whoami} + +file=(); title=(); +bloguser=$user +while(! ~ $#* 0) { + switch($1) { + case -u + base=/gsoc/www/people/$user/blog/ + case -b + shift + base=$1 + case -f + shift + file=$1 + } + shift +} + +if(~ $"EDITOR '') + EDITOR=vi + +if(~ $#file 0 || ! test -f $file) { + file=/tmp/blogtmp.$pid + rm $file >[2]/dev/null + touch $file +} + +$EDITOR $file +aspell -c $file +rm $file.bak >[2]/dev/null + +fn mkbpost { + umask 002 # Let group write + bptext=$1 + if(! ~ $#2 0) + bpid=`{echo -n '-'^$"bpid | sed 's/'$forbidden_uri_chars'+/_/g; 1q'} + d=`{/bin/date +%F|sed 's,-,/,g'} + + ddir=$blagh_root^$d^'/' + n=`{ls $ddir >[2]/dev/null |wc -l} + + mkdir -p $ddir/$"n^$"bpid/ + { + # TODO: Enable metadata + #echo '* Posted:' `{date} + #if(! ~ $#logged_user 0) + # echo '* Author: '$logged_user + cat $bptext + }> $ddir/$"n^$"bpid/index.md +} + +forbidden_uri_chars='[^a-zA-Z0-9_+\-\/\.]' +blagh_root=$base + +if(test -s $file) + mkbpost $file +if not + echo Empty file! diff --git a/werc/bin/aux/gensitemaptxt.rc b/werc/bin/aux/gensitemaptxt.rc new file mode 100755 index 0000000..a1b349d --- /dev/null +++ b/werc/bin/aux/gensitemaptxt.rc @@ -0,0 +1,14 @@ +#!/bin/rc +# DEPRECATED: sitemap.tpl now generates and updates a sitemap.txt when requested, and is also more smart than this simplistic script. + +for(d in sites/*/) { +echo $d +9 du -a $d | awk '/\.(md|html)$/ { print $2 }; {}' | 9 sed -e 's/\.(md|html)$//' -e 's,/index$,/,' -e 's,^sites/,http://,' > $d/sitemap.txt + +if(! test -f $d/robots.txt) { + echo generating missing robots.txt for $d + echo $d|sed 's,sites/,Sitemap: http://,; s/$/sitemap.txt/;' > $d/robots.txt + cat $d/robots.txt +} + +} diff --git a/werc/bin/aux/runtsts.rc b/werc/bin/aux/runtsts.rc new file mode 100755 index 0000000..b5b1df7 --- /dev/null +++ b/werc/bin/aux/runtsts.rc @@ -0,0 +1,16 @@ +#!/bin/rc + +tstdom='http://test.cat-v.org' + +cd sites/tst.cat-v.org + +tstfiles=`{du -a |awk '/\.tst$/ { print $2 }; {} ' | sed 's/^\.//; s/\.tst$//'} + +for(f in $tstfiles) { + ifs=' +' { tsts=`{cat ./$f.tst} } + + for(t in $tsts) { + echo tst $t + } +} diff --git a/werc/bin/cgilib.rc b/werc/bin/cgilib.rc new file mode 100755 index 0000000..4516bf9 --- /dev/null +++ b/werc/bin/cgilib.rc @@ -0,0 +1,236 @@ +# Useful CGI stuff + +fn dprint { echo $* >[1=2] } +fn dprintv { { for(v in $*) { echo -n $v^'#'^$#$v^'=' $$v '; ' }; echo } >[1=2] } +fn echo {if(! ~ $1 -n || ! ~ $2 '') /bin/echo $*} +fn escape_html { sed 's/&/\&/g; s//\>/g' $* } + +fn http_redirect { + if(~ $1 http://* https://*) + t=$1 + if not if(~ $1 /*) + t=$"base_url^$1 + if not + t=$"base_url^$"req_path^$1 + exec /bin/echo 'Status: '^$2^' +Location: '^$t^' + +' + exit +} +fn perm_redirect { http_redirect $1 '301 Moved Permanantly' } +fn post_redirect { http_redirect $1 '303 See Other' } + + +# Note: should check if content type is application/x-www-form-urlencoded? +# Should compare with http://www.shelldorado.com/scripts/cmds/urlgetopt.txt +fn load_post_args { + if(~ $REQUEST_METHOD POST && ~ $#post_args 0) { + ifs='& +' for(pair in `{cat}) { + ifs='=' { pair=`{echo -n $pair} } + n='post_arg_'^`{echo $pair(1)|nurldecode|tr -cd 'a-zA-Z0-9_'} + post_args=( $post_args $n ) + ifs=() { $n=`{echo -n $pair(2)|nurldecode|tr -d ' '} } + } + pair=() + } + if not + status='No POST or post args already loaded' +} +# Status is () if at least one arg is found. DEPRECATED: access vars directly. +fn get_post_args { + load_post_args + _status='No post arg matches' + for(n in $*) { + v=post_arg_$n + if(! ~ $#$v 0) { + $n=$$v + _status=() + } + } + status=$_status +} + +# This seems slightly improve performance, but might depend on httpd buffering behavior. +fn awk_buffer { + awk '{ + buf = buf $0"\n" + if(length(buf) > 1400) { + printf "%s", buf + buf = "" + } + } + END { printf "%s", buf }' +} + +fn nurldecode { urlencode -d || url_decode} # GROSS + +fn url_decode { +awk ' +BEGIN { + hextab ["0"] = 0; hextab ["8"] = 8; + hextab ["1"] = 1; hextab ["9"] = 9; + hextab ["2"] = 2; hextab ["A"] = hextab ["a"] = 10 + hextab ["3"] = 3; hextab ["B"] = hextab ["b"] = 11; + hextab ["4"] = 4; hextab ["C"] = hextab ["c"] = 12; + hextab ["5"] = 5; hextab ["D"] = hextab ["d"] = 13; + hextab ["6"] = 6; hextab ["E"] = hextab ["e"] = 14; + hextab ["7"] = 7; hextab ["F"] = hextab ["f"] = 15; +} +{ + decoded = "" + i = 1 + len = length ($0) + while ( i <= len ) { + c = substr ($0, i, 1) + if ( c == "%" ) { + if ( i+2 <= len ) { + c1 = substr ($0, i+1, 1) + c2 = substr ($0, i+2, 1) + if ( hextab [c1] == "" || hextab [c2] == "" ) { + print "WARNING: invalid hex encoding: %" c1 c2 | "cat >&2" + } else { + code = 0 + hextab [c1] * 16 + hextab [c2] + 0 + c = sprintf ("%c", code) + i = i + 2 + } + } else { + print "WARNING: invalid % encoding: " substr ($0, i, len - i) + } + } else if ( c == "+" ) { + c = " " + } + decoded = decoded c + ++i + } + printf "%s", decoded +} +' +} + +fn nurlencode { urlencode || url_encode } # GROSS + +fn url_encode { + awk ' + BEGIN { + # We assume an awk implementation that is just plain dumb. + # We will convert an character to its ASCII value with the + # table ord[], and produce two-digit hexadecimal output + # without the printf("%02X") feature. + + EOL = "%0A" # "end of line" string (encoded) + split ("1 2 3 4 5 6 7 8 9 A B C D E F", hextab, " ") + hextab [0] = 0 + for ( i=1; i<=255; ++i ) ord [ sprintf ("%c", i) "" ] = i + 0 + if ("'^$"EncodeEOL^'" == "yes") EncodeEOL = 1; else EncodeEOL = 0 + } + { + encoded = "" + for ( i=1; i<=length ($0); ++i ) { + c = substr ($0, i, 1) + if ( c ~ /[a-zA-Z0-9.-]/ ) { + encoded = encoded c # safe character + } else if ( c == " " ) { + encoded = encoded "+" # special handling + } else { + # unsafe character, encode it as a two-digit hex-number + lo = ord [c] % 16 + hi = int (ord [c] / 16); + encoded = encoded "%" hextab [hi] hextab [lo] + } + } + if ( EncodeEOL ) { + printf ("%s", encoded EOL) + } else { + print encoded + } + } + END { + #if ( EncodeEOL ) print "" + } +' $* +} + +# Cookies +fn set_cookie { + # TODO: should check input values more carefully + name=$1 + val=$2 + extraHttpHeaders=( $extraHttpHeaders 'Set-cookie: '^$"name^'='^$"val^'; path=/;' ) +} +fn get_cookie { + ifs=';' { co=`{echo $HTTP_COOKIE} } + + # XXX: we might be adding a trailing new line? + # The ' ?' is needed to deal with '; ' inter-cookie delimiter + { for(c in $co) echo $c } | sed -n 's/^ ?'$1'=//p' +} + + +fn static_file { + echo -n 'Content-Type: ' + select_mime $1 + echo + exec cat $1 +} + +fn select_mime { + m='text/plain' + if(~ $1 *.css) + m='text/css' + if not if(~ $1 *.ico) + m='image/x-icon' + if not if(~ $1 *.png) + m='image/png' + if not if(~ $1 *.jpg *.jpeg) + m='image/jpeg' + if not if(~ $1 *.gif) + m='image/gif' + if not if(~ $1 *.pdf) + m='application/pdf' + echo $m +} + +############################################## +# Generic rc programming helpers + +# Manage nested lists +fn ll_add { + _l=$1^_^$#$1 + $_l=$*(2-) + $1=( $$1 $_l ) +} +# Add to the head: dangerous if you shrink list by hand! +fn ll_addh { + _l=$1^_^$#$1 + $_l=$*(2-) + $1=( $_l $$1 ) +} + + +NEW_LINE=' +' + +# crop_text [max_lenght [ellipsis]] +# TODO: Option to crop only at word-delimiters. +fn crop_text { + m=512 + e='...' + if(! ~ $#1 0) + m=$1 + if(! ~ $#2 0) + e=$2 + + awk -v 'max='^$"m -v 'ellipsis='$e ' + { + nc += 1 + length; + if(nc > max) { + print substr($0, 1, nc - max) " " ellipsis + exit + } + print + }' +} + + diff --git a/werc/bin/contrib/fix-rc-scripts b/werc/bin/contrib/fix-rc-scripts new file mode 100755 index 0000000..beb21c5 --- /dev/null +++ b/werc/bin/contrib/fix-rc-scripts @@ -0,0 +1,27 @@ +#!/usr/local/plan9/bin/rc + +# Fix rc shell scripts to find rc without launching env every time. +# Invoke with rc and plan9 versions of grep and ed in $PATH + +# If your system lacks which (e.g. some gnu/linux) +# substitute the full path to rc in this line: +rc=/usr/local/plan9/bin/rc +firstline='#!'$"rc + +if(~ $#* 0) files = * +if not files = $* + +myname = `{basename $0} + +for(file in $files) { + if(test -d $file) $0 $file/* + if not if(~ $file *$myname) {} + if not if(sed 1q $file | grep '^#!/.*[/ ]rc$' > /dev/null) { + { + echo 1c + echo $firstline + echo . + echo wq + } | ed $file > /dev/null + } +} diff --git a/werc/bin/contrib/hgweb.config b/werc/bin/contrib/hgweb.config new file mode 100755 index 0000000..fba802b --- /dev/null +++ b/werc/bin/contrib/hgweb.config @@ -0,0 +1,12 @@ +[web] +style = gitweb +allow_archive = bz2 + +#[paths] +#w9 = /gsoc/hg/w9/ + +[collections] +#allow_archive = bz2 zip +/gsoc/hg = /gsoc/hg/ +#/var/hg = /var/hg/ + diff --git a/werc/bin/contrib/hgwebdir.cgi b/werc/bin/contrib/hgwebdir.cgi new file mode 100755 index 0000000..5fe4b16 --- /dev/null +++ b/werc/bin/contrib/hgwebdir.cgi @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# +# An example CGI script to export multiple hgweb repos, edit as necessary + +# send python tracebacks to the browser if an error occurs: +import cgitb +cgitb.enable() + +# adjust python path if not a system-wide install: +#import sys +#sys.path.insert(0, "/path/to/python/lib") + +# If you'd like to serve pages with UTF-8 instead of your default +# locale charset, you can do so by uncommenting the following lines. +# Note that this will cause your .hgrc files to be interpreted in +# UTF-8 and all your repo files to be displayed using UTF-8. +# +#import os +#os.environ["HGENCODING"] = "UTF-8" + +from mercurial.hgweb.hgwebdir_mod import hgwebdir +from mercurial.hgweb.request import wsgiapplication +import mercurial.hgweb.wsgicgi as wsgicgi + +# The config file looks like this. You can have paths to individual +# repos, collections of repos in a directory tree, or both. +# +# [paths] +# virtual/path = /real/path +# virtual/path = /real/path +# +# [collections] +# /prefix/to/strip/off = /root/of/tree/full/of/repos +# +# collections example: say directory tree /foo contains repos /foo/bar, +# /foo/quux/baz. Give this config section: +# [collections] +# /foo = /foo +# Then repos will list as bar and quux/baz. +# +# Alternatively you can pass a list of ('virtual/path', '/real/path') tuples +# or use a dictionary with entries like 'virtual/path': '/real/path' + +def make_web_app(): + return hgwebdir("hgweb.config") + +wsgicgi.launch(wsgiapplication(make_web_app)) diff --git a/werc/bin/contrib/markdown.pl b/werc/bin/contrib/markdown.pl new file mode 100755 index 0000000..3758a87 --- /dev/null +++ b/werc/bin/contrib/markdown.pl @@ -0,0 +1,1447 @@ +#!/usr/bin/env perl +# +# Markdown -- A text-to-HTML conversion tool for web writers +# +# Copyright (c) 2004 John Gruber +# +# +package Markdown; +require 5.006_000; +use strict; +use warnings; + +use Digest::MD5 qw(md5_hex); +use vars qw($VERSION); +$VERSION = '1.0.1'; +# Tue 14 Dec 2004 + +## Disabled; causes problems under Perl 5.6.1: +# use utf8; +# binmode( STDOUT, ":utf8" ); # c.f.: http://acis.openlib.org/dev/perl-unicode-struggle.html + + +# +# Global default settings: +# +my $g_empty_element_suffix = " />"; # Change to ">" for HTML output +my $g_tab_width = 4; + + +# +# Globals: +# + +# Regex to match balanced [brackets]. See Friedl's +# "Mastering Regular Expressions", 2nd Ed., pp. 328-331. +my $g_nested_brackets; +$g_nested_brackets = qr{ + (?> # Atomic matching + [^\[\]]+ # Anything other than brackets + | + \[ + (??{ $g_nested_brackets }) # Recursive set of nested brackets + \] + )* +}x; + + +# Table of hash values for escaped characters: +my %g_escape_table; +foreach my $char (split //, '\\`*_{}[]()>#+-.!') { + $g_escape_table{$char} = md5_hex($char); +} + + +# Global hashes, used by various utility routines +my %g_urls; +my %g_titles; +my %g_html_blocks; + +# Used to track when we're inside an ordered or unordered list +# (see _ProcessListItems() for details): +my $g_list_level = 0; + + +#### Blosxom plug-in interface ########################################## + +# Set $g_blosxom_use_meta to 1 to use Blosxom's meta plug-in to determine +# which posts Markdown should process, using a "meta-markup: markdown" +# header. If it's set to 0 (the default), Markdown will process all +# entries. +my $g_blosxom_use_meta = 0; + +sub start { 1; } +sub story { + my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_; + + if ( (! $g_blosxom_use_meta) or + (defined($meta::markup) and ($meta::markup =~ /^\s*markdown\s*$/i)) + ){ + $$body_ref = Markdown($$body_ref); + } + 1; +} + + +#### Movable Type plug-in interface ##################################### +eval {require MT}; # Test to see if we're running in MT. +unless ($@) { + require MT; + import MT; + require MT::Template::Context; + import MT::Template::Context; + + eval {require MT::Plugin}; # Test to see if we're running >= MT 3.0. + unless ($@) { + require MT::Plugin; + import MT::Plugin; + my $plugin = new MT::Plugin({ + name => "Markdown", + description => "A plain-text-to-HTML formatting plugin. (Version: $VERSION)", + doc_link => 'http://daringfireball.net/projects/markdown/' + }); + MT->add_plugin( $plugin ); + } + + MT::Template::Context->add_container_tag(MarkdownOptions => sub { + my $ctx = shift; + my $args = shift; + my $builder = $ctx->stash('builder'); + my $tokens = $ctx->stash('tokens'); + + if (defined ($args->{'output'}) ) { + $ctx->stash('markdown_output', lc $args->{'output'}); + } + + defined (my $str = $builder->build($ctx, $tokens) ) + or return $ctx->error($builder->errstr); + $str; # return value + }); + + MT->add_text_filter('markdown' => { + label => 'Markdown', + docs => 'http://daringfireball.net/projects/markdown/', + on_format => sub { + my $text = shift; + my $ctx = shift; + my $raw = 0; + if (defined $ctx) { + my $output = $ctx->stash('markdown_output'); + if (defined $output && $output =~ m/^html/i) { + $g_empty_element_suffix = ">"; + $ctx->stash('markdown_output', ''); + } + elsif (defined $output && $output eq 'raw') { + $raw = 1; + $ctx->stash('markdown_output', ''); + } + else { + $raw = 0; + $g_empty_element_suffix = " />"; + } + } + $text = $raw ? $text : Markdown($text); + $text; + }, + }); + + # If SmartyPants is loaded, add a combo Markdown/SmartyPants text filter: + my $smartypants; + + { + no warnings "once"; + $smartypants = $MT::Template::Context::Global_filters{'smarty_pants'}; + } + + if ($smartypants) { + MT->add_text_filter('markdown_with_smartypants' => { + label => 'Markdown With SmartyPants', + docs => 'http://daringfireball.net/projects/markdown/', + on_format => sub { + my $text = shift; + my $ctx = shift; + if (defined $ctx) { + my $output = $ctx->stash('markdown_output'); + if (defined $output && $output eq 'html') { + $g_empty_element_suffix = ">"; + } + else { + $g_empty_element_suffix = " />"; + } + } + $text = Markdown($text); + $text = $smartypants->($text, '1'); + }, + }); + } +} +else { +#### BBEdit/command-line text filter interface ########################## +# Needs to be hidden from MT (and Blosxom when running in static mode). + + # We're only using $blosxom::version once; tell Perl not to warn us: + no warnings 'once'; + unless ( defined($blosxom::version) ) { + use warnings; + + #### Check for command-line switches: ################# + my %cli_opts; + use Getopt::Long; + Getopt::Long::Configure('pass_through'); + GetOptions(\%cli_opts, + 'version', + 'shortversion', + 'html4tags', + ); + if ($cli_opts{'version'}) { # Version info + print "\nThis is Markdown, version $VERSION.\n"; + print "Copyright 2004 John Gruber\n"; + print "http://daringfireball.net/projects/markdown/\n\n"; + exit 0; + } + if ($cli_opts{'shortversion'}) { # Just the version number string. + print $VERSION; + exit 0; + } + if ($cli_opts{'html4tags'}) { # Use HTML tag style instead of XHTML + $g_empty_element_suffix = ">"; + } + + + #### Process incoming text: ########################### + my $text; + { + local $/; # Slurp the whole file + $text = <>; + } + print Markdown($text); + } +} + + + +sub Markdown { +# +# Main function. The order in which other subs are called here is +# essential. Link and image substitutions need to happen before +# _EscapeSpecialChars(), so that any *'s or _'s in the +# and tags get encoded. +# + my $text = shift; + + # Clear the global hashes. If we don't clear these, you get conflicts + # from other articles when generating a page which contains more than + # one article (e.g. an index page that shows the N most recent + # articles): + %g_urls = (); + %g_titles = (); + %g_html_blocks = (); + + + # Standardize line endings: + $text =~ s{\r\n}{\n}g; # DOS to Unix + $text =~ s{\r}{\n}g; # Mac to Unix + + # Make sure $text ends with a couple of newlines: + $text .= "\n\n"; + + # Convert all tabs to spaces. + $text = _Detab($text); + + # Strip any lines consisting only of spaces and tabs. + # This makes subsequent regexen easier to write, because we can + # match consecutive blank lines with /\n+/ instead of something + # contorted like /[ \t]*\n+/ . + $text =~ s/^[ \t]+$//mg; + + # Turn block-level HTML blocks into hash entries + $text = _HashHTMLBlocks($text); + + # Strip link definitions, store in hashes. + $text = _StripLinkDefinitions($text); + + $text = _RunBlockGamut($text); + + $text = _UnescapeSpecialChars($text); + + return $text . "\n"; +} + + +sub _StripLinkDefinitions { +# +# Strips link definitions from text, stores the URLs and titles in +# hash references. +# + my $text = shift; + my $less_than_tab = $g_tab_width - 1; + + # Link defs are in the form: ^[id]: url "optional title" + while ($text =~ s{ + ^[ ]{0,$less_than_tab}\[(.+)\]: # id = $1 + [ \t]* + \n? # maybe *one* newline + [ \t]* + ? # url = $2 + [ \t]* + \n? # maybe one newline + [ \t]* + (?: + (?<=\s) # lookbehind for whitespace + ["(] + (.+?) # title = $3 + [")] + [ \t]* + )? # title is optional + (?:\n+|\Z) + } + {}mx) { + $g_urls{lc $1} = _EncodeAmpsAndAngles( $2 ); # Link IDs are case-insensitive + if ($3) { + $g_titles{lc $1} = $3; + $g_titles{lc $1} =~ s/"/"/g; + } + } + + return $text; +} + + +sub _HashHTMLBlocks { + my $text = shift; + my $less_than_tab = $g_tab_width - 1; + + # Hashify HTML blocks: + # We only want to do this for block-level HTML tags, such as headers, + # lists, and tables. That's because we still want to wrap

s around + # "paragraphs" that are wrapped in non-block-level tags, such as anchors, + # phrase emphasis, and spans. The list of tags we're looking for is + # hard-coded: + my $block_tags_a = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del/; + my $block_tags_b = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math/; + + # First, look for nested blocks, e.g.: + #

+ #
+ # tags for inner block must be indented. + #
+ #
+ # + # The outermost tags must start at the left margin for this to match, and + # the inner nested divs must be indented. + # We need to do this before the next, more liberal match, because the next + # match will start at the first `
` and stop at the first `
`. + $text =~ s{ + ( # save in $1 + ^ # start of line (with /m) + <($block_tags_a) # start tag = $2 + \b # word break + (.*\n)*? # any number of lines, minimally matching + # the matching end tag + [ \t]* # trailing spaces/tabs + (?=\n+|\Z) # followed by a newline or end of document + ) + }{ + my $key = md5_hex($1); + $g_html_blocks{$key} = $1; + "\n\n" . $key . "\n\n"; + }egmx; + + + # + # Now match more liberally, simply from `\n` to `\n` + # + $text =~ s{ + ( # save in $1 + ^ # start of line (with /m) + <($block_tags_b) # start tag = $2 + \b # word break + (.*\n)*? # any number of lines, minimally matching + .* # the matching end tag + [ \t]* # trailing spaces/tabs + (?=\n+|\Z) # followed by a newline or end of document + ) + }{ + my $key = md5_hex($1); + $g_html_blocks{$key} = $1; + "\n\n" . $key . "\n\n"; + }egmx; + # Special case just for
. It was easier to make a special case than + # to make the other regex more complicated. + $text =~ s{ + (?: + (?<=\n\n) # Starting after a blank line + | # or + \A\n? # the beginning of the doc + ) + ( # save in $1 + [ ]{0,$less_than_tab} + <(hr) # start tag = $2 + \b # word break + ([^<>])*? # + /?> # the matching end tag + [ \t]* + (?=\n{2,}|\Z) # followed by a blank line or end of document + ) + }{ + my $key = md5_hex($1); + $g_html_blocks{$key} = $1; + "\n\n" . $key . "\n\n"; + }egx; + + # Special case for standalone HTML comments: + $text =~ s{ + (?: + (?<=\n\n) # Starting after a blank line + | # or + \A\n? # the beginning of the doc + ) + ( # save in $1 + [ ]{0,$less_than_tab} + (?s: + + ) + [ \t]* + (?=\n{2,}|\Z) # followed by a blank line or end of document + ) + }{ + my $key = md5_hex($1); + $g_html_blocks{$key} = $1; + "\n\n" . $key . "\n\n"; + }egx; + + + return $text; +} + + +sub _RunBlockGamut { +# +# These are all the transformations that form block-level +# tags like paragraphs, headers, and list items. +# + my $text = shift; + + $text = _DoHeaders($text); + + # Do Horizontal Rules: + $text =~ s{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}{\n tags around block-level tags. + $text = _HashHTMLBlocks($text); + + $text = _FormParagraphs($text); + + return $text; +} + + +sub _RunSpanGamut { +# +# These are all the transformations that occur *within* block-level +# tags like paragraphs, headers, and list items. +# + my $text = shift; + + $text = _DoCodeSpans($text); + + $text = _EscapeSpecialChars($text); + + # Process anchor and image tags. Images must come first, + # because ![foo][f] looks like an anchor. + $text = _DoImages($text); + $text = _DoAnchors($text); + + # Make links out of things like `` + # Must come after _DoAnchors(), because you can use < and > + # delimiters in inline links like [this](). + $text = _DoAutoLinks($text); + + $text = _EncodeAmpsAndAngles($text); + + $text = _DoItalicsAndBold($text); + + # Do hard breaks: + $text =~ s/ {2,}\n/ or tags. +# my $tags_to_skip = qr!<(/?)(?:pre|code|kbd|script|math)[\s>]!; + + foreach my $cur_token (@$tokens) { + if ($cur_token->[0] eq "tag") { + # Within tags, encode * and _ so they don't conflict + # with their use in Markdown for italics and strong. + # We're replacing each such character with its + # corresponding MD5 checksum value; this is likely + # overkill, but it should prevent us from colliding + # with the escape values by accident. + $cur_token->[1] =~ s! \* !$g_escape_table{'*'}!gx; + $cur_token->[1] =~ s! _ !$g_escape_table{'_'}!gx; + $text .= $cur_token->[1]; + } else { + my $t = $cur_token->[1]; + $t = _EncodeBackslashEscapes($t); + $text .= $t; + } + } + return $text; +} + + +sub _DoAnchors { +# +# Turn Markdown link shortcuts into XHTML
tags. +# + my $text = shift; + + # + # First, handle reference-style links: [link text] [id] + # + $text =~ s{ + ( # wrap whole match in $1 + \[ + ($g_nested_brackets) # link text = $2 + \] + + [ ]? # one optional space + (?:\n[ ]*)? # one optional newline followed by spaces + + \[ + (.*?) # id = $3 + \] + ) + }{ + my $result; + my $whole_match = $1; + my $link_text = $2; + my $link_id = lc $3; + + if ($link_id eq "") { + $link_id = lc $link_text; # for shortcut links like [this][]. + } + + if (defined $g_urls{$link_id}) { + my $url = $g_urls{$link_id}; + $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid + $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. + $result = "? # href = $3 + [ \t]* + ( # $4 + (['"]) # quote char = $5 + (.*?) # Title = $6 + \5 # matching quote + )? # title is optional + \) + ) + }{ + my $result; + my $whole_match = $1; + my $link_text = $2; + my $url = $3; + my $title = $6; + + $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid + $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. + $result = " tags. +# + my $text = shift; + + # + # First, handle reference-style labeled images: ![alt text][id] + # + $text =~ s{ + ( # wrap whole match in $1 + !\[ + (.*?) # alt text = $2 + \] + + [ ]? # one optional space + (?:\n[ ]*)? # one optional newline followed by spaces + + \[ + (.*?) # id = $3 + \] + + ) + }{ + my $result; + my $whole_match = $1; + my $alt_text = $2; + my $link_id = lc $3; + + if ($link_id eq "") { + $link_id = lc $alt_text; # for shortcut links like ![this][]. + } + + $alt_text =~ s/"/"/g; + if (defined $g_urls{$link_id}) { + my $url = $g_urls{$link_id}; + $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid + $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. + $result = "\"$alt_text\"";? # src url = $3 + [ \t]* + ( # $4 + (['"]) # quote char = $5 + (.*?) # title = $6 + \5 # matching quote + [ \t]* + )? # title is optional + \) + ) + }{ + my $result; + my $whole_match = $1; + my $alt_text = $2; + my $url = $3; + my $title = ''; + if (defined($6)) { + $title = $6; + } + + $alt_text =~ s/"/"/g; + $title =~ s/"/"/g; + $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid + $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. + $result = "\"$alt_text\"";" . _RunSpanGamut($1) . "\n\n"; + }egmx; + + $text =~ s{ ^(.+)[ \t]*\n-+[ \t]*\n+ }{ + "

" . _RunSpanGamut($1) . "

\n\n"; + }egmx; + + + # atx-style headers: + # # Header 1 + # ## Header 2 + # ## Header 2 with closing hashes ## + # ... + # ###### Header 6 + # + $text =~ s{ + ^(\#{1,6}) # $1 = string of #'s + [ \t]* + (.+?) # $2 = Header text + [ \t]* + \#* # optional closing #'s (not counted) + \n+ + }{ + my $h_level = length($1); + "" . _RunSpanGamut($2) . "\n\n"; + }egmx; + + return $text; +} + + +sub _DoLists { +# +# Form HTML ordered (numbered) and unordered (bulleted) lists. +# + my $text = shift; + my $less_than_tab = $g_tab_width - 1; + + # Re-usable patterns to match list item bullets and number markers: + my $marker_ul = qr/[*+-]/; + my $marker_ol = qr/\d+[.]/; + my $marker_any = qr/(?:$marker_ul|$marker_ol)/; + + # Re-usable pattern to match any entirel ul or ol list: + my $whole_list = qr{ + ( # $1 = whole list + ( # $2 + [ ]{0,$less_than_tab} + (${marker_any}) # $3 = first list item marker + [ \t]+ + ) + (?s:.+?) + ( # $4 + \z + | + \n{2,} + (?=\S) + (?! # Negative lookahead for another list item marker + [ \t]* + ${marker_any}[ \t]+ + ) + ) + ) + }mx; + + # We use a different prefix before nested lists than top-level lists. + # See extended comment in _ProcessListItems(). + # + # Note: There's a bit of duplication here. My original implementation + # created a scalar regex pattern as the conditional result of the test on + # $g_list_level, and then only ran the $text =~ s{...}{...}egmx + # substitution once, using the scalar as the pattern. This worked, + # everywhere except when running under MT on my hosting account at Pair + # Networks. There, this caused all rebuilds to be killed by the reaper (or + # perhaps they crashed, but that seems incredibly unlikely given that the + # same script on the same server ran fine *except* under MT. I've spent + # more time trying to figure out why this is happening than I'd like to + # admit. My only guess, backed up by the fact that this workaround works, + # is that Perl optimizes the substition when it can figure out that the + # pattern will never change, and when this optimization isn't on, we run + # afoul of the reaper. Thus, the slightly redundant code to that uses two + # static s/// patterns rather than one conditional pattern. + + if ($g_list_level) { + $text =~ s{ + ^ + $whole_list + }{ + my $list = $1; + my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol"; + # Turn double returns into triple returns, so that we can make a + # paragraph for the last item in a list, if necessary: + $list =~ s/\n{2,}/\n\n\n/g; + my $result = _ProcessListItems($list, $marker_any); + $result = "<$list_type>\n" . $result . "\n"; + $result; + }egmx; + } + else { + $text =~ s{ + (?:(?<=\n\n)|\A\n?) + $whole_list + }{ + my $list = $1; + my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol"; + # Turn double returns into triple returns, so that we can make a + # paragraph for the last item in a list, if necessary: + $list =~ s/\n{2,}/\n\n\n/g; + my $result = _ProcessListItems($list, $marker_any); + $result = "<$list_type>\n" . $result . "\n"; + $result; + }egmx; + } + + + return $text; +} + + +sub _ProcessListItems { +# +# Process the contents of a single ordered or unordered list, splitting it +# into individual list items. +# + + my $list_str = shift; + my $marker_any = shift; + + + # The $g_list_level global keeps track of when we're inside a list. + # Each time we enter a list, we increment it; when we leave a list, + # we decrement. If it's zero, we're not in a list anymore. + # + # We do this because when we're not inside a list, we want to treat + # something like this: + # + # I recommend upgrading to version + # 8. Oops, now this line is treated + # as a sub-list. + # + # As a single paragraph, despite the fact that the second line starts + # with a digit-period-space sequence. + # + # Whereas when we're inside a list (or sub-list), that line will be + # treated as the start of a sub-list. What a kludge, huh? This is + # an aspect of Markdown's syntax that's hard to parse perfectly + # without resorting to mind-reading. Perhaps the solution is to + # change the syntax rules such that sub-lists must start with a + # starting cardinal number; e.g. "1." or "a.". + + $g_list_level++; + + # trim trailing blank lines: + $list_str =~ s/\n{2,}\z/\n/; + + + $list_str =~ s{ + (\n)? # leading line = $1 + (^[ \t]*) # leading whitespace = $2 + ($marker_any) [ \t]+ # list marker = $3 + ((?s:.+?) # list item text = $4 + (\n{1,2})) + (?= \n* (\z | \2 ($marker_any) [ \t]+)) + }{ + my $item = $4; + my $leading_line = $1; + my $leading_space = $2; + + if ($leading_line or ($item =~ m/\n{2,}/)) { + $item = _RunBlockGamut(_Outdent($item)); + } + else { + # Recursion for sub-lists: + $item = _DoLists(_Outdent($item)); + chomp $item; + $item = _RunSpanGamut($item); + } + + "
  • " . $item . "
  • \n"; + }egmx; + + $g_list_level--; + return $list_str; +} + + + +sub _DoCodeBlocks { +# +# Process Markdown `
    ` blocks.
    +#	
    +
    +	my $text = shift;
    +
    +	$text =~ s{
    +			(?:\n\n|\A)
    +			(	            # $1 = the code block -- one or more lines, starting with a space/tab
    +			  (?:
    +			    (?:[ ]{$g_tab_width} | \t)  # Lines must start with a tab or a tab-width of spaces
    +			    .*\n+
    +			  )+
    +			)
    +			((?=^[ ]{0,$g_tab_width}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
    +		}{
    +			my $codeblock = $1;
    +			my $result; # return value
    +
    +			$codeblock = _EncodeCode(_Outdent($codeblock));
    +			$codeblock = _Detab($codeblock);
    +			$codeblock =~ s/\A\n+//; # trim leading newlines
    +			$codeblock =~ s/\s+\z//; # trim trailing whitespace
    +
    +			$result = "\n\n
    " . $codeblock . "\n
    \n\n"; + + $result; + }egmx; + + return $text; +} + + +sub _DoCodeSpans { +# +# * Backtick quotes are used for spans. +# +# * You can use multiple backticks as the delimiters if you want to +# include literal backticks in the code span. So, this input: +# +# Just type ``foo `bar` baz`` at the prompt. +# +# Will translate to: +# +#

    Just type foo `bar` baz at the prompt.

    +# +# There's no arbitrary limit to the number of backticks you +# can use as delimters. If you need three consecutive backticks +# in your code, use four for delimiters, etc. +# +# * You can use spaces to get literal backticks at the edges: +# +# ... type `` `bar` `` ... +# +# Turns to: +# +# ... type `bar` ... +# + + my $text = shift; + + $text =~ s@ + (`+) # $1 = Opening run of ` + (.+?) # $2 = The code block + (?$c
    "; + @egsx; + + return $text; +} + + +sub _EncodeCode { +# +# Encode/escape certain characters inside Markdown code runs. +# The point is that in code, these characters are literals, +# and lose their special Markdown meanings. +# + local $_ = shift; + + # Encode all ampersands; HTML entities are not + # entities within a Markdown code span. + s/&/&/g; + + # Encode $'s, but only if we're running under Blosxom. + # (Blosxom interpolates Perl variables in article bodies.) + { + no warnings 'once'; + if (defined($blosxom::version)) { + s/\$/$/g; + } + } + + + # Do the angle bracket song and dance: + s! < !<!gx; + s! > !>!gx; + + # Now, escape characters that are magic in Markdown: + s! \* !$g_escape_table{'*'}!gx; + s! _ !$g_escape_table{'_'}!gx; + s! { !$g_escape_table{'{'}!gx; + s! } !$g_escape_table{'}'}!gx; + s! \[ !$g_escape_table{'['}!gx; + s! \] !$g_escape_table{']'}!gx; + s! \\ !$g_escape_table{'\\'}!gx; + + return $_; +} + + +sub _DoItalicsAndBold { + my $text = shift; + + # must go first: + $text =~ s{ (\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1 } + {$2}gsx; + + $text =~ s{ (\*|_) (?=\S) (.+?) (?<=\S) \1 } + {$2}gsx; + + return $text; +} + + +sub _DoBlockQuotes { + my $text = shift; + + $text =~ s{ + ( # Wrap whole match in $1 + ( + ^[ \t]*>[ \t]? # '>' at the start of a line + .+\n # rest of the first line + (.+\n)* # subsequent consecutive lines + \n* # blanks + )+ + ) + }{ + my $bq = $1; + $bq =~ s/^[ \t]*>[ \t]?//gm; # trim one level of quoting + $bq =~ s/^[ \t]+$//mg; # trim whitespace-only lines + $bq = _RunBlockGamut($bq); # recurse + + $bq =~ s/^/ /g; + # These leading spaces screw with
     content, so we need to fix that:
    +			$bq =~ s{
    +					(\s*
    .+?
    ) + }{ + my $pre = $1; + $pre =~ s/^ //mg; + $pre; + }egsx; + + "
    \n$bq\n
    \n\n"; + }egmx; + + + return $text; +} + + +sub _FormParagraphs { +# +# Params: +# $text - string to process with html

    tags +# + my $text = shift; + + # Strip leading and trailing lines: + $text =~ s/\A\n+//; + $text =~ s/\n+\z//; + + my @grafs = split(/\n{2,}/, $text); + + # + # Wrap

    tags. + # + foreach (@grafs) { + unless (defined( $g_html_blocks{$_} )) { + $_ = _RunSpanGamut($_); + s/^([ \t]*)/

    /; + $_ .= "

    "; + } + } + + # + # Unhashify HTML blocks + # + foreach (@grafs) { + if (defined( $g_html_blocks{$_} )) { + $_ = $g_html_blocks{$_}; + } + } + + return join "\n\n", @grafs; +} + + +sub _EncodeAmpsAndAngles { +# Smart processing for ampersands and angle brackets that need to be encoded. + + my $text = shift; + + # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: + # http://bumppo.net/projects/amputator/ + $text =~ s/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/&/g; + + # Encode naked <'s + $text =~ s{<(?![a-z/?\$!])}{<}gi; + + return $text; +} + + +sub _EncodeBackslashEscapes { +# +# Parameter: String. +# Returns: The string, with after processing the following backslash +# escape sequences. +# + local $_ = shift; + + s! \\\\ !$g_escape_table{'\\'}!gx; # Must process escaped backslashes first. + s! \\` !$g_escape_table{'`'}!gx; + s! \\\* !$g_escape_table{'*'}!gx; + s! \\_ !$g_escape_table{'_'}!gx; + s! \\\{ !$g_escape_table{'{'}!gx; + s! \\\} !$g_escape_table{'}'}!gx; + s! \\\[ !$g_escape_table{'['}!gx; + s! \\\] !$g_escape_table{']'}!gx; + s! \\\( !$g_escape_table{'('}!gx; + s! \\\) !$g_escape_table{')'}!gx; + s! \\> !$g_escape_table{'>'}!gx; + s! \\\# !$g_escape_table{'#'}!gx; + s! \\\+ !$g_escape_table{'+'}!gx; + s! \\\- !$g_escape_table{'-'}!gx; + s! \\\. !$g_escape_table{'.'}!gx; + s{ \\! }{$g_escape_table{'!'}}gx; + + return $_; +} + + +sub _DoAutoLinks { + my $text = shift; + + $text =~ s{<((https?|ftp):[^'">\s]+)>}{
    $1}gi; + + # Email addresses: + $text =~ s{ + < + (?:mailto:)? + ( + [-.\w]+ + \@ + [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+ + ) + > + }{ + _EncodeEmailAddress( _UnescapeSpecialChars($1) ); + }egix; + + return $text; +} + + +sub _EncodeEmailAddress { +# +# Input: an email address, e.g. "foo@example.com" +# +# Output: the email address as a mailto link, with each character +# of the address encoded as either a decimal or hex entity, in +# the hopes of foiling most address harvesting spam bots. E.g.: +# +# foo +# @example.com +# +# Based on a filter by Matthew Wickline, posted to the BBEdit-Talk +# mailing list: +# + + my $addr = shift; + + srand; + my @encode = ( + sub { '&#' . ord(shift) . ';' }, + sub { '&#x' . sprintf( "%X", ord(shift) ) . ';' }, + sub { shift }, + ); + + $addr = "mailto:" . $addr; + + $addr =~ s{(.)}{ + my $char = $1; + if ( $char eq '@' ) { + # this *must* be encoded. I insist. + $char = $encode[int rand 1]->($char); + } elsif ( $char ne ':' ) { + # leave ':' alone (to spot mailto: later) + my $r = rand; + # roughly 10% raw, 45% hex, 45% dec + $char = ( + $r > .9 ? $encode[2]->($char) : + $r < .45 ? $encode[1]->($char) : + $encode[0]->($char) + ); + } + $char; + }gex; + + $addr = qq{$addr}; + $addr =~ s{">.+?:}{">}; # strip the mailto: from the visible part + + return $addr; +} + + +sub _UnescapeSpecialChars { +# +# Swap back in all the special characters we've hidden. +# + my $text = shift; + + while( my($char, $hash) = each(%g_escape_table) ) { + $text =~ s/$hash/$char/g; + } + return $text; +} + + +sub _TokenizeHTML { +# +# Parameter: String containing HTML markup. +# Returns: Reference to an array of the tokens comprising the input +# string. Each token is either a tag (possibly with nested, +# tags contained therein, such as , or a +# run of text between tags. Each element of the array is a +# two-element array; the first is either 'tag' or 'text'; +# the second is the actual value. +# +# +# Derived from the _tokenize() subroutine from Brad Choate's MTRegex plugin. +# +# + + my $str = shift; + my $pos = 0; + my $len = length $str; + my @tokens; + + my $depth = 6; + my $nested_tags = join('|', ('(?:<[a-z/!$](?:[^<>]') x $depth) . (')*>)' x $depth); + my $match = qr/(?s: ) | # comment + (?s: <\? .*? \?> ) | # processing instruction + $nested_tags/ix; # nested tags + + while ($str =~ m/($match)/g) { + my $whole_tag = $1; + my $sec_start = pos $str; + my $tag_start = $sec_start - length $whole_tag; + if ($pos < $tag_start) { + push @tokens, ['text', substr($str, $pos, $tag_start - $pos)]; + } + push @tokens, ['tag', $whole_tag]; + $pos = pos $str; + } + push @tokens, ['text', substr($str, $pos, $len - $pos)] if $pos < $len; + \@tokens; +} + + +sub _Outdent { +# +# Remove one level of line-leading tabs or spaces +# + my $text = shift; + + $text =~ s/^(\t|[ ]{1,$g_tab_width})//gm; + return $text; +} + + +sub _Detab { +# +# Cribbed from a post by Bart Lateur: +# +# + my $text = shift; + + $text =~ s{(.*?)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge; + return $text; +} + + +1; + +__END__ + + +=pod + +=head1 NAME + +B + + +=head1 SYNOPSIS + +B [ B<--html4tags> ] [ B<--version> ] [ B<-shortversion> ] + [ I ... ] + + +=head1 DESCRIPTION + +Markdown is a text-to-HTML filter; it translates an easy-to-read / +easy-to-write structured text format into HTML. Markdown's text format +is most similar to that of plain text email, and supports features such +as headers, *emphasis*, code blocks, blockquotes, and links. + +Markdown's syntax is designed not as a generic markup language, but +specifically to serve as a front-end to (X)HTML. You can use span-level +HTML tags anywhere in a Markdown document, and you can use block level +HTML tags (like
    and as well). + +For more information about Markdown's syntax, see: + + http://daringfireball.net/projects/markdown/ + + +=head1 OPTIONS + +Use "--" to end switch parsing. For example, to open a file named "-z", use: + + Markdown.pl -- -z + +=over 4 + + +=item B<--html4tags> + +Use HTML 4 style for empty element tags, e.g.: + +
    + +instead of Markdown's default XHTML style tags, e.g.: + +
    + + +=item B<-v>, B<--version> + +Display Markdown's version number and copyright information. + + +=item B<-s>, B<--shortversion> + +Display the short-form version number. + + +=back + + + +=head1 BUGS + +To file bug reports or feature requests (other than topics listed in the +Caveats section above) please send email to: + + support@daringfireball.net + +Please include with your report: (1) the example input; (2) the output +you expected; (3) the output Markdown actually produced. + + +=head1 VERSION HISTORY + +See the readme file for detailed release notes for this version. + +1.0.1 - 14 Dec 2004 + +1.0 - 28 Aug 2004 + + +=head1 AUTHOR + + John Gruber + http://daringfireball.net + + PHP port and other contributions by Michel Fortin + http://michelf.com + + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2003-2004 John Gruber + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name "Markdown" nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as +is" and any express or implied warranties, including, but not limited +to, the implied warranties of merchantability and fitness for a +particular purpose are disclaimed. In no event shall the copyright owner +or contributors be liable for any direct, indirect, incidental, special, +exemplary, or consequential damages (including, but not limited to, +procurement of substitute goods or services; loss of use, data, or +profits; or business interruption) however caused and on any theory of +liability, whether in contract, strict liability, or tort (including +negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. + +=cut diff --git a/werc/bin/contrib/md2html.awk b/werc/bin/contrib/md2html.awk new file mode 100755 index 0000000..81d1241 --- /dev/null +++ b/werc/bin/contrib/md2html.awk @@ -0,0 +1,427 @@ +#!/bin/awk -f +# +# by: Jesus Galan (yiyus) 2009 +# +# Usage: md2html.awk file.md > file.html +# See: http://4l77.com/src/md2html.awk + +function eschtml(t) { + gsub("&", "\\&", t); + gsub("<", "\\<", t); + return t; +} + +function oprint(t){ + if(nr == 0) + print t; + else + otext = otext "\n" t; +} + +function subref(id){ + for(; nr > 0 && sub("<<" id, ref[id], otext); nr--); + if(nr == 0 && otext) { + print otext; + otext = ""; + } +} + +function nextil(t) { + if(!match(t, /[`<&\[*_\\-]|(\!\[)/)) + return t; + t1 = substr(t, 1, RSTART - 1); + tag = substr(t, RSTART, RLENGTH); + t2 = substr(t, RSTART + RLENGTH); + if(ilcode && tag != "`") + return eschtml(t1 tag) nextil(t2); + # Backslash escaping + if(tag == "\\"){ + if(match(t2, /^[\\`*_{}\[\]()#+\-\.!]/)){ + tag = substr(t2, 1, 1); + t2 = substr(t2, 2); + } + return t1 tag nextil(t2); + } + # Dashes + if(tag == "-"){ + if(sub(/^-/, "", t2)) + tag = "—"; + return t1 tag nextil(t2); + } + # Inline Code + if(tag == "`"){ + if(sub(/^`/, "", t2)){ + if(!match(t2, /``/)) + return t1 "”" nextil(t2); + ilcode2 = !ilcode2; + } + else if(ilcode2) + return t1 tag nextil(t2); + tag = ""; + if(ilcode){ + t1 = eschtml(t1); + tag = ""; + } + ilcode = !ilcode; + return t1 tag nextil(t2); + } + if(tag == "<"){ + # Autolinks + if(match(t2, /^[^ ]+[\.@][^ ]+>/)){ + url = eschtml(substr(t2, 1, RLENGTH - 1)); + t2 = substr(t2, RLENGTH + 1); + linktext = url; + if(match(url, /@/) && !match(url, /^mailto:/)) + url = "mailto:" url; + return t1 "" linktext "" nextil(t2); + } + # Html tags + if(match(t2, /^[A-Za-z\/!][^>]*>/)){ + tag = tag substr(t2, RSTART, RLENGTH); + t2 = substr(t2, RLENGTH + 1); + return t1 tag nextil(t2); + } + return t1 "<" nextil(t2); + } + # Html special entities + if(tag == "&"){ + if(match(t2, /^#?[A-Za-z0-9]+;/)){ + tag = tag substr(t2, RSTART, RLENGTH); + t2 = substr(t2, RLENGTH + 1); + return t1 tag nextil(t2); + } + return t1 "&" nextil(t2); + } + # Images + if(tag == "!["){ + if(!match(t2, /(\[.*\])|(\(.*\))/)) + return t1 tag nextil(t2); + match(t2, /^[^\]]*/); + alt = substr(t2, 1, RLENGTH); + t2 = substr(t2, RLENGTH + 2); + if(match(t2, /^\(/)){ + # Inline + sub(/^\(/, "", t2); + match(t2, /^[^\)]+/); + url = eschtml(substr(t2, 1, RLENGTH)); + t2 = substr(t2, RLENGTH + 2); + title = ""; + if(match(url, /[ ]+\".*\"[ ]*$/)) { + title = substr(url, RSTART, RLENGTH); + url = substr(url, 1, RSTART - 1); + match(title, /\".*\"/); + title = " title=\"" substr(title, RSTART + 1, RLENGTH - 2) "\""; + } + if(match(url, /^<.*>$/)) + url = substr(url, 2, RLENGTH - 2); + return t1 "\""" nextil(t2); + } + else{ + # Referenced + sub(/^ ?\[/, "", t2); + id = alt; + if(match(t2, /^[^\]]+/)) + id = substr(t2, 1, RLENGTH); + t2 = substr(t2, RLENGTH + 2); + if(ref[id]) + r = ref[id]; + else{ + r = "<<" id; + nr++; + } + return t1 "\""" nextil(t2); + } + } + # Links + if(tag == "["){ + if(!match(t2, /(\[.*\])|(\(.*\))/)) + return t1 tag nextil(t2); + match(t2, /^[^\]]*(\[[^\]]*\][^\]]*)*/); + linktext = substr(t2, 1, RLENGTH); + t2 = substr(t2, RLENGTH + 2); + if(match(t2, /^\(/)){ + # Inline + match(t2, /^[^\)]+(\([^\)]+\)[^\)]*)*/); + url = substr(t2, 2, RLENGTH - 1); + pt2 = substr(t2, RLENGTH + 2); + title = ""; + if(match(url, /[ ]+\".*\"[ ]*$/)) { + title = substr(url, RSTART, RLENGTH); + url = substr(url, 1, RSTART - 1); + match(title, /\".*\"/); + title = " title=\"" substr(title, RSTART + 1, RLENGTH - 2) "\""; + } + if(match(url, /^<.*>$/)) + url = substr(url, 2, RLENGTH - 2); + url = eschtml(url); + return t1 "" nextil(linktext) "" nextil(pt2); + } + else{ + # Referenced + sub(/^ ?\[/, "", t2); + id = linktext; + if(match(t2, /^[^\]]+/)) + id = substr(t2, 1, RLENGTH); + t2 = substr(t2, RLENGTH + 2); + if(ref[id]) + r = ref[id]; + else{ + r = "<<" id; + nr++; + } + pt2 = t2; + return t1 "" nextil(linktext) "" nextil(pt2); + } + } + # Emphasis + if(match(tag, /[*_]/)){ + ntag = tag; + if(sub("^" tag, "", t2)){ + if(stag[ns] == tag && match(t2, "^" tag)) + t2 = tag t2; + else + ntag = tag tag + } + n = length(ntag); + tag = (n == 2) ? "strong" : "em"; + if(match(t1, / $/) && match(t2, /^ /)) + return t1 tag nextil(t2); + if(stag[ns] == ntag){ + tag = "/" tag; + ns--; + } + else + stag[++ns] = ntag; + tag = "<" tag ">"; + return t1 tag nextil(t2); + } +} + +function inline(t) { + ilcode = 0; + ilcode2 = 0; + ns = 0; + + return nextil(t); +} + +function printp(tag) { + if(!match(text, /^[ ]*$/)){ + text = inline(text); + if(tag != "") + oprint("<" tag ">" text ""); + else + oprint(text); + } + text = ""; +} + +BEGIN { + blank = 0; + code = 0; + hr = 0; + html = 0; + nl = 0; + nr = 0; + otext = ""; + text = ""; + par = "p"; +} + +# References +!code && /^ *\[[^\]]*\]:[ ]+/ { + sub(/^ *\[/, ""); + match($0, /\]/); + id = substr($0, 1, RSTART - 1); + sub(id "\\]:[ ]+", ""); + title = ""; + if(match($0, /\".*\"$/)) + title = "\" title=\"" substr($0, RSTART + 1, RLENGTH - 2); + sub(/[ ]+\".*\"$/, ""); + url = eschtml($0); + ref[id] = url title; + + subref(id); + next; +} + +# html +!html && /^<(address|blockquote|center|dir|div|dl|fieldset|form|h[1-6r]|\ +isindex|menu|noframes|noscript|ol|p|pre|table|ul|!--)/ { + if(code) + oprint(""); + for(; !text && block[nl] == "blockquote"; nl--) + oprint(""); + match($0, /^<(address|blockquote|center|dir|div|dl|fieldset|form|h[1-6r]|\ + isindex|menu|noframes|noscript|ol|p|pre|table|ul|!--)/); + htag = substr($0, 2, RLENGTH - 1); + if(!match($0, "(<\\/" htag ">)|((^
    $)")) + html = 1; + if(html && match($0, /^
    $/ || +(hr && />$/)) { + html = 0; + hr = 0; + oprint($0); + next; +} + +html { + oprint($0); + next; +} + +# List and quote blocks + +# Remove indentation +{ + for(nnl = 0; nnl < nl; nnl++) + if((match(block[nnl + 1], /[ou]l/) && !sub(/^( | )/, "")) || \ + (block[nnl + 1] == "blockquote" && !sub(/^> ?/, ""))) + break; +} +nnl < nl && !blank && text && ! /^ ? ? ?([*+-]|([0-9]+\.)+)( +| )/ { nnl = nl; } +# Quote blocks +{ + while(sub(/^> /, "")) + nblock[++nnl] = "blockquote"; +} +# Horizontal rules +{ hr = 0; } +(blank || (!text && !code)) && /^ ? ? ?([-*_][ ]*)([-*_][ ]*)([-*_][ ]*)+$/ { + if(code){ + oprint(""); + code = 0; + } + blank = 0; + nnl = 0; + hr = 1; +} +# List items +block[nl] ~ /[ou]l/ && /^$/ { + blank = 1; + next; +} +{ newli = 0; } +!hr && (nnl != nl || !text || block[nl] ~ /[ou]l/) && /^ ? ? ?[*+-]( +| )/ { + sub(/^ ? ? ?[*+-]( +| )/, ""); + nnl++; + nblock[nnl] = "ul"; + newli = 1; +} +(nnl != nl || !text || block[nl] ~ /[ou]l/) && /^ ? ? ?([0-9]+\.)+( +| )/ { + sub(/^ ? ? ?([0-9]+\.)+( +| )/, ""); + nnl++; + nblock[nnl] = "ol"; + newli = 1; +} +newli { + if(blank && nnl == nl && !par) + par = "p"; + blank = 0; + printp(par); + if(nnl == nl && block[nl] == nblock[nl]) + oprint("
  • "); +} +blank && ! /^$/ { + if(match(block[nnl], /[ou]l/) && !par) + par = "p"; + printp(par); + par = "p"; + blank = 0; +} + +# Close old blocks and open new ones +nnl != nl || nblock[nl] != block[nl] { + if(code){ + oprint(""); + code = 0; + } + printp(par); + b = (nnl > nl) ? nblock[nnl] : block[nnl]; + par = (match(b, /[ou]l/)) ? "" : "p"; +} +nnl < nl || (nnl == nl && nblock[nl] != block[nl]) { + for(; nl > nnl || (nnl == nl && pblock[nl] != block[nl]); nl--){ + if(match(block[nl], /[ou]l/)) + oprint("
  • "); + oprint(""); + } +} +nnl > nl { + for(; nl < nnl; nl++){ + block[nl + 1] = nblock[nl + 1]; + oprint("<" block[nl + 1] ">"); + if(match(block[nl + 1], /[ou]l/)) + oprint("
  • "); + } +} +hr { + oprint("
    "); + next; +} + +# Code blocks +code && /^$/ { + if(blanK) + oprint(""); + blank = 1; + next; +} +!text && sub(/^( | )/, "") { + if(blanK) + oprint(""); + blank = 0; + if(!code) + oprint("
    ");
    +	code = 1;
    +	$0 = eschtml($0);
    +	oprint($0);
    +	next;
    +}
    +code {
    +	oprint("
    "); + code = 0; +} + +# Setex-style Headers +text && /^=+$/ {printp("h1"); next;} +text && /^-+$/ {printp("h2"); next;} + +# Atx-Style headers +/^#+/ && (!newli || par=="p" || /^##/) { + for(n = 0; n < 6 && sub(/^# */, ""); n++) + sub(/#$/, ""); + par = "h" n; +} + +# Paragraph +/^$/ { + printp(par); + par = "p"; + next; +} + +# Add text +{ text = (text ? text " " : "") $0; } + +END { + if(code){ + oprint(""); + code = 0; + } + printp(par); + for(; nl > 0; nl--){ + if(match(block[nl], /[ou]l/)) + oprint("
  • "); + oprint(""); + } + gsub(/<<[^\"]*/, "", otext); + print(otext); +} diff --git a/werc/bin/contrib/rc-httpd/handlers/authorize b/werc/bin/contrib/rc-httpd/handlers/authorize new file mode 100755 index 0000000..ea4db3e --- /dev/null +++ b/werc/bin/contrib/rc-httpd/handlers/authorize @@ -0,0 +1,6 @@ +#!/bin/rc +if(~ $REMOTE_USER ''){ + extra_headers=($extra_headers 'WWW-Authenticate: Basic realm="'$"SERVER_NAME'"') + error 401 + exit +} diff --git a/werc/bin/contrib/rc-httpd/handlers/cgi b/werc/bin/contrib/rc-httpd/handlers/cgi new file mode 100755 index 0000000..2c9a9b9 --- /dev/null +++ b/werc/bin/contrib/rc-httpd/handlers/cgi @@ -0,0 +1,46 @@ +#!/bin/rc +fn filter_headers{ + response=(200 OK) + lines='' + done=false + while(~ $done false){ + line=`{getline} + head=`{echo $line | awk '{print tolower($1)}'} + if(~ $head status:*) + response=`{echo $line | awk '{$1="" ; print}'} + if not if(~ $line '') + done=true + if not + lines=$"lines^$"line^$cr^' +' + } + echo 'HTTP/1.1' $"response^$cr + echo -n $"lines + do_log $response(1) +} + +fn run_cgi { + path=$cgi_path exec $"cgi_bin $params || echo 'Status: 500' +} + +cgi_bin=$1 +cgi_dir=. +if(! ~ $#* 1) + cgi_dir=$*($#*) +if not if(~ $"cgi_bin /*){ + cgi_dir=`{basename -d $"cgi_bin} + cgi_dir=$"cgi_dir +} +if(! ~ $"cgi_bin */*) + cgi_bin=./$"cgi_bin +if(! builtin cd $"cgi_dir >[2]/dev/null || ! test -x $"cgi_bin){ + error 500 + exit +} + +run_cgi | { + filter_headers + emit_extra_headers + echo $cr + exec cat +} diff --git a/werc/bin/contrib/rc-httpd/handlers/dir-index b/werc/bin/contrib/rc-httpd/handlers/dir-index new file mode 100755 index 0000000..00ff8ce --- /dev/null +++ b/werc/bin/contrib/rc-httpd/handlers/dir-index @@ -0,0 +1,111 @@ +#!/bin/rc +PATH_INFO=`{echo $PATH_INFO | urldecode.awk} +full_path=$"FS_ROOT^$"PATH_INFO +full_path=$"full_path +if(! test -d $full_path){ + error 404 + exit +} +if(! test -r $full_path -x $full_path){ + error 503 + exit +} +do_log 200 +builtin cd $full_path +if(~ $"NOINDEXFILE ^ $"NOINDEX ''){ + ifile=index.htm* + if(! ~ $ifile(1) *'*'){ + PATH_INFO=$ifile(1) + FS_ROOT='' + exec serve-static + } +} +title=`{echo $SITE_TITLE | sed s,%s,^$"PATH_INFO^,} +title=$"title +lso=() +switch($2){ +case size + # ls has no option to sort by size + # could pipe it through sort, I suppose +case date + lso=-t +} +echo 'HTTP/1.1 200 OK'^$cr +emit_extra_headers +echo 'Content-type: text/html'^$cr +echo $cr +echo ' + +'^$title^' + + +' +echo '

    '^$title^'

    ' +if(! ~ $PATH_INFO /) + echo 'Parent directory' +echo '
    ' +ls -lQ $lso | awk ' +function urlencode(loc){ + # very minimal encoding, just enough for our static-file purposes + url=loc + gsub("%", "%25", url) # this one first! + gsub("\\$", "%24", url) + gsub("&", "%26", url) + gsub("\\+", "%2B", url) + gsub("\\?", "%3F", url) + gsub(" ", "%20", url) + gsub("\"", "%22", url) + gsub("#", "%23", url) + return url +} +function hrsize(size){ + if(size > 1073741824) return sprintf("%.1fGB", size/1073741824) + if(size > 10485760) return sprintf("%iMB", size/1048576) + if(size > 1048576) return sprintf("%.1fMB", size/1048576) + if(size > 10240) return sprintf("%iKB", size/1024) + if(size > 1024) return sprintf("%.1fKB", size/1024) + return sprintf("%iB", size) +} +/^(-|a)/ { + print "" + print "" + print "" + print "" + print "" + $1="" ; $2="" ; $3="" ; $4="" ; $5="" ; $6="" ; $7="" ; $8="" ; $9="" + sub("^ *?", "") + print "" + print "" + $0="" +} +/^d/ { + print "" + print "" + print "" + print "" + print "" + $1="" ; $2="" ; $3="" ; $4="" ; $5="" ; $6="" ; $7="" ; $8="" ; $9="" + sub("^ *?", "") + print "" + print "" +}' +echo '
    "hrsize($6)""$7""$8""$9""$0"
    "$7""$8""$9""$0"/
    + + +' diff --git a/werc/bin/contrib/rc-httpd/handlers/error b/werc/bin/contrib/rc-httpd/handlers/error new file mode 100755 index 0000000..282d870 --- /dev/null +++ b/werc/bin/contrib/rc-httpd/handlers/error @@ -0,0 +1,43 @@ +#!/bin/rc +# DO NOT make this script callable directly from the web! +fn do_error{ + echo 'HTTP/1.1 '^$1^$cr + emit_extra_headers + echo 'Content-type: text/html'^$cr + echo $cr + echo ' + +'^$1^' + + +

    '^$1^'

    ' + echo $2 + echo '

    rc-httpd at' $SERVER_NAME '' + echo ' + + + ' +} + +fn 401{ + do_error '401 Unauthorized' \ + 'The requested path '^$"location^' requires authorization.' +} + +fn 404{ + do_error '404 Not Found' \ + 'The requested path '^$"location^' was not found on this server.' +} + +fn 500{ + do_error '500 Internal Server Error' \ + 'The server has encountered an internal misconfiguration and is unable to satisfy your request.' +} + +fn 503{ + do_error '503 Forbidden' \ + 'You do not have permission to access '^$"location^' on this server.' +} + +do_log $1 +$1 diff --git a/werc/bin/contrib/rc-httpd/handlers/redirect b/werc/bin/contrib/rc-httpd/handlers/redirect new file mode 100755 index 0000000..e223091 --- /dev/null +++ b/werc/bin/contrib/rc-httpd/handlers/redirect @@ -0,0 +1,30 @@ +#!/bin/rc +if(~ $#2 0){ + error 500 + exit +} +switch($1){ +case perm* + do_log 301 + echo 'HTTP/1.1 301 Moved Permanently'^$cr +case temp* + do_log 302 + echo 'HTTP/1.1 302 Moved Temporarily'^$cr +case seeother + do_log 303 + echo 'HTTP/1.1 303 See Other'^$cr +case * + error 500 + exit +} +echo 'Location: ' ^ $2 ^ $cr +emit_extra_headers +echo 'Content-type: text/html'^$cr +echo $cr +echo '' +if(~ $#3 0) + echo 'Browser did not accept redirect.' +if not + echo $3 +echo 'Click here' +echo '' diff --git a/werc/bin/contrib/rc-httpd/handlers/serve-static b/werc/bin/contrib/rc-httpd/handlers/serve-static new file mode 100755 index 0000000..00cc70a --- /dev/null +++ b/werc/bin/contrib/rc-httpd/handlers/serve-static @@ -0,0 +1,43 @@ +#!/bin/rc +full_path=`{echo $"FS_ROOT^$"PATH_INFO | urldecode.awk} +full_path=$"full_path +if(~ $full_path */) + error 503 +if(test -d $full_path){ + redirect perm $"location^'/' \ + 'URL not quite right, and browser did not accept redirect.' + exit +} +if(! test -e $full_path){ + error 404 + exit +} +if(! test -r $full_path){ + error 503 + exit +} +do_log 200 +switch($full_path){ +case *.html *.htm + type=text/html +case *.css + type=text/css +case *.txt + type='text/plain; charset=utf-8' +case *.jpg *.jpeg + type=image/jpeg +case *.gif + type=image/gif +case *.png + type=image/png +case * + type=`{file -m $full_path || file -i $full_path} # GROSS +} +max_age=3600 # 1 hour +echo 'HTTP/1.1 200 OK'^$cr +emit_extra_headers +echo 'Content-type: '^$type^'; charset=utf-8'^$cr +echo 'Content-length: '^`{ls -l $full_path | awk '{print $6}'} +echo 'Cache-control: max-age='^$max_age^$cr +echo $cr +exec cat $full_path diff --git a/werc/bin/contrib/rc-httpd/handlers/static-or-cgi b/werc/bin/contrib/rc-httpd/handlers/static-or-cgi new file mode 100755 index 0000000..4d8a2d4 --- /dev/null +++ b/werc/bin/contrib/rc-httpd/handlers/static-or-cgi @@ -0,0 +1,14 @@ +#!/bin/rc +cgiargs=$* + +fn error{ + if(~ $1 404) + exec cgi $cgiargs + if not + $rc_httpd_dir/handlers/error $1 +} + +if(~ $location */) + exec cgi $cgiargs +if not + exec serve-static diff --git a/werc/bin/contrib/rc-httpd/handlers/static-or-index b/werc/bin/contrib/rc-httpd/handlers/static-or-index new file mode 100755 index 0000000..f0904f8 --- /dev/null +++ b/werc/bin/contrib/rc-httpd/handlers/static-or-index @@ -0,0 +1,5 @@ +#!/bin/rc +if(~ $PATH_INFO */) + exec dir-index $params +if not + exec serve-static diff --git a/werc/bin/contrib/rc-httpd/lib/urldecode.awk b/werc/bin/contrib/rc-httpd/lib/urldecode.awk new file mode 100755 index 0000000..1dadd00 --- /dev/null +++ b/werc/bin/contrib/rc-httpd/lib/urldecode.awk @@ -0,0 +1,39 @@ +# taken from werc +BEGIN { + hextab ["0"] = 0; hextab ["8"] = 8; + hextab ["1"] = 1; hextab ["9"] = 9; + hextab ["2"] = 2; hextab ["A"] = hextab ["a"] = 10 + hextab ["3"] = 3; hextab ["B"] = hextab ["b"] = 11; + hextab ["4"] = 4; hextab ["C"] = hextab ["c"] = 12; + hextab ["5"] = 5; hextab ["D"] = hextab ["d"] = 13; + hextab ["6"] = 6; hextab ["E"] = hextab ["e"] = 14; + hextab ["7"] = 7; hextab ["F"] = hextab ["f"] = 15; +} +{ + decoded = "" + i = 1 + len = length ($0) + while ( i <= len ) { + c = substr ($0, i, 1) + if ( c == "%" ) { + if ( i+2 <= len ) { + c1 = substr ($0, i+1, 1) + c2 = substr ($0, i+2, 1) + if ( hextab [c1] == "" || hextab [c2] == "" ) { + print "WARNING: invalid hex encoding: %" c1 c2 | "cat >&2" + } else { + code = 0 + hextab [c1] * 16 + hextab [c2] + 0 + c = sprintf ("%c", code) + i = i + 2 + } + } else { + print "WARNING: invalid % encoding: " substr ($0, i, len - i) + } + } else if ( c == "+" ) { + c = " " + } + decoded = decoded c + ++i + } + printf "%s", decoded +} diff --git a/werc/bin/contrib/rc-httpd/rc-httpd b/werc/bin/contrib/rc-httpd/rc-httpd new file mode 100755 index 0000000..8e4fad9 --- /dev/null +++ b/werc/bin/contrib/rc-httpd/rc-httpd @@ -0,0 +1,102 @@ +#!/bin/rc +rc_httpd_dir=/home/sl/www/werc/bin/contrib/rc-httpd +libdir = $rc_httpd_dir/lib +path=($PLAN9/bin $rc_httpd_dir/handlers $PATH) +cgi_path=$PLAN9/bin +SERVER_PORT=80 # default for CGI scripts, may be overridden by the Host header +extra_headers='Server: rc-httpd' +cr= + +fn do_log{ + echo `{date} :: $SERVER_NAME :: $request :: \ + $HTTP_USER_AGENT :: $1 :: $HTTP_REFERER >[1=2] +} + +fn emit_extra_headers{ + for(header in $extra_headers) + echo $"header^$cr +} + +fn getline{ read | sed 's/'^$"cr^'$//g' } + +fn terminate{ + echo `{date} connection terminated >[1=2] + exit terminate +} + +fn trim_input{ dd -bs 1 -count $CONTENT_LENGTH } + +request=`{getline} +if(~ $#request 0) + terminate +REQUEST_METHOD=$request(1) +REQUEST_URI=$request(2) +reqlines='' +HTTP_COOKIE='' +REMOTE_USER='' +done=false +chunked=no +while(~ $"done false){ + line=`{getline} + if(~ $#line 0) + done=true + reqlines=$"reqlines$"line' +' + h=`{echo $line | awk '{print tolower($1)}'} + switch($h){ + case '' + done=true + case host: + SERVER_NAME=$line(2) + case referer: + HTTP_REFERER=$line(2) + case user-agent: + HTTP_USER_AGENT=`{echo $line | sed 's;[^:]+:[ ]+;;'} + case content-length: + CONTENT_LENGTH=$line(2) + case content-type: + CONTENT_TYPE=$line(2) + case cookie: + cookie=`{echo $line | sed 's;^[^:]+:[ ]*;;'} + HTTP_COOKIE=$"HTTP_COOKIE^$"cookie^'; ' + case authorization: + REMOTE_USER=`{auth/httpauth $line(3)} + case transfer-encoding: + ~ $line(2) chunked && chunked=yes + } +} +if(~ $REQUEST_URI *://* //*){ + SERVER_NAME=`{echo $REQUEST_URI | sed ' + s;^[^:]+:;; + s;^//([^/]+).*;\1;'} + REQUEST_URI=`{echo $REQUEST_URI | sed ' + s;^[^:]+:;; + s;^//[^/]+/?;/;'} +} +QUERY_STRING=`{echo $REQUEST_URI | sed 's;[^?]*\??;;'} +params=`{echo $QUERY_STRING | sed 's;\+; ;g'} +location=`{echo $REQUEST_URI | sed 's;\?.*;;'} +location=`{echo $location | sed ' + s;[^/]+/\.\./;/;g + s;/\./;/;g + s;//+;/;g +'} +SERVER_NAME=`{echo $SERVER_NAME | sed 's;^(\[[^\]]+\]|[^:]+)\:([0-9]+)$;\1 \2;'} +if(~ $#SERVER_NAME 2){ + SERVER_PORT=$SERVER_NAME(2) + SERVER_NAME=$SERVER_NAME(1) +} +if(~ $REQUEST_METHOD (PUT POST)){ + if(! ~ $"CONTENT_LENGTH '') + trim_input | exec $rc_httpd_dir/select-handler + if not{ + if(~ $chunked yes){ + echo 'HTTP/1.1 411 Length required'^$cr + echo $cr + exit + } + exec $rc_httpd_dir/select-handler + } +} +if not + . $rc_httpd_dir/select-handler diff --git a/werc/bin/contrib/rc-httpd/select-handler b/werc/bin/contrib/rc-httpd/select-handler new file mode 100755 index 0000000..ec819d4 --- /dev/null +++ b/werc/bin/contrib/rc-httpd/select-handler @@ -0,0 +1,20 @@ +#!/bin/rc +rfork n + +# Route requests to werc. +# Change paths to match your system. + +if(~ $SERVER_NAME 9base.werc.cat-v.org) + PLAN9=/usr/local/9base +if(~ $SERVER_NAME frontbase.werc.cat-v.org) + PLAN9=/usr/local/plan9front +if(~ $SERVER_NAME plan9port.werc.cat-v.org) + PLAN9=/usr/local/plan9 + +if(~ $SERVER_NAME *){ + PATH_INFO=$location + FS_ROOT=/home/sl/www/werc/sites/$SERVER_NAME + exec static-or-cgi /home/sl/www/werc/bin/werc.rc +} +if not + error 503 diff --git a/werc/bin/contrib/tcp80 b/werc/bin/contrib/tcp80 new file mode 100755 index 0000000..ae111a0 --- /dev/null +++ b/werc/bin/contrib/tcp80 @@ -0,0 +1,7 @@ +#!/bin/rc +# For use with listen(8). +# Change paths to match your system. +# Eitdit rc-httpd/rc-httpd to match your system. +PLAN9=/usr/local/plan9 +PATH=($PATH /home/sl/www/werc/bin/contrib) +exec /home/sl/www/werc/bin/contrib/rc-httpd/rc-httpd >>[2]/var/log/rc-httpd diff --git a/werc/bin/contrib/urldecode.awk b/werc/bin/contrib/urldecode.awk new file mode 100755 index 0000000..bd791e3 --- /dev/null +++ b/werc/bin/contrib/urldecode.awk @@ -0,0 +1,39 @@ +#!/bin/awk -f +BEGIN { + hextab ["0"] = 0; hextab ["8"] = 8; + hextab ["1"] = 1; hextab ["9"] = 9; + hextab ["2"] = 2; hextab ["A"] = hextab ["a"] = 10 + hextab ["3"] = 3; hextab ["B"] = hextab ["b"] = 11; + hextab ["4"] = 4; hextab ["C"] = hextab ["c"] = 12; + hextab ["5"] = 5; hextab ["D"] = hextab ["d"] = 13; + hextab ["6"] = 6; hextab ["E"] = hextab ["e"] = 14; + hextab ["7"] = 7; hextab ["F"] = hextab ["f"] = 15; +} +{ + decoded = "" + i = 1 + len = length ($0) + while ( i <= len ) { + c = substr ($0, i, 1) + if ( c == "%" ) { + if ( i+2 <= len ) { + c1 = substr ($0, i+1, 1) + c2 = substr ($0, i+2, 1) + if ( hextab [c1] == "" || hextab [c2] == "" ) { + print "WARNING: invalid hex encoding: %" c1 c2 | "cat >&2" + } else { + code = 0 + hextab [c1] * 16 + hextab [c2] + 0 + c = sprintf ("%c", code) + i = i + 2 + } + } else { + print "WARNING: invalid % encoding: " substr ($0, i, len - i) + } + } else if ( c == "+" ) { + c = " " + } + decoded = decoded c + ++i + } + print decoded +} diff --git a/werc/bin/contrib/urlencode.awk b/werc/bin/contrib/urlencode.awk new file mode 100755 index 0000000..d4d354d --- /dev/null +++ b/werc/bin/contrib/urlencode.awk @@ -0,0 +1,126 @@ +# Taken from http://www.shelldorado.com/scripts/cmds/urlencode +########################################################################## +# Title : urlencode - encode URL data +# Author : Heiner Steven (heiner.steven@odn.de) +# Date : 2000-03-15 +# Requires : awk +# Categories : File Conversion, WWW, CGI +# SCCS-Id. : @(#) urlencode 1.4 06/10/29 +########################################################################## +# Description +# Encode data according to +# RFC 1738: "Uniform Resource Locators (URL)" and +# RFC 1866: "Hypertext Markup Language - 2.0" (HTML) +# +# This encoding is used i.e. for the MIME type +# "application/x-www-form-urlencoded" +# +# Notes +# o The default behaviour is not to encode the line endings. This +# may not be what was intended, because the result will be +# multiple lines of output (which cannot be used in an URL or a +# HTTP "POST" request). If the desired output should be one +# line, use the "-l" option. +# +# o The "-l" option assumes, that the end-of-line is denoted by +# the character LF (ASCII 10). This is not true for Windows or +# Mac systems, where the end of a line is denoted by the two +# characters CR LF (ASCII 13 10). +# We use this for symmetry; data processed in the following way: +# cat | urlencode -l | urldecode -l +# should (and will) result in the original data +# +# o Large lines (or binary files) will break many AWK +# implementations. If you get the message +# awk: record `...' too long +# record number xxx +# consider using GNU AWK (gawk). +# +# o urlencode will always terminate it's output with an EOL +# character +# +# Thanks to Stefan Brozinski for pointing out a bug related to non-standard +# locales. +# +# See also +# urldecode +########################################################################## + +PN=`basename "$0"` # Program name +VER='1.4' + +: ${AWK=awk} + +Usage () { + echo >&2 "$PN - encode URL data, $VER +usage: $PN [-l] [file ...] + -l: encode line endings (result will be one line of output) + +The default is to encode each input line on its own." + exit 1 +} + +Msg () { + for MsgLine + do echo "$PN: $MsgLine" >&2 + done +} + +Fatal () { Msg "$@"; exit 1; } + +set -- `getopt hl "$@" 2>/dev/null` || Usage +[ $# -lt 1 ] && Usage # "getopt" detected an error + +EncodeEOL=no +while [ $# -gt 0 ] +do + case "$1" in + -l) EncodeEOL=yes;; + --) shift; break;; + -h) Usage;; + -*) Usage;; + *) break;; # First file name + esac + shift +done + +LANG=C export LANG +$AWK ' + BEGIN { + # We assume an awk implementation that is just plain dumb. + # We will convert an character to its ASCII value with the + # table ord[], and produce two-digit hexadecimal output + # without the printf("%02X") feature. + + EOL = "%0A" # "end of line" string (encoded) + split ("1 2 3 4 5 6 7 8 9 A B C D E F", hextab, " ") + hextab [0] = 0 + for ( i=1; i<=255; ++i ) ord [ sprintf ("%c", i) "" ] = i + 0 + if ("'"$EncodeEOL"'" == "yes") EncodeEOL = 1; else EncodeEOL = 0 + } + { + encoded = "" + for ( i=1; i<=length ($0); ++i ) { + c = substr ($0, i, 1) + if ( c ~ /[a-zA-Z0-9.-]/ ) { + encoded = encoded c # safe character + } else if ( c == " " ) { + encoded = encoded "+" # special handling + } else { + # unsafe character, encode it as a two-digit hex-number + lo = ord [c] % 16 + hi = int (ord [c] / 16); + encoded = encoded "%" hextab [hi] hextab [lo] + } + } + if ( EncodeEOL ) { + printf ("%s", encoded EOL) + } else { + print encoded + } + } + END { + #if ( EncodeEOL ) print "" + } +' "$@" + diff --git a/werc/bin/contrib/webserver.rc b/werc/bin/contrib/webserver.rc new file mode 100755 index 0000000..8044565 --- /dev/null +++ b/werc/bin/contrib/webserver.rc @@ -0,0 +1,30 @@ +#!/bin/rc + +# A web server in rc by maht +# Originally from http://www.proweb.co.uk/~matt/rc/webserver.rc + +ifs=' ' +request=`{sed 1q} + +url=$request(2) +file=`{echo $url | sed 's/http:\/\/[^\/]*//' | tr -d \012} + +if(test -d $file){ + file=$file ^'/index.html' +} +if(test -e $file) { + response='200' +} +if not { + response='404' + file='404.html' +} + +echo 'HTTP/1.1 ' ^$response +echo 'Date: ' `{date} +echo 'Server: rc shell' +echo 'Content-Length: ' `{cat $file | wc -c | tr -d ' '} +echo 'Content-Type: ' `{file -i $file | awk '{ print $2 }'} +echo 'Connection: close' +echo +cat $file diff --git a/werc/bin/corehandlers.rc b/werc/bin/corehandlers.rc new file mode 100755 index 0000000..a43e5b9 --- /dev/null +++ b/werc/bin/corehandlers.rc @@ -0,0 +1,157 @@ +# Werc builtin handlers + +fn nav_tree { + if(! ~ $#sideBarNavTitle 0) + echo '

    '$"sideBarNavTitle':

    ' + # Ignore stderr, last path element might be a file that doesn't exist (eg., foo for foo.md) + # /./ to deal with p9p's ls failure to follow dir symlinks otherwise + ls -F $sitedir/./$req_paths_list >[2]/dev/null \ + | { + sed $dirfilter'/\/[^_.\/][^\/]*(\.(md|txt|html)|\/)$/!d; s!^'$sitedir'!!; '$dirclean + if(! ~ $#synth_paths 0) echo $synth_paths | tr ' ' $NEW_LINE + } | sort -u | awk -F/ ' + function p(x, y, s) { for(i=0; i < x-y; i+=1) print s } + BEGIN { lNF=2; print "
    • home
    • " } + { + d = "" + if(match($0, "/$")) + d = "/" + sub("/$", "") # Strip trailing / for dirs so NF is consistent + + p(NF, lNF, "
      • ") + p(lNF, NF, "
    • ") + lNF = NF + + bname = $NF d + path = $0 d + gsub(/[\-_]/, " ", bname) + + # To avoid false matches add trailing / even for plain files to act as delimiter + pa = path + gsub(/[^\/]$/, "&/", pa) + + if(index(ENVIRON["req_path"] "/", pa) == 1) + print "
    • » " bname "
    • " + else + print "
    • " bname "
    • " + } + END { p(lNF, 2, "
    "); print "" }' +} + +fn link_bar { + if(~ $1 -t) { + echo '

    '$2'

    ' + shift; shift + } + echo '
      ' + while(! ~ $#* 0) { + echo '
    • - '$1'
    • ' + shift; shift + } + echo '
    ' +} + +fn md_handler { $formatter $1 } + +fn tpl_handler { template $* } + +fn html_handler { + # body states: 0 = no found, 2 = after , 1 = after , -1 = after + awk 'gsub(".*<[Bb][Oo][Dd][Yy][^>]*>", "") > 0 {body=2} + gsub("]*>.*", "") > 0 {print; body=body-1} + body==2 {print} + body==0 {buf=buf "\n" $0} + END {if(body<=0) {print buf}}' < $1 +} + +fn txt_handler { + # Note: Words are not broken, even if they are way beyond 82 chars long + echo '
    '
    +    sed 's//\>/g' < $1 | fmt -l 82 -j
    +    echo '
    ' +} + +fn dir_listing_handler { + d=`{basename -d $1} + if(~ $#d 0) + d='/' + echo $d|sed 's,.*//,,g; s,/$,,; s,/, / ,g; s,.*,

    &

      ,' + # Symlinks suck: '/.' forces ls to list the linked dir if $d is a symlink. + ls -F $dir_listing_ls_opts $sitedir$d/. | sed $dirfilter$dirclean' s,.*/([^/]+/?)$,
    • \1
    • ,' + echo '
    ' +} + +fn notices_handler { + for(type in notify_errors notify_notes notify_success) + for(n in $$type) + echo '
    '$"n'
    ' +} + +fn setup_handlers { + + if(test -f $local_path.md) { + local_file=$local_path.md + handler_body_main=(md_handler $local_file) + } + if not if(test -f $local_path.tpl) { + local_file=$local_path.tpl + handler_body_main=(tpl_handler $local_file) + } + if not if(test -f $local_path.html) { + local_file=$local_path.html + handler_body_main=(html_handler $local_file) + } + # Global tpl (eg sitemap.tpl), should take precedence over txt handler! + if not if(test -f tpl^$req_path^.tpl) + # XXX Should we set $local_file for global .tpls? + handler_body_main=(tpl_handler tpl^$req_path^.tpl) + if not if(test -f $local_path.txt) { + local_file=$local_path.txt + handler_body_main=(txt_handler $local_file) + } + + # XXX Should check that $enabled_apps exist in $werc_apps? + # XXX Should split init of apps that provide main handler (eg., blog) and apps that don't (eg., comments)? + if(! ~ $#enabled_apps 0) + for(a in $enabled_apps) + $a^'_init' + + if(! ~ $#handler_body_main 0) { + # WE ARE NOT DONE I WANT MY HEADERS + if(test -f $sitedir$req_path'_header.md') + ll_add handlers_body_head md_handler $sitedir$req_path'_header.md' + if(test -f $sitedir$req_path'_footer.md') + ll_add handlers_body_foot md_handler $sitedir$req_path'_footer.md' + } # We are done + # Dir listing + if not if(~ $local_path */index) { + handler_body_main=(dir_listing_handler $req_path) + if(test -f $sitedir$req_path'_header.md') + ll_add handlers_body_head md_handler $sitedir$req_path'_header.md' + if(test -f $sitedir$req_path'_footer.md') + ll_add handlers_body_foot md_handler $sitedir$req_path'_footer.md' + } + # Canonize explicit .html urls, the web server might handle this first! + if not if(~ $local_path *.html && test -f $local_path) + perm_redirect `{ echo $req_path|sed 's/.html$//' } + # Fallback static file handler + if not if(test -f $local_path) + static_file $local_path + if not if(~ $req_path /pub/* && test -f .$req_path) + static_file .$req_path + # File not found + if not + setup_404_handler +} + +# This function allows config files to define their own 404 handlers. +fn setup_404_handler { + handler_body_main=(tpl_handler `{get_lib_file 404.tpl}) + echo 'Status: 404 Not Found' + dprint 'NOT FOUND: '$SERVER_NAME^$"REQUEST_URI^' - '^$"HTTP_REFERER^' - '^$"HTTP_USER_AGENT +} + +fn run_handlers { for(h in $*) run_handler $$h } +fn run_handler { $*(1) $*(2-) } + + diff --git a/werc/bin/fltr_cache.rc b/werc/bin/fltr_cache.rc new file mode 100755 index 0000000..9394724 --- /dev/null +++ b/werc/bin/fltr_cache.rc @@ -0,0 +1,37 @@ +#!/bin/rc + +fn fltr_cache { + a=() + tmpf=() + + proc=$1 + shift + + if(~ $#* 0) { + tmpf=/tmp/fmttmp.$pid + f=$tmpf + score=`{{tee $tmpf || exit 1} | sha1sum} + } + if not { + f=$1 + if(~ $f */) { + score=`{du -an $f | sha1sum || exit 1} # XXX using -n(bytes) instead of -t(lastmod) because sitemap proc touches files in tree. + a=$f + f=/dev/null + } + if not { + score=`{sha1sum $f || exit 1} + score=$score(1) + } + } + cachedir=/tmp/fltr_cache/$score + mkdir -p $cachedir >[2]/dev/null + + if(test -s $cachedir/$proc) + cat $cachedir/$proc + if not + if($proc $a < $f | tee $cachedir/$pid) + mv $cachedir/$pid $cachedir/$proc + + rm $tmpf $cachedir/$pid >[2]/dev/null & +} diff --git a/werc/bin/template.awk b/werc/bin/template.awk new file mode 100755 index 0000000..8f02ebb --- /dev/null +++ b/werc/bin/template.awk @@ -0,0 +1,55 @@ +#!/bin/awk -f +function pr(str) { + if(lastc !~ "[{(]") + gsub(/'/, "''", str) + printf "%s", str +} +function trans(c) { + printf "%s", end + + lastc = c + end = "\n" + if(c == "%") + end = "" + else if(c == "(") + printf "echo -n " + else if(c ~ "[})]") { + end = "'\n" + printf "echo -n '" + } +} + +BEGIN { + lastc = "{" + trans("}") +} +END { + print end +} + +/^%/ && $0 !~ /^%[{()}%]/ && lastc !~ /[({]/ { + trans("%") + print substr($0, 2) + next +} +{ + if(lastc == "%") + trans("}") + n = split($0, a, "%") + pr(a[1]) + for(i=2; i<=n; i++) { + c = substr(a[i], 1, 1) + rest = substr(a[i], 2) + + if((lastc !~ "[({]" && c ~ "[({]") || + (lastc == "{" && c == "}") || + (lastc == "(" && c == ")")) + trans(c) + else if(c == "%") + pr("%") + else + pr("%" c) + pr(rest) + } + pr("\n") +} diff --git a/werc/bin/werc.rc b/werc/bin/werc.rc new file mode 100755 index 0000000..0d006a3 --- /dev/null +++ b/werc/bin/werc.rc @@ -0,0 +1,138 @@ +#!/bin/rc +. ./cgilib.rc +. ./werclib.rc +. ./wercconf.rc +. ./corehandlers.rc +. ./fltr_cache.rc +cd .. + +forbidden_uri_chars='[^a-zA-Z0-9_+\-\/\.,:]' +difs=$ifs # Used to restore default ifs when needed + +# Expected input: ls -F style, $sitedir/path/to/files/ +# +dirfilter='s/\*$//; s,/+\./+,/,g; s,^\./,,; /\/[._][^\/]/d; /'$forbidden_uri_chars'/d; /\/sitemap\.xml$/d; /\/index\.(md|html|txt|tpl)$/d; /\/(robots|sitemap)\.txt$/d; /_werc\/?$/d; ' +dirclean=' s/\.(md|html|txt)$//; ' + +# Careful, the proper p9p path might not be set until initrc.local is sourced +path=(. /bin ./bin) + +res_tail='' +http_content_type='text/html' +ll_add handlers_bar_left nav_tree +werc_apps=( apps/* ) +werc_root=`{pwd} +sitesdir=sites + + . ./etc/initrc + +if(test -f etc/initrc.local) + . ./etc/initrc.local + +for(a in $werc_apps) + . ./$a/app.rc + +fn werc_exec_request { + site=$SERVER_NAME + base_url=http://$site:$SERVER_PORT + sitedir=$sitesdir/$site + headers=`{get_lib_file headers.tpl} + master_template=`{get_lib_file default_master.tpl} + current_date_time=`{date} + + # Note: $REQUEST_URI is not officially in CGI 1.1, but seems to be de-facto + # Note: We only urldecode %5F->'_' because some sites (stackoverflow.com?) urlencode it in their links, + # perhaps we should completel urldecode the whole url. + req_path=`{echo -n $REQUEST_URI | sed 's/\?.*//; s!//+!/!g; s/%5[Ff]/_/g; s/'^$forbidden_uri_chars^'//g; s/\.\.*/./g; 1q'} + req_url=$base_url^$req_path + local_path=$sitedir$req_path + local_file='' + ifs='/' { args=`{echo -n $req_path} } + + # Preload post args for templates where cgi's stdin is not accessible + if(~ $REQUEST_METHOD POST) { + load_post_args + login_user + } + + if(~ $req_path */index) + perm_redirect `{echo $req_path | sed 's,/index$,/,'} + + if(~ $local_path */) { + if(test -d $local_path) + local_path=$local_path^'index' + # XXX: This redir might step on apps with synthetic dirs. + if not if(ls `{basename -d $local_path}^* >/dev/null >[2]/dev/null) + perm_redirect `{echo $req_path|sed 's,/+$,,'} + } + if not if(~ $req_path *'.' *',' *';' *':') + perm_redirect `{echo $req_path | sed 's/[.,;:)]$//'} + if not if(test -d $local_path) + perm_redirect $req_path^'/' + + if(! ~ $#args 0) + ifs=$NEW_LINE { pageTitle=`{ echo $args|sed -e 's/ / - /g' -e 's/([a-z])-([a-z])/\1 \2/g' -e 's/_/ /g' } } + + cd $sitedir + req_paths_list='/' # Note: req_paths_list doesn't include 'stnythetic' dirs. + conf_wd='/' # Used in config files to know where we are in the document tree. + if(test -f _werc/config) + . _werc/config + for(i in $args) { + conf_wd=$conf_wd^$i + req_paths_list=($req_paths_list $conf_wd) + if(test -d $i) { + conf_wd=$conf_wd'/' + cd $i + if(test -f _werc/config) + . _werc/config + } + } + cd $werc_root + + if(~ $#perm_redir_to 1) + perm_redirect $perm_redir_to + for(l in $perm_redir_patterns) { + p=$$l + r=$p(1) + # If target is absolute, then patern must match whole string + if(~ $p(2) http://* https://*) + r='^'$r + t=`{ echo $req_path | sed 's!'^$r^'!'^$p(2)^'!' } # Malicious danger! + + if(! ~ $"t '' $req_path) + perm_redirect $t + } + + setup_handlers + + + # Set Page title + if(! ~ $local_file '') { + t=`{get_file_title $local_file} + if(! ~ $"t '') + pageTitle=$t + } + + # XXX Is this never true? because we set pageTitle earlier based on url. + if(~ $"pageTitle '') + pageTitle=$"siteTitle' '$"siteSubTitle +# if not +# pageTitle=$"pageTitle' | '$"siteTitle' '$"siteSubTitle + + for(h in $extraHttpHeaders) + echo $h + echo Content-Type: $http_content_type + echo # End of HTTP headers + + if(! ~ $#debug 0) + dprint $"SERVER_NAME^$"REQUEST_URI - $"HTTP_USER_AGENT - $"REQUEST_METHOD - $"handler_body_main - $"master_template + + if(~ $REQUEST_METHOD HEAD) + exit + + template $headers $master_template # | awk_buffer + echo $res_tail +} + +werc_exec_request diff --git a/werc/bin/werc_errlog_wrap.rc b/werc/bin/werc_errlog_wrap.rc new file mode 100755 index 0000000..94bd18f --- /dev/null +++ b/werc/bin/werc_errlog_wrap.rc @@ -0,0 +1,5 @@ +#!/bin/rc + +# This is a wrapper script for broken http servers like recent lighttpd versions which throw away cgi's stderr. + +./werc.rc >>[2]/tmp/wlog.txt diff --git a/werc/bin/wercconf.rc b/werc/bin/wercconf.rc new file mode 100755 index 0000000..bb3422d --- /dev/null +++ b/werc/bin/wercconf.rc @@ -0,0 +1,19 @@ +# To be used from config files +fn conf_perm_redirect { + if(~ $#* 1) + perm_redir_to=$1 + if not + ll_addh perm_redir_patterns $1 $2 +} + +fn conf_hide_paths { + for(i in $*) + dirfilter=$dirfilter^'/'^`{echo $sitedir$conf_wd$i|sed 's!/+!\\/!g'}^'/d; ' +} + +# Usually will be called from within conf_enable_foo +fn conf_enable_app { + # Note: maybe we should add test -d apps/$1/? + if(! ~ $1 $enabled_apps) + enabled_apps=( $enabled_apps $1 ) +} diff --git a/werc/bin/werclib.rc b/werc/bin/werclib.rc new file mode 100755 index 0000000..bcebf91 --- /dev/null +++ b/werc/bin/werclib.rc @@ -0,0 +1,393 @@ +fn get_lib_file { + if(! ~ $#sitedir 0 && test -f $sitedir/_werc/lib/$1) + echo -n $sitedir/_werc/lib/$1 + if not if(! ~ $#masterSite 0 && test -f $sitesdir/$masterSite/_werc/lib/$1) + echo -n $sitesdir/$masterSite/_werc/lib/$1 + if not if(test -f lib/$1) + echo -n lib/$1 + if not if(~ $#* 2) + echo -n $2 + if not + status='Can''t find lib file: '$1 +} + +fn template { awk -f bin/template.awk $* | rc $rcargs } + +# Auth code +# TODO: check http://cookies.lcs.mit.edu/pubs/webauth:tr.pdf +allowed_user_chars='[a-zA-Z0-9_]' +# Cookie format: WERC_USER: name:timestamp:hash(name.timestamp.password) +# login_user can't be used from a template because it sets a cookie +fn login_user { + # Note: we set the cookie even if it is already there. + if(get_user $*) + set_cookie werc_user $"logged_user^':0:'^$"logged_password +} + +# Check login status, if called with group arg we check membership too +fn check_user { + get_user + g=($* admin) + _status=$status + if(! ~ $"_status '') + _status=(Not logged in: $"_status) + if not if(! ~ $#* 0 && ! ~ $logged_user $* && ! grep -s '^'^$logged_user^'$' $werc_root/etc/users/$g/members >[2]/dev/null) + _status=(User $logged_user not in: $*) + status=$_status +} + +# If not logged in, try to get user login info from POST or from cookie +fn get_user { + if(~ $#logged_user 0) { + if(~ $#* 2) { + user_name=$1 + user_password=$2 + } + if not if(~ $REQUEST_METHOD POST) + get_post_args user_name user_password + + if(~ $#user_name 0) { + ifs=':' { cu=`{ifs=$difs {get_cookie werc_user} | tr -d $NEW_LINE} } + if(! ~ $#cu 0) { + user_name=$cu(1) + user_password=$cu(3) + } + } + auth_user $user_name $user_password + } + if not + status=() +} + +# Check if user_name and user_password represent a valid user account +# If valid, 'log in' by setting logged_user +fn auth_user { + user_name=$1 + user_password=$2 + + pfile=$werc_root/etc/users/$"user_name/password + if(~ $#user_name 0 || ~ $#user_password 0) + status=('Auth: missing user name or pass: '^$"user_name^' / '^$"user_password) + if not if(! test -f $pfile) + status=('Auth: cant find '^$pfile) + if not if(! test -s $pfile || ! ~ $user_password `{cat $pfile}) + status=('Auth: Pass '$user_password' doesnt match '^`{cat $pfile}) + if not { + logged_user=$user_name + logged_password=$user_password + dprint Auth: success + status=() + } +} + +fn user_controls { + echo User: $"logged_user +} + + +# .md '(meta-)data' extract +fn get_md_file_attr { + sed -n '/^\* '$2': /p; /^\* '$2': /q; /^$/q' < $1 +} + + +# File title extraction +fn get_md_title { + #sed 's/^(................................................................[^ ]*).*$/\1/g; 1q' < $1 + sed -n -e '1N; /^.*\n===*$/N; /.*\n===*\n *$/!b' -e 's/\n==*\n//p' < $1 +} + +fn get_html_title { + t=`{sed -n '32q; s/^.*<[Tt][Ii][Tt][Ll][Ee]> *([^<]+) *(<\/[Tt][Ii][Tt][Ll][Ee]>.*)?$/\1/p' < $1} + + # As a backup we might want to pick the first 'non-tag' text in the file with: + if(~ $"t '') + t=`{sed -n -e 's/^(<[^>]+>)*([^<]+).*/\2/p; 32q' < $1 | sed 1q} + + echo $t +} + +fn get_file_title { + if (~ $1 *.md) + get_md_title $1 + if not if(~ $1 *.html) + get_html_title $1 + if not if(~ $1 */) { + if(test -f $1/index.md) + get_md_title $1/index.md + if not if(test -f $1/index.html) + get_html_title $1/index.html + } +} + +fn ndate { + if(~ $#* 7) + date=$*(2-) + if not + date=`{date} + switch($date(2)){ + case Jan; mo=01 + case Feb; mo=02 + case Mar; mo=03 + case Apr; mo=04 + case May; mo=05 + case Jun; mo=06 + case Jul; mo=07 + case Aug; mo=08 + case Sep; mo=09 + case Oct; mo=10 + case Nov; mo=11 + case Dec; mo=12 + } + switch($date(3)){ + case [0-9] + da=0^$date(3) + case * + da=$date(3) + } + switch($date(5)){ + case A; tz=+0100 + case ADT; tz=-0300 + case AFT; tz=+430 + case AKDT; tz=-0800 + case AKST; tz=-0900 + case ALMT; tz=+0600 + case AMST; tz=-0300 + case AMT; tz=-0400 + case ANAST; tz=+1200 + case ANAT; tz=+1200 + case AQTT; tz=+0500 + case ART; tz=-0300 + case AST; tz=-0400 + case AZOST; tz=+0000 + case AZOT; tz=-0100 + case AZST; tz=+0500 + case AZT; tz=+0400 + case B; tz=+0200 + case BNT; tz=+0800 + case BOT; tz=-0400 + case BRST; tz=-0200 + case BRT; tz=-0300 + case BST; tz=+0100 + case BTT; tz=+0600 + case C; tz=+0300 + case CAST; tz=+0800 + case CAT; tz=+0200 + case CCT; tz=+0630 + case CDT; tz=-0500 + case CEST; tz=+0200 + case CET; tz=+0100 + case CHADT; tz=+1345 + case CHAST; tz=+1245 + case CKT; tz=-1000 + case CLST; tz=-0300 + case CLT; tz=-0400 + case COT; tz=-0500 + case CST; tz=-0600 + case CVT; tz=-0100 + case CXT; tz=+0700 + case ChST; tz=+1000 + case D; tz=+0400 + case DAVT; tz=+0700 + case E; tz=+0500 + case EASST; tz=-0500 + case EAST; tz=-0600 + case EAT; tz=+0300 + case ECT; tz=-0500 + case EDT; tz=-0400 + case EEST; tz=+0300 + case EET; tz=+0200 + case EGST; tz=+0000 + case EGT; tz=-0100 + case EST; tz=-0500 + case ET; tz=-0500 + case F; tz=+0600 + case FJST; tz=+1300 + case FJT; tz=+1200 + case FKST; tz=-0300 + case FKT; tz=-0400 + case FNT; tz=-0200 + case G; tz=+0700 + case GALT; tz=-0600 + case GAMT; tz=-0900 + case GET; tz=+0400 + case GFT; tz=-0300 + case GILT; tz=+1200 + case GMT; tz=+0000 + case GST; tz=+0400 + case GYT; tz=-0400 + case H; tz=+0800 + case HAA; tz=-0300 + case HAC; tz=-0500 + case HADT; tz=-0900 + case HAE; tz=-0400 + case HAP; tz=-0700 + case HAR; tz=-0600 + case HAST; tz=-1000 + case HAT; tz=-0230 + case HAY; tz=-0800 + case HKT; tz=+0800 + case HLV; tz=-0430 + case HNA; tz=-0400 + case HNC; tz=-0600 + case HNE; tz=-0500 + case HNP; tz=-0800 + case HNR; tz=-0700 + case HNT; tz=-0330 + case HNY; tz=-0900 + case HOVT; tz=+0700 + case I; tz=+0900 + case ICT; tz=+0700 + case IDT; tz=+0300 + case IOT; tz=+0600 + case IRDT; tz=+0430 + case IRKST; tz=+0900 + case IRKT; tz=+0800 + case IRST; tz=+0330 + case IST; tz=+0200 + case JST; tz=+0900 + case K; tz=+1000 + case KGT; tz=+0600 + case KRAST; tz=+0800 + case KRAT; tz=+0700 + case KST; tz=+0900 + case KUYT; tz=+0400 + case L; tz=+1100 + case LHDT; tz=+1100 + case LHST; tz=+1030 + case LINT; tz=+1400 + case M; tz=+1200 + case MAGST; tz=+1200 + case MAGT; tz=+1100 + case MART; tz=-0930 + case MAWT; tz=+0500 + case MDT; tz=-0600 + case MHT; tz=+1200 + case MMT; tz=+0630 + case MSD; tz=+0400 + case MSK; tz=+0300 + case MST; tz=-0700 + case MUT; tz=+0400 + case MVT; tz=+0500 + case MYT; tz=+0800 + case N; tz=-0100 + case NCT; tz=+1100 + case NDT; tz=-0230 + case NFT; tz=+1130 + case NOVST; tz=+0700 + case NOVT; tz=+0600 + case NPT; tz=+0545 + case NST; tz=-0330 + case NUT; tz=-1100 + case NZDT; tz=+1300 + case NZST; tz=+1200 + case O; tz=-0200 + case OMSST; tz=+0700 + case OMST; tz=+0600 + case P; tz=-0300 + case PDT; tz=-0700 + case PET; tz=-0500 + case PETST; tz=+1200 + case PETT; tz=+1200 + case PGT; tz=+1000 + case PHOT; tz=+1300 + case PHT; tz=+0800 + case PKT; tz=+0500 + case PMDT; tz=-0200 + case PMST; tz=-0300 + case PONT; tz=+1100 + case PST; tz=-0800 + case PT; tz=-0800 + case PWT; tz=+0900 + case PYST; tz=-0300 + case PYT; tz=-0400 + case Q; tz=-0400 + case R; tz=-0500 + case RET; tz=+0400 + case S; tz=-0600 + case SAMT; tz=+0400 + case SAST; tz=+0200 + case SBT; tz=+1100 + case SCT; tz=+0400 + case SGT; tz=+0800 + case SRT; tz=-0300 + case SST; tz=-1100 + case T; tz=-0700 + case TAHT; tz=-1000 + case TFT; tz=+0500 + case TJT; tz=+0500 + case TKT; tz=-1000 + case TLT; tz=+0900 + case TMT; tz=+0500 + case TVT; tz=+1200 + case U; tz=-0800 + case ULAT; tz=+0800 + case UYST; tz=-0200 + case UYT; tz=-0300 + case UZT; tz=+0500 + case V; tz=-0900 + case VET; tz=-0430 + case VLAST; tz=+1100 + case VLAT; tz=+1000 + case VUT; tz=+1100 + case W; tz=-1000 + case WAST; tz=+0200 + case WAT; tz=+0100 + case WDT; tz=+0900 + case WEST; tz=+0100 + case WET; tz=+0000 + case WFT; tz=+1200 + case WGST; tz=-0200 + case WGT; tz=-0300 + case WIB; tz=+0700 + case WIT; tz=+0900 + case WITA; tz=+0800 + case WST; tz=+0800 + case WT; tz=+0000 + case X; tz=-1100 + case Y; tz=-1200 + case YAKST; tz=+1000 + case YAKT; tz=+0900 + case YAPT; tz=+1000 + case YEKST; tz=+0600 + case YEKT; tz=+0500 + case Z; tz=+0000 + } + switch($1){ + case -a # rfc3339 + tz=`{echo $tz | sed 's/00$/:00/'} + echo $date(6)^-$mo-$da^T^$date(4)^$tz + case -i # iso-8601 lite + echo $date(6)^-$mo-$da + case -m # rfc2822 + echo $date(1)^, $da $date(2) $date(6) $date(4) $tz + case -t # iso-8601 + echo $date(6)^-$mo-$da^T^$date(4)^$tz + } +} + +########################################################################## +########################################################################## +#app_blog_methods = ( _post index.rss ) +#fn app_blog__post { +# echo +#} +# +#app_blog___default { +# if (~ $blog) +# call_app blogpost +#} +# +## -- +#app_blogpost_methods = ( comment _edit ) +# +#fn app_blogpost_comment { +# call_app comments +#} +# +## -- +#app_comments_methods = ( _post _edit ) +# +#fn app_comments___default { +# +#} diff --git a/werc/lib/404.tpl b/werc/lib/404.tpl new file mode 100644 index 0000000..f839439 --- /dev/null +++ b/werc/lib/404.tpl @@ -0,0 +1,3 @@ +

    The requested document at '%($base_url$"req_path%)' doesn't exist

    +

    Or take a look at the sitemap.

    +
    diff --git a/werc/lib/default_master.tpl b/werc/lib/default_master.tpl new file mode 100644 index 0000000..abf89c5 --- /dev/null +++ b/werc/lib/default_master.tpl @@ -0,0 +1,26 @@ +
    +

    %($"siteTitle%)
    [ %($"siteSubTitle%) ]

    + +
    + +% if(! ~ $#handlers_bar_left 0) { + +% } + +
    +% run_handlers $handlers_body_head +% run_handler $handler_body_main +% run_handlers $handlers_body_foot +
    + +
    +% cat `{ get_lib_file footer.inc } +
    diff --git a/werc/lib/footer.inc b/werc/lib/footer.inc new file mode 100644 index 0000000..1eac7d8 --- /dev/null +++ b/werc/lib/footer.inc @@ -0,0 +1,7 @@ + + + diff --git a/werc/lib/headers.tpl b/werc/lib/headers.tpl new file mode 100644 index 0000000..3b82e09 --- /dev/null +++ b/werc/lib/headers.tpl @@ -0,0 +1,30 @@ + + + + + %($pageTitle%) + + + +% if(test -f $sitedir/_werc/pub/style.css) +% echo ' ' + + +% # Legacy charset declaration for backards compatibility with non-html5 browsers. + + + +% if(! ~ $#meta_description 0) +% echo ' ' +% if(! ~ $#meta_keywords 0) +% echo ' ' + +% h = `{get_lib_file headers.inc} +% if(! ~ $#h 0) +% cat $h + + %($"extraHeaders%) + + + + diff --git a/werc/lib/top_bar.inc b/werc/lib/top_bar.inc new file mode 100644 index 0000000..cbb89b8 --- /dev/null +++ b/werc/lib/top_bar.inc @@ -0,0 +1,15 @@ + + + + diff --git a/werc/pub/default_favicon.ico b/werc/pub/default_favicon.ico new file mode 100755 index 0000000..817f5fa Binary files /dev/null and b/werc/pub/default_favicon.ico differ diff --git a/werc/pub/style/imgs/back.jpeg b/werc/pub/style/imgs/back.jpeg new file mode 100644 index 0000000..2d8cb67 Binary files /dev/null and b/werc/pub/style/imgs/back.jpeg differ diff --git a/werc/pub/style/imgs/sgl.png b/werc/pub/style/imgs/sgl.png new file mode 100755 index 0000000..d68580e Binary files /dev/null and b/werc/pub/style/imgs/sgl.png differ diff --git a/werc/pub/style/imgs/tc.png b/werc/pub/style/imgs/tc.png new file mode 100644 index 0000000..2548b0c Binary files /dev/null and b/werc/pub/style/imgs/tc.png differ diff --git a/werc/pub/style/sinorca-screen-alt.css b/werc/pub/style/sinorca-screen-alt.css new file mode 100755 index 0000000..d11e9ad --- /dev/null +++ b/werc/pub/style/sinorca-screen-alt.css @@ -0,0 +1,292 @@ +/*********************************************** + * TITLE: Sinorca Alterative Screen Stylesheet * + * URI : sinorca/sinorca-screen-alt.css * + * MODIF: 2003-May-13 18:48 +0800 * + ***********************************************/ + + +/* ##### Common Styles ##### */ + +body { + color: black; + background-color: white; + font-family: verdana, helvetica, arial, sans-serif; + font-size: 71%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} + +html > body { + font-size: 8.5pt; +} + +acronym, .titleTip { + border-bottom: 1px dotted rgb(153,153,153); + cursor: help; + margin: 0; + padding: 0 0 0.4px 0; +} + +.doNotDisplay { + display: none; +} + +.smallCaps { + font-size: 110%; + font-variant: small-caps; +} + + +/* ##### Header ##### */ + +.superHeader { + color: white; + background-color: rgb(100,135,220); + height: 2em; +} + +.superHeader a { + color: white; + background-color: transparent; + text-decoration: none; + font-size: 91%; + margin: 0; + padding: 0 0.5ex 0 0.25ex; +} + +.superHeader a:hover { + text-decoration: underline; +} + +.superHeader .left { + position: absolute; + left: 1.5mm; + top: 0.75ex; +} + +.superHeader .right { + position: absolute; + right: 1.5mm; + top: 0.75ex; +} + +.midHeader { + color: rgb(39,78,144); + background-color: rgb(140,170,230); +} + +.headerTitle { + font-size: 337%; + font-weight: normal; + margin: 0 0 0 4mm; + padding: 0.25ex 0; +} + +.subHeader { + color: white; + background-color: rgb(0,51,153); + margin: 0; + padding: 1ex 1ex 1ex 1.5mm; +} + +.subHeader a { + color: white; + background-color: transparent; + text-decoration: none; + font-weight: bold; + margin: 0; + padding: 0 0.75ex 0 0.5ex; +} + +.subHeader a:hover { + text-decoration: underline; +} + +.superHeader .highlight, .subHeader .highlight { + color: rgb(253,160,91); + background-color: transparent; +} + + +/* ##### Side Boxes ##### */ + +#side-bar { + width: 14em; + margin: 2.5em 0 0 1.25mm; + float: left; + clear: left; +} + +body > #side-bar { + margin-left: 2.5mm; /* Circumvents a rendering bug in MSIE (6.0) */ +} + +.sideBarTitle { + color: white; + background-color: rgb(100,135,220); + font-weight: bold; + margin: 0; + padding: 0.4ex 0 0.4ex 0.6ex; +} + +#side-bar ul { + list-style-type: none; + list-style-position: outside; + margin: 0; + padding: 0 0 2.25em 0; +} + +#side-bar li { + margin: 0; + padding: 0.1ex 0; /* Circumvents a rendering bug (?) in MSIE (6.0) */ +} + +#side-bar a, .thisPage { + color: rgb(0,102,204); + background-color: transparent; + text-decoration: none; + font-weight: bold; + margin: 0; + padding: 1.3ex 2ex; + display: block; +} + +.thisPage { + color: black; + background-color: transparent; +} + +#side-bar a:hover { + color: white; + background-color: rgb(100,135,220); + text-decoration: none; +} + +.sideBarText { + line-height: 1.5em; + margin: 0 0 2.5em 0; + padding: 1ex 0.5ex 0 0.5ex; + display: block; +} + +.sideBarText + .sideBarText { /* Not recognised by MSIE (6.0) */ + margin-top: -1.5em; +} + +#side-bar .sideBarText a { + text-decoration: underline; + font-weight: normal; + margin: 0; + padding: 0; + display: inline; +} + +#side-bar .sideBarText a:hover { + color: rgb(0,102,204); + background-color: transparent; + text-decoration: none; +} + + +/* ##### Main Copy ##### */ + +#main-copy { + color: black; + background-color: transparent; + text-align: justify; + line-height: 1.5em; + margin: -1em 0 0 15em; + padding: 0.5mm 5mm 5mm 5mm; +} + +#bodyText { + margin: 0 0 0 15.5em; + padding: 2mm 5mm 2mm 5mm; +} + + +#main-copy p { + margin: 1em 1ex 2em 1ex; + padding: 0; +} + +#main-copy a { + color: rgb(0,102,204); + background-color: transparent; + text-decoration: underline; +} + +#main-copy a:hover { + text-decoration: none; +} + +#main-copy h1 { + color: rgb(0,102,204); + background-color: transparent; + font-size: 145.5%; + font-weight: bold; + margin: 2em 0 0 0; + padding: 0.5ex 0 0.5ex 0.6ex; + border-bottom: 1px solid rgb(0,102,204); +} + +#main-copy .topOfPage { + color: rgb(0,102,204); + background-color: transparent; + font-size: 91%; + font-weight: bold; + text-decoration: none; + margin: 3ex 1ex 0 0; + padding: 0; + float: right; +} + +dl { + margin: 1em 1ex 2em 1ex; + padding: 0; +} + +dt { + font-weight: bold; + margin: 0 0 0 0; + padding: 0; +} + +dd { + margin: 0 0 2em 2em; + padding: 0; +} + + +/* ##### Footer ##### */ + +#footer { + color: white; + background-color: rgb(100,135,220); + font-size: 91%; + margin: 0; + padding: 1em 2.5mm 2.5ex 2.5mm; + clear: both; +} + +#footer .left { + text-align: left; + line-height: 1.45em; + float: left; + clear: left; +} + +#footer .right { + text-align: right; + line-height: 1.45em; +} + +#footer a { + color: white; + background-color: transparent; + text-decoration: underline; +} + +#footer a:hover { + text-decoration: none; +} \ No newline at end of file diff --git a/werc/pub/style/style.css b/werc/pub/style/style.css new file mode 100644 index 0000000..4d60b5f --- /dev/null +++ b/werc/pub/style/style.css @@ -0,0 +1,377 @@ +body { display: flex; flex-wrap: wrap; font-family: sans; } +header { flex-basis: 100%; flex-shrink: 0; } +article { flex-basis: 60%; padding-left: 1em; } +footer { flex-basis: 100%; flex-shrink: 0; } +header nav { display: flex; justify-content: space-between; } +nav a, header a { text-decoration: none ; color: inherit; } +header h1 span { margin-left: 1em; font-size: 50%; font-style: italic; } +body > nav { flex-basis: content; padding-right: 1vw; min-width: 16em; } +nav ul { display: flex; flex-direction: column; list-style-type: none; list-style-position: outside; padding-left: 0; } +nav li ul { padding-left: 0.6em } +footer { display: flex; justify-content: space-between; } + +:root { + --alt-accent2: #C0CEE8ff; + --primary-accent: #AEA3F0ff; + --rebecca-purple: #5B3D8Aff; + --primary-dark: #0C072Cff; + --alt-accent: #989898ff; + --back-secondary: #1C202Fff; + --back-primary: #000300ff; + --primary: #E4F0FEff; + --white: white; + --secondary-accent: #A4D1ADff; + --link: #2667deff; + --code: #18A02Cff; +} + +body { + background: + linear-gradient(to right, rgba(0, 5, 10, 0.9), rgba(0, 5, 5, 0.9)), + url('imgs/back.jpeg'), + var(--back-primary); + background-color: var(--back-primary); + background-position: center center; + background-size: 110vh 75vh; + background-repeat: repeat-y; + margin: 0; + padding: 0; + font-size: 84%; + font-family: verdana, helvetica, arial, sans-serif; +} + +a { + text-decoration: none; + color: var(--link); +} + +a:hover { + text-decoration: underline; +} + +/* header and top bar */ +header nav { + background-color: var(--primary-accent); + color: var(--primary-dark); + border-bottom: 3px solid var(--primary-dark); + padding: 0.3em; + font-size: 91%; +} + +header h1 { + display: flex; + background-color: var(--back-secondary); + color: var(--primary); + margin: 0; + border-bottom: 3px solid var(--primary-dark); + font-size: 200%; + font-weight: bold; + padding: 0.5ex 0 0.5ex 0.6ex; +} + +header h1 #headerSubTitle { + display: block; + margin-left: 2em; + font-size: 40%; + color: var(--secondary-accent) +} + +header h1 .headerLink { + display: inline-block; + margin-top: 0.2ex; + margin-left: 0.6ex; +} + +header h1 a img { + width: 50px; +} + +header a:hover { + text-decoration: none; +} + +header nav a { + padding: 0.2ex 0.5ex 0.2ex; + transition: background-color 0.3s ease; +} + +header nav a:hover { + text-decoration: underline; + background-color: rgba(255, 255, 255, 0.2); +} + +header nav .right { + font-weight: bold; +} + +/* sidebar */ +body>nav { + padding: 0; + border-right: 3px solid var(--alt-accent2); +} + +body>nav>div a, +input[type="submit"] { + color: var(--secondary-accent); + display: block; + font-weight: bold; + padding: 0.25em 1ex 0.25em 2mm; + font-size: 102% +} + +body>nav>div a:hover, +input[type="submit"]:hover { + color: var(--primary-accent) !important; + background-color: var(--back-primary); + border-left: var(--secondary-accent) solid 0.3em; + text-decoration: none; +} + +input[type="submit"] { + background-color: transparent; + font-family: inherit; + border: none; + margin-top: 0; +} + +fieldset input[type="submit"]:hover { + border: 2px ridge var(--secondary-accent); + border-left: var(--secondary-accent) solid 0.3em; +} + +fieldset input[type="submit"] { + border: 2px solid var(--secondary-accent); + margin-top: 0.6em; +} + +fieldset { + padding: 1em; + max-width: 1000px; +} + +input[type="text"], textarea { + width: 100%; + padding: 10px; + margin-bottom: 10px; + box-sizing: border-box; + font-size: 12px; + font-family: monospace; +} + +.log input[type="text"] { + padding: 2px; + width: unset; +} + +body>nav>div .dt { + color: var(--primary); +} + +body>nav>div a:hover .dt { + color: var(--primary-accent); +} + +body>nav>div p { + font-weight: bold; + margin: 0 0 0.5em 2mm; + padding: 1em 0 0 0; +} + +/* main copy */ +article { + padding: 0.5ex 1vw 5vh 1vw; + color: var(--primary); + backdrop-filter: blur(3px); + flex: 1 1 60%; + max-width: 1100px; +} + +article h1, +article h2 { + color: var(--primary-accent); + font-weight: bold; + margin: 1em 0 1em 0; +} + +article h3 { + color: var(--secondary-accent); + font-weight: bold; + margin: 2em 0 0 0; +} + +article h4 article h5 { + color: var(--primary); + margin: 2em 0 0 0; +} + +article h6, +article h7, +article h8 { + color: var(--primary); + font-weight: bold; + margin: 2em 0 0 0; +} + +article a { + color: var(--link); +} + +article a:hover { + filter: brightness(85%) +} + +article img { + width: 90%; + max-width: 600px; + border: 0.4em solid var(--back-primary); + background-color: black !important; + padding: 0.2em; +} + +.center { + text-align: center; +} + +img[title="main"] { + display: block; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +hr { + color: var(--alt-accent2) +} + +/* footer */ +footer { + color: white; + background-color: color-mix(in srgb, var(--primary-back), transparent 86%); +} + +footer a { + color: inherit; +} + +footer div { + padding: 1em; +} + +/* tables */ +table { + border: 1px solid rgba(128, 128, 128, 0.5); + padding: 0; +} + +th { + color: white; + background-color: rgb(100, 135, 220); +} + +tr:nth-child(odd) { + background-color: rgba(128, 128, 128, 0.1) +} + +/* accents */ +.accent { + color: var(--primary-accent) +} + +.accent2 { + color: var(--secondary-accent) +} + +/* dates */ +.date { + display: flex; + align-items: center; + text-align: center; + font-weight: normal; + max-width: fit-content; + font-size: x-small; + color: var(--primary); +} + +.date::before, +.date::after { + content: '⋆★⋆'; + flex: 1; + color: var(--alt-accent) +} + +.date:not(:empty)::before { + margin-right: .25em; +} + +.date:not(:empty)::after { + margin-left: .25em; +} + +.bfeed p { + margin: 0.6ex 0 0.6ex; +} + +.bfeed h2 { + margin-bottom: 0.2ex; +} + +.bfeed h2 a { + font-size: 90%; + color: var(--primary-accent); + text-decoration: none; +} + +.bfeed h2 a:hover { + text-decoration: none; +} + +blockquote { + font-style: italic; + color: var(--secondary-accent); + border-left: 3px solid var(--alt-accent); + padding-left: 1em; +} + +/* animations */ + +.fire { + color: #f48c06; + text-shadow: + 0px -1px 3px #f48c06, + 0px -2px 6px #dc2f02, + 0px -6px 12px #9d0208; + animation: flicker 3s infinite; +} + +@keyframes flicker { + + 0%, + 100% { + text-shadow: + 0px -1px 3px #f48c06, + 0px -2px 6px #dc2f02, + 0px -6px 12px #9d0208; + } + + 50% { + text-shadow: + 0 -2px 6px #f48c06, + 0 -4px 12px #dc2f02, + 0 -8px 16px #9d0208; + } +} + +/* media */ +@media screen and (max-width: 600px) { + article { + flex-basis: 100%; + padding: 0.5em; + } + body > nav { + flex-basis: 100%; + border-right: none; + border-bottom: 3px solid var(--alt-accent2); + border-top: 3px solid var(--alt-accent2); + padding-bottom: 1em; + } +} \ No newline at end of file diff --git a/werc/pub/style/style.suckless.css b/werc/pub/style/style.suckless.css new file mode 100644 index 0000000..058da84 --- /dev/null +++ b/werc/pub/style/style.suckless.css @@ -0,0 +1,375 @@ +/* suckless.org werc style */ + +body { + color: #000000; + background-color: #ffffff; + font-family: verdana, helvetica, arial, sans-serif; + font-size: 84%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} + + +/* # Header # */ +.superHeader { + color: black; + background-color: #eeeeee; + height: 2em; +} + +.superHeader img { + vertical-align: bottom; +} + +.superHeader a { + color: black; + background-color: transparent; + text-decoration: none; + font-size: 91%; + margin: 0; + padding: 0 0.5ex 0 0.25ex; +} + +.superHeader a:hover { + text-decoration: underline; +} + +.superHeader .left { + position: absolute; + left: 1.5mm; + top: 0.75ex; +} + +.superHeader .right { + position: absolute; + right: 1.5mm; + top: 0.75ex; +} + +.midHeader { + background-color: #99ccff; + border-top: solid 0 #cccccc; + border-bottom: solid 0 #cccccc; + border-width: 1px 0; +} + +.midHeader a { + color: black; +} + +.headerTitle { + font-size: 200%; + font-weight: normal; + margin: 0 0 0 4mm; + padding: 0.25ex 0; +} +#headerSubTitle { + font-size: 50%; + font-style: italic; + margin-left: 1em; +} + +.headerTitle a { + text-decoration: none; +} + +.subHeader { + display: none; + color: black; + background-color: #99ccff; + margin: 0; + padding: 1ex 1ex 1ex 1.5mm; +} + +.subHeader a { + color: black; + background-color: transparent; + text-decoration: none; + font-weight: bold; + margin: 0; + padding: 0 0.75ex 0 0.5ex; +} + +.subHeader a:hover { + text-decoration: underline; +} + +.superHeader .highlight, .subHeader .highlight { + background-color: transparent; +} + + +/* # Side # */ +#side-bar { + width: 16em; + float: left; + clear: left; + border-right: 1px solid #cccccc; +} + +#side-bar div { + border: 0px; +} + +.sideBarTitle { + font-weight: bold; + margin: 0 0 0.5em 2mm; + padding: 1em 0 0 0; +} + +#side-bar ul { + list-style-type: none; + list-style-position: outside; + margin: 0; + padding: 0 0 0.3em 0; +} + +li ul { + padding-left: 1.0em !important; +} + +#side-bar li { + margin: 0; + padding: 0.1ex 0; /* Circumvents a rendering bug (?) in MSIE 6.0 */ +} + +#side-bar a { + color: #336699; + background-color: transparent; + text-decoration: none; + margin: 0; + padding: 0.35em 1ex 0.35em 2mm; + display: block; + text-transform: none; + font-weight: bold!important; + font-size: 104%; +} + +.thisPage, .thisPage a { + color: black!important; + font-weight: bold; + background-color: #eeeeeee; + padding-left: 5mm; +} + +#side-bar a:hover { + color: black; + background-color: #eeeeee; + text-decoration: none; + border: 0px; +} + +.sideBarText { + line-height: 1.5em; + margin: 0 0 1em 0; + padding: 0 1.5ex 0 2.5mm; + display: block; +} + +#side-bar .sideBarText a { + text-decoration: underline; + margin: 0; + padding: 0; + display: inline; +} + +#side-bar .sideBarText a:hover { + color: #336699; + background-color: transparent; + text-decoration: none; +} + +.lighterBackground { + color: inherit; + background-color: white; +} + +/* # Main Copy # */ +#main-copy { + max-width: 70em; + color: black; + background-color: transparent; + text-align: justify; + line-height: 1.5em; + margin: 0em 0 0 16em; + padding: 0.5mm 5mm 5mm 5mm; + border-left: 1px solid #cccccc; +} + +#bodyText { + margin: 0 0 0 15.5em; + padding: 2mm 5mm 2mm 5mm; +} + +#main-copy p { + margin: 1em 1ex 1em 1ex !important; /* Need !important so troff-generated pages don't look totally squezed */ + padding: 0; +} + +#main-copy a { + color: #336699; + background-color: transparent; + text-decoration: none; +} + +#main-copy a:hover { + text-decoration: underline; +} + +#main-copy h1, #main-copy h2 { + color: #336699; + background-color: transparent; + font-size: 135%; + margin: 2em 0 0 0; + padding: 0.5ex 0 0.5ex 0.6ex; + border-bottom: 1px solid #336699; +} + +#main-copy h2 { + font-size: 115.5%; + border-bottom: 1px solid #336699; +} + +#main-copy h3 { + color: #336699; + background-color: transparent; + font-size: 105%; + margin: 2em 0 0 0; + padding: 0.5ex 0 0 0.6ex; +} + +#main-copy .topOfPage { + color: #66cccc; + background-color: transparent; + font-size: 91%; + font-weight: bold; + text-decoration: none; + margin: 3ex 1ex 0 0; + padding: 0; + float: right; +} + +dl { + margin: 1em 1ex 2em 1ex; + padding: 0; +} + +dt { + font-weight: bold; + margin: 0 0 0 0; + padding: 0; +} + +dd { + margin: 0 0 2em 2em; + padding: 0; +} + + +/* # Footer # */ +#footer { + color: black; + background-color: #eeeeee; + font-size: 91%; + margin: 0; + padding: 1em 2.5mm 2.5ex 2.5mm; + clear: both; + border-top: 1px solid #cccccc; + border-bottom: 1px solid #cccccc; +} + +#footer .left { + text-align: left; + line-height: 1.45em; + float: left; + clear: left; +} + +#footer .right { + text-align: right; + line-height: 1.45em; +} + +#footer a { + color: black; + background-color: transparent; + text-decoration: none; +} + +#footer a:hover { + text-decoration: underline; +} + + +/* GENERAL */ + +table { + border: solid 1px black; +} +th { + background-color: #abc; + border: solid 1px black; + text-align: center; +} +td { + background-color: #def; + border: solid 1px black; +} + +hr { + border-width: 0px 0px 0.1em 0px; + border-color: black; +} + +acronym, .titleTip { + border-bottom: 1px dotted rgb(153,153,153); + cursor: help; + margin: 0; + padding: 0 0 0.4px 0; +} + +pre { + margin-left: 2em; + font-size: 1.2em; +} + +blockquote { + border-left: 1px solid blue; + font-style: italic; +} + +.smallCaps { + font-size: 110%; + font-variant: small-caps; +} + +.doNotDisplay { display: none; } + + +.notify_errors, +.notify_notes, +.notify_success { padding: .8em; margin-bottom: 1em; border: 1px solid #ddd; } + +.notify_errors { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; } +.notify_notes { background: #FFF6BF; color: #514721; border-color: #FFD324; } +.notify_success { background: #E6EFC2; color: #264409; border-color: #C6D880; } +.notify_errors a { color: #8a1f11; } +.notify_notes a { color: #514721; } +.notify_success a { color: #264409; } + + +/* # Page/Handler specific # */ +h1.dir-list-head, ul.dir-list { + text-transform: none; + font-weight: bold; +} +ul.sitemap-list a { + text-transform: none; +} + +/* # Junk: should move elsewhere # */ +/* S-pam */ +.gpam { text-align: center; } +.gpam table, .gpam th, .gpam td { border: none; } + + diff --git a/werc/pub/style/style.werc140.css b/werc/pub/style/style.werc140.css new file mode 100755 index 0000000..e3261e9 --- /dev/null +++ b/werc/pub/style/style.werc140.css @@ -0,0 +1,330 @@ +/* Default werc style */ + +body { + color: black; + background-color: white; + font-family: Helvetica, Verdana, Arial, 'Liberation Sans', FreeSans, sans-serif; + font-size: 84%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} + + +/* # Header # */ +.superHeader { + color: white; + background-color: rgb(100,135,220); + height: 1.6em; +} + +.superHeader img { vertical-align: bottom; } + +.superHeader a { + color: white; + background-color: transparent; + font-size: 91%; + margin: 0; + padding: 0 0.5ex 0 0.25ex; +} + +a { text-decoration: none; } +a:hover { text-decoration: underline; } + +.superHeader div { + position: absolute; + top: 0.40ex; +} + +.superHeader .left { left: 0.4em; } +.superHeader .right { right: 0.4em; } + +.midHeader { + color: rgb(39,78,144); + background-color: rgb(140,170,230); + background-color: #ff6d06; + border: solid 0 black; + border-width: 2px 0; +} + +.headerTitle { + color: black; + font-size: 233%; + font-weight: normal; + margin: 0 0 0 4mm; + padding: 0.25ex 0; +} +#headerSubTitle { + font-size: 50%; + font-style: italic; + margin-left: 1em; +} + +.headerTitle a { color: black; } +.headerTitle a:hover { text-decoration: none; } + +.subHeader { + display: none; + color: white; + background-color: rgb(0,51,153); + margin: 0; + padding: 1ex 1ex 1ex 1.5mm; +} + +.subHeader a { + color: white; + background-color: transparent; + font-weight: bold; + margin: 0; + padding: 0 0.75ex 0 0.5ex; +} + +.superHeader .highlight, .subHeader .highlight { + color: rgb(253,160,91); + background-color: transparent; +} + + +/* # Side # */ +#side-bar { + width: 16em; + float: left; + clear: left; + border-right: 1px solid #ddd; +} + +#side-bar div { + border-bottom: 1px solid #ddd; +} + +.sideBarTitle { + font-weight: bold; + margin: 0 0 0.5em 2mm; + padding: 1em 0 0 0; +} + +#side-bar ul { + list-style-type: none; + list-style-position: outside; + margin: 0; + padding: 0 0 0.3em 0; +} + +li ul { + padding-left: 0.6em !important; +} + +#side-bar li { + margin: 0; + padding: 0.1ex 0; /* Circumvents a rendering bug (?) in MSIE 6.0 XXX should move to iehacks.css, this causes an ugly gap */ +} + +#side-bar a { + color: rgb(0,102,204); + background-color: transparent; + margin: 0; + padding: 0.25em 1ex 0.25em 2mm; + display: block; + text-transform: capitalize; + font-weight: bold!important; + font-size: 102%; + border-left: white solid 0.2em; +} + +.thisPage, .thisPage a { + color: black!important; + background-color: white; + padding-left: 5mm; +} + +#side-bar a:hover { + color: white; + background-color: rgb(100,135,220); + border-left: black solid 0.2em; + text-decoration: none; +} + +.sideBarText { + line-height: 1.5em; + margin: 0 0 1em 0; + padding: 0 1.5ex 0 2.5mm; + display: block; +} + +#side-bar .sideBarText a { + margin: 0; + padding: 0; + display: inline; +} + +#side-bar .sideBarText a:hover { + color: rgb(0,102,204); + background-color: transparent; + text-decoration: none; +} + + +/* # Main Copy # */ +#main-copy { + max-width: 70em; + color: black; + background-color: transparent; + text-align: justify; + line-height: 1.5em; + margin: 0em 0 0 16em; + padding: 0.5mm 5mm 5mm 5mm; + border-left: 1px solid #ddd; +} + +#bodyText { + margin: 0 0 0 15.5em; + padding: 2mm 5mm 2mm 5mm; +} + +#main-copy p { + margin: 1em 1ex 1em 1ex !important; /* Need !important so troff-generated pages don't look totally squezed */ + padding: 0; +} + +#main-copy a { + color: rgb(0,102,204); + background-color: transparent; +} + +#main-copy a:hover { + color: rgb(100,135,220); +} + +#main-copy h1, #main-copy h2 { + color: rgb(0,102,204); + background-color: transparent; + font-size: 145.5%; + font-weight: bold; + margin: 2em 0 0 0; + padding: 0.5ex 0 0.5ex 0.6ex; + border-bottom: 2px solid rgb(0,102,204); +} + +#main-copy h2 { + font-size: 115.5%; + border-bottom: 1px solid rgb(0,102,204); +} + +#main-copy .topOfPage { + color: rgb(0,102,204); + background-color: transparent; + font-size: 91%; + font-weight: bold; + text-decoration: none; + margin: 3ex 1ex 0 0; + padding: 0; + float: right; +} + +dl { + margin: 1em 1ex 2em 1ex; + padding: 0; +} + +dt { + font-weight: bold; + margin: 0 0 0 0; + padding: 0; +} + +dd { + margin: 0 0 2em 2em; + padding: 0; +} + + +/* # Footer # */ +#footer { + color: white; + background-color: rgb(100,135,220); + padding: 1em; + clear: both; +} + +#footer .left { + text-align: left; + line-height: 1.55em; + float: left; + clear: left; +} + +#footer .right { + text-align: right; + line-height: 1.45em; +} + +#footer a { + color: white; + background-color: transparent; +} + + +/* GENERAL */ + +table { + border: solid 1px black; +} +th { + background-color: #abc; + border: solid 1px black; + text-align: center; +} +td { + background-color: #def; + border: solid 1px black; +} + +hr { + border-width: 0px 0px 0.1em 0px; + border-color: black; +} + +acronym, .titleTip { + border-bottom: 1px solid #ddd; + cursor: help; + margin: 0; + padding: 0 0 0.4px 0; +} + +pre { + margin-left: 2em; + font-size: 1.2em; +} + +blockquote { + border-left: 1px solid blue; + font-style: italic; +} + +.smallCaps { + font-size: 110%; + font-variant: small-caps; +} + +.doNotDisplay { display: none; } + + +.notify_errors, +.notify_notes, +.notify_success { padding: .8em; margin-bottom: 1em; border: 2px solid #ddd; } + +.notify_errors { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; } +.notify_notes { background: #FFF6BF; color: #514721; border-color: #FFD324; } +.notify_success { background: #E6EFC2; color: #264409; border-color: #C6D880; } +.notify_errors a { color: #8a1f11; } +.notify_notes a { color: #514721; } +.notify_success a { color: #264409; } + + +/* # Page/Handler specific # */ +h1.dir-list-head, ul.dir-list { + text-transform: capitalize; + font-weight: bold; +} +ul.sitemap-list a { + text-transform: capitalize; +} diff --git a/werc/pub/style/style_old.css b/werc/pub/style/style_old.css new file mode 100755 index 0000000..e4a41fe --- /dev/null +++ b/werc/pub/style/style_old.css @@ -0,0 +1,330 @@ +/* Old Default style */ +/* ##### Common Styles ##### */ + +body { + color: black; + XXXbackground-color: rgb(240,240,240); + background-color: white; + font-family: verdana, helvetica, arial, sans-serif; + font-size: 71%; /* Enables font size scaling in MSIE */ + margin: 0; + padding: 0; +} + +html > body { + font-size: 8.5pt; +} + +acronym, .titleTip { + border-bottom: 1px dotted rgb(153,153,153); + cursor: help; + margin: 0; + padding: 0 0 0.4px 0; +} + +.doNotDisplay { + display: none; +} + +.smallCaps { + font-size: 110%; + font-variant: small-caps; +} + + +/* ##### Header ##### */ + +.superHeader { + color: white; + background-color: rgb(100,135,220); + height: 2em; +} + +.superHeader a { + color: white; + background-color: transparent; + text-decoration: none; + font-size: 91%; + margin: 0; + padding: 0 0.5ex 0 0.25ex; +} + +.superHeader a:hover { + text-decoration: underline; +} + +.superHeader .left { + position: absolute; + left: 1.5mm; + top: 0.75ex; +} + +.superHeader .right { + position: absolute; + right: 1.5mm; + top: 0.75ex; +} + +.midHeader { + color: rgb(39,78,144); + background-color: rgb(140,170,230); + border: solid 0 black; + border-width: 0.3em 0; +} + +.headerTitle { + color: black; + font-size: 337%; + font-weight: normal; + margin: 0 0 0 4mm; + padding: 0.25ex 0; +} +#headerSubTitle { + font-size: 50%; + font-style: italic; +} + +.subHeader { +display: none; + color: white; + background-color: rgb(0,51,153); + margin: 0; + padding: 1ex 1ex 1ex 1.5mm; +} + +.subHeader a { + color: white; + background-color: transparent; + text-decoration: none; + font-weight: bold; + margin: 0; + padding: 0 0.75ex 0 0.5ex; +} + +.subHeader a:hover { + text-decoration: underline; +} + +.superHeader .highlight, .subHeader .highlight { + color: rgb(253,160,91); + background-color: transparent; +} + + +/* ##### Side Bar ##### */ + +#side-bar { + width: 15em; + float: left; + clear: left; + border-right: 1px solid rgb(153,153,153); +} + +#side-bar div { + border-bottom: 1px solid rgb(153,153,153); +} + +.sideBarTitle { + font-weight: bold; + margin: 0 0 0.5em 2.5mm; + padding: 1em 0 0 0; +} + +#side-bar ul { + list-style-type: none; + list-style-position: outside; + margin: 0; + padding: 0 0 1.1em 0; +} + +#side-bar li { + margin: 0; + padding: 0.1ex 0; /* Circumvents a rendering bug (?) in MSIE 6.0 */ +} + +#side-bar a, .thisPage { + color: rgb(0,102,204); + background-color: transparent; + XXXtext-decoration: none; + margin: 0; + padding: 0.55em 1ex 0.55em 5mm; + display: block; +} + +.thisPage { + color: black; + background-color: white; + padding-left: 5mm; + XXXborder-top: 1px solid rgb(153,153,153); + XXXborder-bottom: 1px solid rgb(153,153,153); + font-weight: 600; +} + +#side-bar a:hover { + color: white; + background-color: rgb(100,135,220); + text-decoration: none; +} + +.sideBarText { + line-height: 1.5em; + margin: 0 0 1em 0; + padding: 0 1.5ex 0 2.5mm; + display: block; +} + +#side-bar .sideBarText a { + text-decoration: underline; + margin: 0; + padding: 0; + display: inline; +} + +#side-bar .sideBarText a:hover { + color: rgb(0,102,204); + background-color: transparent; + text-decoration: none; +} + +.lighterBackground { + color: inherit; + background-color: white; +} + + +/* ##### Main Copy ##### */ + +#main-copy { + max-width: 90em; + color: black; + background-color: white; + text-align: justify; + line-height: 1.5em; + margin: 0 0 0 15em; + padding: 0.5mm 5mm 5mm 5mm; + border-left: 1px solid rgb(153,153,153); +} + +#main-copy p { + margin: 1em 1ex 2em 1ex; + padding: 0; +} + +#main-copy a { + color: rgb(0,102,204); + background-color: transparent; + text-decoration: underline; +} + +#main-copy a:hover { + text-decoration: none; +} + +#main-copy h1 { + color: white; + background-color: rgb(100,135,220); + font-size: 100%; + font-weight: bold; + margin: 3em 0 0 0; + padding: 0.5ex 0 0.5ex 1ex; +} + +#main-copy .topOfPage { + color: white; + background-color: transparent; + font-size: 91%; + font-weight: bold; + text-decoration: none; + margin: 2.5ex 1ex 0 0; /* For MSIE */ + padding: 0; + float: right; +} + +#main-copy > .topOfPage { + margin: 2.75ex 1ex 0 0; /* For fully standards-compliant user agents */ +} + +dl { + margin: 1em 1ex 2em 1ex; + padding: 0; +} + +dt { + font-weight: bold; + margin: 0 0 0 0; + padding: 0; +} + +dd { + margin: 0 0 2em 2em; + padding: 0; +} + + +/* ##### Footer ##### */ + +#footer { + color: white; + background-color: rgb(100,135,220); + font-size: 91%; + margin: 0; + padding: 1em 2.5mm 2.5ex 2.5mm; + clear: both; +} + +#footer .left { + line-height: 1.45em; + float: left; + clear: left; +} + +#footer .right { + text-align: right; + line-height: 1.45em; +} + +#footer a { + color: white; + background-color: transparent; + text-decoration: underline; +} + +#footer a:hover { + text-decoration: none; +} + + +/* GENERAL */ +/* Spam */ +.spam { + text-align: center; +} + +/* Tables */ +table { + border: solid 1px black; +} +th { + background-color: #abc; + border: solid 1px black; +} +td { + background-color: #def; + border: solid 1px black; +} + +hr { + border-width: 0px 0px 0.1em 0px; + border-color: black; +} + +.spam table, .spam th, .spam td { + border: none; +} + +/* Code */ +pre { + margin-left: 2em; +} + + diff --git a/werc/sites/ppl.thirdculture.top/_werc/config b/werc/sites/ppl.thirdculture.top/_werc/config new file mode 100644 index 0000000..9964f73 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/_werc/config @@ -0,0 +1,3 @@ +masterSite=thirdculture.top +siteTitle='third culture' +siteSubTitle='the members of third culture' diff --git a/werc/sites/ppl.thirdculture.top/dulien/_werc/config b/werc/sites/ppl.thirdculture.top/dulien/_werc/config new file mode 100644 index 0000000..7442da0 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/dulien/_werc/config @@ -0,0 +1,2 @@ +conf_enable_blog +conf_enable_wiki \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/dulien/_werc/pub/style.css b/werc/sites/ppl.thirdculture.top/dulien/_werc/pub/style.css new file mode 100644 index 0000000..8b1af38 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/dulien/_werc/pub/style.css @@ -0,0 +1 @@ +/* Put custom styles here */ \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/guenf/_werc/config b/werc/sites/ppl.thirdculture.top/guenf/_werc/config new file mode 100644 index 0000000..7442da0 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/guenf/_werc/config @@ -0,0 +1,2 @@ +conf_enable_blog +conf_enable_wiki \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/guenf/_werc/pub/style.css b/werc/sites/ppl.thirdculture.top/guenf/_werc/pub/style.css new file mode 100644 index 0000000..8b1af38 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/guenf/_werc/pub/style.css @@ -0,0 +1 @@ +/* Put custom styles here */ \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/kaz/_werc/config b/werc/sites/ppl.thirdculture.top/kaz/_werc/config new file mode 100644 index 0000000..7442da0 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/kaz/_werc/config @@ -0,0 +1,2 @@ +conf_enable_blog +conf_enable_wiki \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/kaz/_werc/pub/style.css b/werc/sites/ppl.thirdculture.top/kaz/_werc/pub/style.css new file mode 100644 index 0000000..8b1af38 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/kaz/_werc/pub/style.css @@ -0,0 +1 @@ +/* Put custom styles here */ \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/nevada/_werc/config b/werc/sites/ppl.thirdculture.top/nevada/_werc/config new file mode 100644 index 0000000..7442da0 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/nevada/_werc/config @@ -0,0 +1,2 @@ +conf_enable_blog +conf_enable_wiki \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/nevada/_werc/pub/style.css b/werc/sites/ppl.thirdculture.top/nevada/_werc/pub/style.css new file mode 100644 index 0000000..8b1af38 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/nevada/_werc/pub/style.css @@ -0,0 +1 @@ +/* Put custom styles here */ \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/q/_werc/config b/werc/sites/ppl.thirdculture.top/q/_werc/config new file mode 100644 index 0000000..7442da0 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/q/_werc/config @@ -0,0 +1,2 @@ +conf_enable_blog +conf_enable_wiki \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/q/_werc/pub/style.css b/werc/sites/ppl.thirdculture.top/q/_werc/pub/style.css new file mode 100644 index 0000000..8b1af38 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/q/_werc/pub/style.css @@ -0,0 +1 @@ +/* Put custom styles here */ \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/thomas/_werc/config b/werc/sites/ppl.thirdculture.top/thomas/_werc/config new file mode 100644 index 0000000..7442da0 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/thomas/_werc/config @@ -0,0 +1,2 @@ +conf_enable_blog +conf_enable_wiki \ No newline at end of file diff --git a/werc/sites/ppl.thirdculture.top/thomas/_werc/pub/style.css b/werc/sites/ppl.thirdculture.top/thomas/_werc/pub/style.css new file mode 100644 index 0000000..8b1af38 --- /dev/null +++ b/werc/sites/ppl.thirdculture.top/thomas/_werc/pub/style.css @@ -0,0 +1 @@ +/* Put custom styles here */ \ No newline at end of file diff --git a/werc/sites/thirdculture.top/_header.md b/werc/sites/thirdculture.top/_header.md new file mode 100644 index 0000000..5a0973b --- /dev/null +++ b/werc/sites/thirdculture.top/_header.md @@ -0,0 +1,8 @@ +**Home of the *third culture* collective**. + +> "Always leave a place better than when you came" + +Born from the need to express in a setting of isolation and normativity. We seek to be a resilient center for those who search to better themselves and the collapsing cultures around them through **honest expression**. + +![Ruins](/_werc/pub/imgs/dither_ruins.png "main") +
    diff --git a/werc/sites/thirdculture.top/_werc/config b/werc/sites/thirdculture.top/_werc/config new file mode 100644 index 0000000..7b02382 --- /dev/null +++ b/werc/sites/thirdculture.top/_werc/config @@ -0,0 +1,5 @@ +siteTitle='third culture' +siteSubTitle='what is, was, and will be' +conf_enable_blog news/ +blogTitle='News' +conf_blog_only_pull=1 diff --git a/werc/sites/thirdculture.top/_werc/lib/blagh/new_post.tpl b/werc/sites/thirdculture.top/_werc/lib/blagh/new_post.tpl new file mode 100644 index 0000000..47dfb29 --- /dev/null +++ b/werc/sites/thirdculture.top/_werc/lib/blagh/new_post.tpl @@ -0,0 +1,12 @@ +
    +% notices_handler +
    + Submit a new blog post + + + +

    Content:

    +
    + +
    +
    diff --git a/werc/sites/thirdculture.top/_werc/lib/dirdir/edit.tpl b/werc/sites/thirdculture.top/_werc/lib/dirdir/edit.tpl new file mode 100755 index 0000000..6484d1c --- /dev/null +++ b/werc/sites/thirdculture.top/_werc/lib/dirdir/edit.tpl @@ -0,0 +1,29 @@ +
    +

    Editing: %($req_path%)

    +
    +
    +
    + Editing wiki with path: %($req_path%) + +
    + + +
    + DirDir documents are written using Markdown syntax. +
    +
    +
    + +% if(! ~ $"post_arg_dirdir_preview '') { +

    Preview:

    +
    +% echo $post_arg_edit_text | $formatter +
    +% } diff --git a/werc/sites/thirdculture.top/_werc/lib/footer.inc b/werc/sites/thirdculture.top/_werc/lib/footer.inc new file mode 100644 index 0000000..fcc0008 --- /dev/null +++ b/werc/sites/thirdculture.top/_werc/lib/footer.inc @@ -0,0 +1,5 @@ + +
    diff --git a/werc/sites/thirdculture.top/_werc/lib/top_bar.inc b/werc/sites/thirdculture.top/_werc/lib/top_bar.inc new file mode 100644 index 0000000..dd81523 --- /dev/null +++ b/werc/sites/thirdculture.top/_werc/lib/top_bar.inc @@ -0,0 +1,22 @@ +
    + [ + home | + members | + music | + shelter | + radio | + visual | + basement | + wiki + ] +
    + +
    + [ + moridori | + 4mdv | + faal | + los3r + ] +
    + diff --git a/werc/sites/thirdculture.top/_werc/pub/imgs/chillin.png b/werc/sites/thirdculture.top/_werc/pub/imgs/chillin.png new file mode 100644 index 0000000..3f7e74c Binary files /dev/null and b/werc/sites/thirdculture.top/_werc/pub/imgs/chillin.png differ diff --git a/werc/sites/thirdculture.top/_werc/pub/imgs/dither_ruins.png b/werc/sites/thirdculture.top/_werc/pub/imgs/dither_ruins.png new file mode 100644 index 0000000..e3d140f Binary files /dev/null and b/werc/sites/thirdculture.top/_werc/pub/imgs/dither_ruins.png differ diff --git a/werc/sites/thirdculture.top/_werc/pub/imgs/ruins.jpeg b/werc/sites/thirdculture.top/_werc/pub/imgs/ruins.jpeg new file mode 100644 index 0000000..639dfa4 Binary files /dev/null and b/werc/sites/thirdculture.top/_werc/pub/imgs/ruins.jpeg differ diff --git a/werc/sites/thirdculture.top/_werc/pub/imgs/tcl.svg b/werc/sites/thirdculture.top/_werc/pub/imgs/tcl.svg new file mode 100644 index 0000000..8b2ad2c --- /dev/null +++ b/werc/sites/thirdculture.top/_werc/pub/imgs/tcl.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/werc/sites/thirdculture.top/_werc/pub/imgs/tcl2.svg b/werc/sites/thirdculture.top/_werc/pub/imgs/tcl2.svg new file mode 100644 index 0000000..2dcaf27 --- /dev/null +++ b/werc/sites/thirdculture.top/_werc/pub/imgs/tcl2.svg @@ -0,0 +1,24 @@ + + + + + + + diff --git a/werc/sites/thirdculture.top/about/index.md b/werc/sites/thirdculture.top/about/index.md new file mode 100644 index 0000000..dddf063 --- /dev/null +++ b/werc/sites/thirdculture.top/about/index.md @@ -0,0 +1,15 @@ +# About: Third Culture + +**Third Culture** is an artist collective started by [moridori](https://moridori.xyz) and [los3r](https://www.instagram.com/los3333r/) in 2024. +We currently operate out of Ottawa ON, Canada. + +![Image of members chilling](/_werc/pub/imgs/chillin.png "main") + +**Third Culture** was born out of the need to connect passionate and honest artists in an otherwise isolated landscape (real life and online). Our desire is to build a third place that supports creation and artistry as well as intermingles it with other forms. For many of us, we feel a lack of belonging, scattered passions yet without a shared foundation. This is what stifles many modes of artistry and keeps us isolated from each other and potential friends alike. Third Culture seeks to remedy this. To us real impact is not an increasing number on a screen but tangible change you make in yourself and others lives and seeing it first hand. We want to bridge this gap and allow for free and honest expression to flow through our senses and not locked in our hearts. We may never reach these goals but that is not the point, the goal is to try and when it comes down to it convince ourselves we've left beautiful ruins. + +**Third Culture** members: + +* [moridori](https://moridori.xyz/) +* [los3r](https://www.instagram.com/los3333r/) +* [Future as a Letterbomber](https://moridori.xyz/letterbomber/) +* [498,516,889 Dead Virgins](https://deadcel.me/) diff --git a/werc/sites/thirdculture.top/favicon.ico b/werc/sites/thirdculture.top/favicon.ico new file mode 100644 index 0000000..cb6f257 Binary files /dev/null and b/werc/sites/thirdculture.top/favicon.ico differ diff --git a/werc/sites/thirdculture.top/favicon.svg b/werc/sites/thirdculture.top/favicon.svg new file mode 100644 index 0000000..2dcaf27 --- /dev/null +++ b/werc/sites/thirdculture.top/favicon.svg @@ -0,0 +1,24 @@ + + + + + + + diff --git a/werc/sites/thirdculture.top/index.md b/werc/sites/thirdculture.top/index.md new file mode 100644 index 0000000..e69de29 diff --git a/werc/sites/thirdculture.top/index.rss b/werc/sites/thirdculture.top/index.rss new file mode 100644 index 0000000..e69de29 diff --git a/werc/sites/thirdculture.top/news/2024/07/12/0/index.md b/werc/sites/thirdculture.top/news/2024/07/12/0/index.md new file mode 100644 index 0000000..38e59d3 --- /dev/null +++ b/werc/sites/thirdculture.top/news/2024/07/12/0/index.md @@ -0,0 +1,4 @@ +third culture is founded +------------------------------------- + +Far out and away from the crowd, in complete darkness, a *match is lit*. diff --git a/werc/sites/thirdculture.top/news/_werc/config b/werc/sites/thirdculture.top/news/_werc/config new file mode 100644 index 0000000..cc6d2ce --- /dev/null +++ b/werc/sites/thirdculture.top/news/_werc/config @@ -0,0 +1,3 @@ +conf_enable_wiki +conf_enable_blog +conf_blog_only_pull=0 diff --git a/werc/sites/thirdculture.top/wiki/_werc/config b/werc/sites/thirdculture.top/wiki/_werc/config new file mode 100644 index 0000000..74d3067 --- /dev/null +++ b/werc/sites/thirdculture.top/wiki/_werc/config @@ -0,0 +1 @@ +conf_enable_wiki diff --git a/werc/sites/thirdculture.top/wiki/index.md b/werc/sites/thirdculture.top/wiki/index.md new file mode 100644 index 0000000..9015a7a --- /dev/null +++ b/werc/sites/thirdculture.top/wiki/index.md @@ -0,0 +1 @@ +index diff --git a/werc/tpl/_debug.tpl b/werc/tpl/_debug.tpl new file mode 100644 index 0000000..4d650ea --- /dev/null +++ b/werc/tpl/_debug.tpl @@ -0,0 +1,29 @@ +% if(! ~ $#debug_shell 0) { +
    + + +
    + + +%{ +fn evl { + # Buffering is probably messing this up: + #rc -c 'flag x +;{'^$post_arg_command'} |[2] awk ''{print ">> "$0}''' + rc -c 'flag s +; flag x +;'^$post_arg_command +} + if(! ~ $#post_arg_command 0 && ! ~ $#post_arg_command '') { + echo '
    '
    +        evl | escape_html |[2] awk '{print ""$0""}' 
    +        echo '
    ' + } +%} +% } + +
    +% env | escape_html
    +

    + +% umask + diff --git a/werc/tpl/_users/login.tpl b/werc/tpl/_users/login.tpl new file mode 100644 index 0000000..ebaca78 --- /dev/null +++ b/werc/tpl/_users/login.tpl @@ -0,0 +1,18 @@ +

    User login

    +
    +% if(check_user) { + You are logged in as: %($logged_user%) +% } +% if not { +% if (~ $REQUEST_METHOD POST) +% echo '
    Login failed!
    ' +
    +
    +
    +
    + +
    +
    +% } + +
    diff --git a/werc/tpl/sitemap.tpl b/werc/tpl/sitemap.tpl new file mode 100644 index 0000000..9505b6d --- /dev/null +++ b/werc/tpl/sitemap.tpl @@ -0,0 +1,67 @@ +

    Site map

    + +%{ +tmpfile=/tmp/werc_sitemap_$pid.txt +tmpfilex=/tmp/werc_sitemapx_$pid.txt +saveddf=$dirfilter + +MON2NUM='s/Jan/01/; s/Feb/02/; s/Mar/03/; s/Apr/04/; s/May/05/; s/Jun/06/; s/Jul/07/; s/Aug/08/; s/Sep/09/; s/Oct/10/; s/Nov/11/; s/Dec/12/;' + +fn get_mdate { + t=`{mtime $1} + t=`{date $t(1) | sed -e $MON2NUM -e 's/ ([0-9]) / 0\1 /g'} # Make sure day of the month is two digits. + echo $t(6)^'-'^$t(2)^'-'^$t(3) +} + +fn listDir { + d=$1 + dirfilter=$saveddf + if(test -f $d/_werc/config) + . $d/_werc/config + + if(~ $#perm_redir_to 0) { + echo '
      ' + + for(i in `{ls -dF $d^*/ $d^*.md $d^*.html $d^*.txt >[2]/dev/null | sed $dirfilter}) { + desc=`{get_file_title $i} + u=`{echo $i|sed 's!'$sitedir'!!; '$dirclean's!/index$!/!; '} + if(! ~ $#desc 0 && ! ~ $desc '') + desc=' - '$"desc + n=`{echo /$u|sed 's/[\-_]/ /g; s,.*/([^/]+)/?$,\1,'} + echo '
    • '^$"n^'' $"desc '
    • ' + echo $base_url^$u >> $tmpfile + echo ''$base_url^$u''^`{get_mdate $i}^'' >> $tmpfilex + if(test -d $i) + @{ listDir $i } + } + echo '
    ' + } +} + + +fltr_cache listDir $sitedir/ + +if(test -s $tmpfile) { + mv $tmpfile $sitedir/sitemap.txt & +} +if not if(test -f $tmpfile) + rm $tmpfile + +if(test -s $tmpfilex) { + { + echo ' +' + + cat $tmpfilex + rm $tmpfilex & + echo '' + # TODO Enable automaic search engine update notification. + #hget 'http://google.com/ping?sitemap='^`{url_encode $base_url'/sitemap.gz'} > /dev/null + + } | gzip > $sitedir/sitemap.gz & + #} > $sitedir/sitemap.xml & +} +if not if(test -f $tmpfilex) + rm $tmpfilex + +%}