cleong/sixbeermk

Random haiku generator

dev-main 2023-04-04 20:32 UTC

This package is auto-updated.

Last update: 2024-04-21 20:10:25 UTC


README

Monkey

6bmk is an access control mechanism for Internet discussion boards. It consists of two parts: a random haiku generator and a PowerPoint flyer generator. The haiku serve as a form of one-time code. Only people possessing a strip of paper torn from the flyer can join the group.

Flyer

Strip

This project is inspired by bulletin board systems (BBSes) of yesteryears. Users of such systems generally all live in the same area code. This geographic proximity meant people could easily meet up in the real world. And they did frequently, either at group events or visiting each other's homes. "Like a family" is not an uncommon description when people speak of their BBS experience. It's hope that by imposing a geographic limit on membership, we could recreate the old social dynamic on the Internet.

Installation

Node.js:

npm install 6bmk

PHP

composer require cleong/sixbeermk

Usage - Node.js

Generating haiku

import { generateHaiku, normalizeHaiku } from '6bmk';
import { createHash } from 'crypto';

async function *getAccessHaiku(db, flyerId, locale) {
  // load existing haiku first
  const rows = await db.query(`SELECT text FROM haiku WHERE flyer_id = ?`, [ flyerId ]);
  for (const { text } of rows) {
    yield text;
  }
  // generate new ones if there aren't enough
  for await (const text of generateHaiku({ locale })) {
    // generate hash
    const sha1 = createHash('sha1');
    sha1.update(normalizeHaiku(text));
    const hash = sha1.digest('hex');
    // save to database
    db.query(`INSERT INTO haiku (flyer_id, text, hash) VALUES(?, ?, ?)`, [ flyerId, text, hash ]);
    yield text;
  }
}

generateHaiku returns an async generator. Generally you would save its output to a database so you can verify later that a user has entered a correct haiku. normalizeHaiku removes punctuations, normalizes whitespaces, and converts characters to lowercase. These steps ensure we would get the same hash despite minor differences.

Generating flyer

import { createFlyer } from '6bmk';

async function createDownload(db, flyerId) {
  const [ row ] = await db.query(`SELECT address, instructions, options FROM flyer WHERE id = ?`, [ flyerId ]);
  const { address, instructions, options } = row;
  const { paper, orientation, mode, locale } = JSON.parse(options);
  const haiku = getAccessHaiku(db, flyerId, locale);
  return createFlyer({ paper, orientation, mode, address, instructions, haiku });
}

createFlyer returns a Node Readable Stream. If you're using Fastify, you can simply return the stream in your handler. If you're using Express, you would need to pipe the stream into res. In both cases you should set the appriopriate HTTP headers so the response is handled as a download by the browser.

For a working example, check out the code in examples/fastify or examples/express.

CommonJS

const { createFlyer, generateHaiku } = require('6bmk/cjs');

Usage - PHP

Generating haiku

<?php

use cleong\sixbeermk\HaikuGenerator;

function get_access_haiku($db, $flyer_id, $locale) {
  // load existing haiku first
  $result = $db->query("SELECT text FROM haiku WHERE flyer_id = $flyer_id");
  $rows = $result->fetch_column();
  foreach ($rows as $text) {
    yield $text;
  }
  // generate new ones if there aren't enough
  $options = [ 'locale' => $locale ];
  foreach(HaikuGenerator::generate($options) as $text) {
    // generate hash
    $hash = sha1(HaikuGenerator::normalize($text));
    // save to database
    $stmt = $db->prepare("INSERT INTO haiku (flyer_id, text, hash) VALUES(?, ?, ?)");
    $stmt->bind_param("iss", $flyer_id, $text, $hash);
    $stmt->execute();
    yield $text;
  }
}

HaikuGenerator::generate returns a generator. Generally you would save its output to a database so you can verify later that a user has entered a correct haiku. HaikuGenerator::normalize removes punctuations, normalizes whitespaces, and converts characters to lowercase. These steps ensure we would get the same hash despite minor differences.

For a working example, check out the code in examples/php.

Generating flyer

<?php

use cleong\sixbeermk\FlyerGenerator;

function create_download($db, $flyer_id) {
  $result = $db->query("SELECT address, instructions, options FROM flyer WHERE id = $flyer_id");
  list(
    'address' => $address,
    'instructions' => $instructions,
    'options' => $options,
  ) = $result->fetch_assoc();
  $options = json_decode($options, true);
  $haiku = get_access_haiku($db, $flyer_id, $options['locale']);
  return FlyerGenerator::generate($options + [
    'address' => $address,
    'instructions' => $instructions,
    'haiku' => $haiku,
  ]);
}

FlyerGenerator::generate returns a stream. Use fpassthru to send the file content to the browser. You should set the appriopriate HTTP headers beforehand so that the response is handled as a download.

Number of possible haiku

By default, the small en-US dictionary is used during haiku generation. Its content is as follows:

1-syllable words: 5956
2-syllable words: 12443
3-syllable words: 8549
4-syllable words: 3892
5-syllable words: 1260
6-syllable words: 191
7-syllable words: 15

The number of possible haiku is thus 1.5009341463235493e+64. Run calc-combo.js in the tools folder to see what results from the larger dictionaries.

Acknowledgement

The word lists used by this library come from the Spell Checker Oriented Word Lists database (http://wordlist.aspell.net/).

The CMU Pronouncing Dictionary is used to determine the number of syllable in each word (https://github.com/aparrish/pronouncingjs).