Dates and Calendars

Don't keep all your eggs in one huuuuuuuge basket

Putting all the blog pages into one group makes for a giant list.
I suppose pagelists could do some auto-sorting.
I prefer to keep them separate.
Year and month is a good-enough way of doing it.

To that end, change the ptv_entryurl setting

## create a default page name for my entries, based on today's date.
## create default title
## set default new entry status (installed default is 'draft')
function processBlogsPrePagename($src, $auth){
        global $_POST,$action;
        $today = date("Y-m-d");
        if ($action=='bi_ne') {
                # $_POST['ptv_entryurl']='Blog.'.$today;
               $_POST['ptv_entryurl'] = date('Y-F.l-d');
                $_POST['ptv_entrytitle'] = date("Y.m.d");

TODO: I don't remember where this was documented

Problem: listing them all.

The below wildcards allow for the above format to appear in all blogit lists.

$bi_BlogGroups = 'Blog|20\d\d-.*';

This is both too permissive and too restrictive -- it only allows dates from 2000..2099, and will accept anything after the hyphen.
For my purposes, this is a good-enough approximation. YMMV.


Still doesn't want to show up for the Cookbook:BlogCalendar recipe, since that expects pages to be named in a ISO date-format (eg 2015-07-08, as seen here). Prefixes are allowed, but still expects the format as part of the page name. BlogIt uses other criteria (internal pagetextvars, I believe) to note which pages are blog pages. BlogCal would need some sort of extension to work this way.


This tends to limit you to a single blog-entry per day, AFAIK.

See Also

Blog.2015-05-29 - where I first started talking about changing page names.

NOTE: not yet implemented in this wiki

BlogIt Wish List

I swear I had this somewhere, once.... I have a list @ Cookbook:BlogIt-Talk

  • integrated BlogCalendar
  • working for php 5.5
  • uploads when creating pages
  • preview while editing
  • work nicely with SourceBlock
  • access-keys


More Markdown refinements

Got strong working, possible

## Markdown-ish
## 2015.07.06
## some markdown markup-like markup
## 2016.06.17
## _emphasized_
Markup('mkem', 'inline',

## originally from
## markdown\markdown-inline.php
Markup('mkstrong','<mkem', '/(\*\*|__)(\w.*?)\1/', '<strong>$2</strong>');

$md_nested_brackets_depth = 1; # this fixes some problem, and probably breaks something I don't use/test-for

If you look at the original cookbook recipe Cookbook:Markdown, there is a suite of notes/test-pages included:

  • Markdown.EditQuickReference
  • Markdown.Markdown
  • Markdown.Syntax
  • Markdown.TestFile

issue with anchors

TODO: something (probably markdown-links ) is interfering with having multiple-anchors on a line.


[[#anchor]] [[#anchors]]

[[#anchor]] [[#anchors]] [[#anotherAnchor]]

[[#anchor]] [[#anchors]] [[#anotherAnchor]] [[#fourthAnchor]]

No Spaces: [[#anchor]][[#anchors]][[#anotherAnchor]][[#fourthAnchor]]

No Spaces:

something about odd-numbers?

[[#anchor]] [[#anchors]] [[#anotherAnchor]] [[#fourthAnchor]] [[#fifthAnchor]]

Markdown and Blogit

Markdown code

This works!

Except it renders BlogIt-Admin dead-in-the-water. AAARGH!

It's the strong and emphasized markup -- the markdown-links code has no effect. Hunh.

NOTE: the below code was modified from strong/emphasized markup code inside of creole.php

Which uses a double back-slash // for emphasized, thus the need for checking if it's in a URL.

## some markdown markup-like markup
## 2016.06.17
## **strong**
Markup('**', 'inline',

## _emphasized_
Markup('_', 'inline',

$md_nested_brackets_depth = 1; # allows some link things to work, that are otherwise broken (without changing the original file)

This version works for empahsized:

## some markdown markup-like markup
## 2016.06.17
## _emphasized_
Markup('_', 'inline',

Here's some markup test (see Main/WikiSandbox)

This is a test of **strong** and _emphasized_ text.
Will not work_without_ leading _whitespace_.
_Except_ at the beginning of a line.
**Strong** at the beginning of a line
* Yet still allows
** sub-lists with **strong** elements

This is a test of strong and emphasized text.
Will not work_without_ leading whitespace.
Except at the beginning of a line.
Strong at the beginning of a line

  • Yet still allows
    • sub-lists with strong elements
NOTE: the proposed strong markup has some sort of conflict with BlogIt, and borks editing.
This is a test of **strong** and _emphasized_ text.
Will not work_without_ leading _whitespace_.
_Except_ at the beginning of a line.
**Strong** at the beginning of a line
* Yet still allows
** sub-lists with **strong** elements

This is a test of strong and emphasized text.
Will not work_without_ leading whitespace.
Except at the beginning of a line.
Strong at the beginning of a line

  • Yet still allows
    • sub-lists with strong elements






[here's the sandbox](Main/WikiSandbox)

[here's the sandbox](Main/WikiSandbox)

[here's the sandbox](Main.WikiSandbox)

[here's the sandbox](Main.WikiSandbox)

[here's the sandbox](WikiSandbox)

[here's the sandbox](WikiSandbox)

[here's the sandbox](Main)

[here's the sandbox](Main)

[here's the sandbox](Main.Main)

[here's the sandbox](Main.Main)


The link code is ganked from the markdown extension.
It's the only part of the code that I'm using, and it has been modified.

<?php if (!defined('PmWiki')) exit();
# Markdown  -  A text-to-HTML conversion tool for web writers
# Copyright (c) 2004-2005 John Gruber  
# <>
# Copyright (c) 2004-2005 Michel Fortin - PHP Port  
# <>
# PmWiki Conversion Copyrigh (c) 2006 Benjamin C. Wilson
# <

## NOTE: depth > 1 causes std wiki markup links to break
##       if used w/ std markup (which is my goal)
$md_nested_brackets_depth = 1;
$md_nested_brackets =
    str_repeat('(?>[^\[\]]+|\[', $md_nested_brackets_depth).
    str_repeat('\])*', $md_nested_brackets_depth);

## original
// Markup("MkAn1", '<links',
//   "/(\\[($md_nested_brackets)\\]\\([ \\t]*<?(.*?)>?[ \\t]*((['\"])(.*?)\\5)?\\))/xse",
//   "DoAnchors('

## fiddling
Markup_e("MkAn1", '
  "/(\\[($md_nested_brackets)\\]\\([ \\t]*<?(.*?)>?[ \\t]*((['

Markup("MkAn2",'>fulltext','[','return DoAnchors2($x);');

function DoAnchors2($text) {
    global $md_nested_brackets;
    $text = _StripLinkDefinitions($text);
    $text = preg_replace_callback("{
        (                   # wrap whole match in $1
            ($md_nested_brackets)   # link text = $2

          [ .,\?!;:]?              # one optional space
          (?:\\n[ ]*)?      # one optional newline followed by spaces

            (.*?)       # id = $3
        '_DoAnchors_reference_callback', $text);
    return $text;

function DoAnchors($all,$name,$url,$title=''){
    if ($title != '') {
        $title = trim($title,' \"');
        $title = " title='$title'";
    return Keep("<a href='$url'$title>$name</a>");

function _DoAnchors_inline_callback($matches) {
    global $md_escape_table;
    $whole_match    = $matches[1];
    $link_text      = $matches[2];
    $url            = $matches[3];
    $title          =& $matches[6];

    $result = "<a href=\"$url\"";
    if (isset($title)) {
        $title = str_replace('"', '&quot;', $title);
        #$title = str_replace(array('*', '_'),
                            #array($md_escape_table['*'], $md_escape_table['_']),
       $result .=  " title='$title'";

    $result .= ">$link_text</a>";
    return $result;

# Table of hash values for escaped characters:
$md_escape_table = array(
    "\\" => md5("\\"),
    "`" => md5("`"),
    "*" => md5("*"),
    "_" => md5("_"),
    "{" => md5("{"),
    "}" => md5("}"),
    "[" => md5("["),
    "]" => md5("]"),
    "(" => md5("("),
    ")" => md5(")"),
    ">" => md5(">"),
    "#" => md5("#"),
    "+" => md5("+"),
    "-" => md5("-"),
    "." => md5("."),
    "!" => md5("!")
$md_urls = array();
$md_titles = array();

function _DoAnchors_reference_callback($matches) {
    global $md_urls, $md_titles, $md_escape_table;
    $all = $matches[1];
    $text   = $matches[2];
    $link_id     = strtolower($matches[3]);

    if ($link_id == "") {
        $link_id = strtolower($text); # for shortcut links like [this][].

    if (isset($md_urls[$link_id])) {
        $url = $md_urls[$link_id];
        # We've got to encode these to avoid conflicting with italics/bold.
       $result = "<a href=\"$url\"";
        if ( isset( $md_titles[$link_id] ) ) {
            $title = $md_titles[$link_id];
            $title = str_replace(array('*',     '_'),
                                       $md_escape_table['_']), $title);
            $result .=  " title='$title'";
        $result .= ">$text</a>";
    else {
        $result = $all;
    return Keep($result);
function _StripLinkDefinitions_callback($matches) {
    global $md_urls, $md_titles;
    $link_id = strtolower($matches[1]);
    $md_urls[$link_id] = _EncodeAmpsAndAngles($matches[2]);
    if (isset($matches[3]))
        $md_titles[$link_id] = str_replace('"', '&quot;', $matches[3]);
    return ''; # String that will replace the block
function _EncodeAmpsAndAngles($text) {
# Smart processing for ampersands and angle brackets that need to be encoded.

    # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
   $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
                         '&amp;', $text);;

    # Encode naked <'s
   $text = preg_replace('{<(?![a-z/?\$!])}i', '&lt;', $text);

    return $text;
function _StripLinkDefinitions($text) {
# Strips link definitions from text, stores the URLs and titles in
# hash references.
   global $MarkdownTabWidth;
    $less_than_tab = $MarkdownTabWidth - 1;

    # Link defs are in the form: ^[id]: url "optional title"
   $text = preg_replace_callback('{
                        ^[ ]{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
    return $text;
function _UnescapeSpecialChars($text) {
# Swap back in all the special characters we've hidden.
   global $md_escape_table;
    return str_replace(array_values($md_escape_table),
                       array_keys($md_escape_table), $text);


BlogIt Follies

Sometime in mid-June BlogIt on this installation started throwing errors, with no configuration changes.
Something on the server... but what?

BlogIt is not compatible with PHP 5.5, which I proved multiple times as I tried to convert the markup (some of it converts... more on that later).
Ultimately, I could get it to work by specifying PHP 5.4 and fixing one line of markup

See the below messages for more notes which I will inline

On 2014-12-16 17:33, Mark Lee wrote:

    ERROR: pat=/(\[\[#blogit_(\w[_-\w]*)\]\](?: *\n)?)(.*?)(\[\[#blogit_\2end\]\])/s

Petko: I believe this was fixed in recent BlogIt versions; the part


should probably be written


It is subsequently noted that there has been no updated BlogIt version.

However, applying the above update did fix the problem I had with PHP 5.4


Change $PageTextVarPatterns[''] = '/(\[\[#blogit_(\w[_-\w]*)\]\](?: *\n)?)(.*?)(\[\[#blogit_\2end\]\])/s'; #[1]
to $PageTextVarPatterns[''] = '/(\[\[#blogit_(\w[-_\w]*)\]\](?: *\n)?)(.*?)(\[\[#blogit_\2end\]\])/s'; #[1]

This is line ~143.

Additionally, I found the following markup to work (email thread source):

# original
// Markup('blogit', 'fulltext', '/\(:blogit (list|cleantext)\s?(.*?):\)(.*?)\(:blogitend:\)/esi',
//      "blogitMU_$1(PSS('$2'), PSS('$3'))"
// );

## This is non-working, as it appears in an email
## NotE: the line is chopped off by the email
// Markup_e('blogit', 'fulltext', '/\(:blogit
//  (list|cleantext)\s?(.*?):\)(.*?)\(:blogitend:\)/si',
//         function ($m) {
//             echo("blogit nonsense: ");
//             $func = 'blogitMU_'.$m[1];
//             return $func($m[2], $m[3]);
//         }
//   );

## If you fix the regex to be on a single line, the above will work
## this version has an exterior, non-anonymous function because: REASONS
Markup_e('blogit', 'fulltext', '/\(:blogit (list|cleantext)\s?(.*?):\)(.*?)\(:blogitend:\)/si',

function bimod($m) {
            // echo("blogit nonsense: ");
            // print_r($m);
            $func = 'blogitMU_'.$m[1];
            return $func($m[2], $m[3]);


More psql follies

Change/reset postgresql user password on windows 7
how to reset password

Let's say you have trouble logging in to postgres.

  1. Find your installation, and find the pg_hba.conf file inside of the data folder
  2. Change the Method from md5 to trust
  3. Save the file
  4. update the password
    1. psql -U postgres (or whatever the username name is)
    2. ALTER USER postgres with password 'secure-password';
  5. Change the Method from trust back to md5
  6. RESTART THE SERVICE from services.msc
    1. command-line attempts result in:
λ postgres restart
Execution of PostgreSQL by a user with administrative permissions is not permitted.
The server must be started under an unprivileged user ID to prevent
possible system security compromises. See the documentation for
more information on how to properly start the server.

Now, my password update still failed:

λ psql -U postgres
psql (9.4.1)
WARNING: Console code page (437) differs from Windows code page (1252)
8-bit characters might not work correctly. See psql reference
page "Notes for Windows users" for details.
Type "help" for help.

postgres=# ALTER USER postgres WITH PASSWORD 'password'
postgres-# \q

λ psql -U postgres
Password for user postgres:
psql: FATAL: password authentication failed for user "postgres"
NOTE: I attempted the password update with both single- and double-quotes.

Results the same (auth failure) in both cases.



I don't think I did anything differently... perhaps single-quotes with trailing semi-colon?

postgres=# ALTER USER postgres WITH PASSWORD 'password';
postgres=# \q

after that, reset .conf to use md5, reset the service (all steps I had done before), but this time it worked.

I'm thinking it's the semi-colon.....

NOTE: when I couldn't get the password-change to work, I left .conf at trust and connected in-code without a password:
 pgconn: 'postgres://postgres@localhost:5432/postgres'

BlogIt again

Default dates &c

So, I have been gradually getting annoyed with putting all the blog entries into one giant group called Blog.

For lack of a better solution.

I finally came up with something (not implemented here yet):

$_POST['ptv_entryurl'] = date('Y-F.l-d');

which gives us something like

This means that every month will have its own group.

Now: to figure out how this affects other features (if at all),

Although it most certainly affects the dropdown-menu I want to construct.
Which needed revising, anyway.

PostgreSQL sequencer

I was stuck doing work-work last night, and haven't revisited it. I think it will come together quickly, now that I can work locally.

I need to corral the promises into the correct sequence.
Make it automatically initialize the db-connection and initialize the db with the first entry.
Make the db-name unique (parameter to sequencer).
Provide config settings to sequencer when instantiating (instead of insisting they be in an external file).
Expose next() first() last() count() and currentIndex() methods
It's a sequencer, so should not expose arbitrary jumps.
I don't think we need to re-expose the sequenced, since that was provided externally, anyway.

More Postgres

More work on working on PosrgreSQL locally

Why am I concerned with working locally?
Best practices and all that, yadda yadda yadda.
Although it's easy to set up a new Heroku pg instance, externalizing a dev component is a bit of half-assed job.
Plus, once you're working on a project that is connected to Heroku and has a live DB, you shouldn't be messing with the live data.


I got a local db going with my roughed-up code.
I did find that it needs work.

I have a DBInit call - that should be handled by the call to Next() automagically, if required.
and the DB_INIT_RECORD thing -- currently it doesn't return anything.
In a timer-driven bot that just means we wait until the second iteration.

Who writes this stuff, anyway?

Oh, yeah. I did.
Why didn't I write it better?

Because I wrote what worked. It worked, and I "shipped it" -- put the bot live.

Now I want to do better.

This is the local connection: query.connectionParameters = "postgres://postgres:password@localhost:5432/postgres";
Following the schema of connString = "postgres://username:password@localhost/database";

The following node.js session worked, roughly:

> var sequencer = new (require('./sequencer.js'))

> { console.log(arguments); });
{ state: [Function],
always: [Function],
then: [Function],
promise: [Function],
pipe: [Function],
done: [Function],
fail: [Function],
progress: [Function] }
> { '0': 'QUERY ERROR: error: relation "sequence" does not exist' }

> sequencer.initDB().then(function(status) { console.log(status); });
initializing DB
{ state: [Function],
always: [Function],
then: [Function],
promise: [Function],
pipe: [Function],
done: [Function],
fail: [Function],
progress: [Function] }
> Database initialized
Database initialized

> { console.log(arguments); });
{ state: [Function],
always: [Function],
then: [Function],
promise: [Function],
pipe: [Function],
done: [Function],
fail: [Function],
progress: [Function] }
> DB initialized with first record

> { console.log(arguments); });
{ state: [Function],
always: [Function],
then: [Function],
promise: [Function],
pipe: [Function],
done: [Function],
fail: [Function],
progress: [Function] }
> currentIndex: 0
{ '0': 'first' }

> { console.log(arguments); });
{ state: [Function],
always: [Function],
then: [Function],
promise: [Function],
pipe: [Function],
done: [Function],
fail: [Function],
progress: [Function] }
> currentIndex: 1
{ '0': 'second' }

PostgreSQ: without Heroku

Local Dev time (misc note)

Add psql and other things to the path by executing pg_env.bat
should in the root folder of your PostGreSQL installation (NOT bin)
There was an annoying 'could not find a "psql" to execute' error
Need to remove the double-quotes from the batch file

See Also


Heroku and PostgreSql

Heroku and PostgreSQL


Some links:

I really, really thought I had some samples in node.js, but cannot find back.

To install pgsql locally, use the installer at

To connect to the database when running on my dev machine (NOT on heroku server itself) ?ssl=true needed to be appended to the DATABASE_URL .env variable.
No idea what will happen (yet) if I have that config server-side, as well.

Since connecting to the db is an asynchronous operation, the sequencer component (that uses postgreSQL) will have to use promises, or something.

ETIMEDOUT error from local dev

So, you've updated to use SSL, and you're behind a firewall, and you're getting an error like the following:

DB init error: { [Error: connect ETIMEDOUT] code: 'ETIMEDOUT', errno: 'ETIMEDOUT', syscall: 'connect' }

It's because you're behind a firewall that isn't opening the port you want to use. TOUGH LUCK.

Unfortunately, the best way to get command line access to your Heroku Postgres instance is to have your network admin open up the firewall for the required port. However, if you're willing to consider some other alternatives you could:

  • Use a cloud-friendly admin interface such as JackDB25 to gain access to your db.
  • SSH into a remote shell (VPS, or any machine outside your network) and invoke heroku pg:psql or psql directly from there.


CMDER woes

For whatever reason, working with node.js got weird inside of my CMDER shell replacement recently.
I updated this and that -- can't remember what.
And node could not be found from within the console.
It was on the path -- echo showed me exactly what I expected to see.
Opening up a vanilla windows shell and node worked just fine.
where node worked just fine.
And calling node explicitly with the full path returned from where worked just fine, as well.

I decided to look at the init.bat file that was being executed on CMDER load.
Through trial-and-error, commenting out the following line brought me back to working order:

@set PATH=c:\Program Files (x86)\GnuWin32\bin;%PATH% > nul


UPDATE: yeah, that didn't work quite right. FURTHER testing showed it was the > nul that was causing the problem.

So, to wrap-up: this is what I have now (2015.04.28)

@set PATH=c:\Program Files (x86)\GnuWin32\bin;%PATH%