<commit_before>// Arbitrary numbers chosen to ensure Long Portrait mode fits into Chrome on Android.
// Firefox uses less vertical space for the URL bar so Long Portrait will be available in both.
// 270 is six times 45, as board is twelve squares and logo is two.
// 73 is the remaining 3.24444 squares that can fit into the Chrome window.
// Scaled up until all values are integers for ease of reading.
const THRESHOLD_LongPortraitFitToWidth = 270/(45+270+73);
const THRESHOLD_LongPortraitFitToHeight = (45+270)/(45+270+73);
const THRESHOLD_ShortPortraitFitToWidth = (45+270)/(270+73);
const THRESHOLD_ShortPortraitFitToHeight = 1;
const THRESHOLD_ShortLandscapeFitToWidth = (270+73)/(45+270);
const THRESHOLD_ShortLandscapeFitToHeight = (45+270+73)/(45+270);
const THRESHOLD_LongLandscapeFitToWidth = (45+270+73)/270;

function reorganise() {
  ratio = window.innerWidth / window.innerHeight;
  if (ratio < THRESHOLD_LongPortraitFitToWidth) {arrange_LongPortraitFitToWidth();
  } else if (ratio < THRESHOLD_LongPortraitFitToHeight) {arrange_LongPortraitFitToHeight();
  } else if (ratio < THRESHOLD_ShortPortraitFitToWidth) {arrange_ShortPortraitFitToWidth();
  } else if (ratio < THRESHOLD_ShortPortraitFitToHeight) {arrange_ShortPortraitFitToHeight();
  } else if (ratio < THRESHOLD_ShortLandscapeFitToWidth) {arrange_ShortLandscapeFitToWidth();
  } else if (ratio < THRESHOLD_ShortLandscapeFitToHeight) {arrange_ShortLandscapeFitToHeight();
  } else if (ratio < THRESHOLD_LongLandscapeFitToWidth) {arrange_LongLandscapeFitToWidth();
  } else {arrange_LongLandscapeFitToHeight();
  }
}

function arrange_LongPortraitFitToWidth() {
  document.getElementById('div-title-west').style.display = 'none';
  document.getElementById('div-title-north').style.display = 'flex';
  document.getElementById('div-info-east').style.display = 'none';
  document.getElementById('div-info-south').style.display = 'inline';

  var w = window.innerWidth;
  document.getElementById('div-title-north').style.width = w.toString().concat('px');
  document.getElementById('div-title-north').style.height = (w/6).toString().concat('px');
  document.getElementById('div-board-area').style.width = w.toString().concat('px');
  document.getElementById('div-board-area').style.height = w.toString().concat('px');
  document.getElementById('div-info-south').style.width = w.toString().concat('px');
  document.getElementById('div-info-south').style.height = (window.innerHeight-w*7/6).toString().concat('px');

  document.getElementById('board-canvas').style.width = w.toString().concat('px');
  document.getElementById('board-canvas').style.height = w.toString().concat('px');

  document.getElementById('div-logo-north').style.width = (w*4/6).toString().concat('px');
  document.getElementById('button-new-game-north').style.width = (w/6).toString().concat('px');
  document.getElementById('button-full-screen-north').style.width = (w/6).toString().concat('px');
}

function arrange_LongPortraitFitToHeight() {
  document.getElementById('div-title-west').style.display = 'none';
  document.getElementById('div-title-north').style.display = 'flex';
  document.getElementById('div-info-east').style.display = 'none';
  document.getElementById('div-info-south').style.display = 'inline';

  var w = window.innerHeight * THRESHOLD_LongPortraitFitToWidth;
  document.getElementById('div-title-north').style.width = w.toString().concat('px');
  document.getElementById('div-title-north').style.height = (w/6).toString().concat('px');
  document.getElementById('div-board-area').style.width = w.toString().concat('px');
  document.getElementById('div-board-area').style.height = w.toString().concat('px');
  document.getElementById('div-info-south').style.width = w.toString().concat('px');
  document.getElementById('div-info-south').style.height = (window.innerHeight-w*7/6).toString().concat('px');

  document.getElementById('board-canvas').style.width = w.toString().concat('px');
  document.getElementById('board-canvas').style.height = w.toString().concat('px');

  document.getElementById('div-logo-north').style.width = (w*4/6).toString().concat('px');
  document.getElementById('button-new-game-north').style.width = (w/6).toString().concat('px');
  document.getElementById('button-full-screen-north').style.width = (w/6).toString().concat('px');
}

function arrange_ShortPortraitFitToWidth() {
  document.getElementById('div-title-north').style.display = 'none';
  document.getElementById('div-title-west').style.display = 'flex';
  document.getElementById('div-info-east').style.display = 'none';
  document.getElementById('div-info-south').style.display = 'inline';

  var w = window.innerWidth;
  document.getElementById('div-title-west').style.width = (w/7).toString().concat('px');
  document.getElementById('div-title-west').style.height = (w*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.width = (w*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.height = (w*6/7).toString().concat('px');
  document.getElementById('div-info-south').style.width = w.toString().concat('px');
  document.getElementById('div-info-south').style.height = (window.innerHeight-w*6/7).toString().concat('px');

  document.getElementById('board-canvas').style.width = (w*6/7).toString().concat('px');
  document.getElementById('board-canvas').style.height = (w*6/7).toString().concat('px');

  document.getElementById('div-logo-west').style.height = (w*4/7).toString().concat('px');
  document.getElementById('button-new-game-west').style.height = (w/7).toString().concat('px');
  document.getElementById('button-full-screen-west').style.height = (w/7).toString().concat('px');
}

function arrange_ShortPortraitFitToHeight() {
  document.getElementById('div-title-north').style.display = 'none';
  document.getElementById('div-title-west').style.display = 'flex';
  document.getElementById('div-info-east').style.display = 'none';
  document.getElementById('div-info-south').style.display = 'inline';

  var w = window.innerHeight * THRESHOLD_ShortPortraitFitToWidth;
  document.getElementById('div-title-west').style.width = (w/7).toString().concat('px');
  document.getElementById('div-title-west').style.height = (w*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.width = (w*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.height = (w*6/7).toString().concat('px');
  document.getElementById('div-info-south').style.width = w.toString().concat('px');
  document.getElementById('div-info-south').style.height = (window.innerHeight-w*6/7).toString().concat('px');

  document.getElementById('board-canvas').style.width = (w*6/7).toString().concat('px');
  document.getElementById('board-canvas').style.height = (w*6/7).toString().concat('px');

  document.getElementById('div-logo-west').style.height = (w*4/7).toString().concat('px');
  document.getElementById('button-new-game-west').style.height = (w/7).toString().concat('px');
  document.getElementById('button-full-screen-west').style.height = (w/7).toString().concat('px');
}

function arrange_ShortLandscapeFitToWidth() {
  document.getElementById('div-title-west').style.display = 'none';
  document.getElementById('div-title-north').style.display = 'flex';
  document.getElementById('div-info-south').style.display = 'none';
  document.getElementById('div-info-east').style.display = 'inline';

  var h = window.innerWidth * THRESHOLD_ShortPortraitFitToWidth;
  document.getElementById('div-title-north').style.width = (h*6/7).toString().concat('px');
  document.getElementById('div-title-north').style.height = (h/7).toString().concat('px');
  document.getElementById('div-board-area').style.width = (h*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.height = (h*6/7).toString().concat('px');
  document.getElementById('div-info-east').style.width = (window.innerWidth-h*6/7).toString().concat('px');
  document.getElementById('div-info-east').style.height = (h*6/7).toString().concat('px');

  document.getElementById('board-canvas').style.width = (h*6/7).toString().concat('px');
  document.getElementById('board-canvas').style.height = (h*6/7).toString().concat('px');

  document.getElementById('div-logo-north').style.width = (h*4/7).toString().concat('px');
  document.getElementById('button-new-game-north').style.width = (h/7).toString().concat('px');
  document.getElementById('button-full-screen-north').style.width = (h/7).toString().concat('px');
}

function arrange_ShortLandscapeFitToHeight() {
  document.getElementById('div-title-west').style.display = 'none';
  document.getElementById('div-title-north').style.display = 'flex';
  document.getElementById('div-info-south').style.display = 'none';
  document.getElementById('div-info-east').style.display = 'inline';

  var h = window.innerHeight;
  document.getElementById('div-title-north').style.width = (h*6/7).toString().concat('px');
  document.getElementById('div-title-north').style.height = (h/7).toString().concat('px');
  document.getElementById('div-board-area').style.width = (h*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.height = (h*6/7).toString().concat('px');
  document.getElementById('div-info-east').style.width = (window.innerWidth-h*6/7).toString().concat('px');
  document.getElementById('div-info-east').style.height = (h*6/7).toString().concat('px');

  document.getElementById('board-canvas').style.width = (h*6/7).toString().concat('px');
  document.getElementById('board-canvas').style.height = (h*6/7).toString().concat('px');

  document.getElementById('div-logo-north').style.width = (h*4/7).toString().concat('px');
  document.getElementById('button-new-game-north').style.width = (h/7).toString().concat('px');
  document.getElementById('button-full-screen-north').style.width = (h/7).toString().concat('px');
}

function arrange_LongLandscapeFitToWidth() {
  document.getElementById('div-title-north').style.display = 'none';
  document.getElementById('div-title-west').style.display = 'flex';
  document.getElementById('div-info-south').style.display = 'none';
  document.getElementById('div-info-east').style.display = 'inline';

  var h  = window.innerWidth * THRESHOLD_LongPortraitFitToWidth;
  document.getElementById('div-title-west').style.width = (h/6).toString().concat('px');
  document.getElementById('div-title-west').style.height = h.toString().concat('px');
  document.getElementById('div-board-area').style.width = h.toString().concat('px');
  document.getElementById('div-board-area').style.height = h.toString().concat('px');
  document.getElementById('div-info-east').style.width = (window.innerWidth-h*7/6).toString().concat('px');
  document.getElementById('div-info-east').style.height = h.toString().concat('px');

  document.getElementById('board-canvas').style.width = h.toString().concat('px');
  document.getElementById('board-canvas').style.height = h.toString().concat('px');

  document.getElementById('div-logo-west').style.height = (h*4/6).toString().concat('px');
  document.getElementById('button-new-game-west').style.height = (h/6).toString().concat('px');
  document.getElementById('button-full-screen-west').style.height = (h/6).toString().concat('px');
}

function arrange_LongLandscapeFitToHeight() {
  document.getElementById('div-title-north').style.display = 'none';
  document.getElementById('div-title-west').style.display = 'flex';
  document.getElementById('div-info-south').style.display = 'none';
  document.getElementById('div-info-east').style.display = 'inline';

  var h  = window.innerHeight;
  document.getElementById('div-title-west').style.width = (h/6).toString().concat('px');
  document.getElementById('div-title-west').style.height = h.toString().concat('px');
  document.getElementById('div-board-area').style.width = h.toString().concat('px');
  document.getElementById('div-board-area').style.height = h.toString().concat('px');
  document.getElementById('div-info-east').style.width = (window.innerWidth-h*7/6).toString().concat('px');
  document.getElementById('div-info-east').style.height = h.toString().concat('px');

  document.getElementById('board-canvas').style.width = h.toString().concat('px');
  document.getElementById('board-canvas').style.height = h.toString().concat('px');

  document.getElementById('div-logo-west').style.height = (h*4/6).toString().concat('px');
  document.getElementById('button-new-game-west').style.height = (h/6).toString().concat('px');
  document.getElementById('button-full-screen-west').style.height = (h/6).toString().concat('px');
}

function toggle_full_screen() {
  if (!document.fullscreenElement) {
    alert('Attempting full screen');
    document.body.requestFullscreen;
  } else {
    alert('Exiting full screen');
    document.exitFullscreen();
  }
}

window.onresize = reorganise;
window.onload = reorganise;
<commit_msg>Correct the calling of the full screen function<commit_after>// Arbitrary numbers chosen to ensure Long Portrait mode fits into Chrome on Android.
// Firefox uses less vertical space for the URL bar so Long Portrait will be available in both.
// 270 is six times 45, as board is twelve squares and logo is two.
// 73 is the remaining 3.24444 squares that can fit into the Chrome window.
// Scaled up until all values are integers for ease of reading.
const THRESHOLD_LongPortraitFitToWidth = 270/(45+270+73);
const THRESHOLD_LongPortraitFitToHeight = (45+270)/(45+270+73);
const THRESHOLD_ShortPortraitFitToWidth = (45+270)/(270+73);
const THRESHOLD_ShortPortraitFitToHeight = 1;
const THRESHOLD_ShortLandscapeFitToWidth = (270+73)/(45+270);
const THRESHOLD_ShortLandscapeFitToHeight = (45+270+73)/(45+270);
const THRESHOLD_LongLandscapeFitToWidth = (45+270+73)/270;

function reorganise() {
  ratio = window.innerWidth / window.innerHeight;
  if (ratio < THRESHOLD_LongPortraitFitToWidth) {arrange_LongPortraitFitToWidth();
  } else if (ratio < THRESHOLD_LongPortraitFitToHeight) {arrange_LongPortraitFitToHeight();
  } else if (ratio < THRESHOLD_ShortPortraitFitToWidth) {arrange_ShortPortraitFitToWidth();
  } else if (ratio < THRESHOLD_ShortPortraitFitToHeight) {arrange_ShortPortraitFitToHeight();
  } else if (ratio < THRESHOLD_ShortLandscapeFitToWidth) {arrange_ShortLandscapeFitToWidth();
  } else if (ratio < THRESHOLD_ShortLandscapeFitToHeight) {arrange_ShortLandscapeFitToHeight();
  } else if (ratio < THRESHOLD_LongLandscapeFitToWidth) {arrange_LongLandscapeFitToWidth();
  } else {arrange_LongLandscapeFitToHeight();
  }
}

function arrange_LongPortraitFitToWidth() {
  document.getElementById('div-title-west').style.display = 'none';
  document.getElementById('div-title-north').style.display = 'flex';
  document.getElementById('div-info-east').style.display = 'none';
  document.getElementById('div-info-south').style.display = 'inline';

  var w = window.innerWidth;
  document.getElementById('div-title-north').style.width = w.toString().concat('px');
  document.getElementById('div-title-north').style.height = (w/6).toString().concat('px');
  document.getElementById('div-board-area').style.width = w.toString().concat('px');
  document.getElementById('div-board-area').style.height = w.toString().concat('px');
  document.getElementById('div-info-south').style.width = w.toString().concat('px');
  document.getElementById('div-info-south').style.height = (window.innerHeight-w*7/6).toString().concat('px');

  document.getElementById('board-canvas').style.width = w.toString().concat('px');
  document.getElementById('board-canvas').style.height = w.toString().concat('px');

  document.getElementById('div-logo-north').style.width = (w*4/6).toString().concat('px');
  document.getElementById('button-new-game-north').style.width = (w/6).toString().concat('px');
  document.getElementById('button-full-screen-north').style.width = (w/6).toString().concat('px');
}

function arrange_LongPortraitFitToHeight() {
  document.getElementById('div-title-west').style.display = 'none';
  document.getElementById('div-title-north').style.display = 'flex';
  document.getElementById('div-info-east').style.display = 'none';
  document.getElementById('div-info-south').style.display = 'inline';

  var w = window.innerHeight * THRESHOLD_LongPortraitFitToWidth;
  document.getElementById('div-title-north').style.width = w.toString().concat('px');
  document.getElementById('div-title-north').style.height = (w/6).toString().concat('px');
  document.getElementById('div-board-area').style.width = w.toString().concat('px');
  document.getElementById('div-board-area').style.height = w.toString().concat('px');
  document.getElementById('div-info-south').style.width = w.toString().concat('px');
  document.getElementById('div-info-south').style.height = (window.innerHeight-w*7/6).toString().concat('px');

  document.getElementById('board-canvas').style.width = w.toString().concat('px');
  document.getElementById('board-canvas').style.height = w.toString().concat('px');

  document.getElementById('div-logo-north').style.width = (w*4/6).toString().concat('px');
  document.getElementById('button-new-game-north').style.width = (w/6).toString().concat('px');
  document.getElementById('button-full-screen-north').style.width = (w/6).toString().concat('px');
}

function arrange_ShortPortraitFitToWidth() {
  document.getElementById('div-title-north').style.display = 'none';
  document.getElementById('div-title-west').style.display = 'flex';
  document.getElementById('div-info-east').style.display = 'none';
  document.getElementById('div-info-south').style.display = 'inline';

  var w = window.innerWidth;
  document.getElementById('div-title-west').style.width = (w/7).toString().concat('px');
  document.getElementById('div-title-west').style.height = (w*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.width = (w*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.height = (w*6/7).toString().concat('px');
  document.getElementById('div-info-south').style.width = w.toString().concat('px');
  document.getElementById('div-info-south').style.height = (window.innerHeight-w*6/7).toString().concat('px');

  document.getElementById('board-canvas').style.width = (w*6/7).toString().concat('px');
  document.getElementById('board-canvas').style.height = (w*6/7).toString().concat('px');

  document.getElementById('div-logo-west').style.height = (w*4/7).toString().concat('px');
  document.getElementById('button-new-game-west').style.height = (w/7).toString().concat('px');
  document.getElementById('button-full-screen-west').style.height = (w/7).toString().concat('px');
}

function arrange_ShortPortraitFitToHeight() {
  document.getElementById('div-title-north').style.display = 'none';
  document.getElementById('div-title-west').style.display = 'flex';
  document.getElementById('div-info-east').style.display = 'none';
  document.getElementById('div-info-south').style.display = 'inline';

  var w = window.innerHeight * THRESHOLD_ShortPortraitFitToWidth;
  document.getElementById('div-title-west').style.width = (w/7).toString().concat('px');
  document.getElementById('div-title-west').style.height = (w*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.width = (w*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.height = (w*6/7).toString().concat('px');
  document.getElementById('div-info-south').style.width = w.toString().concat('px');
  document.getElementById('div-info-south').style.height = (window.innerHeight-w*6/7).toString().concat('px');

  document.getElementById('board-canvas').style.width = (w*6/7).toString().concat('px');
  document.getElementById('board-canvas').style.height = (w*6/7).toString().concat('px');

  document.getElementById('div-logo-west').style.height = (w*4/7).toString().concat('px');
  document.getElementById('button-new-game-west').style.height = (w/7).toString().concat('px');
  document.getElementById('button-full-screen-west').style.height = (w/7).toString().concat('px');
}

function arrange_ShortLandscapeFitToWidth() {
  document.getElementById('div-title-west').style.display = 'none';
  document.getElementById('div-title-north').style.display = 'flex';
  document.getElementById('div-info-south').style.display = 'none';
  document.getElementById('div-info-east').style.display = 'inline';

  var h = window.innerWidth * THRESHOLD_ShortPortraitFitToWidth;
  document.getElementById('div-title-north').style.width = (h*6/7).toString().concat('px');
  document.getElementById('div-title-north').style.height = (h/7).toString().concat('px');
  document.getElementById('div-board-area').style.width = (h*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.height = (h*6/7).toString().concat('px');
  document.getElementById('div-info-east').style.width = (window.innerWidth-h*6/7).toString().concat('px');
  document.getElementById('div-info-east').style.height = (h*6/7).toString().concat('px');

  document.getElementById('board-canvas').style.width = (h*6/7).toString().concat('px');
  document.getElementById('board-canvas').style.height = (h*6/7).toString().concat('px');

  document.getElementById('div-logo-north').style.width = (h*4/7).toString().concat('px');
  document.getElementById('button-new-game-north').style.width = (h/7).toString().concat('px');
  document.getElementById('button-full-screen-north').style.width = (h/7).toString().concat('px');
}

function arrange_ShortLandscapeFitToHeight() {
  document.getElementById('div-title-west').style.display = 'none';
  document.getElementById('div-title-north').style.display = 'flex';
  document.getElementById('div-info-south').style.display = 'none';
  document.getElementById('div-info-east').style.display = 'inline';

  var h = window.innerHeight;
  document.getElementById('div-title-north').style.width = (h*6/7).toString().concat('px');
  document.getElementById('div-title-north').style.height = (h/7).toString().concat('px');
  document.getElementById('div-board-area').style.width = (h*6/7).toString().concat('px');
  document.getElementById('div-board-area').style.height = (h*6/7).toString().concat('px');
  document.getElementById('div-info-east').style.width = (window.innerWidth-h*6/7).toString().concat('px');
  document.getElementById('div-info-east').style.height = (h*6/7).toString().concat('px');

  document.getElementById('board-canvas').style.width = (h*6/7).toString().concat('px');
  document.getElementById('board-canvas').style.height = (h*6/7).toString().concat('px');

  document.getElementById('div-logo-north').style.width = (h*4/7).toString().concat('px');
  document.getElementById('button-new-game-north').style.width = (h/7).toString().concat('px');
  document.getElementById('button-full-screen-north').style.width = (h/7).toString().concat('px');
}

function arrange_LongLandscapeFitToWidth() {
  document.getElementById('div-title-north').style.display = 'none';
  document.getElementById('div-title-west').style.display = 'flex';
  document.getElementById('div-info-south').style.display = 'none';
  document.getElementById('div-info-east').style.display = 'inline';

  var h  = window.innerWidth * THRESHOLD_LongPortraitFitToWidth;
  document.getElementById('div-title-west').style.width = (h/6).toString().concat('px');
  document.getElementById('div-title-west').style.height = h.toString().concat('px');
  document.getElementById('div-board-area').style.width = h.toString().concat('px');
  document.getElementById('div-board-area').style.height = h.toString().concat('px');
  document.getElementById('div-info-east').style.width = (window.innerWidth-h*7/6).toString().concat('px');
  document.getElementById('div-info-east').style.height = h.toString().concat('px');

  document.getElementById('board-canvas').style.width = h.toString().concat('px');
  document.getElementById('board-canvas').style.height = h.toString().concat('px');

  document.getElementById('div-logo-west').style.height = (h*4/6).toString().concat('px');
  document.getElementById('button-new-game-west').style.height = (h/6).toString().concat('px');
  document.getElementById('button-full-screen-west').style.height = (h/6).toString().concat('px');
}

function arrange_LongLandscapeFitToHeight() {
  document.getElementById('div-title-north').style.display = 'none';
  document.getElementById('div-title-west').style.display = 'flex';
  document.getElementById('div-info-south').style.display = 'none';
  document.getElementById('div-info-east').style.display = 'inline';

  var h  = window.innerHeight;
  document.getElementById('div-title-west').style.width = (h/6).toString().concat('px');
  document.getElementById('div-title-west').style.height = h.toString().concat('px');
  document.getElementById('div-board-area').style.width = h.toString().concat('px');
  document.getElementById('div-board-area').style.height = h.toString().concat('px');
  document.getElementById('div-info-east').style.width = (window.innerWidth-h*7/6).toString().concat('px');
  document.getElementById('div-info-east').style.height = h.toString().concat('px');

  document.getElementById('board-canvas').style.width = h.toString().concat('px');
  document.getElementById('board-canvas').style.height = h.toString().concat('px');

  document.getElementById('div-logo-west').style.height = (h*4/6).toString().concat('px');
  document.getElementById('button-new-game-west').style.height = (h/6).toString().concat('px');
  document.getElementById('button-full-screen-west').style.height = (h/6).toString().concat('px');
}

function toggle_full_screen() {
  if (!document.fullscreenElement) {
    alert('Attempting full screen');
    document.getElementById('div-outer-vertical-flexbox').requestFullscreen();
  } else {
    alert('Exiting full screen');
    document.exitFullscreen();
  }
}

window.onresize = reorganise;
window.onload = reorganise;
<|endoftext|>


<commit_before>import React from 'react'
import Helmet from "react-helmet"

import { prefixLink } from 'gatsby-helpers'
import { TypographyStyle, GoogleFont } from 'react-typography'
import typography from './utils/typography'

const BUILD_TIME = Date.now();

module.exports = React.createClass({
  propTypes () {
    return {
      body: React.PropTypes.string,
    }
  },
  render () {
    const head = Helmet.rewind();

    let css;

    if (process.env.NODE_ENV === 'production') {
      css =


<commit_before>import React from 'react'
import DocumentTitle from 'react-document-title'
import { prefixLink } from 'gatsby-helpers'

const BUILD_TIME = new Date().getTime()

module.exports = React.createClass({
    displayName: 'HTML',
    propTypes: {
        body: React.PropTypes.string,
    },
    render() {
        const {body, route} = this.props
        const title = DocumentTitle.rewind()
        const font = <link href='https://fonts.googleapis.com/css?family=Roboto:400,400italic,500,700&subset=latin,cyrillic' rel='stylesheet' type='text/css' />
        let css
        if (process.env.NODE_ENV === 'production') {
            css =


<commit_before>/**
 * @author  John Resig <jeresig@gmail.com>
 * @author  Originally by Marcus Spiegel <marcus.spiegel@gmail.com>
 * @link    https://github.com/jeresig/i18n-node
 * @license http://opensource.org/licenses/MIT
 *
 * @version 0.4.4
 */

// dependencies
var vsprintf = require("sprintf").vsprintf,
	fs = require("fs"),
	path = require("path");

var i18n = module.exports = function(opt) {
	var self = this;

	// Put into dev or production mode
	this.devMode = process.env.NODE_ENV !== "production";

	// Copy over options
	for (var prop in opt) {
		this[prop] = opt[prop];
	}

	// you may register helpers in global scope, up to you
	if (typeof this.register === "object") {
		i18n.registerMethods.forEach(function(method) {
			self.register[method] = self[method].bind(self);
		});
	}

	// implicitly read all locales
	// if it's an array of locale names, read in the data
	if (opt.locales && opt.locales.forEach) {
		this.locales = {};

		opt.locales.forEach(function(locale) {
			self.readFile(locale);
		});

		this.defaultLocale = opt.locales[0];
	}

	// Set the locale to the default locale
	this.setLocale(this.defaultLocale);

	// Check the defaultLocale
	if (!this.locales[this.defaultLocale]) {
		console.error("Not a valid default locale.");
	}

	if (this.request) {
		if (this.subdomain) {
			this.setLocaleFromSubdomain(this.request);
		} else if (this.query) {
			this.setLocaleFromQuery(this.request);
		} else {
			this.setLocaleFromPath(this.request);
		}
		this.prefLocale = this.preferredLocale();
	}
};

i18n.version = "0.4.4";

i18n.localeCache = {};
i18n.resMethods = ["__", "__n", "getLocale", "isPreferredLocale"];

i18n.expressBind = function(app, opt) {
	if (!app) {
		return;
	}

	app.use(function(req, res, next) {
		opt.request = req;
		req.i18n = new i18n(opt);

		// Express 3
		if (res.locals) {
			i18n.registerMethods(res.locals)
		}

		next();
	});

	// Express 2
	if (app.dynamicHelpers) {
		app.dynamicHelpers(i18n.registerMethods({}));
	}
};

i18n.registerMethods = function(helpers) {
	i18n.resMethods.forEach(function(method) {
		helpers[method] = function(req) {
			return req.i18n[method].bind(req.i18n);
		};
	});

	return helpers;
};

i18n.prototype = {
	defaultLocale: "en",
	extension: ".js",
	directory: "./locales",

	__: function() {
		var msg = this.translate(this.locale, arguments[0]);

		if (arguments.length > 1) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 1));
		}

		return msg;
	},

	__n: function(singular, plural, count) {
		var msg = this.translate(this.locale, singular, plural);

		msg = vsprintf(parseInt(count, 10) > 1 ? msg.other : msg.one, [count]);

		if (arguments.length > 3) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 3));
		}

		return msg;
	},

	setLocale: function(locale) {
		if (!this.locales[locale]) {
			if (this.devMode) {
				console.warn("Locale (" + locale + ") not found.");
			}

			locale = this.defaultLocale;
		}

		return (this.locale = locale);
	},

	getLocale: function() {
		return this.locale;
	},

	isPreferredLocale: function() {
		return !this.prefLocale ||
			this.prefLocale === this.getLocale();
	},

	setLocaleFromQuery: function(req) {
		req = req || this.request;

		if (!req || !req.query || !req.query.lang) {
			return;
		}

		var locale = req.query.lang.toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from query: " + locale);
			}

			this.setLocale(locale);
		}
	},

	setLocaleFromSubdomain: function(req) {
		req = req || this.request;

		if (!req || !req.headers || !req.headers.host) {
			return;
		}

		if (/^([^.]+)/.test(req.headers.host) && this.locales[RegExp.$1]) {
			if (this.devMode) {
				console.log("Overriding locale from host: " + RegExp.$1);
			}

			this.setLocale(RegExp.$1);
		}
	},

	// locale in the beginning of the path like: http://suuper.com/en-GB/drill/down/path-to-the-end
	setLocaleFromPath: function(req) {
		req = req || this.request;

		if (!req || !req.path) {
			return;
		}

		// match locale according to: http://www.ietf.org/rfc/rfc1766.txt  (caseinsensitive)
		if (/^\/([a-z]{2}(?:-(?:[A-Z]{2}))*)\//i.test(req.path) && this.locales[RegExp.$1]) {
			if (this.devMode) {
				console.log("Overriding locale from host: " + RegExp.$1);
			}

			this.setLocale(RegExp.$1);
		}
	},

	preferredLocale: function(req) {
		req = req || this.request;

		if (!req || !req.headers) {
			return;
		}

		var accept = req.headers["accept-language"] || "",
			self = this,
			prefLocale = this.defaultLocale;

		(accept.match(/(^|,\s*)([a-z]+)/g) || []).forEach(function(locale) {
			if (!prefLocale && self.locales[locale]) {
				prefLocale = locale;
			}
		});

		return prefLocale;
	},

	// read locale file, translate a msg and write to fs if new
	translate: function(locale, singular, plural) {
		if (!locale || !this.locales[locale]) {
			if (this.devMode) {
				console.warn("WARN: No locale found. Using the default (" +
					this.defaultLocale + ") as current locale");
			}

			locale = this.defaultLocale;

			this.initLocale(locale, {});
		}

		if (!this.locales[locale][singular]) {
			this.locales[locale][singular] = plural ?
				{ one: singular, other: plural } :
				singular;

			if (this.devMode) {
				this.writeFile(locale);
			}
		}

		return this.locales[locale][singular];
	},

	// try reading a file
	readFile: function(locale) {
		var file = this.locateFile(locale);

		if (!this.devMode && i18n.localeCache[file]) {
			this.initLocale(locale, i18n.localeCache[file]);
			return;
		}

		try {
			var localeFile = fs.readFileSync(file);

			try {
				// parsing filecontents to locales[locale]
				this.initLocale(locale, JSON.parse(localeFile));

			} catch (e) {
				console.error('unable to parse locales from file (maybe ' + file +
					' is empty or invalid json?): ', e);
			}

		} catch (e) {
			// unable to read, so intialize that file
			// locales[locale] are already set in memory, so no extra read required
			// or locales[locale] are empty, which initializes an empty locale.json file
			this.writeFile(locale);
		}
	},

	// try writing a file in a created directory
	writeFile: function(locale) {
		// don't write new locale information to disk if we're not in dev mode
		if (!this.devMode) {
			// Initialize the locale if didn't exist already
			this.initLocale(locale, {});
		}

		// creating directory if necessary
		try {
			fs.lstatSync(this.directory);

		} catch (e) {
			if (this.devMode) {
				console.log('creating locales dir in: ' + this.directory);
			}

			fs.mkdirSync(this.directory, 0755);
		}

		// Initialize the locale if didn't exist already
		this.initLocale(locale, {});

		// writing to tmp and rename on success
		try {
			var target = this.locateFile(locale),
				tmp = target + ".tmp";

			fs.writeFileSync(tmp, JSON.stringify(
				this.locales[locale], null, "\t"), "utf8");

			if (fs.statSync(tmp).isFile()) {
				fs.renameSync(tmp, target);

			} else {
				console.error('unable to write locales to file (either ' + tmp +
					' or ' + target + ' are not writeable?): ', e);
			}

		} catch (e) {
			console.error('unexpected error writing files (either ' + tmp +
				' or ' + target + ' are not writeable?): ', e);
		}
	},

	// basic normalization of filepath
	locateFile: function(locale) {
		return path.normalize(this.directory + '/' + locale + this.extension);
	},

	initLocale: function(locale, data) {
		if (!this.locales[locale]) {
			this.locales[locale] = data;

			// Only cache the files when we're not in dev mode
			if (!this.devMode) {
			    var file = this.locateFile(locale);
				if ( !i18n.localeCache[file] ) {
			    	i18n.localeCache[file] = data;
				}
			}
		}
	}
};
<commit_msg>restricted locale to be the first segment in the path<commit_after>/**
 * @author  John Resig <jeresig@gmail.com>
 * @author  Originally by Marcus Spiegel <marcus.spiegel@gmail.com>
 * @link    https://github.com/jeresig/i18n-node
 * @license http://opensource.org/licenses/MIT
 *
 * @version 0.4.4
 */

// dependencies
var vsprintf = require("sprintf").vsprintf,
	fs = require("fs"),
	path = require("path");

var i18n = module.exports = function(opt) {
	var self = this;

	// Put into dev or production mode
	this.devMode = process.env.NODE_ENV !== "production";

	// Copy over options
	for (var prop in opt) {
		this[prop] = opt[prop];
	}

	// you may register helpers in global scope, up to you
	if (typeof this.register === "object") {
		i18n.registerMethods.forEach(function(method) {
			self.register[method] = self[method].bind(self);
		});
	}

	// implicitly read all locales
	// if it's an array of locale names, read in the data
	if (opt.locales && opt.locales.forEach) {
		this.locales = {};

		opt.locales.forEach(function(locale) {
			self.readFile(locale);
		});

		this.defaultLocale = opt.locales[0];
	}

	// Set the locale to the default locale
	this.setLocale(this.defaultLocale);

	// Check the defaultLocale
	if (!this.locales[this.defaultLocale]) {
		console.error("Not a valid default locale.");
	}

	if (this.request) {
		if (this.subdomain) {
			this.setLocaleFromSubdomain(this.request);
		} else if (this.query) {
			this.setLocaleFromQuery(this.request);
		} else {
			this.setLocaleFromPath(this.request);
		}
		this.prefLocale = this.preferredLocale();
	}
};

i18n.version = "0.4.4";

i18n.localeCache = {};
i18n.resMethods = ["__", "__n", "getLocale", "isPreferredLocale"];

i18n.expressBind = function(app, opt) {
	if (!app) {
		return;
	}

	app.use(function(req, res, next) {
		opt.request = req;
		req.i18n = new i18n(opt);

		// Express 3
		if (res.locals) {
			i18n.registerMethods(res.locals)
		}

		next();
	});

	// Express 2
	if (app.dynamicHelpers) {
		app.dynamicHelpers(i18n.registerMethods({}));
	}
};

i18n.registerMethods = function(helpers) {
	i18n.resMethods.forEach(function(method) {
		helpers[method] = function(req) {
			return req.i18n[method].bind(req.i18n);
		};
	});

	return helpers;
};

i18n.prototype = {
	defaultLocale: "en",
	extension: ".js",
	directory: "./locales",

	__: function() {
		var msg = this.translate(this.locale, arguments[0]);

		if (arguments.length > 1) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 1));
		}

		return msg;
	},

	__n: function(singular, plural, count) {
		var msg = this.translate(this.locale, singular, plural);

		msg = vsprintf(parseInt(count, 10) > 1 ? msg.other : msg.one, [count]);

		if (arguments.length > 3) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 3));
		}

		return msg;
	},

	setLocale: function(locale) {
		if (!this.locales[locale]) {
			if (this.devMode) {
				console.warn("Locale (" + locale + ") not found.");
			}

			locale = this.defaultLocale;
		}

		return (this.locale = locale);
	},

	getLocale: function() {
		return this.locale;
	},

	isPreferredLocale: function() {
		return !this.prefLocale ||
			this.prefLocale === this.getLocale();
	},

	setLocaleFromQuery: function(req) {
		req = req || this.request;

		if (!req || !req.query || !req.query.lang) {
			return;
		}

		var locale = req.query.lang.toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from query: " + locale);
			}

			this.setLocale(locale);
		}
	},

	setLocaleFromSubdomain: function(req) {
		req = req || this.request;

		if (!req || !req.headers || !req.headers.host) {
			return;
		}

		if (/^([^.]+)/.test(req.headers.host) && this.locales[RegExp.$1]) {
			if (this.devMode) {
				console.log("Overriding locale from host: " + RegExp.$1);
			}

			this.setLocale(RegExp.$1);
		}
	},

	// locale in the beginning of the path like: http://suuper.com/en-GB/drill/down/path-to-the-end
	setLocaleFromPath: function(req) {
		req = req || this.request;

		if (!req || !req.path) {
			return;
		}

		// match locale according to: http://www.ietf.org/rfc/rfc1766.txt  (caseinsensitive)
		if (/\/([a-z]{2}(?:-(?:[A-Z]{2}))*)\//i.test(req.path) && this.locales[RegExp.$1]) {
			if (this.devMode) {
				console.log("Overriding locale from host: " + RegExp.$1);
			}

			this.setLocale(RegExp.$1);
		}
	},

	preferredLocale: function(req) {
		req = req || this.request;

		if (!req || !req.headers) {
			return;
		}

		var accept = req.headers["accept-language"] || "",
			self = this,
			prefLocale = this.defaultLocale;

		(accept.match(/(^|,\s*)([a-z]+)/g) || []).forEach(function(locale) {
			if (!prefLocale && self.locales[locale]) {
				prefLocale = locale;
			}
		});

		return prefLocale;
	},

	// read locale file, translate a msg and write to fs if new
	translate: function(locale, singular, plural) {
		if (!locale || !this.locales[locale]) {
			if (this.devMode) {
				console.warn("WARN: No locale found. Using the default (" +
					this.defaultLocale + ") as current locale");
			}

			locale = this.defaultLocale;

			this.initLocale(locale, {});
		}

		if (!this.locales[locale][singular]) {
			this.locales[locale][singular] = plural ?
				{ one: singular, other: plural } :
				singular;

			if (this.devMode) {
				this.writeFile(locale);
			}
		}

		return this.locales[locale][singular];
	},

	// try reading a file
	readFile: function(locale) {
		var file = this.locateFile(locale);

		if (!this.devMode && i18n.localeCache[file]) {
			this.initLocale(locale, i18n.localeCache[file]);
			return;
		}

		try {
			var localeFile = fs.readFileSync(file);

			try {
				// parsing filecontents to locales[locale]
				this.initLocale(locale, JSON.parse(localeFile));

			} catch (e) {
				console.error('unable to parse locales from file (maybe ' + file +
					' is empty or invalid json?): ', e);
			}

		} catch (e) {
			// unable to read, so intialize that file
			// locales[locale] are already set in memory, so no extra read required
			// or locales[locale] are empty, which initializes an empty locale.json file
			this.writeFile(locale);
		}
	},

	// try writing a file in a created directory
	writeFile: function(locale) {
		// don't write new locale information to disk if we're not in dev mode
		if (!this.devMode) {
			// Initialize the locale if didn't exist already
			this.initLocale(locale, {});
		}

		// creating directory if necessary
		try {
			fs.lstatSync(this.directory);

		} catch (e) {
			if (this.devMode) {
				console.log('creating locales dir in: ' + this.directory);
			}

			fs.mkdirSync(this.directory, 0755);
		}

		// Initialize the locale if didn't exist already
		this.initLocale(locale, {});

		// writing to tmp and rename on success
		try {
			var target = this.locateFile(locale),
				tmp = target + ".tmp";

			fs.writeFileSync(tmp, JSON.stringify(
				this.locales[locale], null, "\t"), "utf8");

			if (fs.statSync(tmp).isFile()) {
				fs.renameSync(tmp, target);

			} else {
				console.error('unable to write locales to file (either ' + tmp +
					' or ' + target + ' are not writeable?): ', e);
			}

		} catch (e) {
			console.error('unexpected error writing files (either ' + tmp +
				' or ' + target + ' are not writeable?): ', e);
		}
	},

	// basic normalization of filepath
	locateFile: function(locale) {
		return path.normalize(this.directory + '/' + locale + this.extension);
	},

	initLocale: function(locale, data) {
		if (!this.locales[locale]) {
			this.locales[locale] = data;

			// Only cache the files when we're not in dev mode
			if (!this.devMode) {
			    var file = this.locateFile(locale);
				if ( !i18n.localeCache[file] ) {
			    	i18n.localeCache[file] = data;
				}
			}
		}
	}
};
<|endoftext|>


<commit_before>/*
 * @package jsDAV
 * @subpackage DAV
 * @copyright Copyright(c) 2011 Ajax.org B.V. <info AT ajax DOT org>
 * @author Mike de Boer <info AT mikedeboer DOT nl>
 * @license http://github.com/mikedeboer/jsDAV/blob/master/LICENSE MIT License
 */
"use strict";

var jsDAV      = require("./../jsdav");
var jsDAV_Tree = require("./tree").jsDAV_Tree;

var Async      = require("./../../support/async.js");
var Util       = require("./util");
var Exc        = require("./exceptions");

/**
 * ObjectTree class
 *
 * This implementation of the Tree class makes use of the INode, IFile and ICollection API's
 */
function jsDAV_ObjectTree(rootNode) {
    this.rootNode = rootNode;
}

exports.jsDAV_ObjectTree = jsDAV_ObjectTree;

(function() {
    this.REGBASE = this.REGBASE | jsDAV.__OBJECTTREE__;

    /**
     * Returns the iNode object for the requested path
     *
     * @param {String} path
     * @return jsDAV_iNode
     */
    this.getNodeForPath = function(path, cbgetnodepath) {
        path = Util.trim(path, "/");

        //if (!path || path=='.') return this.rootNode;
        var currentNode = this.rootNode;
        var c           = path.split("/");
        var i           = 0;
        var l           = c.length;
        // We're splitting up the path variable into folder/subfolder components
        // and traverse to the correct node..
        Async.range(i, l - 1)
             .each(function(pathPart, cbnextnpath) {
                // If this part of the path is just a dot, it actually means we can skip it
                if (pathPart == "." || pathPart === "")
                    return cbnextnpath();
                if (!currentNode.hasFeature(jsDAV.__ICOLLECTION__))
                    return cbnextnpath(new Exc.jsDAV_Exception_FileNotFound("Could not find node at path: " + path));

                currentNode.getChild(pathPart, function(err, crt) {
                    if (err)
                        return cbnextnpath(err);
                    currentNode = crt;
                    cbnextnpath();
                });
             })
             .end(function(err) {
                 if (err)
                     return cbgetnodepath(err);
                 cbgetnodepath(null, currentNode);
             });
    };
}).call(jsDAV_ObjectTree.prototype = new jsDAV_Tree());
<commit_msg>Guard against currentNode === undefined<commit_after>/*
 * @package jsDAV
 * @subpackage DAV
 * @copyright Copyright(c) 2011 Ajax.org B.V. <info AT ajax DOT org>
 * @author Mike de Boer <info AT mikedeboer DOT nl>
 * @license http://github.com/mikedeboer/jsDAV/blob/master/LICENSE MIT License
 */
"use strict";

var jsDAV      = require("./../jsdav");
var jsDAV_Tree = require("./tree").jsDAV_Tree;

var Async      = require("./../../support/async.js");
var Util       = require("./util");
var Exc        = require("./exceptions");

/**
 * ObjectTree class
 *
 * This implementation of the Tree class makes use of the INode, IFile and ICollection API's
 */
function jsDAV_ObjectTree(rootNode) {
    this.rootNode = rootNode;
}

exports.jsDAV_ObjectTree = jsDAV_ObjectTree;

(function() {
    this.REGBASE = this.REGBASE | jsDAV.__OBJECTTREE__;

    /**
     * Returns the iNode object for the requested path
     *
     * @param {String} path
     * @return jsDAV_iNode
     */
    this.getNodeForPath = function(path, cbgetnodepath) {
        path = Util.trim(path, "/");

        //if (!path || path=='.') return this.rootNode;
        var currentNode = this.rootNode;
        var c           = path.split("/");
        var i           = 0;
        var l           = c.length;
        // We're splitting up the path variable into folder/subfolder components
        // and traverse to the correct node..
        Async.range(i, l - 1)
             .each(function(pathPart, cbnextnpath) {
                // If this part of the path is just a dot, it actually means we can skip it
                if (pathPart == "." || pathPart === "")
                    return cbnextnpath();
                if (currentNode === undefined || !currentNode.hasFeature(jsDAV.__ICOLLECTION__))
                    return cbnextnpath(new Exc.jsDAV_Exception_FileNotFound("Could not find node at path: " + path));

                currentNode.getChild(pathPart, function(err, crt) {
                    if (err)
                        return cbnextnpath(err);
                    currentNode = crt;
                    cbnextnpath();
                });
             })
             .end(function(err) {
                 if (err)
                     return cbgetnodepath(err);
                 cbgetnodepath(null, currentNode);
             });
    };
}).call(jsDAV_ObjectTree.prototype = new jsDAV_Tree());
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

if (typeof process !== "undefined") {
    require("amd-loader");
}

define(function(require, exports, module) {
"use strict";

var config = require("ace/config");
var assert = require("./test/assertions");

module.exports = {

    "test path resolution" : function() {
        config.set("packaged", "true");
        var url = config.moduleUrl("kr_theme", "theme");
        assert.equal(url, "theme-kr.js");

        config.set("basePath", "a/b");
        url = config.moduleUrl("m/theme", "theme");
        assert.equal(url, "a/b/theme-m.js");

        url = config.moduleUrl("m/theme", "ext");
        assert.equal(url, "a/b/ext-theme.js");

        config.set("workerPath", "c/");
        url = config.moduleUrl("foo/1", "worker");
        assert.equal(url, "c/worker-1.js");

        config.setModuleUrl("foo/1", "a/b1.js");
        url = config.moduleUrl("foo/1", "theme");
        assert.equal(url, "a/b1.js");

        assert.equal();
    }
};

});

if (typeof module !== "undefined" && module === require.main) {
    require("asyncjs").test.testcase(module.exports).exec()
}
<commit_msg>fix test<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

if (typeof process !== "undefined") {
    require("amd-loader");
}

define(function(require, exports, module) {
"use strict";

var config = require("./config");
var assert = require("./test/assertions");

module.exports = {

    "test path resolution" : function() {
        config.set("packaged", "true");
        var url = config.moduleUrl("kr_theme", "theme");
        assert.equal(url, "theme-kr.js");

        config.set("basePath", "a/b");
        url = config.moduleUrl("m/theme", "theme");
        assert.equal(url, "a/b/theme-m.js");

        url = config.moduleUrl("m/theme", "ext");
        assert.equal(url, "a/b/ext-theme.js");

        config.set("workerPath", "c/");
        url = config.moduleUrl("foo/1", "worker");
        assert.equal(url, "c/worker-1.js");

        config.setModuleUrl("foo/1", "a/b1.js");
        url = config.moduleUrl("foo/1", "theme");
        assert.equal(url, "a/b1.js");

        assert.equal();
    }
};

});

if (typeof module !== "undefined" && module === require.main) {
    require("asyncjs").test.testcase(module.exports).exec()
}
<|endoftext|>


<commit_before>function DroongaProtocolConnectionWrapper(connection, callback, options) {
  this._connection = connection;
  this._callback = callback;
  this._options = options;
}
DroongaProtocolConnectionWrapper.prototype = {
  emit: function(event, data, callback) {
    if (callback) {
      var originalCallback = callback;
      callback = function(error, response) {
        originalCallback(error, response.body);
      };
    } else {
      callback = this._callback;
    }
    this._connection.emitMessage(event, data, callback, this._options);
  },
  destroy: function() {
    delete this._connection;
    delete this._callback;
    delete this._options;
  }
};
exports.DroongaProtocolConnectionWrapper = DroongaProtocolConnectionWrapper;

function SocketIOClientSocketWrapper(socket, options) {
  this._socket = socket;
  this._options = options || {};
}
SocketIOClientSocketWrapper.prototype = {
  emit: function(event, data) {
    if (this._options.event)
      event = this._options.event;
    this._socket.emit(event, data);
  },
  destroy: function() {
    delete this._socket;
  }
};
exports.SocketIOClientSocketWrapper = SocketIOClientSocketWrapper;
<commit_msg>Accept null response<commit_after>function DroongaProtocolConnectionWrapper(connection, callback, options) {
  this._connection = connection;
  this._callback = callback;
  this._options = options;
}
DroongaProtocolConnectionWrapper.prototype = {
  emit: function(event, data, callback) {
    if (callback) {
      var originalCallback = callback;
      callback = function(error, response) {
        originalCallback(error, response && response.body);
      };
    } else {
      callback = this._callback;
    }
    this._connection.emitMessage(event, data, callback, this._options);
  },
  destroy: function() {
    delete this._connection;
    delete this._callback;
    delete this._options;
  }
};
exports.DroongaProtocolConnectionWrapper = DroongaProtocolConnectionWrapper;

function SocketIOClientSocketWrapper(socket, options) {
  this._socket = socket;
  this._options = options || {};
}
SocketIOClientSocketWrapper.prototype = {
  emit: function(event, data) {
    if (this._options.event)
      event = this._options.event;
    this._socket.emit(event, data);
  },
  destroy: function() {
    delete this._socket;
  }
};
exports.SocketIOClientSocketWrapper = SocketIOClientSocketWrapper;
<|endoftext|>


<commit_before>'use strict'

const LRU = require('lru-cache');
const array_stream = require('../array_stream');
const resolve = require('path').resolve;
const readFile = require('fs').readFile;
const cache_options = {
    max: 500,
    dispose: (key, value) => {
        console.log('Cache remove:', key);
    }
};

module.exports = (entrypoint) => {

    entrypoint.module_root = entrypoint.base = '/node_modules/';

    return {
        cache: LRU(cache_options),
        read: (instance, listener, options) => {

            if (options.session) {
                // TODO access check
            }

            const stream = array_stream();
            stream.on('error', console.error.bind(console));

            readFile(resolve('./instance.nq'), (err, data) => {

                if (err) {
                    return stream.emit('error', err);
                }

                let triples = [];
                data = data.toString().split('\n');
                data.forEach((triple, index) => {
                    if (triple[0] === '#' || !triple) {
                        return;
                    }
                    triple = triple.replace(/<([^<>]*)>/g, '$1').split(' ', 3);
                    triples.push({
                        subject: triple[0],
                        predicate: triple[1],
                        object: triple[2]
                    });
                });

                stream.set(triples);
            });

            return stream;
        },
        mod: (name, options, cb) => {
            cb(null, require(entrypoint.module_root + name));
        }
    };
};
<commit_msg>use cayley triple io to get triples<commit_after>'use strict'

const LRU = require('lru-cache');
const CayleyTripleIo = require('cayley-triple-io');
const array_stream = require('../array_stream');
const resolve = require('path').resolve;
const readFile = require('fs').readFile;
const cache_options = {
    max: 500,
    dispose: (key, value) => {
        console.log('Cache remove:', key);
    }
};
const cayley = new CayleyTripleIo.Client({
    url: 'http://localhost:64210/',
    prefixes: {
        builder: 'http://service.jillix.com/jillix/service/app/builder/',
        schema: 'http://schema.org/',
        flow: 'http://schema.jillix.net/vocab/',
        rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
    }
});

module.exports = (entrypoint) => {

    entrypoint.module_root = entrypoint.base = '/node_modules/';

    return {
        cache: LRU(cache_options),
        read: (instance, listener, options) => {

            if (options.session) {
                // TODO access check
            }

            const stream = cayley.createReadStream([
                'flow:ModuleInstanceConfig',
                ['In', 'rdf:type']
            ], {
                out: [
                    'flow:event'
                ]
            });

            return stream;
        },
        mod: (name, options, cb) => {
            cb(null, require(entrypoint.module_root + name));
        }
    };
};
<|endoftext|>


<commit_before>var BeanBag = require('BeanBag');
var bodyParser = require('body-parser');
var documentsToCsv = require('./documentsToCsv');
var documentsToXlsx = require('./documentsToXlsx');
var express = require('express');

function rowsToDocuments(rows) {
    return rows.map(function (row) {
        return row.doc;
    });
}

module.exports = function (config) {
    config = config || {};
    var app = express();
    var handlerName = config.handlerName;

    if (!handlerName) {
        throw new Error('No handler name specified.');
    }

    if (!config.databaseName) {
        throw new Error('No database name specified.');
    }

    config.databaseHost = config.databaseHost || 'http://localhost';
    config.databasePort = config.databasePort || 5984;

    // connect to CouchDB
    var couchdb = new BeanBag({
        url: config.databaseHost + ':' + config.databasePort + '/' + config.databaseName
    });

    app.use(bodyParser.json());

    app.get('/', function (req, res) {
        couchdb.request({
            path: '_all_docs',
            query: {
                include_docs: true
            }
        }, function (err, result, body) {
            if (err) {
                return res.status(err.statusCode).send({
                    error: err.name
                });
            }

            var format = req.query.format;
            var result = {};
            result[handlerName] = rowsToDocuments(body.rows || []);

            if (format === 'csv') {
                return documentsToCsv(handlerName).writeToStream(res, result[handlerName]);
            } else if (format === 'xlsx') {
                res.setHeader('Content-disposition', 'attachment; filename=' + handlerName + '.xlsx');

                return documentsToXlsx(handlerName).writeToStream(res, result[handlerName]);
            }

            res.status(200).send(result);
        });
    });

    app.get('/:docId', function (req, res) {
        var docId = req.params.docId;
        var query = req.query || {};

        couchdb.request({
            path: docId
        }, function (err, result, body) {
            if (err) {
                return res.status(err.statusCode).send({
                    error: err.name
                });
            }

            var format = req.query.format;

            if (!body[handlerName]) {
                body[handlerName] = [];
            }

            if (format === 'csv') {
                return documentsToCsv(handlerName).writeToStream(res, [body]);
            } else if (format === 'xlsx') {
                res.setHeader('Content-disposition', 'attachment; filename=' + handlerName + '.xlsx');

                return documentsToXlsx(handlerName).writeToStream(res, [body]);
            }

            res.status(200).send(body);
        });
    });

    app.post('/:docId', function (req, res) {
        var docId = req.params.docId;

        couchdb.request({
            method: 'PUT',
            path: docId,
            body: req.body
        }, function (err, result) {
            if (err) {
                return res.status(err.statusCode).send({
                    error: err.name
                });
            }

            res.status(200).send(result.body);
        });
    });

    return app;
};
<commit_msg>Make CSV output download as an attachment.<commit_after>var BeanBag = require('BeanBag');
var bodyParser = require('body-parser');
var documentsToCsv = require('./documentsToCsv');
var documentsToXlsx = require('./documentsToXlsx');
var express = require('express');

function rowsToDocuments(rows) {
    return rows.map(function (row) {
        return row.doc;
    });
}

module.exports = function (config) {
    config = config || {};
    var app = express();
    var handlerName = config.handlerName;

    if (!handlerName) {
        throw new Error('No handler name specified.');
    }

    if (!config.databaseName) {
        throw new Error('No database name specified.');
    }

    config.databaseHost = config.databaseHost || 'http://localhost';
    config.databasePort = config.databasePort || 5984;

    // connect to CouchDB
    var couchdb = new BeanBag({
        url: config.databaseHost + ':' + config.databasePort + '/' + config.databaseName
    });

    app.use(bodyParser.json());

    app.get('/', function (req, res) {
        couchdb.request({
            path: '_all_docs',
            query: {
                include_docs: true
            }
        }, function (err, result, body) {
            if (err) {
                return res.status(err.statusCode).send({
                    error: err.name
                });
            }

            var format = req.query.format;
            var result = {};
            result[handlerName] = rowsToDocuments(body.rows || []);

            if (format === 'csv') {
                res.setHeader('Content-disposition', 'attachment; filename=' + handlerName + '.csv');

                return documentsToCsv(handlerName).writeToStream(res, result[handlerName]);
            } else if (format === 'xlsx') {
                res.setHeader('Content-disposition', 'attachment; filename=' + handlerName + '.xlsx');

                return documentsToXlsx(handlerName).writeToStream(res, result[handlerName]);
            }

            res.status(200).send(result);
        });
    });

    app.get('/:docId', function (req, res) {
        var docId = req.params.docId;
        var query = req.query || {};

        couchdb.request({
            path: docId
        }, function (err, result, body) {
            if (err) {
                return res.status(err.statusCode).send({
                    error: err.name
                });
            }

            var format = req.query.format;

            if (!body[handlerName]) {
                body[handlerName] = [];
            }

            if (format === 'csv') {
                res.setHeader('Content-disposition', 'attachment; filename=' + handlerName + '.csv');

                return documentsToCsv(handlerName).writeToStream(res, [body]);
            } else if (format === 'xlsx') {
                res.setHeader('Content-disposition', 'attachment; filename=' + handlerName + '.xlsx');

                return documentsToXlsx(handlerName).writeToStream(res, [body]);
            }

            res.status(200).send(body);
        });
    });

    app.post('/:docId', function (req, res) {
        var docId = req.params.docId;

        couchdb.request({
            method: 'PUT',
            path: docId,
            body: req.body
        }, function (err, result) {
            if (err) {
                return res.status(err.statusCode).send({
                    error: err.name
                });
            }

            res.status(200).send(result.body);
        });
    });

    return app;
};
<|endoftext|>


<commit_before>'use strict';

/*
 * Distributes negation in the Juttle AST into subexpressions.
 */

var ASTVisitor = require('juttle/lib/compiler/ast-visitor');

class Rewriter extends ASTVisitor {
    negate(op) {
        // Missing in this list is 'in'. It is missing an opposite operator,
        // and also not supported in InfluxDB. We assume it was transformed
        // into ORs sequence in a previous rewrite.
        var negations = {
            '==':  '!=',
            '!=':  '==',
            '=~':  '!~',
            '!~':  '=~',
            '<':   '>=',
            '>':   '<=',
            '<=':  '>',
            '>=':  '<',
            'AND': 'OR',
            'OR':  'AND'
        };
        return negations[op];
    }

    visitBinaryExpression(node, negate) {
        if (this._hasNegation(node.left)) {
            this.visit(node.left, !negate);
            node.left = this._rewriteNegation(node.left);
        } else {
            this.visit(node.left, negate);
        }

        if (this._hasNegation(node.right)) {
            this.visit(node.right, !negate);
            node.right = this._rewriteNegation(node.right);
        } else {
            this.visit(node.right, negate);
        }

        if (negate) {
            var op = this.negate(node.operator);

            if (!op) { throw new Error(`Operator ${node.operator} negation not supported`); }

            node.operator = op;
        }
    }

    visitUnaryExpression(node, negate) {
        if (this._hasNegation(node.expression)) {
            this.visit(node.expression, !negate);
            node.expression = this._rewriteNegation(node.expression);
        } else {
            this.visit(node.expression, negate);
        }
    }

    _hasNegation(node) {
        return (node.type === 'UnaryExpression' && node.operator === 'NOT');
    }

    _rewriteNegation(node) {
        return node.expression;
    }

    visitExpressionFilterTerm(node, negate) {
        if (this._hasNegation(node.expression)) {
            this.visit(node.expression, !negate);
            node.expression = this._rewriteNegation(node.expression);
        } else {
            this.visit(node.expression, negate);
        }
    }

    visitFilterLiteral(node, negate) {
        if (this._hasNegation(node.ast)) {
            this.visit(node.ast, !negate);
            node.ast = this._rewriteNegation(node.ast);
        } else {
            this.visit(node.ast, negate);
        }
    }

    visit(node, negate) {
        this[`visit${node.type}`].apply(this, arguments);
    }
}

module.exports = Rewriter;
<commit_msg>not.js - indentation fix<commit_after>'use strict';

/*
 * Distributes negation in the Juttle AST into subexpressions.
 */

var ASTVisitor = require('juttle/lib/compiler/ast-visitor');

class Rewriter extends ASTVisitor {
    negate(op) {
        // Missing in this list is 'in'. It is missing an opposite operator,
        // and also not supported in InfluxDB. We assume it was transformed
        // into ORs sequence in a previous rewrite.
        var negations = {
            '==': '!=',
            '!=': '==',
            '=~': '!~',
            '!~': '=~',
            '<': '>=',
            '>': '<=',
            '<=': '>',
            '>=': '<',
            'AND': 'OR',
            'OR': 'AND'
        };
        return negations[op];
    }

    visitBinaryExpression(node, negate) {
        if (this._hasNegation(node.left)) {
            this.visit(node.left, !negate);
            node.left = this._rewriteNegation(node.left);
        } else {
            this.visit(node.left, negate);
        }

        if (this._hasNegation(node.right)) {
            this.visit(node.right, !negate);
            node.right = this._rewriteNegation(node.right);
        } else {
            this.visit(node.right, negate);
        }

        if (negate) {
            var op = this.negate(node.operator);

            if (!op) { throw new Error(`Operator ${node.operator} negation not supported`); }

            node.operator = op;
        }
    }

    visitUnaryExpression(node, negate) {
        if (this._hasNegation(node.expression)) {
            this.visit(node.expression, !negate);
            node.expression = this._rewriteNegation(node.expression);
        } else {
            this.visit(node.expression, negate);
        }
    }

    _hasNegation(node) {
        return (node.type === 'UnaryExpression' && node.operator === 'NOT');
    }

    _rewriteNegation(node) {
        return node.expression;
    }

    visitExpressionFilterTerm(node, negate) {
        if (this._hasNegation(node.expression)) {
            this.visit(node.expression, !negate);
            node.expression = this._rewriteNegation(node.expression);
        } else {
            this.visit(node.expression, negate);
        }
    }

    visitFilterLiteral(node, negate) {
        if (this._hasNegation(node.ast)) {
            this.visit(node.ast, !negate);
            node.ast = this._rewriteNegation(node.ast);
        } else {
            this.visit(node.ast, negate);
        }
    }

    visit(node, negate) {
        this[`visit${node.type}`].apply(this, arguments);
    }
}

module.exports = Rewriter;
<|endoftext|>


<commit_before>describe('flatten', function() {

    describe('flattenObject', function() {

        var data,
        flattenedData;

        beforeEach(function() {
            data = {
                "patriots": {
                    "coaches": {
                        "head": "bill",
                        "oline": "scarnecchia"
                    }
                },
                "myNumber": 12,
                "myBoolean": true,
                "myString": 'hello',
                "myNull": null,
                "nestedTypes": {
                    "myNumber": 12,
                    "myBoolean": true,
                    "myString": 'hello',
                    "myNull": null,
                }
            };

            flattenedData = flattenObject(data);
        });

        it('should concat nested object keys', function() {
            expect('patriots/coaches/head' in flattenedData).toBe(true);
            expect('patriots/coaches/oline' in flattenedData).toBe(true);
        });

        it('should maintain values for concatted nested keys', function() {
            expect(flattenedData['patriots/coaches/head']).toBe('bill');
            expect(flattenedData['patriots/coaches/oline']).toBe('scarnecchia');
        });

        it('should maintain scalar data types', function() {
            expect(typeof flattenedData.myNumber).toBe('number');
            expect(typeof flattenedData.myBoolean).toBe('boolean');
            expect(typeof flattenedData.myString).toBe('string');
            expect(flattenedData.myNull).toBe(null);
        });

        it('should maintain nested scalar data types', function() {
            expect(typeof flattenedData['nestedTypes/myNumber']).toBe('number');
            expect(typeof flattenedData['nestedTypes/myBoolean']).toBe('boolean');
            expect(typeof flattenedData['nestedTypes/myString']).toBe('string');
            expect(flattenedData['nestedTypes/myNull']).toBe(null);
        });

        it('should flatten all object values', function() {
            expect(isFlattened(flattenedData)).toBe(true);
            expect(isFlattened(data)).toBe(false);
        });

    });

    describe('isScalar', function() {

        var scalars;

        beforeEach(function() {
            scalars = {
                "myNumber": 12,
                "myBoolean": true,
                "myString": 'hello',
                "myNull": null
            };
        });

        it('should return true when passed number', function() {
            expect(isScalar(scalars.myNumber)).toBe(true);
        });

        it('should return true when passed boolean', function() {
            expect(isScalar(scalars.myBoolean)).toBe(true);
        });

        it('should return true when passed string', function() {
            expect(isScalar(scalars.myString)).toBe(true);
        });

        it('should return true when passed null', function() {
            expect(isScalar(scalars.myNull)).toBe(true);
        });

    });

    describe('isArray', function() {

        var scalars;

        beforeEach(function() {
            scalars = {
                "myNumber": 12,
                "myBoolean": true,
                "myString": 'hello',
                "myNull": null
            };
        });

        it('should return true when passed array', function() {
            var myArray = [];

            expect(isArray(myArray)).toBe(true);
        });

        it('should return false when passed scalar or object', function() {
            expect(isArray(scalars.myNumber)).toBe(false);
            expect(isArray(scalars.myBoolean)).toBe(false);
            expect(isArray(scalars.myString)).toBe(false);
            expect(isArray(scalars.myNull)).toBe(false);
            expect(isArray({})).toBe(false);
        });

    });

    describe('isObject', function() {

        var scalars;

        beforeEach(function() {
            scalars = {
                "myNumber": 12,
                "myBoolean": true,
                "myString": 'hello',
                "myNull": null
            };
        });

        it('should return true when passed object', function() {
            var myObject = {};

            expect(isObject(myObject)).toBe(true);
        });

        it('should return false when passed scalar or array', function() {
            expect(isObject(scalars.myNumber)).toBe(false);
            expect(isObject(scalars.myBoolean)).toBe(false);
            expect(isObject(scalars.myString)).toBe(false);
            expect(isObject(scalars.myNull)).toBe(false);
            expect(isObject([])).toBe(false);
        });

    });

});

/**
 *
 * isFlattened
 * return {boolean} - true if no object values are objects
 *
 */

function isFlattened(data) {
    var isFlattened = true;

    for (var key in data) {
        var value = data[key];
        var valueType = typeof value;

        if (valueType === 'object' &&
            value !== null &&
            !(Array.isArray(value))) {
            isFlattened = false;
            break;
        }
    }

    return isFlattened;
}<commit_msg>tests: add unittests for flattenMany function<commit_after>describe('flatten', function() {

    describe('flattenObject', function() {

        var data,
        flattenedData;

        beforeEach(function() {
            data = {
                "patriots": {
                    "coaches": {
                        "head": "bill",
                        "oline": "scarnecchia"
                    }
                },
                "myNumber": 12,
                "myBoolean": true,
                "myString": 'hello',
                "myNull": null,
                "nestedTypes": {
                    "myNumber": 12,
                    "myBoolean": true,
                    "myString": 'hello',
                    "myNull": null,
                }
            };

            flattenedData = flattenObject(data);
        });

        it('should concat nested object keys', function() {
            expect('patriots/coaches/head' in flattenedData).toBe(true);
            expect('patriots/coaches/oline' in flattenedData).toBe(true);
        });

        it('should maintain values for concatted nested keys', function() {
            expect(flattenedData['patriots/coaches/head']).toBe('bill');
            expect(flattenedData['patriots/coaches/oline']).toBe('scarnecchia');
        });

        it('should maintain scalar data types', function() {
            expect(typeof flattenedData.myNumber).toBe('number');
            expect(typeof flattenedData.myBoolean).toBe('boolean');
            expect(typeof flattenedData.myString).toBe('string');
            expect(flattenedData.myNull).toBe(null);
        });

        it('should maintain nested scalar data types', function() {
            expect(typeof flattenedData['nestedTypes/myNumber']).toBe('number');
            expect(typeof flattenedData['nestedTypes/myBoolean']).toBe('boolean');
            expect(typeof flattenedData['nestedTypes/myString']).toBe('string');
            expect(flattenedData['nestedTypes/myNull']).toBe(null);
        });

        it('should flatten all object values', function() {
            expect(isFlattened(flattenedData)).toBe(true);
            expect(isFlattened(data)).toBe(false);
        });

    });

describe('flattenMany', function() {
        var data;

        beforeEach(function() {
            data = [
                {
                    "title": "Creativity Inc",
                    "author": "Ed Catmull",
                    "meta": {
                        "keywords": "business"
                    }
                },
                {
                    "title": "Ego is the Enemy",
                    "author": "Ryan Holiday",
                    "meta": {
                        "keywords": "philosophy"
                    }
                }
            ];
        });

        it('flatten all objects in an array', function() {
            var flattenedData = flattenMany(data);

            var isAllFlattened = true;

            for (var i = 0, n = flattenedData.length; i < n; i++) {
                var currentObject = flattenedData[i];
                if (!isFlattened(currentObject)) {
                    isAllFlattened = false;
                    break;
                }
            }

            expect(isAllFlattened).toBe(true);
        });

    });

    describe('isScalar', function() {

        var scalars;

        beforeEach(function() {
            scalars = {
                "myNumber": 12,
                "myBoolean": true,
                "myString": 'hello',
                "myNull": null
            };
        });

        it('should return true when passed number', function() {
            expect(isScalar(scalars.myNumber)).toBe(true);
        });

        it('should return true when passed boolean', function() {
            expect(isScalar(scalars.myBoolean)).toBe(true);
        });

        it('should return true when passed string', function() {
            expect(isScalar(scalars.myString)).toBe(true);
        });

        it('should return true when passed null', function() {
            expect(isScalar(scalars.myNull)).toBe(true);
        });

    });

    describe('isArray', function() {

        var scalars;

        beforeEach(function() {
            scalars = {
                "myNumber": 12,
                "myBoolean": true,
                "myString": 'hello',
                "myNull": null
            };
        });

        it('should return true when passed array', function() {
            var myArray = [];

            expect(isArray(myArray)).toBe(true);
        });

        it('should return false when passed scalar or object', function() {
            expect(isArray(scalars.myNumber)).toBe(false);
            expect(isArray(scalars.myBoolean)).toBe(false);
            expect(isArray(scalars.myString)).toBe(false);
            expect(isArray(scalars.myNull)).toBe(false);
            expect(isArray({})).toBe(false);
        });

    });

    describe('isObject', function() {

        var scalars;

        beforeEach(function() {
            scalars = {
                "myNumber": 12,
                "myBoolean": true,
                "myString": 'hello',
                "myNull": null
            };
        });

        it('should return true when passed object', function() {
            var myObject = {};

            expect(isObject(myObject)).toBe(true);
        });

        it('should return false when passed scalar or array', function() {
            expect(isObject(scalars.myNumber)).toBe(false);
            expect(isObject(scalars.myBoolean)).toBe(false);
            expect(isObject(scalars.myString)).toBe(false);
            expect(isObject(scalars.myNull)).toBe(false);
            expect(isObject([])).toBe(false);
        });

    });

});

/**
 *
 * isFlattened
 * return {boolean} - true if no object values are objects
 *
 */

function isFlattened(data) {
    var isFlattened = true;

    for (var key in data) {
        var value = data[key];
        var valueType = typeof value;

        if (valueType === 'object' &&
            value !== null &&
            !(Array.isArray(value))) {
            isFlattened = false;
            break;
        }
    }

    return isFlattened;
}<|endoftext|>


<commit_before>var app = angular.module("angularFretboard", ['Scope.safeApply']);

app.directive("fretboard", ["$rootScope",
  function($rootScope) {
    var fretboardsGeneratedCounter = 0;

    return {
      restrict: "A",
      scope: {
        config: "=fretboardConfig",
        //tuningChangeCallback : "&fretboardTuningChangeCallback"
      },
      // The controller code is run before the scopes of other directives which
      // need access to it, so create the jQuery fretboard here
      controller: ["$scope", "$element", "$attrs",
        function($scope, $element, $attrs) {
          var ctrl = this;

          var unWatchConfig = $scope.$watch(function() {
            return $scope.config;
          }, function(newVal, oldVal) {
            if (newVal) {
              initialize($scope.config, $element, ctrl);
              $scope.$watch(function() {
                return $scope.config.noteClickingDisabled;
              }, function(newVal, oldVal) {
                if (newVal === true) {
                  ctrl.jQueryFretboard.disableNoteClicking();
                } else {
                  ctrl.jQueryFretboard.enableNoteClicking();
                }
              });

              $scope.$watch(function() {
                return $scope.config.tuningClickingDisabled;
              }, function(newVal, oldVal) {
                if (newVal === true) {
                  ctrl.jQueryFretboard.disableTuningClicking();
                } else {
                  ctrl.jQueryFretboard.enableTuningClicking();
                }
              });

              $scope.$watch(function() {
                return $scope.config.isChordMode;
              }, function(newVal, oldVal) {
                if (newVal === true) {
                  ctrl.jQueryFretboard.setChordMode(true);
                } else {
                  ctrl.jQueryFretboard.setChordMode(false);
                }
              });

              unWatchConfig();
            }
          });

        }
      ],
      // we create 2 inner directives so they can each have their own ngModel, which handles two-way data-binding
      // for only one thing
      template: '

' +
        '

'
    }

    function initialize(config, element, ctrl) {
      var domId = getUniqueDomIdForFretboard();
      element.attr("id", domId).fretboard(config);

      ctrl.jQueryFretboardElement = element;
      ctrl.jQueryFretboard = element.data('fretboard');
    }

    function getUniqueDomIdForFretboard() {
      fretboardsGeneratedCounter++;
      return "fretboardjs-" + fretboardsGeneratedCounter;
    }
  }
]);

// Do not give these inner directives isolate scope or they will won't be able
// to access the config in the fretboard directive's isolate scope
app.directive("fretboardTuning", ["$rootScope", "$parse",
  function($rootScope, $parse) {
    var isFirst = true;

    return {
      restrict: "A",
      require: ["ngModel", "^fretboard"],
      link: function(scope, element, attrs, ctrls) {
        var ngModelCtrl = ctrls[0];
        var fretboardCtrl = ctrls[1];

        var unWatchFretboard = scope.$watch(function() {
          return fretboardCtrl.jQueryFretboard;
        }, function(newVal, oldVal) {
          if (newVal) {
            var jQueryFretboardElement = fretboardCtrl.jQueryFretboardElement;
            var jQueryFretboard = fretboardCtrl.jQueryFretboard;

            //var tuningChangeCallback = ($parse(attrs.tuningChangeCallback))(scope);

            // Updating the controller
            jQueryFretboardElement.on("tuningChanged", function() {
              $rootScope.$safeApply(function() {
                ngModelCtrl.$setViewValue(jQueryFretboard.getGuitarStringNotes());

                //if (tuningChangeCallback) {
                //  tuningChangeCallback();
                //}
              });
            });

            ngModelCtrl.$render = function() {
              //console.log("render");
              // prevent double rendering the first time
              if (isFirst) {
                //console.log("skip");
                // Put the tuning on the controller in case its config file did not
                // define a tuning (in which case the default was used)
                ngModelCtrl.$setViewValue(jQueryFretboard.getGuitarStringNotes());
                isFirst = false;
                return;
              }

              jQueryFretboard.setTuning(ngModelCtrl.$viewValue);

              //if (tuningChangeCallback) {
              //  tuningChangeCallback();
              //}
            }

            unWatchFretboard();
          }
        });
      }
    }
  }
]);

app.directive("fretboardClickedNotes", ["$rootScope", "$parse",
  function($rootScope, $parse) {
    return {
      restrict: "A",
      require: ["ngModel", "^fretboard"],
      link: function(scope, element, attrs, ctrls) {
        var ngModelCtrl = ctrls[0];
        var fretboardCtrl = ctrls[1];

        var unWatchFretboard = scope.$watch(function() {
          return fretboardCtrl.jQueryFretboard;
        }, function(newVal, oldVal) {
          if (newVal) {
            var jQueryFretboardElement = fretboardCtrl.jQueryFretboardElement;
            var jQueryFretboard = fretboardCtrl.jQueryFretboard;

            //var clickedNoteCallback = ($parse(attrs.clickedNoteCallback))(scope);

            // Updating the controller
            jQueryFretboardElement.on("noteClicked", function() {
              $rootScope.$safeApply(function() {
                ngModelCtrl.$setViewValue(jQueryFretboard.getClickedNotes());

                //if (clickedNoteCallback) {
                //  clickedNoteCallback();
                //}
              });
            });

            ngModelCtrl.$render = function() {
              jQueryFretboard.clearClickedNotes(); // will trigger notesCleared event

              var newNotes = ngModelCtrl.$viewValue;

              if (!newNotes) {
                return;
              }

              for (var i = 0; i < newNotes.length; i++) {
                if (newNotes[i]) {
                  jQueryFretboard.setClickedNoteByStringNoteAndFretNum(newNotes[i]);
                }
              }

              //if (clickedNoteCallback) {
              //  clickedNoteCallback();
              //}
            }
          }

          unWatchFretboard();
        });
      }
    }
  }
]);
<commit_msg>removed protection against double-render the first time<commit_after>var app = angular.module("angularFretboard", ['Scope.safeApply']);

app.directive("fretboard", ["$rootScope",
  function($rootScope) {
    var fretboardsGeneratedCounter = 0;

    return {
      restrict: "A",
      scope: {
        config: "=fretboardConfig"
      },
      // The controller code is run before the scopes of other directives which
      // need access to it, so create the jQuery fretboard here
      controller: ["$scope", "$element", "$attrs",
        function($scope, $element, $attrs) {
          var ctrl = this;

          var unWatchConfig = $scope.$watch(function() {
            return $scope.config;
          }, function(newVal, oldVal) {
            if (newVal) {
              initialize($scope.config, $element, ctrl);
              $scope.$watch(function() {
                return $scope.config.noteClickingDisabled;
              }, function(newVal, oldVal) {
                if (newVal === true) {
                  ctrl.jQueryFretboard.disableNoteClicking();
                } else {
                  ctrl.jQueryFretboard.enableNoteClicking();
                }
              });

              $scope.$watch(function() {
                return $scope.config.tuningClickingDisabled;
              }, function(newVal, oldVal) {
                if (newVal === true) {
                  ctrl.jQueryFretboard.disableTuningClicking();
                } else {
                  ctrl.jQueryFretboard.enableTuningClicking();
                }
              });

              $scope.$watch(function() {
                return $scope.config.isChordMode;
              }, function(newVal, oldVal) {
                if (newVal === true) {
                  ctrl.jQueryFretboard.setChordMode(true);
                } else {
                  ctrl.jQueryFretboard.setChordMode(false);
                }
              });

              unWatchConfig();
            }
          });

        }
      ],
      // we create 2 inner directives so they can each have their own ngModel, which handles two-way data-binding
      // for only one thing
      template: '

' +
        '

'
    }

    function initialize(config, element, ctrl) {
      var domId = getUniqueDomIdForFretboard();
      element.attr("id", domId).fretboard(config);

      ctrl.jQueryFretboardElement = element;
      ctrl.jQueryFretboard = element.data('fretboard');
    }

    function getUniqueDomIdForFretboard() {
      fretboardsGeneratedCounter++;
      return "fretboardjs-" + fretboardsGeneratedCounter;
    }
  }
]);

// Do not give these inner directives isolate scope or they will won't be able
// to access the config in the fretboard directive's isolate scope
app.directive("fretboardTuning", ["$rootScope", "$parse",
  function($rootScope, $parse) {
    var isFirst = true;

    return {
      restrict: "A",
      require: ["ngModel", "^fretboard"],
      link: function(scope, element, attrs, ctrls) {
        var ngModelCtrl = ctrls[0];
        var fretboardCtrl = ctrls[1];

        var unWatchFretboard = scope.$watch(function() {
          return fretboardCtrl.jQueryFretboard;
        }, function(newVal, oldVal) {
          if (newVal) {
            var jQueryFretboardElement = fretboardCtrl.jQueryFretboardElement;
            var jQueryFretboard = fretboardCtrl.jQueryFretboard;

            // Updating the controller
            jQueryFretboardElement.on("tuningChanged", function() {
              $rootScope.$safeApply(function() {
                ngModelCtrl.$setViewValue(jQueryFretboard.getGuitarStringNotes());
              });
            });

            ngModelCtrl.$render = function() {
              jQueryFretboard.setTuning(ngModelCtrl.$viewValue);
            }

            unWatchFretboard();
          }
        });
      }
    }
  }
]);

app.directive("fretboardClickedNotes", ["$rootScope", "$parse",
  function($rootScope, $parse) {
    return {
      restrict: "A",
      require: ["ngModel", "^fretboard"],
      link: function(scope, element, attrs, ctrls) {
        var ngModelCtrl = ctrls[0];
        var fretboardCtrl = ctrls[1];

        var unWatchFretboard = scope.$watch(function() {
          return fretboardCtrl.jQueryFretboard;
        }, function(newVal, oldVal) {
          if (newVal) {
            var jQueryFretboardElement = fretboardCtrl.jQueryFretboardElement;
            var jQueryFretboard = fretboardCtrl.jQueryFretboard;

            // Updating the controller
            jQueryFretboardElement.on("noteClicked", function() {
              $rootScope.$safeApply(function() {
                ngModelCtrl.$setViewValue(jQueryFretboard.getClickedNotes());
              });
            });

            ngModelCtrl.$render = function() {
              jQueryFretboard.clearClickedNotes(); // will trigger notesCleared event

              var newNotes = ngModelCtrl.$viewValue;

              if (!newNotes) {
                return;
              }

              for (var i = 0; i < newNotes.length; i++) {
                if (newNotes[i]) {
                  jQueryFretboard.setClickedNoteByStringNoteAndFretNum(newNotes[i]);
                }
              }
            }
          }

          unWatchFretboard();
        });
      }
    }
  }
]);<|endoftext|>