-BEGIN{
- my $word = qr,(\w+),a;
- my $number = qr,(\d+),a;
-
- sub generic {
- for my $thing (@_) {
- my $pkg = ucfirst $thing;
- get qr,/$thing/, => $pkg;
- get qr,/$thing/read, => "${pkg}::Read";
- get qr,/$thing/$word, => "${pkg}::Entry";
-# post qr,/$thing/$word/create, => "${pkg}::Entry::Create";
- get qr,/$thing/$word/read, => "${pkg}::Entry::Read";
-# post qr,/$thing/$word/update, => "${pkg}::Entry::Update";
-# post qr,/$thing/$word/delete, => "${pkg}::Entry::Delete";
- }
- }
+sub dispatch_request{
+ $env = $_[PSGI_ENV];
+ sub (GET) {
+ sub (/css/:theme) {
+ my $theme = $_{theme};
+ return NOT_FOUND unless -e "css/themes/$theme.css";
+ my $css = read_file "css/themes/$theme.css";
+ $css .= read_file $_ for <css/*.css>;
+ my @headers = ('X-Forever' => 1, 'Cache-Control' => 'public, max-age=604800', 'Content-Type' => 'text/css');
+ [200, \@headers, [development ? $css : CSS::Minifier::XS::minify $css]]
+ },
+
+ sub (/js.js) {
+ my $js;
+ $js .= read_file $_ for <js/*.js>;
+ my @headers = ('X-Forever' => 1, 'Cache-Control' => 'public, max-age=604800', 'Content-Type' => 'application/javascript');
+ [200, \@headers, [development ? $js : JavaScript::Minifier::XS::minify $js]]
+ },
+
+ sub (/src/:job) {
+ return NOT_FOUND if !job;
+ forbid job->private || job->problem->private || job->contest && job->contest->private;
+ my @headers = ('X-Forever' => 1, 'Cache-Control' => 'public, max-age=604800', 'Content-Type' => CONTENT_TYPES->{job->format});
+ [200, \@headers, [job->source]]
+ },
+
+ sub (?:contest=) {
+ return NOT_FOUND if !contest;
+ forbid contest->is_pending;
+ response_filter { return shift }
+ },
+
+ sub (?:problem=) {
+ return NOT_FOUND if !problem;
+ forbid problem->is_private;
+ response_filter { return shift }
+ },
+
+ sub (?:format~) {
+ my $format = lc ($_{format} // '');
+ response_filter {
+ my ($r) = @_;
+ return $r if ref $r ne 'Plack::App::Gruntmaster::Response';
+ return [200, ['Content-Type' => 'application/json'], [encode_json $r->{params}]] if $format eq 'json';
+ my $ret = render $r->{template}, 'en', title => $r->{title}, %{$r->{params}};
+ [200, ['Content-Type' => 'text/html'], [encode 'UTF-8', $ret]]
+ },
+ },
+
+ sub (/st/:contest) {
+ response st => 'Standings', {
+ st => [ contest->standings ],
+ problems => [map { $_->problem } contest->contest_problems],
+ }
+ },
+
+ sub (/ct/:contest/log/st) { redirect "/st/$_{contest}" },
+
+ sub (/us/) { response us => 'Users', {us => db->user_list} },
+ sub (/ct/ + ?:owner~) { response ct => 'Contests', db->contest_list(%_) },
+ sub (/log/ + ?:contest~&:owner~&:page~&:problem~) { response log => 'Job list', {%{db->job_list(%_)}, maybe contest => $_{contest}} },
+ sub (/pb/ + ?:owner~&:contest~) { response pb => 'Problems', {%{db->problem_list(%_)}, maybe contest => $_{contest}} },