diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | EXTERNAL.md | 16 | ||||
-rw-r--r-- | README.md | 11 | ||||
-rw-r--r-- | UNLICENSE | 24 | ||||
-rwxr-xr-x | bin/Markdown.pl | 1450 | ||||
-rwxr-xr-x | bin/ssg5 | 276 | ||||
-rwxr-xr-x | build.sh | 10 | ||||
-rw-r--r-- | clean.do | 1 | ||||
-rw-r--r-- | site.do | 1 | ||||
-rw-r--r-- | src/_footer.html | 7 | ||||
-rw-r--r-- | src/_header.html | 17 | ||||
-rw-r--r-- | src/guidelines.md | 51 | ||||
-rw-r--r-- | src/guidelines_en.md | 51 | ||||
-rw-r--r-- | src/index.md | 11 | ||||
-rw-r--r-- | src/index_en.md | 11 | ||||
-rw-r--r-- | src/landing.md | 9 | ||||
-rw-r--r-- | src/landing_en.md | 9 | ||||
-rw-r--r-- | src/manifesto.md | 31 | ||||
-rw-r--r-- | src/manifesto_en.md | 31 | ||||
-rw-r--r-- | src/style.css | 67 | ||||
-rw-r--r-- | sync.do | 3 |
21 files changed, 2088 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8b3c274 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/dst diff --git a/EXTERNAL.md b/EXTERNAL.md new file mode 100644 index 0000000..c03e61c --- /dev/null +++ b/EXTERNAL.md @@ -0,0 +1,16 @@ +# External TT-Related Projects + +## Known Mirrors + +| Maintainer | Link | +| --------------------------------------------- | --------------------- | +| [mark@szy.io](mailto:mark@szy.io) | https://szy.io/tt/ | +| [gabe@erisian.tech](mailto:gabe@erisian.tech) | https://erisian.tech/ | +| [toast@toast.cafe](mailto:toast@toast.cafe) |https://trivial.technology/ | + +## Similarly-Spirited Projects + +- https://fourthievesvinegar.org/ +- https://scihub.org/ + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..396c046 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Тривиальные Технологии + +Русский пеервод. Распространение, зеркалирвоание и модификации приветствуются. + +# Trivial Technology + +This is the repository for the website of a Trivial Technology mirror. +See the website proper for more details! + +If this mirror doesn't suit you, feel free to make your own. +Alternatively, see the EXTERNAL.md file for other mirrors we're aware of! diff --git a/UNLICENSE b/UNLICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to <https://unlicense.org> diff --git a/bin/Markdown.pl b/bin/Markdown.pl new file mode 100755 index 0000000..e4c8469 --- /dev/null +++ b/bin/Markdown.pl @@ -0,0 +1,1450 @@ +#!/usr/bin/perl + +# +# Markdown -- A text-to-HTML conversion tool for web writers +# +# Copyright (c) 2004 John Gruber +# <http://daringfireball.net/projects/markdown/> +# + + +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 <a> +# and <img> 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]* + <?(\S+?)>? # 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 <p>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.: + # <div> + # <div> + # tags for inner block must be indented. + # </div> + # </div> + # + # 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 `<div>` and stop at the first `</div>`. + $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 + </\2> # 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<tag>` to `</tag>\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 + .*</\2> # 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 <hr />. 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: + <! + (--.*?--\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<hr$g_empty_element_suffix\n}gmx; + $text =~ s{^[ ]{0,2}([ ]? -[ ]?){3,}[ \t]*$}{\n<hr$g_empty_element_suffix\n}gmx; + $text =~ s{^[ ]{0,2}([ ]? _[ ]?){3,}[ \t]*$}{\n<hr$g_empty_element_suffix\n}gmx; + + $text = _DoLists($text); + + $text = _DoCodeBlocks($text); + + $text = _DoBlockQuotes($text); + + # We already ran _HashHTMLBlocks() before, in Markdown(), but that + # was to escape raw HTML in the original Markdown source. This time, + # we're escaping the markup we've just created, so that we don't wrap + # <p> 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 `<http://example.com/>` + # Must come after _DoAnchors(), because you can use < and > + # delimiters in inline links like [this](<url>). + $text = _DoAutoLinks($text); + + $text = _EncodeAmpsAndAngles($text); + + $text = _DoItalicsAndBold($text); + + # Do hard breaks: + $text =~ s/ {2,}\n/ <br$g_empty_element_suffix\n/g; + + return $text; +} + + +sub _EscapeSpecialChars { + my $text = shift; + my $tokens ||= _TokenizeHTML($text); + + $text = ''; # rebuild $text from the tokens +# my $in_pre = 0; # Keep track of when we're inside <pre> or <code> 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 <a> 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 = "<a href=\"$url\""; + if ( defined $g_titles{$link_id} ) { + my $title = $g_titles{$link_id}; + $title =~ s! \* !$g_escape_table{'*'}!gx; + $title =~ s! _ !$g_escape_table{'_'}!gx; + $result .= " title=\"$title\""; + } + $result .= ">$link_text</a>"; + } + else { + $result = $whole_match; + } + $result; + }xsge; + + # + # Next, inline-style links: [link text](url "optional title") + # + $text =~ s{ + ( # wrap whole match in $1 + \[ + ($g_nested_brackets) # link text = $2 + \] + \( # literal paren + [ \t]* + <?(.*?)>? # 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 = "<a href=\"$url\""; + + if (defined $title) { + $title =~ s/"/"/g; + $title =~ s! \* !$g_escape_table{'*'}!gx; + $title =~ s! _ !$g_escape_table{'_'}!gx; + $result .= " title=\"$title\""; + } + + $result .= ">$link_text</a>"; + + $result; + }xsge; + + return $text; +} + + +sub _DoImages { +# +# Turn Markdown image shortcuts into <img> 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 = "<img src=\"$url\" alt=\"$alt_text\""; + if (defined $g_titles{$link_id}) { + my $title = $g_titles{$link_id}; + $title =~ s! \* !$g_escape_table{'*'}!gx; + $title =~ s! _ !$g_escape_table{'_'}!gx; + $result .= " title=\"$title\""; + } + $result .= $g_empty_element_suffix; + } + else { + # If there's no such link ID, leave intact: + $result = $whole_match; + } + + $result; + }xsge; + + # + # Next, handle inline images: ![alt text](url "optional title") + # Don't forget: encode * and _ + + $text =~ s{ + ( # wrap whole match in $1 + !\[ + (.*?) # alt text = $2 + \] + \( # literal paren + [ \t]* + <?(\S+?)>? # 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 = "<img src=\"$url\" alt=\"$alt_text\""; + if (defined $title) { + $title =~ s! \* !$g_escape_table{'*'}!gx; + $title =~ s! _ !$g_escape_table{'_'}!gx; + $result .= " title=\"$title\""; + } + $result .= $g_empty_element_suffix; + + $result; + }xsge; + + return $text; +} + + +sub _DoHeaders { + my $text = shift; + + # Setext-style headers: + # Header 1 + # ======== + # + # Header 2 + # -------- + # + $text =~ s{ ^(.+)[ \t]*\n=+[ \t]*\n+ }{ + "<h1>" . _RunSpanGamut($1) . "</h1>\n\n"; + }egmx; + + $text =~ s{ ^(.+)[ \t]*\n-+[ \t]*\n+ }{ + "<h2>" . _RunSpanGamut($1) . "</h2>\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); + "<h$h_level>" . _RunSpanGamut($2) . "</h$h_level>\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 . "</$list_type>\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 . "</$list_type>\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); + } + + "<li>" . $item . "</li>\n"; + }egmx; + + $g_list_level--; + return $list_str; +} + + + +sub _DoCodeBlocks { +# +# Process Markdown `<pre><code>` 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<pre><code>" . $codeblock . "\n</code></pre>\n\n"; + + $result; + }egmx; + + return $text; +} + + +sub _DoCodeSpans { +# +# * Backtick quotes are used for <code></code> 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: +# +# <p>Just type <code>foo `bar` baz</code> at the prompt.</p> +# +# 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 <code>`bar`</code> ... +# + + my $text = shift; + + $text =~ s@ + (`+) # $1 = Opening run of ` + (.+?) # $2 = The code block + (?<!`) + \1 # Matching closer + (?!`) + @ + my $c = "$2"; + $c =~ s/^[ \t]*//g; # leading whitespace + $c =~ s/[ \t]*$//g; # trailing whitespace + $c = _EncodeCode($c); + "<code>$c</code>"; + @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; + + # <strong> must go first: + $text =~ s{ (\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1 } + {<strong>$2</strong>}gsx; + + $text =~ s{ (\*|_) (?=\S) (.+?) (?<=\S) \1 } + {<em>$2</em>}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 <pre> content, so we need to fix that: + $bq =~ s{ + (\s*<pre>.+?</pre>) + }{ + my $pre = $1; + $pre =~ s/^ //mg; + $pre; + }egsx; + + "<blockquote>\n$bq\n</blockquote>\n\n"; + }egmx; + + + return $text; +} + + +sub _FormParagraphs { +# +# Params: +# $text - string to process with html <p> tags +# + my $text = shift; + + # Strip leading and trailing lines: + $text =~ s/\A\n+//; + $text =~ s/\n+\z//; + + my @grafs = split(/\n{2,}/, $text); + + # + # Wrap <p> tags. + # + foreach (@grafs) { + unless (defined( $g_html_blocks{$_} )) { + $_ = _RunSpanGamut($_); + s/^([ \t]*)/<p>/; + $_ .= "</p>"; + } + } + + # + # 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]+)>}{<a href="$1">$1</a>}gi; + + # Email addresses: <address@domain.foo> + $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.: +# +# <a href="mailto:foo@e +# xample.com">foo +# @example.com</a> +# +# Based on a filter by Matthew Wickline, posted to the BBEdit-Talk +# mailing list: <http://tinyurl.com/yu7ue> +# + + 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{<a href="$addr">$addr</a>}; + $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 <a href="<MTFoo>">, 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. +# <http://www.bradchoate.com/past/mtregex.php> +# + + 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: <! ( -- .*? -- \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: +# <http://www.nntp.perl.org/group/perl.macperl.anyperl/154> +# + 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<Markdown> + + +=head1 SYNOPSIS + +B<Markdown.pl> [ B<--html4tags> ] [ B<--version> ] [ B<-shortversion> ] + [ I<file> ... ] + + +=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 <div> and <table> 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.: + + <br> + +instead of Markdown's default XHTML style tags, e.g.: + + <br /> + + +=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 +<http://daringfireball.net/> +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/bin/ssg5 b/bin/ssg5 new file mode 100755 index 0000000..4edf2ef --- /dev/null +++ b/bin/ssg5 @@ -0,0 +1,276 @@ +#!/bin/sh -e +# +# https://rgz.ee/bin/ssg5 +# Copyright 2018-2019 Roman Zolotarev <hi@romanzolotarev.com> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +main() { + test -n "$1" || usage + test -n "$2" || usage + test -n "$3" || usage + test -n "$4" || usage + test -d "$1" || no_dir "$1" + test -d "$2" || no_dir "$2" + + src=$(readlink_f "$1") + dst=$(readlink_f "$2") + + IGNORE=$( + if ! test -f "$src/.ssgignore" + then + printf ' ! -path "*/.*"' + return + fi + while read -r x + do + test -n "$x" || continue + printf ' ! -path "*/%s*"' "$x" + done < "$src/.ssgignore" + ) + + # files + + title="$3" + + h_file="$src/_header.html" + f_file="$src/_footer.html" + test -f "$f_file" && FOOTER=$(cat "$f_file") && export FOOTER + test -f "$h_file" && HEADER=$(cat "$h_file") && export HEADER + + list_dirs "$src" | + (cd "$src" && cpiopdu "$dst") + + fs=$( + if test -f "$dst/.files" + then list_affected_files "$src" "$dst/.files" + else list_files "$1" + fi + ) + + if test -n "$fs" + then + echo "$fs" | tee "$dst/.files" + + if echo "$fs" | grep -q '\.md$' + then + if test -x "$(which lowdown 2> /dev/null)" + then + echo "$fs" | grep '\.md$' | + render_md_files_lowdown "$src" "$dst" "$title" + else + if test -x "$(which Markdown.pl 2> /dev/null)" + then + echo "$fs" | grep '\.md$' | + render_md_files_Markdown_pl "$src" "$dst" "$title" + else + echo "couldn't find lowdown nor Markdown.pl" + exit 3 + fi + fi + fi + + echo "$fs" | grep '\.html$' | + render_html_files "$src" "$dst" "$title" + + echo "$fs" | grep -Ev '\.md$|\.html$' | + (cd "$src" && cpiopdu "$dst") + fi + + printf '[ssg] ' >&2 + print_status 'file, ' 'files, ' "$fs" >&2 + + + # sitemap + + base_url="$4" + date=$(date +%Y-%m-%d) + urls=$(list_pages "$src") + + test -n "$urls" && + render_sitemap "$urls" "$base_url" "$date" > "$dst/sitemap.xml" + + print_status 'url' 'urls' "$urls" >&2 + echo >&2 +} + + +readlink_f() { + file="$1" + cd "$(dirname "$file")" + file=$(basename "$file") + while test -L "$file" + do + file=$(readlink "$file") + cd "$(dirname "$file")" + file=$(basename "$file") + done + dir=$(pwd -P) + echo "$dir/$file" +} + + +print_status() { + test -z "$3" && printf 'no %s' "$2" && return + + echo "$3" | awk -v singular="$1" -v plural="$2" ' + END { + if (NR==1) printf NR " " singular + if (NR>1) printf NR " " plural + }' +} + + +usage() { + echo "usage: ${0##*/} src dst title base_url" >&2 + exit 1 +} + + +no_dir() { + echo "${0##*/}: $1: No such directory" >&2 + exit 2 +} + +list_dirs() { + cd "$1" && eval "find . -type d ! -name '.' ! -path '*/_*' $IGNORE" +} + + +list_files() { + cd "$1" && eval "find . -type f ! -name '.' ! -path '*/_*' $IGNORE" +} + + +list_dependant_files () { + e="\\( -name '*.html' -o -name '*.md' -o -name '*.css' -o -name '*.js' \\)" + cd "$1" && eval "find . -type f ! -name '.' ! -path '*/_*' $IGNORE $e" +} + +list_newer_files() { + cd "$1" && eval "find . -type f ! -name '.' $IGNORE -newer $2" +} + + +has_partials() { + grep -qE '^./_.*\.html$|^./_.*\.js$|^./_.*\.css$' +} + + +list_affected_files() { + fs=$(list_newer_files "$1" "$2") + + if echo "$fs" | has_partials + then list_dependant_files "$1" + else echo "$fs" + fi +} + + +render_html_files() { + while read -r f + do render_html_file "$3" < "$1/$f" > "$2/$f" + done +} + + +render_md_files_lowdown() { + while read -r f + do + lowdown \ + -D html-skiphtml \ + -d metadata \ + -d autolink < "$1/$f" | + render_html_file "$3" \ + > "$2/${f%\.md}.html" + done +} + + +render_md_files_Markdown_pl() { + while read -r f + do + Markdown.pl < "$1/$f" | + render_html_file "$3" \ + > "$2/${f%\.md}.html" + done +} + + +render_html_file() { + # h/t Devin Teske + awk -v title="$1" ' + { body = body "\n" $0 } + END { + body = substr(body, 2) + if (body ~ /<[Hh][Tt][Mm][Ll]/) { + print body + exit + } + if (match(body, /<[[:space:]]*[Hh]1(>|[[:space:]][^>]*>)/)) { + t = substr(body, RSTART + RLENGTH) + sub("<[[:space:]]*/[[:space:]]*[Hh]1.*", "", t) + gsub(/^[[:space:]]*|[[:space:]]$/, "", t) + if (t) title = t " — " title + } + n = split(ENVIRON["HEADER"], header, /\n/) + for (i = 1; i <= n; i++) { + if (match(tolower(header[i]), "<title></title>")) { + head = substr(header[i], 1, RSTART - 1) + tail = substr(header[i], RSTART + RLENGTH) + print head "<title>" title "</title>" tail + } else print header[i] + } + print body + print ENVIRON["FOOTER"] + }' +} + + +list_pages() { + e="\\( -name '*.html' -o -name '*.md' \\)" + cd "$1" && eval "find . -type f ! -path '*/.*' ! -path '*/_*' $IGNORE $e" | + sed 's#^./##;s#.md$#.html#;s#/index.html$#/#' +} + + +render_sitemap() { + urls="$1" + base_url="$2" + date="$3" + + echo '<?xml version="1.0" encoding="UTF-8"?>' + echo '<urlset' + echo 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' + echo 'xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9' + echo 'http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"' + echo 'xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' + echo "$urls" | + sed -E 's#^(.*)$#<url><loc>'"$base_url"'/\1</loc><lastmod>'\ +"$date"'</lastmod><priority>1.0</priority></url>#' + echo '</urlset>' +} + +cpiopdu() { + dst="$1" + while IFS='$\n' read -r f; do + b="$(basename $f)" + d="$(dirname $f)" + mkdir -p "$1/$d" + [ -d "$f" ] && mkdir -p "$1/$f" + [ -f "$f" ] && cp "$f" "$1/$d/$b" + done +} + +main "$@" diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..9db8586 --- /dev/null +++ b/build.sh @@ -0,0 +1,10 @@ +#!/bin/sh +d="$(dirname $0)" +case "$d" in + /*) ;; + *) d="$PWD/$d" +esac +export PATH="$PATH:$d/bin" + +mkdir -p dst +ssg5 src dst "trivial technology" "$@" diff --git a/clean.do b/clean.do new file mode 100644 index 0000000..e33c18d --- /dev/null +++ b/clean.do @@ -0,0 +1 @@ +rm -r dst @@ -0,0 +1 @@ +./build.sh "scientia potentia est" ./ diff --git a/src/_footer.html b/src/_footer.html new file mode 100644 index 0000000..781712f --- /dev/null +++ b/src/_footer.html @@ -0,0 +1,7 @@ +<footer> + <hr /> + <p> + Maintained at <a href='https://gitea.phreedom.club/tolstoevsky/ttt'>https://git.phreedom.club/tolstoevsky/tt</a> by <a href='mailto:tolstoevsky@phreedom.club'>Tolstoevsky</a> + </p></footer> + </body> + </html> diff --git a/src/_header.html b/src/_header.html new file mode 100644 index 0000000..a01fe5a --- /dev/null +++ b/src/_header.html @@ -0,0 +1,17 @@ +<!doctype html> +<html><head> + <title></title> + <meta charset="UTF-8"> + <meta name="generator" content="romanzolotarev.com/ssg"> + <meta name="stylesheet" content="perfectmotherfuckingwebsite.com"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="https://phreedom.club/tt.css"> + + </head><body> + <div class="homelink"><a href="/">Home</a></div> + <nav> + <a href="index.html">Главная</a> <a href="index_en.html">/Main</a> + <a href="manifesto.html">Манифест</a> <a href="manifesto_en.html">/Manifesto</a> + <a href="landing.html">Лендинг</a> <a href="landing_en.html">/Landing</a> + <a href="guidelines.html">Методичка</a> <a href="guidelines_en.html">/Guidelines</a> + </nav> diff --git a/src/guidelines.md b/src/guidelines.md new file mode 100644 index 0000000..8f913e0 --- /dev/null +++ b/src/guidelines.md @@ -0,0 +1,51 @@ +# Тривиальные технологии: Методические Редомендации + +Итак, допустим, вы убеждены и хотите дополнительных инструкций о том, как помочь движению. Это именно тот документ, что вам нужен. Первые два раздела — короткие и рассказывают о том, как вы можете помочь, не разрабатывая собственное ПО в рамках ТТ. Третий раздел содержит указания по максимальному упрощению ПО, в попытке сделать его Тривиальным. + +## Используйте ТТ, расскажите друзьям + +Новые возможности бесполезны, если люди ими не пользуются. Правда в том, что **вы** способны всё поменять. Если вас не устраивает положение дел в какой-то области попробуйте программу ТТ. Если вы всё ещё не удовлетворены — вам будет намного проще поменять всё под свои нужды, так попробуйте это сделать! Видите недовольство своих друзей — расскажите им о ТТ. Если вы знакомы с разработчиками — расскажите им о ТТ. Если вы знаете людей, чьи цели сходны с вашими — расскажите им о ТТ, пусть предложат свой вариант. + +## Держите Зеркала + +ТТ по своей сути Тривиальны. Они не могут быть централизованы. Например, эта инстанция, оригинальная она или нет, всего лишь зеркало. Ваше зеркало может содержать изменения, делающие его более пригодными для ваших нужд или нужд вашего сообщества. Всё это доступно под Unlicense, так что вам нет нужды беспокоиться о том, что вы делаете с идеей. Вот ряд рекомендаций по процедуре зеркалирования: + +1. Скопируйте исходники (через git или просто как текстовые файлы). + +2. Измените `_footer.html`, добавив туда *ваши* контактные данные в качестве сопровождающего. + +3. Вычистите страницу `external`, если она существует и содержит данные. + +4. Внесите изменения на своё усмотрение и разместите результат. + +На страничке `external` по желанию можно сделать две вещи. Можно добавить список других известных вам зеркал — в этом случае вам может потребоваться поддерживать контакт с их сопровождающими. Второе — вы можете разместить список "сертифицированного" Тривиального ПО. + +Процесс сертификации прост: попросите человека, не имевшего дела с этим ПО, пополльзоваться им на протяжении выходных (суть требования про "два дня"), пусть попробует понять это ПО полностью, включая *API* зависимостей, всю лицензию и мета-знания (как собрать и запустить это ПО). Если вы не можете найти подобного человека, найдите технаря, но в этом случае требование по времени сокращается в 8 раз (до шести часов). Это гораздо более жёсткое требование. Ну и, разумеется, вы не можете сертифицировать собственные проекты. + +Людям, просматривающим список сертифицированных проектов, рекомендуется самостоятельно проверять эту сертификацию, и, возможно, добавить свой список. Варианты, когда кто-то просто сертифицирует всё, что пожелает, включая свои собственные рпокты, должны быть очевидными — в этом случае зеркало стоит просто игнорировать, просто ввиду недобросовестности сопровождающего. + +## Создавайте Тривиальное ПО + +Первый шаг прост — вы должны пожелать, чтобы ваш проект был Тривиальным. Если у вас есть подобное желание, вставьте фразу об этом в README, заявляя миру, что ваш проект стремится достичь стандартов движения ТТ, и ссылку на зеркало по вашему выбору (ссылка должна вести на страницу лендинга). Всё остальное имеет невеликое значение, если вам удастся достичь указанных стандартов. Всё остальное — не более, чем рекомендации. + +1. Ваши коммиты должны быть минимальными и объяснять причину вносимых изменений. + +2. Оставляйте комментарии в местах существенных изменений. + +3. Всё, что объявлено глобально, должно быть read-only для всех модулей, в которых оно объявлено. Изменения вносятся в стиле библиотек или в main. В этом случае указывайте на это в комментариях. + +4. Функции и типы должны быть логичными и ограниченными. Ни в коем случае не создавайте функцию, делающую множество вещей. + +5. Минимизируйте количество аргументов. Если у функции 10 аргументов — проверьте, почему их столько и не стоит ли их перегруппировать в reusable type. + +6. Минимизируйте вложенность и потоковые функции. Поддерживайте несколько уровней отступов. Если вам нужно настраиваемое поведение, подумайте о map/reduce и о visitor pattern. Функции высшего порядка хороши, если их использование понятно. + +7. Поддерживайте файл NEWS. Он должен быть последовательным и содержать только изменения, видимые пользователю. + +8. Поддерживайте файл READING. Он должен содержать информацию о том, как читать исходники, в каком порядке и мягко помогать читателю разобраться в вашей программе. + +9. Минимизируйте объём и ограничения лицензии в файле LICENSE, так как полное понимание этого файла — часть понимания вашего проекта. Мы рекомендуем Unlicense и 0BSD. + +10. Минимизируйте количество "мета-работы". Проект, использующий CMake, требует от читателя понимания CMake. Это лишнее переключение контекста сильно увеличивает сложность понимания проекта, особенно, когда мета-работа разрастается до сотен строк. Предпочитайте либо очень малый объём мета-работы (простой makefile или скрипт) или языки, не требующие оной (например Go, где вся дополнительная работа сводится к build-flags, число которых должно быть минимальным). + +11. Добавляйте только те функции, которые используете лично вы. Вместо добавления всех фишек — просто оставьте открытые места, где каждый сможет расширить функциональность под себя. Если вы не используете какую-то фичу сами, вы не знаете, как другой может захотеть её использовать, так что просто позвольте им сделать это самим, для их собственных нужд. diff --git a/src/guidelines_en.md b/src/guidelines_en.md new file mode 100644 index 0000000..35d186c --- /dev/null +++ b/src/guidelines_en.md @@ -0,0 +1,51 @@ +# Trivial Technologies: Guidelines + +Let us say you are convinced, and you want some further instructions on how to help. This is that document. The first two sections are shorter and speak on how to help without developing brand new TT software. The third primary section will contain guidelines on how to maximally simplify software, in the attempt to be a TT. + +## Use TT, Tell Your Friends + +Empowering the people has no effect if the people do not use this ability. The truth is that *you* **are** capable of these things. If you are unhappy with the state of things in a given field, try a TT program. If you are still unhappy with it, it will be the easiest option for you to modify to your liking, so try doing that! If you see that your friends are unhappy, tell them about TT as an option. If you know developers, tell them about TT too. If you know people with similar goals to ours, tell them about TT so that they may host their own variation. + +## Host Mirrors + +TT is itself Trivial. It is not meant to be centralized. This hosted instance, whether it's the original one or not, is too, just a mirror. Your mirror may also contain changes, such that it will fit your needs and your community better. The whole thing is available under the Unlicense, so you needn't worry about anything you do with the idea. Here is the recommended procedure to make a mirror: + +1. Copy the sources (whether using git or as plain files). + +2. Modify the `_footer.html` file to have *your* contact data, as the maintainer. + +3. Clean out the `external` page, if it exists and contains entries. + +4. Make any further modifications you wish and deploy it. + +In the `external` page, two things may optionally go if you so wish it. You may have a list of other known mirrors on there, in which case you may wish to stay in contact with the maintainers of them. Secondly, you may have a list of certified TT software. + +The certification process is simple: find a lay person that has never seen that software, and ask them to spend a weekend (the source of the "2 days" requirement) trying to understand the software in its entirety - including the *API* of the dependencies, the entirety of the license, and the meta knowledge (how to build/deploy it). If you cannot find such a person, you may use a technologist instead, but then the time allowed is restricted to 1/8th (i.e 6 hours). This is a much harsher requirement. Finally, you cannot certify your own projects., + +People looking at the list of certified projects are encouraged to verify the certifications themselves, perhaps to add them to their own list. Scenarios of someone simply certifying whatever they wish, or their own projects, should become blatantly clear, in which case the mirror in question is to be ignored when it comes to that, for they are clearly acting in bad faith. + +## Make TT Software + +The first step is simple - you must desire for your project to be Trivial. If you have such a desire, insert a phrase into your README, proclaiming to the word that your project strives to achieve the standards of the TT movement, and link to a mirror of your choosing (you should link to the landing page). The rest matters little, if you manage to achieve those standards. The rest of this are but recommendations. + +1. Your commits should be minimally small, and explain why the changes in question were made. + +2. You should comment in locations whenever state is significantly changed. + +3. Globals, if you have any, should be read-only to the modules in which they are defined. They should only be changed by library-style consumers, or in main. If that is the case, track that in a comment near them. + +4. Keep functions and types logical and limited. In no case should you have a function that does a great many things. + +5. Minimize the amount of arguments. If there are 10 arguments to a function, consider why they are there, and whether they can be grouped together under a reusable type. + +6. Minimize nesting and other flow features. You should have few levels of indentation. If you need customizable behaviors, consider map/reduce, or a visitor pattern. Higher Order Functions are good as long as their use is clear. + +7. Keep a NEWS file. It should be consistent, and only speak of user-visible changes. + +8. Keep a READING file. It should explain how to read the sources, in what order, and gently guide the reader to understanding your program. + +9. Minimize both the restrictions of your LICENSE file, as well as the length, for understanding it in its entirety is part of understanding your project. We recommend the Unlicense and 0BSD. + +10. Minimize the amount of "meta-work" required. A project that uses CMake requires the reader to understand CMake. This needless context-switching greatly increases the difficulty of understanding projects, especially when the meta-work grows to thousands of lines. Prefer either very small amounts thereof (basic makefile, simple script) or languages that do not have meta-work associated with them (such as Go, where the entirety of the meta work is build-flags, the use of which should be minimal). + +11. Only add the features you personally use. Instead of adding all the features, simply leave open points into which one may add features themselves. If you do not use a feature, you do not know how one might want to use it, so instead empower them to add it themselves, for their own fork. diff --git a/src/index.md b/src/index.md new file mode 100644 index 0000000..e74258d --- /dev/null +++ b/src/index.md @@ -0,0 +1,11 @@ +# Тривиальные технологии + +Тривиальные Технологии (ТТ) — это новый способ производства СПО, цель которого — максимально расширить возможности человека, предоставив средства для достижения любой цели. + +ТТ тривиальны. Любой новичок должен быть в состоянии полностью понять их за два дня. Профессионал должен быть в состоянии разобраться за чашкой чаю дождливым вечером. Они не должны представлять из себя чёрный ящик, вскрытие которого чревато навлечением на себя древнего проклятия. + +ТТ податливы. Есть очевидные места для добавления функций, и точки расширения функциональности. Нет никакой необходимости танцевать с бубном вокруг особенностей реализации ради получения нужной функциональности. + +ТТ открыты. Настолько, насколько возможно. ТТ предлагаются без каких-либо условий. Они лицензируются под максимально пермиссивными лицензиями, которые мы можем найти (0BSD, Unlicence, CC0) и даже это представляется нам компромиссом. Никто не осудит вас за форк ТТ, не у кого спрашивать разрешения, нет никакого оригинального автора, которого необходимо вечно упоминать. + +ТТ принадлежат вам. Чтоб выяснить, откуда есть пошли ТТ, и какие принципы лежат в основе движения, прочитайте Манифест. diff --git a/src/index_en.md b/src/index_en.md new file mode 100644 index 0000000..12e3a0c --- /dev/null +++ b/src/index_en.md @@ -0,0 +1,11 @@ +# Trivial Technologies + +Trivial Technology (TT) is a new way of doing FOSS, whose goal is to maximally empower the individual, by providing a stepping stone for whatever they may wish to build. + +TT is Trivial. A beginner should be able to completely understand it in 2 days. A professional should grasp it in a rainy afternoon. It is not meant to be a plug-and-play black box that one does not open lest they contact some ancient curse. + +TT is malleable. There are visible hooks for adding features and open points where one can extend functionality. It is not a feature pinata where one has to dance around implementation details. + +TT is open. As much as possible, TT is offered with no strings attached and we mean it. It's licenced under the most permissive licences we can find (0BSD, Unlicence, CC0) and even that we see as a compromise. Nobody will frown at you for forking TT, there's nobody to ask for permission, there's no original author that has to be forever mentioned. + +TT is your own. To find out more about how this came to be and what are the larger principles behind this movement, be sure to read our manifesto. diff --git a/src/landing.md b/src/landing.md new file mode 100644 index 0000000..5bab4f2 --- /dev/null +++ b/src/landing.md @@ -0,0 +1,9 @@ +# Тривиальные Технологии: лендинг + +С большой вероятностью, вы попали сюда по ссылке из README какого-либо проекта. Это означает, что этот проект стремится быть тем, что мы называем "Тривиальными Технологиями". И вот что это означает. + +Закон об авторском праве был создан, чтоб гарантировать доступ и обеспечить распространение полезных произведений искусства и технологии. Однако сейчас он делает прямо противоположное. Горстка избранных контролирует каждую толику технологий, которые вы используете, и вы должны вымаливаить, как нищие, чтобы любые вещи, нужные вам или вашему сообществу были добавлены, исправлены или удалены в конечном продукте. Из-за "авторских прав" вы не можете самостоятельно вносить эти изменения. Либо можете, но на кабальных условиях. Кроме того, централизация контролирующих это органов увеличивает риски: горстка избранных владеет вашей информацией, контролирует, как вы используете их продукт, и даже если сейчас они действуют в рамках разумного, их в любой момент могут перекупить и всё изменится. + +Тривиальные Технологии стремятся достичь прямо противоположных целей. Тривиальные Технологии отрицают авторское право, даже в качестве средства самовоспроизводства. Тривиальные Технологии стремятся к отсутствию ключевых владельцев; изменения и ремиксы приветствуются, и оригинальному автору совершенно необязательно даже знать о том, что вы используете его произведение. Тривиальные Технологии стремятся быть простыми — настолько простыми, чтобы сторонний человек мог разобраться в сути технологии за два дня, получив тем самым возможность изменять её под свои требования. + +Вкратце, проект, приведший вас сюда, не принадлежит сам себе. Он принадлежит всем. Вы должны быть в состоянии легко в нём разобраться и свободно делать с ним всё, что пожелаете независимо от мнения авторов — это знание, в его самой чистой и свободной форме. diff --git a/src/landing_en.md b/src/landing_en.md new file mode 100644 index 0000000..6ebd6ba --- /dev/null +++ b/src/landing_en.md @@ -0,0 +1,9 @@ +# Trivial Technologies: Landing + +You have likely arrived here by clicking on a link found in a project's README. That link being there means that the project strives to be what we call a "Trivial Technology". Here is what that means. + +Copyright law was created to ensure access and promote the propagation of the useful arts. However, nowadays, it does quite the opposite. A select few control every piece of technology that you use, and you must ask, as beggars, for things essential to you or your community to be added, fixed, or not removed. Because of copyright, you may not do the modifications yourself. When you may, it is likely cost-prohibitive to do so. Further, due to the centralization of the controlling parties, the risks become great: the select few hold your information, control how you may use their product, and even if they are to be sane now, they could be bought out at any moment, for all of that to change. + +A Trivial Technology, instead, seeks to be the opposite. Trivial Technologies reject copyright, even as a vehicle for self-perpetuation. Trivial Technologies seek to not have any central owners, modifications, remixes are encouraged, and the original writer need not even know about your use. Trivial Technologies seek to be simple, so simple even someone not in the industry could, within a short time (2 days) understand the entirety of the technology, and thus gain the ability to change it according to their own designs. + +In short, the project that linked you here is not its own. It belongs to all. It belongs to you. You should be able to understand it easily, and you should feel free to do whatever you wish with it, approved by the authors or not. It is knowledge, in its purest, emancipated form. diff --git a/src/manifesto.md b/src/manifesto.md new file mode 100644 index 0000000..e0c494d --- /dev/null +++ b/src/manifesto.md @@ -0,0 +1,31 @@ +# Тривиальные Технологии: Манифест + +Призрак бродит по техносфере — призрак Освобождения. Все мировые силы объединились в священный союз, чтобы изгнать призрака: Комиссии по Стандартам, Правительства и Суды, Медиа и IT-компании. Те, кто извлекает прибыль из ограничения доступа к знаниям — будь то в денежном выражении или в виде влияния. Те, кто извлекает прибыть из целых сфер деятельности, отгороженных от простых смертных бюрократическими барьерами, жаргоном и временными рамками. + +Открытые научные знания — высмеиваются. Люди, обучающие других изготавливать собственные лекарства, видя злоупотребления фармкомпаний, объявляются опасными преступниками. Движение за Открытый Исходный код принимается только в том виде, в котором приводит к централизации под крылом корпораций. + +Следующие инструменты: авторское право, патентное право, законы о торговых марках, все они служат одной цели — централизовать знания, держать их под контролем оригинального автора. Мы же, наоборот, стремимся к прямо противоположному — освобождению знания где это только возможно. Это движение, хоть и относится в первую очередь к программному обеспечению, является часть более обширного философского течения. + +Чтобы сделать доступными знания о ПО, равно как и возможность изменять и распространять его, мы стремимся уничтожить все препятствия, которые нам по силам. Доступ к изменению и любому типу использования предоставляется путём перевода в Общественное Достояние (или лицензии без обязательств, если перевод в ОД невозможен). Программное обеспечение само по себе должно быть доступным — в идеале, неспециалист должен быть способен разобраться в нём за два дня. Следует принимать активные меры для поддержания его в таком состоянии, подстилая соломку, где придётся. + +Мы называем подобное понятное и свободное ПО "Тривиальным ПО", или как вариант "Тривиальными Технологиями". На них никто не может заявить свои права — как на колесо. Как с рычагом, любой может разобраться, как их использовать, объединять и модифицировать для создания чего-либо иного. Любой может получить выгоду от создания, но выгода сама по себе не должна вставать на пути знания. + +## Что должно быть сделано + +1. Идея должна быть распространена. Всё, что вы здесь видите, свободно доступно для использования, изменения и распространения. Держите копии, зеркала, изменённые версии, рассказывайте друзьям. Если вы хотите внести существенные изменения, либо поменять сам манифест, пожалуйста, измените и название во избежание недопонимания, и чтобы вас не путали с нами. + +2. Должны существовать проекты, стремящиеся стать Тривиальными. Это не всегда достижимо, но само намерение и усилия, в направлении разумного дизайна проектов, улучшат положение вещей сами по себе. Размещайте в README ваших проектов ссылки с декларацией ваших намерений, и ссылки на зеркало по вашему выбору. Не всё ПО должно быть Тривиальным, но в каждом направлении деятельности такая альтернатива должна существовать — тогда у любого, недовольного тем, как обстоят дела, будет точка для самостоятельного старта. + +3. Люди должны быть проинформированы. Подавляющее большинство людей уверено, что не может ничего сделать, и это относится не только к ПО, но и к другим направлениям деятельности. Они считают, что слишком тупы, необучены, неспособны, чтобы хотя бы попытаться. Продемонстрируйте им, что это не так. Поощряйте их к действиям. Позвольте массам подняться выше того, что они считали пределом своих способностей. + +## Open Source сломан + +Вы можете спросить — почему бы просто не следовать существующей философии, такой как GNU или OSI. Да потому что Открытый Код принципиально поломан. + +Open Source всегда фокусировался на лицензировании, на использовании авторского права как инструмента дла достижения своих целей. Чем это хорошо, само по себе? Представьте себе огромную кодовую базу, действительно огромную, с костылями через каждые 5 строк, исправляющими ошибки в совершенно другом источнике. Допустим, продукт, созданный на основе этого кода, широко используется. Пускай он выпущен под GPL, как много пользователей сможет доработать его под свои конкретные нужды? Лицензия сама по себе ничего не значит. Кроме того, эти движения по сути своей несовместимы с целями ТТ. + +Когда речь заходит о GNU, их обещания и цели быстренько рассыпаются на части. Их исходники быстро становятся всё сложнее и сложнее, увязая в обязательствах, которые они на себя взвалили. Они используют авторское право как основу для своих собственных ограничений, тем самым эффективно усиливая систему, с которой стремятся бороться. Они говорят о распространении программ как фундаментально дружественном акте, в то время как бесконечные форки GPL-программ приводят к нескончаемым распрям. GNU — фундаментальная сила централизации, а централизованные системы намного легче контролируются и разрушаются внешними силами, чем любые другие. + +Что же до OSI, они своему названию не соответствуют. По запросу FSF они сертифицировали AGPL, лицензию, нарушающую как минимум 6 пункт OSD. Спешное принятие, престижа ради, заставило пожалеть о последствиях. Когда же появилась очень похожая лицензия (SSPL от MongoDB Inc.), они её отвергли. Некоторые члены организации указывали на непоследовательность позиции руководства. OSI бежит от Общественного Достояния как от чумы, отказываясь сертифицировать CC0 и Unlicense, несмотря на то, что ни одна из них не нарушает ни один из пунктов OSD. Они утверждают, что это связано с тем, что перевод в Общественное Достояние требует пересмотра законов каждой страны, в тоже время упоминая некую резервную лицензию, которая соответствует требованиям. Вот только упоминание ведёт в никуда. + +Другие похожие движения (различные нео-лицензии например) — просто подделки под GPL, страдающие теми же или худшими болячками. diff --git a/src/manifesto_en.md b/src/manifesto_en.md new file mode 100644 index 0000000..8d987d9 --- /dev/null +++ b/src/manifesto_en.md @@ -0,0 +1,31 @@ +# Trivial Technologies: Manifesto + +A specter is haunting software—the specter of Emancipation. All of the world's Powers have entered into a holy alliance to exorcise this specter: Journal and Standards Body, Government and Judge, Media and IT Company. Those who would seek to profit from those that may need knowledge they possess, whether it be monetarily or through increased influence. Those who would profit from entire fields of endeavor remaining accessible only to the elites, barred behind red tape, jargon and time barriers. + +The open scientific endeavors are ridiculed. Those teaching others to make their own medication in the face of pharmaceutical abuse, when not ignored, are hunted as dangerous criminals. The open source movement only became acceptable when that fundamentally centralizing force became the very corporations it seeks to stop. + +These tools: copyright, patent, trademark laws, all serve the same purpose—to centralize knowledge, keep it in the hands and control of the original creator. We, instead, seek the opposite. We seek the emancipation of knowledge, whenever possible. This movement, while pertaining to software, is fundamentally but a component of that grander philosophy. + +To allow for the knowledge of software, and the ability to modify it, to spread, we reduce as many barriers as possible. Access to modification and use of any kind is granted by way of public domain (or a license free of obligations, when that is not possible). The software itself shall be accessible, ideally understandable by a layman within 2 days. Measures should be taken towards keeping it that way proactively, and easing any potential rough patches one may run into. + +We call such understandable and emancipated software "Trivial Software", or perhaps a "Trivial Technology". Like the wheel, no one may lay claim to it. Like the lever, any can understand how to use, aggregate and modify it to make something else. Any may profit from the creation, but that profit shall never be allowed to get in the way of the knowledge itself. + +## What is to Be Done + +1. The Idea must be spread. All that you can see here is available freely, to use, modify, and distribute. Host copies, host mirrors, host modifications, tell your friends. If you desire to make significant modifications, or change the manifesto, do consider calling yourself something else, lest you be confused for us. + +2. There must be projects that strive to be Trivial. It is not always attainable, but the intent and the effort put into sane design will still improve the state of things. Put links in your READMEs declaring your intentions, and linking to a mirror of your choosing. Not all software need be Trivial, but for any activity, there should be an alternative that is, so that one dissatisfied with the state of things may jump off of it to serve themselves. + +3. The people must be informed. It is overwhelmingly common for one to believe that they cannot do things, whether it be in software or other fields of endeavor. That they are too dumb, too uneducated, too incapable to even attempt them. Show them otherwise. Encourage them otherwise. Allow the masses to rise beyond what they thought themselves capable of. + +## Open Source is Broken + +One may ask why one wouldn't simply follow an existing philosophy, such as that of GNU or the OSI. This is because Open Source is fundamentally broken. + +Open Source has always focused on licensing. Using copyright as a tool to get its way. What good does that do, on its own? Imagine a codebase, truly humongous, with a workaround every 5 lines for a mistake in an entirely different section of the sources. Pretend that the product made from this codebase is widely used. Were it to be released under the GPL, how many would be able to mold it to better fit their needs? A license, on its own, means nothing. Further, these movements are inherently incompatible with the goals of TT. + +When it comes to GNU, their promises and goals quickly fall apart. Their sources quickly get progressively more complex, bogged down by the requirements they put upon themselves. It uses copyright as a vessel for their restrictions, effectively reinforcing the system that it seeks to subvert. It speaks of sharing programs as the fundamental act of friendship, and yet GPL forks result only in never-ending feuds. GNU is fundamentally a force for centralization, and centralized systems are far easier for the Powers that be to corrupt than any others. + +As for OSI, it refuses to hold to its definition. When the FSF asked, they certified the AGPL, a license that breaks at the very least point 6 of the OSD. It was rushed through because of the attached prestige, only later to be regretted. When an extremely similar license came along (the SSPL, by MongoDB Inc.), they rejected it, for the prestige was gone. Some members pointed out that the position is inconsistent. The OSI avoids the public domain like the plague, failing to certify CC0 and the Unlicense, despite neither violating any component of the OSD. They claim that this is because reviewing a public domain dedication requires reviewing the laws of each country, in the same breath as they mention a fallback license that is compliant. That mention goes nowhere. + +Other similar movements (such as the various neo-licenses) are simply knock-offs of the GPL, plagued with the same problems, if not moreso. diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..7c5535d --- /dev/null +++ b/src/style.css @@ -0,0 +1,67 @@ +@font-face {
+ font-family: "Computer Modern Serif";
+ src: url(/font/cmunrm.ttf);
+}
+
+@font-face {
+ font-family: "Computer Modern Serif";
+ src: url(/font/cmunbx.ttf);
+ font-weight: bold;
+}
+
+body {
+ font-family: "Computer Modern Serif", serif;
+ font-size: 16pt;
+ font-variant-ligatures: none;
+ margin: 50px auto;
+ padding: 0 10px;
+ max-width: 650px;
+ color: #444;
+}
+
+.homelink {
+ margin-bottom: 25px;
+}
+
+@media (prefers-color-scheme: dark) {
+ body {
+ color:white;
+ background:#444
+ }
+ a:link {
+ color:#5bf
+ }
+ a:visited {
+ color:#ccf
+ }
+}
+
+h1, h2, h3 {
+ line-height: 1.2;
+}
+
+a {
+ color: #524632;
+}
+
+hr {
+ width: 75%;
+ border: none;
+ height: 1px;
+ color: #292f36;
+ background-color: #292f36;
+}
+
+ul {
+ list-style-type: square;
+}
+
+blockquote {
+ font-style: italic;
+ padding-left: 20px;
+ border-left: 3px solid #78c0a8;
+}
+
+code {
+ font-size: 0.9em;
+}
@@ -0,0 +1,3 @@ +redo clean +redo site +ssb-webify publish dst |