Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add `Q` encoder/decoder

  • Loading branch information...
commit ad5644a731c756c85045cff09635828c66ff602f 1 parent 3dbc514
@mathiasbynens authored
View
5 q/README.md
@@ -0,0 +1,5 @@
+# [`Q` encoder/decoder](http://mothereff.in/q)
+
+This tool can be used to encode/decode any text using the `Q` encoding. It uses [_q-encoding](http://mths.be/q) under the hood.
+
+Made by [Mathias Bynens](http://mathiasbynens.be/).
View
87 q/eff.css
@@ -0,0 +1,87 @@
+html, textarea {
+ font: 1em/1.6 sans-serif;
+}
+
+body {
+ max-width: 40em;
+ padding: 0 1em;
+}
+
+h1 {
+ text-align: center;
+ font-size: 1.3em;
+ margin: 0 0 .5em;
+ padding-top: 1em;
+}
+
+h2 {
+ font-size: 1em;
+}
+
+a {
+ color: #333;
+ text-decoration: none;
+ border-bottom: 1px solid #aaa;
+ padding: .1em .2em;
+}
+
+a:hover, a:focus {
+ color: #fff;
+ border-color: #036;
+ background: #36c;
+}
+
+textarea {
+ font-family: Monaco, Consolas, monospace;
+}
+
+#footer {
+ margin-top: 2em;
+ text-align: center;
+}
+
+textarea {
+ border: 3px double green;
+ background: #90ee90;
+ width: 100%;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ display: block;
+ margin: 1em 0 .5em;
+ padding: .7em;
+ resize: vertical;
+ min-height: 9.5em;
+}
+
+code {
+ font-family: Monaco, Consolas, monospace;
+ font-size: .9em;
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+.invalid, :invalid {
+ border-color: red;
+ background: #ffb6c1;
+}
+
+@media (min-width: 42em) {
+
+ html {
+ font-size: 1.2em;
+ background: #c4c4c4;
+ height: 100%;
+ }
+
+ body {
+ margin: 0 auto;
+ padding: 0 2em;
+ min-height: 100%;
+ background: #fff;
+ border: solid #aaa;
+ border-width: 0 1px;
+ }
+
+}
View
72 q/eff.js
@@ -0,0 +1,72 @@
+(function(window, document) {
+
+ var textareas = document.getElementsByTagName('textarea');
+ var decoded = textareas[0];
+ var encoded = textareas[1];
+ var permalink = document.getElementById('permalink');
+ // http://mathiasbynens.be/notes/localstorage-pattern
+ var storage = (function() {
+ var uid = new Date;
+ var storage;
+ var result;
+ try {
+ (storage = window.localStorage).setItem(uid, uid);
+ result = storage.getItem(uid) == uid;
+ storage.removeItem(uid);
+ return result && storage;
+ } catch (exception) {}
+ }());
+
+ function encode(string) {
+ // URL-encode some more characters to avoid issues when using permalink URLs in Markdown
+ return encodeURIComponent(string).replace(/['()_*]/g, function(character) {
+ return '%' + character.charCodeAt().toString(16);
+ });
+ }
+
+ function update() {
+ var shouldDecode = this == encoded;
+ var value;
+ if (shouldDecode) {
+ value = utf8.decode(q.decode(encoded.value));
+ decoded.value = value;
+ } else {
+ value = q.encode(utf8.encode(decoded.value));
+ encoded.value = value;
+ }
+ value = decoded.value;
+ permalink.hash = encode(value);
+ storage && (storage.q = value);
+ };
+
+ // http://mathiasbynens.be/notes/oninput
+ decoded.onkeyup = encoded.onkeyup = update;
+ decoded.oninput = encoded.oninput = function() {
+ decoded.onkeyup = encoded.onkeyup = null;
+ update.call(this);
+ };
+
+ if (storage) {
+ storage.q && (decoded.value = storage.q);
+ update();
+ }
+
+ window.onhashchange = function() {
+ decoded.value = decodeURIComponent(location.hash.slice(1));
+ update();
+ };
+
+ if (location.hash) {
+ window.onhashchange();
+ }
+
+}(this, document));
+
+// Google Analytics
+window._gaq = [['_setAccount', 'UA-6065217-60'], ['_trackPageview']];
+(function(d, t) {
+ var g = d.createElement(t),
+ s = d.getElementsByTagName(t)[0];
+ g.src = '//www.google-analytics.com/ga.js';
+ s.parentNode.insertBefore(g, s);
+}(document, 'script'));
View
19 q/index.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang=en>
+<meta charset=utf-8>
+<title>`Q` encoder/decoder</title>
+<meta name=viewport content="width=device-width,initial-scale=1">
+<link rel=stylesheet href=eff.css>
+<meta name=description content="An online, on-the-fly `Q` encoder/decoder.">
+<h1><code>Q</code> encoder/decoder</h1>
+<noscript><strong>To use this tool, please <a href=http://enable-javascript.com/>enable JavaScript</a> and reload the page.</strong></noscript>
+<h2>Decoded:</h2>
+<textarea autofocus>&#xA1;Hola, se&#xF1;or!</textarea>
+<h2>Encoded: (<a href=#%C2%A1Hola%2C%20se%C3%B1or! id=permalink>permalink</a>)</h2>
+<textarea>=C2=A1Hola,_se=C3=B1or!</textarea>
+<h2>About this tool</h2>
+<p>This tool uses <a href=http://mths.be/q><i>q-encoding</i></a> and <a href=http://mths.be/utf8js>utf8.js</a> to do all the encoding/decoding.
+<p id=footer>Made by <a href=http://mathiasbynens.be/>@mathias</a> — <a href=https://github.com/mathiasbynens/mothereff.in/tree/master/q>fork this on GitHub!</a></p>
+<script src=vendor/q.js></script>
+<script src=vendor/utf8.js></script>
+<script src=eff.js></script>
View
88 q/vendor/q.js
@@ -0,0 +1,88 @@
+/*! http://mths.be/q v0.1.1 by @mathias | MIT license */
+;(function(root) {
+
+ // Detect free variables `exports`.
+ var freeExports = typeof exports == 'object' && exports;
+
+ // Detect free variable `module`.
+ var freeModule = typeof module == 'object' && module &&
+ module.exports == freeExports && module;
+
+ // Detect free variable `global`, from Node.js or Browserified code, and use
+ // it as `root`.
+ var freeGlobal = typeof global == 'object' && global;
+ if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
+ root = freeGlobal;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ // http://tools.ietf.org/html/rfc2047#section-4.2
+ var stringFromCharCode = String.fromCharCode;
+ var decode = function(input) {
+ return input
+ // Decode `_` into a space. This is character-encoding-independent;
+ // see http://tools.ietf.org/html/rfc2047#section-4.2, item 2.
+ .replace(/_/g, ' ')
+ // Decode escape sequences of the form `=XX` where `XX` is any
+ // combination of two hexidecimal digits. For optimal compatibility,
+ // lowercase hexadecimal digits are supported as well. See
+ // http://tools.ietf.org/html/rfc2045#section-6.7, note 1.
+ .replace(/=([a-fA-F0-9]{2})/g, function($0, $1) {
+ var codePoint = parseInt($1, 16);
+ return stringFromCharCode(codePoint);
+ });
+ };
+
+ var regexUnsafeSymbols = /[\0-\x1F=\?_\x7F-\uD7FF\uDC00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF]/g;
+ var encode = function(string) {
+ // Note: this assumes the input is already encoded into octets (e.g. using
+ // UTF-8), and that the resulting octets are within the extended ASCII
+ // range.
+ return string
+ // Encode symbols that are definitely unsafe (i.e. unsafe in any context).
+ .replace(regexUnsafeSymbols, function(symbol) {
+ if (symbol > '\xFF') {
+ throw RangeError(
+ '`q.encode()` expects extended ASCII input only. Don\u2019t ' +
+ 'forget to encode the input first using a character encoding ' +
+ 'like UTF-8.'
+ );
+ }
+ var codePoint = symbol.charCodeAt(0);
+ var hexadecimal = codePoint.toString(16).toUpperCase();
+ return '=' + ('0' + hexadecimal).slice(-2);
+ })
+ // Encode spaces as `_`, as it’s shorter than `=20`.
+ .replace(/\x20/g, '_');
+ };
+
+ var q = {
+ 'encode': encode,
+ 'decode': decode,
+ 'version': '0.1.1'
+ };
+
+ // Some AMD build optimizers, like r.js, check for specific condition patterns
+ // like the following:
+ if (
+ typeof define == 'function' &&
+ typeof define.amd == 'object' &&
+ define.amd
+ ) {
+ define(function() {
+ return q;
+ });
+ } else if (freeExports && !freeExports.nodeType) {
+ if (freeModule) { // in Node.js or RingoJS v0.8.0+
+ freeModule.exports = q;
+ } else { // in Narwhal or RingoJS v0.7.0-
+ for (var key in q) {
+ q.hasOwnProperty(key) && (freeExports[key] = q[key]);
+ }
+ }
+ } else { // in Rhino or a web browser
+ root.q = q;
+ }
+
+}(this));
View
10 q/vendor/update.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+cd "$(dirname "${BASH_SOURCE}")"
+
+curl -# "https://raw.githubusercontent.com/mathiasbynens/q-encoding/master/q.js" > q.js
+curl -# "https://raw.githubusercontent.com/mathiasbynens/utf8.js/master/utf8.js" > utf8.js
+
+cat "q.js" "utf8.js" "../eff.js" > "/tmp/q.js"
+echo "Copying concatenated JS to pasteboard..."
+pbcopy < "/tmp/q.js"
View
234 q/vendor/utf8.js
@@ -0,0 +1,234 @@
+/*! http://mths.be/utf8js v2.0.0 by @mathias */
+;(function(root) {
+
+ // Detect free variables `exports`
+ var freeExports = typeof exports == 'object' && exports;
+
+ // Detect free variable `module`
+ var freeModule = typeof module == 'object' && module &&
+ module.exports == freeExports && module;
+
+ // Detect free variable `global`, from Node.js or Browserified code,
+ // and use it as `root`
+ var freeGlobal = typeof global == 'object' && global;
+ if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
+ root = freeGlobal;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ var stringFromCharCode = String.fromCharCode;
+
+ // Taken from http://mths.be/punycode
+ function ucs2decode(string) {
+ var output = [];
+ var counter = 0;
+ var length = string.length;
+ var value;
+ var extra;
+ while (counter < length) {
+ value = string.charCodeAt(counter++);
+ if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+ // high surrogate, and there is a next character
+ extra = string.charCodeAt(counter++);
+ if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+ output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+ } else {
+ // unmatched surrogate; only append this code unit, in case the next
+ // code unit is the high surrogate of a surrogate pair
+ output.push(value);
+ counter--;
+ }
+ } else {
+ output.push(value);
+ }
+ }
+ return output;
+ }
+
+ // Taken from http://mths.be/punycode
+ function ucs2encode(array) {
+ var length = array.length;
+ var index = -1;
+ var value;
+ var output = '';
+ while (++index < length) {
+ value = array[index];
+ if (value > 0xFFFF) {
+ value -= 0x10000;
+ output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+ value = 0xDC00 | value & 0x3FF;
+ }
+ output += stringFromCharCode(value);
+ }
+ return output;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ function createByte(codePoint, shift) {
+ return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
+ }
+
+ function encodeCodePoint(codePoint) {
+ if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
+ return stringFromCharCode(codePoint);
+ }
+ var symbol = '';
+ if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
+ symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
+ }
+ else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
+ symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
+ symbol += createByte(codePoint, 6);
+ }
+ else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
+ symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
+ symbol += createByte(codePoint, 12);
+ symbol += createByte(codePoint, 6);
+ }
+ symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
+ return symbol;
+ }
+
+ function utf8encode(string) {
+ var codePoints = ucs2decode(string);
+ var length = codePoints.length;
+ var index = -1;
+ var codePoint;
+ var byteString = '';
+ while (++index < length) {
+ codePoint = codePoints[index];
+ byteString += encodeCodePoint(codePoint);
+ }
+ return byteString;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ function readContinuationByte() {
+ if (byteIndex >= byteCount) {
+ throw Error('Invalid byte index');
+ }
+
+ var continuationByte = byteArray[byteIndex] & 0xFF;
+ byteIndex++;
+
+ if ((continuationByte & 0xC0) == 0x80) {
+ return continuationByte & 0x3F;
+ }
+
+ // If we end up here, it’s not a continuation byte
+ throw Error('Invalid continuation byte');
+ }
+
+ function decodeSymbol() {
+ var byte1;
+ var byte2;
+ var byte3;
+ var byte4;
+ var codePoint;
+
+ if (byteIndex > byteCount) {
+ throw Error('Invalid byte index');
+ }
+
+ if (byteIndex == byteCount) {
+ return false;
+ }
+
+ // Read first byte
+ byte1 = byteArray[byteIndex] & 0xFF;
+ byteIndex++;
+
+ // 1-byte sequence (no continuation bytes)
+ if ((byte1 & 0x80) == 0) {
+ return byte1;
+ }
+
+ // 2-byte sequence
+ if ((byte1 & 0xE0) == 0xC0) {
+ var byte2 = readContinuationByte();
+ codePoint = ((byte1 & 0x1F) << 6) | byte2;
+ if (codePoint >= 0x80) {
+ return codePoint;
+ } else {
+ throw Error('Invalid continuation byte');
+ }
+ }
+
+ // 3-byte sequence (may include unpaired surrogates)
+ if ((byte1 & 0xF0) == 0xE0) {
+ byte2 = readContinuationByte();
+ byte3 = readContinuationByte();
+ codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
+ if (codePoint >= 0x0800) {
+ return codePoint;
+ } else {
+ throw Error('Invalid continuation byte');
+ }
+ }
+
+ // 4-byte sequence
+ if ((byte1 & 0xF8) == 0xF0) {
+ byte2 = readContinuationByte();
+ byte3 = readContinuationByte();
+ byte4 = readContinuationByte();
+ codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
+ (byte3 << 0x06) | byte4;
+ if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
+ return codePoint;
+ }
+ }
+
+ throw Error('Invalid UTF-8 detected');
+ }
+
+ var byteArray;
+ var byteCount;
+ var byteIndex;
+ function utf8decode(byteString) {
+ byteArray = ucs2decode(byteString);
+ byteCount = byteArray.length;
+ byteIndex = 0;
+ var codePoints = [];
+ var tmp;
+ while ((tmp = decodeSymbol()) !== false) {
+ codePoints.push(tmp);
+ }
+ return ucs2encode(codePoints);
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ var utf8 = {
+ 'version': '2.0.0',
+ 'encode': utf8encode,
+ 'decode': utf8decode
+ };
+
+ // Some AMD build optimizers, like r.js, check for specific condition patterns
+ // like the following:
+ if (
+ typeof define == 'function' &&
+ typeof define.amd == 'object' &&
+ define.amd
+ ) {
+ define(function() {
+ return utf8;
+ });
+ } else if (freeExports && !freeExports.nodeType) {
+ if (freeModule) { // in Node.js or RingoJS v0.8.0+
+ freeModule.exports = utf8;
+ } else { // in Narwhal or RingoJS v0.7.0-
+ var object = {};
+ var hasOwnProperty = object.hasOwnProperty;
+ for (var key in utf8) {
+ hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
+ }
+ }
+ } else { // in Rhino or a web browser
+ root.utf8 = utf8;
+ }
+
+}(this));
Please sign in to comment.
Something went wrong with that request. Please try again.