<header>
    <h1><span>obelisk</span> buildr <em>stripped</em></h1>
  <aside class="links">
    <li><a target="_blank" href="https://bit.ly/1g08VKQ">full experiment</a></li>
    <li><a target="_blank" href="https://bit.ly/1hnlAcE">github</a></li>
  </aside>
</header>

<main>

  <div id="buildr">
      <canvas id="scene"></canvas>
  </div>

  <div id="palette" class="is-hidden">
  <button class="red" data-tool="brush" data-value="#c82829">1</button>
  <button class="orange" data-tool="brush" data-value="#f5871f">2</button>
  <button class="yellow" data-tool="brush" data-value="#eab700">3</button>
  <button class="green" data-tool="brush" data-value="#718c00">4</button>
  <button class="aqua" data-tool="brush" data-value="#3e999f">5</button>
  <button class="blue" data-tool="brush" data-value="#4271ae">6</button>
  <button class="purple" data-tool="brush" data-value="#8959a8">7</button>
  <button class="black" data-tool="brush" data-value="#4d4d4c">8</button>
  <button class="white is-active" data-tool="brush" data-value="#eeeeee">9</button>
  </div >

  <div id="overlay" class="is-hidden"></div>

  <div id="help" class="pane">
      <ul>
          <li><p><b>B</b>: Brush tool.</p></li>
          <li><p><b>E</b>: Erase tool.</p></li>
                <li><p><b>spacebar</b>: Color palette.</p></li>
                <li><p><b></b>, <b></b>: Rotate view.</p></li>
                <li><p><b>+</b>, <b>-</b>, <b>scroll</b>: Move draw layer up / down.</p></li>
                <li><p><b>CTRL + Z</b>: Undo.</p></li>
                <li><p><b>CTRL + S</b>: Save to gist.</p></li>
                <li><p><b>N</b>: New art.</p></li>
                <li><p><b>F</b>: Full canvas.</p></li>
                <li><p><b>H</b>: Toggle this thing.</p></li>
      </ul>
  </div>

</main>

<script src="http://ngryman.sh/obelisk-buildr/libs.js" type="text/javascript"></script>

</body>
</html>
@font-face {
  font-family: Lato;
  src: url('https://github.com/ngryman/obelisk-buildr/raw/master/fonts/lato.woff?92048847') format('woff'),
    url('https://github.com/ngryman/obelisk-buildr/raw/master/fonts/lato.ttf?92048847') format('truetype');
  font-weight: normal;
  font-style: normal;
}

* {
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

a,
a:active
a:visited {
  color: #eee;
}

a:active {
  text-decoration: none;
}

button {
  margin: 2px;
  padding: 0;
  border: none;
  outline: none;
}

html, body, main {
  margin: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

body {
  min-width: 320px;
  background-color: #111;
  color: #eee;
  font-family: Lato, Arial, sans-serif;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

main {
  text-align: center;
}

@media (min-width: 700px) and (min-height: 700px), (min-height: 700px) {
  main {
    padding-top: 70px;
    padding-bottom: 70px;
  }
}

#buildr {
  height: 100%;
}

#overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #000;
  opacity: .3;
  transition: opacity 200ms;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

#overlay.is-hidden {
  opacity: 0;
  pointer-events: none;
}

header {
  display: block;
  position: absolute;
  z-index: 1;
  padding: 6px;
  width: 100%;
  text-align: justify;
}

header::after {
  content: '';
  display: inline-block;
  width: 100%;
  height: 0;
  font-size: 0;
  line-height: 0;
}

header > * {
  display: inline-block;
  vertical-align: middle;
}

header h1 {
  margin: 0;
  height: 54px;
  line-height: 54px;
  color: #fff;
  text-align: left;
  font-weight: 300;
}

header h1 span {
  color: #00B2B2;
}

header h1:before {
  content: '';
  display: inline-block;
  vertical-align: text-top;
  margin-right: 15px;
  width: 40px;
  height: 40px;
  background-image: url(http://ngryman.sh/obelisk-buildr/logo.png);
  background-position: left center;
  background-repeat: no-repeat;
  background-size: 40px;
  -webkit-animation: doodle 4s linear infinite;
  animation: doodle 4s linear infinite;
}

header em {
  color: #777;
  font-size: 50%;
}

header aside {
  text-align: right;
}

header li {
  list-style-type: none;
}

@-webkit-keyframes doodle {
  25% { -webkit-transform: rotate(5deg); transform: rotate(5deg); }
  75% { -webkit-transform: rotate(-5deg); transform: rotate(-5deg); }
}

@keyframes doodle {
  25% { -webkit-transform: rotate(5deg); transform: rotate(5deg); }
  75% { -webkit-transform: rotate(-5deg); transform: rotate(-5deg); }
}

/**
* hide on small screens when they are in landscape mode
*
* [1]: using top instead of transform, because we can't have
*      position fixed elements in transformed elements. This
*      is needed for github auth buttons on small screens.
*/

@media (orientation: landscape) and (max-height: 400px) {
  header {
    top: -70px; /* [1] */
  }
}
#help {
  top: 70px;
  left: 0;
  width: 300px;
}

#help.is-hidden {
  opacity: 0;
  -webkit-transform: translateX(-100%) scale(.8);
  transform: translateX(-100%) scale(.8);
}
#palette {
  position: fixed;
  z-index: 1;
  padding: 5px;
  width: 200px;
  background: rgba(17, 17, 17, .9);
  opacity: 1;
  text-align: left;
  -webkit-transform: scale(1);
  transform: scale(1);
  /*transform: translateX(-50%) translateY(-50%);*/
  -webkit-backface-visibility: hidden;
  /*transform: translateX(-50%) translateY(-50%);*/
  backface-visibility: hidden;
  border: 1px solid #444;
  box-shadow: 0 0 0 1px #000, 0 0 15px rgba(0, 0, 0, .5);
  transition: opacity 100ms, -webkit-transform 100ms;
  transition: opacity 100ms, transform 100ms;
}

#palette.is-hidden {
  opacity: 0;
  -webkit-transform: scale(.7);
  transform: scale(.7);
  pointer-events: none;
}

#palette button {
  width: 30px;
  height: 30px;
  font-size: 10px;
}

#palette button.is-active {
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .4) inset;
}

#palette .red {
  background: linear-gradient(#c82829, rgba(200, 40, 41, 0.80));
}

#palette .red:active {
  background: linear-gradient(#af2829, rgba(175, 40, 41, 0.80));
}

#palette .orange {
  background: linear-gradient(#f5871f, rgba(245, 135, 31, 0.80));
}

#palette .orange:active {
  background: linear-gradient(#c8651f, rgba(200, 104, 31, 0.80));
}

#palette .yellow {
  background: linear-gradient(#eab700, rgba(234, 183, 0, 0.80));
}

#palette .yellow:active {
  background: linear-gradient(#bd8b00, rgba(189, 147, 0, 0.80));
}

#palette .green {
  background: linear-gradient(#718c00, rgba(113, 140, 0, 0.80));
}

#palette .green:active {
  background: linear-gradient(#475f00, rgba(71, 95, 0, 0.80));
}

#palette .aqua {
  background: linear-gradient(#3e999f, rgba(62, 153, 159, 0.81));
}

#palette .aqua:active {
  background: linear-gradient(#396c72, rgba(53, 108, 114, 0.81));
}

#palette .blue {
  background: linear-gradient(#4271ae, rgba(66, 113, 174, 0.81));
}

#palette .blue:active {
  background: linear-gradient(#404681, rgba(62, 71, 129, 0.81));
}

#palette .purple {
  background: linear-gradient(#8959a8, rgba(137, 89, 168, 0.80));
}

#palette .purple:active {
  background: linear-gradient(#5c3b7b, rgba(93, 59, 123, 0.80));
}

#palette .black {
  background: linear-gradient(#4d4d4c, rgba(77, 77, 76, 0.80));
}

#palette .black:active {
  background: linear-gradient(#20201f, rgba(32, 32, 31, 0.80));
}

#palette .white {
  background: linear-gradient(#ddd, rgba(221, 221, 221, 0.80));
}

#palette .white:active {
  background: linear-gradient(#b0b0b0, rgba(176, 176, 176, 0.80));
}
.pane {
  position: fixed;
  z-index: 1;
  padding: 15px 30px;
  background: rgba(17, 17, 17, .9);
  border: 1px solid #444;
  box-shadow: 0 0 0 1px #000, 0 0 15px rgba(0, 0, 0, .5);
  transition: all 300ms;
  border-radius: 2px;
}

.pane h2 {
  font-weight: 300;
}

.pane ul {
  margin-top: 20px;
  padding-left: 20px;
}

.pane p {
  text-align: left;
}

.pane b {
  margin: 0 2px;
  padding: 0 2px;
  font-weight: 300;
  color: #000;
  background: #fff;
}
#scene {
  width: 100%;
  height: 100%;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

@media (min-width: 800px) {
  #scene {
    width: 800px;
  }
}
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

// TODO: move this elsewhere
obelisk.Point3D.prototype.clone = function() {
    return new obelisk.Point3D(this.x, this.y, this.z);
};

/**
 * Module dependencies.
 */

var ui = require('./ui'),
    tool = require('./tool'),
    pointer = require('./pointer'),
    history = require('./history'),
    storage = require('./storage');

/**
 * Private variables
 */

var canvasEl = document.getElementById('scene');
var persistLock = false;
var autoSaveTimeout;
var resizeTimeout;
var fullCanvased = false;

/**
 * Module declaration.
 */

var app = {};

/**
 *
 */
app.init = function() {
    ui.scene.init();
      ui.palette.init();

      tool.init(ui.scene)
    .use('brush');

      pointer.init(ui.scene)
          .click(tool.click)
          .drag(tool.drag);

      bindShortcuts();
      bindScroll();
      bindResize();

      touchDisclaimer();

  // fetches initial art
  //TODO

    logCurious();
};

/**
 * @private
 */
function logCurious() {
  console.log('Hey! Curious or having bugs?');
  console.log('Please post ideas or issues here: https://github.com/ngryman/obelisk-buildr/issues.');
  console.log('You can play with the window.scene object.');
  if (console.table) {
    var methods = {
      snapshot: { description: 'Returns a base64 image of the current scene.' },
      load: { description: 'Loads a scene. Same format as the art.json file in gists.' },
      save: { description: 'Returns data associated with the current scene. Same format as the art.json file in gists.' }
    };
    console.table(methods);
  }
}

/**
 * @private
 */
function bindShortcuts() {
    document.addEventListener('keydown', onKeyDown);
}

/**
 * @private
 */
function bindScroll() {
    var isFirefox = /Firefox/i.test(navigator.userAgent);
    document.addEventListener(isFirefox ? 'DOMMouseScroll' : 'mousewheel', onScroll);
}

/**
 * @private
 */
function bindResize() {
    window.addEventListener('resize', onResize);
}

/**
 * @private
 */
function touchDisclaimer() {
  var isChrome = /chrome/i.exec(navigator.userAgent),
      isAndroid = /android/i.exec(navigator.userAgent),
      hasTouch = 'ontouchstart' in window && !(isChrome && !isAndroid);

  if (hasTouch)
    ui.notification.error('Hey! For now, there is no real support for touch devices. Yeah i know...');
  }

/**
 * @param {boolean} silent
 * @returns {object}
 * @private
 */
function save(silent) {
}

/**
 * @private
 */
function persist() {
}

/**
 * @private
 */
function create() {
  ui.scene.clear();
  ui.notification.info('new craft!');
}

/**
 * @private
 */
function fullCanvas() {
  var display = fullCanvased ? 'block' : 'none';
  document.querySelector('header').style.display = display;
  document.querySelector('footer').style.display = display;

  var padding = fullCanvased ? '70px' : '0px';
  document.querySelector('main').style.paddingTop = padding;
  document.querySelector('main').style.paddingBottom = padding;

  ui.scene.resize();

  fullCanvased = !fullCanvased;
}

/**
 * @param {event} e
 * @private
 */
function onKeyDown(e) {
  switch (e.keyCode) {
      // +
    case 107:
      ui.scene.adjustFloor(+1);
      break;

      // -
    case 109:
      ui.scene.adjustFloor(-1);
      break;

      // left
    case 37:
      ui.scene.rotate(+1);
      break;

      // right
    case 39:
      ui.scene.rotate(-1);
      break;

      // b
    case 66:
      tool.use('brush');
      break;

      // e
    case 69:
      tool.use('erase');
      break;

      // space bar
    case 32:
      ui.palette.toggle();
      break;

      // ctrl + z
    case 90:
      if (e.ctrlKey) history.back();
      break;

      // n
    case 78:
      create();
      break;

      // f
    case 70:
      fullCanvas();
      break;

      // h
    case 72:
      e.preventDefault();
      ui.help.toggle();
      break;
  }

  // 123456789
  if (e.keyCode >= 49 && e.keyCode <= 57)
    tool.use('brush').set(ui.palette.color(e.keyCode - 49));
}

/**
 * @param {event} e
 * @private
 */
function onScroll(e) {
  var delta = e.detail ? -e.detail : e.wheelDelta;
  ui.scene.adjustFloor(delta > 0 ? -1 : +1);
}

/**
 * @param {event} e
 * @private
 */
function onResize(e) {
  // hide on first event
  if (null == resizeTimeout)
    canvasEl.style.visibility = 'hidden';

  // debounce scene resize
  clearTimeout(resizeTimeout);
  resizeTimeout = setTimeout(function() {
    ui.scene.resize();
    canvasEl.style.visibility = 'visible';
    resizeTimeout = null;
  }, 100);
}

/**
 * @private
 */
function onAutoSave() {
}

/**
 * Global export.
 */
window.app = app;

/**
 * Exports for hackers
 */

window.scene = ui.scene;
},{"./history":3,"./pointer":4,"./storage":5,"./tool":6,"./ui":11}],2:[function(require,module,exports){
},{}],3:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

/**
 * Private variables
 */

var stack = [];
var sequence = null;

/**
 * Module declaration.
 */

var history = {};

/**
 *
 * @param {function} fn
 */
history.push = function(fn) {
  if (!sequence)
    return stack.push(fn);
  sequence.push(fn);
};

/**
 *
 */
history.startSequence = function() {
    sequence = [];
};

/**
 *
 */
history.stopSequence = function() {
  var seq = sequence;

  stack.push(function() {
    seq.forEach(function(action) {
      action();
    });
    });

    sequence = null;
};

/**
 *
 * @returns {boolean}
 */
history.isSequenced = function() {
    return (null != sequence);
};

/**
 *
 */
history.back = function() {
  if (0 === stack.length) return;

  stack.pop()();
};

/**
 * Exports.
 */

module.exports = history;
},{}],4:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

/**
 * Module dependencies.
 */

var history = require('./history');

/**
 * Private variables
 */

var canvasEl = document.getElementById('scene');
var canvasOffset = new obelisk.Point();
var scene;
var x, y;// TODO: screenPos
var viewPoint = new obelisk.Point3D(); // TODO: viewPos
var loopStarted = false;
var loopStopIn = 0;
var down = false;
var dragging = false;
var clickHandler;
var dragHandler;
var moveHandler;

/**
 * Module declaration.
 */

var pointer = {};

/**
 *
 * @param {scene} _scene
 * @returns {pointer}
 */
pointer.init = function(_scene) {
  var main = document.querySelector('#buildr');
  main.addEventListener('mousedown', onDown);
  main.addEventListener('mousemove', onMove);
  main.addEventListener('mouseup', onUp);
  main.addEventListener('mouseleave', onUp);

  window.addEventListener('resize', onResize);

  Loop.on('tick', apply);

  onResize();

  scene = _scene;

  return pointer;
};

/**
 *
 * @param {function} handler
 * @returns {pointer}
 */
pointer.click = function(handler) {
  clickHandler = handler;
  return pointer;
};

/**
 *
 * @param {function} handler
 * @returns {pointer}
 */
pointer.drag = function(handler) {
  dragHandler = handler;
  return pointer;
};

/**
 *
 * @param {function} handler
 * @returns {pointer}
 */
pointer.move = function(handler) {
  moveHandler = handler;
  return pointer;
};

/**
 * @private
 */
function onDown() {
  down = true;
}

/**
 * @private
 */
function onUp() {
  // may happen when called by mouseleave
  if (!down) return;
  down = false;

  if (!dragging) {
    if (clickHandler) clickHandler();
    return;
  }
  dragging = false;

  if (history.isSequenced())
    history.stopSequence();
}

/**
 * @param {event} e
 * @private
 */
function onMove(e) {
  x = e.pageX - canvasOffset.x;
  y = e.pageY - canvasOffset.y;

  if (down && !dragging)
    dragging = true;

  if (!loopStarted) {
    Loop.start();
    loopStarted = true;
  }
  loopStopIn = 1;
}

/**
 * @private
 */
function onResize() {
  canvasOffset.x = canvasEl.offsetLeft;
  canvasOffset.y = canvasEl.offsetTop;
}

/**
 * @private
 */
function apply() {
  scene.screenToView(x, y, viewPoint);
  scene.select(viewPoint);

  if (dragging) {
    if (dragHandler) dragHandler();
    return;
    }

  if (moveHandler) moveHandler();

  if (0 === loopStopIn) {
    Loop.stop();
    loopStarted = false;
  }
  loopStopIn--;
}

/**
 * Exports.
 */

module.exports = pointer;
},{"./history":3}],5:[function(require,module,exports){
},{"./github":2}],6:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

/**
 * Module dependencies.
 */

var tools = {
  brush: require('./tools/brush'),
  erase: require('./tools/erase')
};

/**
 * Private variables
 */

var scene;
var current;

/**
 * Module declaration.
 */

var tool = {};

/**
 *
 * @param _scene
 * @returns {tool}
 */
tool.init = function(_scene) {
  scene = _scene;
  return tool;
};

/**
 *
 * @param type
 * @returns {tool}
 */
tool.use = function(type) {
  current = tools[type];
  return tool;
};

/**
 *
 * @param value
 * @returns {tool}
 */
tool.set = function(value) {
  if (current.set) current.set(value);
  return tool;
};

/**
 *
 * @returns {tool}
 */
tool.click = function() {
  current.click(scene);
  return tool;
};

/**
 *
 * @returns {tool}
 */
tool.drag = function() {
  current.drag(scene);
  return tool;
};

/**
 * Exports.
 */

module.exports = tool;
},{"./tools/brush":7,"./tools/erase":8}],7:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

/**
 * Module dependencies.
 */

var history = require('../history');

/**
 * Private variables
 */

var color = obelisk.ColorPattern.GRAY;

/**
 * Module declaration.
 */

var brush = {};

/**
 *
 * @param {string} value
 */
brush.set = function(value) {
  // strip #
  value = value.slice(1);
  // convert to number
  value = parseInt(value, 16);

  color = value;
};

/**
 *
 * @param {scene} scene
 */
brush.click = function(scene) {
  if (scene.add(color))
    history.push(scene.remove.bind(scene, scene.selected().clone()));
};

/**
 *
 * @param {scene} scene
 */
brush.drag = function(scene) {
  if (scene.add(color)) {
    if (!history.isSequenced())
      history.startSequence();

    history.push(scene.remove.bind(scene, scene.selected().clone()));
  }
};

/**
 * Exports.
 */

module.exports = brush;
},{"../history":3}],8:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

/**
 * Module dependencies.
 */

var history = require('../history');

/**
 * Module declaration.
 */

var erase = {};

/**
 *
 * @param {scene} scene
 */
erase.click = function(scene) {
  var color = scene.color();
  if (scene.remove())
    history.push(scene.add.bind(scene,
                                color,
                                scene.selected().clone()
                               ));
};

/**
 *
 * @param {scene} scene
 */
erase.drag = function(scene) {
  var color = scene.color();
  if (scene.remove()) {
    if (!history.isSequenced())
      history.startSequence();

    history.push(scene.add.bind(scene,
                                color,
                                scene.selected().clone()
                               ));
  }
};

/**
 * Exports.
 */

module.exports = erase;
},{"../history":3}],9:[function(require,module,exports){
},{"./../github":2}],10:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

/**
 * Private variables
 */

var el = document.querySelector('#help');

/**
 * Module declaration.
 */

var help = {};

help.toggle = function() {
  el.classList.toggle('is-hidden');
};

/**
 * Exports.
 */

module.exports = help;
},{}],11:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

/**
 * Exports.
 */

module.exports = {
  auth: require('./auth'),
  notification: require('./notification'),
  palette: require('./palette'),
  scene: require('./scene'),
  welcome: require('./welcome'),
  help: require('./help')
};
},{"./auth":9,"./help":10,"./notification":12,"./palette":13,"./scene":14,"./welcome":15}],12:[function(require,module,exports){
},{}],13:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

/**
 * Module dependencies.
 */

var tool = require('./../tool');

/**
 * Private variables
 */

var el = document.getElementById('palette');
var overlayEl = document.getElementById('overlay');
var active = document.querySelector('#palette .is-active');
var visible = false;
var x, y;
var width, height;

/**
 * Module declaration.
 */

var palette = {};

/**
 *
 */
palette.init = function() {
  var style = getComputedStyle(el);
  width = parseInt(style.width);
  height = parseInt(style.height);

  window.addEventListener('mousemove', function(e) {
    x = e.clientX;
    y = e.clientY;
  });

  el.addEventListener('click', function(e) {
    var btn = e.target;

    if ('BUTTON' != btn.tagName) return;

    if (active)
      active.classList.remove('is-active');
    btn.classList.add('is-active');

    // tool selection and value
    tool.use(btn.dataset.tool).set(btn.dataset.value);

    active = e.target;
  });
};

/**
 *
 */
palette.toggle = function() {
  if (!visible) {
    el.style.left = (x - width / 2) + 'px';
    el.style.top = (y - height / 2) + 'px';
  }

  el.classList.toggle('is-hidden');
  overlayEl.classList.toggle('is-hidden');

  visible = !visible;
};

/**
 *
 * @param {number} index
 * @returns {string}
 */
palette.color = function(index) {
  var btn = el.querySelector('button:nth-child(' + (index + 1) + ')');
  return btn.dataset.value;
};

/**
 * Exports.
 */

module.exports = palette;
},{"./../tool":6}],14:[function(require,module,exports){
/*!
 * obelisk-builder
 * Copyright (c) 2013 Nicolas Gryman <ngryman@gmail.com>
 * MIT Licensed
 */

'use strict';

/**
 * Private variables
 */

var canvasEl = document.getElementById('scene');
var SIZE = 20;
var BLOCK_SIZE = 20;
var view;
var floor;
var cubes;
var blocks;
var origin;
var changed = false;
var changedHandler;

/**
 * Module declaration.
 */

var scene = {};

/**
 *
 * @returns {scene}
 */
scene.init = function() {
  cubes = {};
  cubes[obelisk.ColorPattern.GRAY] = createCube(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, obelisk.ColorPattern.GRAY);

  floor = {
    normal: createBrick(BLOCK_SIZE, BLOCK_SIZE, '0xFF222222'),
    elevated: createBrick(BLOCK_SIZE + 2, BLOCK_SIZE + 2, '0xFF222222'),
    highlighted: createBrick(BLOCK_SIZE, BLOCK_SIZE, '0xFF444444'),
    elevatedHighlighted: createBrick(BLOCK_SIZE + 2, BLOCK_SIZE + 2, '0xFF555555'),
    selected: new obelisk.Point3D(-1, -1, 0),
    offset: 0
  };

  blocks = matrix(SIZE);

  scene.resize();

  return scene;
};

/**
 *
 */
scene.resize = function() {
  // 1:1 ratio
  var style = getComputedStyle(canvasEl);
  canvasEl.width = parseInt(style.width);
  canvasEl.height = parseInt(style.height);

  origin = new obelisk.Point(canvasEl.width / 2, canvasEl.height / 2);

  view = new obelisk.PixelView(canvasEl, new obelisk.Point(
    origin.x, origin.y
  ));

  var oldBlockSize = BLOCK_SIZE;

  // small screens
  if (canvasEl.width < 800 || canvasEl.height < 800) {
    var size = Math.min(canvasEl.width, canvasEl.height);

    // compute new block size
    BLOCK_SIZE = Math.floor(size / 40);
    // ensure it's even (obelisk needs it)
    BLOCK_SIZE = BLOCK_SIZE - (BLOCK_SIZE % 2);
  }
  // ensure block size comes back to its original size
  else
    BLOCK_SIZE = 20;

  // adapt existing geom to the correct size
  if (oldBlockSize != BLOCK_SIZE) {
    for (var color in cubes) {
      if (!cubes.hasOwnProperty(color)) continue;
      cubes[color] = createCube(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, parseInt(color));
    }

    floor.normal = createBrick(BLOCK_SIZE, BLOCK_SIZE, '0xFF222222');
    floor.elevated = createBrick(BLOCK_SIZE + 2, BLOCK_SIZE + 2, '0xFF222222');
    floor.highlighted = createBrick(BLOCK_SIZE, BLOCK_SIZE, '0xFF444444');
    floor.elevatedHighlighted = createBrick(BLOCK_SIZE + 2, BLOCK_SIZE + 2, '0xFF555555');
  }

  scene.draw();
};

/**
 *
 */
scene.draw = function() {
  view.clear();

  drawBlocks(view, blocks, cubes, 0, floor.offset);
  drawFloor(view, floor);
  drawBlocks(view, blocks, cubes, floor.offset, SIZE);
};

/**
 *
 * @param {number} x
 * @param {number} y
 * @param {obelisk.Point3D} point
 */
scene.screenToView = function(x, y, point) {
  x -= origin.x;
  y -= origin.y;

  point.x = Math.floor(((x + 2 * y) / 2) / BLOCK_SIZE) + floor.offset;
  point.y = Math.floor(((-x + 2 * y) / 2) / BLOCK_SIZE) + floor.offset;
  point.z = floor.offset;
};

/**
 *
 * @param {obelisk.Point3D} point
 */
scene.select = function(point) {
  clampBounds(point);

  floor.selected.x = point.x;
  floor.selected.y = point.y;
  floor.selected.z = point.z;

  scene.draw();
};

/**
 *
 * @returns {obelisk.Point}
 */
scene.selected = function() {
  return floor.selected;
};

/**
 *
 * @param {obelisk.Point3D} point
 * @returns {number|null}
 */
scene.color = function(point) {
  point = point || scene.selected();

  var block = blocks[point.x][point.y][point.z];
  if (!block) return null;

  return block.color;
};

/**
 *
 * @param {number} color
 * @param {obelisk.Point3D} point
 * @returns {boolean}
 */
scene.add = function(color, point) {
  point = point || floor.selected;

  // already exists
  if (null != blocks[point.x][point.y][point.z]) return false;

  // if a cube with the given color does not exist, create it
  if (null == cubes[color])
    cubes[color] = createCube(BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, color);

  var block = point.clone();
  block.color = color;

  blocks[block.x][block.y][block.z] = block;
  scene.draw();

  changed = true;
  if (changedHandler) changedHandler();

  return true;
};

/**
 *
 * @param {obelisk.Point3D} point
 * @returns {boolean}
 */
scene.remove = function(point) {
  point = point || floor.selected;

  if (null == blocks[point.x][point.y][point.z]) return false;

  blocks[point.x][point.y][point.z] = null;
  scene.draw();

  changed = true;
  if (changedHandler) changedHandler();

  return true;
};

/**
 *
 * @param {number} delta
 */
scene.adjustFloor = function(delta) {
  floor.offset += delta;

  if (floor.offset < 0) floor.offset = 0;
  else if (floor.offset >= SIZE) floor.offset = SIZE - 1;

  scene.draw();
};

/**
 *
 * @param {number} direction
 */
scene.rotate = function(direction) {
  var b = blocks,
      n = SIZE,
      x, y, z, start, end;

  // transpose
  for (z = 0; z < n; z++)
    for (x = 0; x < n; x++)
      for (y = 0; y < n; y++)
        if (x < y) swap(b, x, y, y, x, z);

  if (1 === direction) {
    // reverse rows
    for (z = 0; z < n; z++)
      for (x = 0; x < n; x++)
        for (start = 0, end = n - 1; start < end; start++, end--)
          swap(b, x, start, x, end, z);
  }
  else if (-1 == direction) {
    // reverse cols
    for (z = 0; z < n; z++)
      for (y = 0; y < n; y++)
        for (start = 0, end = n - 1; start < end; start++, end--)
          swap(b, start, y, end, y, z);
  }

  scene.draw();
};

/**
 *
 * @param {boolean} silent
 * @returns {object}
 */
scene.save = function(silent) {
  var data = [];

  // creates a color table
  var colors = [], colorsHash = {};
  for (var p in cubes) {
    if (!cubes.hasOwnProperty(p)) continue;

    colorsHash[p] = colors.length;
    colors.push(p);
  }

  // basically "compact" the memory structure by only saving existing blocks,
  // referencing colors in color table, with short properties name
  for (var x = 0; x < SIZE; x++) {
    for (var y = 0; y < SIZE; y++) {
      for (var z = 0; z < SIZE; z++) {
        if (null != blocks[x][y][z]) {
          var b = blocks[x][y][z];
          data.push({
            x: b.x,
            y: b.y,
            z: b.z,
            c: colorsHash[b.color]
          });
        }
      }
    }
  }

  if (!silent) changed = false;

  return {
    colors: colors,
    data: data
  };
};

/**
 *
 * @param {object} data
 */
scene.load = function(data) {
  var i;

  // ensure colors are numbers
  var colors = data.colors;
  for (i = 0; i < colors.length; i++)
    colors[i] = parseInt(colors[i]);

  data = data.data;

  blocks = matrix(SIZE);

  for (i = 0; i < data.length; i++)
    scene.add(colors[data[i].c], new obelisk.Point3D(data[i].x, data[i].y, data[i].z));

  scene.draw();

  changed = false;
};

/**
 *
 * @returns {string}
 */
scene.snapshot = function() {
  // isolate art
  view.clear();
  view.context.fillStyle = '#222222';
  view.context.fillRect(0, 0, canvasEl.width, canvasEl.height);
  drawBlocks(view, blocks, cubes, 0, SIZE);

  var image = canvasEl.toDataURL("image/png");

  scene.draw();

  return image;
};

/**
 *
 */
scene.clear = function() {
  blocks = matrix(SIZE);
  scene.draw();
};

/**
 *
 * @param {function} callback
 * @returns {boolean|undefined}
 */
scene.changed = function(callback) {
  if (!callback) return changed;
  changedHandler = callback;
  return this;
};

/**
 *
 * @param {number} width
 * @param {number} height
 * @param {string} hexColor
 * @returns {obelisk.Brick}
 * @private
 */
function createBrick(width, height, hexColor) {
  var dimension = new obelisk.BrickDimension(width, height);
  var color = new obelisk.SideColor().getByInnerColor(hexColor);

  return new obelisk.Brick(dimension, color, false);
}

/**
 *
 * @param {number} width
 * @param {number} height
 * @param {number} depth
 * @param {string} hexColor
 * @returns {obelisk.Cube}
 * @private
 */
function createCube(width, height, depth, hexColor) {
  var dimension = new obelisk.CubeDimension(width, height, depth);
  var color = new obelisk.CubeColor(
    obelisk.ColorGeom.applyBrightness(hexColor, -20 * 4),
    obelisk.ColorGeom.applyBrightness(hexColor, 60),
    obelisk.ColorGeom.applyBrightness(hexColor, -20 * 2),
    obelisk.ColorGeom.applyBrightness(hexColor, -20),
    hexColor
  );

  return new obelisk.Cube(dimension, color);
}

/**
 *
 * @param {obelisk.Point3D} point
 * @private
 */
function clampBounds(point) {
  if (point.x < 0) point.x = 0;
  else if (point.x >= SIZE) point.x = SIZE - 1;
  if (point.y < 0) point.y = 0;
  else if (point.y >= SIZE) point.y = SIZE - 1;
  if (point.z < 0) point.z = 0;
  else if (point.z >= SIZE) point.z = SIZE - 1;
}

/**
 *
 * @param {number} size
 * @returns {array}
 * @private
 */
function matrix(size) {
  var m = new Array(size);
  for (var x = 0; x < size; x++) {
    m[x] = new Array(size);
    for (var y = 0; y < size; y++) {
      m[x][y] = new Array(size);
    }
  }

  return m;
}

/**
 *
 * @param {number} m
 * @param {number} x1
 * @param {number} y1
 * @param {number} x2
 * @param {number} y2
 * @param {number} z
 * @private
 */
function swap(m, x1, y1, x2, y2, z) {
  var tmp = m[x2][y2][z], c;

  c = m[x2][y2][z] = m[x1][y1][z];
  if (c) {
    c.x = x2;
    c.y = y2;
  }

  c = m[x1][y1][z] = tmp;
  if (c) {
    c.x = x1;
    c.y = y1;
  }
}

/**
 *
 * @param {obelisk.PixelView} view
 * @param {object} floor
 * @private
 */
function drawFloor(view, floor) {
  var normal = floor.normal,
      highlighted = floor.highlighted,
      point = new obelisk.Point3D();

  if (floor.offset > 0) {
    normal = floor.elevated;
    highlighted = floor.elevatedHighlighted;
    view.context.globalAlpha = 0.7;
  }

  for (var x = 0; x < 20; x++) {
    for (var y = 0; y < 20; y++) {
      if (x == floor.selected.x && y == floor.selected.y) continue;

      point.x = x * BLOCK_SIZE;
      point.y = y * BLOCK_SIZE;
      point.z = floor.offset * BLOCK_SIZE;

      view.renderObject(normal, point);
    }
  }

  if (-1 != floor.selected.x) {
    point.x = floor.selected.x * BLOCK_SIZE;
    point.y = floor.selected.y * BLOCK_SIZE;
    point.z = floor.offset * BLOCK_SIZE;

    view.renderObject(highlighted, point);
  }

  view.context.globalAlpha = 1;
}

/**
 *
 * @param {obelisk.PixelView} view
 * @param {array} blocks
 * @param {object} cubes
 * @param {number} startZ
 * @param {number} endZ
 * @private
 */
function drawBlocks(view, blocks, cubes, startZ, endZ) {
  var point = new obelisk.Point3D();

  for (var x = 0; x < SIZE; x++) {
    for (var y = 0; y < SIZE; y++) {
      for (var z = startZ; z < endZ; z++) {
        var block = blocks[x][y][z];

        if (!block) continue;

        point.x = block.x * BLOCK_SIZE;
        point.y = block.y * BLOCK_SIZE;
        point.z = block.z * BLOCK_SIZE;

        view.renderObject(cubes[block.color], point);
      }
    }
  }
}

/**
 * Exports.
 */

module.exports = scene;
},{}],15:[function(require,module,exports){
},{}]},{},[1])

app.init();

// loads heart
scene.load({"colors":["13117481","15658734"],"data":[{"x":0,"y":9,"z":10,"c":0},{"x":0,"y":9,"z":11,"c":0},{"x":0,"y":9,"z":12,"c":0},{"x":0,"y":9,"z":13,"c":0},{"x":1,"y":9,"z":8,"c":0},{"x":1,"y":9,"z":9,"c":0},{"x":1,"y":9,"z":10,"c":0},{"x":1,"y":9,"z":11,"c":0},{"x":1,"y":9,"z":12,"c":0},{"x":1,"y":9,"z":13,"c":0},{"x":1,"y":9,"z":14,"c":0},{"x":2,"y":9,"z":7,"c":0},{"x":2,"y":9,"z":8,"c":0},{"x":2,"y":9,"z":9,"c":0},{"x":2,"y":9,"z":10,"c":0},{"x":2,"y":9,"z":11,"c":0},{"x":2,"y":9,"z":12,"c":0},{"x":2,"y":9,"z":13,"c":0},{"x":2,"y":9,"z":14,"c":0},{"x":2,"y":9,"z":15,"c":0},{"x":3,"y":9,"z":6,"c":0},{"x":3,"y":9,"z":7,"c":0},{"x":3,"y":9,"z":8,"c":0},{"x":3,"y":9,"z":9,"c":0},{"x":3,"y":9,"z":10,"c":0},{"x":3,"y":9,"z":11,"c":0},{"x":3,"y":9,"z":12,"c":0},{"x":3,"y":9,"z":13,"c":0},{"x":3,"y":9,"z":14,"c":0},{"x":3,"y":9,"z":15,"c":0},{"x":3,"y":9,"z":16,"c":0},{"x":4,"y":9,"z":5,"c":0},{"x":4,"y":9,"z":6,"c":0},{"x":4,"y":9,"z":7,"c":0},{"x":4,"y":9,"z":8,"c":0},{"x":4,"y":9,"z":9,"c":0},{"x":4,"y":9,"z":10,"c":0},{"x":4,"y":9,"z":11,"c":0},{"x":4,"y":9,"z":12,"c":0},{"x":4,"y":9,"z":13,"c":0},{"x":4,"y":9,"z":14,"c":0},{"x":4,"y":9,"z":15,"c":0},{"x":4,"y":9,"z":16,"c":0},{"x":4,"y":9,"z":17,"c":0},{"x":5,"y":9,"z":4,"c":0},{"x":5,"y":9,"z":5,"c":0},{"x":5,"y":9,"z":6,"c":0},{"x":5,"y":9,"z":7,"c":0},{"x":5,"y":9,"z":8,"c":0},{"x":5,"y":9,"z":9,"c":0},{"x":5,"y":9,"z":10,"c":0},{"x":5,"y":9,"z":11,"c":0},{"x":5,"y":9,"z":12,"c":0},{"x":5,"y":9,"z":13,"c":0},{"x":5,"y":9,"z":14,"c":0},{"x":5,"y":9,"z":15,"c":0},{"x":5,"y":9,"z":16,"c":0},{"x":5,"y":9,"z":17,"c":0},{"x":6,"y":9,"z":3,"c":0},{"x":6,"y":9,"z":4,"c":0},{"x":6,"y":9,"z":5,"c":0},{"x":6,"y":9,"z":6,"c":0},{"x":6,"y":9,"z":7,"c":0},{"x":6,"y":9,"z":8,"c":0},{"x":6,"y":9,"z":9,"c":0},{"x":6,"y":9,"z":10,"c":0},{"x":6,"y":9,"z":11,"c":0},{"x":6,"y":9,"z":12,"c":0},{"x":6,"y":9,"z":13,"c":0},{"x":6,"y":9,"z":14,"c":0},{"x":6,"y":9,"z":15,"c":0},{"x":6,"y":9,"z":16,"c":0},{"x":6,"y":9,"z":17,"c":0},{"x":7,"y":9,"z":2,"c":0},{"x":7,"y":9,"z":3,"c":0},{"x":7,"y":9,"z":4,"c":0},{"x":7,"y":9,"z":5,"c":0},{"x":7,"y":9,"z":6,"c":0},{"x":7,"y":9,"z":7,"c":0},{"x":7,"y":9,"z":8,"c":0},{"x":7,"y":9,"z":9,"c":0},{"x":7,"y":9,"z":10,"c":0},{"x":7,"y":9,"z":11,"c":0},{"x":7,"y":9,"z":12,"c":0},{"x":7,"y":9,"z":13,"c":0},{"x":7,"y":9,"z":14,"c":0},{"x":7,"y":9,"z":15,"c":0},{"x":7,"y":9,"z":16,"c":0},{"x":8,"y":9,"z":1,"c":0},{"x":8,"y":9,"z":2,"c":0},{"x":8,"y":9,"z":3,"c":0},{"x":8,"y":9,"z":4,"c":0},{"x":8,"y":9,"z":5,"c":0},{"x":8,"y":9,"z":6,"c":0},{"x":8,"y":9,"z":7,"c":0},{"x":8,"y":9,"z":8,"c":0},{"x":8,"y":9,"z":9,"c":0},{"x":8,"y":9,"z":10,"c":0},{"x":8,"y":9,"z":11,"c":0},{"x":8,"y":9,"z":12,"c":0},{"x":8,"y":9,"z":13,"c":0},{"x":8,"y":9,"z":14,"c":0},{"x":8,"y":9,"z":15,"c":0},{"x":9,"y":9,"z":0,"c":0},{"x":9,"y":9,"z":1,"c":0},{"x":9,"y":9,"z":2,"c":0},{"x":9,"y":9,"z":3,"c":0},{"x":9,"y":9,"z":4,"c":0},{"x":9,"y":9,"z":5,"c":0},{"x":9,"y":9,"z":6,"c":0},{"x":9,"y":9,"z":7,"c":0},{"x":9,"y":9,"z":8,"c":0},{"x":9,"y":9,"z":9,"c":0},{"x":9,"y":9,"z":10,"c":0},{"x":9,"y":9,"z":11,"c":0},{"x":9,"y":9,"z":12,"c":0},{"x":9,"y":9,"z":13,"c":0},{"x":9,"y":9,"z":14,"c":0},{"x":10,"y":9,"z":0,"c":0},{"x":10,"y":9,"z":1,"c":0},{"x":10,"y":9,"z":2,"c":0},{"x":10,"y":9,"z":3,"c":0},{"x":10,"y":9,"z":4,"c":0},{"x":10,"y":9,"z":5,"c":0},{"x":10,"y":9,"z":6,"c":0},{"x":10,"y":9,"z":7,"c":0},{"x":10,"y":9,"z":8,"c":0},{"x":10,"y":9,"z":9,"c":0},{"x":10,"y":9,"z":10,"c":0},{"x":10,"y":9,"z":11,"c":0},{"x":10,"y":9,"z":12,"c":0},{"x":10,"y":9,"z":13,"c":0},{"x":10,"y":9,"z":14,"c":0},{"x":11,"y":9,"z":1,"c":0},{"x":11,"y":9,"z":2,"c":0},{"x":11,"y":9,"z":3,"c":0},{"x":11,"y":9,"z":4,"c":0},{"x":11,"y":9,"z":5,"c":0},{"x":11,"y":9,"z":6,"c":0},{"x":11,"y":9,"z":7,"c":0},{"x":11,"y":9,"z":8,"c":0},{"x":11,"y":9,"z":9,"c":0},{"x":11,"y":9,"z":10,"c":0},{"x":11,"y":9,"z":11,"c":0},{"x":11,"y":9,"z":12,"c":0},{"x":11,"y":9,"z":13,"c":0},{"x":11,"y":9,"z":14,"c":0},{"x":11,"y":9,"z":15,"c":0},{"x":12,"y":9,"z":2,"c":0},{"x":12,"y":9,"z":3,"c":0},{"x":12,"y":9,"z":4,"c":0},{"x":12,"y":9,"z":5,"c":0},{"x":12,"y":9,"z":6,"c":0},{"x":12,"y":9,"z":7,"c":0},{"x":12,"y":9,"z":8,"c":0},{"x":12,"y":9,"z":9,"c":0},{"x":12,"y":9,"z":10,"c":0},{"x":12,"y":9,"z":11,"c":0},{"x":12,"y":9,"z":12,"c":0},{"x":12,"y":9,"z":13,"c":0},{"x":12,"y":9,"z":14,"c":0},{"x":12,"y":9,"z":15,"c":0},{"x":12,"y":9,"z":16,"c":0},{"x":13,"y":9,"z":3,"c":0},{"x":13,"y":9,"z":4,"c":0},{"x":13,"y":9,"z":5,"c":0},{"x":13,"y":9,"z":6,"c":0},{"x":13,"y":9,"z":7,"c":0},{"x":13,"y":9,"z":8,"c":0},{"x":13,"y":9,"z":9,"c":0},{"x":13,"y":9,"z":10,"c":0},{"x":13,"y":9,"z":11,"c":0},{"x":13,"y":9,"z":12,"c":0},{"x":13,"y":9,"z":13,"c":0},{"x":13,"y":9,"z":14,"c":0},{"x":13,"y":9,"z":15,"c":0},{"x":13,"y":9,"z":16,"c":0},{"x":13,"y":9,"z":17,"c":0},{"x":14,"y":9,"z":4,"c":0},{"x":14,"y":9,"z":5,"c":0},{"x":14,"y":9,"z":6,"c":0},{"x":14,"y":9,"z":7,"c":0},{"x":14,"y":9,"z":8,"c":0},{"x":14,"y":9,"z":9,"c":0},{"x":14,"y":9,"z":10,"c":0},{"x":14,"y":9,"z":11,"c":0},{"x":14,"y":9,"z":12,"c":0},{"x":14,"y":9,"z":13,"c":0},{"x":14,"y":9,"z":14,"c":0},{"x":14,"y":9,"z":15,"c":0},{"x":14,"y":9,"z":16,"c":0},{"x":14,"y":9,"z":17,"c":0},{"x":15,"y":9,"z":5,"c":0},{"x":15,"y":9,"z":6,"c":0},{"x":15,"y":9,"z":7,"c":0},{"x":15,"y":9,"z":8,"c":0},{"x":15,"y":9,"z":9,"c":0},{"x":15,"y":9,"z":10,"c":0},{"x":15,"y":9,"z":11,"c":0},{"x":15,"y":9,"z":12,"c":0},{"x":15,"y":9,"z":13,"c":0},{"x":15,"y":9,"z":14,"c":0},{"x":15,"y":9,"z":15,"c":0},{"x":15,"y":9,"z":16,"c":0},{"x":15,"y":9,"z":17,"c":0},{"x":16,"y":9,"z":6,"c":0},{"x":16,"y":9,"z":7,"c":0},{"x":16,"y":9,"z":8,"c":0},{"x":16,"y":9,"z":9,"c":0},{"x":16,"y":9,"z":10,"c":0},{"x":16,"y":9,"z":11,"c":0},{"x":16,"y":9,"z":12,"c":0},{"x":16,"y":9,"z":13,"c":0},{"x":16,"y":9,"z":14,"c":0},{"x":16,"y":9,"z":15,"c":0},{"x":16,"y":9,"z":16,"c":0},{"x":17,"y":9,"z":7,"c":0},{"x":17,"y":9,"z":8,"c":0},{"x":17,"y":9,"z":9,"c":0},{"x":17,"y":9,"z":10,"c":0},{"x":17,"y":9,"z":11,"c":0},{"x":17,"y":9,"z":12,"c":0},{"x":17,"y":9,"z":13,"c":0},{"x":17,"y":9,"z":14,"c":0},{"x":17,"y":9,"z":15,"c":0},{"x":18,"y":9,"z":8,"c":0},{"x":18,"y":9,"z":9,"c":0},{"x":18,"y":9,"z":10,"c":0},{"x":18,"y":9,"z":11,"c":0},{"x":18,"y":9,"z":12,"c":0},{"x":18,"y":9,"z":13,"c":0},{"x":18,"y":9,"z":14,"c":0},{"x":19,"y":9,"z":10,"c":0},{"x":19,"y":9,"z":11,"c":0},{"x":19,"y":9,"z":12,"c":0},{"x":19,"y":9,"z":13,"c":0}]});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.