<commit_before>import Component from 'ben-component';
import TextTool from './text-tool';
import DataCanvas from 'ben-canvas';
import lineCursor from '../img/pen@1x.ico';
import rectCursor from '../img/rect.ico';

const LINE = 'line';
const RECT = 'rect';
const TEXT = 'text';
const EASE = 'ease';

class Sketch extends Component {
  constructor(options) {
    super(null, options);
    this.ctx = this.canvas.getContext('2d');
    this.container = this.options.container;
    this.container.appendChild(this.el);
    this.toolType = LINE;
    this.color = '#f00';
    this.cache = [];
    this.textMeasure();
    this.initEvent();
    this.text = false;
  }

  createEl() {
    const el = super.createEl('div', {
      style: `display: block; width: 100%; height: 100%;`
    }, {
      className: 'ben-sketch'
    });
    this.canvas = this.createCanvas();
    el.appendChild(this.canvas);
    return el;
  }

  createCanvas() {
    console.log(this.options.container.clientWidth, this.options.container.clientHeight)
    const canvas = super.createEl('canvas', {
      width: this.options.container.clientWidth,
      height: this.options.container.clientHeight,
      style: 'display: block;'
    }, {
      className: 'pf-canvas'
    });
    return canvas;
  }

  initEvent() {
    this.on('mousedown', (e) => {console.log(this.toolType); this[`${this.toolType}MousedownListener`](e)});
    this.on('mouseup', (e) => this[`${this.toolType}MouseupListener`](e));
  }

  textMeasure() {
    const measureEl = this.measureEl = super.createEl('pre', {
      'class': 'sketch-temp text-pre',
    });
    this.container.appendChild(measureEl);
  }

  [`${LINE}MousedownListener`](e) {
    console.log(LINE, 'mousedown');
    const linePoints = [];
    linePoints.push({
      x: e.offsetX,
      y: e.offsetY
    });
    this.tempCanvas = super.createEl('canvas', {
      width: this.canvas.width,
      height: this.canvas.height,
      style: `cursor: url("${lineCursor}") 5 25, auto;`
    }, {
      className: 'sketch-temp line-canvas'
    });
    const lineCtx = this.tempCanvas.getContext('2d');
    lineCtx.lineWidth = 1;
    lineCtx.strokeStyle = this.color;
    lineCtx.lineJoin = 'round';
    lineCtx.lineCap = 'round';
    this.tempCanvas.addEventListener('mousemove', (e) => {
      lineCtx.clearRect(0, 0, this.width(), this.height());
      linePoints.push({
        x: e.offsetX,
        y: e.offsetY
      });
      lineCtx.beginPath();
      lineCtx.moveTo(linePoints[0].x, linePoints[0].y);
      linePoints.map(point => lineCtx.lineTo(point.x, point.y));
      lineCtx.stroke();
    });
    this.tempCanvas.addEventListener('mouseup', (e) => this[`${LINE}MouseupListener`](e, linePoints));
    this.container.appendChild(this.tempCanvas);
  }

  [`${LINE}MouseupListener`](e, linePoints) {
    console.log(LINE, 'mouseup');
    if (this.tempCanvas) {
      this.container.removeChild(this.tempCanvas);
      if (linePoints.length < 2) {
        return;
      }
      linePoints.map(point => {
        point.x /= this.tempCanvas.width,
        point.y /= this.tempCanvas.height;
      });
      DataCanvas.line(this.ctx, {
        points: linePoints
      });
      this.trigger(LINE, {
        points: linePoints
      });
    }
  }

  [`${RECT}MousedownListener`](event) {
    console.log(RECT, 'mousedown');
    // store the start position of the rect.
    const x = event.offsetX, y = event.offsetY;
    const rectData = {
      position: {
        x: x / this.ctx.canvas.width,
        y: y / this.ctx.canvas.height
      }
    }
    // create temp canvas for preview rect in real-time.
    this.tempCanvas = super.createEl('canvas', {
      width: this.width(),
      height: this.height(),
      style: `cursor: url("${rectCursor}") 9 17, auto;`
    }, {
      className: 'sketch-temp rect-canvas'
    });
    const rectCtx = this.tempCanvas.getContext('2d');

    this.tempCanvas.addEventListener('mousemove', (e) => {
      // clear previous rect.
      rectCtx.clearRect(0, 0, this.width(), this.height());
      // get the current rect width and height;
      const width = e.offsetX - x,
        height = e.offsetY - y;
      // store the width and height of current rect in ratio of canvas demension.
      rectData.width = width / rectCtx.canvas.width;
      rectData.height = height / rectCtx.canvas.height;
      // draw the current rect to temp canvas for preview.
      rectCtx.strokeRect(x, y, width, height);
    });

    this.tempCanvas.addEventListener('mouseup', (e) => this[`${RECT}MouseupListener`](e, rectData))
    this.container.appendChild(this.tempCanvas);
  }

  [`${RECT}MouseupListener`](e, rectData) {
    console.log(RECT, 'mouseup');
    if (this.tempCanvas) {
      this.container.removeChild(this.tempCanvas);
      if (!rectData.width || !rectData.height) {
        return;
      }
      // Draw the final rect to the target canvas.
      DataCanvas.rect(this.ctx, rectData);
      // send event to sdk.
      this.trigger(RECT, rectData);
    }
  }

  [`${TEXT}MousedownListener`](e) {
    console.log(TEXT, 'mousedown');
  }

  [`${TEXT}MouseupListener`](e) {
    console.log(TEXT, 'mouseup');
    if (this.textTool) {
      this.textTool = null;
      return;
    }
    const textPoints = [];
    textPoints.push({
      x: e.offsetX,
      y: e.offsetY
    });
    const textTool = this.textTool = new TextTool(this.container, textPoints[0].x, textPoints[0].y);
    textTool.on('valuechange', (event, data) => {
      this.measureEl.innerHTML = data + '  ';
      textTool.width(this.measureEl.clientWidth);
      textTool.height(this.measureEl.clientHeight);
    });
    textTool.on('submit', (event, data) => {
      if (!data.data) {
        return;
      }
      const textOptions = {
        position: {
          x: e.offsetX / this.ctx.canvas.width,
          y: e.offsetY / this.ctx.canvas.height
        },
        color: this.color,
        text: data.data
      }
      DataCanvas.text(this.ctx, textOptions);
      this.trigger(TEXT, textOptions);
    });
  }

  [`${EASE}MousedownListener`](e) {
    console.log(EASE, 'mousedown');
    const easePoints = [];
    easePoints.push({
      x: e.offsetX / this.ctx.canvas.width,
      y: e.offsetY / this.ctx.canvas.height
    });
    this.ctx.save();
    this.ctx.lineWidth = 10;
    this.ctx.lineCap = 'round';
    this.ctx.lineJoin = 'round';
    this.ctx.globalCompositeOperation = 'destination-out';
    this.ctx.beginPath();
    const mousemove = (e) => {
      easePoints.push({
        x: e.offsetX / this.ctx.canvas.width,
        y: e.offsetY / this.ctx.canvas.height
      })
      this.ctx.lineTo(e.offsetX, e.offsetY);
      this.ctx.stroke();
    }
    const mouseup = () => {
      this.canvas.removeEventListener('mousemove', mousemove);
      this.canvas.removeEventListener('mouseup', mouseup);
      this.ctx.restore();
      this.trigger(EASE, {
        points: easePoints
      });
    }
    this.canvas.addEventListener('mousemove', mousemove);
    this.canvas.addEventListener('mouseup', mouseup);
  }

  [`${EASE}MouseupListener`](e) {
    console.log(EASE, 'mouseup');
  }

  width() {
    return this.el.clientWidth;
  }

  height() {
    return this.el.clientHeight;
  }

  setTool(toolName) {
    if (!toolName) {
      throw new Error('Sketch:setTool(toolName): toolName argument is needed!');
    }
    this.toolType = toolName;
  }

  draw(type, options) {
    DataCanvas[type](this.ctx, options);
    this.cache.push({
      type,
      options
    });
  }

  clear() {
    DataCanvas.clear(this.ctx);
    this.cache.push({
      type: 'clear'
    });
  }

  resize() {
    this.canvas.width = this.options.container.clientWidth;
    this.canvas.height = this.options.container.clientHeight;
  }
}

export default Sketch;<commit_msg>add setColor method<commit_after>import Component from 'ben-component';
import TextTool from './text-tool';
import DataCanvas from 'ben-canvas';
import lineCursor from '../img/pen@1x.ico';
import rectCursor from '../img/rect.ico';

const LINE = 'line';
const RECT = 'rect';
const TEXT = 'text';
const EASE = 'ease';

const COLOR_RED = '#f00';
const COLOR_DEFAULT = COLOR_RED;

class Sketch extends Component {
  constructor(options) {
    super(null, options);
    this.ctx = this.canvas.getContext('2d');
    this.container = this.options.container;
    this.container.appendChild(this.el);
    this.toolType = LINE;
    this.color = COLOR_DEFAULT;
    this.cache = [];
    this.textMeasure();
    this.initEvent();
    this.text = false;
  }

  createEl() {
    const el = super.createEl('div', {
      style: `display: block; width: 100%; height: 100%;`
    }, {
      className: 'ben-sketch'
    });
    this.canvas = this.createCanvas();
    el.appendChild(this.canvas);
    return el;
  }

  createCanvas() {
    const canvas = super.createEl('canvas', {
      width: this.options.container.clientWidth,
      height: this.options.container.clientHeight,
      style: 'display: block;'
    }, {
      className: 'pf-canvas'
    });
    return canvas;
  }

  initEvent() {
    this.on('mousedown', (e) => {console.log(this.toolType); this[`${this.toolType}MousedownListener`](e)});
    this.on('mouseup', (e) => this[`${this.toolType}MouseupListener`](e));
  }

  textMeasure() {
    const measureEl = this.measureEl = super.createEl('pre', {
      'class': 'sketch-temp text-pre',
    });
    this.container.appendChild(measureEl);
  }

  [`${LINE}MousedownListener`](e) {
    console.log(LINE, 'mousedown', this.color);
    const linePoints = [];
    linePoints.push({
      x: e.offsetX,
      y: e.offsetY
    });
    this.tempCanvas = super.createEl('canvas', {
      width: this.canvas.width,
      height: this.canvas.height,
      style: `cursor: url("${lineCursor}") 5 25, auto;`
    }, {
      className: 'sketch-temp line-canvas'
    });
    const lineCtx = this.tempCanvas.getContext('2d');
    lineCtx.lineWidth = 1;
    lineCtx.strokeStyle = this.color;
    lineCtx.lineJoin = 'round';
    lineCtx.lineCap = 'round';
    this.tempCanvas.addEventListener('mousemove', (e) => {
      lineCtx.clearRect(0, 0, this.width(), this.height());
      linePoints.push({
        x: e.offsetX,
        y: e.offsetY
      });
      lineCtx.beginPath();
      lineCtx.moveTo(linePoints[0].x, linePoints[0].y);
      linePoints.map(point => lineCtx.lineTo(point.x, point.y));
      lineCtx.stroke();
    });
    this.tempCanvas.addEventListener('mouseup', (e) => this[`${LINE}MouseupListener`](e, linePoints));
    this.container.appendChild(this.tempCanvas);
  }

  [`${LINE}MouseupListener`](e, linePoints) {
    if (this.tempCanvas) {
      this.container.removeChild(this.tempCanvas);
      if (linePoints.length < 2) {
        return;
      }
      linePoints.map(point => {
        point.x /= this.tempCanvas.width,
        point.y /= this.tempCanvas.height;
      });
      DataCanvas.line(this.ctx, {
        points: linePoints,
        color: this.color
      });
      this.trigger(LINE, {
        points: linePoints,
        color: this.color
      });
      this.tempCanvas = null;
    }
  }

  [`${RECT}MousedownListener`](event) {
    console.log(RECT, 'mousedown');
    // store the start position of the rect.
    const x = event.offsetX, y = event.offsetY;
    const rectData = {
      position: {
        x: x / this.ctx.canvas.width,
        y: y / this.ctx.canvas.height
      },
      color: this.color
    }
    // create temp canvas for preview rect in real-time.
    this.tempCanvas = super.createEl('canvas', {
      width: this.width(),
      height: this.height(),
      style: `cursor: url("${rectCursor}") 9 17, auto;`
    }, {
      className: 'sketch-temp rect-canvas'
    });
    const rectCtx = this.tempCanvas.getContext('2d');
    rectCtx.strokeStyle = this.color;

    this.tempCanvas.addEventListener('mousemove', (e) => {
      // clear previous rect.
      rectCtx.clearRect(0, 0, this.width(), this.height());
      // get the current rect width and height;
      const width = e.offsetX - x,
        height = e.offsetY - y;
      // store the width and height of current rect in ratio of canvas demension.
      rectData.width = width / rectCtx.canvas.width;
      rectData.height = height / rectCtx.canvas.height;
      // draw the current rect to temp canvas for preview.
      rectCtx.strokeRect(x, y, width, height);
    });

    this.tempCanvas.addEventListener('mouseup', (e) => this[`${RECT}MouseupListener`](e, rectData))
    this.container.appendChild(this.tempCanvas);
  }

  [`${RECT}MouseupListener`](e, rectData) {
    console.log(RECT, 'mouseup');
    if (this.tempCanvas) {
      this.container.removeChild(this.tempCanvas);
      if (!rectData.width || !rectData.height) {
        return;
      }
      // Draw the final rect to the target canvas.
      DataCanvas.rect(this.ctx, rectData);
      // send event to sdk.
      this.trigger(RECT, rectData);
    }
  }

  [`${TEXT}MousedownListener`](e) {
    console.log(TEXT, 'mousedown');
  }

  [`${TEXT}MouseupListener`](e) {
    console.log(TEXT, 'mouseup');
    if (this.textTool) {
      this.textTool = null;
      return;
    }
    const textPoints = [];
    textPoints.push({
      x: e.offsetX,
      y: e.offsetY
    });
    const textTool = this.textTool = new TextTool(this.container, textPoints[0].x, textPoints[0].y);
    textTool.on('valuechange', (event, data) => {
      this.measureEl.innerHTML = data + '  ';
      textTool.width(this.measureEl.clientWidth);
      textTool.height(this.measureEl.clientHeight);
    });
    textTool.on('submit', (event, data) => {
      if (!data.data) {
        return;
      }
      const textOptions = {
        position: {
          x: e.offsetX / this.ctx.canvas.width,
          y: e.offsetY / this.ctx.canvas.height
        },
        color: this.color,
        text: data.data
      }
      DataCanvas.text(this.ctx, textOptions);
      this.trigger(TEXT, textOptions);
    });
  }

  [`${EASE}MousedownListener`](e) {
    console.log(EASE, 'mousedown');
    const easePoints = [];
    easePoints.push({
      x: e.offsetX / this.ctx.canvas.width,
      y: e.offsetY / this.ctx.canvas.height
    });
    this.ctx.save();
    this.ctx.lineWidth = 10;
    this.ctx.lineCap = 'round';
    this.ctx.lineJoin = 'round';
    this.ctx.globalCompositeOperation = 'destination-out';
    this.ctx.beginPath();
    const mousemove = (e) => {
      easePoints.push({
        x: e.offsetX / this.ctx.canvas.width,
        y: e.offsetY / this.ctx.canvas.height
      })
      this.ctx.lineTo(e.offsetX, e.offsetY);
      this.ctx.stroke();
    }
    const mouseup = () => {
      this.canvas.removeEventListener('mousemove', mousemove);
      this.canvas.removeEventListener('mouseup', mouseup);
      this.ctx.restore();
      this.trigger(EASE, {
        points: easePoints
      });
    }
    this.canvas.addEventListener('mousemove', mousemove);
    this.canvas.addEventListener('mouseup', mouseup);
  }

  [`${EASE}MouseupListener`](e) {
    console.log(EASE, 'mouseup');
  }

  width() {
    return this.el.clientWidth;
  }

  height() {
    return this.el.clientHeight;
  }

  setTool(toolName) {
    if (!toolName) {
      throw new Error('Sketch:setTool(toolName): toolName argument is needed!');
    }
    this.toolType = toolName;
  }

  setColor(color) {
    console.log(color);
    if (!color) {
      throw new Error('Sketch:setTool(toolColor): toolColor argument is needed!');
    }
    this.color = color;
  }

  draw(type, options) {
    DataCanvas[type](this.ctx, options);
    this.cache.push({
      type,
      options
    });
  }

  clear() {
    DataCanvas.clear(this.ctx);
    this.cache = [];
  }

  resize() {
    this.canvas.width = this.options.container.clientWidth;
    this.canvas.height = this.options.container.clientHeight;
  }
}

export default Sketch;<|endoftext|>


<commit_before>(function () {
  'use strict';

  var getLicon = function (React, _) {
    return React.createClass({
      getClassName: function () {
        var className = 'licon';

        // Icon type
        if (this.props.icon) {
          className += ' licon-' + this.props.icon;
        }

        // Size
        if (this.props.large) {
          className += ' licon-large';
        } else if (this.props.small) {
          className += ' licon-small';
        }

        // Border radius
        if (this.props.rounded) {
          className += ' licon-rounded';
        } else if (this.props.round) {
          className += ' licon-round';
        }

        // Border
        if (this.props.border) {
          className += ' licon-border';
        }

        return className;
      },

      render: function () {
        var props = _.extend({}, this.props, { className: this.getClassName() });

        return (
          React.createElement(
            'span',
            props,
            React.createElement('span')
          )
        );
      }
    });
  };

  // Establish the root object, `window` in the browser, or `exports` on the server.
  var root = this || window;

  // Export for commonjs / browserify
  if (typeof exports !== 'undefined') {
    var React = require('react');
    var _ = require('underscore');
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = getLicon(React, _);
    }
    exports.Licon = getLicon(React, _);
  } else if (typeof root !== 'undefined') {
    if (typeof root.React !== 'undefined' && typeof root._ !== 'undefined') {
      // Add to root object
      root.Licon = getLicon(root.React, root._);
    }

    // Define for requirejs
    if (typeof root.define === 'function' && root.define.amd) {
      root.define(['react', 'underscore'], function(defineReact, define_) {
        return getLicon(defineReact, define_);
      });
    }
  }

})();
<commit_msg>Add hidden class if props.hidden<commit_after>(function () {
  'use strict';

  var getLicon = function (React, _) {
    return React.createClass({
      getClassName: function () {
        var className = 'licon';

        // Icon type
        if (this.props.icon) {
          className += ' licon-' + this.props.icon;
        }

        // Size
        if (this.props.large) {
          className += ' licon-large';
        } else if (this.props.small) {
          className += ' licon-small';
        }

        // Border radius
        if (this.props.rounded) {
          className += ' licon-rounded';
        } else if (this.props.round) {
          className += ' licon-round';
        }

        // Border
        if (this.props.border) {
          className += ' licon-border';
        }

        if (this.props.hidden) {
          className += ' licon-hidden';
        }

        return className;
      },

      render: function () {
        var props = _.extend({}, this.props, { className: this.getClassName() });

        return (
          React.createElement(
            'span',
            props,
            React.createElement('span')
          )
        );
      }
    });
  };

  // Establish the root object, `window` in the browser, or `exports` on the server.
  var root = this || window;

  // Export for commonjs / browserify
  if (typeof exports !== 'undefined') {
    var React = require('react');
    var _ = require('underscore');
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = getLicon(React, _);
    }
    exports.Licon = getLicon(React, _);
  } else if (typeof root !== 'undefined') {
    if (typeof root.React !== 'undefined' && typeof root._ !== 'undefined') {
      // Add to root object
      root.Licon = getLicon(root.React, root._);
    }

    // Define for requirejs
    if (typeof root.define === 'function' && root.define.amd) {
      root.define(['react', 'underscore'], function(defineReact, define_) {
        return getLicon(defineReact, define_);
      });
    }
  }

})();
<|endoftext|>


<commit_before>import 'whatwg-fetch';
import codemirror from 'codemirror';
import 'codemirror/mode/javascript/javascript';
import analytics from './analytics';
import redirectTraffic from './redirect-traffic';
import layoutFunctions from './layoutFunctions';
import clickEvents from './clickEvents';
import drag from './drag';
import examples from './add-examples';
import libraries from './add-libraries';
import $ from './helpers';
import share from './share';
import snackbar from './snackbar';
import frameBridge from './frameBridge';
import MESSAGES from './sandbox/keys';

const codeWrapper = $.getElement('.code-wrapper'),
  fiddleWrapper = $.getElement('.fiddle-wrapper'),
  themeChanger = $.getElement('.change-theme'),
  savedTheme = localStorage.getItem('theme'),
  pathAr = location.pathname.split('/'),
  fiddleId = pathAr[pathAr.length - 2],
  embedded = pathAr[1] === 'embed',
  startFiddle = $.getElement('.star');

analytics.start();
redirectTraffic.register();

window.embedded = embedded;
window.exampleSelector = $.getElement('.examples');
examples.addExamples();

window.librariesSelector = $.getElement('.libraries');
libraries.addLibraries();

// check to see if the share button should be shown
if (fiddleId && !embedded) {
  const shareEl = $.getElement('.share');
  $.addStyleTo(startFiddle, 'display', 'block');
  if (shareEl) { share.shareFiddle(fiddleId); }
} else {
  $.addStyleTo(startFiddle, 'display', 'none');
}

// handle the embedded buttons
if (embedded) {
  const es6Btn = $.getElement('.es6-click-btn');
  const consoleBtn = $.getElement('.console-click-btn');
  $.getElement('.edit-at-es6').href = document.location.href.replace('/embed', '');

  es6Btn.onclick = () => {
    $.getElement('.fiddle').addStyle('display', 'block');
    $.getElement('.result-wrapper').addStyle('display', 'none');
    $.addClass(es6Btn, 'selected');
    $.removeClass(consoleBtn, 'selected');
  };

  consoleBtn.onclick = () => {
    $.getElement('.fiddle').addStyle('display', 'none');
    $.getElement('.result-wrapper').addStyle('display', 'block');
    $.removeClass(es6Btn, 'selected');
    $.addClass(consoleBtn, 'selected');
  };
}

// Change the layout of the page based on the type clicked.
// Save this layout choice in localStorage
// By default this will be vertical
$.getElement('.vertical').onclick = () => {
  layoutFunctions.setVerticalStyle(codeWrapper);
  layoutFunctions.saveLayoutOption('vertical');
};

// Onclick of the horizontal button then make the page visually horizontal
// And save the layout option clicked (in this case horizontal) to localstorage
$.getElement('.horizontal').onclick = () => {
  layoutFunctions.setHorizontalStyle(codeWrapper);
  layoutFunctions.saveLayoutOption('horizontal');
};

// add the fiddle area
const fiddle = codemirror($.getElement('.fiddle'), {
  lineNumbers: !embedded,
  readOnly: embedded ? 'nocursor' : false,
  theme: savedTheme || 'default',
});
fiddle.focus();

// If the user has previously selected to use the horizontal layout then load that
if (localStorage.getItem('es6fiddleLayout') === 'horizontal') {
  layoutFunctions.setHorizontalStyle(codeWrapper);
  // Otherwise make the page the default vertical style
} else {
  layoutFunctions.setVerticalStyle(codeWrapper);
}

// If the user has previously enabled dark mode then open in dark mode
if (localStorage.getItem('es6fiddleDarkMode') === 'true') {
  clickEvents.enableDarkMode();
} else {
  clickEvents.disableDarkMode();
}

// When the dark mode button is clicked, toggle the dark mode setting
$.getElement('.dark-mode').onclick = () => {
  clickEvents.darkModeClick(clickEvents.disableDarkMode, clickEvents.enableDarkMode, fiddle);
};

// Set the saved theme in the theme changer dropdown
if (savedTheme) {
  themeChanger.value = savedTheme;
}

// Add line number to all console.log() statements
function calculateLineNumber(fiddleValue) {
  const lines = fiddleValue.split(/\n/);
  let newLines = '';
  newLines = lines.map((line, index) => {
    const consReg = /(console\.log\()(.*)/;
    //  separate console.log from original string and split it in to
    // "console.log(" and ")"
    const clgLines = line.match(consReg);
    if (clgLines) {
      // Add line no: to console.log and join it with rest of the original line.
      // return line.slice(0, clgLines.index) + clgLines[1] + `'${index+1}: ' , ` +clgLines[2];
      return `${line.slice(0, clgLines.index) + clgLines[1]}'${index + 1}: ' , ${clgLines[2]}`;
    }
    return line;
  });
  return newLines.join('\n');
}

/* eslint-disable */
const runFiddle = () => {
  frameBridge.send(MESSAGES.RUN_SCRIPT, calculateLineNumber(fiddle.getValue()));
};

/* eslint-enable */

const getFiddle = (data) => {
  if (data.fiddle) {
    if (data.value) {
      fiddle.setValue(data.value);
    } else {
      fiddle.setValue('* Sorry, but I could not load your code right now. *');
    }
    if (data.isPrivate) {
      const privateIcon = $.getElement('.fa-globe');
      privateIcon.classList.remove('fa-globe');
      privateIcon.classList.add('fa-lock');
      privateIcon.parentElement.setAttribute('data-balloon', 'Private Fiddle');
    }
  } else {
    $.addStyleTo(startFiddle, 'display', 'none');
    fiddle.setValue(data.message);
  }

  if (embedded) { // go ahead and run the code
    runFiddle();
  }
};

// if fiddleId is define then load up the saved code
if (fiddleId) {
  fetch(`/fiddles/${fiddleId}`, {
    credentials: 'same-origin',
  }).then(resp => resp.json()).then(data => getFiddle(data));
}

// if this is not an embedded fiddle than add extra elements to this
if (!embedded) {
  // run the input
  $.getElement('.run').onclick = runFiddle;

  // lint the result
  $.getElement('.lint').onclick = () => {
    const lint = JSHINT(fiddle.getValue(), {
      esnext: true,
      devel: true,
      browser: true,
    });

    // remove the line error class from all lines
    fiddle.eachLine((line) => {
      fiddle.removeLineClass(line, 'background', 'line-error');
    });

    const lints = [];
    if (!lint) {
      JSHINT.errors.forEach((err) => {
        fiddle.addLineClass(err.line - 1, 'background', 'line-error');
        lints.push(`console.log('Line ' + ${err.line} + ':', '${err.reason.replace(/'/g, '\\\'')}')\n`);
      });
    } else {
      lints.push('console.log(\'Awesome! Your code is lint free!\');');
    }

    frameBridge.send(MESSAGES.RUN_SCRIPT, lints.join('\n'));
  };

  // export to Github gist
  $.getElement('.gist').onclick = () => clickEvents.exportAsGist(fiddle);

  // save the code
  document.querySelector('.save').onclick = () => clickEvents.saveBtn(fiddle);

  // star the code
  $.getElement('.star').onclick = () => {
    const pathArr = window.location.pathname.split('/'),
      fiddleID = pathArr[1].length > 1 ? pathArr[1] : -1;

    if (fiddleID !== -1) {
      fetch(`/star/${fiddleID}`, {
        method: 'POST',
        credentials: 'same-origin',
        headers: new Headers({
          'Content-Type': 'application/json',
        }),
      })
      .then(resp => resp.json())
      .then(data => clickEvents.starFiddle(data));
    }
  };

  // Make fiddle private
  $.getElement('.private').onclick = () => {
    const pathArr = window.location.pathname.split('/'),
      fiddleID = pathArr[1].length > 1 ? pathArr[1] : -1;

    if (fiddleID !== -1) {
      fetch(`/private/${fiddleID}`, {
        method: 'POST',
        credentials: 'same-origin',
        headers: new Headers({
          'Content-Type': 'application/json',
        }),
      })
          .then(resp => resp.json())
          .then(data => clickEvents.privateFiddle(data));
    } else {
      snackbar.showSnackbar('You don\'t appear to have any code or its not saved.');
    }
  };

  themeChanger.onchange = () => {
    const theme = themeChanger.options[themeChanger.selectedIndex].textContent;
    fiddle.setOption('theme', theme);
    localStorage.setItem('theme', theme);
  };

  // load the selected code
  window.exampleSelector.onchange = () => {
    if (window.exampleSelector.value) {
      let code = 'Example Can Not Be Found';

      if (window.es6Example[window.exampleSelector.value]) {
        ({ code } = window.es6Example[window.exampleSelector.value]);
      } else if (window.es7Example[window.exampleSelector.value]) {
        ({ code } = window.es7Example[window.exampleSelector.value]);
      }

      fiddle.setValue(code);
    }
  };

  // load the selected javascript library
  window.librariesSelector.onchange = () => {
    if (window.librariesSelector.value) {
      const script = $.createElement('script');
      script.onload = function onScriptLoad() {
        console.log(`${window.librariesSelector.selectedOptions[0].text} Script loaded`);
      };
      script.src = window.librariesSelector.value;

      document.head.appendChild(script);
    }
  };
} // end not embedded

// Add dragging funcionality
fiddleWrapper.addEventListener('click', function init() {
  fiddleWrapper.removeEventListener('click', init, false);
  $.getElement('.resizer').addEventListener('mousedown', drag.initDrag, false);
}, false);
<commit_msg>Add a dropdown for library selection, dynamically load predefined js libraries<commit_after>import 'whatwg-fetch';
import codemirror from 'codemirror';
import 'codemirror/mode/javascript/javascript';
import analytics from './analytics';
import redirectTraffic from './redirect-traffic';
import layoutFunctions from './layoutFunctions';
import clickEvents from './clickEvents';
import drag from './drag';
import examples from './add-examples';
import libraries from './add-libraries';
import $ from './helpers';
import share from './share';
import snackbar from './snackbar';
import frameBridge from './frameBridge';
import MESSAGES from './sandbox/keys';

const codeWrapper = $.getElement('.code-wrapper'),
  fiddleWrapper = $.getElement('.fiddle-wrapper'),
  themeChanger = $.getElement('.change-theme'),
  savedTheme = localStorage.getItem('theme'),
  pathAr = location.pathname.split('/'),
  fiddleId = pathAr[pathAr.length - 2],
  embedded = pathAr[1] === 'embed',
  startFiddle = $.getElement('.star');

analytics.start();
redirectTraffic.register();
window.embedded = embedded;
window.exampleSelector = $.getElement('.examples');
examples.addExamples();

window.librariesSelector = $.getElement('.libraries');
libraries.addLibraries();

// check to see if the share button should be shown
if (fiddleId && !embedded) {
  const shareEl = $.getElement('.share');
  $.addStyleTo(startFiddle, 'display', 'block');
  if (shareEl) { share.shareFiddle(fiddleId); }
} else {
  $.addStyleTo(startFiddle, 'display', 'none');
}

// handle the embedded buttons
if (embedded) {
  const es6Btn = $.getElement('.es6-click-btn');
  const consoleBtn = $.getElement('.console-click-btn');
  $.getElement('.edit-at-es6').href = document.location.href.replace('/embed', '');

  es6Btn.onclick = () => {
    $.getElement('.fiddle').addStyle('display', 'block');
    $.getElement('.result-wrapper').addStyle('display', 'none');
    $.addClass(es6Btn, 'selected');
    $.removeClass(consoleBtn, 'selected');
  };

  consoleBtn.onclick = () => {
    $.getElement('.fiddle').addStyle('display', 'none');
    $.getElement('.result-wrapper').addStyle('display', 'block');
    $.removeClass(es6Btn, 'selected');
    $.addClass(consoleBtn, 'selected');
  };
}

// Change the layout of the page based on the type clicked.
// Save this layout choice in localStorage
// By default this will be vertical
$.getElement('.vertical').onclick = () => {
  layoutFunctions.setVerticalStyle(codeWrapper);
  layoutFunctions.saveLayoutOption('vertical');
};

// Onclick of the horizontal button then make the page visually horizontal
// And save the layout option clicked (in this case horizontal) to localstorage
$.getElement('.horizontal').onclick = () => {
  layoutFunctions.setHorizontalStyle(codeWrapper);
  layoutFunctions.saveLayoutOption('horizontal');
};

// add the fiddle area
const fiddle = codemirror($.getElement('.fiddle'), {
  lineNumbers: !embedded,
  readOnly: embedded ? 'nocursor' : false,
  theme: savedTheme || 'default',
});
fiddle.focus();

// If the user has previously selected to use the horizontal layout then load that
if (localStorage.getItem('es6fiddleLayout') === 'horizontal') {
  layoutFunctions.setHorizontalStyle(codeWrapper);
  // Otherwise make the page the default vertical style
} else {
  layoutFunctions.setVerticalStyle(codeWrapper);
}

// If the user has previously enabled dark mode then open in dark mode
if (localStorage.getItem('es6fiddleDarkMode') === 'true') {
  clickEvents.enableDarkMode();
} else {
  clickEvents.disableDarkMode();
}

// When the dark mode button is clicked, toggle the dark mode setting
$.getElement('.dark-mode').onclick = () => {
  clickEvents.darkModeClick(clickEvents.disableDarkMode, clickEvents.enableDarkMode, fiddle);
};

// Set the saved theme in the theme changer dropdown
if (savedTheme) {
  themeChanger.value = savedTheme;
}

// Add line number to all console.log() statements
function calculateLineNumber(fiddleValue) {
  const lines = fiddleValue.split(/\n/);
  let newLines = '';
  newLines = lines.map((line, index) => {
    const consReg = /(console\.log\()(.*)/;
    //  separate console.log from original string and split it in to
    // "console.log(" and ")"
    const clgLines = line.match(consReg);
    if (clgLines) {
      // Add line no: to console.log and join it with rest of the original line.
      // return line.slice(0, clgLines.index) + clgLines[1] + `'${index+1}: ' , ` +clgLines[2];
      return `${line.slice(0, clgLines.index) + clgLines[1]}'${index + 1}: ' , ${clgLines[2]}`;
    }
    return line;
  });
  return newLines.join('\n');
}

/* eslint-disable */
const runFiddle = () => {
  frameBridge.send(MESSAGES.RUN_SCRIPT, calculateLineNumber(fiddle.getValue()));
};

/* eslint-enable */

const getFiddle = (data) => {
  if (data.fiddle) {
    if (data.value) {
      fiddle.setValue(data.value);
    } else {
      fiddle.setValue('* Sorry, but I could not load your code right now. *');
    }
    if (data.isPrivate) {
      const privateIcon = $.getElement('.fa-globe');
      privateIcon.classList.remove('fa-globe');
      privateIcon.classList.add('fa-lock');
      privateIcon.parentElement.setAttribute('data-balloon', 'Private Fiddle');
    }
  } else {
    $.addStyleTo(startFiddle, 'display', 'none');
    fiddle.setValue(data.message);
  }

  if (embedded) { // go ahead and run the code
    runFiddle();
  }
};

// if fiddleId is define then load up the saved code
if (fiddleId) {
  fetch(`/fiddles/${fiddleId}`, {
    credentials: 'same-origin',
  }).then(resp => resp.json()).then(data => getFiddle(data));
}

// if this is not an embedded fiddle than add extra elements to this
if (!embedded) {
  // run the input
  $.getElement('.run').onclick = runFiddle;

  // lint the result
  $.getElement('.lint').onclick = () => {
    const lint = JSHINT(fiddle.getValue(), {
      esnext: true,
      devel: true,
      browser: true,
    });

    // remove the line error class from all lines
    fiddle.eachLine((line) => {
      fiddle.removeLineClass(line, 'background', 'line-error');
    });

    const lints = [];
    if (!lint) {
      JSHINT.errors.forEach((err) => {
        fiddle.addLineClass(err.line - 1, 'background', 'line-error');
        lints.push(`console.log('Line ' + ${err.line} + ':', '${err.reason.replace(/'/g, '\\\'')}')\n`);
      });
    } else {
      lints.push('console.log(\'Awesome! Your code is lint free!\');');
    }

    frameBridge.send(MESSAGES.RUN_SCRIPT, lints.join('\n'));
  };

  // export to Github gist
  $.getElement('.gist').onclick = () => clickEvents.exportAsGist(fiddle);

  // save the code
  document.querySelector('.save').onclick = () => clickEvents.saveBtn(fiddle);

  // star the code
  $.getElement('.star').onclick = () => {
    const pathArr = window.location.pathname.split('/'),
      fiddleID = pathArr[1].length > 1 ? pathArr[1] : -1;

    if (fiddleID !== -1) {
      fetch(`/star/${fiddleID}`, {
        method: 'POST',
        credentials: 'same-origin',
        headers: new Headers({
          'Content-Type': 'application/json',
        }),
      })
      .then(resp => resp.json())
      .then(data => clickEvents.starFiddle(data));
    }
  };

  // Make fiddle private
  $.getElement('.private').onclick = () => {
    const pathArr = window.location.pathname.split('/'),
      fiddleID = pathArr[1].length > 1 ? pathArr[1] : -1;

    if (fiddleID !== -1) {
      fetch(`/private/${fiddleID}`, {
        method: 'POST',
        credentials: 'same-origin',
        headers: new Headers({
          'Content-Type': 'application/json',
        }),
      })
          .then(resp => resp.json())
          .then(data => clickEvents.privateFiddle(data));
    } else {
      snackbar.showSnackbar('You don\'t appear to have any code or its not saved.');
    }
  };

  themeChanger.onchange = () => {
    const theme = themeChanger.options[themeChanger.selectedIndex].textContent;
    fiddle.setOption('theme', theme);
    localStorage.setItem('theme', theme);
  };

  // load the selected code
  window.exampleSelector.onchange = () => {
    if (window.exampleSelector.value) {
      let code = 'Example Can Not Be Found';

      if (window.es6Example[window.exampleSelector.value]) {
        ({ code } = window.es6Example[window.exampleSelector.value]);
      } else if (window.es7Example[window.exampleSelector.value]) {
        ({ code } = window.es7Example[window.exampleSelector.value]);
      }

      fiddle.setValue(code);
    }
  };

  // load the selected javascript library
  window.librariesSelector.onchange = () => {
    if (window.librariesSelector.value) {
      const script = $.createElement('script');
      script.onload = function onScriptLoad() {
        console.log(`${window.librariesSelector.selectedOptions[0].text} Script loaded`);
      };
      script.src = window.librariesSelector.value;

      document.head.appendChild(script);
    }
  };
} // end not embedded

// Add dragging funcionality
fiddleWrapper.addEventListener('click', function init() {
  fiddleWrapper.removeEventListener('click', init, false);
  $.getElement('.resizer').addEventListener('mousedown', drag.initDrag, false);
}, false);
<|endoftext|>


<commit_before>'use strict';

import Promise from 'bluebird';

import Ui from './ui';
import Post from './post';
import Esa from './esa';

export default class Popup {
  constructor() {
    this.ui = new Ui();
    this.post = new Post();
    this.esa = undefined;
  }

  setPreviousPost() {
    Post.load((loadedPost) => {
      this.post = loadedPost;
      this.syncSaveButtonWithPost();

      this.ui.title = this.post.title;
      this.ui.body = this.post.body;
      if (this.ui.title != '') {
        // Move cursor at previous position
        this.ui.cursorPosition = this.post.cursorPosition;
      }
    });
  }

  setPreviousState() {
    return new Promise((resolve, reject) => {
      let defaultConfig = {
        teamName: '',
        token: '',
        teamIcon: '',
        savedPostLink: '',
        postId: '',
      };
      chrome.storage.sync.get(defaultConfig, (config) => {
        if (!config.teamName || !config.token) {
          this.ui.toggleDisplayOptionLink(true);
          this.ui.teamName = 'Configuration failed';

          reject('Please configure options (\\( ˘⊖˘)/)');
        }

        this.esa = new Esa(config);

        this.ui.toggleDisplayOptionLink(false);

        if (config.savedPostLink != '') {
          this.ui.savedPostLink = config.savedPostLink;
        } else {
          // NOTE: 0.2.1以前の後方互換性のための対応
          // TODO: 次々回のリリースで削除する（storageから取得する部分も一緒に削除する）
          this.ui.savedPostLink = `https://${config.teamName}.esa.io/posts/${
            config.postId
          }`;
        }

        this.ui.teamName = config.teamName;
        this.ui.teamIcon = config.teamIcon;

        resolve();
      });
    });
  }

  save() {
    this.ui.toggleDisabledSaveButton(true);
    this.ui.toggleUploadingStatus(true);

    this.searchTargetPostInEsa()
      .then(this.uploadPost.bind(this))
      .then(this.syncPostWithEsaResponse.bind(this))
      .then(this.syncUIWithPost.bind(this))
      .then(this.notifySuccess.bind(this))
      .catch(this.notifyError.bind(this))
      .finally(() => {
        this.ui.toggleUploadingStatus(false);
      });
  }

  searchTargetPostInEsa() {
    return new Promise((resolve, reject) => {
      let [category, title] = Post.splitCategory(this.ui.title);

      let q = `name:${title}`;
      if (category.length != 0) q = `${q} category:${category}`;

      let filterPostsFunc = (response) => {
        // nameによる検索は部分一致のため、完全一致させるために検索結果から更に絞り込んでいる
        let hitPost = Post.filterPosts(title, category, response);

        let postId = hitPost ? hitPost.number : undefined;
        resolve(postId);
      };

      this.esa.search(q, filterPostsFunc, reject);
    });
  }

  uploadPost(postId) {
    return new Promise((resolve, reject) => {
      let [category, title] = Post.splitCategory(this.ui.title);

      let postData = {
        id: postId,
        name: title,
        category: category,
        body_md: this.ui.body,
        message: 'from tsuibami',
      };

      this.esa.save(postData, resolve, reject);
    });
  }

  syncPostWithEsaResponse(response) {
    this.post.saved = true;
    this.post.savedPostLink = response.url;
    if (this.ui.isClearCheckBoxChecked) {
      this.post.title = '';
      this.post.body = '';
      this.post.cursorPosition = 0;
    } else {
      // 保存したタイトルによっては末尾に "(2)" などの表記がesaによってつけられていたり、タイトル無しで保存した場合にカテゴリが変わっている可能性があるため、内容を更新する
      this.post.title = response.full_name;
    }

    return new Promise((resolve, reject) => {
      this.post.store(
        () => {
          this.syncSaveButtonWithPost();
          resolve(response);
        },
        () => {
          reject(response);
        },
      );
    });
  }

  syncUIWithPost(response) {
    return new Promise((resolve, _reject) => {
      this.ui.title = this.post.title;
      this.ui.body = this.post.body;

      this.ui.savedPostLink = this.post.savedPostLink;
      resolve(response);
    });
  }

  syncSaveButtonWithPost() {
    this.ui.toggleDisabledSaveButton(this.post.saved);
  }

  notifySuccess(response) {
    let message;
    // 最初の保存の時だけメッセージを変える
    if (response.revision_number == 1) {
      message = 'created!';
    } else {
      message = 'updated!';
    }
    this.showMessage(message + ' (\\( ⁰⊖⁰)/)', true);
  }

  notifyError(msg) {
    console.log(msg);
    let message = msg.hasOwnProperty('statusText') ? msg.statusText : msg;
    message = msg.hasOwnProperty('status')
      ? `${message} (${msg.status})`
      : message;
    this.showMessage(message);
  }

  showMessage(message, succeeded) {
    if (succeeded) {
      this.ui.messageArea.showMessageOnSuccess(message);
    } else {
      this.ui.messageArea.showMessageOnFailure(message);
    }
  }
}
<commit_msg>Simplify<commit_after>'use strict';

import Promise from 'bluebird';

import Ui from './ui';
import Post from './post';
import Esa from './esa';

export default class Popup {
  constructor() {
    this.ui = new Ui();
    this.post = new Post();
    this.esa = undefined;
  }

  setPreviousPost() {
    Post.load((loadedPost) => {
      this.post = loadedPost;
      this.syncSaveButtonWithPost();

      this.ui.title = this.post.title;
      this.ui.body = this.post.body;
      if (this.ui.title != '') {
        // Move cursor at previous position
        this.ui.cursorPosition = this.post.cursorPosition;
      }
    });
  }

  setPreviousState() {
    return new Promise((resolve, reject) => {
      let defaultConfig = {
        teamName: '',
        token: '',
        teamIcon: '',
        savedPostLink: '',
        postId: '',
      };
      chrome.storage.sync.get(defaultConfig, (config) => {
        if (!config.teamName || !config.token) {
          this.ui.toggleDisplayOptionLink(true);
          this.ui.teamName = 'Configuration failed';

          reject('Please configure options (\\( ˘⊖˘)/)');
        }

        this.esa = new Esa(config);

        this.ui.toggleDisplayOptionLink(false);

        if (config.savedPostLink != '') {
          this.ui.savedPostLink = config.savedPostLink;
        } else {
          // NOTE: 0.2.1以前の後方互換性のための対応
          // TODO: 次々回のリリースで削除する（storageから取得する部分も一緒に削除する）
          this.ui.savedPostLink = `https://${config.teamName}.esa.io/posts/${
            config.postId
          }`;
        }

        this.ui.teamName = config.teamName;
        this.ui.teamIcon = config.teamIcon;

        resolve();
      });
    });
  }

  save() {
    this.ui.toggleDisabledSaveButton(true);
    this.ui.toggleUploadingStatus(true);

    this.searchTargetPostInEsa()
      .then(this.uploadPost.bind(this))
      .then(this.syncPostWithEsaResponse.bind(this))
      .then(this.syncUIWithPost.bind(this))
      .then(this.notifySuccess.bind(this))
      .catch(this.notifyError.bind(this))
      .finally(() => {
        this.ui.toggleUploadingStatus(false);
      });
  }

  searchTargetPostInEsa() {
    return new Promise((resolve, reject) => {
      let [category, title] = Post.splitCategory(this.ui.title);

      let q = `name:${title}`;
      if (category.length != 0) q = `${q} category:${category}`;

      let filterPostsFunc = (response) => {
        // nameによる検索は部分一致のため、完全一致させるために検索結果から更に絞り込んでいる
        let hitPost = Post.filterPosts(title, category, response);

        let postId = hitPost ? hitPost.number : undefined;
        resolve(postId);
      };

      this.esa.search(q, filterPostsFunc, reject);
    });
  }

  uploadPost(postId) {
    return new Promise((resolve, reject) => {
      let [category, title] = Post.splitCategory(this.ui.title);

      let postData = {
        id: postId,
        name: title,
        category: category,
        body_md: this.ui.body,
        message: 'from tsuibami',
      };

      this.esa.save(postData, resolve, reject);
    });
  }

  syncPostWithEsaResponse(response) {
    this.post.saved = true;
    this.post.savedPostLink = response.url;
    if (this.ui.isClearCheckBoxChecked) {
      this.post.title = '';
      this.post.body = '';
      this.post.cursorPosition = 0;
    } else {
      // 保存したタイトルによっては末尾に "(2)" などの表記がesaによってつけられていたり、タイトル無しで保存した場合にカテゴリが変わっている可能性があるため、内容を更新する
      this.post.title = response.full_name;
    }

    return new Promise((resolve, reject) => {
      this.post.store(
        () => {
          this.syncSaveButtonWithPost();
          resolve(response);
        },
        () => {
          reject(response);
        },
      );
    });
  }

  syncUIWithPost(response) {
    return new Promise((resolve, _reject) => {
      this.ui.title = this.post.title;
      this.ui.body = this.post.body;

      this.ui.savedPostLink = this.post.savedPostLink;
      resolve(response);
    });
  }

  syncSaveButtonWithPost() {
    this.ui.toggleDisabledSaveButton(this.post.saved);
  }

  notifySuccess(response) {
    // 最初の保存の時だけメッセージを変える
    let message = response.revision_number == 1 ? 'created!' : 'updated!';
    this.showMessage(message + ' (\\( ⁰⊖⁰)/)', true);
  }

  notifyError(msg) {
    console.log(msg);
    let message = msg.hasOwnProperty('statusText') ? msg.statusText : msg;
    message = msg.hasOwnProperty('status')
      ? `${message} (${msg.status})`
      : message;
    this.showMessage(message);
  }

  showMessage(message, succeeded) {
    if (succeeded) {
      this.ui.messageArea.showMessageOnSuccess(message);
    } else {
      this.ui.messageArea.showMessageOnFailure(message);
    }
  }
}
<|endoftext|>


<commit_before>/*global define*/
define([
        'require',
        'jquery',
        'fx-c-c/adapters/star_schema_adapter',
        'fx-c-c/templates/base_template',
        'fx-c-c/creators/highcharts_creator',
        'highcharts'
    ],
    function (RequireJS, $) {

        'use strict';

        var defaultOptions = {
            default: ''
        };

        function ChartCreator() {
            $.extend(true, this, defaultOptions);
            return this;
        }

        ChartCreator.prototype.init = function (config) {

            if (this._validateInput(config)) {

                this.preloadResources(config);
            }

            /* if (config.render) {
             this.render(config.render);
             }*/
        };

        ChartCreator.prototype.render = function (config) {

            var series = [];

            this.template.render(config);

            for (var i =0 ; i < config.series.length; i++ ) {
                series.push(this.adapter.getData(config.series[i]))
            }

            config.chart_series = series;

            this.creator.render(config);
        };

        ChartCreator.prototype.preloadResources = function (config) {

            var baseTemplate = this.getTemplateUrl(),
                adapter = this.getAdapterUrl(),
                creator = this.getCreatorUrl(),
                self = this;

            RequireJS([
                baseTemplate,
                adapter,
                creator
            ], function (Template, Adapter, Creator) {

                self.template = new Template($.extend(true, {model: config.model}, config.template));
                self.adapter = new Adapter($.extend(true, {model: config.model}, config.adapter));
                self.creator = new Creator($.extend(true, {model: config.model}, config.creator));

                self.adapter.prepareData($.extend(true, {model: config.model}, config.adapter));

                if (typeof config.onReady === 'function'){
                    config.onReady();
                }

            });
        };

        ChartCreator.prototype.getAdapterUrl = function () {
            //TODO add here adapter discovery logic
            return this.adapterUrl ? this.adapterUrl : 'fx-c-c/adapters/star_schema_adapter';
        };

        ChartCreator.prototype.getTemplateUrl = function () {
            //TODO add here template discovery logic
            return this.templateUrl ? this.templateUrl : 'fx-c-c/templates/base_template';
        };

        ChartCreator.prototype.getCreatorUrl = function () {
            //TODO add here template discovery logic
            return this.creatorUrl ? this.creatorUrl : 'fx-c-c/creators/highcharts_creator';
        };

        ChartCreator.prototype._validateInput = function () {
            return true;
        };

        return ChartCreator;
    });<commit_msg>clean up<commit_after>/*global define*/
define([
        'require',
        'jquery',
        'fx-c-c/adapters/star_schema_adapter',
        'fx-c-c/templates/base_template',
        'fx-c-c/creators/highcharts_creator',
        'highcharts'
    ],
    function (RequireJS, $) {

        'use strict';

        var defaultOptions = {
            default: ''
        };

        function ChartCreator() {
            $.extend(true, this, defaultOptions);
            return this;
        }

        ChartCreator.prototype.init = function (config) {

            if (this._validateInput(config)) {

                this.preloadResources(config);
            }

            /* if (config.render) {
             this.render(config.render);
             }*/
        };

        ChartCreator.prototype.render = function (config) {

            var series = [];

            this.template.render(config);

            for (var i =0 ; i < config.series.length; i++ ) {
                series.push(this.adapter.getData(config.series[i]));
            }

            config.chart_series = series;

            this.creator.render(config);
        };

        ChartCreator.prototype.preloadResources = function (config) {

            var baseTemplate = this.getTemplateUrl(),
                adapter = this.getAdapterUrl(),
                creator = this.getCreatorUrl(),
                self = this;

            RequireJS([
                baseTemplate,
                adapter,
                creator
            ], function (Template, Adapter, Creator) {

                self.template = new Template($.extend(true, {model: config.model}, config.template));
                self.adapter = new Adapter($.extend(true, {model: config.model}, config.adapter));
                self.creator = new Creator($.extend(true, {model: config.model}, config.creator));

                self.adapter.prepareData($.extend(true, {model: config.model}, config.adapter));

                if (typeof config.onReady === 'function'){
                    config.onReady();
                }

            });
        };

        ChartCreator.prototype.getAdapterUrl = function () {
            //TODO add here adapter discovery logic
            return this.adapterUrl ? this.adapterUrl : 'fx-c-c/adapters/star_schema_adapter';
        };

        ChartCreator.prototype.getTemplateUrl = function () {
            //TODO add here template discovery logic
            return this.templateUrl ? this.templateUrl : 'fx-c-c/templates/base_template';
        };

        ChartCreator.prototype.getCreatorUrl = function () {
            //TODO add here template discovery logic
            return this.creatorUrl ? this.creatorUrl : 'fx-c-c/creators/highcharts_creator';
        };

        ChartCreator.prototype._validateInput = function () {
            return true;
        };

        return ChartCreator;
    });<|endoftext|>


<commit_before>var fs = require('fs'),
	path = require('path');

var storage = function(key, value) {
	if (value) {
		window.localStorage[key] = value;
	} else {
		return window.localStorage[key];
	}
};

var defaults = {
	port: {
		type: 'number',
		value: 8888
	},
	basicRule: {
		type: 'object',
		value: {
			beforeRequests: false,
			afterResponses: false
		}
	}
};

var config = function(key, value) {
	if (value !== undefined) {
		saveConfig(key, value);
	} else {
		return getConfig(key);
	}
};

var saveConfig = function(key, value) {
	switch(defaults[key].type) {
	case 'number':
		value = '' + value;
		break;
	case 'boolean':
		value = value === true ? 'true' : 'false';
		break;
	case 'object':
		value = JSON.stringify(value);
		break;
	default:
		break;
	}

	window.localStorage[key] = value;
};

var getConfig = function(key) {
	var val = window.localStorage[key];

	if (val) {
		switch(defaults[key].type) {
		case 'number':
			val = parseInt(val, 10);
			break;
		case 'boolean':
			val = val == 'true' ? true : false;
			break;
		case 'object':
			val = JSON.parse(val);
			break;
		default:
			break;
		}
	} else {
		val = defaults[key].value;
	}

	return val;
};

var err = function(str) {
	return function(err) {
		if (err) {
			throw { message: err };
		}
	};
};

var rmdir = function(dirPath) {
	var list = fs.readdirSync(dirPath);

	for (var i=0; i<list.length; i++) {
		var filename = path.join(dirPath, list[i]);
		var stat = fs.statSync(filename);

		if (!(filename == '.' || filename == '..')) {
			fs.unlinkSync(filename);
		}
	}
	fs.rmdirSync(dirPath);
};

var noerr = function(next) {
	return function() {
		var args = Array.prototype.slice.call(arguments);
		args.unshift(null);
		next.apply(null, args);
	};
};

var apply = function(_this, _function) {
	return function() {
		var args = Array.prototype.slice.call(arguments);
		args.unshift(_this);
		_function.apply(null, args);
	};
};

module.exports = exports = {
	storage: storage,
	config: config,
	err: err,
	rmdir: rmdir,
	noerr: noerr,
	apply: apply,
	empty: function() { }
};<commit_msg>すべての設定を取得する関数を追加<commit_after>var fs = require('fs'),
	path = require('path');

var storage = function(key, value) {
	if (value) {
		window.localStorage[key] = value;
	} else {
		return window.localStorage[key];
	}
};

var defaults = {
	port: {
		type: 'number',
		value: 8888,
		user: true
	},
	basicRule: {
		type: 'object',
		value: {
			beforeRequests: false,
			afterResponses: false
		},
		user: false
	}
};

var config = function(key, value) {
	if (value !== undefined) {
		saveConfig(key, value);
	} else {
		return getConfig(key);
	}
};

var saveConfig = function(key, value) {
	switch(defaults[key].type) {
	case 'number':
		value = '' + value;
		break;
	case 'boolean':
		value = value === true ? 'true' : 'false';
		break;
	case 'object':
		value = JSON.stringify(value);
		break;
	default:
		break;
	}

	window.localStorage[key] = value;
};

var getConfig = function(key) {
	var val = window.localStorage[key];

	if (val) {
		switch(defaults[key].type) {
		case 'number':
			val = parseInt(val, 10);
			break;
		case 'boolean':
			val = val == 'true' ? true : false;
			break;
		case 'object':
			val = JSON.parse(val);
			break;
		default:
			break;
		}
	} else {
		val = defaults[key].value;
	}

	return val;
};

var getAllConfig = function() {
	var ret = { };

	for (var key in defaults) {
		ret[key] = defaults[key];
		ret[key].value = getConfig(key);
	}

	return ret;
}

var err = function(str) {
	return function(err) {
		if (err) {
			throw { message: err };
		}
	};
};

var rmdir = function(dirPath) {
	var list = fs.readdirSync(dirPath);

	for (var i=0; i<list.length; i++) {
		var filename = path.join(dirPath, list[i]);
		var stat = fs.statSync(filename);

		if (!(filename == '.' || filename == '..')) {
			fs.unlinkSync(filename);
		}
	}
	fs.rmdirSync(dirPath);
};

var noerr = function(next) {
	return function() {
		var args = Array.prototype.slice.call(arguments);
		args.unshift(null);
		next.apply(null, args);
	};
};

var apply = function(_this, _function) {
	return function() {
		var args = Array.prototype.slice.call(arguments);
		args.unshift(_this);
		_function.apply(null, args);
	};
};

module.exports = exports = {
	storage: storage,
	config: config,
	getAll: getAllConfig,
	err: err,
	rmdir: rmdir,
	noerr: noerr,
	apply: apply,
	empty: function() { }
};<|endoftext|>


<commit_before>const _ = require('lodash');

const constants = require('./constants');
const types = require('./propTypes');

/**
 * Reduces list or lists type into a single array of rows, as well as collect useful information about rows as they are
 * collected.
 * @param  {object} prevState             The previous state of the reduce function. Matches the return value.
 * @param  {string} headerClassName       className to attach to the row containing the header component of a given list
 * @param  {renderable} headerComponent   a React renderable component that will be the header of a given list
 * @param  {object} headerProps           props to pass to the header component
 * @param  {number} height                The height of the header component
 * @param  {boolean} initCollapsed        whether a given list is collapsed or not. This only applies when constructing
 *                                        the first row state
 * @param  {array} rows                   List of rows to copy into state
 * @param  {number} index                 index of the reduce operation
 * @return {object}                       see comment at the return
 */
function reduceRowsIntoRowConfig(
  prevState, { headerClassName, headerComponent, headerProps, height, initCollapsed, rows: inRows }, index
) {
  const {
    adjustHeaderOffset,
    collapsedSections,
    contentHeight: prevHeight,
    headers,
    stackHeaders,
    offsetBuffer,
    offsetCount: prevOffset,
    partitions
  } = prevState;
  let { rows: outRows } = prevState;
  let contentHeight = prevHeight;
  let nextOffset = prevOffset;
  let newHeaderOffset = adjustHeaderOffset;

  if (headerComponent) {
    nextOffset++;
    nextOffset %= offsetBuffer;

    if (nextOffset === 0) {
      partitions.push(contentHeight);
    }

    headers.push({
      adjustHeaderOffset,
      index: outRows.length,
      height,
      lockPosition: contentHeight - adjustHeaderOffset,
      realOffset: contentHeight
    });

    if (stackHeaders) {
      newHeaderOffset += height;
    }

    if (_.isUndefined(collapsedSections[index])) {
      collapsedSections[index] = !!initCollapsed;
    }

    contentHeight += height;
    outRows.push({
      className: headerClassName,
      contentComponent: headerComponent,
      height,
      isHeader: true,
      props: headerProps
    });
  }

  if (!headerComponent || !collapsedSections[index]) {
    outRows = _.concat(outRows, _.map(inRows, row => {
      nextOffset++;
      nextOffset %= offsetBuffer;

      if (nextOffset === 0) {
        partitions.push(contentHeight);
      }

      contentHeight += row.height;
      return row;
    }));
  }

  return {
    adjustHeaderOffset: newHeaderOffset, // keeps a running tally of the headeroffsets, used for locking/stagnig headers
    collapsedSections, // an array of boolean values corresponding to each section in the lists object
    contentHeight, // the height of the content contained by this list
    headers, // an array containing header data, (offsets, row index, height, lockPosition)
    stackHeaders, // should we be calculating headerOffsets from height
    offsetBuffer, // number of rows to display per partition
    offsetCount: nextOffset, // keeps track of partition size inbetween reductions
    partitions, // an array mapping the starting partition indices to starting vertical transforms
    rows: outRows // the rows that we will use as state
  };
}

/**
 * Initializes the reduce call to reduceRowsIntoRowConfig. The step where we convert a list prop into lists is done here
 * @param  {array} list                     List or lists prop.
 * @param  {number} offsetBuffer            The number of rows per partition
 * @param  {boolean} stackHeaders           Signifies that we should do the math to calculate stacking header offsets
 * @param  {Array}  [collapsedSections=[]]  The collapsedSection state from the scrollable class
 * @return {object}                         Reduces the list/lists into consumable state for the scrollable
 */
function buildRowConfig(list, offsetBuffer, stackHeaders, collapsedSections = []) {
  const offsetCount = offsetBuffer - 1;

  if (list.length === 0) {
    return { contentHeight: 0, headers: null, partitions: [], rows: [] };
  }

  function avgRowHeight(config) {
    const {
      contentHeight,
      rows: { length }
    } = config;
    return _.assign(config, {
      avgRowHeight: length && _.ceil(contentHeight / length)
    });
  }

  if (list[0] && list[0].headerComponent) {
    return avgRowHeight(_.reduce(list, reduceRowsIntoRowConfig, {
      adjustHeaderOffset: 0,
      collapsedSections,
      contentHeight: 0,
      headers: [],
      stackHeaders,
      offsetBuffer,
      offsetCount,
      partitions: [],
      rows: []
    }));
  }

  return avgRowHeight(_.reduce([{ rows: list }], reduceRowsIntoRowConfig, {
    contentHeight: 0,
    collapsedSections,
    headers: null,
    offsetBuffer,
    offsetCount,
    partitions: [],
    rows: []
  }));
}

/**
 * assign meaning to math
 * @param  {number} contentHeight the height of the content
 * @param  {number} offsetHeight  the offsetHeight from the vertical scrollbar
 * @return {number}               the difference between contentHeight and offsetHeight
 */
function getMaxHeight(contentHeight, offsetHeight) {
  return contentHeight - offsetHeight;
}

/**
 * calculates the width of a gutter via mouse movement. Also takes into account minWidth bound of a gutter.
 * @param  {string} side             which side are we resizing
 * @param  {Number} [minWidth=0]     the minimum value the gutter may be resized to
 * @param  {number} baseWidth        the width we started with when we began resizing
 * @param  {number} startingPosition position our mouse was in when we started resizing
 * @param  {number} currentPosition  current position of our mouse
 * @return {number}                  the next width of the gutter
 */
function getResizeWidth(side, minWidth = 0, baseWidth, startingPosition, currentPosition) {
  const deltaWidth = startingPosition - currentPosition;
  const modifier = side === constants.handleClass.LEFT ? -1 : 1;
  return Math.max(minWidth, baseWidth + (modifier * deltaWidth));
}

/**
 * calculates which partition is the top of our renderable content and clamps verticalTransform to within min/max values
 * @param  {number} preClampTransform vertical transform before we clamp it between min / max values
 * @param  {number} maxHeight         maximum height our vertical transform can reach
 * @param  {array} partitions         list of numbers which represent the starting vertical transformation of partitions
 *                                    by index (partitions[5] is the starting vertical transform of the 6th partition)
 * @return {object}                   topPartionIndex and the clamped verticalTransform
 */
function getScrollValues(preClampTransform, maxHeight, partitions) {
  const verticalTransform = _.clamp(preClampTransform, 0, maxHeight);
  const topPartitionIndex = _.findIndex(
    partitions, partitionStartingIndex => partitionStartingIndex > verticalTransform
  ) - 1;
  return { topPartitionIndex, verticalTransform };
}

/**
 * helper function that returns a very strict width object for gutters
 * @param  {Number} [width=0] the width we wish to express as a style object
 * @return {object}           a style object representing a the given width
 */
function getWidthStyle(width = 0) {
  return _.isNumber(width) && width > 0 ? {
    minWidth: `${width}px`,
    width: `${width}px`
  } : undefined;
}

module.exports = {
  buildRowConfig,
  getMaxHeight,
  getResizeWidth,
  getScrollValues,
  getWidthStyle,
  types
};
<commit_msg>4x speed improvement on prop transition<commit_after>const fp = require('lodash/fp');

const constants = require('./constants');
const types = require('./propTypes');

function avgRowHeight(config) {
  const {
    contentHeight,
    rows: { length }
  } = config;
  return _.assign(config, {
    avgRowHeight: length && _.ceil(contentHeight / length)
  });
}

/**
 * Initializes the reduce call to reduceRowsIntoRowConfig. The step where we convert a list prop into lists is done here
 * @param  {array} list                     List or lists prop.
 * @param  {number} offsetBuffer            The number of rows per partition
 * @param  {boolean} stackHeaders           Signifies that we should do the math to calculate stacking header offsets
 * @param  {Array}  [collapsedSections=[]]  The collapsedSection state from the scrollable class
 * @return {object}                         Reduces the list/lists into consumable state for the scrollable
 */
function buildRowConfig(list, offsetBuffer, stackHeaders, collapsedSections = []) {
  let offsetCount = offsetBuffer - 1;

  if (list.length === 0) {
    return { contentHeight: 0, headers: null, partitions: [], rows: [] };
  }

  const isMultiList = Boolean(list[0] && list[0].headerComponent);

  const lists = isMultiList ? list : [{ rows: list }];

  let numRows = 0;
  let listIterator = lists.length;

  while (listIterator--) {
    numRows += 1 + lists[listIterator].rows.length;
  }

  if (!isMultiList) {
    numRows--;
  }

  const rows = new Array(numRows);
  const headers = [];
  const partitions = [];

  let controlIterator = numRows;
  let rowIterator = -1;
  let insertionIterator = 0;
  let adjustHeaderOffset = 0;
  let contentHeight =  0;
  let listItem;

  listIterator = 0;

  while (controlIterator--) {
    if (rowIterator === -1) {
      listItem = lists[listIterator];
      rowIterator++;

      if (listItem.headerComponent) {
        offsetCount++;
        offsetCount %= offsetBuffer;

        if (offsetCount === 0) {
          partitions.push(contentHeight);
        }

        headers.push({
          adjustHeaderOffset,
          index: insertionIterator,
          height: listItem.height,
          lockPosition: contentHeight - adjustHeaderOffset,
          realOffset: contentHeight
        });

        if (stackHeaders) {
          adjustHeaderOffset += listItem.height;
        }

        if (collapsedSections[listIterator] === undefined) {
          collapsedSections[listIterator] = Boolean(listItem.initCollapsed);
        }

        contentHeight += listItem.height;
        rows[insertionIterator++] = {
          className: listItem.headerClassName,
          contentComponent: listItem.headerComponent,
          height: listItem.height,
          isHeader: true,
          props: listItem.headerProps
        };
      }

      if (isMultiList) {
        continue;
      }
    }

    if (collapsedSections[listIterator]) {
      controlIterator -= listItem.rows.length - 1;
      continue;
    }

    const row = listItem.rows[rowIterator++];

    offsetCount++;
    offsetCount %= offsetBuffer;

    if (offsetCount === 0) {
      partitions.push(contentHeight);
    }

    contentHeight += row.height;

    rows[insertionIterator++] = row;

    if (listItem.rows.length === rowIterator) {
      rowIterator = -1;
      listIterator++;
    }
  }

  return avgRowHeight({
    adjustHeaderOffset,
    collapsedSections,
    contentHeight,
    headers,
    stackHeaders,
    offsetBuffer,
    offsetCount,
    partitions,
    rows
  });
}

/**
 * assign meaning to math
 * @param  {number} contentHeight the height of the content
 * @param  {number} offsetHeight  the offsetHeight from the vertical scrollbar
 * @return {number}               the difference between contentHeight and offsetHeight
 */
function getMaxHeight(contentHeight, offsetHeight) {
  return contentHeight - offsetHeight;
}

/**
 * calculates the width of a gutter via mouse movement. Also takes into account minWidth bound of a gutter.
 * @param  {string} side             which side are we resizing
 * @param  {Number} [minWidth=0]     the minimum value the gutter may be resized to
 * @param  {number} baseWidth        the width we started with when we began resizing
 * @param  {number} startingPosition position our mouse was in when we started resizing
 * @param  {number} currentPosition  current position of our mouse
 * @return {number}                  the next width of the gutter
 */
function getResizeWidth(side, minWidth = 0, baseWidth, startingPosition, currentPosition) {
  const deltaWidth = startingPosition - currentPosition;
  const modifier = side === constants.handleClass.LEFT ? -1 : 1;
  return Math.max(minWidth, baseWidth + (modifier * deltaWidth));
}

/**
 * calculates which partition is the top of our renderable content and clamps verticalTransform to within min/max values
 * @param  {number} preClampTransform vertical transform before we clamp it between min / max values
 * @param  {number} maxHeight         maximum height our vertical transform can reach
 * @param  {array} partitions         list of numbers which represent the starting vertical transformation of partitions
 *                                    by index (partitions[5] is the starting vertical transform of the 6th partition)
 * @return {object}                   topPartionIndex and the clamped verticalTransform
 */
function getScrollValues(preClampTransform, maxHeight, partitions) {
  const verticalTransform = fp.clamp(0, maxHeight, preClampTransform);
  const topPartitionIndex = fp.findIndex(
    partitionStartingIndex => partitionStartingIndex > verticalTransform,
    partitions
  ) - 1;
  return { topPartitionIndex, verticalTransform };
}

/**
 * helper function that returns a very strict width object for gutters
 * @param  {Number} [width=0] the width we wish to express as a style object
 * @return {object}           a style object representing a the given width
 */
function getWidthStyle(width = 0) {
  return fp.isNumber(width) && width > 0 ? {
    minWidth: `${width}px`,
    width: `${width}px`
  } : undefined;
}

module.exports = {
  buildRowConfig,
  getMaxHeight,
  getResizeWidth,
  getScrollValues,
  getWidthStyle,
  types
};
<|endoftext|>


<commit_before>
function daysInMonth(month,year) {
  return new Date(year, month + 1, 0).getDate();
}

function kmhToDegsPerH(kmh) {
  return kmh / 111;
}

module.exports.daysInMonth = daysInMonth;
module.exports.kmhToDegsPerH = kmhToDegsPerH;
<commit_msg>Add function for calculating time range in months<commit_after>
var moment = require('moment');

function daysInMonth(month,year) {
  return new Date(year, month + 1, 0).getDate();
}

function kmhToDegsPerH(kmh) {
  return kmh / 111;
}

function timeRangeInMonths(timeRange) {
  return Math.round(moment(timeRange[1]*1000).diff(moment(timeRange[0]*1000), 'months', true));
}

module.exports.daysInMonth = daysInMonth;
module.exports.kmhToDegsPerH = kmhToDegsPerH;
module.exports.timeRangeInMonths = timeRangeInMonths;
<|endoftext|>


<commit_before>require(['GlRenderer', 'stats'], function(GlRenderer, Stats) {
    var stats = new Stats();
    stats.setMode(0);

    // init canvas width to that of window
    var canvas = document.getElementById('canvas');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    var renderer = null;

    // align top-left
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';
    document.body.appendChild(stats.domElement);

    // local video
    var video = document.createElement('video');
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia || navigator.msGetUserMedia;

    if (navigator.getUserMedia) {
        navigator.getUserMedia({
            video: true
        }, function (stream) {
            video.src = window.URL.createObjectURL(stream);
            video.onloadedmetadata = function(e) {
                video.play();

                renderer = new GlRenderer(canvas, false, video);
                renderFrame();
            };
            video.width = 512;
            video.height = 256;
        }, function (err) {
            alert('Request camera failed');
        });
    } else {
        alert('getUserMedia not supported');
    }

    function renderFrame() {
        stats.begin();

        // if (video.readyState === video.HAVE_ENOUGH_DATA) {
            // setTimeout(function() {

            renderer.render();
        // }, 1000);
        // }

        stats.end();

        // requestAnimationFrame(renderFrame);
    }
});
<commit_msg>video shader not working<commit_after>require(['GlRenderer', 'stats'], function(GlRenderer, Stats) {
    var stats = new Stats();
    stats.setMode(0);

    // init canvas width to that of window
    var canvas = document.getElementById('canvas');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    var renderer = null;

    // align top-left
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';
    document.body.appendChild(stats.domElement);

    // local video
    var video = document.createElement('video');
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia || navigator.msGetUserMedia;

    if (navigator.getUserMedia) {
        navigator.getUserMedia({
            video: true
        }, function (stream) {
            video.src = window.URL.createObjectURL(stream);
            video.onloadedmetadata = function(e) {
                video.play();

                renderer = new GlRenderer(canvas, false, video);
                renderFrame();
            };
            video.width = 512;
            video.height = 256;
        }, function (err) {
            alert('Request camera failed');
        });
    } else {
        alert('getUserMedia not supported');
    }

    function renderFrame() {
        stats.begin();

        renderer.render();

        stats.end();

        requestAnimationFrame(renderFrame);
    }
});
<|endoftext|>


<commit_before>var https = require('https'),
    expect = require('chai').expect,
    sodium = require('sodium').api,
    util = require('util'),
    fs = require('fs'),
    myutil = require('../libs/util.js')
    axolotl = require("../libs/axolotl.js"),
    schema = require('../models/schema.js'),
    mongoose = require('mongoose'),
    ds = require('../models/DataSourceMongoose.js');

var AxolotlState = mongoose.model('AxolotlState');
var DataSource = ds.DataSource;
/**
 * Create a database connection to use globally throughout the program.
 */
global.db_conn = mongoose.connect('mongodb://localhost/keys');

var headers = {
    'user-agent': 'test-client',
    'Content-Type': 'application/json; charset=utf-8'/*,
    'Content-Length': */
};

var options = {
    hostname: '127.0.0.1',
    port: 8888,
    path: '/',
    method: 'GET',
    headers: headers,
    rejectUnauthorized: false,
    requestCert: true,
};

function exchangeKeys(callback)
{
    var dsm = new DataSource(),
        state = dsm.axolotl_state.create();
    var aliceParams = {
        'id' : sodium.crypto_box_keypair (),
        'eph0' : sodium.crypto_box_keypair ()
    }
    var aliceKeyExchangeMsg =               //build message with public id and ephemeral key
    {
        'id' : aliceParams.id.publicKey.toString('base64'),
        'eph0' : aliceParams.eph0.publicKey.toString('base64')
    }
    var keyExchangeOut =
    {
        "type" : "KEYXC",
        "keys" : aliceKeyExchangeMsg
    };
    function updateStateAlice(keys, keyExchangeIn) {
        state.root_key              = keys.rk;
        state.chain_key_recv        = keys.ck; // Alice is Client. So we set CKr first.
        state.header_key_recv       = keys.hk;
        state.next_header_key_send  = keys.nhk0;
        state.next_header_key_recv  = keys.nhk1;
        state.dh_identity_key_send  = aliceParams.id.secretKey;
        state.dh_identity_key_send_pub  = aliceParams.id.publicKey;
        state.dh_identity_key_recv  = new Buffer(keyExchangeIn.id, 'base64');
        state.dh_ratchet_key_recv   = new Buffer(keyExchangeIn.eph1, 'base64');
        state.counter_send = 0;
        state.counter_recv = 0;
        state.previous_counter_send = 0;
        state.ratchet_flag = true;
        // Alice's state is not a data source, so we need to save this by hand.
        myutil.debug('Header key:', state.next_header_key_send);
        dsm.axolotl_state.save(function (err, state) {
            expect(err).to.not.exist;
            callback(keyExchangeIn.id, aliceParams);
        });
    }
    var jkeyExchangeOut = JSON.stringify(keyExchangeOut);
    options.headers['Content-Length'] = jkeyExchangeOut.length;
    var jkeyExchangeIn = '';
    var keyExchangeIn;

    var req = https.request(options, function(res)    //send KeyExchange message
    {
        res.on('data', function(d)   //get response from Server
        {
            jkeyExchangeIn += d;
        });
        res.on('end', function ()
        {
            keyExchangeIn = JSON.parse(jkeyExchangeIn);
            axolotl.keyAgreementAlice(aliceParams, keyExchangeIn, function(err, keys)
            {
                if (err)
                {
                    throw new Error('Apparently Alice could not finish the key agreement.');
                }
                else
                {
                    updateStateAlice(keys, keyExchangeIn);
                }
            });
        });
    });

    req.on('error', function(e)
    {
        console.error(e);
    });

    myutil.debug('Sending:', jkeyExchangeOut);
    req.write(jkeyExchangeOut);
    req.end();
}

var message = {
    "type" : "PROXY",
    "payload": "Hallo Server!"
};

describe('Simple test client', function()
{
    describe('Key exchange and message', function()
    {
        var aliceParams;
        var bobID;
        it('should encrypt and decrypt messages from the backend', function(done)
        {
            exchangeKeys(function(remoteID, localParams)
            {
                aliceParams = localParams;
                bobID = remoteID;
                var jMessage = JSON.stringify(message);
                myutil.debug('Encrypting message:', jMessage, 'for', bobID );
                axolotl.sendMessage(bobID, jMessage, function(err, ciphertext, state)
                {
                    expect(err, 'Error from sending message').to.not.exist;
                    myutil.debug('Encrypted message:', ciphertext);
                    var result = '';
                    ciphertext.type = 'CRYPT';
                    ciphertext.from = aliceParams.id.publicKey.toString('base64');
                    var jPayload = JSON.stringify(ciphertext);
                    options.headers['Content-Length'] = jPayload.length;
                    var req = https.request(options, function(res)
                    {
                        res.on('data', function(d)
                        {
                            result += d;
                        });
                        res.on('end', function ()
                        {
                            result = JSON.parse(result);
                            myutil.debug('Received answer:', result);
                            axolotl.recvMessage(bobID, result, function(err, plaintext)
                            {
                                expect(err).to.not.exist;
                                myutil.debug('Decrypted message:', plaintext);
                                done();
                            });
                        });
                    });
                    req.on('error', function(e)
                    {
                        console.error(e);
                    });
                    myutil.debug('Sending message:', jPayload);
                    req.write(jPayload);
                    req.end();
                });
            });
        });
        after (function (done){
            AxolotlState.remove({
                    dh_identity_key_recv : new Buffer(aliceParams.id.publicKey, 'base64')
                },
                function()
                {
                });
            AxolotlState.remove({
                    dh_identity_key_recv : new Buffer(bobID, 'base64')
                }, function()
                {
                });
            done();
        });
    });
});

<commit_msg>workaround for database connection issues<commit_after>var https = require('https'),
    main = require('../main.js'),
    expect = require('chai').expect,
    sodium = require('sodium').api,
    util = require('util'),
    fs = require('fs'),
    myutil = require('../libs/util.js')
    axolotl = require("../libs/axolotl.js"),
    schema = require('../models/schema.js'),
    mongoose = require('mongoose'),
    ds = require('../models/DataSourceMongoose.js');

var AxolotlState = mongoose.model('AxolotlState');
var DataSource = ds.DataSource;

var headers = {
    'user-agent': 'test-client',
    'Content-Type': 'application/json; charset=utf-8'/*,
    'Content-Length': */
};

var options = {
    hostname: '127.0.0.1',
    port: 8888,
    path: '/',
    method: 'GET',
    headers: headers,
    rejectUnauthorized: false,
    requestCert: true,
};

function exchangeKeys(callback)
{
    var dsm = new DataSource(),
        state = dsm.axolotl_state.create();
    var aliceParams = {
        'id' : sodium.crypto_box_keypair (),
        'eph0' : sodium.crypto_box_keypair ()
    }
    var aliceKeyExchangeMsg =               //build message with public id and ephemeral key
    {
        'id' : aliceParams.id.publicKey.toString('base64'),
        'eph0' : aliceParams.eph0.publicKey.toString('base64')
    }
    var keyExchangeOut =
    {
        "type" : "KEYXC",
        "keys" : aliceKeyExchangeMsg
    };
    function updateStateAlice(keys, keyExchangeIn) {
        state.root_key              = keys.rk;
        state.chain_key_recv        = keys.ck; // Alice is Client. So we set CKr first.
        state.header_key_recv       = keys.hk;
        state.next_header_key_send  = keys.nhk0;
        state.next_header_key_recv  = keys.nhk1;
        state.dh_identity_key_send  = aliceParams.id.secretKey;
        state.dh_identity_key_send_pub  = aliceParams.id.publicKey;
        state.dh_identity_key_recv  = new Buffer(keyExchangeIn.id, 'base64');
        state.dh_ratchet_key_recv   = new Buffer(keyExchangeIn.eph1, 'base64');
        state.counter_send = 0;
        state.counter_recv = 0;
        state.previous_counter_send = 0;
        state.ratchet_flag = true;
        // Alice's state is not a data source, so we need to save this by hand.
        myutil.debug('Header key:', state.next_header_key_send);
        dsm.axolotl_state.save(function (err, state) {
            expect(err).to.not.exist;
            callback(keyExchangeIn.id, aliceParams);
        });
    }
    var jkeyExchangeOut = JSON.stringify(keyExchangeOut);
    options.headers['Content-Length'] = jkeyExchangeOut.length;
    var jkeyExchangeIn = '';
    var keyExchangeIn;

    var req = https.request(options, function(res)    //send KeyExchange message
    {
        res.on('data', function(d)   //get response from Server
        {
            jkeyExchangeIn += d;
        });
        res.on('end', function ()
        {
            keyExchangeIn = JSON.parse(jkeyExchangeIn);
            axolotl.keyAgreementAlice(aliceParams, keyExchangeIn, function(err, keys)
            {
                if (err)
                {
                    throw new Error('Apparently Alice could not finish the key agreement.');
                }
                else
                {
                    updateStateAlice(keys, keyExchangeIn);
                }
            });
        });
    });

    req.on('error', function(e)
    {
        console.error(e);
    });

    myutil.debug('Sending:', jkeyExchangeOut);
    req.write(jkeyExchangeOut);
    req.end();
}

var message = {
    "type" : "PROXY",
    "payload": "Hallo Server!"
};

describe('Simple test client', function()
{
    describe('Key exchange and message', function()
    {
        var aliceParams;
        var bobID;
        it('should encrypt and decrypt messages from the backend', function(done)
        {
            exchangeKeys(function(remoteID, localParams)
            {
                aliceParams = localParams;
                bobID = remoteID;
                var jMessage = JSON.stringify(message);
                myutil.debug('Encrypting message:', jMessage, 'for', bobID );
                axolotl.sendMessage(bobID, jMessage, function(err, ciphertext, state)
                {
                    expect(err, 'Error from sending message').to.not.exist;
                    myutil.debug('Encrypted message:', ciphertext);
                    var result = '';
                    ciphertext.type = 'CRYPT';
                    ciphertext.from = aliceParams.id.publicKey.toString('base64');
                    var jPayload = JSON.stringify(ciphertext);
                    options.headers['Content-Length'] = jPayload.length;
                    var req = https.request(options, function(res)
                    {
                        res.on('data', function(d)
                        {
                            result += d;
                        });
                        res.on('end', function ()
                        {
                            result = JSON.parse(result);
                            myutil.debug('Received answer:', result);
                            axolotl.recvMessage(bobID, result, function(err, plaintext)
                            {
                                expect(err).to.not.exist;
                                myutil.debug('Decrypted message:', plaintext);
                                done();
                            });
                        });
                    });
                    req.on('error', function(e)
                    {
                        console.error(e);
                    });
                    myutil.debug('Sending message:', jPayload);
                    req.write(jPayload);
                    req.end();
                });
            });
        });
        after (function (done){
            AxolotlState.remove({
                    dh_identity_key_recv : new Buffer(aliceParams.id.publicKey, 'base64')
                },
                function()
                {
                });
            AxolotlState.remove({
                    dh_identity_key_recv : new Buffer(bobID, 'base64')
                }, function()
                {
                });
            done();
        });
    });
});

<|endoftext|>