74 コミット 8d5956cb7f ... 536757e8e2

作者 SHA1 メッセージ 日付
  Alex Schroeder 536757e8e2 ban-contributors: fix get_range 3 年 前
  Alex Schroeder 00af1aa638 New CSS 3 年 前
  Alex Schroeder c2cf3e7b43 namespaces: reload @IndexList before saving 3 年 前
  Alex Schroeder 05c14d37b2 ban-contributors: another regexp improvement 3 年 前
  Alex Schroeder fc3614f291 ban-contributors: improved the IP regex generator 3 年 前
  Alex Schroeder e201c77696 namespaces: share BannedContent and BannedHosts 3 年 前
  Alex Schroeder f280cb5df4 Revert "namespaces: share BannedContent and BannedHosts" 3 年 前
  Alex Schroeder 29863d7109 namespaces: share BannedContent and BannedHosts 3 年 前
  Alex Schroeder b514ea7846 Fix TRANSLATIONS glob in the Makefile 3 年 前
  Tobias Fendin eeaf615d3b Added more swedish translations 3 年 前
  Tobias Fendin f003481c5e Translated webmention to swedish 3 年 前
  Alex Schroeder 4d10ef389a Add script/unsusbscribe.pl 3 年 前
  Alex Schroeder 726ffdced1 banned-regexps: do not remove URLs from the text 3 年 前
  Alex Schroeder 18c4071da8 t/test: handle spaces in PERLBREW_PATH 3 年 前
  Alex Schroeder fd7fa0c3ab Add progress indicator to stats 3 年 前
  Alex Schroeder 2ba5b72242 stats.pl is a new script to print some stats for a page dir 3 年 前
  Alex Schroeder fa5a2f7a1a rc2mail: print $root 3 年 前
  Alex Schroeder ad042630b6 ban-contributors: fix regexp generator 3 年 前
  Alex Schroeder 9cf35b9b52 Updated Swedish translation 3 年 前
  Alex Schroeder 4f69103b8c wiki: simplify a regular expression 3 年 前
  Alex Schroeder 37c882780a emoji: add \b after :p 3 年 前
  Alex Schroeder 6d5f97e1ba journal-rss: fix headers for raw output 3 年 前
  Alex Schroeder 4b1063c699 journal-rss: add one more test 3 年 前
  Alex Schroeder b891674a6f journal-rss: support raw mode 3 年 前
  Alex Schroeder 1a65df6e36 Update the French translation 3 年 前
  Alex Schroeder 6043be852c Fix handling of $RssExclude 4 年 前
  Alex Schroeder bb11bdf789 Updated the tests for HTML5 4 年 前
  Alex Schroeder 540fd588c9 Incompatible HTML changes 4 年 前
  Alex Schroeder 278fad1f43 Fixed development target in Makefile 4 年 前
  Alex Schroeder eadeb460f5 Fixed tests 4 年 前
  Alex Schroeder 5da9ce64c0 Lazy loading of images 4 年 前
  Alex Schroeder 40498b53f7 duckduckgo-search: no www subdomain 4 年 前
  Alex Schroeder eaf97602ff Make sure the bogus hash is served for raw changes 4 年 前
  Alex Schroeder 987c262425 wiki: add n limit to index action 4 年 前
  Alex Schroeder c33ee0a9e6 markdown-rule: add one more test 4 年 前
  Alex Schroeder eb7665661f gemini-server: handle Gemini markup 4 年 前
  Alex Schroeder 72ae1bf56f gemini-server: fix month in Atom date 4 年 前
  Alex Schroeder 8f30ed8109 gemini-server: don't require a space after URL 4 年 前
  Alex Schroeder 19e71f1180 gemini-server: clean up feed generation 4 年 前
  Alex Schroeder 9397a38394 gemini-server: add RSS and Atom feeds 4 年 前
  Alex Schroeder 17bd2d08cd gemini-server: small updates 4 年 前
  Alex Schroeder 47a5e81000 Run extension even if testing 4 年 前
  Alex Schroeder 7bfe740fb2 gemini-server: add language support 4 年 前
  Alex Schroeder 6a324b59b9 gemini-server: move run_extensions to the top 4 年 前
  Alex Schroeder 23545006a5 gemini-server: add diff support 4 年 前
  Alex Schroeder 65012eacbb gemini-server: add history page support 4 年 前
  Alex Schroeder 91107143f3 gemini-server: switching from gemini+write to titan 4 年 前
  Alex Schroeder cafda90555 gemini-server: various improvements 4 年 前
  Alex Schroeder 32dfec102d gemini-server: add support for a config file 4 年 前
  Alex Schroeder c1cdca5f95 gemini-server: more tests 4 年 前
  Alex Schroeder 61dc928e33 gemini-server: write tests, fix bugs 4 年 前
  Alex Schroeder d43fe3fab9 gemini-server: more improvements 4 年 前
  Alex Schroeder 3acb572c0d gemini-server: small improvements 4 年 前
  Alex Schroeder 0f6787d349 gemini-server: use temporary redirects, always 4 年 前
  Alex Schroeder af287a1279 gemini-server: various improvements 4 年 前
  Alex Schroeder 6bbd43f8a3 gemini-server: various improvements 4 年 前
  Alex Schroeder 364d7c695b gemini-server: serve Gemini, best effort 4 年 前
  Alex Schroeder 871af41881 gemini-server: add searching, matching, sorting 4 年 前
  Alex Schroeder 4648bfbd83 wiki: make url-decoding case insensitive 4 年 前
  Alex Schroeder 129d02850b gemini-server: answer with a redirect after saving 4 年 前
  Alex Schroeder ee23ef509c gemini-server: fix issues to allow writes 4 年 前
  Alex Schroeder 7e865696b0 gemini-server: add write support 4 年 前
  Alex Schroeder 244d06ca3b gemini-server: fix recent changes and rss 4 年 前
  Alex Schroeder 1a59075b51 gemini-server: new 4 年 前
  Alex Schroeder e0b3c18499 mail: allow unsubscription from all pages 4 年 前
  Alex Schroeder 5434136a4d mail: allow unsubscription from all pages 4 年 前
  Alex Schroeder aeeb182dad mail: allow unsubscription from all pages 4 年 前
  Alex Schroeder 4d6882ffc7 ip-to-regexp.pl: new command line script 4 年 前
  Alex Schroeder 828482f439 webmention: various updates 4 年 前
  Alex Schroeder 2b6f2dfa0c pygmentize: add a test 4 年 前
  Alex Schroeder 413b43174c webmention: avoid warning about CGI::param 4 年 前
  Alex Schroeder 9709c87185 webmention: better UI 4 年 前
  Alex Schroeder 0cca358de2 webmention: add UI 4 年 前
  Alex Schroeder acff0cb69f Add tests for grep-filtered 4 年 前

+ 14 - 3
Makefile

@@ -3,7 +3,7 @@
 # subdirectory.
 
 VERSION_NO=$(shell git describe --tags)
-TRANSLATIONS=$(wildcard modules/translations/[a-z]*-utf8.pl$)
+TRANSLATIONS=$(wildcard modules/translations/*-utf8.pl)
 MODULES=$(sort $(wildcard modules/*.pl))
 BUILD=build/wiki.pl $(foreach file, $(notdir $(MODULES)) $(notdir $(TRANSLATIONS)), build/$(file))
 
@@ -64,6 +64,17 @@ test:
 # Spin up a quick test
 
 development:
+	@if grep --quiet 'ScriptName = "http://127.0.0.1:8080";' test-data/config; then \
+	  echo Not overwriting \$$ScriptName in test-data/config; \
+	else \
+	  echo '$ScriptName = "http://127.0.0.1:8080";' >> test-data/config; \
+	fi
 	morbo --listen http://*:8080 \
-	--watch wiki.pl --watch test-data/config --watch test-data/modules/ \
-	stuff/mojolicious-app.pl
+	  --watch wiki.pl --watch test-data/config --watch test-data/modules/ \
+	  stuff/mojolicious-app.pl
+
+%.pem:
+	openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout key.pem
+
+gemini: cert.pem key.pem
+	perl stuff/gemini-server.pl --wiki_cert_file=cert.pem --wiki_key_file=key.pem

+ 425 - 0
css/latex.css

@@ -0,0 +1,425 @@
+/*!
+ * LaTeX.css (https://latex.now.sh/)
+ *
+ * Source: https://github.com/vincentdoerig/latex-css
+ * Licensed under MIT (https://github.com/vincentdoerig/latex-css/blob/master/LICENSE)
+*/
+
+@font-face {
+  font-family: 'Latin Modern';
+  font-style: normal;
+  font-weight: normal;
+  font-display: swap;
+  src: url('/style/fonts/LM-regular.woff2') format('woff2'),
+    url('/style/fonts/LM-regular.woff') format('woff'),
+    url('/style/fonts/LM-regular.ttf') format('truetype');
+}
+
+@font-face {
+  font-family: 'Latin Modern';
+  font-style: italic;
+  font-weight: normal;
+  font-display: swap;
+  src: url('/style/fonts/LM-italic.woff2') format('woff2'),
+    url('/style/fonts/LM-italic.woff') format('woff'),
+    url('/style/fonts/LM-italic.ttf') format('truetype');
+}
+
+@font-face {
+  font-family: 'Latin Modern';
+  font-style: normal;
+  font-weight: bold;
+  font-display: swap;
+  src: url('/style/fonts/LM-bold.woff2') format('woff2'),
+    url('/style/fonts/LM-bold.woff') format('woff'),
+    url('/style/fonts/LM-bold.ttf') format('truetype');
+}
+
+@font-face {
+  font-family: 'Latin Modern';
+  font-style: italic;
+  font-weight: bold;
+  font-display: swap;
+  src: url('/style/fonts/LM-bold-italic.woff2') format('woff2'),
+    url('/style/fonts/LM-bold-italic.woff') format('woff'),
+    url('/style/fonts/LM-bold-italic.ttf') format('truetype');
+}
+
+/* Box sizing rules */
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+}
+
+/* Remove default margin */
+body,
+h1,
+h2,
+h3,
+h4,
+p,
+ul[class],
+ol[class],
+li,
+figure,
+figcaption,
+dl,
+dd {
+  margin: 0;
+}
+
+/* Make default font-size 1rem and add smooth scrolling to anchors */
+html {
+  font-size: 1.4rem;
+  scroll-behavior: smooth;
+}
+
+body {
+  font-family: 'Latin Modern', Georgia, Cambria, 'DejaVu Serif', 'Times New Roman', Times, serif;
+  line-height: 1.4;
+  max-width: 80ch;
+  min-height: 100vh;
+  overflow-x: hidden;
+  margin: 0 auto;
+  padding: 2rem 1.25rem;
+
+  counter-reset: theorem;
+  counter-reset: definition;
+
+  color: hsl(0, 5%, 10%);
+  background-color: hsl(210, 20%, 98%);
+
+  text-rendering: optimizeLegibility;
+}
+
+/* Justify and hyphenate all paragraphs */
+p {
+  text-align: justify;
+  hyphens: auto;
+  -webkit-hyphens: auto;
+  -moz-hyphens: auto;
+  margin-top: 1rem;
+}
+
+/* A elements that don't have a class get default styles */
+a:not([class]) {
+  text-decoration-skip-ink: auto;
+}
+
+/* Make links red */
+a {
+  text-decoration: none;
+  color: #a00;
+}
+a:visited {
+  text-decoration: none;
+  color: #800;
+}
+
+a:focus {
+  outline-offset: 2px;
+  outline: 2px solid hsl(220, 90%, 52%);
+}
+
+
+/* Ueberschriften mit Links nur dezent einfärben */
+h1 a, h1 a:visited,
+h2 a, h2 a:visited,
+h3 a, h3 a:visited, 
+h4 a, h4 a:visited,
+h5 a, h5 a:visited,
+h6 a, h6 a:visited {
+  color: #555;
+}
+
+/* goto bar */
+div.menu form.search {
+  font-size:75%;
+  margin-top:2em;
+  margin-bottom:3em;
+}
+
+div.menu span.gotobar a.local,
+div.menu span.gotobar a.local:visited {
+  text-decoration: none;
+  color: #1e133c87;
+  margin-right:1.1em;
+  font-weight: bold;
+}
+
+/* Make images easier to work with */
+img {
+  max-width: 100%;
+  display: block;
+}
+
+/* Inherit fonts for inputs and buttons */
+input,
+button,
+textarea,
+select {
+  font: inherit;
+}
+
+/* Prevent textarea from overflowing */
+textarea {
+  width: 100%;
+}
+
+/* Natural flow and rhythm in articles by default */
+article > * + * {
+  margin-top: 1em;
+}
+
+/* Styles for inline code or code snippets */
+code,
+pre,
+kbd {
+  font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
+    monospace;
+  font-size: 85%;
+}
+pre {
+  padding: 1rem 1.4rem;
+  max-width: 100%;
+  overflow: auto;
+  border-radius: 4px;
+  background: hsl(210, 28%, 93%);
+}
+pre code {
+  font-size: 95%;
+  position: relative;
+}
+kbd {
+  background: hsl(210, 5%, 100%);
+  border: 1px solid hsl(210, 5%, 70%);
+  border-radius: 2px;
+  padding: 2px 4px;
+  font-size: 75%;
+}
+
+/* Make table 100% width, add borders between rows */
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+  width: 100%;
+  max-width: 100%;
+}
+th,
+td {
+  text-align: left;
+  padding: 0.5rem;
+}
+td {
+  border-bottom: 1px solid hsl(0, 0%, 85%);
+}
+thead th {
+  border-bottom: 2px solid hsl(0, 0%, 70%);
+}
+tfoot th {
+  border-top: 2px solid hsl(0, 0%, 70%);
+}
+
+/* Center align the title */
+h1:first-child {
+  text-align: center;
+}
+
+/* Nested ordered list for ToC */
+nav ol {
+  counter-reset: item;
+  padding-left: 2rem;
+}
+nav li {
+  display: block;
+}
+nav li:before {
+  content: counters(item, '.') ' ';
+  counter-increment: item;
+  padding-right: 0.85rem;
+}
+
+/* Center definitions (most useful for display equations) */
+dl dd {
+  text-align: center;
+}
+
+/* Theorem */
+.theorem {
+  counter-increment: theorem;
+  display: block;
+  margin: 12px 0;
+  font-style: italic;
+}
+.theorem::before {
+  content: 'Satz ' counter(theorem) '. ';
+  font-weight: bold;
+  font-style: normal;
+}
+
+/* Lemma */
+.lemma {
+  counter-increment: theorem;
+  display: block;
+  margin: 12px 0;
+  font-style: italic;
+}
+.lemma::before {
+  content: 'Lemma ' counter(theorem) '. ';
+  font-weight: bold;
+  font-style: normal;
+}
+
+/* Proof */
+.proof {
+  display: block;
+  margin: 12px 0;
+  font-style: normal;
+  position: relative;
+}
+.proof::before {
+  content: 'Beweis. ' attr(title);
+  font-style: italic;
+}
+.proof:after {
+  content: '◾️';
+  position: absolute;
+  right: -12px;
+  bottom: -2px;
+}
+
+/* Definition */
+.definition {
+  counter-increment: definition;
+  display: block;
+  margin: 12px 0;
+  font-style: normal;
+}
+.definition::before {
+  content: 'Definition ' counter(definition) '. ';
+  font-weight: bold;
+  font-style: normal;
+}
+
+/* Center align author name, use small caps and add vertical spacing  */
+.author {
+  margin: 0.85rem 0;
+  font-variant-caps: small-caps;
+  text-align: center;
+}
+
+/* Make footnote text smaller and left align it (looks bad with long URLs) */
+.footnotes p {
+  text-align: left;
+  line-height: 1.5;
+  font-size: 85%;
+  margin-bottom: 0.4rem;
+}
+.footnotes {
+  border-top: 1px solid hsl(0, 0%, 39%);
+}
+
+/* Center title and paragraph */
+.abstract,
+.abstract p {
+  text-align: center;
+}
+.abstract {
+  margin: 2.25rem 0;
+}
+
+/* Format the LaTeX symbol correctly (a higher up, e lower) */
+.latex span:nth-child(1) {
+  text-transform: uppercase;
+  font-size: 0.75em;
+  vertical-align: 0.28em;
+  margin-left: -0.48em;
+  margin-right: -0.15em;
+  line-height: 1ex;
+}
+
+.latex span:nth-child(2) {
+  text-transform: uppercase;
+  vertical-align: -0.5ex;
+  margin-left: -0.1667em;
+  margin-right: -0.125em;
+  line-height: 1ex;
+}
+
+/* Heading typography */
+h1 {
+  font-size: 2.5rem;
+  line-height: 3.25rem;
+  margin-bottom: 1.625rem;
+}
+
+h2 {
+  font-size: 1.7rem;
+  line-height: 2rem;
+  margin-top: 3rem;
+}
+
+h3 {
+  font-size: 1.4rem;
+  margin-top: 2.5rem;
+}
+
+h4 {
+  font-size: 1.2rem;
+  margin-top: 2rem;
+}
+
+h5 {
+  font-size: 1rem;
+  margin-top: 1.8rem;
+}
+
+h6 {
+  font-size: 1rem;
+  font-style: italic;
+  font-weight: normal;
+  margin-top: 2.5rem;
+}
+
+h3,
+h4,
+h5,
+h6 {
+  line-height: 1.625rem;
+}
+
+h1 + h2 {
+  margin-top: 1.625rem;
+}
+
+h2 + h3,
+h3 + h4,
+h4 + h5 {
+  margin-top: 0.8rem;
+}
+
+h5 + h6 {
+  margin-top: -0.8rem;
+}
+
+h2,
+h3,
+h4,
+h5,
+h6 {
+  margin-bottom: 0.8rem;
+}
+
+div.diff div.old {
+    background-color: #FFFFAF;
+}
+
+div.diff div.new {
+    background-color: #CFFFCF;
+}
+
+div.content blockquote {
+    font-style: italic;
+}
+

+ 95 - 49
modules/ban-contributors.pl

@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2016  Alex Schroeder <alex@gnu.org>
+# Copyright (C) 2013-2021  Alex Schroeder <alex@gnu.org>
 
 # This program is free software: you can redistribute it and/or modify it under
 # the terms of the GNU General Public License as published by the Free Software
@@ -96,16 +96,20 @@ sub DoBanHosts {
       if (IsItBanned($_, \@regexps)) {
 	print $q->p(Ts("%s is banned", $name));
       } else {
-	my ($start, $end) = BanContributors::get_range($_);
-	$range = "[$start - $end]";
-	$name .= " " . $range;
-	print GetFormStart(undef, 'get', 'ban'),
-	  GetHiddenValue('action', 'ban'),
-	  GetHiddenValue('id', $id),
-	  GetHiddenValue('range', $range),
-	  GetHiddenValue('regexp', BanContributors::get_regexp_ip($start, $end)),
-	  GetHiddenValue('recent_edit', 'on'),
-	  $q->p($name, $q->submit(T('Ban!'))), $q->end_form();
+	my @pairs = BanContributors::get_range($_);
+	while (@pairs) {
+	  my $start = shift(@pairs);
+	  my $end = shift(@pairs);
+	  $range = "[$start - $end]";
+	  $name .= " " . $range;
+	  print GetFormStart(undef, 'get', 'ban'),
+	      GetHiddenValue('action', 'ban'),
+	      GetHiddenValue('id', $id),
+	      GetHiddenValue('range', $range),
+	      GetHiddenValue('regexp', BanContributors::get_regexp_ip($start, $end)),
+	      GetHiddenValue('recent_edit', 'on'),
+	      $q->p($name, $q->submit(T('Ban!'))), $q->end_form();
+	}
       }
     }
   }
@@ -171,43 +175,67 @@ use Net::Whois::Parser qw/parse_whois/;
 sub get_range {
   my $ip = shift;
   my $response = parse_whois(domain => $ip);
-  my ($start, $end);
   my $re = '(?:[0-9]{1,3}\.){3}[0-9]{1,3}';
-  my ($start, $end) = $response->{inetnum} =~ /($re) *- *($re)/;
-  return $start, $end;
+  # Just try all the keys and see whether there is a range match.
+  for (keys %$response) {
+    my @result;
+    $_ = $response->{$_};
+    for (ref eq 'ARRAY' ? @$_ : $_) {
+      push(@result, $1, $2) if /($re) *- *($re)/;
+    }
+    return @result if @result;
+  }
+  # Fallback
+  return $ip, $ip;
 }
 
 sub get_groups {
   my ($from, $to) = @_;
   my @groups;
-  if ($from < 10) {
-    my $to = $to >= 10 ? 9 : $to;
-    push(@groups, [$from, $to]);
-    $from = $to + 1;
+  if ($from == $to) {
+    return [$from, $to];
   }
-  while ($from < $to) {
-    my $to = int($from/100) < int($to/100) ? $from + 99 - $from % 100 : $to;
-    if ($from % 10) {
-      push(@groups, [$from, $from + 9 - $from % 10]);
-      $from += 10 - $from % 10;
-    }
-    if (int($from/10) < int($to/10)) {
-      if ($to % 10 == 9) {
-	push(@groups, [$from, $to]);
-	$from = 1 + $to;
-      } else {
-	push(@groups, [$from, $to - 1 - $to % 10]);
-	$from = $to - $to % 10;
-      }
-    } else {
-      push(@groups, [$from - $from % 10, $to]);
-      last;
-    }
-    if ($to % 10 != 9) {
-      push(@groups, [$from, $to]);
-      $from = 1 + $to; # jump from 99 to 100
-    }
+  # ones up to the nearest ten
+  if ($from < $to and ($from % 10 or $from < 10)) {
+    # from 5-7: as is
+    # from 5-17: 5 + 9 - 5 = 9 thus 5-9, set $from to 10
+    my $to2 = int($to/10) > int($from/10) ? $from + 9 - $from % 10 : $to;
+    push(@groups, [$from, $to2]);
+    $from = $to2 + 1;
+  }
+  # tens up to the nearest hundred
+  if ($from < $to and $from % 100) {
+    # 10-17: as is
+    # 10-82: 10 to 79, set $from to 80 (8*10-1)
+    # 10-182: 10 to 99, set $from to 100 (10+99=10=99)
+    # 110-182: 110 to 179, set $from to 180 (170)
+    # 110-222: 110 to 199, set $from to 200 (110+99-10 = 199)
+    my $to2 = int($to/100) > int($from/100) ? $from + 99 - $from % 100
+	: int($to/10) > int($from/10) ? int($to / 10) * 10 - 1
+	: $to;
+    push(@groups, [$from, $to2]);
+    $from = $to2 + 1;
+  }
+  # up to the next hundred
+  if (int($to/100) > int($from/100)) {
+    # from 100 to 223: set $from to 200 (2*100-1)
+    my $to2 = int($to/100) * 100 - 1;
+    push(@groups, [$from, $to2]);
+    $from = $to2 + 1;
   }
+  # up to the next ten
+  if (int($to/10) > int($from/10)) {
+    # 10 to 17: skip
+    # 100 to 143: set $from to 140 (14*10-1)
+    my $to2 = int($to / 10) * 10 - 1;
+    push(@groups, [$from, $to2]);
+    $from = $to2 + 1;
+  }
+  # up to the next one
+  if ($from <= $to) {
+    push(@groups, [$from, $to]);
+  }
+  # warn join("; ", map { "@$_" } @groups);
   return \@groups;
 }
 
@@ -235,24 +263,42 @@ sub get_regexp_ip {
   my $regexp = "^";
   for my $i (0 .. 3) {
     if ($start[$i] eq $end[$i]) {
+      # if the byte is the same, use it as is
       $regexp .= $start[$i];
-    } elsif ($start[$i] eq '0' and $end[$i] eq '255') {
+      $regexp .= '\.' if $i < 3;
+    } elsif ($start[$i] == 0 and $end[$i] == 255) {
+      # the starting byte is 0 and the end byte is 255, then anything goes:
+      # we're done, e.g. 185.244.214.0 - 185.244.214.255 results in 185\.244\.214\.
+      last;
+    } elsif ($i == 3 and $start[$i] != $end[$i]) {
+      # example 45.87.2.128 - 45.87.2.255: the last bytes differ
+      $regexp .= '(' . get_regexp_range($start[$i], $end[$i]) . ')';
       last;
-    } elsif ($start[$i + 1] > 0) {
-      $regexp .= '(' . $start[$i] . '\.('
-	  . get_regexp_range($start[$i + 1], '255') . ')|'
-	  . get_regexp_range($start[$i] + 1, $end[$i + 1]) . ')';
-      $regexp .= '\.';
+    } elsif ($start[$i + 1] == 0 and $end[$i + 1] == 255) {
+      # if we're here, we already know that the start byte and the end byte are
+      # not the same; if the next bytes are from 0 to 255, we know that
+      # everything else doesn't matter, e.g. 42.118.48.0 - 42.118.63.255
+      $regexp .= '(' . get_regexp_range($start[$i], $end[$i]) . ')';
+      $regexp .= '\.' if $i < 3;
+      last;
+    } elsif ($end[$i] - $start[$i] == 1 and $start[$i + 1] > 0 and $end[$i + 1] < 255) {
+      # if we're here, we already know that the start byte and the end byte are
+      # not the same; if the starting byte of the next (!) byte is bigger than
+      # zero, then we need groups: in the case 77.56.180.0 - 77.57.70.255 for
+      # example,
+      $regexp .= '(' . $start[$i] . '\.(' . get_regexp_range($start[$i + 1], 255) . ')|'
+		   . $end[$i] . '\.(' . get_regexp_range(0, $end[$i + 1]) . ')';
+      $regexp .= '\.' if $i < 3;
       last;
     } else {
-      $regexp .= '(' . get_regexp_range($start[$i], $end[$i]) . ')$';
+      warn "Unhandled regexp: $from - $to ($i)";
+      $regexp .= 'XXX';
+      $regexp .= '\.' if $i < 3;
       last;
     }
-    $regexp .= '\.' if $i < 3;
   }
   return $regexp;
 }
 
 # this is required in case we concatenate other modules to this one
 package OddMuse;
-

+ 1 - 3
modules/banned-regexps.pl

@@ -64,13 +64,11 @@ sub RegexpNewBannedContent {
   my $str = shift;
   # check whether Banned Content complains
   my $rule = RegexpOldBannedContent($str, @_);
-  # remove URLs as they have been checked by $BannedContent
-  $str =~ s/$FullUrlPattern//g;
   if (not $rule) {
     foreach (split(/\n/, GetPageContent($BannedRegexps))) {
       next unless m/^\s*([^#]+?)\s*(#\s*(\d\d\d\d-\d\d-\d\d\s*)?(.*))?$/;
       my ($regexp, $comment, $re) = ($1, $4, undef);
-      eval { $re = qr/$regexp/i; };
+      eval { $re = qr/($regexp)/i; };
       if (defined($re) && $str =~ $re) {
 	my $group1 = $1;
 	my $explanation = ($group1

+ 10 - 5
modules/creole.pl

@@ -246,7 +246,8 @@ sub CreoleRule {
             $q->img({-src=> UnquoteHtml($1),
                      -alt=> UnquoteHtml($3),
                      -title=> UnquoteHtml($3),
-                     -class=> 'url outside'})));
+		     -class=> 'url outside',
+		     -loading=>'lazy'})));
   }
   # image link: [[link|{{pic}}]] and [[link|{{pic|text}}]]
   elsif (m/\G(\[\[$FreeLinkPattern$CreoleLinkPipePattern
@@ -257,7 +258,8 @@ sub CreoleRule {
                  $q->img({-src=> GetDownloadLink(FreeToNormal($3), 2),
                           -alt=> UnquoteHtml($text),
                           -title=> UnquoteHtml($text),
-                          -class=> 'upload'}), 'image')), $text);
+                          -class=> 'upload',
+			  -loading=>'lazy'}), 'image')), $text);
   }
   # image link: [[link|{{url}}]] and [[link|{{url|text}}]]
   elsif (m/\G(\[\[$FreeLinkPattern$CreoleLinkPipePattern
@@ -268,7 +270,8 @@ sub CreoleRule {
                  $q->img({-src=> UnquoteHtml($3),
                           -alt=> UnquoteHtml($text),
                           -title=> UnquoteHtml($text),
-                          -class=> 'url outside'}), 'image')), $text);
+                          -class=> 'url outside',
+			  -loading=>'lazy'}), 'image')), $text);
   }
   # image link: [[url|{{pic}}]] and [[url|{{pic|text}}]]
   elsif (m/\G(\[\[$FullUrlPattern$CreoleLinkPipePattern
@@ -279,7 +282,8 @@ sub CreoleRule {
             $q->img({-src=> GetDownloadLink(FreeToNormal($3), 2),
                      -alt=> UnquoteHtml($text),
                      -title=> UnquoteHtml($text),
-                     -class=> 'upload'}))), $text);
+                     -class=> 'upload',
+		     -loading=>'lazy'}))), $text);
   }
   # image link: [[url|{{url}}]] and [[url|{{url|text}}]]
   elsif (m/\G\[\[$FullUrlPattern$CreoleLinkPipePattern
@@ -289,7 +293,8 @@ sub CreoleRule {
             $q->img({-src=> UnquoteHtml($2),
                      -alt=> UnquoteHtml($4),
                      -title=> UnquoteHtml($4),
-                     -class=> 'url outside'})));
+                     -class=> 'url outside',
+		     -loading=>'lazy'})));
   }
   # link: [[url]] and [[url|text]]
   elsif (m/\G\[\[$FullUrlPattern$CreoleLinkTextPattern\]\]/cgs) {

+ 1 - 1
modules/ditaa.pl

@@ -43,7 +43,7 @@ sub DitaaRule {
     my $data = MIME::Base64::encode_base64($image);
     my $url = "data:image/png;base64,$data";
     return CloseHtmlEnvironments()
-      . "<div$style>" . $q->img({-src=>$url, -alt=>$map}) . "</div>";
+      . "<div$style>" . $q->img({-src=>$url, -alt=>$map, -loading=>'lazy'}) . "</div>";
   }
   return undef;
 }

+ 1 - 1
modules/duckduckgo-search.pl

@@ -49,5 +49,5 @@ sub DuckDuckGoSearchInit {
 
 sub DoDuckDuckGoSearch {
   my $search = UrlEncode(GetParam('search', undef));
-  print $q->redirect({-uri=>"https://www.duckduckgo.com/?q=$search+site%3A$DuckDuckGoSearchDomain"});
+  print $q->redirect({-uri=>"https://duckduckgo.com/?q=$search+site%3A$DuckDuckGoSearchDomain"});
 }

+ 1 - 1
modules/emoji.pl

@@ -48,7 +48,7 @@ sub EmojiRule {
   } elsif (/\G&gt;:-?\(/cg) {
     # 😠 1F620 ANGRY FACE
     return '&#x1F620;';
-  } elsif (/\G:-?[Ppb]/cg) {
+  } elsif (/\G:-?[Ppb]\b/cg) {
     # 😝 1F61D FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES
     return '&#x1F61D;';
   } elsif (/\G&lt;3/cg) {

+ 1 - 1
modules/image.pl

@@ -66,7 +66,7 @@ sub ImageSupportRule {
       $src = $ImageUrlPath . '/' . ImageUrlEncode($name);
     }
     if ($found) {
-      $result = $q->img({-src=>$src, -alt=>$alt, -title=>$alt, -class=>'upload'});
+      $result = $q->img({-src=>$src, -alt=>$alt, -title=>$alt, -class=>'upload', -loading=>'lazy'});
       $result = $q->a({-href=>$link, -class=>$linkclass}, $result);
       if ($comments) {
 	for (split '\n', $comments) {

+ 0 - 0
modules/journal-rss.pl


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません