From 9d507e5a298e17dbd21aabc0eac4329a97d11413 Mon Sep 17 00:00:00 2001 From: Carl Masak Date: Sun, 2 Jan 2011 01:54:29 +0100 Subject: [PATCH] initial commit --- .gitignore | 2 + Markdown_1.0.1/License.text | 30 + Markdown_1.0.1/Markdown Readme.text | 341 +++++++ Markdown_1.0.1/Markdown.pl | 1450 +++++++++++++++++++++++++++ css/main.css | 148 +++ css/upload_main_css | 2 + images/fading-background.png | Bin 0 -> 10142 bytes images/str-trans-boxplot.png | Bin 0 -> 10298 bytes images/tree-and-road.jpg | Bin 0 -> 12240 bytes pages/about.markdown | 57 ++ pages/no-comments.markdown | 38 + psyde | 248 +++++ templates/default.atom | 12 + templates/default.html | 33 + templates/entry.atom | 13 + templates/post.html | 12 + templates/postitem.html | 4 + templates/postlist.html | 35 + upload_blog | 49 + 19 files changed, 2474 insertions(+) create mode 100644 .gitignore create mode 100644 Markdown_1.0.1/License.text create mode 100644 Markdown_1.0.1/Markdown Readme.text create mode 100755 Markdown_1.0.1/Markdown.pl create mode 100644 css/main.css create mode 100644 css/upload_main_css create mode 100644 images/fading-background.png create mode 100644 images/str-trans-boxplot.png create mode 100644 images/tree-and-road.jpg create mode 100644 pages/about.markdown create mode 100644 pages/no-comments.markdown create mode 100755 psyde create mode 100644 templates/default.atom create mode 100644 templates/default.html create mode 100644 templates/entry.atom create mode 100644 templates/post.html create mode 100644 templates/postitem.html create mode 100644 templates/postlist.html create mode 100755 upload_blog diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a74121e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +_site +posts diff --git a/Markdown_1.0.1/License.text b/Markdown_1.0.1/License.text new file mode 100644 index 0000000..6d76506 --- /dev/null +++ b/Markdown_1.0.1/License.text @@ -0,0 +1,30 @@ +Copyright (c) 2004, John Gruber + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name "Markdown" nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as +is" and any express or implied warranties, including, but not limited +to, the implied warranties of merchantability and fitness for a +particular purpose are disclaimed. In no event shall the copyright owner +or contributors be liable for any direct, indirect, incidental, special, +exemplary, or consequential damages (including, but not limited to, +procurement of substitute goods or services; loss of use, data, or +profits; or business interruption) however caused and on any theory of +liability, whether in contract, strict liability, or tort (including +negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. diff --git a/Markdown_1.0.1/Markdown Readme.text b/Markdown_1.0.1/Markdown Readme.text new file mode 100644 index 0000000..6fbb95f --- /dev/null +++ b/Markdown_1.0.1/Markdown Readme.text @@ -0,0 +1,341 @@ +Markdown +======== + +Version 1.0.1 - Tue 14 Dec 2004 + +by John Gruber + + + +Introduction +------------ + +Markdown is a text-to-HTML conversion tool for web writers. Markdown +allows you to write using an easy-to-read, easy-to-write plain text +format, then convert it to structurally valid XHTML (or HTML). + +Thus, "Markdown" is two things: a plain text markup syntax, and a +software tool, written in Perl, that converts the plain text markup +to HTML. + +Markdown works both as a Movable Type plug-in and as a standalone Perl +script -- which means it can also be used as a text filter in BBEdit +(or any other application that supporst filters written in Perl). + +Full documentation of Markdown's syntax and configuration options is +available on the web: . +(Note: this readme file is formatted in Markdown.) + + + +Installation and Requirements +----------------------------- + +Markdown requires Perl 5.6.0 or later. Welcome to the 21st Century. +Markdown also requires the standard Perl library module `Digest::MD5`. + + +### Movable Type ### + +Markdown works with Movable Type version 2.6 or later (including +MT 3.0 or later). + +1. Copy the "Markdown.pl" file into your Movable Type "plugins" + directory. The "plugins" directory should be in the same directory + as "mt.cgi"; if the "plugins" directory doesn't already exist, use + your FTP program to create it. Your installation should look like + this: + + (mt home)/plugins/Markdown.pl + +2. Once installed, Markdown will appear as an option in Movable Type's + Text Formatting pop-up menu. This is selectable on a per-post basis. + Markdown translates your posts to HTML when you publish; the posts + themselves are stored in your MT database in Markdown format. + +3. If you also install SmartyPants 1.5 (or later), Markdown will offer + a second text formatting option: "Markdown with SmartyPants". This + option is the same as the regular "Markdown" formatter, except that + automatically uses SmartyPants to create typographically correct + curly quotes, em-dashes, and ellipses. See the SmartyPants web page + for more information: + +4. To make Markdown (or "Markdown with SmartyPants") your default + text formatting option for new posts, go to Weblog Config -> + Preferences. + +Note that by default, Markdown produces XHTML output. To configure +Markdown to produce HTML 4 output, see "Configuration", below. + + +### Blosxom ### + +Markdown works with Blosxom version 2.x. + +1. Rename the "Markdown.pl" plug-in to "Markdown" (case is + important). Movable Type requires plug-ins to have a ".pl" + extension; Blosxom forbids it. + +2. Copy the "Markdown" plug-in file to your Blosxom plug-ins folder. + If you're not sure where your Blosxom plug-ins folder is, see the + Blosxom documentation for information. + +3. That's it. The entries in your weblog will now automatically be + processed by Markdown. + +4. If you'd like to apply Markdown formatting only to certain posts, + rather than all of them, see Jason Clark's instructions for using + Markdown in conjunction with Blosxom's Meta plugin: + + + + +### BBEdit ### + +Markdown works with BBEdit 6.1 or later on Mac OS X. (It also works +with BBEdit 5.1 or later and MacPerl 5.6.1 on Mac OS 8.6 or later.) + +1. Copy the "Markdown.pl" file to appropriate filters folder in your + "BBEdit Support" folder. On Mac OS X, this should be: + + BBEdit Support/Unix Support/Unix Filters/ + + See the BBEdit documentation for more details on the location of + these folders. + + You can rename "Markdown.pl" to whatever you wish. + +2. That's it. To use Markdown, select some text in a BBEdit document, + then choose Markdown from the Filters sub-menu in the "#!" menu, or + the Filters floating palette + + + +Configuration +------------- + +By default, Markdown produces XHTML output for tags with empty elements. +E.g.: + +
+ +Markdown can be configured to produce HTML-style tags; e.g.: + +
+ + +### Movable Type ### + +You need to use a special `MTMarkdownOptions` container tag in each +Movable Type template where you want HTML 4-style output: + + + ... put your entry content here ... + + +The easiest way to use MTMarkdownOptions is probably to put the +opening tag right after your `` tag, and the closing tag right +before ``. + +To suppress Markdown processing in a particular template, i.e. to +publish the raw Markdown-formatted text without translation into +(X)HTML, set the `output` attribute to 'raw': + + + ... put your entry content here ... + + + +### Command-Line ### + +Use the `--html4tags` command-line switch to produce HTML output from a +Unix-style command line. E.g.: + + % perl Markdown.pl --html4tags foo.text + +Type `perldoc Markdown.pl`, or read the POD documentation within the +Markdown.pl source code for more information. + + + +Bugs +---- + +To file bug reports or feature requests please send email to: +. + + + +Version History +--------------- + +1.0.1 (14 Dec 2004): + ++ Changed the syntax rules for code blocks and spans. Previously, + backslash escapes for special Markdown characters were processed + everywhere other than within inline HTML tags. Now, the contents + of code blocks and spans are no longer processed for backslash + escapes. This means that code blocks and spans are now treated + literally, with no special rules to worry about regarding + backslashes. + + **NOTE**: This changes the syntax from all previous versions of + Markdown. Code blocks and spans involving backslash characters + will now generate different output than before. + ++ Tweaked the rules for link definitions so that they must occur + within three spaces of the left margin. Thus if you indent a link + definition by four spaces or a tab, it will now be a code block. + + [a]: /url/ "Indented 3 spaces, this is a link def" + + [b]: /url/ "Indented 4 spaces, this is a code block" + + **IMPORTANT**: This may affect existing Markdown content if it + contains link definitions indented by 4 or more spaces. + ++ Added `>`, `+`, and `-` to the list of backslash-escapable + characters. These should have been done when these characters + were added as unordered list item markers. + ++ Trailing spaces and tabs following HTML comments and `
` tags + are now ignored. + ++ Inline links using `<` and `>` URL delimiters weren't working: + + like [this]() + ++ Added a bit of tolerance for trailing spaces and tabs after + Markdown hr's. + ++ Fixed bug where auto-links were being processed within code spans: + + like this: `` + ++ Sort-of fixed a bug where lines in the middle of hard-wrapped + paragraphs, which lines look like the start of a list item, + would accidentally trigger the creation of a list. E.g. a + paragraph that looked like this: + + I recommend upgrading to version + 8. Oops, now this line is treated + as a sub-list. + + This is fixed for top-level lists, but it can still happen for + sub-lists. E.g., the following list item will not be parsed + properly: + + + I recommend upgrading to version + 8. Oops, now this line is treated + as a sub-list. + + Given Markdown's list-creation rules, I'm not sure this can + be fixed. + ++ Standalone HTML comments are now handled; previously, they'd get + wrapped in a spurious `

` tag. + ++ Fix for horizontal rules preceded by 2 or 3 spaces. + ++ `


` HTML tags in must occur within three spaces of left + margin. (With 4 spaces or a tab, they should be code blocks, but + weren't before this fix.) + ++ Capitalized "With" in "Markdown With SmartyPants" for + consistency with the same string label in SmartyPants.pl. + (This fix is specific to the MT plug-in interface.) + ++ Auto-linked email address can now optionally contain + a 'mailto:' protocol. I.e. these are equivalent: + + + + ++ Fixed annoying bug where nested lists would wind up with + spurious (and invalid) `

` tags. + ++ You can now write empty links: + + [like this]() + + and they'll be turned into anchor tags with empty href attributes. + This should have worked before, but didn't. + ++ `***this***` and `___this___` are now turned into + + this + + Instead of + + this + + which isn't valid. (Thanks to Michel Fortin for the fix.) + ++ Added a new substitution in `_EncodeCode()`: s/\$/$/g; This + is only for the benefit of Blosxom users, because Blosxom + (sometimes?) interpolates Perl scalars in your article bodies. + ++ Fixed problem for links defined with urls that include parens, e.g.: + + [1]: http://sources.wikipedia.org/wiki/Middle_East_Policy_(Chomsky) + + "Chomsky" was being erroneously treated as the URL's title. + ++ At some point during 1.0's beta cycle, I changed every sub's + argument fetching from this idiom: + + my $text = shift; + + to: + + my $text = shift || return ''; + + The idea was to keep Markdown from doing any work in a sub + if the input was empty. This introduced a bug, though: + if the input to any function was the single-character string + "0", it would also evaluate as false and return immediately. + How silly. Now fixed. + + + +Donations +--------- + +Donations to support Markdown's development are happily accepted. See: + for details. + + + +Copyright and License +--------------------- + +Copyright (c) 2003-2004 John Gruber + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name "Markdown" nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as +is" and any express or implied warranties, including, but not limited +to, the implied warranties of merchantability and fitness for a +particular purpose are disclaimed. In no event shall the copyright owner +or contributors be liable for any direct, indirect, incidental, special, +exemplary, or consequential damages (including, but not limited to, +procurement of substitute goods or services; loss of use, data, or +profits; or business interruption) however caused and on any theory of +liability, whether in contract, strict liability, or tort (including +negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. diff --git a/Markdown_1.0.1/Markdown.pl b/Markdown_1.0.1/Markdown.pl new file mode 100755 index 0000000..e4c8469 --- /dev/null +++ b/Markdown_1.0.1/Markdown.pl @@ -0,0 +1,1450 @@ +#!/usr/bin/perl + +# +# Markdown -- A text-to-HTML conversion tool for web writers +# +# Copyright (c) 2004 John Gruber +# +# + + +package Markdown; +require 5.006_000; +use strict; +use warnings; + +use Digest::MD5 qw(md5_hex); +use vars qw($VERSION); +$VERSION = '1.0.1'; +# Tue 14 Dec 2004 + +## Disabled; causes problems under Perl 5.6.1: +# use utf8; +# binmode( STDOUT, ":utf8" ); # c.f.: http://acis.openlib.org/dev/perl-unicode-struggle.html + + +# +# Global default settings: +# +my $g_empty_element_suffix = " />"; # Change to ">" for HTML output +my $g_tab_width = 4; + + +# +# Globals: +# + +# Regex to match balanced [brackets]. See Friedl's +# "Mastering Regular Expressions", 2nd Ed., pp. 328-331. +my $g_nested_brackets; +$g_nested_brackets = qr{ + (?> # Atomic matching + [^\[\]]+ # Anything other than brackets + | + \[ + (??{ $g_nested_brackets }) # Recursive set of nested brackets + \] + )* +}x; + + +# Table of hash values for escaped characters: +my %g_escape_table; +foreach my $char (split //, '\\`*_{}[]()>#+-.!') { + $g_escape_table{$char} = md5_hex($char); +} + + +# Global hashes, used by various utility routines +my %g_urls; +my %g_titles; +my %g_html_blocks; + +# Used to track when we're inside an ordered or unordered list +# (see _ProcessListItems() for details): +my $g_list_level = 0; + + +#### Blosxom plug-in interface ########################################## + +# Set $g_blosxom_use_meta to 1 to use Blosxom's meta plug-in to determine +# which posts Markdown should process, using a "meta-markup: markdown" +# header. If it's set to 0 (the default), Markdown will process all +# entries. +my $g_blosxom_use_meta = 0; + +sub start { 1; } +sub story { + my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_; + + if ( (! $g_blosxom_use_meta) or + (defined($meta::markup) and ($meta::markup =~ /^\s*markdown\s*$/i)) + ){ + $$body_ref = Markdown($$body_ref); + } + 1; +} + + +#### Movable Type plug-in interface ##################################### +eval {require MT}; # Test to see if we're running in MT. +unless ($@) { + require MT; + import MT; + require MT::Template::Context; + import MT::Template::Context; + + eval {require MT::Plugin}; # Test to see if we're running >= MT 3.0. + unless ($@) { + require MT::Plugin; + import MT::Plugin; + my $plugin = new MT::Plugin({ + name => "Markdown", + description => "A plain-text-to-HTML formatting plugin. (Version: $VERSION)", + doc_link => 'http://daringfireball.net/projects/markdown/' + }); + MT->add_plugin( $plugin ); + } + + MT::Template::Context->add_container_tag(MarkdownOptions => sub { + my $ctx = shift; + my $args = shift; + my $builder = $ctx->stash('builder'); + my $tokens = $ctx->stash('tokens'); + + if (defined ($args->{'output'}) ) { + $ctx->stash('markdown_output', lc $args->{'output'}); + } + + defined (my $str = $builder->build($ctx, $tokens) ) + or return $ctx->error($builder->errstr); + $str; # return value + }); + + MT->add_text_filter('markdown' => { + label => 'Markdown', + docs => 'http://daringfireball.net/projects/markdown/', + on_format => sub { + my $text = shift; + my $ctx = shift; + my $raw = 0; + if (defined $ctx) { + my $output = $ctx->stash('markdown_output'); + if (defined $output && $output =~ m/^html/i) { + $g_empty_element_suffix = ">"; + $ctx->stash('markdown_output', ''); + } + elsif (defined $output && $output eq 'raw') { + $raw = 1; + $ctx->stash('markdown_output', ''); + } + else { + $raw = 0; + $g_empty_element_suffix = " />"; + } + } + $text = $raw ? $text : Markdown($text); + $text; + }, + }); + + # If SmartyPants is loaded, add a combo Markdown/SmartyPants text filter: + my $smartypants; + + { + no warnings "once"; + $smartypants = $MT::Template::Context::Global_filters{'smarty_pants'}; + } + + if ($smartypants) { + MT->add_text_filter('markdown_with_smartypants' => { + label => 'Markdown With SmartyPants', + docs => 'http://daringfireball.net/projects/markdown/', + on_format => sub { + my $text = shift; + my $ctx = shift; + if (defined $ctx) { + my $output = $ctx->stash('markdown_output'); + if (defined $output && $output eq 'html') { + $g_empty_element_suffix = ">"; + } + else { + $g_empty_element_suffix = " />"; + } + } + $text = Markdown($text); + $text = $smartypants->($text, '1'); + }, + }); + } +} +else { +#### BBEdit/command-line text filter interface ########################## +# Needs to be hidden from MT (and Blosxom when running in static mode). + + # We're only using $blosxom::version once; tell Perl not to warn us: + no warnings 'once'; + unless ( defined($blosxom::version) ) { + use warnings; + + #### Check for command-line switches: ################# + my %cli_opts; + use Getopt::Long; + Getopt::Long::Configure('pass_through'); + GetOptions(\%cli_opts, + 'version', + 'shortversion', + 'html4tags', + ); + if ($cli_opts{'version'}) { # Version info + print "\nThis is Markdown, version $VERSION.\n"; + print "Copyright 2004 John Gruber\n"; + print "http://daringfireball.net/projects/markdown/\n\n"; + exit 0; + } + if ($cli_opts{'shortversion'}) { # Just the version number string. + print $VERSION; + exit 0; + } + if ($cli_opts{'html4tags'}) { # Use HTML tag style instead of XHTML + $g_empty_element_suffix = ">"; + } + + + #### Process incoming text: ########################### + my $text; + { + local $/; # Slurp the whole file + $text = <>; + } + print Markdown($text); + } +} + + + +sub Markdown { +# +# Main function. The order in which other subs are called here is +# essential. Link and image substitutions need to happen before +# _EscapeSpecialChars(), so that any *'s or _'s in the +# and tags get encoded. +# + my $text = shift; + + # Clear the global hashes. If we don't clear these, you get conflicts + # from other articles when generating a page which contains more than + # one article (e.g. an index page that shows the N most recent + # articles): + %g_urls = (); + %g_titles = (); + %g_html_blocks = (); + + + # Standardize line endings: + $text =~ s{\r\n}{\n}g; # DOS to Unix + $text =~ s{\r}{\n}g; # Mac to Unix + + # Make sure $text ends with a couple of newlines: + $text .= "\n\n"; + + # Convert all tabs to spaces. + $text = _Detab($text); + + # Strip any lines consisting only of spaces and tabs. + # This makes subsequent regexen easier to write, because we can + # match consecutive blank lines with /\n+/ instead of something + # contorted like /[ \t]*\n+/ . + $text =~ s/^[ \t]+$//mg; + + # Turn block-level HTML blocks into hash entries + $text = _HashHTMLBlocks($text); + + # Strip link definitions, store in hashes. + $text = _StripLinkDefinitions($text); + + $text = _RunBlockGamut($text); + + $text = _UnescapeSpecialChars($text); + + return $text . "\n"; +} + + +sub _StripLinkDefinitions { +# +# Strips link definitions from text, stores the URLs and titles in +# hash references. +# + my $text = shift; + my $less_than_tab = $g_tab_width - 1; + + # Link defs are in the form: ^[id]: url "optional title" + while ($text =~ s{ + ^[ ]{0,$less_than_tab}\[(.+)\]: # id = $1 + [ \t]* + \n? # maybe *one* newline + [ \t]* + ? # url = $2 + [ \t]* + \n? # maybe one newline + [ \t]* + (?: + (?<=\s) # lookbehind for whitespace + ["(] + (.+?) # title = $3 + [")] + [ \t]* + )? # title is optional + (?:\n+|\Z) + } + {}mx) { + $g_urls{lc $1} = _EncodeAmpsAndAngles( $2 ); # Link IDs are case-insensitive + if ($3) { + $g_titles{lc $1} = $3; + $g_titles{lc $1} =~ s/"/"/g; + } + } + + return $text; +} + + +sub _HashHTMLBlocks { + my $text = shift; + my $less_than_tab = $g_tab_width - 1; + + # Hashify HTML blocks: + # We only want to do this for block-level HTML tags, such as headers, + # lists, and tables. That's because we still want to wrap

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

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

" . _RunSpanGamut($1) . "

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

    Just type foo `bar` baz at the prompt.

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

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

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

    /; + $_ .= "

    "; + } + } + + # + # Unhashify HTML blocks + # + foreach (@grafs) { + if (defined( $g_html_blocks{$_} )) { + $_ = $g_html_blocks{$_}; + } + } + + return join "\n\n", @grafs; +} + + +sub _EncodeAmpsAndAngles { +# Smart processing for ampersands and angle brackets that need to be encoded. + + my $text = shift; + + # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: + # http://bumppo.net/projects/amputator/ + $text =~ s/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/&/g; + + # Encode naked <'s + $text =~ s{<(?![a-z/?\$!])}{<}gi; + + return $text; +} + + +sub _EncodeBackslashEscapes { +# +# Parameter: String. +# Returns: The string, with after processing the following backslash +# escape sequences. +# + local $_ = shift; + + s! \\\\ !$g_escape_table{'\\'}!gx; # Must process escaped backslashes first. + s! \\` !$g_escape_table{'`'}!gx; + s! \\\* !$g_escape_table{'*'}!gx; + s! \\_ !$g_escape_table{'_'}!gx; + s! \\\{ !$g_escape_table{'{'}!gx; + s! \\\} !$g_escape_table{'}'}!gx; + s! \\\[ !$g_escape_table{'['}!gx; + s! \\\] !$g_escape_table{']'}!gx; + s! \\\( !$g_escape_table{'('}!gx; + s! \\\) !$g_escape_table{')'}!gx; + s! \\> !$g_escape_table{'>'}!gx; + s! \\\# !$g_escape_table{'#'}!gx; + s! \\\+ !$g_escape_table{'+'}!gx; + s! \\\- !$g_escape_table{'-'}!gx; + s! \\\. !$g_escape_table{'.'}!gx; + s{ \\! }{$g_escape_table{'!'}}gx; + + return $_; +} + + +sub _DoAutoLinks { + my $text = shift; + + $text =~ s{<((https?|ftp):[^'">\s]+)>}{
    $1}gi; + + # Email addresses: + $text =~ s{ + < + (?:mailto:)? + ( + [-.\w]+ + \@ + [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+ + ) + > + }{ + _EncodeEmailAddress( _UnescapeSpecialChars($1) ); + }egix; + + return $text; +} + + +sub _EncodeEmailAddress { +# +# Input: an email address, e.g. "foo@example.com" +# +# Output: the email address as a mailto link, with each character +# of the address encoded as either a decimal or hex entity, in +# the hopes of foiling most address harvesting spam bots. E.g.: +# +# foo +# @example.com +# +# Based on a filter by Matthew Wickline, posted to the BBEdit-Talk +# mailing list: +# + + my $addr = shift; + + srand; + my @encode = ( + sub { '&#' . ord(shift) . ';' }, + sub { '&#x' . sprintf( "%X", ord(shift) ) . ';' }, + sub { shift }, + ); + + $addr = "mailto:" . $addr; + + $addr =~ s{(.)}{ + my $char = $1; + if ( $char eq '@' ) { + # this *must* be encoded. I insist. + $char = $encode[int rand 1]->($char); + } elsif ( $char ne ':' ) { + # leave ':' alone (to spot mailto: later) + my $r = rand; + # roughly 10% raw, 45% hex, 45% dec + $char = ( + $r > .9 ? $encode[2]->($char) : + $r < .45 ? $encode[1]->($char) : + $encode[0]->($char) + ); + } + $char; + }gex; + + $addr = qq{$addr}; + $addr =~ s{">.+?:}{">}; # strip the mailto: from the visible part + + return $addr; +} + + +sub _UnescapeSpecialChars { +# +# Swap back in all the special characters we've hidden. +# + my $text = shift; + + while( my($char, $hash) = each(%g_escape_table) ) { + $text =~ s/$hash/$char/g; + } + return $text; +} + + +sub _TokenizeHTML { +# +# Parameter: String containing HTML markup. +# Returns: Reference to an array of the tokens comprising the input +# string. Each token is either a tag (possibly with nested, +# tags contained therein, such as , or a +# run of text between tags. Each element of the array is a +# two-element array; the first is either 'tag' or 'text'; +# the second is the actual value. +# +# +# Derived from the _tokenize() subroutine from Brad Choate's MTRegex plugin. +# +# + + my $str = shift; + my $pos = 0; + my $len = length $str; + my @tokens; + + my $depth = 6; + my $nested_tags = join('|', ('(?:<[a-z/!$](?:[^<>]') x $depth) . (')*>)' x $depth); + my $match = qr/(?s: ) | # comment + (?s: <\? .*? \?> ) | # processing instruction + $nested_tags/ix; # nested tags + + while ($str =~ m/($match)/g) { + my $whole_tag = $1; + my $sec_start = pos $str; + my $tag_start = $sec_start - length $whole_tag; + if ($pos < $tag_start) { + push @tokens, ['text', substr($str, $pos, $tag_start - $pos)]; + } + push @tokens, ['tag', $whole_tag]; + $pos = pos $str; + } + push @tokens, ['text', substr($str, $pos, $len - $pos)] if $pos < $len; + \@tokens; +} + + +sub _Outdent { +# +# Remove one level of line-leading tabs or spaces +# + my $text = shift; + + $text =~ s/^(\t|[ ]{1,$g_tab_width})//gm; + return $text; +} + + +sub _Detab { +# +# Cribbed from a post by Bart Lateur: +# +# + my $text = shift; + + $text =~ s{(.*?)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge; + return $text; +} + + +1; + +__END__ + + +=pod + +=head1 NAME + +B + + +=head1 SYNOPSIS + +B [ B<--html4tags> ] [ B<--version> ] [ B<-shortversion> ] + [ I ... ] + + +=head1 DESCRIPTION + +Markdown is a text-to-HTML filter; it translates an easy-to-read / +easy-to-write structured text format into HTML. Markdown's text format +is most similar to that of plain text email, and supports features such +as headers, *emphasis*, code blocks, blockquotes, and links. + +Markdown's syntax is designed not as a generic markup language, but +specifically to serve as a front-end to (X)HTML. You can use span-level +HTML tags anywhere in a Markdown document, and you can use block level +HTML tags (like
    and as well). + +For more information about Markdown's syntax, see: + + http://daringfireball.net/projects/markdown/ + + +=head1 OPTIONS + +Use "--" to end switch parsing. For example, to open a file named "-z", use: + + Markdown.pl -- -z + +=over 4 + + +=item B<--html4tags> + +Use HTML 4 style for empty element tags, e.g.: + +
    + +instead of Markdown's default XHTML style tags, e.g.: + +
    + + +=item B<-v>, B<--version> + +Display Markdown's version number and copyright information. + + +=item B<-s>, B<--shortversion> + +Display the short-form version number. + + +=back + + + +=head1 BUGS + +To file bug reports or feature requests (other than topics listed in the +Caveats section above) please send email to: + + support@daringfireball.net + +Please include with your report: (1) the example input; (2) the output +you expected; (3) the output Markdown actually produced. + + +=head1 VERSION HISTORY + +See the readme file for detailed release notes for this version. + +1.0.1 - 14 Dec 2004 + +1.0 - 28 Aug 2004 + + +=head1 AUTHOR + + John Gruber + http://daringfireball.net + + PHP port and other contributions by Michel Fortin + http://michelf.com + + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2003-2004 John Gruber + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name "Markdown" nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as +is" and any express or implied warranties, including, but not limited +to, the implied warranties of merchantability and fitness for a +particular purpose are disclaimed. In no event shall the copyright owner +or contributors be liable for any direct, indirect, incidental, special, +exemplary, or consequential damages (including, but not limited to, +procurement of substitute goods or services; loss of use, data, or +profits; or business interruption) however caused and on any theory of +liability, whether in contract, strict liability, or tort (including +negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. + +=cut diff --git a/css/main.css b/css/main.css new file mode 100644 index 0000000..1e24994 --- /dev/null +++ b/css/main.css @@ -0,0 +1,148 @@ +body { + font-size: 100%; + line-height: 1.5; + margin: 0 auto 4em; + max-width: 50em; + color: #211; + background: url('http://strangelyconsistent.org/blog/images/fading-background.png'); + background-repeat: repeat-x; + background-position: center top; + font-family: corbel, 'lucida grande', helvetica, sans-serif; +} + +body>header { + text-align: center; +} + +body>header>hgroup>h1 { + font: 1.4cm/1.14 "Molengo"; + font-weight: bold; + margin: 0; + margin-top: .3em; + margin-bottom: .2em; +/* position: absolute; + top: -30px; + left: 10px; */ +} + +body>header>hgroup>h1>a { + color: black; + text-decoration: none; +} + +body>header>hgroup>h2 { + font-family: 'OFL Sorts Mill Goudy TT', arial, serif; + margin: 0; + margin-left: 20px; + font-size: 100%; + font-style: italic; + font-weight: normal; +/* position: absolute; + top: 65px; + left: 10px; */ +} + +body>header>nav li { + display: inline; + list-style-type: none; +} + +article { + margin-top: 4em; + margin-left: 10em; + max-width: 42em; + margin-left: auto; + margin-right: auto; +} + +article .postinfo { + color: #666; + display: block; + float: left; + margin-left: -8em; + text-align: right; +} + +article .postinfo div { + border-top: solid 1px #eee; + line-height: 200%; +} + +article .postinfo a { + color: #666; +} + +article h1 { + font: 0.8cm/0.71 "Molengo"; + font-weight: bold; + line-height: 100%; +} + +article h2 { + font: 0.6cm/0.61 "Molengo"; + font-weight: bold; + line-height: 100%; +} + +article h1 a { + color: #211; + text-decoration: none; +} + +article aside { + color: #666; + background: #f5f5f5; + border: solid 1px #ccc; + font-size: 80%; + display: inline; + float: right; + margin-right: -10em; + padding: 0.5em; + width: 8em; +} + +.quote { + background: #ded; + margin: 1em; + padding: 1em; +} + +.separator { + text-align: center; +} + +pre { + background: #eee; + padding: 1em; + font: normal normal normal medium/1.2 Consolas, 'Andale Mono', Monaco, 'Liberation Mono', 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', monospace; + font-size: 100%; + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ +} + +.index h1 { + text-align: center; +} + +.index .entry { + margin: 50px 80px 50px 100px; +} + +.index .published { + width: 120px; + text-align: center; + float: left; + font-variant: small-caps; + color: #666; + margin-top: 0; + padding-right: 20px; +} + +.index h3 { + display: block; + margin: 0 100px 0 200px; + line-height: 1.3636; +} diff --git a/css/upload_main_css b/css/upload_main_css new file mode 100644 index 0000000..fd5b846 --- /dev/null +++ b/css/upload_main_css @@ -0,0 +1,2 @@ +cd public_html/blog/css +pu main.css diff --git a/images/fading-background.png b/images/fading-background.png new file mode 100644 index 0000000000000000000000000000000000000000..b6db8db19da8034f63d67848c219ceb036c6e17e GIT binary patch literal 10142 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 IidGT-3pVi%UjP6A literal 0 HcmV?d00001 diff --git a/images/str-trans-boxplot.png b/images/str-trans-boxplot.png new file mode 100644 index 0000000000000000000000000000000000000000..5bb03bb465fe6c101a94ba1c2934186cd43993de GIT binary patch literal 10298 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 literal 0 HcmV?d00001 diff --git a/images/tree-and-road.jpg b/images/tree-and-road.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2ed7de5c83377a55bdfe1446d124f2126a645b14 GIT binary patch literal 12240 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 +my %all_posts; +my $POSTS_IN_INDEX = 3; + +sub subst_all(Str $string is copy, *@substitutions) { + for @substitutions { + $string .= subst(.key, .value, :g) + } + $string; +} + +sub html_escape { + # RAKUDO: Need this unnecessary prefix:<~> to make it work + return (~$^original).trans: + ['&', '<', '>' ] + => ['&', '<', '>'] + ; +} + +sub apply_some_styles { + # RAKUDO: Need this unnecessary prefix:<~> to make it work + return (~$^original).trans: + ['class="quote"', + "class='quote'", + 'class="separator"', + "class='separator'"] + => ['style="background: #ded; margin: 1em; padding: 1em;"', + 'style="background: #ded; margin: 1em; padding: 1em;"', + 'style="text-align: center"', + 'style="text-align: center"'] + ; +} + +sub nonexistent-or-older($target, :than(@sources)!) { + return $target.IO !~~ :e + || $target.IO.changed before any(@sources).IO.changed; +} + +say "[_site/list-of-posts.html]"; +for dir('posts', :test( / '.markdown' $ / )) -> $markdown_filename { + given open "posts/$markdown_filename" -> $infile { + + $infile.get; + + my %info; + until (my $line = $infile.get) eq '---' { + my ($key, $value) = $line.split(': ', 2); + %info{$key} = $value; + } + %info ~~ /(\d\d\d\d) '-' (\d\d) '-' (\d\d)/; + %info = "$2.Int() @monthnames[$1-1], $0"; + %info = "$markdown_filename.subst(/'.' <-[.]>+ $/, '')"; + %all_posts{%info} = { + filename =>"posts/$markdown_filename", + %info, + }; + + my $html_filename = $markdown_filename.subst(/'.' <-[.]>+ $/, '.html'); + unless nonexistent-or-older "_site/$html_filename", + :than["posts/$markdown_filename"] { + $infile.close(); + next; + } + say "[posts/$markdown_filename -> _site/$html_filename]"; + + my $temp_filename = "/tmp/justmarkdown"; + given open $temp_filename, :w -> $tempfile { + $tempfile.print($infile.slurp); + $tempfile.close(); + } + + $infile.close(); + + my $converted_content + = qx[Markdown_1.0.1/Markdown.pl --html4tags /tmp/justmarkdown]; + unlink $temp_filename; + + my $article = $article_template.&subst_all( + '$root' => $root_url, + '$url' => %info, + '$title' => %info, + '$author' => %info<author>, + '$created' => %info<created>, + '$humandate' => %info<humandate>, + '$body' => $converted_content, + ); + + my $page = $default_template.&subst_all( + '$title' => %info<title>, + '$root' => $root_url, + '$body' => $article, + ); + + given open "_site/$html_filename", :w -> $outfile { + $outfile.print($page); + $outfile.close(); + } + } +} + +my $postitem_template = slurp("templates/postitem.html"); +my $postlist_template = slurp("templates/postlist.html"); +my $post_list = ''; + +for %all_posts{reverse sort { %all_posts{$_}<created> }, keys %all_posts} { + $post_list ~= $postitem_template.&subst_all( + '$root' => $root_url, + '$url' => .<url>, + '$title' => .<title>, + '$author' => .<author>, + '$humandate' => .<humandate>, + ); +} + +my $post_list_page = $postlist_template.&subst_all( + '$title' => "All posts", + '$root' => $root_url, + '$body' => $post_list, +); +given open "_site/list-of-posts.html", :w -> $outfile { + $outfile.print($post_list_page); + $outfile.close(); +} + +my @all_posts_newest_first = reverse sort { %all_posts{$_}<created> }, + keys %all_posts; + +my @index_filenames = map { .<filename> }, + %all_posts{@all_posts_newest_first[^(3 min +%all_posts)]}; +if nonexistent-or-older "_site/index.html", + :than(@index_filenames) { + + say "[@index_filenames.join("\n ") -> _site/index.html]"; + my $index_posts_content = ''; + + for %all_posts{@all_posts_newest_first[^(3 min +%all_posts)]} -> %info { + + my $markdown_filename = %info<url> ~ ".markdown"; + given open "posts/$markdown_filename" -> $infile { + + $infile.get; + 1 until $infile.get eq '---'; + + my $temp_filename = "/tmp/justmarkdown"; + given open $temp_filename, :w -> $tempfile { + $tempfile.print($infile.slurp); + $tempfile.close(); + } + + $infile.close(); + + my $converted_content + = qx[Markdown_1.0.1/Markdown.pl /tmp/justmarkdown]; + unlink $temp_filename; + + my $article = $article_template.&subst_all( + '$root' => $root_url, + '$url' => %info<url>, + '$title' => %info<title>, + '$author' => %info<author>, + '$created' => %info<created>, + '$humandate' => %info<humandate>, + '$body' => $converted_content, + ); + $index_posts_content ~= $article; + } + } + + my $index_page = $default_template.&subst_all( + '$title' => "Main page", + '$root' => $root_url, + '$body' => $index_posts_content, + ); + given open "_site/index.html", :w -> $outfile { + $outfile.print($index_page); + $outfile.close(); + } +} + +my @feed_filenames = map { .<filename> }, + %all_posts{@all_posts_newest_first[^(10 min +%all_posts)]}; +if nonexistent-or-older "_site/feed.atom", + :than(@feed_filenames) { + + say "[@feed_filenames.join("\n ") -> _site/feed.atom]"; + + my $atom_entry_template = slurp("templates/entry.atom"); + my $atom_template = slurp("templates/default.atom"); + my $atom_content = ''; + + for %all_posts{@all_posts_newest_first[^(10 min +%all_posts)]} -> %info { + my $markdown_filename = %info<url> ~ ".markdown"; + given open "posts/$markdown_filename" -> $infile { + + $infile.get; + 1 until $infile.get eq '---'; + + my $temp_filename = "/tmp/justmarkdown"; + given open $temp_filename, :w -> $tempfile { + $tempfile.print($infile.slurp); + $tempfile.close(); + } + + $infile.close(); + + my $converted_content + = qx[Markdown_1.0.1/Markdown.pl /tmp/justmarkdown]; + unlink $temp_filename; + + my $date = %info<created>.substr(0, 10); + my $id = ($root_url ~ '/' ~ %info<url>).&subst_all( + 'http://' => 'tag:', + '.org/' => ".org,$date:", + ); + + my $article = $atom_entry_template.&subst_all( + '$id' => $id, + '$root' => $root_url, + '$url' => %info<url>, + '$title' => %info<title>, + '$author' => %info<author>, + '$created' => %info<created>, + '$body' => html_escape( + apply_some_styles($converted_content) + ), + ); + $atom_content ~= $article; + } + } + + my $atom_feed = $atom_template.&subst_all( + '$updated' => %all_posts{@all_posts_newest_first[0]}<created>, + '$body' => $atom_content, + ); + given open "_site/feed.atom", :w -> $outfile { + $outfile.print($atom_feed); + $outfile.close(); + } +} diff --git a/templates/default.atom b/templates/default.atom new file mode 100644 index 0000000..bf1e800 --- /dev/null +++ b/templates/default.atom @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<feed xmlns="http://www.w3.org/2005/Atom"> + + <title>Strangely Consistent + + + $updated + http://strangelyconsistent.org/ + +$body + + diff --git a/templates/default.html b/templates/default.html new file mode 100644 index 0000000..7dcb8ad --- /dev/null +++ b/templates/default.html @@ -0,0 +1,33 @@ + + + + + $title :: Strangely Consistent + + + + + + + +
    +
    +

    Strangely Consistent

    +

    Musings about programming, Perl 6, and programming Perl 6

    +
    + +
    + + $body + + diff --git a/templates/entry.atom b/templates/entry.atom new file mode 100644 index 0000000..7d419ea --- /dev/null +++ b/templates/entry.atom @@ -0,0 +1,13 @@ + + $title + + $id + + $author + + $created + + $body + + + diff --git a/templates/post.html b/templates/post.html new file mode 100644 index 0000000..a374774 --- /dev/null +++ b/templates/post.html @@ -0,0 +1,12 @@ + diff --git a/templates/postitem.html b/templates/postitem.html new file mode 100644 index 0000000..e950082 --- /dev/null +++ b/templates/postitem.html @@ -0,0 +1,4 @@ +
    +
    $humandate
    +

    $title

    +
    diff --git a/templates/postlist.html b/templates/postlist.html new file mode 100644 index 0000000..acc659b --- /dev/null +++ b/templates/postlist.html @@ -0,0 +1,35 @@ + + + + + $title :: Strangely Consistent + + + + + + +
    +
    +

    Strangely Consistent

    +

    Musings about programming, Perl 6, and programming Perl 6

    +
    + +
    + +
    +

    List of all posts

    + $body +
    + + diff --git a/upload_blog b/upload_blog new file mode 100755 index 0000000..5777118 --- /dev/null +++ b/upload_blog @@ -0,0 +1,49 @@ +#! /usr/bin/env perl6 +use v6; + +my $SERVER = 'www48.your-server.de'; +#my %months = hash(.kv).invert; + +#given "/tmp/ftp-checkdates".&open(:w) { +# .say("cd public_html/blog"); +# .say("ls"); +# .close; +#} + +#my %needs_update; +#for qqx[ftp -v $SERVER < /tmp/ftp-checkdates].split(/\n/) { +# my @fields = .comb(/\S+/); +# next unless @fields == 9; +# +# my $year = 2010; +# my $month = %months{@fields[5]} + 1; +# my $day = @fields[6]; +# +# @fields[7] ~~ /^ (\d\d) \: (\d\d) $/ +# or die "Unknown information in time field"; +# my ($hour, $minute, $second) = $0, $1, 59; +# my $timezone = 60 * 60; +# +# my $filename = ~@fields[8]; +# next if $filename ~~ /^\./; +# next unless "_site/$filename".IO.e; +# next if DateTime.new(:$year, :$month, :$day, +# :$hour, :$minute, :$second, :$timezone).Instant +# > "_site/$filename".IO.changed; say $filename +# +# ++%needs_update{$filename}; +#} + +given "/tmp/ftp-instructions".&open(:w) { + .say("cd public_html/blog"); + + for dir("_site") -> $filename { +# if %needs_update{$filename} { + .say("pu $filename"); +# } + } + + .close; +} + +run qq[[ cd _site; ftp -v $SERVER < /tmp/ftp-instructions | grep '^150 ' ]];