npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

d64

v1.0.0

Published

dominictarr style base64, like base64 but lexiographically sortable

Downloads

117,732

Readme

d64

a copy-pastable, url friendly, ascii embeddable, lexiographicly sortable binary encoding.

Example

var d64  = require('d64')

var buf  = new Buffer([0x01, 0x23, 0x45, 0x67, 0x89, 0xab])
var str  = d64.encode(binary)
var buf2 = d64.decode(string)

Encoding binary as base 64 ascii

There is already a well described base64 encoding [1] but it has some downsides, base 64 encoded are not lexiographically sortable, because the ascii characters do not have the same ordering as they unencoded bytes they encode. Consistent ordering is very useful when building database which needs sorting in an enviroment where a binary key is not possible (for example, in indexeddb or levelup[2] in the browser)

Also, it's simplest if all the characters used do not need to be encoded in common text inputs, such as URLs, or the shell. Finally, some of the non-alphanumeric characters may trigger line breaks in a textarea, which can make the encoded string ambigious.

There are other encodings which have addressed some of these issues, such as hex and base32[1], base58[3]. base16 or base32 expand the message more than necessary, and since base58 does not line up with a whole number of bits, then the implementation is not simple, and requires big integers.

There are also other interesting encodings such as zbase32 [4] or proquints [5] which are optimized for human transmission (recognition and pronouncability).

d64 is optimized for being easy to implement, fast to encode/decode, and that a collection of encoded strings should have the same bytewise ordering as they would unencoded.

the 64 characters, in ascending order, are . (full stop) 0-9 (the digits), A-Z (the capital letters), _ (underscore), a-z (the lowercase letters).

var chars = '.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'

Justification for choice of characters

There are only 62 alphanumeric characters, so we need to pick two more. first, lets find the characters which can be used in URLs without escaping them.

var sensible = '!@#$%^&*(){}?+|_"<>\',-.'
  .split('').sort().map(encodeURIComponent)
  .filter(function (e) { return e.length ==1 })
  .join('')

the non-encoded characters are !'()*-._~

_ is an obvious choice, because it's very nearly always a valid character within a variable name, so it's treated like a aphabetic character in most cases.

It's better not to choose ! and ~, because they are the first and last printable characters, so they are quite useful for delimiting strings while maintaining the sorting properties - for instance strings of d64.

! and ~ are commonly used in levelup[2], and that is one of the target applications for d64.

- causes text areas to line wrap, so that is out.

'*() are all significant in bash.

that leaves just . It feels weird to use . as a value, but all the other choices have been eliminated.

Invalid encoded lengths

d64 does not use any padding at the end, as in base64. (there are no suitable characters left, anyway) the string length mod 4 a d64 string encodes is always 2, 3, or 0. If the length % 4 is 1, that means there is 6 bits overhanging which is invalid.

For characters which overhang the byte array, (i.e. the last character if length % 4 == 2 or 3) the overhanging portion must encode 0 bits.

if length % 4 == 2 then 4 bits overhang, the valid characters are: .FVK if length % 4 == 3 then 2 bits overhang, the valid characters are: .37BFJNRVZcgkosw

var overhang2bits = chars.split('').filter(function (_, i) { return !(i&0xf) }).join('')
// ==> .FVK
var overhang4bits = chars.split('').filter(function (_, i) { return !(i&0x3) }).join('')
// ==> .37BFJNRVZcgkosw

Although everything is for a reason and carefully described, that doesn't mean inventing your own encoding isn't a douchebag thing to do, but hey - everyone else does it!

References

  1. http://www.rfc-base.org/txt/rfc-3548.txt
  2. https://github.com/rvagg/node-levelup
  3. http://search.cpan.org/~miyagawa/Encode-Base58-0.01/lib/Encode/Base58.pm
  4. http://search.cpan.org/~gwyn/Convert-zBase32-0.0201/lib/Convert/zBase32.pm
  5. http://arxiv.org/html/0901.4016

License

MIT