diff --git a/Bug.pm b/Bug.pm deleted file mode 100644 index 92c145b..0000000 --- a/Bug.pm +++ /dev/null @@ -1,363 +0,0 @@ - -=head1 SQL Schema - - CREATE TABLE $p ( - id integer PRIMARY KEY AUTOINCREMENT NOT NULL, - issue integer NOT NULL, - date integer NOT NULL, - name text DEFAULT '' NOT NULL, - email text DEFAULT '' NOT NULL, - admin integer DEFAULT 0 NOT NULL, - closed integer DEFAULT 0 NOT NULL, - type text DEFAULT '' NOT NULL, - status text DEFAULT '' NOT NULL, - summary text NOT NULL, - message text DEFAULT '' NOT NULL - ); - -=cut - -package TUWF::Bug; - -use TUWF ':xml', ':html', 'html_escape'; -use POSIX 'strftime'; - -sub new { - my $class = shift; - return bless { - table => 'issues', - types => [qw|bug feature docs other|], - default_type => 'other', - statusses => [qw|new accepted duplicate confirmed fixed wontfix worksforme|], - default_status => 'new', - admins => ['code1', 'code2'], - @_ - }, $class; -} - - -sub dbListing { - my $self = shift; - my %o = ( - results => 100, - page => 1, - closed => 2, - @_ - ); - $o{reverse} = 1 if !$o{sort}; - - my %where = ( - 'NOT EXISTS(SELECT 1 FROM !s im WHERE im.id > m.id AND im.issue = m.issue)' => $self->{table}, - $o{id} ? ('issue = ?' => $o{id}) : (), - $o{closed} != 2 ? ('closed = ?' => $o{closed}?1:0) : (), - ); - - my $order = sprintf { - date => 'id %s', - }->{$o{sort}||'date'}, $o{reverse} ? 'DESC' : 'ASC'; - - my($r, $np) = $TUWF::OBJ->dbPage(\%o, q{ - SELECT issue, summary, date, type, status, closed - FROM !s m - !W - ORDER BY !s}, $self->{table}, \%where, $order - ); - return wantarray ? ($r, $np) : $r; -} - - -sub dbItem { - my($self, $id) = @_; - return $TUWF::OBJ->dbAll(q{ - SELECT issue, summary, date, type, status, closed, name, admin, message - FROM !s - WHERE issue = ? - ORDER BY id}, $self->{table}, $id - ); -} - - -sub dbRecent { - my $self = shift; - return $TUWF::OBJ->dbAll(q{ - SELECT issue, summary, date, name - FROM !s - ORDER BY id DESC LIMIT 10}, $self->{table} - ); -} - - -sub dbEmails { - my($self, $id) = @_; - return [ map $_->{email}, @{$TUWF::OBJ->dbAll(q|SELECT DISTINCT email FROM !s WHERE issue = ? AND email <> ''|, $self->{table}, $id)} ]; -} - - -sub dbSave { - my($self, $id, $closed, @a) = @_; - - # TODO: Issue ID allocation may currently cause two bug reports created at - # the same time to get the same id. - my $issue = $id ? '?' : '(SELECT COALESCE(MAX(issue)+1, 1) FROM !s)'; - - $TUWF::OBJ->dbExec( - "INSERT INTO !s (issue, date, closed, summary, name, email, type, status, message, admin) VALUES ($issue, ?, ?, !l)", - $self->{table}, $id || $self->{table}, time(), $closed?1:0, \@a); - return $TUWF::OBJ->dbRow('SELECT issue FROM !s ORDER BY date DESC LIMIT 1 ', $self->{table})->{issue}; -} - - -# TODO: pagination / filtering -sub htmlListing { - my($s, $l, $lnk) = @_; - if(!@$l) { - p class => 'bug_nolisting', 'No bugs found! Yay?'; - return; - } - table class => 'bug_listing'; - thead; Tr; - td class => 'bug_col_id', 'Id'; - td class => 'bug_col_type', 'Type'; - td class => 'bug_col_status', 'Status'; - td class => 'bug_col_date', 'Updated'; - td class => 'bug_col_summary','Summary'; - end; end; - for(@$l) { - Tr $_->{closed} ? (class => 'bug_closed') : (); - td class => 'bug_col_id', $_->{issue}; - td class => 'bug_col_type', $_->{type}; - td class => 'bug_col_status', $_->{status}; - td class => 'bug_col_date', strftime '%Y-%m-%d', gmtime $_->{date}; - td class => 'bug_col_summary'; - a href => $lnk->($_->{issue}), $_->{summary}; - end; - end; - } - end; -} - - -sub _escape_url { - my $str = shift; - my $r = ''; - my $last = 0; - while($str =~ m{((?:https?|ftp)://[^ ><"\n\s]+[\d\w=/-])}g) { - $r .= sprintf '%s%2$s', html_escape(substr $str, $last, (pos($str)-length($1))-$last), html_escape($1); - $last = pos $str; - } - return $r.html_escape(substr $str, $last); -} - - -sub htmlItem { - my($s, $d) = @_; - my $last = $d->[$#$d]; - dl class => 'bug_status'; - dt 'Id'; dd $last->{issue}; - dt 'Messages'; dd $#$d+1; - dt 'Type'; dd $last->{type}; - dt 'Status'; dd $last->{status}; - end; - div class => 'bug_item'; - my $num = -1; - for my $m (@$d) { - div class => 'bug_message'; - h1 !++$num ? 'Description' : "Reply $num"; - dl; - dt !$num ? 'Created' : 'Added'; - dd; - txt strftime '%Y-%m-%d %T GMT', gmtime $m->{date}; - txt ' by '; - txt $m->{name}||'Anonymous' if !$m->{admin}; - b $m->{name}||'Admin' if $m->{admin}; - end; - for($num ? qw|summary type status| : ()) { - if($m->{$_} ne $d->[$num-1]{$_}) { - dt "\u$_"; - dd sprintf '"%s" to "%s"', $d->[$num-1]{$_}, $m->{$_}; - } - } - if($num && !$m->{closed} != !$d->[$num-1]{closed}) { - dt "Closed"; - dd sprintf '"%s" to "%s"', $d->[$num-1]{closed}?'yes':'no', $m->{closed}?'yes':'no'; - } - end; - p; lit _escape_url $m->{message}; end; - end; - } - end; -} - - -sub htmlForm { - my($s, $l, $url) = @_; - # TODO: anti-spam JS - form class => 'bug_frm', action => $url, method => 'post'; - fieldset; - input type => 'hidden', name => 'bug_id', value => $l ? $l->{issue} : 0; - legend $l ? 'Reply' : 'Report a new bug'; - ul; - li class => 'bug_frm_summary'; - label for => 'bug_summary', 'Summary'; - input type => 'text', name => 'bug_summary', id => 'bug_summary', size => 45, value => $l?$l->{summary}:''; - end; - li class => 'bug_frm_name'; - label for => 'bug_name', 'Name'; - input type => 'text', name => 'bug_name', id => 'bug_name', size => 20, value => $TUWF::OBJ->reqCookie('bug_name')||''; - lit ' '; - txt 'Name+email will be remembered with a cookie.'; - end; - li class => 'bug_frm_mail'; - label for => 'bug_email', 'Email'; - input type => 'text', name => 'bug_email', id => 'bug_email', size => 20, value => $TUWF::OBJ->reqCookie('bug_email')||''; - lit ' '; - txt 'Optional, only used for notifications.'; - end; - if($l) { - li class => 'bug_frm_admin'; - label for => 'bug_type', 'Admin'; - Select name => 'bug_type'; - option value => $_, $_ eq $l->{type} ? (selected => 'selected') : (), $_ for @{$s->{types}}; - end; - Select name => 'bug_status'; - option value => $_, $_ eq $l->{status} ? (selected => 'selected') : (), $_ for @{$s->{statusses}}; - end; - Select name => 'bug_closed'; - option value => 0, !$l->{closed} ? (selected => 'selected') : (), 'Open'; - option value => 1, $l->{closed} ? (selected => 'selected') : (), 'Closed'; - end; - input type => 'password', name => 'bug_code', id => 'bug_code', size => 10, value => $TUWF::OBJ->reqCookie('bug_code')||'code'; - end; - } else { - li class => 'bug_frm_type'; - label for => 'bug_type', 'Type'; - Select name => 'bug_type'; - option value => $_, $_ eq $s->{default_type} ? (selected => 'selected') : (), $_ for @{$s->{types}}; - end; - end; - } - li class => 'bug_frm_message'; - textarea name => 'bug_message';end; br; - lit 'Please use a pastebin if you want to include chunks of code or program output.'; - end; - li class => 'bug_frm_submit'; - input type => 'submit', value => 'Submit'; - end; - end 'ul'; - end; - end 'form'; -} - - -sub handleForm { - my($s, $url) = @_; - my $f = $TUWF::OBJ->formValidate( - { post => 'bug_id', template => 'uint' }, - { post => 'bug_summary', maxlength => 200, minlength => 2 }, - { post => 'bug_name', required => 0, default => '', maxlength => 200 }, - { post => 'bug_email', required => 0, template => 'email' }, - { post => 'bug_code', required => 0, default => '' }, - { post => 'bug_message', maxlength => 256*1024, minlength => 1 }, - ); - return($f, undef) if $f->{_err}; - return({ _err => [['bug_summary']], %$f}, undef) if $f->{bug_summary} =~ qr{http://}; # SPAM - return({ _err => [['bug_summary']], %$f}, undef) if $f->{bug_message} =~ qr{(?:{bug_code} = '' if $f->{bug_code} eq 'code'; - my $admin = grep($_ eq $f->{bug_code}, @{$s->{admins}}) ? 1 : 0; - - my $l; - # Reply - if($f->{bug_id} > 0) { - $l = $s->dbListing(id => $f->{bug_id})->[0]; - push @{$f->{_err}}, ['bug_id', 'db_check', ''] and return($f, undef) if !$l; - - # Check admin things - if($admin) { - my $fa = $TUWF::OBJ->formValidate( - { post => 'bug_type', enum => $s->{types} }, - { post => 'bug_status', enum => $s->{statusses} }, - { post => 'bug_closed', enum => [0,1] }, - ); - $f = { %$f, %$fa }; - return($f, $l) if $f->{_err}; - } else { - push @{$f->{_err}}, [ 'bug_code', 'invalid', '' ] and return($f, undef) if $f->{bug_code}; - $f->{bug_type} = $l->{type}; - $f->{bug_status} = $l->{status}; - $f->{bug_closed} = $l->{closed}; - } - - # New bug - } else { - $f->{bug_status} = $s->{default_status}; - $f->{bug_closed} = 0; - my $fa = $TUWF::OBJ->formValidate({ post => 'bug_type', enum => $s->{types} }); - $f = { %$f, %$fa }; - return($f, $l) if $f->{_err}; - } - - # No errors? Save! - my $id = $s->dbSave(map($f->{"bug_$_"}, qw|id closed summary name email type status message|), $admin); - - my $u = $url->($id); - - # For replies, send out notification emails - if($l) { - my $mails = $s->dbEmails($id); - my $base = $TUWF::OBJ->reqBaseURI(); - for(grep $_ ne $f->{bug_email}, @$mails) { - $TUWF::OBJ->mail( - "Hello!\n\n". - "A new reply has been posted to a bug you have previously shown\n". - "an interest in. You can find the reply at the following URL:\n\n". - " $base$u\n\n". - "If you do not wish to receive any more notifications for this (and\n". - "perhaps other) bugs, please reply to this email stating your intent.", - Subject => "Reply to $f->{bug_summary}", - To => $_, - ); - } - } - - $l = $s->dbListing(id => $id)->[0] if !$l; - $TUWF::OBJ->resRedirect($u, 'post'); - $f->{$_} and $TUWF::OBJ->resCookie($_ => $f->{$_}, expires => time()+365*24*3600) for ('bug_name', 'bug_email', 'bug_code'); - - return($f, $l); -} - - -sub atomFeed { - my($s, $lnk) = @_; - - my $r = $s->dbRecent(); - my $t = $r->[0]{date}||1463296545; - - $TUWF::OBJ->resHeader('Last-Modified' => strftime '%a, %d %b %Y %H:%M:%S GMT', gmtime $t); - $TUWF::OBJ->resHeader('Content-Type' => 'application/atom+xml'); - xml; - tag feed => xmlns => 'http://www.w3.org/2005/Atom', 'xml:lang' => 'en', 'xml:base' => 'https://dev.yorhel.nl/'; - tag title => "\u$s->{table} Recent Comments"; - tag updated => strftime('%Y-%m-%dT%H:%M:%SZ', gmtime $t); - tag id => $lnk->('feed.atom'); - tag link => rel => 'self', type => 'application/atom+xml', href => $lnk->('feed.atom'), undef; - tag link => rel => 'alternate', type => 'text/html', href => $lnk->(''), undef; - - for(@$r) { - my $d = strftime('%Y-%m-%dT%H:%M:%SZ', gmtime $_->{date}); - tag 'entry'; - tag id => $lnk->($_->{issue})."#$d"; - tag title => $_->{summary}; - tag updated => $d; - tag published => $d; - tag 'author'; - tag name => $_->{name}; - end; - tag link => rel => 'alternate', type => 'text/html', href => $lnk->($_->{issue}), undef; - end 'entry'; - } - end 'feed'; -} - -1; diff --git a/index.cgi b/index.cgi deleted file mode 100644 index 033de53..0000000 --- a/index.cgi +++ /dev/null @@ -1,603 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -use utf8; -use TUWF ':html'; -use POSIX 'strftime'; - -use Cwd 'abs_path'; -our $ROOT; -BEGIN { ($ROOT = abs_path $0) =~ s{index\.cgi$}{}; } - - -my @changes = ( - [ '2019-02-04', '/ncdu', 'ncdu 1.14 released' ], - [ '2018-02-23', '/nginx-confgen', 'nginx-confgen 1.2 released' ], - [ '2018-02-18', '/tuwf', 'TUWF 1.2 released' ], - [ '2018-01-29', '/ncdu', 'ncdu 1.13 released' ], - [ '2018-01-24', '/nginx-confgen', 'nginx-confgen 1.1 released' ], - [ '2018-01-19', '/nginx-confgen', 'New project: nginx-confgen' ], - [ '2017-05-28', '/doc/funcweb', 'New article: An Opinionated Survey of Functional Web Development' ], - [ '2016-12-30', '/ncdc', 'ncdc 1.20 released' ], - [ '2016-08-24', '/ncdu', 'ncdu 1.12 released' ], - [ '2016-08-16', '/dump/btrfssize', 'Uploaded btrfs-size.pl' ], - [ '2015-09-27', '/tuwf', 'TUWF 1.0 released' ], - [ '2015-04-05', '/ncdu', 'ncdu 1.11 released' ], - [ '2014-07-29', '/doc/easyipc', 'New article: The Sorry State of Convenient IPC' ], - [ '2014-06-25', '/doc', 'Uploaded my masters thesis' ], - [ '2014-04-23', '/ncdc', 'ncdc 1.19.1 released' ], - [ '2014-02-11', '/ncdc', 'ncdc 1.19 released' ], - [ '2014-01-09', '/doc/dcstats', 'Uploaded an article on DC file list stats' ], - [ '2013-11-14', '/yxml/man', 'yxml now has a manual' ], - [ '2013-10-05', '/ncdc', 'ncdc 1.18.1 released' ], - [ '2013-09-25', '/ncdc', 'ncdc 1.18 released' ], - [ '2013-09-03', '/yxml', 'Announcing yxml: A small, fast and correct XML parser' ], - [ '2013-07-05', '/dump/insbench', 'Documented a little data structure benchmark' ], - [ '2013-06-15', '/ncdc', 'ncdc 1.17 released' ], - [ '2013-05-09', '/ncdu', 'ncdu 1.10 released' ], - [ '2013-04-04', '/ylib', 'Created a page for Ylib' ], - [ '2013-04-03', '/ncdc', 'Created a mailing list for ncdc' ], - [ '2013-03-23', '/ncdc', 'ncdc 1.16.1 released.' ], - [ '2013-03-02', '/ncdc', 'ncdc 1.15 released.' ], - [ '2012-12-15', '/globster', 'Announcing yet another awesome project: Globster!' ], - [ '2012-12-02', '/ncdu/jsonfmt', 'Documented the ncdu export file format' ], - [ '2012-11-04', '/ncdc', 'ncdc 1.14 released' ], - [ '2012-10-17', '/dump', 'Added reference to my repo of small C libs to the code dump' ], - [ '2012-10-07', '/dump#maildir.pl','Added maildir.pl to the code dump' ], - [ '2012-09-27', '/ncdu', 'ncdu 1.9 released.' ], - [ '2012-09-25', '/dump#dbusev.c', 'Added dbusev.c to the code dump' ], - [ '2012-08-16', '/ncdc', 'ncdc 1.13 released.' ], - [ '2012-07-10', '/ncdc', 'ncdc 1.12 released.' ], - [ '2012-05-15', '/ncdc', 'ncdc 1.11 released.' ], - [ '2012-05-03', '/ncdc/install', 'Added installation instructions for ncdc.' ], - [ '2012-05-03', '/ncdc', 'ncdc 1.10 released.' ], - [ '2012-04-10', undef, 'Minor site re-style: ncdu/ncdc/tuwf now have their own menu.' ], - [ '2012-03-30', '/dump', 'Updated ncdc-share-report for Go 1' ], - [ '2012-03-24', '/ncdu/bug', 'Moved ncdu bug tracker from sourceforge to this site' ], - [ '2012-03-17', '/ncdc/bug', 'Wrote a small bug tracker for ncdc' ], - [ '2012-03-14', '/ncdc', 'ncdc 1.9 released.' ], - [ '2012-02-15', '/doc/commvis', 'Added an article on my new communication system.' ], - [ '2012-02-13', '/ncdc', 'ncdc 1.8 released.' ], - [ '2012-01-19', '/tuwf', 'TUWF 0.2 released.' ], - [ '2012-01-17', undef, 'Complete site redesign.' ], - [ '2011-12-30', '/ncdc', 'ncdc 1.7 released!' ], - [ '2011-12-07', '/ncdc', 'ncdc 1.6 released!' ], - [ '2011-11-26', '/doc', 'Added article section and the article on SQLite.' ], - [ '2011-11-03', '/ncdu', 'ncdu 1.8 released!' ], - [ '2011-11-03', '/ncdc', 'ncdc 1.5 released!' ], - [ '2011-10-26', '/ncdc', 'ncdc 1.4 released!' ], - [ '2011-10-19', undef, 'PGP-signed all releases of ncdu, ncdc and TUWF.' ], - [ '2011-10-14', '/ncdc', 'ncdc 1.3 released!' ], - [ '2011-09-25', '/ncdc', 'ncdc 1.1 released - follwed by a 1.2 quickfix.' ], - [ '2011-09-16', '/ncdc', 'ncdc 1.0 released!' ], - [ '2011-09-15', '/ncdc/scr', 'Added some screenshots for ncdu.' ], - [ '2011-09-03', '/ncdc', 'ncdc 0.9 released!' ], - [ '2011-08-26', '/ncdc', 'ncdc 0.8 released!' ], - [ '2011-08-17', '/ncdc', 'ncdc 0.7 released!' ], - [ '2011-08-08', '/ncdc', 'ncdc 0.6 released & user guide updated' ], - [ '2011-08-02', '/ncdc', 'ncdc 0.5 released!' ], - [ '2011-07-23', '/ncdc', 'ncdc 0.4 released!' ], - [ '2011-07-15', '/ncdc', 'ncdc 0.3 released!' ], - [ '2011-06-27', '/ncdc', 'ncdc 0.2 released!' ], - [ '2011-06-20', '/ncdc', 'ncdc 0.1 released! And wrote a user guide for it.' ], - [ '2011-06-11', '/dump/nccolour', 'Added NCurses colour experiment' ], - [ '2011-06-03', '/ncdc', 'Added my latest project: ncdc' ], - [ '2011-02-07', '/tuwf', 'TUWF 0.1 released and now also available on CPAN' ], - [ '2011-01-27', '/tuwf', 'Documented and uploaded one of my older projects: TUWF' ], - [ '2011-01-09', '/dump', 'Added my json.mll OCaml library to code dump' ], - [ '2010-08-13', '/ncdu', 'ncdu 1.7 released!' ], - [ '2009-12-22', '/dump', 'Added vinfo.c script to code dump' ], - [ '2009-10-23', '/ncdu', 'ncdu 1.6 released!' ], - [ '2009-09-21', undef, 'Tiny CSS fix to make this site look good in certain configurations.' ], - [ '2009-05-02', '/ncdu', 'ncdu 1.5 released!' ], - [ '2009-04-30', undef, 'Site redesign and reorganisation.' ], -); - -my %feeds = map +($_,1), qw|ncdc ncdu globster tuwf yxml|; -my $feedreg = join '|', keys %feeds; - - -TUWF::register( - qr{} => sub { podpage(shift, 'home', '', '', "Yorhel's Projects") }, - qr{ncdu} => sub { podpage(shift, 'ncdu', 'ncdu', '', 'NCurses Disk Usage') }, - qr{ncdu/man} => sub { podpage(shift, 'ncdu-man', 'ncdu', 'man', 'Ncdu Manual', 1) }, - qr{ncdu/changes} => sub { changelog(shift, 'ncdu-changelog', 'ncdu', 'ncdu', 'changes', 'Ncdu Changelog') }, - qr{ncdu/scr} => sub { podpage(shift, 'ncdu-scr', 'ncdu', 'scr', 'Ncdu Screenshots') }, - qr{ncdu/jsonfmt} => sub { podpage(shift, 'ncdu-jsonfmt', 'ncdu', 'jsonfmt', 'Ncdu Export File Format') }, - qr{ncdc} => sub { podpage(shift, 'ncdc', 'ncdc', '', 'NCurses Direct Connect') }, - qr{ncdc/faq} => sub { podpage(shift, 'ncdc-faq', 'ncdc', 'faq', 'Ncdc Q&A', 1) }, - qr{ncdc/scr} => sub { podpage(shift, 'ncdc-scr', 'ncdc', 'scr', 'Ncdc Screenshots') }, - qr{ncdc/man} => sub { podpage(shift, 'ncdc-man', 'ncdc', 'man', 'Ncdc Manual', 1) }, - qr{ncdc/install} => sub { podpage(shift, 'ncdc-install', 'ncdc', 'install', 'Ncdc Installation Instructions', 1) }, - qr{ncdc/changes} => sub { changelog(shift, 'ncdc-changelog', 'ncdc', 'ncdc', 'changes', 'Ncdc Changelog') }, - qr{globster} => sub { podpage(shift, 'globster', 'globster', '', 'The Globster Direct Connect Client') }, - qr{globster/api} => sub { podpage(shift, 'globster-api', 'globster', 'api', 'The Globster D-Bus API', 1) }, - qr{globster/daemon} => sub { podpage(shift, 'globster-daemon', 'globster', 'daemon', 'The globster(1) Man Page', 1) }, - qr{globster/launch} => sub { podpage(shift, 'globster-launch', 'globster', 'launch', 'The globster-launch(1) Man Page', 1) }, - qr{globster/ctl} => sub { podpage(shift, 'globster-ctl', 'globster', 'ctl', 'The globsterctl(1) Man Page', 1) }, - qr{nginx-confgen} => sub { podpage(shift, 'nginx-confgen', 'nginx-confgen', '', 'Nginx Configuration Generator') }, - qr{nginx-confgen/man} => sub { podpage(shift, 'nginx-confgen-man', 'nginx-confgen', 'man', 'The nginx-confgen(1) Man Page', 1) }, - qr{nginx-confgen/changes} => sub { changelog(shift, 'nginx-confgen-changelog', undef, 'nginx-confgen', 'changes', 'nginx-confgen Changelog', 1) }, - qr{tuwf} => sub { podpage(shift, 'tuwf', 'tuwf', '', 'The Ultimate Website Framework') }, - qr{tuwf/man(?:/(db|intro|misc|request|response|validate|xml))?} => \&tuwfmanual, - qr{tuwf/changes} => sub { changelog(shift, 'tuwf-changelog', 'TUWF', 'tuwf', 'changes', 'TUWF Changelog') }, - qr{ylib} => sub { podpage(shift, 'ylib/README.pod', 'ylib', '', 'Ylib') }, - qr{yxml} => sub { podpage(shift, 'yxml', 'yxml', '', 'Yxml - A small, fast and correct* XML parser') }, - qr{yxml/man} => sub { podpage(shift, 'yxml-man', 'yxml', 'man', 'Yxml Manual', 1) }, - qr{doc} => sub { podpage(shift, 'doc', 'doc', '', 'Writing') }, - qr{doc/sqlaccess} => sub { podpage(shift, 'sqlaccess', 'doc', '', 'Multi-threaded Access to an SQLite3 Database', 1) }, - qr{doc/commvis} => sub { podpage(shift, 'doc-commvis', 'doc', '', 'A Distributed Communication System for Modular Applications', 1) }, - qr{doc/dcstats} => sub { podpage(shift, 'doc-dcstats', 'doc', '', 'Some Measurements on Direct Connect File Lists', 1) }, - qr{doc/easyipc} => sub { podpage(shift, 'doc-easyipc', 'doc', '', 'The Sorry State of Convenient IPC', 1) }, - qr{doc/funcweb} => sub { podpage(shift, 'doc-funcweb', 'doc', '', 'An Opinionated Survey of Functional Web Development') }, - qr{dump} => sub { podpage(shift, 'dump', 'dump', '', 'Code dump') }, - qr{demo} => sub { podpage(shift, 'dump-demo', 'dump', 'demo', 'Demos') }, - qr{dump/awshrink} => sub { podpage(shift, 'dump-awshrink', 'dump', 'awshrink', 'AWStats Data File Shrinker') }, - qr{dump/btrfssize}=> sub { podpage(shift, 'dump-btrfssize', 'dump', 'btrfssize', 'btrfs-size.pl') }, - qr{dump/grenamr} => sub { podpage(shift, 'dump-grenamr', 'dump', 'grenamr', 'GTK+ Mass File Renamer') }, - qr{dump/insbench} => sub { podpage(shift, 'dump-insbench', 'dump', 'insbench', 'Insertion Performance Benchmarks') }, - qr{dump/nccolour} => sub { podpage(shift, 'dump-nccolour', 'dump', 'nccolour', 'Colours in NCurses') }, - qr{(?:($feedreg)/)?feed\.atom} => \&atom, - qr{(ncdc|ncdu|globster|yxml)/bug} => \&bug_list, - qr{(ncdc|ncdu|globster|yxml)/bug/feed\.atom} => \&bug_atom, - qr{(ncdc|ncdu|globster|yxml)/bug/post} => \&bug_post, - qr{(ncdc|ncdu|globster|yxml)/bug/new} => \&bug_new, - qr{(ncdc|ncdu|globster|yxml)/bug/([1-9][0-9]*)} => \&bug_item, -); - -TUWF::set( - logfile => '/var/log/apache2/tuwf.log', - error_404_handler => \¬found, - mail_from => 'Yorhels Bug Tracker ', - # this is a fairly static site, allow some aggressive caching - pre_request_handler => sub { $_[0]->resHeader('Cache-Control', 's-max-age=86400, max-age=3600'); 1; }, - cookie_defaults => { domain => 'dev.yorhel.nl', path => '/', secure => 1 }, - db_login => [ undef, undef, undef ], -); - -TUWF::run(); - - -sub podpage { - my($s, $f, $p, $se, $t, $toc) = @_; - $s->htmlHeader(title => $t, page => $p, sec => $se); - $s->htmlPOD($f, $toc); - $s->htmlFooter; -} - - -sub changelog { - my($s, $f, $pr, $p, $se, $t) = @_; - $s->htmlHeader(title => $t, page => $p, sec => $se); - open my $F, '<', "$ROOT/dat/$f" or die $!; - ul; - for my $v (split /\n\n/, join '', <$F>) { - $v =~ s/^([0-9]+\.[0-9]+(?:\.[0-9]+)?)\s+-\s+([0-9]{4}-[0-9]{2}-[0-9]{2})//; - li style => 'list-style-type: none; margin: 0'; - b $1; - txt " - $2"; - if($pr) { - txt ' - '; - lit $s->genDLLink("$pr-$1.tar.gz"); - } - br; - ul; - for (split(/\r?\n\s+-\s+/, $v)) { - s/[\r\n\s]{2,50}/ /; - li $_ if $_; - } - end; - br; - end; - } - end; - close $F; - $s->htmlFooter; -} - - -sub tuwfmanual { - my $s = shift; - my $man = shift || ''; - my %mod = (qw|db DB xml XML|); - my $mod = 'TUWF'; - $mod .= '/'.($mod{$man} || ucfirst $man) if $man; - (my $pm = $mod) =~ s/\//::/; - $s->htmlHeader(title => $pm.' Documentation', page => 'tuwf', sec => 'man', sec2 => $man); - (my $f = $INC{"TUWF.pm"}) =~ s/TUWF\.pm$/$mod.pod/; - $s->htmlPOD($f, 1); - $s->htmlFooter; -} - - -sub atom { - my $s = shift; - my $sub = shift; - my $t = (stat("$ROOT/index.cgi"))[9]; - $s->resHeader('Last-Modified' => strftime '%a, %d %b %Y %H:%M:%S GMT', gmtime $t); - $s->resHeader('Content-Type' => 'application/atom+xml'); - TUWF::XML::xml; - tag feed => xmlns => 'http://www.w3.org/2005/Atom', 'xml:lang' => 'en', 'xml:base' => 'https://dev.yorhel.nl/'; - tag title => $sub ? "\u$sub Project Announcements" : "Yorhel's Projects"; - tag updated => strftime('%Y-%m-%dT%H:%M:%SZ', gmtime $t); - tag id => "https://dev.yorhel.nl/feed.atom"; - tag link => rel => 'self', type => 'application/atom+xml', href => "https://dev.yorhel.nl/feed.atom", undef; - tag link => rel => 'alternate', type => 'text/html', href => 'https://dev.yorhel.nl/', undef; - - my $n = 0; - for(@changes) { - next if $sub && (!$_->[1] || $_->[1] !~ /^\/\Q$sub/); - last if $n++ >= 10; - tag 'entry'; - tag id => 'https://dev.yorhel.nl'.($_->[1]||'/').'#'.$_->[0]; - tag title => $_->[2]; - tag updated => $_->[0].'T12:00:00Z'; - tag published => $_->[0].'T12:00:00Z'; - tag 'author'; - tag name => 'Yoran Heling'; - tag uri => 'https://dev.yorhel.nl/'; - tag email => 'projects@yorhel.nl'; - end; - tag link => rel => 'alternate', type => 'text/html', href => 'https://dev.yorhel.nl'.($_->[1]||'/'), undef; - end 'entry'; - } - end 'feed'; -} - - -sub notfound { - my $s = shift; - my $u = lc $s->reqPath; - ($_->[0] eq $u || $_->[0] eq "$u/") && return $s->resRedirect($_->[1], 'perm') for ( - [ '/bluecubes', '/demo' ], - [ '/ncdc/guide', '/ncdc/man' ], - [ '/dump', '/dump' ], - [ '/dump/index2', '/dump' ], - [ '/dump/pmdc2-parse', '/dump' ], - [ '/dump/cbbcode', '/dump' ], - [ '/dump/cechoserv', '/dump' ], - [ '/dump/cyapong', '/dump' ], - [ '/dump/awshrink', '/dump/awshrink' ], - [ '/dump/grenamr', '/dump/grenamr' ], - ); - return $s->resRedirect("$u", 'perm') if $u =~ s/\/$//; - return $s->resRedirect("/$1/bug$2", 'perm') if $u =~ /^(ncd[uc])\/issue(.*)$/; - $s->resStatus(404); - $s->htmlHeader(title => '404', page => '404'); - txt 'Sorry, there is no page at this URI. Try one of the links from the menu to find the page you are looking for.'; - $s->htmlFooter; -} - - - - -# Bug tracker - -sub _bug_init { - require "$ROOT/Bug.pm"; - my($s, $p) = @_; - $s->resHeader('Cache-Control', 'no-cache'); - #$s->_load_module('TUWF::DB'); - #$s->{_TUWF}{db_login} = [ undef, undef, undef ]; - #$s->dbInit; - return TUWF::Bug->new(table => $p, admins => [ $ENV{ISSUE_CODE} ]); -} - - -sub bug_list { - my($s, $p) = @_; - my $is = _bug_init(@_); - $s->htmlHeader(title => "\u$p Bug tracker", page => $p, sec => 'bug'); - br; a href => "/$p/bug/new", 'Report new bug'; - - p class => 'bug_filter'; - txt 'filter{'; - my $cl = $s->reqParam('cl')||0; - a href => "/$p/bug", 'open' if $cl; - txt 'open' if !$cl; - txt '/'; - a href => "/$p/bug?cl=1", 'closed' if $cl != 1; - txt 'closed' if $cl == 1; - txt '/'; - a href => "/$p/bug?cl=2", 'all' if $cl != 2; - txt 'all' if $cl == 2; - txt '}'; - end; - - $is->htmlListing((scalar $is->dbListing(closed => $cl)), sub { "/$p/bug/".shift }); - br; a href => "/$p/bug/new", 'Report new bug'; br; br; - $s->htmlFooter; -} - - -sub bug_atom { - my($s, $p) = @_; - my $is = _bug_init(@_); - $is->atomFeed(sub { "https://dev.yorhel.nl/$p/bug/".shift }); -} - - -sub bug_new { - my($s, $p) = @_; - my $is = _bug_init(@_); - $s->htmlHeader(title => "\u$p: Report new bug", page => $p, sec => 'bug'); - br; a href => "/$p/bug", 'Back to the bug index'; br; br; - $is->htmlForm(undef, "/$p/bug/post"); - $s->htmlFooter; -} - - -sub bug_post { - my($s, $p) = @_; - return $s->resNotFound if $s->reqMethod() ne 'POST'; - my $is = _bug_init($s, $p); - my($f, $l) = $is->handleForm(sub { "/$p/bug/".shift }); - - if($f->{_err}) { - $s->htmlHeader(title => 'Error creating message', page => $p, sec => 'bug'); - p 'There was an error in the form. Please use the \'back\' button of your - browser to go back to the form (hopefully) without losing your message. - There was an error in the following fields: '.join(', ', map {(my$f=$_->[0])=~s/bug_// ;"\u$f"} @{$f->{_err}}).'.'; - return $s->htmlFooter; - } - - # Announce this report to the ncdc hub, through the globster bot - #eval { - # $ENV{DBUS_SESSION_BUS_ADDRESS} = 'unix:path=/tmp/dbus-globster'; - # require Net::DBus; - # my $msg = "Bug activity for $p: $l->{summary} -> https://dev.yorhel.nl/$p/bug/$l->{issue}"; - # Net::DBus->find->get_service("net.blicky.Globster")->get_object("/net/blicky/Globster/Hub/1")->SendChat(-1, $msg, 0); - # 1; - #} || warn $@; -} - - -sub bug_item { - my($s, $p, $i) = @_; - my $is = _bug_init($s, $p); - my $item = $is->dbItem($i); - return $s->resNotFound if !@$item; - my $last = $item->[$#$item]; - $s->htmlHeader(title => "\u$p: $last->{summary}", page => $p, sec => 'bug'); - br; a href => "/$p/bug", 'Back to the bug index'; br; br; - $is->htmlItem($item); - $is->htmlForm($last, "/$p/bug/post"); - br; a href => "/$p/bug", 'Back to the bug index'; br; br; - $s->htmlFooter; -} - - - - -package TUWF::Object; -use TUWF ':html'; - - -# Accepts some special formatting codes: -# [dllink $file $title] -# [img $class $file $alt] -# [html]..É -# [yh-changes] -sub htmlPOD { - my($s, $file, $toc) = @_; - require Pod::Simple::HTML; - - { - # The usual output escaping function is terribly stupid - no warnings 'redefine', 'once'; - *Pod::Simple::HTML::esc = sub { - return map TUWF::XML::html_escape($_), @_ if wantarray; - return TUWF::XML::html_escape($_[0]) if defined wantarray; - $_ = TUWF::XML::html_escape($_) for(@_); - return @_; - }; - - # Let's override the manual page links - *Pod::Simple::HTML::do_man_link = sub { - my $l = $_[1]->attr('to'); - my %l = qw| - globsterctl(1) /globster/ctl - globster-launch(1) /globster/launch - globster(1) /globster/daemon - globster-api(7) /globster/api - ncdu(1) /ncdu/man - |; - return $l{$l} || ($l =~ /(.+)\((.)\)/ and "http://manned.org/$1.$2"); - }; - } - - my $p = Pod::Simple::HTML->new(); - my $html = ''; - $p->html_header_before_title(''); - $p->html_footer(''); - $p->parse_characters(1); - $p->output_string(\$html); - $p->{podhtml_LOT} = { - 'TUWF' => '/tuwf/man', - 'TUWF::DB' => '/tuwf/man/db', - 'TUWF::Intro' => '/tuwf/man/intro', - 'TUWF::Misc' => '/tuwf/man/misc', - 'TUWF::Request' => '/tuwf/man/request', - 'TUWF::Response' => '/tuwf/man/response', - 'TUWF::XML' => '/tuwf/man/xml', - }; - open(my $F, '<:utf8', $file =~ /^\// ? $file : "$ROOT/dat/$file") or die $!; - $p->parse_file($F); - close $F; - lit $p->index_as_html() if $toc; - $html =~ s/\[dllink ([^ ]+)(?: ([^>]+))?\]/$s->genDLLink($1, $2)/eg; - $html =~ s/\[img ([^ ]+) ([^ ]+) ([^\]]*)\]/$3/g; - $html =~ s{\[html\](.*)É}{(my $h = $1) =~ s/\>/>/g; $h =~ s/\</genChanges()/e; - $html =~ s/
( +(?:method|signal|property)) /
$1 /g;
-  lit $html;
-}
-
-
-sub genDLLink {
-  my($s, $f, $m) = @_;
-  return sprintf
-    '%s'
-   .'pgp-sha1-md5',
-   $f, $f||$m;
-}
-
-
-# Generate the changelog HTML for this website
-sub genChanges {
-  return join "\n", map {
-    "$_->[0] "
-    .($_->[1]?qq{}:'')
-    .TUWF::XML::html_escape($_->[2])
-    .($_->[1]?'':'')
-    .'
'; - } @changes; -} - - -sub htmlHeader { - my $s = shift; - my %o = ( - spec => { map +($_,1), qw|ncdu ncdc globster tuwf yxml nginx-confgen| }, - page => '', - sec => '', - sec2 => '', - @_ - ); - html; - head; - Link rel => 'stylesheet', href => '/style.css', type => 'text/css', media => 'all'; - Link rel => 'alternate', type => 'application/atom+xml', href => ($feeds{$o{page}||''} ? "/$o{page}" : '').'/feed.atom', title => 'Site updates'; - title $o{title}; - end; - body; - div id => 'body'; - div id => 'uglyhack', ' '; - div id => 'left'; - $s->htmlMenu(%o); - div class => 'notes'; - txt 'Yoran Heling'; br; - a href => 'mailto:projects@yorhel.nl', 'projects@yorhel.nl'; - br; a href => 'https://yorhel.nl/', 'home'; - txt ' - '; a href => 'https://g.blicky.net/', 'git'; - txt ' - '; a href => 'https://niu.moe/@ayo', '@ayo'; - br; b '= donate ='; - a href => 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=BBF8LGT2LLNFN&lc=US¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted', 'paypal'; - br; b '= pgp ='; - txt 'only used for releases'; br; - a href => 'https://yorhel.nl/key.asc', 'key'; - txt ' - '; a href => 'http://pgp.mit.edu:11371/pks/lookup?search=0x8c2739fa', 'mit'; - br; i '7446 0D32 B808 10EB A9AF A2E9 6239 4C69 8C27 39FA'; - end; - img id => 'scissors', src => '/img/scissors.png', alt => 'Cute decorative scissors, cutting through your code.'; - end 'div'; - div id => 'main'; - h1 class => 'title', $o{title}; -} - - -sub htmlFooter { - end 'div'; # main - div id => 'footer'; - p 'all lefts and rights reversed'; - end; - end 'div'; # body - end 'body'; - end 'html'; -} - - -sub htmlMenu { - my($s, %o) = @_; - h1 class => 'title', "~ \u$o{page} ~" if $o{spec}{$o{page}}; - my $m = sub { - li; - my $s = ($_[0] =~ m{^/([^/]+)} && $o{spec}{$1} && $o{page} ne $1) || $_[0] =~ m{^https?://}; - my @c = ($s?'special':(), $_[2]?'menusel':(), $_[4]?'tiny':()); - a href => $_[0], @c?(class => join ' ',@c):(), $_[1]; - if($_[3]) { - ul; - $_[3]->(); - end; - } - end; - }; - ul; - if($o{page} eq 'ncdu') { - $m->('/ncdu', 'Info', !$o{sec}); - $m->('/ncdu/man', 'Manual', $o{sec} eq 'man', sub { - $m->('/ncdu/jsonfmt','File Format', $o{sec} eq 'jsonfmt'); - }); - $m->('/ncdu/changes', 'Changelog', $o{sec} eq 'changes'); - $m->('/ncdu/scr', 'Screenshots', $o{sec} eq 'scr'); - $m->('/ncdu/bug', 'Bug tracker', $o{sec} eq 'bug'); - } elsif($o{page} eq 'ncdc') { - $m->('/ncdc', 'Info', !$o{sec}); - $m->('/ncdc/install', 'Installation',$o{sec} eq 'install'); - $m->('/ncdc/faq', 'Q&A', $o{sec} eq 'faq'); - $m->('/ncdc/man', 'Manual', $o{sec} eq 'man'); - $m->('/ncdc/changes', 'Changelog', $o{sec} eq 'changes'); - $m->('/ncdc/scr', 'Screenshots', $o{sec} eq 'scr'); - $m->('/ncdc/bug', 'Bug tracker', $o{sec} eq 'bug'); - } elsif($o{page} eq 'globster') { - $m->('/globster', 'Info', !$o{sec}); - $m->('/globster/daemon', 'Commands', (scalar $o{sec} =~ /(daemon|ctl|launch)/), sub { - $m->('/globster/daemon', 'globster', $o{sec} eq 'daemon', undef, 1); - $m->('/globster/ctl', 'globsterctl', $o{sec} eq 'ctl', undef, 1); - $m->('/globster/launch', 'globster-launch', $o{sec} eq 'launch', undef, 1); - }); - $m->('/globster/api', 'API Doc', $o{sec} eq 'api'); - $m->('/globster/bug', 'Bug tracker', $o{sec} eq 'bug'); - } elsif($o{page} eq 'tuwf') { - $m->('/tuwf', 'Info', !$o{sec}); - $m->('/tuwf/man', 'Manual', $o{sec} eq 'man', sub { - $m->('/tuwf/man', 'Main', $o{sec} eq 'man' && !$o{sec2}); - $m->('/tuwf/man/db', '::DB', $o{sec} eq 'man' && $o{sec2} eq 'db'); - $m->('/tuwf/man/intro', '::Intro', $o{sec} eq 'man' && $o{sec2} eq 'intro'); - $m->('/tuwf/man/misc', '::Misc', $o{sec} eq 'man' && $o{sec2} eq 'misc'); - $m->('/tuwf/man/request', '::Request', $o{sec} eq 'man' && $o{sec2} eq 'request'); - $m->('/tuwf/man/response', '::Response', $o{sec} eq 'man' && $o{sec2} eq 'response'); - $m->('/tuwf/man/validate', '::Validate', $o{sec} eq 'man' && $o{sec2} eq 'validate'); - $m->('/tuwf/man/xml', '::XML', $o{sec} eq 'man' && $o{sec2} eq 'xml'); - }); - $m->('/tuwf/changes', 'Changelog', $o{sec} eq 'changes'); - $m->('https://code.blicky.net/yorhel/tuwf/issues', 'Issues'); - } elsif($o{page} eq 'yxml') { - $m->('/yxml', 'Info', !$o{sec}); - $m->('/yxml/man', 'Manual', $o{sec} eq 'man'); - $m->('/yxml/bug', 'Bug tracker', $o{sec} eq 'bug'); - } elsif($o{page} eq 'nginx-confgen') { - $m->('/nginx-confgen', 'Info', !$o{sec}); - $m->('/nginx-confgen/man', 'Manual', $o{sec} eq 'man'); - $m->('/nginx-confgen/changes', 'Changelog', $o{sec} eq 'changes'); - $m->('https://code.blicky.net/yorhel/nginx-confgen/issues', 'Issues'); - } else { - $m->('/', 'Home', !$o{page}); - $m->('/ncdu', 'Ncdu '); - $m->('/ncdc', 'Ncdc '); - $m->('/tuwf', 'Tuwf '); - $m->('/yxml', 'Yxml '); - $m->('/nginx-confgen', 'Nginx-cfg '); - $m->('/ylib', 'Ylib', $o{page} eq 'ylib'); - $m->('/doc', 'Writing', $o{page} eq 'doc'); - $m->('/dump', 'Code dump', $o{page} eq 'dump', sub { - $m->('/dump', 'Misc.', $o{page} eq 'dump' && !$o{sec}); - $m->('/demo', 'Demos', $o{page} eq 'dump' && $o{sec} eq 'demo'); - $m->('/dump/awshrink','AWShrink', $o{page} eq 'dump' && $o{sec} eq 'awshrink'); - $m->('/dump/grenamr', 'Grenamr', $o{page} eq 'dump' && $o{sec} eq 'grenamr'); - $m->('/dump/nccolour','NC-Colour', $o{page} eq 'dump' && $o{sec} eq 'nccolour'); - $m->('/dump/insbench','Ins-bench', $o{page} eq 'dump' && $o{sec} eq 'insbench'); - $m->('/dump/btrfssize','Btrfs-size', $o{page} eq 'dump' && $o{sec} eq 'btrfssize'); - }); - $m->('/globster', 'Globster '); - } - if($o{spec}{$o{page}}) { - li; - a href => '/', class => 'small special', 'Projects home '; - end; - } - end; -} - diff --git a/pub/.htaccess b/pub/.htaccess new file mode 100644 index 0000000..81b263f --- /dev/null +++ b/pub/.htaccess @@ -0,0 +1,246 @@ +DirectorySlash off +RewriteEngine on +RewriteBase / + +# This rule is evaluated even after the last "everything goes to .html" rule, +# meaning it will keep redirecting. :( +#RewriteRule ^(.+)\.html$ $1 [L,R=permanent] + +# Old URLs +RewriteRule ^demo/*$ /dump/demo [L,R=permanent] +RewriteRule ^bluecubes/*$ /dump/demo [L,R=permanent] +RewriteRule ^ncdc/guide/*$ /ncdc/man [L,R=permanent] +RewriteRule ^dump/index2/*$ /dump [L,R=permanent] +RewriteRule ^dump/pmdc2-parse/*$ /dump [L,R=permanent] +RewriteRule ^dump/cbbcode/*$ /dump [L,R=permanent] +RewriteRule ^dump/cechoserv/*$ /dump [L,R=permanent] +RewriteRule ^dump/cyapong/*$ /dump [L,R=permanent] +RewriteRule ^ncdu/issue(.*)$ /ncdu/bug$1 [L,R=permanent] +RewriteRule ^ncdc/issue(.*)$ /ncdc/bug$1 [L,R=permanent] + +RewriteRule ^ncdu/bug/1$ https://code.blicky.net/yorhel/ncdu/issues/3 [L,R=permanent] +RewriteRule ^ncdu/bug/2$ https://code.blicky.net/yorhel/ncdu/issues/4 [L,R=permanent] +RewriteRule ^ncdu/bug/3$ https://code.blicky.net/yorhel/ncdu/issues/5 [L,R=permanent] +RewriteRule ^ncdu/bug/4$ https://code.blicky.net/yorhel/ncdu/issues/6 [L,R=permanent] +RewriteRule ^ncdu/bug/5$ https://code.blicky.net/yorhel/ncdu/issues/7 [L,R=permanent] +RewriteRule ^ncdu/bug/6$ https://code.blicky.net/yorhel/ncdu/issues/8 [L,R=permanent] +RewriteRule ^ncdu/bug/9$ https://code.blicky.net/yorhel/ncdu/issues/9 [L,R=permanent] +RewriteRule ^ncdu/bug/10$ https://code.blicky.net/yorhel/ncdu/issues/10 [L,R=permanent] +RewriteRule ^ncdu/bug/13$ https://code.blicky.net/yorhel/ncdu/issues/11 [L,R=permanent] +RewriteRule ^ncdu/bug/14$ https://code.blicky.net/yorhel/ncdu/issues/12 [L,R=permanent] +RewriteRule ^ncdu/bug/15$ https://code.blicky.net/yorhel/ncdu/issues/13 [L,R=permanent] +RewriteRule ^ncdu/bug/16$ https://code.blicky.net/yorhel/ncdu/issues/14 [L,R=permanent] +RewriteRule ^ncdu/bug/17$ https://code.blicky.net/yorhel/ncdu/issues/15 [L,R=permanent] +RewriteRule ^ncdu/bug/18$ https://code.blicky.net/yorhel/ncdu/issues/16 [L,R=permanent] +RewriteRule ^ncdu/bug/19$ https://code.blicky.net/yorhel/ncdu/issues/17 [L,R=permanent] +RewriteRule ^ncdu/bug/20$ https://code.blicky.net/yorhel/ncdu/issues/18 [L,R=permanent] +RewriteRule ^ncdu/bug/21$ https://code.blicky.net/yorhel/ncdu/issues/19 [L,R=permanent] +RewriteRule ^ncdu/bug/22$ https://code.blicky.net/yorhel/ncdu/issues/20 [L,R=permanent] +RewriteRule ^ncdu/bug/24$ https://code.blicky.net/yorhel/ncdu/issues/21 [L,R=permanent] +RewriteRule ^ncdu/bug/25$ https://code.blicky.net/yorhel/ncdu/issues/22 [L,R=permanent] +RewriteRule ^ncdu/bug/26$ https://code.blicky.net/yorhel/ncdu/issues/23 [L,R=permanent] +RewriteRule ^ncdu/bug/27$ https://code.blicky.net/yorhel/ncdu/issues/24 [L,R=permanent] +RewriteRule ^ncdu/bug/28$ https://code.blicky.net/yorhel/ncdu/issues/25 [L,R=permanent] +RewriteRule ^ncdu/bug/29$ https://code.blicky.net/yorhel/ncdu/issues/26 [L,R=permanent] +RewriteRule ^ncdu/bug/30$ https://code.blicky.net/yorhel/ncdu/issues/27 [L,R=permanent] +RewriteRule ^ncdu/bug/31$ https://code.blicky.net/yorhel/ncdu/issues/28 [L,R=permanent] +RewriteRule ^ncdu/bug/32$ https://code.blicky.net/yorhel/ncdu/issues/29 [L,R=permanent] +RewriteRule ^ncdu/bug/33$ https://code.blicky.net/yorhel/ncdu/issues/30 [L,R=permanent] +RewriteRule ^ncdu/bug/34$ https://code.blicky.net/yorhel/ncdu/issues/31 [L,R=permanent] +RewriteRule ^ncdu/bug/35$ https://code.blicky.net/yorhel/ncdu/issues/32 [L,R=permanent] +RewriteRule ^ncdu/bug/36$ https://code.blicky.net/yorhel/ncdu/issues/33 [L,R=permanent] +RewriteRule ^ncdu/bug/37$ https://code.blicky.net/yorhel/ncdu/issues/34 [L,R=permanent] +RewriteRule ^ncdu/bug/38$ https://code.blicky.net/yorhel/ncdu/issues/35 [L,R=permanent] +RewriteRule ^ncdu/bug/39$ https://code.blicky.net/yorhel/ncdu/issues/36 [L,R=permanent] +RewriteRule ^ncdu/bug/40$ https://code.blicky.net/yorhel/ncdu/issues/37 [L,R=permanent] +RewriteRule ^ncdu/bug/41$ https://code.blicky.net/yorhel/ncdu/issues/38 [L,R=permanent] +RewriteRule ^ncdu/bug/42$ https://code.blicky.net/yorhel/ncdu/issues/39 [L,R=permanent] +RewriteRule ^ncdu/bug/43$ https://code.blicky.net/yorhel/ncdu/issues/40 [L,R=permanent] +RewriteRule ^ncdu/bug/44$ https://code.blicky.net/yorhel/ncdu/issues/41 [L,R=permanent] +RewriteRule ^ncdu/bug/45$ https://code.blicky.net/yorhel/ncdu/issues/42 [L,R=permanent] +RewriteRule ^ncdu/bug/46$ https://code.blicky.net/yorhel/ncdu/issues/43 [L,R=permanent] +RewriteRule ^ncdu/bug/47$ https://code.blicky.net/yorhel/ncdu/issues/44 [L,R=permanent] +RewriteRule ^ncdu/bug/48$ https://code.blicky.net/yorhel/ncdu/issues/45 [L,R=permanent] +RewriteRule ^ncdu/bug/49$ https://code.blicky.net/yorhel/ncdu/issues/46 [L,R=permanent] +RewriteRule ^ncdu/bug/50$ https://code.blicky.net/yorhel/ncdu/issues/47 [L,R=permanent] +RewriteRule ^ncdu/bug/51$ https://code.blicky.net/yorhel/ncdu/issues/48 [L,R=permanent] +RewriteRule ^ncdu/bug/52$ https://code.blicky.net/yorhel/ncdu/issues/49 [L,R=permanent] +RewriteRule ^ncdu/bug/53$ https://code.blicky.net/yorhel/ncdu/issues/50 [L,R=permanent] +RewriteRule ^ncdu/bug/54$ https://code.blicky.net/yorhel/ncdu/issues/51 [L,R=permanent] +RewriteRule ^ncdu/bug/55$ https://code.blicky.net/yorhel/ncdu/issues/52 [L,R=permanent] +RewriteRule ^ncdu/bug/56$ https://code.blicky.net/yorhel/ncdu/issues/53 [L,R=permanent] +RewriteRule ^ncdu/bug/57$ https://code.blicky.net/yorhel/ncdu/issues/54 [L,R=permanent] +RewriteRule ^ncdu/bug/58$ https://code.blicky.net/yorhel/ncdu/issues/55 [L,R=permanent] +RewriteRule ^ncdu/bug/59$ https://code.blicky.net/yorhel/ncdu/issues/56 [L,R=permanent] +RewriteRule ^ncdu/bug/60$ https://code.blicky.net/yorhel/ncdu/issues/57 [L,R=permanent] +RewriteRule ^ncdu/bug/61$ https://code.blicky.net/yorhel/ncdu/issues/58 [L,R=permanent] +RewriteRule ^ncdu/bug/62$ https://code.blicky.net/yorhel/ncdu/issues/59 [L,R=permanent] +RewriteRule ^ncdu/bug/63$ https://code.blicky.net/yorhel/ncdu/issues/60 [L,R=permanent] +RewriteRule ^ncdu/bug/64$ https://code.blicky.net/yorhel/ncdu/issues/61 [L,R=permanent] +RewriteRule ^ncdu/bug/65$ https://code.blicky.net/yorhel/ncdu/issues/62 [L,R=permanent] +RewriteRule ^ncdu/bug/66$ https://code.blicky.net/yorhel/ncdu/issues/63 [L,R=permanent] +RewriteRule ^ncdu/bug/67$ https://code.blicky.net/yorhel/ncdu/issues/64 [L,R=permanent] +RewriteRule ^ncdu/bug/68$ https://code.blicky.net/yorhel/ncdu/issues/65 [L,R=permanent] +RewriteRule ^ncdu/bug/69$ https://code.blicky.net/yorhel/ncdu/issues/66 [L,R=permanent] +RewriteRule ^ncdu/bug/70$ https://code.blicky.net/yorhel/ncdu/issues/67 [L,R=permanent] +RewriteRule ^ncdu/bug/71$ https://code.blicky.net/yorhel/ncdu/issues/68 [L,R=permanent] +RewriteRule ^ncdu/bug/72$ https://code.blicky.net/yorhel/ncdu/issues/69 [L,R=permanent] +RewriteRule ^ncdu/bug/73$ https://code.blicky.net/yorhel/ncdu/issues/70 [L,R=permanent] +RewriteRule ^ncdu/bug/74$ https://code.blicky.net/yorhel/ncdu/issues/71 [L,R=permanent] +RewriteRule ^ncdu/bug/75$ https://code.blicky.net/yorhel/ncdu/issues/72 [L,R=permanent] +RewriteRule ^ncdu/bug/76$ https://code.blicky.net/yorhel/ncdu/issues/73 [L,R=permanent] +RewriteRule ^ncdu/bug/77$ https://code.blicky.net/yorhel/ncdu/issues/74 [L,R=permanent] +RewriteRule ^ncdu/bug/78$ https://code.blicky.net/yorhel/ncdu/issues/75 [L,R=permanent] +RewriteRule ^ncdu/bug/79$ https://code.blicky.net/yorhel/ncdu/issues/76 [L,R=permanent] +RewriteRule ^ncdu/bug/80$ https://code.blicky.net/yorhel/ncdu/issues/77 [L,R=permanent] +RewriteRule ^ncdu/bug/81$ https://code.blicky.net/yorhel/ncdu/issues/78 [L,R=permanent] +RewriteRule ^ncdu/bug/82$ https://code.blicky.net/yorhel/ncdu/issues/79 [L,R=permanent] +RewriteRule ^ncdu/bug/83$ https://code.blicky.net/yorhel/ncdu/issues/80 [L,R=permanent] +RewriteRule ^ncdu/bug/84$ https://code.blicky.net/yorhel/ncdu/issues/81 [L,R=permanent] +RewriteRule ^ncdu/bug/85$ https://code.blicky.net/yorhel/ncdu/issues/82 [L,R=permanent] +RewriteRule ^ncdu/bug/86$ https://code.blicky.net/yorhel/ncdu/issues/83 [L,R=permanent] +RewriteRule ^ncdu/bug/87$ https://code.blicky.net/yorhel/ncdu/issues/84 [L,R=permanent] +RewriteRule ^ncdu/bug/88$ https://code.blicky.net/yorhel/ncdu/issues/85 [L,R=permanent] +RewriteRule ^ncdu/bug/89$ https://code.blicky.net/yorhel/ncdu/issues/86 [L,R=permanent] +RewriteRule ^ncdu/bug/90$ https://code.blicky.net/yorhel/ncdu/issues/87 [L,R=permanent] +RewriteRule ^ncdu/bug/91$ https://code.blicky.net/yorhel/ncdu/issues/88 [L,R=permanent] +RewriteRule ^ncdu/bug/92$ https://code.blicky.net/yorhel/ncdu/issues/89 [L,R=permanent] +RewriteRule ^ncdu/bug/93$ https://code.blicky.net/yorhel/ncdu/issues/90 [L,R=permanent] +RewriteRule ^ncdu/bug/94$ https://code.blicky.net/yorhel/ncdu/issues/91 [L,R=permanent] +RewriteRule ^ncdu/bug/95$ https://code.blicky.net/yorhel/ncdu/issues/92 [L,R=permanent] +RewriteRule ^ncdu/bug/96$ https://code.blicky.net/yorhel/ncdu/issues/93 [L,R=permanent] +RewriteRule ^ncdu/bug/97$ https://code.blicky.net/yorhel/ncdu/issues/94 [L,R=permanent] +RewriteRule ^ncdu/bug/98$ https://code.blicky.net/yorhel/ncdu/issues/95 [L,R=permanent] +RewriteRule ^ncdu/bug/99$ https://code.blicky.net/yorhel/ncdu/issues/96 [L,R=permanent] +RewriteRule ^ncdu/bug/100$ https://code.blicky.net/yorhel/ncdu/issues/97 [L,R=permanent] +RewriteRule ^ncdu/bug/101$ https://code.blicky.net/yorhel/ncdu/issues/98 [L,R=permanent] +RewriteRule ^ncdu/bug/102$ https://code.blicky.net/yorhel/ncdu/issues/99 [L,R=permanent] +RewriteRule ^ncdu/bug/103$ https://code.blicky.net/yorhel/ncdu/issues/100 [L,R=permanent] +RewriteRule ^ncdu/bug/104$ https://code.blicky.net/yorhel/ncdu/issues/101 [L,R=permanent] +RewriteRule ^ncdu/bug/105$ https://code.blicky.net/yorhel/ncdu/issues/102 [L,R=permanent] +RewriteRule ^ncdu/bug/106$ https://code.blicky.net/yorhel/ncdu/issues/103 [L,R=permanent] +RewriteRule ^ncdu/bug/107$ https://code.blicky.net/yorhel/ncdu/issues/104 [L,R=permanent] +RewriteRule ^ncdu/bug/108$ https://code.blicky.net/yorhel/ncdu/issues/105 [L,R=permanent] +RewriteRule ^ncdu/bug/109$ https://code.blicky.net/yorhel/ncdu/issues/106 [L,R=permanent] +RewriteRule ^ncdu/bug/110$ https://code.blicky.net/yorhel/ncdu/issues/107 [L,R=permanent] +RewriteRule ^ncdu/bug/111$ https://code.blicky.net/yorhel/ncdu/issues/108 [L,R=permanent] +RewriteRule ^ncdu/bug/112$ https://code.blicky.net/yorhel/ncdu/issues/109 [L,R=permanent] +RewriteRule ^ncdu/bug/113$ https://code.blicky.net/yorhel/ncdu/issues/110 [L,R=permanent] +RewriteRule ^ncdu/bug/114$ https://code.blicky.net/yorhel/ncdu/issues/111 [L,R=permanent] +RewriteRule ^ncdu/bug/115$ https://code.blicky.net/yorhel/ncdu/issues/112 [L,R=permanent] +RewriteRule ^ncdu/bug/116$ https://code.blicky.net/yorhel/ncdu/issues/113 [L,R=permanent] +RewriteRule ^ncdu/bug/117$ https://code.blicky.net/yorhel/ncdu/issues/114 [L,R=permanent] +RewriteRule ^ncdu/bug/118$ https://code.blicky.net/yorhel/ncdu/issues/115 [L,R=permanent] +RewriteRule ^ncdu/bug/119$ https://code.blicky.net/yorhel/ncdu/issues/116 [L,R=permanent] +RewriteRule ^ncdu/bug/120$ https://code.blicky.net/yorhel/ncdu/issues/117 [L,R=permanent] +RewriteRule ^ncdu/bug/121$ https://code.blicky.net/yorhel/ncdu/issues/118 [L,R=permanent] +RewriteRule ^ncdu/bug/122$ https://code.blicky.net/yorhel/ncdu/issues/119 [L,R=permanent] +RewriteRule ^ncdu/bug/123$ https://code.blicky.net/yorhel/ncdu/issues/120 [L,R=permanent] +RewriteRule ^ncdu/bug/124$ https://code.blicky.net/yorhel/ncdu/issues/121 [L,R=permanent] +RewriteRule ^ncdu/bug/125$ https://code.blicky.net/yorhel/ncdu/issues/122 [L,R=permanent] +RewriteRule ^ncdu/bug/126$ https://code.blicky.net/yorhel/ncdu/issues/123 [L,R=permanent] +RewriteRule ^ncdu/bug/127$ https://code.blicky.net/yorhel/ncdu/issues/124 [L,R=permanent] +RewriteRule ^ncdu/bug/128$ https://code.blicky.net/yorhel/ncdu/issues/125 [L,R=permanent] +RewriteRule ^ncdu/bug.*$ https://code.blicky.net/yorhel/ncdu/issues [L,R=permanent] + +RewriteRule ^ncdc/bug/1$ https://code.blicky.net/yorhel/ncdc/issues/1 [L,R=permanent] +RewriteRule ^ncdc/bug/2$ https://code.blicky.net/yorhel/ncdc/issues/2 [L,R=permanent] +RewriteRule ^ncdc/bug/3$ https://code.blicky.net/yorhel/ncdc/issues/3 [L,R=permanent] +RewriteRule ^ncdc/bug/4$ https://code.blicky.net/yorhel/ncdc/issues/4 [L,R=permanent] +RewriteRule ^ncdc/bug/5$ https://code.blicky.net/yorhel/ncdc/issues/5 [L,R=permanent] +RewriteRule ^ncdc/bug/9$ https://code.blicky.net/yorhel/ncdc/issues/6 [L,R=permanent] +RewriteRule ^ncdc/bug/10$ https://code.blicky.net/yorhel/ncdc/issues/7 [L,R=permanent] +RewriteRule ^ncdc/bug/11$ https://code.blicky.net/yorhel/ncdc/issues/8 [L,R=permanent] +RewriteRule ^ncdc/bug/12$ https://code.blicky.net/yorhel/ncdc/issues/9 [L,R=permanent] +RewriteRule ^ncdc/bug/13$ https://code.blicky.net/yorhel/ncdc/issues/10 [L,R=permanent] +RewriteRule ^ncdc/bug/14$ https://code.blicky.net/yorhel/ncdc/issues/11 [L,R=permanent] +RewriteRule ^ncdc/bug/17$ https://code.blicky.net/yorhel/ncdc/issues/12 [L,R=permanent] +RewriteRule ^ncdc/bug/18$ https://code.blicky.net/yorhel/ncdc/issues/13 [L,R=permanent] +RewriteRule ^ncdc/bug/19$ https://code.blicky.net/yorhel/ncdc/issues/14 [L,R=permanent] +RewriteRule ^ncdc/bug/20$ https://code.blicky.net/yorhel/ncdc/issues/15 [L,R=permanent] +RewriteRule ^ncdc/bug/21$ https://code.blicky.net/yorhel/ncdc/issues/16 [L,R=permanent] +RewriteRule ^ncdc/bug/24$ https://code.blicky.net/yorhel/ncdc/issues/17 [L,R=permanent] +RewriteRule ^ncdc/bug/25$ https://code.blicky.net/yorhel/ncdc/issues/18 [L,R=permanent] +RewriteRule ^ncdc/bug/26$ https://code.blicky.net/yorhel/ncdc/issues/19 [L,R=permanent] +RewriteRule ^ncdc/bug/27$ https://code.blicky.net/yorhel/ncdc/issues/20 [L,R=permanent] +RewriteRule ^ncdc/bug/28$ https://code.blicky.net/yorhel/ncdc/issues/21 [L,R=permanent] +RewriteRule ^ncdc/bug/29$ https://code.blicky.net/yorhel/ncdc/issues/22 [L,R=permanent] +RewriteRule ^ncdc/bug/30$ https://code.blicky.net/yorhel/ncdc/issues/23 [L,R=permanent] +RewriteRule ^ncdc/bug/31$ https://code.blicky.net/yorhel/ncdc/issues/24 [L,R=permanent] +RewriteRule ^ncdc/bug/32$ https://code.blicky.net/yorhel/ncdc/issues/25 [L,R=permanent] +RewriteRule ^ncdc/bug/33$ https://code.blicky.net/yorhel/ncdc/issues/26 [L,R=permanent] +RewriteRule ^ncdc/bug/34$ https://code.blicky.net/yorhel/ncdc/issues/27 [L,R=permanent] +RewriteRule ^ncdc/bug/35$ https://code.blicky.net/yorhel/ncdc/issues/28 [L,R=permanent] +RewriteRule ^ncdc/bug/36$ https://code.blicky.net/yorhel/ncdc/issues/29 [L,R=permanent] +RewriteRule ^ncdc/bug/37$ https://code.blicky.net/yorhel/ncdc/issues/30 [L,R=permanent] +RewriteRule ^ncdc/bug/38$ https://code.blicky.net/yorhel/ncdc/issues/31 [L,R=permanent] +RewriteRule ^ncdc/bug/39$ https://code.blicky.net/yorhel/ncdc/issues/32 [L,R=permanent] +RewriteRule ^ncdc/bug/40$ https://code.blicky.net/yorhel/ncdc/issues/33 [L,R=permanent] +RewriteRule ^ncdc/bug/41$ https://code.blicky.net/yorhel/ncdc/issues/34 [L,R=permanent] +RewriteRule ^ncdc/bug/42$ https://code.blicky.net/yorhel/ncdc/issues/35 [L,R=permanent] +RewriteRule ^ncdc/bug/43$ https://code.blicky.net/yorhel/ncdc/issues/36 [L,R=permanent] +RewriteRule ^ncdc/bug/44$ https://code.blicky.net/yorhel/ncdc/issues/37 [L,R=permanent] +RewriteRule ^ncdc/bug/45$ https://code.blicky.net/yorhel/ncdc/issues/38 [L,R=permanent] +RewriteRule ^ncdc/bug/46$ https://code.blicky.net/yorhel/ncdc/issues/39 [L,R=permanent] +RewriteRule ^ncdc/bug/47$ https://code.blicky.net/yorhel/ncdc/issues/40 [L,R=permanent] +RewriteRule ^ncdc/bug/48$ https://code.blicky.net/yorhel/ncdc/issues/41 [L,R=permanent] +RewriteRule ^ncdc/bug/49$ https://code.blicky.net/yorhel/ncdc/issues/42 [L,R=permanent] +RewriteRule ^ncdc/bug/50$ https://code.blicky.net/yorhel/ncdc/issues/43 [L,R=permanent] +RewriteRule ^ncdc/bug/51$ https://code.blicky.net/yorhel/ncdc/issues/44 [L,R=permanent] +RewriteRule ^ncdc/bug/52$ https://code.blicky.net/yorhel/ncdc/issues/45 [L,R=permanent] +RewriteRule ^ncdc/bug/53$ https://code.blicky.net/yorhel/ncdc/issues/46 [L,R=permanent] +RewriteRule ^ncdc/bug/54$ https://code.blicky.net/yorhel/ncdc/issues/47 [L,R=permanent] +RewriteRule ^ncdc/bug/55$ https://code.blicky.net/yorhel/ncdc/issues/48 [L,R=permanent] +RewriteRule ^ncdc/bug/56$ https://code.blicky.net/yorhel/ncdc/issues/49 [L,R=permanent] +RewriteRule ^ncdc/bug/57$ https://code.blicky.net/yorhel/ncdc/issues/50 [L,R=permanent] +RewriteRule ^ncdc/bug/58$ https://code.blicky.net/yorhel/ncdc/issues/51 [L,R=permanent] +RewriteRule ^ncdc/bug/59$ https://code.blicky.net/yorhel/ncdc/issues/52 [L,R=permanent] +RewriteRule ^ncdc/bug/60$ https://code.blicky.net/yorhel/ncdc/issues/53 [L,R=permanent] +RewriteRule ^ncdc/bug/61$ https://code.blicky.net/yorhel/ncdc/issues/54 [L,R=permanent] +RewriteRule ^ncdc/bug/62$ https://code.blicky.net/yorhel/ncdc/issues/55 [L,R=permanent] +RewriteRule ^ncdc/bug/63$ https://code.blicky.net/yorhel/ncdc/issues/56 [L,R=permanent] +RewriteRule ^ncdc/bug/64$ https://code.blicky.net/yorhel/ncdc/issues/57 [L,R=permanent] +RewriteRule ^ncdc/bug/65$ https://code.blicky.net/yorhel/ncdc/issues/58 [L,R=permanent] +RewriteRule ^ncdc/bug/66$ https://code.blicky.net/yorhel/ncdc/issues/59 [L,R=permanent] +RewriteRule ^ncdc/bug/67$ https://code.blicky.net/yorhel/ncdc/issues/60 [L,R=permanent] +RewriteRule ^ncdc/bug/68$ https://code.blicky.net/yorhel/ncdc/issues/61 [L,R=permanent] +RewriteRule ^ncdc/bug/69$ https://code.blicky.net/yorhel/ncdc/issues/62 [L,R=permanent] +RewriteRule ^ncdc/bug/70$ https://code.blicky.net/yorhel/ncdc/issues/63 [L,R=permanent] +RewriteRule ^ncdc/bug/71$ https://code.blicky.net/yorhel/ncdc/issues/64 [L,R=permanent] +RewriteRule ^ncdc/bug/72$ https://code.blicky.net/yorhel/ncdc/issues/65 [L,R=permanent] +RewriteRule ^ncdc/bug/73$ https://code.blicky.net/yorhel/ncdc/issues/66 [L,R=permanent] +RewriteRule ^ncdc/bug/74$ https://code.blicky.net/yorhel/ncdc/issues/67 [L,R=permanent] +RewriteRule ^ncdc/bug/75$ https://code.blicky.net/yorhel/ncdc/issues/68 [L,R=permanent] +RewriteRule ^ncdc/bug/76$ https://code.blicky.net/yorhel/ncdc/issues/69 [L,R=permanent] +RewriteRule ^ncdc/bug/77$ https://code.blicky.net/yorhel/ncdc/issues/70 [L,R=permanent] +RewriteRule ^ncdc/bug/78$ https://code.blicky.net/yorhel/ncdc/issues/71 [L,R=permanent] +RewriteRule ^ncdc/bug/79$ https://code.blicky.net/yorhel/ncdc/issues/72 [L,R=permanent] +RewriteRule ^ncdc/bug/80$ https://code.blicky.net/yorhel/ncdc/issues/73 [L,R=permanent] +RewriteRule ^ncdc/bug/81$ https://code.blicky.net/yorhel/ncdc/issues/74 [L,R=permanent] +RewriteRule ^ncdc/bug/82$ https://code.blicky.net/yorhel/ncdc/issues/75 [L,R=permanent] +RewriteRule ^ncdc/bug/83$ https://code.blicky.net/yorhel/ncdc/issues/76 [L,R=permanent] +RewriteRule ^ncdc/bug/84$ https://code.blicky.net/yorhel/ncdc/issues/77 [L,R=permanent] +RewriteRule ^ncdc/bug/85$ https://code.blicky.net/yorhel/ncdc/issues/78 [L,R=permanent] +RewriteRule ^ncdc/bug/86$ https://code.blicky.net/yorhel/ncdc/issues/79 [L,R=permanent] +RewriteRule ^ncdc/bug/87$ https://code.blicky.net/yorhel/ncdc/issues/80 [L,R=permanent] +RewriteRule ^ncdc/bug/88$ https://code.blicky.net/yorhel/ncdc/issues/81 [L,R=permanent] +RewriteRule ^ncdc/bug/89$ https://code.blicky.net/yorhel/ncdc/issues/82 [L,R=permanent] +RewriteRule ^ncdc/bug/90$ https://code.blicky.net/yorhel/ncdc/issues/83 [L,R=permanent] +RewriteRule ^ncdc/bug/91$ https://code.blicky.net/yorhel/ncdc/issues/84 [L,R=permanent] +RewriteRule ^ncdc/bug/92$ https://code.blicky.net/yorhel/ncdc/issues/85 [L,R=permanent] +RewriteRule ^ncdc/bug/93$ https://code.blicky.net/yorhel/ncdc/issues/86 [L,R=permanent] +RewriteRule ^ncdc/bug/94$ https://code.blicky.net/yorhel/ncdc/issues/87 [L,R=permanent] +RewriteRule ^ncdc/bug/95$ https://code.blicky.net/yorhel/ncdc/issues/88 [L,R=permanent] +RewriteRule ^ncdc/bug/96$ https://code.blicky.net/yorhel/ncdc/issues/89 [L,R=permanent] +RewriteRule ^ncdc/bug.*$ https://code.blicky.net/yorhel/ncdc/issue [L,R=permanent] + +RewriteRule ^yxml/bug/1$ https://code.blicky.net/yorhel/yxml/issues/1 [L,R=permanent] +RewriteRule ^yxml/bug/2$ https://code.blicky.net/yorhel/yxml/issues/2 [L,R=permanent] +RewriteRule ^yxml/bug.*$ https://code.blicky.net/yorhel/yxml/issues [L,R=permanent] + +# No trailing slash (except for the download/ directory index) +RewriteCond %{REQUEST_URI} !^/download +RewriteRule ^(.+)/$ $1 [L,R=permanent] + +RewriteCond %{REQUEST_FILENAME}.html -s +RewriteRule ^(.+)$ $1.html [L] diff --git a/pub/download/.htaccess b/pub/download/.htaccess new file mode 100644 index 0000000..ef5cdf8 --- /dev/null +++ b/pub/download/.htaccess @@ -0,0 +1,2 @@ +Options +Indexes +DirectorySlash on diff --git a/template.html b/template.html index 9bb23da..df9303b 100644 --- a/template.html +++ b/template.html @@ -48,7 +48,6 @@
  • API Doc -
  • Bug tracker
  • Projects home
  • $endif$ @@ -61,7 +60,7 @@
  • Manual
  • Changelog
  • Screenshots
  • -
  • Bug tracker
  • +
  • Issues
  • Projects home
  • $endif$ @@ -76,7 +75,7 @@
  • Changelog
  • Screenshots
  • -
  • Bug tracker
  • +
  • Issues
  • Projects home
  • $endif$ @@ -107,7 +106,7 @@
  • Changelog
  • -
  • Issues
  • +
  • Issues
  • Projects home
  • $endif$ @@ -116,7 +115,7 @@ $endif$ diff --git a/updates.pl b/updates.pl index 59d50f6..febc57b 100755 --- a/updates.pl +++ b/updates.pl @@ -1,5 +1,6 @@ #!/usr/bin/perl @UPDATES=map [split(/ +/,$_,3)], split /\n/, <<_; +2019-03-23 / The bug trackers for ncdu, ncdc and yxml have been migrated to Gitea. 2019-02-04 /ncdu ncdu 1.14 released 2018-02-23 /nginx-confgen nginx-confgen 1.2 released 2018-02-18 /tuwf TUWF 1.2 released