diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..9ec8f9d
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,2 @@
+((nil . ((indent-tabs-mode . t)
+ (tab-width . 4))))
diff --git a/app.js b/app.js
new file mode 100644
index 0000000..6b67137
--- /dev/null
+++ b/app.js
@@ -0,0 +1,112 @@
+/**
+ * Module dependencies.
+ */
+
+var express = require('express');
+var routes = require('./routes');
+var user = require('./routes/user');
+var http = require('http');
+var path = require('path');
+var fs = require('fs');
+var app = express();
+var websockServer = require('websocket').server;
+
+// all environments
+app.set('port', process.env.PORT || 48813);
+app.set('views', path.join(__dirname, 'views'));
+app.set('view engine', 'hjs');
+app.use(express.favicon());
+app.use(express.logger('dev'));
+app.use(express.json());
+app.use(express.urlencoded());
+app.use(express.methodOverride());
+app.use(app.router);
+app.use(require('stylus').middleware(path.join(__dirname, 'public')));
+app.use(express.static(path.join(__dirname, 'public')));
+
+// development only
+if ('development' == app.get('env')) {
+ app.use(express.errorHandler());
+}
+
+app.get('/', routes.index);
+app.get('/users', user.list);
+
+var web = http.createServer(app).listen(app.get('port'), function(){
+ console.log('Express server listening on port ' + app.get('port'));
+});
+
+// websocks
+var socket = new websockServer({
+ httpServer: web,
+ autoAcceptConnections: false
+});
+
+function originIsAllowed(origin) {
+ console.log(origin);
+ return 'lol';
+}
+
+connections = [];
+
+socket.on('request', function(request) {
+ if (!originIsAllowed(request.origin)) {
+ request.reject();
+ console.log('hello, i rejected' + request.origin);
+ return;
+ }
+
+ var connection = (function() {
+ try {
+ return request.accept('wow', request.origin);
+ } catch (error) {
+ return;
+ }
+ }());
+
+ if (!connection) return;
+ console.log('i accept', request.origin);
+ connections.push(connection);
+ connection.on('close', function() {
+ connections.forEach(function (cached, index) {
+ if (cached == connection) {
+ delete connections[index];
+ }
+ });
+ });
+
+ connection.on('message', function (message) {
+ message = (function() {
+ try {
+ return JSON.parse(message.utf8Data);
+ } catch (error) {
+ return;
+ }
+ }());
+
+ if (!message) return;
+ connections.forEach(function(cached) {
+ cached.send(JSON.stringify(message));
+ });
+
+ fs.readFile('data/icons.json', function (up, buffer) {
+ if (up) throw up;
+ try {
+ var stickers = JSON.parse(buffer.toString());
+
+ stickers.forEach(function (sticker, index) {
+ if (sticker.id == message.id) {
+ stickers[index] = message;
+ }
+ });
+
+ fs.writeFile('data/icons.json', JSON.stringify(stickers), function (error) {
+ if (error) console.error(error);
+ });
+
+ } catch (tantrum) {
+ throw tantrum;
+ }
+ });
+ });
+});
diff --git a/data/icons.json b/data/icons.json
new file mode 100644
index 0000000..4ea3cca
--- /dev/null
+++ b/data/icons.json
@@ -0,0 +1 @@
+[{"id":"🌀","background":"#ffffff","foreground":"#000000"},{"id":"🌁","background":"#ffffff","foreground":"#000000"},{"id":"🌂","background":"#ffffff","foreground":"#000000"},{"id":"🌃","background":"#ffffff","foreground":"#000000"},{"id":"🌄","background":"#ffffff","foreground":"#000000"},{"id":"🌅","background":"#ffffff","foreground":"#000000"},{"id":"🌆","background":"#ffffff","foreground":"#000000"},{"id":"🌇","background":"#ffffff","foreground":"#000000"},{"id":"🌈","background":"#ffffff","foreground":"#000000"},{"id":"🌉","background":"#ffffff","foreground":"#000000"},{"id":"🌊","background":"#ffffff","foreground":"#000000"},{"id":"🌋","background":"#ffffff","foreground":"#000000"},{"id":"🌌","background":"#ffffff","foreground":"#000000"},{"id":"🌏","background":"#ffffff","foreground":"#000000"},{"id":"🌑","background":"#ffffff","foreground":"#000000"},{"id":"🌓","background":"#ffffff","foreground":"#000000"},{"id":"🌔","background":"#ffffff","foreground":"#000000"},{"id":"🌕","background":"#ffffff","foreground":"#000000"},{"id":"🌙","background":"#ffffff","foreground":"#000000"},{"id":"🌛","background":"#ffffff","foreground":"#000000"},{"id":"🌟","background":"#ffffff","foreground":"#000000"},{"id":"🌠","background":"#ffffff","foreground":"#000000"},{"id":"🌰","foreground":"#000000","background":"#f8fefb"},{"id":"🌱","foreground":"#000000","background":"#f4fffc"},{"id":"🌴","background":"#ffffff","foreground":"#000000"},{"id":"🌵","background":"#ffffff","foreground":"#000000"},{"id":"🌷","background":"#ffffff","foreground":"#000000"},{"id":"🌸","background":"#ffffff","foreground":"#000000"},{"id":"🌹","background":"#ffffff","foreground":"#000000"},{"id":"🌺","background":"#ffffff","foreground":"#000000"},{"id":"🌻","background":"#ffffff","foreground":"#000000"},{"id":"🌼","background":"#ffffff","foreground":"#000000"},{"id":"🌽","foreground":"#000000","background":"#ffffff"},{"id":"🌾","background":"#ffffff","foreground":"#000000"},{"id":"🌿","background":"#ffffff","foreground":"#000000"},{"id":"🍀","background":"#ffffff","foreground":"#000000"},{"id":"🍁","background":"#ffffff","foreground":"#000000"},{"id":"🍂","background":"#ffffff","foreground":"#000000"},{"id":"🍃","background":"#ffffff","foreground":"#000000"},{"id":"🍄","background":"#ffffff","foreground":"#000000"},{"id":"🍅","background":"#ffffff","foreground":"#000000"},{"id":"🍆","background":"#ffffff","foreground":"#000000"},{"id":"🍇","background":"#ffffff","foreground":"#000000"},{"id":"🍈","background":"#ffffff","foreground":"#000000"},{"id":"🍉","background":"#ffffff","foreground":"#000000"},{"id":"🍊","background":"#ffffff","foreground":"#000000"},{"id":"🍌","background":"#ffffff","foreground":"#000000"},{"id":"🍍","background":"#ffffff","foreground":"#000000"},{"id":"🍎","background":"#ffffff","foreground":"#000000"},{"id":"🍏","background":"#ffffff","foreground":"#000000"},{"id":"🍑","background":"#ffffff","foreground":"#000000"},{"id":"🍒","background":"#ffffff","foreground":"#000000"},{"id":"🍓","background":"#ffffff","foreground":"#000000"},{"id":"🍔","background":"#ffffff","foreground":"#000000"},{"id":"🍕","background":"#ffffff","foreground":"#000000"},{"id":"🍖","background":"#ffffff","foreground":"#000000"},{"id":"🍗","background":"#ffffff","foreground":"#000000"},{"id":"🍘","background":"#ffffff","foreground":"#000000"},{"id":"🍙","background":"#ffffff","foreground":"#000000"},{"id":"🍚","background":"#ffffff","foreground":"#000000"},{"id":"🍛","background":"#ffffff","foreground":"#000000"},{"id":"🍜","background":"#ffffff","foreground":"#000000"},{"id":"🍝","background":"#ffffff","foreground":"#000000"},{"id":"🍞","background":"#ffffff","foreground":"#000000"},{"id":"🍟","background":"#ffffff","foreground":"#000000"},{"id":"🍠","background":"#ffffff","foreground":"#000000"},{"id":"🍡","background":"#ffffff","foreground":"#000000"},{"id":"🍢","background":"#ffffff","foreground":"#000000"},{"id":"🍣","background":"#ffffff","foreground":"#000000"},{"id":"🍤","background":"#ffffff","foreground":"#000000"},{"id":"🍥","background":"#ffffff","foreground":"#000000"},{"id":"🍦","background":"#ffffff","foreground":"#000000"},{"id":"🍧","background":"#ffffff","foreground":"#000000"},{"id":"🍨","background":"#ffffff","foreground":"#000000"},{"id":"🍩","background":"#ffffff","foreground":"#000000"},{"id":"🍪","background":"#ffffff","foreground":"#000000"},{"id":"🍫","background":"#ffffff","foreground":"#000000"},{"id":"🍬","background":"#ffffff","foreground":"#000000"},{"id":"🍭","background":"#ffffff","foreground":"#000000"},{"id":"🍮","background":"#ffffff","foreground":"#000000"},{"id":"🍯","background":"#ffffff","foreground":"#000000"},{"id":"🍰","background":"#ffffff","foreground":"#000000"},{"id":"🍱","background":"#ffffff","foreground":"#000000"},{"id":"🍲","background":"#ffffff","foreground":"#000000"},{"id":"🍳","background":"#ffffff","foreground":"#000000"},{"id":"🍴","background":"#ffffff","foreground":"#000000"},{"id":"🍵","background":"#ffffff","foreground":"#000000"},{"id":"🍶","background":"#ffffff","foreground":"#000000"},{"id":"🍷","background":"#ffffff","foreground":"#000000"},{"id":"🍸","background":"#ffffff","foreground":"#000000"},{"id":"🍹","background":"#ffffff","foreground":"#000000"},{"id":"🍺","background":"#ffffff","foreground":"#000000"},{"id":"🍻","background":"#ffffff","foreground":"#000000"},{"id":"🎀","background":"#ffffff","foreground":"#000000"},{"id":"🎁","background":"#ffffff","foreground":"#000000"},{"id":"🎂","background":"#ffffff","foreground":"#000000"},{"id":"🎃","background":"#ffffff","foreground":"#000000"},{"id":"🎄","background":"#ffffff","foreground":"#000000"},{"id":"🎅","background":"#ffffff","foreground":"#000000"},{"id":"🎆","background":"#ffffff","foreground":"#000000"},{"id":"🎇","background":"#ffffff","foreground":"#000000"},{"id":"🎈","background":"#ffffff","foreground":"#000000"},{"id":"🎉","background":"#ffffff","foreground":"#000000"},{"id":"🎊","background":"#ffffff","foreground":"#000000"},{"id":"🎋","background":"#ffffff","foreground":"#000000"},{"id":"🎌","background":"#ffffff","foreground":"#000000"},{"id":"🎍","background":"#ffffff","foreground":"#000000"},{"id":"🎎","background":"#ffffff","foreground":"#000000"},{"id":"🎏","background":"#ffffff","foreground":"#000000"},{"id":"🎐","background":"#ffffff","foreground":"#000000"},{"id":"🎑","background":"#ffffff","foreground":"#000000"},{"id":"🎒","background":"#ffffff","foreground":"#000000"},{"id":"🎓","background":"#ffffff","foreground":"#000000"},{"id":"🎠","background":"#ffffff","foreground":"#000000"},{"id":"🎡","background":"#ffffff","foreground":"#000000"},{"id":"🎢","background":"#ffffff","foreground":"#000000"},{"id":"🎣","background":"#ffffff","foreground":"#000000"},{"id":"🎤","background":"#ffffff","foreground":"#000000"},{"id":"🎥","background":"#ffffff","foreground":"#000000"},{"id":"🎦","background":"#ffffff","foreground":"#000000"},{"id":"🎧","background":"#ffffff","foreground":"#000000"},{"id":"🎨","background":"#ffffff","foreground":"#000000"},{"id":"🎩","background":"#ffffff","foreground":"#000000"},{"id":"🎪","background":"#ffffff","foreground":"#000000"},{"id":"🎫","background":"#ffffff","foreground":"#000000"},{"id":"🎬","background":"#ffffff","foreground":"#000000"},{"id":"🎭","background":"#ffffff","foreground":"#000000"},{"id":"🎮","background":"#ffffff","foreground":"#000000"},{"id":"🎯","background":"#ffffff","foreground":"#000000"},{"id":"🎰","background":"#ffffff","foreground":"#000000"},{"id":"🎱","background":"#ffffff","foreground":"#000000"},{"id":"🎲","background":"#ffffff","foreground":"#000000"},{"id":"🎳","background":"#ffffff","foreground":"#000000"},{"id":"🎴","background":"#ffffff","foreground":"#000000"},{"id":"🎵","background":"#ffffff","foreground":"#000000"},{"id":"🎶","background":"#ffffff","foreground":"#000000"},{"id":"🎷","background":"#ffffff","foreground":"#000000"},{"id":"🎸","background":"#ffffff","foreground":"#000000"},{"id":"🎹","background":"#ffffff","foreground":"#000000"},{"id":"🎺","background":"#ffffff","foreground":"#000000"},{"id":"🎻","background":"#ffffff","foreground":"#000000"},{"id":"🎼","background":"#ffffff","foreground":"#000000"},{"id":"🎽","background":"#ffffff","foreground":"#000000"},{"id":"🎾","background":"#ffffff","foreground":"#000000"},{"id":"🎿","background":"#ffffff","foreground":"#000000"},{"id":"🏀","background":"#ffffff","foreground":"#000000"},{"id":"🏁","background":"#ffffff","foreground":"#000000"},{"id":"🏂","background":"#ffffff","foreground":"#000000"},{"id":"🏃","background":"#ffffff","foreground":"#000000"},{"id":"🏄","background":"#ffffff","foreground":"#000000"},{"id":"🏆","background":"#ffffff","foreground":"#000000"},{"id":"🏈","background":"#ffffff","foreground":"#000000"},{"id":"🏊","background":"#ffffff","foreground":"#000000"},{"id":"🏠","background":"#ffffff","foreground":"#000000"},{"id":"🏡","background":"#ffffff","foreground":"#000000"},{"id":"🏢","background":"#ffffff","foreground":"#000000"},{"id":"🏣","background":"#ffffff","foreground":"#000000"},{"id":"🏥","background":"#ffffff","foreground":"#000000"},{"id":"🏦","background":"#ffffff","foreground":"#000000"},{"id":"🏧","background":"#ffffff","foreground":"#000000"},{"id":"🏨","background":"#ffffff","foreground":"#000000"},{"id":"🏩","background":"#ffffff","foreground":"#000000"},{"id":"🏪","background":"#ffffff","foreground":"#000000"},{"id":"🏫","background":"#ffffff","foreground":"#000000"},{"id":"🏬","background":"#ffffff","foreground":"#000000"},{"id":"🏭","background":"#ffffff","foreground":"#000000"},{"id":"🏮","background":"#ffffff","foreground":"#000000"},{"id":"🏯","background":"#ffffff","foreground":"#000000"},{"id":"🍯","background":"#ffffff","foreground":"#000000"},{"id":"👯","background":"#ffffff","foreground":"#000000"},{"id":"💏","background":"#ffffff","foreground":"#000000"}]
\ No newline at end of file
diff --git a/package.json b/package.json
index cfab1e0..967b026 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,14 @@
{
- "name": "stickers",
- "description": "just some good clean fun",
- "version": "0.0.0",
- "private": true,
- "dependencies": {
- "express": "3.4.4"
- }
+ "name": "application-name",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node app.js"
+ },
+ "dependencies": {
+ "express": "3.4.4",
+ "hjs": "*",
+ "stylus": "*",
+ "websocket": "~1.0.8"
+ }
}
diff --git a/public/components/icon_editor.hjs b/public/components/icon_editor.hjs
new file mode 100644
index 0000000..1bc14e7
--- /dev/null
+++ b/public/components/icon_editor.hjs
@@ -0,0 +1,12 @@
+
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..e69de29
diff --git a/public/javascripts/hogan.js b/public/javascripts/hogan.js
new file mode 100644
index 0000000..09170d6
--- /dev/null
+++ b/public/javascripts/hogan.js
@@ -0,0 +1,500 @@
+/*
+ * Copyright 2011 Twitter, Inc.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var HoganTemplate = (function () {
+
+ function constructor(text) {
+ this.text = text;
+ };
+
+ constructor.prototype = {
+ // render: replaced by generated code.
+ r: function (context, partials) { return ''; },
+
+ // variable escaping
+ v: hoganEscape,
+
+ render: function render(context, partials) {
+ return this.r(context, partials);
+ },
+
+ // tries to find a partial in the curent scope and render it
+ rp: function(name, context, partials, indent) {
+ var partial = partials[name];
+
+ if (!partial) {
+ return '';
+ }
+
+ return partial.render(context, partials);
+ },
+
+ // render a section
+ rs: function(context, partials, section) {
+ var buf = '';
+ var tail = context[context.length - 1];
+ if (!isArray(tail)) {
+ buf = section(context, partials);
+ return buf;
+ }
+
+ for (var i = 0; i < tail.length; i++) {
+ context.push(tail[i]);
+ buf += section(context, partials);
+ context.pop();
+ }
+ return buf;
+ },
+
+ // maybe start a section
+ s: function(val, ctx, partials, inverted, start, end) {
+ if (isArray(val) && val.length === 0) {
+ return false;
+ }
+
+ if (!inverted && typeof val == 'function') {
+ val = this.ls(val, ctx, partials, start, end);
+ }
+
+ var pass = (val === '') || !!val;
+
+ if (!inverted && pass && ctx) {
+ ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]);
+ }
+
+ return pass;
+ },
+
+ // find values with dotted names
+ d: function(key, ctx, partials, returnFound) {
+ if (key === '.' && isArray(ctx[ctx.length - 2])) {
+ return ctx[ctx.length - 1];
+ }
+
+ var names = key.split('.');
+ var val = this.f(names[0], ctx, partials, returnFound);
+ var cx = null;
+ for (var i = 1; i < names.length; i++) {
+ if (val && typeof val == 'object' && names[i] in val) {
+ cx = val;
+ val = val[names[i]];
+ } else {
+ val = '';
+ }
+ }
+
+ if (returnFound && !val) {
+ return false;
+ }
+
+ if (!returnFound && typeof val == 'function') {
+ ctx.push(cx);
+ val = this.lv(val, ctx, partials);
+ ctx.pop();
+ }
+
+ return val;
+ },
+
+ // find values with normal names
+ f: function(key, ctx, partials, returnFound) {
+ var val = false;
+ var v = null;
+ var found = false;
+
+ for (var i = ctx.length - 1; i >= 0; i--) {
+ v = ctx[i];
+ if (v && typeof v == 'object' && key in v) {
+ val = v[key];
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ return (returnFound) ? false : "";
+ }
+
+ if (!returnFound && typeof val == 'function') {
+ val = this.lv(val, ctx, partials);
+ }
+
+ return val;
+ },
+
+ // higher order templates
+ ho: function(val, cx, partials, text) {
+ var t = val.call(cx, text, function(t) {
+ return Hogan.compile(t).render(cx);
+ });
+ var s = Hogan.compile(t.toString()).render(cx, partials);
+ this.b = s;
+ return false;
+ },
+
+ // higher order template result buffer
+ b: '',
+
+ // lambda replace section
+ ls: function(val, ctx, partials, start, end) {
+ var cx = ctx[ctx.length - 1];
+ if (val.length > 0) {
+ return this.ho(val, cx, partials, this.text.substring(start, end));
+ }
+ var t = val.call(cx);
+ if (typeof t == 'function') {
+ return this.ho(t, cx, partials, this.text.substring(start, end));
+ }
+ return t;
+ },
+
+ // lambda replace variable
+ lv: function(val, ctx, partials) {
+ var cx = ctx[ctx.length - 1];
+ return Hogan.compile(val.call(cx).toString()).render(cx, partials);
+ }
+ };
+
+ var rAmp = /&/g, rLt = //g, rApos =/\'/g,
+ rQuot = /\"/g, hChars =/[&<>\"\']/;
+ function hoganEscape(str) {
+ var s = String(str === null ? '' : str);
+ return hChars.test(s) ? s.replace(rAmp,'&')
+ .replace(rLt,'<').replace(rGt,'>')
+ .replace(rApos,''').replace(rQuot, '"') : s;
+ }
+
+ var isArray = Array.isArray || function(a) {
+ return Object.prototype.toString.call(a) === '[object Array]';
+ }
+
+ return constructor;
+})();
+
+var Hogan = (function () {
+
+ function scan(text) {
+ var len = text.length,
+ IN_TEXT = 0,
+ IN_TAG_TYPE = 1,
+ IN_TAG = 2,
+ state = IN_TEXT,
+ tagType = null,
+ buf = '',
+ tokens = [],
+ seenTag = false,
+ i = 0,
+ lineStart = 0,
+ otag = '{{',
+ ctag = '}}';
+
+ function addBuf() {
+ if (buf.length > 0) {
+ tokens.push(new String(buf));
+ buf = '';
+ }
+ }
+
+ function lineIsWhitespace() {
+ var isAllWhitespace = true;
+ for (var j = lineStart; j < tokens.length; j++) {
+ isAllWhitespace =
+ (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) ||
+ (!tokens[j].tag && tokens[j].match(rIsWhitespace) == null);
+ if (!isAllWhitespace) {
+ return false;
+ }
+ }
+
+ return isAllWhitespace;
+ }
+
+ function filterLine(haveSeenTag, noNewLine) {
+ addBuf();
+ if (haveSeenTag && lineIsWhitespace()) {
+ for (var j = lineStart; j < tokens.length; j++) {
+ if (!tokens[j].tag) {
+ tokens.splice(j, 1);
+ }
+ }
+ } else if (!noNewLine) {
+ tokens.push({tag:'\n'})
+ }
+
+ seenTag = false;
+ lineStart = tokens.length;
+ }
+
+ function changeDelimiters(text, index) {
+ var close = '=' + ctag;
+ var closeIndex = text.indexOf(close, index);
+ var delimiters = trim(text.substring(text.indexOf('=', index) + 1,
+ closeIndex)).split(' ');
+ otag = delimiters[0];
+ ctag = delimiters[1];
+ return closeIndex + close.length - 1;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (state == IN_TEXT) {
+ if (tagChange(otag, text, i)) {
+ --i;
+ addBuf();
+ state = IN_TAG_TYPE;
+ } else {
+ if (text[i] == '\n') {
+ filterLine(seenTag);
+ } else {
+ buf += text[i];
+ }
+ }
+ } else if (state == IN_TAG_TYPE) {
+ i += otag.length - 1;
+ var tag = tagTypes[text[i + 1]];
+ tagType = tag ? text[i + 1] : '_v';
+ seenTag = i;
+ if (tagType == '=') {
+ i = changeDelimiters(text, i);
+ state = IN_TEXT;
+ } else {
+ if (tag) {
+ i++;
+ }
+ state = IN_TAG;
+ }
+ } else {
+ if (tagChange(ctag, text, i)) {
+ i += ctag.length - 1;
+ tokens.push({tag: tagType, n: trim(buf),
+ i: (tagType == '/') ? seenTag - 1 : i + 1});
+ buf = '';
+ state = IN_TEXT;
+ if (tagType == '{') {
+ i++;
+ }
+ } else {
+ buf += text[i];
+ }
+ }
+ }
+
+ filterLine(seenTag, true);
+
+ return tokens;
+ }
+
+ function trim(s) {
+ if (s.trim) {
+ return s.trim();
+ }
+
+ return s.replace(/^\s*|\s*$/g, '');
+ }
+
+ // remove whitespace according to Mustache spec
+ var rIsWhitespace = /\S/;
+
+ var tagTypes = {
+ '#': 1, '^': 2, '/': 3, '!': 4, '>': 5,
+ '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10
+ };
+
+ function tagChange(tag, text, index) {
+ if (text[index] != tag[0]) {
+ return false;
+ }
+
+ for (var i = 1, l = tag.length; i < l; i++) {
+ if (text[index + i] != tag[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ function buildTree(tokens, kind, stack, customTags) {
+ var instructions = [],
+ opener = null,
+ token = null;
+
+ while (tokens.length > 0) {
+ token = tokens.shift();
+ if (token.tag == '#' || token.tag == '^' ||
+ isOpener(token, customTags)) {
+ stack.push(token);
+ token.nodes = buildTree(tokens, token.tag, stack, customTags);
+ instructions.push(token);
+ } else if (token.tag == '/') {
+ if (stack.length == 0) {
+ throw new Error('Closing tag without opener: /' + token.n);
+ }
+ opener = stack.pop();
+ if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) {
+ throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n);
+ }
+ opener.end = token.i;
+ return instructions;
+ } else {
+ instructions.push(token);
+ }
+ }
+
+ if (stack.length > 0) {
+ throw new Error('missing closing tag: ' + stack.pop().n);
+ }
+
+ return instructions;
+ }
+
+ function isOpener(token, tags) {
+ for (var i = 0, l = tags.length; i < l; i++) {
+ if (tags[i].o == token.n) {
+ token.tag = '#';
+ return true;
+ }
+ }
+ }
+
+ function isCloser(close, open, tags) {
+ for (var i = 0, l = tags.length; i < l; i++) {
+ if (tags[i].c == close && tags[i].o == open) {
+ return true;
+ }
+ }
+ }
+
+ function generate(tree, text, options) {
+ var code = 'var c = [cx];var b = "";var _ = this;' +
+ walk(tree) + 'return b;';
+ if (options.asString) {
+ return 'function(cx,p){' + code + ';};';
+ }
+
+ var template = new HoganTemplate(text);
+ template.r = new Function('cx', 'p', code);
+ return template;
+ }
+
+ var rQuot = /\"/g, rNewline = /\n/g, rCr = /\r/g, rSlash = /\\/g;
+ function esc(s) {
+ return s.replace(rSlash, '\\\\')
+ .replace(rQuot, '\\\"')
+ .replace(rNewline, '\\n')
+ .replace(rCr, '\\r')
+ };
+
+ function chooseMethod(s) {
+ return (~s.indexOf('.')) ? 'd' : 'f';
+ }
+
+ function walk(tree) {
+ var code = '';
+ for (var i = 0, l = tree.length; i < l; i++) {
+ var tag = tree[i].tag;
+ if (tag == '#') {
+ code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n),
+ tree[i].i, tree[i].end);
+ } else if (tag == '^') {
+ code += invertedSection(tree[i].nodes, tree[i].n,
+ chooseMethod(tree[i].n));
+ } else if (tag == '<' || tag == '>') {
+ code += partial(tree[i].n);
+ } else if (tag == '{' || tag == '&') {
+ code += tripleStache(tree[i].n, chooseMethod(tree[i].n));
+ } else if (tag == '\n') {
+ code += text('\n');
+ } else if (tag == '_v') {
+ code += variable(tree[i].n, chooseMethod(tree[i].n));
+ } else if (tag === undefined) {
+ code += text(tree[i]);
+ }
+ }
+ return code;
+ }
+
+ function section(nodes, id, method, start, end) {
+ var code = 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),';
+ code += 'c,p,0,' + start + ',' + end + ')){';
+ code += 'b += _.rs(c,p,';
+ code += 'function(c,p){ var b = "";';
+ code += walk(nodes);
+ code += 'return b;});c.pop();}';
+ code += 'else{b += _.b; _.b = ""};';
+ return code;
+ }
+
+ function invertedSection(nodes, id, method) {
+ var code = 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0)){';
+ code += walk(nodes);
+ code += '};';
+ return code;
+ }
+
+ function partial(id) {
+ return 'b += _.rp("' + esc(id) + '",c[c.length - 1],p);';
+ }
+
+ function tripleStache(id, method) {
+ return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));';
+ }
+
+ function variable(id, method) {
+ return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));';
+ }
+
+ function text(id) {
+ return 'b += "' + esc(id) + '";';
+ }
+
+ return ({
+ scan: scan,
+
+ parse: function(tokens, options) {
+ options = options || {};
+ return buildTree(tokens, '', [], options.sectionTags || []);
+ },
+
+ cache: {},
+
+ compile: function(text, options) {
+ // options
+ //
+ // asString: false (default)
+ //
+ // sectionTags: [{o: '_foo', c: 'foo'}]
+ // An array of object with o and c fields that indicate names for custom
+ // section tags. The example above allows parsing of {{_foo}}{{/foo}}.
+ //
+ options = options || {};
+
+ var t = this.cache[text];
+ if (t) {
+ return t;
+ }
+ t = generate(this.parse(scan(text), options), text, options);
+ return this.cache[text] = t;
+ }
+ });
+})();
+
+// Export the hogan constructor for Node.js and CommonJS.
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = Hogan;
+ module.exports.Template = HoganTemplate;
+} else if (typeof exports !== 'undefined') {
+ exports.Hogan = Hogan;
+ exports.HoganTemplate = HoganTemplate;
+}
\ No newline at end of file
diff --git a/public/javascripts/javascript.js b/public/javascripts/javascript.js
new file mode 100644
index 0000000..a02b0f0
--- /dev/null
+++ b/public/javascripts/javascript.js
@@ -0,0 +1,96 @@
+;(function () {
+ var stickersContainer = document.getElementById('stickers');
+ var stickers = stickersContainer.querySelectorAll('.js-sticker');
+ var stickerEditor = document.getElementById('sticker-editor');
+ var foregroundInput = stickerEditor.querySelector('.js-color--foreground');
+ var backgroundInput = stickerEditor.querySelector('.js-color--background');
+ var editorSticker = stickerEditor.querySelector('.js-sticker');
+ var sock = new WebSocket('ws://' + location.host, 'wow');
+
+ window.addEventListener('click', function (event) {
+ var sticker = event.target;
+ if (!sticker.classList.contains('sticker')) return;
+ setEditorSticker({
+ foreground: hex(sticker.style.color),
+ background: hex(sticker.style.background),
+ id: sticker.innerText
+ });
+ showStickerEditor();
+ });
+
+ function colorInputChange () {
+ var sticker = document.getElementById(editorSticker.innerText);
+ sticker.style.color = editorSticker.style.color = hex(foregroundInput.value);
+ sticker.style.background = editorSticker.style.background = hex(backgroundInput.value);
+ if (sock && sock.readyState == 1) {
+ sock.send(JSON.stringify({
+ id: editorSticker.innerText,
+ foreground: hex(editorSticker.style.color),
+ background: hex(editorSticker.style.background)
+ }));
+ } else {
+ alert('sock is broke, plz refresh or connect to internet or something');
+ }
+ }
+
+ function decToHex (number) {
+ var hex = (+number).toString(16);
+ if (hex.length == 1) return '0' + hex;
+ return hex;
+ }
+
+ function hex(color) {
+ if (~color.indexOf('#')) return color;
+ var colors = color.replace(/[rgb() ]/g, '').split(',');
+ return '#' + decToHex(colors [0]) + decToHex(colors [1]) + decToHex(colors [2]);
+ }
+
+ function setEditorSticker (details) {
+ foregroundInput.value = editorSticker.style.color = hex(details.foreground);
+ backgroundInput.value = editorSticker.style.background = hex(details.background);
+ editorSticker.innerText = details.id;
+ editorSticker.id = 'editor-' + details.id;
+ }
+
+ function hideStickerEditor () {
+ stickerEditor.classList.remove('is-shown');
+ }
+
+ function showStickerEditor () {
+ stickerEditor.classList.add('is-shown');
+ }
+
+ foregroundInput.addEventListener('change', colorInputChange);
+ backgroundInput.addEventListener('change', colorInputChange);
+
+ stickerEditor.querySelector('.js-close').addEventListener('click', hideStickerEditor);
+ window.addEventListener('keydown', function (event) {
+ event.which == 27 && hideStickerEditor();
+ });
+
+ sock.addEventListener('message', function (message) {
+ message = (function() {
+ try {
+ return JSON.parse(message.data);
+ } catch (error) {
+ return;
+ }
+ })();
+
+ if (!message) return;
+
+ var sticker = document.getElementById(message.id);
+ var editorSticker = document.getElementById('editor' + message.id);
+
+ if (sticker) {
+ sticker.style.color = message.foreground;
+ sticker.style.background = message.background;
+ }
+
+ if (editorSticker) {
+ editorSticker.style.color = message.foreground;
+ editorticker.style.background = message.background;
+ }
+ });
+
+})();
diff --git a/public/javascripts/main.js b/public/javascripts/main.js
new file mode 100644
index 0000000..d7598d4
--- /dev/null
+++ b/public/javascripts/main.js
@@ -0,0 +1,20 @@
+(function(){
+ function toggleClass (element, className) {
+ if (element.classList.contains(className)) {
+ element.classList.remove(className)
+ } else {
+ element.classList.add(className)
+ }
+ }
+
+ window.addEventListener('click', function (event) {
+ var element = event.target;
+ var focused = document.querySelector('.focus')
+ if (focused) {
+ focused.classList.remove('focus')
+ }
+ if (element.tagName == 'I') {
+ toggleClass(element, 'focus')
+ }
+ })
+})
diff --git a/public/old.html b/public/old.html
new file mode 100644
index 0000000..8c4c17a
--- /dev/null
+++ b/public/old.html
@@ -0,0 +1,230 @@
+
+
+
+
+
+🌀
+🌁
+🌂
+🌃
+🌄
+🌅
+🌆
+🌇
+🌈
+🌉
+🌊
+🌋
+🌌
+🌏
+🌑
+🌓
+🌔
+🌕
+🌙
+🌛
+🌟
+🌠
+🌰
+🌱
+🌴
+🌵
+🌷
+🌸
+🌹
+🌺
+🌻
+🌼
+🌽
+🌾
+🌿
+🍀
+🍁
+🍂
+🍃
+🍄
+🍅
+🍆
+🍇
+🍈
+🍉
+🍊
+🍌
+🍍
+🍎
+🍏
+🍑
+🍒
+🍓
+🍔
+🍕
+🍖
+🍗
+🍘
+🍙
+🍚
+🍛
+🍜
+🍝
+🍞
+🍟
+🍠
+🍡
+🍢
+🍣
+🍤
+🍥
+🍦
+🍧
+🍨
+🍩
+🍪
+🍫
+🍬
+🍭
+🍮
+🍯
+🍰
+🍱
+🍲
+🍳
+🍴
+🍵
+🍶
+🍷
+🍸
+🍹
+🍺
+🍻
+🎀
+🎁
+🎂
+🎃
+🎄
+🎅
+🎆
+🎇
+🎈
+🎉
+🎊
+🎋
+🎌
+🎍
+🎎
+🎏
+🎐
+🎑
+🎒
+🎓
+🎠
+🎡
+🎢
+🎣
+🎤
+🎥
+🎦
+🎧
+🎨
+🎩
+🎪
+🎫
+🎬
+🎭
+🎮
+🎯
+🎰
+🎱
+🎲
+🎳
+🎴
+🎵
+🎶
+🎷
+🎸
+🎹
+🎺
+🎻
+🎼
+🎽
+🎾
+🎿
+🏀
+🏁
+🏂
+🏃
+🏄
+🏆
+🏈
+🏊
+🏠
+🏡
+🏢
+🏣
+🏥
+🏦
+🏧
+🏨
+🏩
+🏪
+🏫
+🏬
+🏭
+🏮
+🏯
+🍯
+👯
+💏
diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css
new file mode 100644
index 0000000..dc1b5ad
--- /dev/null
+++ b/public/stylesheets/style.css
@@ -0,0 +1,88 @@
+body {
+ margin: auto;
+ background: #f7f7f7;
+ color: #333;
+ width: 90%;
+ text-align: center;
+}
+.sticker {
+ font-style: normal;
+ font-family: Android Emoji, Symbola, Apple Color Emoji;
+}
+.stickers__sticker {
+ font-size: 4em;
+ line-height: 1.2;
+ margin: 0.1em 0;
+ padding: 0;
+ border-radius: 15em;
+ border: 1px solid rgba(0,0,0,0.1);
+ display: inline-block;
+ cursor: pointer;
+}
+.modal-panel {
+ position: fixed;
+ top: 30%;
+ left: 25%;
+ width: 50%;
+ height: 50%;
+ background: #fff;
+ border: 1px solid #ccc;
+ border-bottom: 5px solid #acf;
+ box-shadow: 2px 2px 2px rgba(0,0,0,0.2);
+ transition: opacity 0.7s ease, top 0.5s ease-in-out;
+ opacity: 0;
+ pointer-events: none;
+}
+.modal-panel.is-shown {
+ top: 25%;
+ opacity: 1;
+ pointer-events: all;
+}
+.modal-panel__close {
+ position: absolute;
+ top: 0;
+ right: 0;
+ font-size: 1em;
+ width: 1.5em;
+ height: 1.5em;
+ line-height: 1.5em;
+ background: #c99;
+ border: #a77;
+ font-style: normal;
+ color: #fee;
+ cursor: pointer;
+}
+.modal-panel__close:before {
+ content: "✖";
+}
+.sticker-editor__pane {
+ display: inline-table;
+ vertical-align: top;
+ width: 40%;
+ white-space: normal;
+}
+.sticker-editor__content {
+ width: 90%;
+ margin: 2em 0;
+ white-space: nowrap;
+}
+.sticker-editor__row {
+ display: table-row;
+ line-height: 2em;
+}
+.sticker-editor__h3 {
+ font-family: roboto, helvetica neue;
+ font-weight: 100;
+ color: #666;
+ text-align: left;
+ display: table-cell;
+ width: 0;
+}
+.sticker-editor__color {
+ display: table-cell;
+ width: 100%;
+}
+.sticker-editor__sticker {
+ font-size: 10em;
+ border-radius: 100%;
+}
diff --git a/public/stylesheets/style.styl b/public/stylesheets/style.styl
new file mode 100644
index 0000000..a8a32b6
--- /dev/null
+++ b/public/stylesheets/style.styl
@@ -0,0 +1,90 @@
+$sticker-font = Android Emoji, Symbola, Apple Color Emoji
+
+body
+ margin: auto
+ background: #f7f7f7
+ color: #333
+ width: 90%
+ text-align: center
+
+.sticker
+ font-style: normal
+ font-family: $sticker-font
+
+.stickers__sticker
+ font-size: 4em
+ line-height: 1.2
+ margin: .1em 0
+ padding: 0
+ border-radius: 15em
+ border: 1px solid rgba( 0, 0, 0, 0.1 )
+ display: inline-block
+ cursor: pointer
+
+.modal-panel
+ position: fixed
+ top: 30%
+ left: 25%
+ width: 50%
+ height: 50%
+ background: #fff
+ border: 1px solid #ccc
+ border-bottom: 5px solid #acf
+ box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.2)
+ transition: opacity .7s ease, top .5s ease-in-out
+ opacity: 0
+ pointer-events: none
+
+.modal-panel.is-shown
+ top: 25%
+ opacity: 1
+ pointer-events: all
+
+.modal-panel__close
+ $font-size = 1em
+ $size = 1.5em
+ position: absolute
+ top: 0
+ right: 0
+ font-size: $font-size
+ width: $size
+ height: $size
+ line-height: $size
+ background: #c99
+ border: #a77
+ font-style: normal
+ color: #fee
+ cursor: pointer
+ &:before
+ content: "✖"
+
+.sticker-editor__pane
+ display: inline-table
+ vertical-align: top
+ width: 40%
+ white-space: normal
+
+.sticker-editor__content
+ width: 90%
+ margin: 2em 0
+ white-space: nowrap
+
+.sticker-editor__row
+ display: table-row
+ line-height: 2em
+
+.sticker-editor__h3
+ font-family: roboto, helvetica neue
+ font-weight: 100
+ color: #666
+ text-align: left
+ display: table-cell
+ width: 0
+
+.sticker-editor__color
+ display: table-cell
+ width: 100%
+
+.sticker-editor__sticker
+ font-size: 10em
+ border-radius: 100%
diff --git a/routes/index.js b/routes/index.js
new file mode 100644
index 0000000..5c57e46
--- /dev/null
+++ b/routes/index.js
@@ -0,0 +1,15 @@
+/*
+ * GET home page.
+ */
+var fs = require('fs');
+exports.index = function(req, res) {
+ fs.readFile('data/icons.json', function (up, buffer) {
+ if (up) throw up;
+ try {
+ var stickers = JSON.parse(buffer.toString());
+ res.render('index', { stickers: stickers});
+ } catch (tantrum) {
+ throw tantrum;
+ }
+ });
+};
diff --git a/routes/user.js b/routes/user.js
new file mode 100644
index 0000000..d5b34aa
--- /dev/null
+++ b/routes/user.js
@@ -0,0 +1,8 @@
+
+/*
+ * GET users listing.
+ */
+
+exports.list = function(req, res){
+ res.send("respond with a resource");
+};
\ No newline at end of file
diff --git a/views/index.hjs b/views/index.hjs
new file mode 100644
index 0000000..aa98b74
--- /dev/null
+++ b/views/index.hjs
@@ -0,0 +1,32 @@
+
+
+ let's play: stickers!
+
+
+ {{#stickers}}
+
+ {{id}}
+
+ {{/stickers}}
+
+
+
+
+