<commit_before>function DrawDots(nbX, spacing, randomMin, randomMax)
{
	var canvas = document.getElementById("dotscanvas");
	canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    if (canvas.getContext) {
        var ctx = canvas.getContext("2d");

		ctx.clearRect(0,0,canvas.width, canvas.height);

		ctx.fillStyle = "rgba(30, 144, 255, 0.25)";
		ctx.beginPath();
		ctx.arc(10, 10, 10, 0, Math.PI * 2, true);
		ctx.fill();
    }

	var loopTimer = setTimeout('draw('+nbX+','+spacing+','+randomMin+','+randomMax+')', 20);
}<commit_msg>removed timeout<commit_after>function DrawDots(nbX, spacing, randomMin, randomMax)
{
	var canvas = document.getElementById("dotscanvas");
	canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    if (canvas.getContext) {
        var ctx = canvas.getContext("2d");

		ctx.clearRect(0,0,canvas.width, canvas.height);

		ctx.fillStyle = "rgba(30, 144, 255, 0.25)";
		ctx.beginPath();
		ctx.arc(10, 10, 10, 0, Math.PI * 2, true);
		ctx.fill();
    }

	//var loopTimer = setTimeout('draw('+nbX+','+spacing+','+randomMin+','+randomMax+')', 20);
}<|endoftext|>


<commit_before>/*!
 * EJS Embedded JavaScript templates
 * Copyright 2012 TJ Holowaychuk <tj@vision-media.ca>
 * Copyright 2112 Matthew Eernisse <mde@fleegix.org>
 * Copyright 2112 Tiancheng "Timothy" Gu <timothygu99@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

/**
 * Module dependencies.
 */

var utils = require('./utils')
  , path = require('path')
  , dirname = path.dirname
  , extname = path.extname
  , join = path.join
  , fs = require('fs')
  , read = fs.readFileSync
  , optInDataWarned = false
  , scopeOptionWarned = false
  , _DEFAULT_DELIMITER = '%'
  , _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context'
            , 'debug', 'compileDebug', 'client'
            ];

/**
 * Intermediate js cache.
 *
 * @type Object
 */

var cache = {};

/**
 * Clear intermediate js cache.
 *
 * @api public
 */

exports.clearCache = function(){
  cache = {};
};

/**
 * Re-throw the given `err` in context to the
 * `str` of ejs, `filename`, and `lineno`.
 *
 * @param {Error} err
 * @param {String} str
 * @param {String} filename
 * @param {String} lineno
 * @api private
 */

function rethrow(err, str, filename, lineno){
  var lines = str.split('\n')
    , start = Math.max(lineno - 3, 0)
    , end = Math.min(lines.length, lineno + 3);

  // Error context
  var context = lines.slice(start, end).map(function(line, i){
    var curr = i + start + 1;
    return (curr == lineno ? ' >> ' : '    ')
      + curr
      + '| '
      + line;
  }).join('\n');

  // Alter exception message
  err.path = filename;
  err.message = (filename || 'ejs') + ':'
    + lineno + '\n'
    + context + '\n\n'
    + err.message;

  throw err;
}

/**
 * Parse the given `str` of ejs, returning the function body.
 *
 * @param {String} str
 * @return {String}
 * @api public
 */

function parse(str, options){
  var d = options.delimiter || exports.delimiter || _DEFAULT_DELIMITER
    , open = '<' + d
    , close = d + '>'
    , filename = options.filename
    , compileDebug = options.compileDebug !== false
    , buf = '';

  buf += 'var buf = [];';
  if (false !== options._with) {
    buf += 'with (locals || {}) { ';
  }
  buf += 'buf.push(\'';

  var lineno = 1;

  var consumeEOL = false;
  for (var i = 0, len = str.length; i < len; ++i) {
    var stri = str[i];
    if (str.slice(i, open.length + i) == open) {
      i += open.length;

      var prefix
        , postfix
        , line = (compileDebug ? '__line=' : '') + lineno
        , noEndNeeded = false;
      switch (str[i]) {
        case '=':
          prefix = "', escape((" + line + ', ';
          postfix = ")), '";
          ++i;
          break;
        case '-':
          prefix = "', (" + line + ', ';
          postfix = "), '";
          ++i;
          break;
        default:
          if (str.substr(i, d.length) == d) {
            buf += "', '" + open + "', '";
            i += d.length - 1;
            noEndNeeded = true;
            continue;
          }
          else {
            prefix = "');" + line + ';';
            postfix = "; buf.push('";
          }
      }

      var end = str.indexOf(close, i);

      if (end < 0){
        throw new Error('Could not find matching close tag for "' + open + str[i - 1] + '".');
      }

      var js = str.substring(i, end)
        , start = i
        , include = null
        , n = 0;

      if ('-' == js[js.length-1]) {
        js = js.substring(0, js.length - 2);
        consumeEOL = true;
      }

      if (js.trim().indexOf('include') === 0) {
        var name = js.trim().slice(7).trim();
        if (!filename) {
          throw new Error('`include` requires the \'filename\' option.');
        }
        var path = resolveInclude(name, filename);
        include = read(path, 'utf8');
        include = parse(include, { filename: path, _with: false, delimiter: d, compileDebug: compileDebug });
        buf += "' + (function(){" + include + "})() + '";
        js = '';
      }

      while (!(n = js.indexOf('\n', n))) {
        n++;
        lineno++;
      }

      if (js[0] == '#') {
        js = '';
      }

      if (js) {
        if (js.lastIndexOf('//') > js.lastIndexOf('\n')) {
          js += '\n';
        }
        buf += prefix;
        buf += js;
        buf += postfix;
      }
      i += end - start + close.length - 1;
    }
    else if (stri == '\\') {
      buf += '\\\\';
    }
    else if (stri == "'") {
      buf += "\\'";
    }
    else if (stri == '\r') {
      // ignore
    }
    else if (stri == '\n') {
      if (consumeEOL) {
        consumeEOL = false;
      }
      else {
        buf += '\\n';
        lineno++;
      }
    }
    else {
      buf += stri;
    }
  }

  if (false !== options._with) {
    buf += "');}return buf.join('');";
  }
  else {
    buf += "');return buf.join('');";
  }
  return buf;
}

/**
 * Compile the given `str` of ejs into a `Function`.
 *
 * @param {String} str
 * @param {Object} opts
 * @return {Function}
 * @api public
 */

var compile = exports.compile = function (str, opts) {
  opts = opts || {};
  var escape = opts.escape || utils.escapeXML
    , input = JSON.stringify(str)
    , compileDebug = opts.compileDebug !== false
    , client = opts.client
    , filename = opts.filename
        ? JSON.stringify(opts.filename)
        : 'undefined'
    , fn;

  if (compileDebug) {
    // Adds the fancy stack trace meta info
    str = 'var __line = 1'
        +   ', __lines = ' + input
        +   ', __filename = ' + filename + ';'
        + 'try {'
        +   parse(str, opts)
        + '}'
        + 'catch (err) {'
        + '  rethrow(err, __lines, __filename, __line);'
        + '}';
  }
  else {
    str = parse(str, opts);
  }

  if (opts.debug) {
    console.log(str);
  }

  if (opts.client) {
    str = 'escape = escape || ' + escape.toString() + ';\n' + str;
    str = 'rethrow = rethrow || ' + rethrow.toString() + ';\n' + str;
  }

  try {
    fn = new Function('locals, escape, include, rethrow', str);
  }
  catch(e) {
    // istanbul ignore else
    if (e.message) {
      if (opts.filename) {
        e.message += ' in ' + opts.filename;
      }
      e.message += ' while compiling ejs';
    }
    throw e;
  }

  if (client) {
    return fn;
  }

  return function(locals){
    return fn(locals, escape, null /* TODO */, rethrow);
  };
};

function cpOptsInData(locals, opts) {
  _OPTS.forEach(function (p) {
    if (typeof locals[p] != 'undefined') {
      if (!(optInDataWarned || locals.__expressRender__)) {
        console.warn('options found in locals object. The option(s) is '
                   + 'copied to the option object. This behavior is '
                   + 'deprecated and will be removed in EJS 3');
        optInDataWarned = true;
      }
      opts[p] = locals[p];
    }
  });
}

/**
 * Render the given `str` of ejs.
 *
 * Options:
 *
 *   - `locals`          Local variables object
 *   - `cache`           Compiled functions are cached, requires `filename`
 *   - `filename`        Used by `cache` to key caches
 *   - `scope`           Function execution context
 *   - `debug`           Output generated function body
 *
 * @param {String} str
 * @param {Object} opts
 * @return {String}
 * @api public
 */

exports.render = function(str, locals, opts){
  var fn;
  locals = locals || {};
  opts = opts || {};

  cpOptsInData(locals, opts);
  if (opts.cache) {
    if (opts.filename) {
      fn = cache[opts.filename] || (cache[opts.filename] = compile(str, opts));
    }
    else {
      throw new Error('"cache" option requires "filename".');
    }
  }
  else {
    fn = compile(str, opts);
  }
  if (opts.scope) {
    if (!scopeOptionWarned){
      console.warn('`scope` option is deprecated and will be removed in EJS 3');
      scopeOptionWarned = true;
    }
    if (!opts.context) {
      opts.context = opts.scope;
    }
    delete opts.scope;
  }

  if (opts.context) {
    return fn.call(opts.context, locals);
  }
  return fn(locals);
};

/**
 * Render an EJS file at the given `path` and callback `fn(err, str)`.
 *
 * @param {String} path
 * @param {Object|Function} options or callback
 * @param {Function} fn
 * @api public
 */

exports.renderFile = function(path, locals, options, fn){
  var args = Array.prototype.slice.call(arguments);
  args.shift(); // path
  fn = args.pop();
  locals = args.shift() || {};
  options = args.pop() || {};

  var key = path + ':string';

  options.filename = path;

  var str;
  try {
    str = options.cache
      ? cache[key] || (cache[key] = read(path, 'utf8'))
      : read(path, 'utf8');
    str = exports.render(str, locals, options);
  }
  catch (err) {
    fn(err);
    return;
  }
  fn(null, str);
};

/**
 * Resolve include `name` relative to `filename`.
 *
 * @param {String} name
 * @param {String} filename
 * @return {String}
 * @api private
 */

function resolveInclude(name, filename) {
  var path = join(dirname(filename), name);
  var ext = extname(name);
  if (!ext) {
    path += '.ejs';
  }
  return path;
}

// express support

exports.__express = function () {
  // (path, opts, cb)
  // Indicate this is the backward-compatible Express API shim
  if (arguments.length == 3) {
    arguments[1].__expressRender__ = true;
  }
  exports.renderFile.apply(null, arguments);
};

/**
 * Expose to require().
 */

// istanbul ignore else
if (require.extensions) {
  require.extensions['.ejs'] = function (module, filename) {
    filename = filename || /* istanbul ignore next */ module.filename;
    var options = { filename: filename, client: true }
      , template = fs.readFileSync(filename).toString()
      , fn = compile(template, options);
    module._compile('module.exports = ' + fn.toString() + ';', filename);
  };
}
<commit_msg>function labels, style<commit_after>/*!
 * EJS Embedded JavaScript templates
 * Copyright 2012 TJ Holowaychuk <tj@vision-media.ca>
 * Copyright 2112 Matthew Eernisse <mde@fleegix.org>
 * Copyright 2112 Tiancheng "Timothy" Gu <timothygu99@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

/**
 * Module dependencies.
 */

var utils = require('./utils')
  , path = require('path')
  , dirname = path.dirname
  , extname = path.extname
  , join = path.join
  , fs = require('fs')
  , read = fs.readFileSync
  , optInDataWarned = false
  , scopeOptionWarned = false
  , _DEFAULT_DELIMITER = '%'
  , _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context'
            , 'debug', 'compileDebug', 'client'
            ];

/**
 * Intermediate js cache.
 *
 * @type Object
 */

var cache = {};

/**
 * Clear intermediate js cache.
 *
 * @api public
 */

exports.clearCache = function clearCache() {
  cache = {};
};

/**
 * Re-throw the given `err` in context to the
 * `str` of ejs, `filename`, and `lineno`.
 *
 * @param {Error} err
 * @param {String} str
 * @param {String} filename
 * @param {String} lineno
 * @api private
 */

function rethrow(err, str, filename, lineno) {
  var lines = str.split('\n')
    , start = Math.max(lineno - 3, 0)
    , end = Math.min(lines.length, lineno + 3);

  // Error context
  var context = lines.slice(start, end).map(function (line, i) {
    var curr = i + start + 1;
    return (curr == lineno ? ' >> ' : '    ')
      + curr
      + '| '
      + line;
  }).join('\n');

  // Alter exception message
  err.path = filename;
  err.message = (filename || 'ejs') + ':'
    + lineno + '\n'
    + context + '\n\n'
    + err.message;

  throw err;
}

/**
 * Parse the given `str` of ejs, returning the function body.
 *
 * @param {String} str
 * @return {String}
 * @api public
 */

function parse(str, options) {
  var d = options.delimiter || exports.delimiter || _DEFAULT_DELIMITER
    , open = '<' + d
    , close = d + '>'
    , filename = options.filename
    , compileDebug = options.compileDebug !== false
    , buf = '';

  buf += 'var buf = [];';
  if (false !== options._with) {
    buf += 'with (locals || {}) { ';
  }
  buf += 'buf.push(\'';

  var lineno = 1;

  var consumeEOL = false;
  for (var i = 0, len = str.length; i < len; ++i) {
    var stri = str[i];
    if (str.slice(i, open.length + i) == open) {
      i += open.length;

      var prefix
        , postfix
        , line = (compileDebug ? '__line=' : '') + lineno
        , noEndNeeded = false;
      switch (str[i]) {
        case '=':
          prefix = "', escape((" + line + ', ';
          postfix = ")), '";
          ++i;
          break;
        case '-':
          prefix = "', (" + line + ', ';
          postfix = "), '";
          ++i;
          break;
        default:
          if (str.substr(i, d.length) == d) {
            buf += "', '" + open + "', '";
            i += d.length - 1;
            noEndNeeded = true;
            continue;
          }
          else {
            prefix = "');" + line + ';';
            postfix = "; buf.push('";
          }
      }

      var end = str.indexOf(close, i);

      if (end < 0) {
        throw new Error('Could not find matching close tag for "' + open + str[i - 1] + '".');
      }

      var js = str.substring(i, end)
        , start = i
        , include = null
        , n = 0;

      if ('-' == js[js.length-1]) {
        js = js.substring(0, js.length - 2);
        consumeEOL = true;
      }

      if (js.trim().indexOf('include') === 0) {
        var name = js.trim().slice(7).trim();
        if (!filename) {
          throw new Error('`include` requires the \'filename\' option.');
        }
        var path = resolveInclude(name, filename);
        include = read(path, 'utf8');
        include = parse(include, { filename: path, _with: false, delimiter: d, compileDebug: compileDebug });
        buf += "' + (function(){" + include + "})() + '";
        js = '';
      }

      while (!(n = js.indexOf('\n', n))) {
        n++;
        lineno++;
      }

      if (js[0] == '#') {
        js = '';
      }

      if (js) {
        if (js.lastIndexOf('//') > js.lastIndexOf('\n')) {
          js += '\n';
        }
        buf += prefix;
        buf += js;
        buf += postfix;
      }
      i += end - start + close.length - 1;
    }
    else if (stri == '\\') {
      buf += '\\\\';
    }
    else if (stri == "'") {
      buf += "\\'";
    }
    else if (stri == '\r') {
      // ignore
    }
    else if (stri == '\n') {
      if (consumeEOL) {
        consumeEOL = false;
      }
      else {
        buf += '\\n';
        lineno++;
      }
    }
    else {
      buf += stri;
    }
  }

  if (false !== options._with) {
    buf += "');}return buf.join('');";
  }
  else {
    buf += "');return buf.join('');";
  }
  return buf;
}

/**
 * Compile the given `str` of ejs into a `Function`.
 *
 * @param {String} str
 * @param {Object} opts
 * @return {Function}
 * @api public
 */

var compile = exports.compile = function (str, opts) {
  opts = opts || {};
  var escape = opts.escape || utils.escapeXML
    , input = JSON.stringify(str)
    , compileDebug = opts.compileDebug !== false
    , client = opts.client
    , filename = opts.filename
        ? JSON.stringify(opts.filename)
        : 'undefined'
    , fn;

  if (compileDebug) {
    // Adds the fancy stack trace meta info
    str = 'var __line = 1'
        +   ', __lines = ' + input
        +   ', __filename = ' + filename + ';'
        + 'try {'
        +   parse(str, opts)
        + '}'
        + 'catch (err) {'
        + '  rethrow(err, __lines, __filename, __line);'
        + '}';
  }
  else {
    str = parse(str, opts);
  }

  if (opts.debug) {
    console.log(str);
  }

  if (opts.client) {
    str = 'escape = escape || ' + escape.toString() + ';\n' + str;
    str = 'rethrow = rethrow || ' + rethrow.toString() + ';\n' + str;
  }

  try {
    fn = new Function('locals, escape, include, rethrow', str);
  }
  catch(e) {
    // istanbul ignore else
    if (e.message) {
      if (opts.filename) {
        e.message += ' in ' + opts.filename;
      }
      e.message += ' while compiling ejs';
    }
    throw e;
  }

  if (client) {
    return fn;
  }

  return function (locals) {
    return fn(locals, escape, null /* TODO */, rethrow);
  };
};

function cpOptsInData(locals, opts) {
  _OPTS.forEach(function (p) {
    if (typeof locals[p] != 'undefined') {
      if (!(optInDataWarned || locals.__expressRender__)) {
        console.warn('options found in locals object. The option(s) is '
                   + 'copied to the option object. This behavior is '
                   + 'deprecated and will be removed in EJS 3');
        optInDataWarned = true;
      }
      opts[p] = locals[p];
    }
  });
}

/**
 * Render the given `str` of ejs.
 *
 * Options:
 *
 *   - `locals`          Local variables object
 *   - `cache`           Compiled functions are cached, requires `filename`
 *   - `filename`        Used by `cache` to key caches
 *   - `scope`           Function execution context
 *   - `debug`           Output generated function body
 *
 * @param {String} str
 * @param {Object} opts
 * @return {String}
 * @api public
 */

exports.render = function render(str, locals, opts) {
  var fn;
  locals = locals || {};
  opts = opts || {};

  cpOptsInData(locals, opts);
  if (opts.cache) {
    if (opts.filename) {
      fn = cache[opts.filename] || (cache[opts.filename] = compile(str, opts));
    }
    else {
      throw new Error('"cache" option requires "filename".');
    }
  }
  else {
    fn = compile(str, opts);
  }
  if (opts.scope) {
    if (!scopeOptionWarned) {
      console.warn('`scope` option is deprecated and will be removed in EJS 3');
      scopeOptionWarned = true;
    }
    if (!opts.context) {
      opts.context = opts.scope;
    }
    delete opts.scope;
  }

  if (opts.context) {
    return fn.call(opts.context, locals);
  }
  return fn(locals);
};

/**
 * Render an EJS file at the given `path` and callback `fn(err, str)`.
 *
 * @param {String} path
 * @param {Object|Function} options or callback
 * @param {Function} fn
 * @api public
 */

exports.renderFile = function renderFile(path, locals, options, fn) {
  var args = Array.prototype.slice.call(arguments);
  args.shift(); // path
  fn = args.pop();
  locals = args.shift() || {};
  options = args.pop() || {};

  var key = path + ':string';

  options.filename = path;

  var str;
  try {
    str = options.cache
      ? cache[key] || (cache[key] = read(path, 'utf8'))
      : read(path, 'utf8');
    str = exports.render(str, locals, options);
  }
  catch (err) {
    fn(err);
    return;
  }
  fn(null, str);
};

/**
 * Resolve include `name` relative to `filename`.
 *
 * @param {String} name
 * @param {String} filename
 * @return {String}
 * @api private
 */

function resolveInclude(name, filename) {
  var path = join(dirname(filename), name);
  var ext = extname(name);
  if (!ext) {
    path += '.ejs';
  }
  return path;
}

// express support

exports.__express = function () {
  // (path, opts, cb)
  // Indicate this is the backward-compatible Express API shim
  if (arguments.length == 3) {
    arguments[1].__expressRender__ = true;
  }
  exports.renderFile.apply(null, arguments);
};

/**
 * Expose to require().
 */

// istanbul ignore else
if (require.extensions) {
  require.extensions['.ejs'] = function (module, filename) {
    filename = filename || /* istanbul ignore next */ module.filename;
    var options = { filename: filename, client: true }
      , template = fs.readFileSync(filename).toString()
      , fn = compile(template, options);
    module._compile('module.exports = ' + fn.toString() + ';', filename);
  };
}
<|endoftext|>


<commit_before>$('omit').change(() => {
    $('#omit-label').html($('#omit').val())
})
$('#omit-label').html($('#omit').val())

//judge draw
var isdraw = false
//mouse point
var drawpoints
//svg path
var drawpath
//svg path style
var pathstyle = {
    strokeWidth: "3px",
    stroke: "#000000",
    fill: "none"
}

//before and after stack
var history_array = []

//path style color
$('#red').click(() => {
    pathstyle.stroke = "#ff0000"
})
$('#black').click(() => {
    pathstyle.stroke = "#000000"
})

//path before
$('#before').click(() => {
    //path delete and save
    var save_path = $('path:last').detach()
    //array include savepath and not undefined
    if(history_array.indexOf(save_path.get()[0]) != 0){
        if(save_path.get()[0] !== undefined){
            //add path in stack array
            history_array.push(save_path.get()[0])
            displaypathdata()
        }
    }
})
//path after
$('#after').click(() => {
    //path restoration
    $('#canvas').append(history_array[history_array.length - 1])
    //delete path in stack array
    history_array.pop()
    displaypathdata()
})

//mouse click
$('#canvas').mousedown((e) => {
    //judge true
    isdraw = true
    //history array delete
    history_array.length = 0
    //point array definition
    drawpoints = []
})
//mouse move
$('#canvas').mousemove((e) => {
    //draw true
    if (isdraw) {
        //add mouse point
        drawpoints.push({
            x: e.clientX,
            y: e.clientY
        })
        //drawingPath check existence
        if (drawpath) {
            drawpath.remove()
        }
        //create path
        drawpath = createPath(drawpoints, parseFloat($('#omit').val()), true)
        //path style setting
        Object.assign(drawpath.style, pathstyle)
        //add svg path to canvas
        $('#canvas').append(drawpath)
    }
})
//mouse up
$('#canvas').mouseup((e) => {
    //judge false
    isdraw = false
    //drawingPath null or undefined
    if (!drawpath) {
        return
    }
    drawpath = null
    displaypathdata()
})

//create path
function createPath(points, tolerance, highestQuality) {
    var path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
    var attribute = SVGCatmullRomSpline.toPath(points.map(point => [point.x, point.y]), tolerance, highestQuality)
    path.setAttributeNS(null, 'd', attribute)
    return path
}

//svg-data size function
function size(str){
    return(encodeURIComponent(str).replace(/%../g,"x").length)
}

//all svg path data
function displaypathdata() {
    $('#datasize').empty()
    var svg_data = size($('#canvas').html())
    $('#datasize').append(svg_data + "Byte")
}
<commit_msg>fix omit<commit_after>$('#omit').change(() => {
    $('#omit-label').html($('#omit').val())
})
$('#omit-label').html($('#omit').val())

//judge draw
var isdraw = false
//mouse point
var drawpoints
//svg path
var drawpath
//svg path style
var pathstyle = {
    strokeWidth: "3px",
    stroke: "#000000",
    fill: "none"
}

//before and after stack
var history_array = []

//path style color
$('#red').click(() => {
    pathstyle.stroke = "#ff0000"
})
$('#black').click(() => {
    pathstyle.stroke = "#000000"
})

//path before
$('#before').click(() => {
    //path delete and save
    var save_path = $('path:last').detach()
    //array include savepath and not undefined
    if(history_array.indexOf(save_path.get()[0]) != 0){
        if(save_path.get()[0] !== undefined){
            //add path in stack array
            history_array.push(save_path.get()[0])
            displaypathdata()
        }
    }
})
//path after
$('#after').click(() => {
    //path restoration
    $('#canvas').append(history_array[history_array.length - 1])
    //delete path in stack array
    history_array.pop()
    displaypathdata()
})

//mouse click
$('#canvas').mousedown((e) => {
    //judge true
    isdraw = true
    //history array delete
    history_array.length = 0
    //point array definition
    drawpoints = []
})
//mouse move
$('#canvas').mousemove((e) => {
    //draw true
    if (isdraw) {
        //add mouse point
        drawpoints.push({
            x: e.clientX,
            y: e.clientY
        })
        //drawingPath check existence
        if (drawpath) {
            drawpath.remove()
        }
        //create path
        drawpath = createPath(drawpoints, parseFloat($('#omit').val()), true)
        //path style setting
        Object.assign(drawpath.style, pathstyle)
        //add svg path to canvas
        $('#canvas').append(drawpath)
    }
})
//mouse up
$('#canvas').mouseup((e) => {
    //judge false
    isdraw = false
    //drawingPath null or undefined
    if (!drawpath) {
        return
    }
    drawpath = null
    displaypathdata()
})

//create path
function createPath(points, tolerance, highestQuality) {
    var path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
    var attribute = SVGCatmullRomSpline.toPath(points.map(point => [point.x, point.y]), tolerance, highestQuality)
    path.setAttributeNS(null, 'd', attribute)
    return path
}

//svg-data size function
function size(str){
    return(encodeURIComponent(str).replace(/%../g,"x").length)
}

//all svg path data
function displaypathdata() {
    $('#datasize').empty()
    var svg_data = size($('#canvas').html())
    $('#datasize').append(svg_data + "Byte")
}
<|endoftext|>


<commit_before>// Dependencies
import config from './config';

import gulp from 'gulp';
import autoprefixer from 'gulp-autoprefixer';
import notify from 'gulp-notify';
import sass from 'gulp-sass';
import sourcemaps from 'gulp-sourcemaps';
import browserSync from 'browser-sync';
import filter from 'gulp-filter';

export function dev() {
    return gulp.src(config.paths.source.styles + '/**/*.scss')
        .pipe(sourcemaps.init())
            .pipe(sass({
                includePaths: [ // Enable import from libraries installed with npm
                    './node_modules',
                ],
            }))
            .on('error', notify.onError({
                title: 'styles - failed',
                message: 'View console for more details.',
                sound: true,
            }))
            .on('error', err => console.error('ERROR TASK: styles MESSAGE: ' + err.message + ' FILENAME: ' + err.fileName + ' LINENUMBER: ' + err.lineNumber))
            .pipe(autoprefixer())
        .pipe(sourcemaps.write('./'))
        .pipe(gulp.dest(config.paths.build.styles))
        .pipe(filter('**/*.css')) // Filter the sourcemaps so that BrowserSync will properly inject the CSS without reloading the page
        .pipe(browserSync.stream());
}

export function prod() {
    let moreCSS = require('gulp-more-css');

    return gulp.src(config.paths.source.styles + '/**/*.scss')
        .pipe(sass({
            includePaths: [ // Enable import from libraries installed with npm
                './node_modules',
            ],
        }))
        .on('error', notify.onError({
            title: 'prod-styles - failed',
            message: 'View console for more details.',
            sound: true,
        }))
        .on('error', err => console.error('ERROR TASK: prod-styles MESSAGE: ' + err.message + ' FILENAME: ' + err.fileName + ' LINENUMBER: ' + err.lineNumber))
        .pipe(autoprefixer())
        .pipe(moreCSS({
            radical: false,
        }))
        .pipe(gulp.dest(config.paths.build.styles));
}

export function lint() {
    let scssLint = require('gulp-scss-lint');

    return gulp.src(config.paths.source.styles + '/**/*.scss')
        .pipe(scssLint());
}

export function criticalCSS(callback) {
    let critical = require('critical');

    critical.generate({
        inline: true,
        base: config.paths.build.base,
        src: '/index.html',
        dest: config.paths.build.base + '/index.html',
        minify: true,
        width: 1280,
        height: 800,
    }, () => {
        callback();
    });
}
<commit_msg>Dcoumentation<commit_after>// Dependencies
import config from './config';

import gulp from 'gulp';
import autoprefixer from 'gulp-autoprefixer';
import notify from 'gulp-notify';
import sass from 'gulp-sass';
import sourcemaps from 'gulp-sourcemaps';
import browserSync from 'browser-sync';
import filter from 'gulp-filter';

export function dev() {
    return gulp.src(config.paths.source.styles + '/**/*.scss')
        .pipe(sourcemaps.init())
            .pipe(sass({
                includePaths: [ // Enable import from libraries installed with npm
                    './node_modules',
                ],
            }))
            .on('error', notify.onError({
                title: 'styles - failed',
                message: 'View console for more details.',
                sound: true,
            }))
            .on('error', err => console.error('ERROR TASK: styles MESSAGE: ' + err.message + ' FILENAME: ' + err.fileName + ' LINENUMBER: ' + err.lineNumber))
            .pipe(autoprefixer())
        .pipe(sourcemaps.write('./'))
        .pipe(gulp.dest(config.paths.build.styles))
        .pipe(filter('**/*.css')) // Filter the sourcemaps so that BrowserSync will properly inject the CSS without reloading the page
        .pipe(browserSync.stream());
}

export function prod() {
    // Modules loaded here, because they are only needed for this task and it will only run once (performance improvement)
    let moreCSS = require('gulp-more-css');

    return gulp.src(config.paths.source.styles + '/**/*.scss')
        .pipe(sass({
            includePaths: [ // Enable import from libraries installed with npm
                './node_modules',
            ],
        }))
        .on('error', notify.onError({
            title: 'prod-styles - failed',
            message: 'View console for more details.',
            sound: true,
        }))
        .on('error', err => console.error('ERROR TASK: prod-styles MESSAGE: ' + err.message + ' FILENAME: ' + err.fileName + ' LINENUMBER: ' + err.lineNumber))
        .pipe(autoprefixer())
        .pipe(moreCSS({
            radical: false,
        }))
        .pipe(gulp.dest(config.paths.build.styles));
}

export function lint() {
    // Modules loaded here, because they are only needed for this task and it will only run once (performance improvement)
    let scssLint = require('gulp-scss-lint');

    return gulp.src(config.paths.source.styles + '/**/*.scss')
        .pipe(scssLint());
}

export function criticalCSS(callback) {
    // Modules loaded here, because they are only needed for this task and it will only run once (performance improvement)
    let critical = require('critical');

    critical.generate({
        inline: true, // Will be inserted into the <head>
        base: config.paths.build.base,
        src: '/index.html',
        dest: config.paths.build.base + '/index.html',
        minify: true,
        width: 1280, // Viewbox
        height: 800, // Viewbox
    }, () => {
        callback();
    });
}
<|endoftext|>


<commit_before>'use strict';

/**
 *  lib
 **/

/*global nodeca*/

// 3rd-party
var Puncher = require('puncher');

////////////////////////////////////////////////////////////////////////////////

var tzOffset = (new Date).getTimezoneOffset();

////////////////////////////////////////////////////////////////////////////////

/**
 *  lib.env(options) -> Object
 *  - options (Object): Environment options.
 *
 *  Create new request environment object.
 *
 *
 *  ##### Options
 *
 *  - **http**: HTTP origin object that contains `req` and `res`.
 *  - **rpc**: API3 (Ajax) origin that contains `req` and `res`.
 *  - **skip**: Array of middlewares to skip
 *  - **session**: Session object
 *  - **method**: Name of the server method, e.g. `'forums.posts.show'`
 *  - **layout**: Layout name as String
 **/
module.exports = function env(options) {
  var req = (options.http || options.rpc).req;
  var ctx = {
    extras:  {
      puncher: new Puncher()
    },
    helpers: {
      asset_path: function asset_path(path) {
        var asset = nodeca.runtime.assets.manifest.assets[path];
        return !asset ? "#" : nodeca.runtime.router.linkTo('assets', { path: asset });
      }
    },
    origin: {
      http: options.http,
      rpc: options.rpc
    },
    skip: (options.skip || []).slice(),
    session: options.session || null,
    request: {
      // FIXME: should be deprecated in flavour of env.origin
      origin:     !!options.rpc ? 'RPC' : 'HTTP',
      method:     options.method,
      ip:         req.connection.remoteAddress,
      user_agent: req.headers['user-agent'],
      namespace:  String(options.method).split('.').shift()
    },
    data: {},
    runtime: {
      // FIXME: must be set from cookies
      theme: 'desktop'
    },
    settings: {
      params: {},
      fetch: function fetchSettings(keys, callback) {
        nodeca.settings.get(keys, this.params, {}, callback);
      }
    },
    response: {
      data: {
        head: {
          title: null, // should be filled with default value
          apiPath: options.method,
          // List of assets for yepnope,
          // Each element is an object with properties:
          //
          //    type:   css|js
          //    link:   asset_url
          //
          // example: assets.push({type: 'js', link: '//example.com/foo.js'});
          assets: []
        },
        menus: {},
        widgets: {}
      },
      headers: {},
      // Layouts are supporting "nesting" via `dots:
      //
      //    default.blogs
      //
      // In the example above, `default.blogs` will be rendered first and the
      // result will be provided for rendering to `default`.
      layout: options.layout || 'default',
      // Default view template name == server method name
      // One might override this, to render different view
      //
      view: options.method
    }
  };

  //
  // env-dependent helper needs to be bounded to env
  //

  ctx.helpers.t = function (phrase, params) {
    var locale = this.runtime.locale || nodeca.config.locales['default'];
    return nodeca.runtime.i18n.t(locale, phrase, params);
  }.bind(ctx);

  ctx.helpers.t.exists = function (phrase) {
    var locale = this.runtime.locale || nodeca.config.locales['default'];
    return nodeca.runtime.i18n.hasPhrase(locale, phrase);
  }.bind(ctx);

  ctx.helpers.date = function (value, format) {
    var locale = this.runtime.locale || nodeca.config.locales['default'];
    return nodeca.shared.date(value, format, locale, tzOffset);
  }.bind(ctx);

  return ctx;
};
<commit_msg>Fix layout auto-preset<commit_after>'use strict';

/**
 *  lib
 **/

/*global nodeca*/

// 3rd-party
var Puncher = require('puncher');

////////////////////////////////////////////////////////////////////////////////

var tzOffset = (new Date).getTimezoneOffset();

////////////////////////////////////////////////////////////////////////////////

/**
 *  lib.env(options) -> Object
 *  - options (Object): Environment options.
 *
 *  Create new request environment object.
 *
 *
 *  ##### Options
 *
 *  - **http**: HTTP origin object that contains `req` and `res`.
 *  - **rpc**: API3 (Ajax) origin that contains `req` and `res`.
 *  - **skip**: Array of middlewares to skip
 *  - **session**: Session object
 *  - **method**: Name of the server method, e.g. `'forums.posts.show'`
 *  - **layout**: Layout name as String
 **/
module.exports = function env(options) {
  var req     = (options.http || options.rpc).req;
  var method  = String(options.method || '');
  var ns      = method.split('.').shift();

  var ctx = {
    extras:  {
      puncher: new Puncher()
    },
    helpers: {
      asset_path: function asset_path(path) {
        var asset = nodeca.runtime.assets.manifest.assets[path];
        return !asset ? "#" : nodeca.runtime.router.linkTo('assets', { path: asset });
      }
    },
    origin: {
      http: options.http,
      rpc: options.rpc
    },
    skip: (options.skip || []).slice(),
    session: options.session || null,
    request: {
      // FIXME: should be deprecated in flavour of env.origin
      origin:     !!options.rpc ? 'RPC' : 'HTTP',
      method:     method,
      ip:         req.connection.remoteAddress,
      user_agent: req.headers['user-agent'],
      namespace:  ns
    },
    data: {},
    runtime: {
      // FIXME: must be set from cookies
      theme: 'desktop'
    },
    settings: {
      params: {},
      fetch: function fetchSettings(keys, callback) {
        nodeca.settings.get(keys, this.params, {}, callback);
      }
    },
    response: {
      data: {
        head: {
          title: null, // should be filled with default value
          apiPath: method,
          // List of assets for yepnope,
          // Each element is an object with properties:
          //
          //    type:   css|js
          //    link:   asset_url
          //
          // example: assets.push({type: 'js', link: '//example.com/foo.js'});
          assets: []
        },
        menus: {},
        widgets: {}
      },
      headers: {},
      // Layouts are supporting "nesting" via `dots:
      //
      //    default.blogs
      //
      // In the example above, `default.blogs` will be rendered first and the
      // result will be provided for rendering to `default`.
      layout: options.layout || ('admin' === ns) ? method : ('default.' + method),
      // Default view template name == server method name
      // One might override this, to render different view
      //
      view: method
    }
  };

  //
  // env-dependent helper needs to be bounded to env
  //

  ctx.helpers.t = function (phrase, params) {
    var locale = this.runtime.locale || nodeca.config.locales['default'];
    return nodeca.runtime.i18n.t(locale, phrase, params);
  }.bind(ctx);

  ctx.helpers.t.exists = function (phrase) {
    var locale = this.runtime.locale || nodeca.config.locales['default'];
    return nodeca.runtime.i18n.hasPhrase(locale, phrase);
  }.bind(ctx);

  ctx.helpers.date = function (value, format) {
    var locale = this.runtime.locale || nodeca.config.locales['default'];
    return nodeca.shared.date(value, format, locale, tzOffset);
  }.bind(ctx);

  return ctx;
};
<|endoftext|>


<commit_before>$(document).ready(function(){
  $('button').click(function(e){
    e.preventDefault();
    var userName = $('input:text').val();
    useName(userName);
    message(userName);
    localStorage.setItem('currentUser', userName);
    return userName;
  });
});

function useName(currentUser, goodDayOrBadDay) { //params of currentUser and what kind of day it is
  var makeGoodorBad = function(goodOrBad) {  //makeGoodorBad - to display correct kind of day later
    var node = document.createElement('p'); //creating proper elements and appending to DOM
    var textnode = document.createTextNode('Hey ' + currentUser + ', ' + goodOrBad);
    node.appendChild(textnode);
    document.getElementById('output').appendChild(node);
  };
  return makeGoodorBad;
}

  //here cometh the Closure
function message (currentUser){

  var goodDay = useName(currentUser, 'itsgood');
  goodDay('what a great day for biking!');

  var badDay = useName(currentUser, 'itsbad');
  badDay('maybe leave the bike at home today....');

  var soSoDay = useName(currentUser, 'itssoso');
  soSoDay('Conditions are not ideal. Depends on you, dude...');
};
<commit_msg>added eventlistener to submit button that checks validation<commit_after>$(document).ready(function(){
  $('button').click(function(e){
    e.preventDefault();
    var userName = $('input:text').val();
    useName(userName);
    message(userName);
    localStorage.setItem('currentUser', userName);
    return userName;
  });
});

function useName(currentUser, goodDayOrBadDay) { //params of currentUser and what kind of day it is
  var makeGoodorBad = function(goodOrBad) {  //makeGoodorBad - to display correct kind of day later
    var node = document.createElement('p'); //creating proper elements and appending to DOM
    var textnode = document.createTextNode('Hey ' + currentUser + ', ' + goodOrBad);
    node.appendChild(textnode);
    document.getElementById('output').appendChild(node);
  };
  return makeGoodorBad;
}

  //here cometh the Closure
function message (currentUser){

  var goodDay = useName(currentUser, 'itsgood');
  goodDay('what a great day for biking!');

  var badDay = useName(currentUser, 'itsbad');
  badDay('maybe leave the bike at home today....');

  var soSoDay = useName(currentUser, 'itssoso');
  soSoDay('Conditions are not ideal. Depends on you, dude...');
};

//Event Listeners for Submit Button
submitButton.addEventListener('click', validateUserName);
<|endoftext|>


<commit_before>const GPIOWrapper = require('./gpio-wrapper');
const SPIWrapper = require('./spi-wrapper');
const {PINS, EPD_MODES, COMMANDS, EPD1X54} = require('./constants');

class EPD {
  constructor(options = {}) {
    this._options = Object.assign(
      Object.assign(
        {},
        {
          mode: EPD_MODES.FULL,
          display: EPD1X54
        }
      ),
      options
    );

    this._ready = false;
    this._closed = false;
    this._terminated = false;

    this._spi = new SPIWrapper();

    const terminate = async () => {
      if (this._terminated) {
        return;
      }
      this._terminated = true;
      await this.exit();
      process.exit(0);
    };

    process.on('SIGINT', terminate);
    process.on('SIGTERM', terminate);
  }

  /**
   * Asynchronous sleep function
   * @param {int} ms - number of milliseconds to sleep
   * @example
   * // sleep for one second
   * await EPD.sleep(1000);
   */
  static sleep(ms) {
    return new Promise((resolve, reject) => setTimeout(resolve, ms));
  }

  static get MODES() {
    return EPD_MODES;
  }

  get spi() {
    return this._spi;
  }

  get isReady() {
    return this._ready;
  }

  get isClosed() {
    return this._closed;
  }

  get isTerminated() {
    return this._terminated;
  }

  getOption(key) {
    if (key in this._options) {
      return this._options[key];
    }
  }

  get mode() {
    return this.getOption('mode');
  }

  get display() {
    return this.getOption('display');
  }

  get xSize() {
    return this.getOption('display').xSize;
  }

  get ySize() {
    return this.getOption('display').ySize;
  }

  get xySize() {
    return [this.xSize, this.ySize];
  }

  /**
   * Initiate the display
   */
  init() {
    return new Promise(async (resolve, reject) => {
      try {
        await GPIOWrapper.setDirOut(PINS.RST);
        await GPIOWrapper.setDirOut(PINS.DC);
        await GPIOWrapper.setDirOut(PINS.CS);
        await GPIOWrapper.setDirIn(PINS.BUSY);
        await this.spi.open();
        if (this.mode === EPD_MODES.FULL) {
          await this.initDisplayFull();
        } else {
          await this.initDisplayPart();
        }
        await this.clearDisplay();
        this._ready = true;
        resolve();
      } catch (err) {
        await this.exit();
        reject(err);
      }
    });
  }

  /**
   * Shutdown everything
   */
  exit() {
    return new Promise(async (resolve, reject) => {
      if (this.isClosed || !this.isReady) {
        return resolve();
      }
      try {
        this._closed = true;
        this._ready = false;
        await this.spi.close();
        await GPIOWrapper.destroy();
        resolve();
      } catch (err) {
        reject(err);
      }
    });
  }

  /**
   * Sleep whilst BUSY pin is high (give up after 5 seconds)
   * @returns {Promise} resolves true when BUSY is low
   */
  whileBusy() {
    return new Promise(async (resolve, reject) => {
      for (let i = 0; i < 500; i++) {
        let busy = await GPIOWrapper.input(PINS.BUSY);
        if (busy === false) {
          return resolve(true);
        }
        await EPD.sleep(10);
      }
      resolve(false);
    });
  }

  writeCommand(command, para = false) {
    return new Promise(async (resolve, reject) => {
      if (para !== false) {
        await this.whileBusy();
      }
      // await GPIOWrapper.output(PINS.CS, GPIOWrapper.LOW); // not required?
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.LOW);
      await this.spi.write([command]);
      if (para !== false) {
        await GPIOWrapper.output(PINS.DC, GPIOWrapper.HIGH);
        await this.spi.write([para]);
      }
      // await GPIOWrapper.output(PINS.CS, GPIOWrapper.HIGH); // not required?
      resolve();
    });
  }

  writeData(data) {
    return new Promise(async (resolve, reject) => {
      // await GPIOWrapper.output(PINS.CS, GPIOWrapper.LOW); // not required?
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.LOW);
      await EPD.sleep(10);
      await this.spi.write([data.shift()]);
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.HIGH);
      if (data.length > 0) {
        await this.spi.write(data);
      }
      // await GPIOWrapper.output(PINS.CS, GPIOWrapper.HIGH); // not required?
      resolve();
    });
  }

  writeDisplayRAM(xSize, ySize, data) {
    if (xSize % 8 !== 0) {
      throw new Error('writeDisplayRAM: xSize must be multiple of 8');
    }
    if (!Array.isArray(data) && !Buffer.isBuffer(data)) {
      data = Array(xSize / 8 * ySize).fill(data);
    }
    return new Promise(async (resolve, reject) => {
      await this.whileBusy();
      // await GPIOWrapper.output(PINS.CS, GPIOWrapper.LOW); // not required?
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.LOW);
      await this.spi.write([0x24]);
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.HIGH);
      await this.spi.write(data);
      // await GPIOWrapper.output(PINS.CS, GPIOWrapper.HIGH); // not required?
      resolve();
    });
  }

  setRAMArea(xStart, xEnd, yStart, yStart1, yEnd, yEnd1) {
    return new Promise(async (resolve, reject) => {
      await this.writeData([0x44, xStart, xEnd]);
      await this.writeData([0x45, yStart, yStart1, yEnd, yEnd1]);
      resolve();
    });
  }

  setRAMPointer(xAddr, yAddr, yAddr1) {
    return new Promise(async (resolve, reject) => {
      await this.writeData([0x4e, xAddr]);
      await this.writeData([0x4f, yAddr, yAddr1]);
      resolve();
    });
  }

  setRAMAreaPointer(xStart, xEnd, yStart, yStart1, yEnd, yEnd1) {
    return new Promise(async (resolve, reject) => {
      await this.setRAMArea(xStart, xEnd, yStart, yStart1, yEnd, yEnd1);
      await this.setRAMPointer(xStart, yStart, yStart1);
      resolve();
    });
  }

  powerOn() {
    return new Promise(async (resolve, reject) => {
      await this.writeCommand(0x22, 0xc0);
      await this.writeCommand(0x20);
      resolve();
    });
  }

  initDisplay() {
    return new Promise(async (resolve, reject) => {
      try {
        // await GPIOWrapper.output(PINS.CS, GPIOWrapper.LOW); // not required?
        await GPIOWrapper.output(PINS.RST, GPIOWrapper.LOW);
        await EPD.sleep(100);
        await GPIOWrapper.output(PINS.RST, GPIOWrapper.HIGH);
        await EPD.sleep(100);
        let reset = await GPIOWrapper.input(PINS.RST);
        if (reset !== true) {
          throw new Error('initDisplay: reset failed');
        }
        await this.writeData(this.display.GDO_CONTROL);
        await this.writeData(COMMANDS.SOFT_START);
        await this.writeData(COMMANDS.VCOM_VOL);
        await this.writeData(COMMANDS.DUMMY_LINE);
        await this.writeData(COMMANDS.GATE_TIME);
        await this.writeData(COMMANDS.RAM_DATA_ENTRY_MODE);
        await this.setRAMArea(
          0x00,
          Math.floor((this.xSize - 1) / 8),
          (this.ySize - 1) % 256,
          Math.floor((this.ySize - 1) / 256),
          0x00,
          0x00
        );
        await this.setRAMPointer(
          0x00,
          (this.ySize - 1) % 256,
          Math.floor((this.ySize - 1) / 256)
        );
      } catch (err) {
        await this.exit();
        return;
      }
      resolve();
    });
  }

  updateDisplayFull() {
    return new Promise(async (resolve, reject) => {
      try {
        await this.writeCommand(0x22, 0xc7);
        await this.writeCommand(0x20);
        await this.writeCommand(0xff);
        resolve();
      } catch (err) {
        return reject(err);
      }
    });
  }

  updateDisplayPart() {
    return new Promise(async (resolve, reject) => {
      try {
        await this.writeCommand(0x22, 0x04);
        await this.writeCommand(0x20);
        await this.writeCommand(0xff);
        resolve();
      } catch (err) {
        return reject(err);
      }
    });
  }

  /**
   * Initiate "full" screen mode
   */
  initDisplayFull() {
    return new Promise(async (resolve, reject) => {
      try {
        await this.initDisplay();
        await this.writeData(this.display.LUT_DEFAULT_FULL);
        await this.powerOn();
      } catch (err) {
        return reject(err);
      }
      await EPD.sleep(1500);
      resolve();
    });
  }

  /**
   * Initiate "partial" screen mode
   */
  initDisplayPart() {
    return new Promise(async (resolve, reject) => {
      try {
        await this.initDisplay();
        await this.writeData(this.display.LUT_DEFAULT_PART);
        await this.powerOn();
      } catch (err) {
        return reject(err);
      }
      await EPD.sleep(1500);
      resolve();
    });
  }

  /**
   * Fill entire screen whilst in "full" screen mode
   * @param {int} data - pixel value to write (probably "0xff" or "0x00")
   */
  writeDisplayFull(data = 0xff) {
    if (this.mode !== EPD_MODES.FULL) {
      throw new Error('writeDisplayFull: cannot use while in "partial" mode');
    }
    return new Promise(async (resolve, reject) => {
      await this.setRAMPointer(
        0x00,
        (this.ySize - 1) % 256,
        Math.floor((this.ySize - 1) / 256)
      );
      await this.writeDisplayRAM(this.xSize, this.ySize, data);
      await this.updateDisplayFull();
      await EPD.sleep(1500);
      resolve();
    });
  }

  /**
   * Write area of the screen whist in "partial" screen mode
   * ...just use "writeDisplayPart2" for logical parameters
   */
  writeDisplayPart(xStart, xEnd, yStart, yEnd, data = 0xff) {
    if (this.mode !== EPD_MODES.PARTIAL) {
      throw new Error('writeDisplayPart: cannot use while in "full" mode');
    }
    return new Promise(async (resolve, reject) => {
      const writeRAM = async () =>
        new Promise(async (resolve, reject) => {
          await this.setRAMAreaPointer(
            Math.floor(xStart / 8),
            Math.floor(xEnd / 8),
            yEnd % 256,
            Math.floor(yEnd / 256),
            yStart % 256,
            Math.floor(yStart / 256)
          );
          await this.writeDisplayRAM(
            xEnd - xStart + 1,
            yEnd - yStart + 1,
            data
          );
          resolve();
        });
      await writeRAM();
      await this.updateDisplayPart();
      await EPD.sleep(100);
      await writeRAM();
      resolve();
    });
  }

  /**
   * Write area of the screen whist in "partial" screen mode
   * @param {int} xStart - zero-based X offset from top-left of screen
   * @param {int} yStart - zero-based Y offset from top-left of screen
   * @param {int} xSize - width of image
   * @param {int} ySize - height of image
   * @param {Array|Buffer} data - image data
   */
  writeDisplayPart2(
    xStart = 0,
    yStart = 0,
    xSize = this.xSize,
    ySize = this.ySize,
    data = 0xff
  ) {
    if (xStart % 8 !== 0) {
      throw new Error('writeDisplayPart2: xStart must be multiple of 8');
    }
    if (xSize % 8 !== 0) {
      throw new Error('writeDisplayPart2: xSize must be multiple of 8');
    }
    return new Promise(async (resolve, reject) => {
      // convert from top-left pixel values supplied
      xStart = this.xSize - xSize - xStart;
      yStart = this.ySize - ySize - yStart;
      await this.writeDisplayPart(
        xStart,
        xStart + xSize - 1,
        yStart,
        yStart + ySize - 1,
        data
      );
      resolve();
    });
  }

  /**
   * Clear the full screen (either mode)
   * @param {int} data - pixel value to write (probably "0xff" or "0x00")
   */
  clearDisplay(data = 0xff) {
    if (this.mode === EPD_MODES.FULL) {
      return new Promise(async (resolve, reject) => {
        await this.writeDisplayFull(data);
        resolve();
      });
    }
    if (this.mode === EPD_MODES.PARTIAL) {
      return new Promise(async (resolve, reject) => {
        await this.writeDisplayPart2(0, 0, this.xSize, this.ySize, data);
        resolve();
      });
    }
  }
}

module.exports = EPD;
<commit_msg>CS test<commit_after>const GPIOWrapper = require('./gpio-wrapper');
const SPIWrapper = require('./spi-wrapper');
const {PINS, EPD_MODES, COMMANDS, EPD1X54} = require('./constants');

class EPD {
  constructor(options = {}) {
    this._options = Object.assign(
      Object.assign(
        {},
        {
          mode: EPD_MODES.FULL,
          display: EPD1X54
        }
      ),
      options
    );

    this._ready = false;
    this._closed = false;
    this._terminated = false;

    this._spi = new SPIWrapper();

    const terminate = async () => {
      if (this._terminated) {
        return;
      }
      this._terminated = true;
      await this.exit();
      process.exit(0);
    };

    process.on('SIGINT', terminate);
    process.on('SIGTERM', terminate);
  }

  /**
   * Asynchronous sleep function
   * @param {int} ms - number of milliseconds to sleep
   * @example
   * // sleep for one second
   * await EPD.sleep(1000);
   */
  static sleep(ms) {
    return new Promise((resolve, reject) => setTimeout(resolve, ms));
  }

  static get MODES() {
    return EPD_MODES;
  }

  get spi() {
    return this._spi;
  }

  get isReady() {
    return this._ready;
  }

  get isClosed() {
    return this._closed;
  }

  get isTerminated() {
    return this._terminated;
  }

  getOption(key) {
    if (key in this._options) {
      return this._options[key];
    }
  }

  get mode() {
    return this.getOption('mode');
  }

  get display() {
    return this.getOption('display');
  }

  get xSize() {
    return this.getOption('display').xSize;
  }

  get ySize() {
    return this.getOption('display').ySize;
  }

  get xySize() {
    return [this.xSize, this.ySize];
  }

  /**
   * Initiate the display
   */
  init() {
    return new Promise(async (resolve, reject) => {
      try {
        await GPIOWrapper.setDirOut(PINS.RST);
        await GPIOWrapper.setDirOut(PINS.DC);
        await GPIOWrapper.setDirOut(PINS.CS);
        await GPIOWrapper.setDirIn(PINS.BUSY);
        await this.spi.open();
        if (this.mode === EPD_MODES.FULL) {
          await this.initDisplayFull();
        } else {
          await this.initDisplayPart();
        }
        await this.clearDisplay();
        this._ready = true;
        resolve();
      } catch (err) {
        await this.exit();
        reject(err);
      }
    });
  }

  /**
   * Shutdown everything
   */
  exit() {
    return new Promise(async (resolve, reject) => {
      if (this.isClosed || !this.isReady) {
        return resolve();
      }
      try {
        this._closed = true;
        this._ready = false;
        await this.spi.close();
        await GPIOWrapper.destroy();
        resolve();
      } catch (err) {
        reject(err);
      }
    });
  }

  /**
   * Sleep whilst BUSY pin is high (give up after 5 seconds)
   * @returns {Promise} resolves true when BUSY is low
   */
  whileBusy() {
    return new Promise(async (resolve, reject) => {
      for (let i = 0; i < 500; i++) {
        let busy = await GPIOWrapper.input(PINS.BUSY);
        if (busy === false) {
          return resolve(true);
        }
        await EPD.sleep(10);
      }
      resolve(false);
    });
  }

  writeCommand(command, para = false) {
    return new Promise(async (resolve, reject) => {
      if (para !== false) {
        await this.whileBusy();
      }
      await GPIOWrapper.output(PINS.CS, GPIOWrapper.LOW); // not required?
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.LOW);
      await this.spi.write([command]);
      if (para !== false) {
        await GPIOWrapper.output(PINS.DC, GPIOWrapper.HIGH);
        await this.spi.write([para]);
      }
      await GPIOWrapper.output(PINS.CS, GPIOWrapper.HIGH); // not required?
      resolve();
    });
  }

  writeData(data) {
    return new Promise(async (resolve, reject) => {
      await GPIOWrapper.output(PINS.CS, GPIOWrapper.LOW); // not required?
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.LOW);
      await EPD.sleep(10);
      await this.spi.write([data.shift()]);
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.HIGH);
      if (data.length > 0) {
        await this.spi.write(data);
      }
      await GPIOWrapper.output(PINS.CS, GPIOWrapper.HIGH); // not required?
      resolve();
    });
  }

  writeDisplayRAM(xSize, ySize, data) {
    if (xSize % 8 !== 0) {
      throw new Error('writeDisplayRAM: xSize must be multiple of 8');
    }
    if (!Array.isArray(data) && !Buffer.isBuffer(data)) {
      data = Array(xSize / 8 * ySize).fill(data);
    }
    return new Promise(async (resolve, reject) => {
      await this.whileBusy();
      await GPIOWrapper.output(PINS.CS, GPIOWrapper.LOW); // not required?
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.LOW);
      await this.spi.write([0x24]);
      await GPIOWrapper.output(PINS.DC, GPIOWrapper.HIGH);
      await this.spi.write(data);
      await GPIOWrapper.output(PINS.CS, GPIOWrapper.HIGH); // not required?
      resolve();
    });
  }

  setRAMArea(xStart, xEnd, yStart, yStart1, yEnd, yEnd1) {
    return new Promise(async (resolve, reject) => {
      await this.writeData([0x44, xStart, xEnd]);
      await this.writeData([0x45, yStart, yStart1, yEnd, yEnd1]);
      resolve();
    });
  }

  setRAMPointer(xAddr, yAddr, yAddr1) {
    return new Promise(async (resolve, reject) => {
      await this.writeData([0x4e, xAddr]);
      await this.writeData([0x4f, yAddr, yAddr1]);
      resolve();
    });
  }

  setRAMAreaPointer(xStart, xEnd, yStart, yStart1, yEnd, yEnd1) {
    return new Promise(async (resolve, reject) => {
      await this.setRAMArea(xStart, xEnd, yStart, yStart1, yEnd, yEnd1);
      await this.setRAMPointer(xStart, yStart, yStart1);
      resolve();
    });
  }

  powerOn() {
    return new Promise(async (resolve, reject) => {
      await this.writeCommand(0x22, 0xc0);
      await this.writeCommand(0x20);
      resolve();
    });
  }

  initDisplay() {
    return new Promise(async (resolve, reject) => {
      try {
        await GPIOWrapper.output(PINS.CS, GPIOWrapper.LOW); // not required?
        await GPIOWrapper.output(PINS.RST, GPIOWrapper.LOW);
        await EPD.sleep(100);
        await GPIOWrapper.output(PINS.RST, GPIOWrapper.HIGH);
        await EPD.sleep(100);
        let reset = await GPIOWrapper.input(PINS.RST);
        if (reset !== true) {
          throw new Error('initDisplay: reset failed');
        }
        await this.writeData(this.display.GDO_CONTROL);
        await this.writeData(COMMANDS.SOFT_START);
        await this.writeData(COMMANDS.VCOM_VOL);
        await this.writeData(COMMANDS.DUMMY_LINE);
        await this.writeData(COMMANDS.GATE_TIME);
        await this.writeData(COMMANDS.RAM_DATA_ENTRY_MODE);
        await this.setRAMArea(
          0x00,
          Math.floor((this.xSize - 1) / 8),
          (this.ySize - 1) % 256,
          Math.floor((this.ySize - 1) / 256),
          0x00,
          0x00
        );
        await this.setRAMPointer(
          0x00,
          (this.ySize - 1) % 256,
          Math.floor((this.ySize - 1) / 256)
        );
      } catch (err) {
        await this.exit();
        return;
      }
      resolve();
    });
  }

  updateDisplayFull() {
    return new Promise(async (resolve, reject) => {
      try {
        await this.writeCommand(0x22, 0xc7);
        await this.writeCommand(0x20);
        await this.writeCommand(0xff);
        resolve();
      } catch (err) {
        return reject(err);
      }
    });
  }

  updateDisplayPart() {
    return new Promise(async (resolve, reject) => {
      try {
        await this.writeCommand(0x22, 0x04);
        await this.writeCommand(0x20);
        await this.writeCommand(0xff);
        resolve();
      } catch (err) {
        return reject(err);
      }
    });
  }

  /**
   * Initiate "full" screen mode
   */
  initDisplayFull() {
    return new Promise(async (resolve, reject) => {
      try {
        await this.initDisplay();
        await this.writeData(this.display.LUT_DEFAULT_FULL);
        await this.powerOn();
      } catch (err) {
        return reject(err);
      }
      await EPD.sleep(1500);
      resolve();
    });
  }

  /**
   * Initiate "partial" screen mode
   */
  initDisplayPart() {
    return new Promise(async (resolve, reject) => {
      try {
        await this.initDisplay();
        await this.writeData(this.display.LUT_DEFAULT_PART);
        await this.powerOn();
      } catch (err) {
        return reject(err);
      }
      await EPD.sleep(1500);
      resolve();
    });
  }

  /**
   * Fill entire screen whilst in "full" screen mode
   * @param {int} data - pixel value to write (probably "0xff" or "0x00")
   */
  writeDisplayFull(data = 0xff) {
    if (this.mode !== EPD_MODES.FULL) {
      throw new Error('writeDisplayFull: cannot use while in "partial" mode');
    }
    return new Promise(async (resolve, reject) => {
      await this.setRAMPointer(
        0x00,
        (this.ySize - 1) % 256,
        Math.floor((this.ySize - 1) / 256)
      );
      await this.writeDisplayRAM(this.xSize, this.ySize, data);
      await this.updateDisplayFull();
      await EPD.sleep(1500);
      resolve();
    });
  }

  /**
   * Write area of the screen whist in "partial" screen mode
   * ...just use "writeDisplayPart2" for logical parameters
   */
  writeDisplayPart(xStart, xEnd, yStart, yEnd, data = 0xff) {
    if (this.mode !== EPD_MODES.PARTIAL) {
      throw new Error('writeDisplayPart: cannot use while in "full" mode');
    }
    return new Promise(async (resolve, reject) => {
      const writeRAM = async () =>
        new Promise(async (resolve, reject) => {
          await this.setRAMAreaPointer(
            Math.floor(xStart / 8),
            Math.floor(xEnd / 8),
            yEnd % 256,
            Math.floor(yEnd / 256),
            yStart % 256,
            Math.floor(yStart / 256)
          );
          await this.writeDisplayRAM(
            xEnd - xStart + 1,
            yEnd - yStart + 1,
            data
          );
          resolve();
        });
      await writeRAM();
      await this.updateDisplayPart();
      await EPD.sleep(100);
      await writeRAM();
      resolve();
    });
  }

  /**
   * Write area of the screen whist in "partial" screen mode
   * @param {int} xStart - zero-based X offset from top-left of screen
   * @param {int} yStart - zero-based Y offset from top-left of screen
   * @param {int} xSize - width of image
   * @param {int} ySize - height of image
   * @param {Array|Buffer} data - image data
   */
  writeDisplayPart2(
    xStart = 0,
    yStart = 0,
    xSize = this.xSize,
    ySize = this.ySize,
    data = 0xff
  ) {
    if (xStart % 8 !== 0) {
      throw new Error('writeDisplayPart2: xStart must be multiple of 8');
    }
    if (xSize % 8 !== 0) {
      throw new Error('writeDisplayPart2: xSize must be multiple of 8');
    }
    return new Promise(async (resolve, reject) => {
      // convert from top-left pixel values supplied
      xStart = this.xSize - xSize - xStart;
      yStart = this.ySize - ySize - yStart;
      await this.writeDisplayPart(
        xStart,
        xStart + xSize - 1,
        yStart,
        yStart + ySize - 1,
        data
      );
      resolve();
    });
  }

  /**
   * Clear the full screen (either mode)
   * @param {int} data - pixel value to write (probably "0xff" or "0x00")
   */
  clearDisplay(data = 0xff) {
    if (this.mode === EPD_MODES.FULL) {
      return new Promise(async (resolve, reject) => {
        await this.writeDisplayFull(data);
        resolve();
      });
    }
    if (this.mode === EPD_MODES.PARTIAL) {
      return new Promise(async (resolve, reject) => {
        await this.writeDisplayPart2(0, 0, this.xSize, this.ySize, data);
        resolve();
      });
    }
  }
}

module.exports = EPD;
<|endoftext|>


<commit_before>var GRID_Y_MAX = 10;
var GRID_X_MAX = 14;
var TILE_SIZE = 64;
var TOOTH_FRAMES = 4;
var TOP_TOOTH_Y = getGridPixel(4);
var BOTTOM_TOOTH_Y = getGridPixel(7);
var FLIPPED=-1,STANDARD=1;
var DECAY_TIME = 35000;
var MAX_CAVITIES = 2;

var game = new Phaser.Game(896, 640, Phaser.AUTO, 'game', { preload: preload, create: create, update: update });
var Teeth, downGums, upGums;
var mouse;
var toothTimers = [], toothStartTimers = [];
function preload() {
  game.load.spritesheet('happyTooth', 'assets/happyTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('sadTooth', 'assets/sadTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('sadderTooth', 'assets/sadderTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('saddestTooth', 'assets/saddestTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('cavityTooth', 'assets/cavityTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('toothbrush', 'assets/toothBrush.png', TILE_SIZE, TILE_SIZE);
  game.load.image('gums', 'assets/gums.png');
  game.load.image('bg', 'assets/background.png');
  game.load.image('realBg', 'assets/realBackground.png');

  game.load.audio('brushingSound', 'assets/Sounds/brushSound.ogg');
  game.load.audio('levelStartSound', 'assets/Sounds/startLevel.ogg');
  game.load.audio('cleanToothSound', 'assets/Sounds/cleanTooth.ogg');
}

var toothbrush;
var winningText;
var brushingSound;
var muteCleanToothSound;
function create() {
  mouse = new Phaser.Pointer(game, 0, Phaser.CURSOR);
  game.physics.startSystem(Phaser.Physics.ARCADE);
  game.add.sprite(0, 0, 'realBg');
  game.add.sprite(0, 0, 'bg');
  brushingSound = game.add.audio('brushingSound');
  brushingSound.loop = true;
  brushingSound.play();
  brushingSound.pause();

  muteCleanToothSound = true;

  initGroups(game);
  Teeth.enableBody = true;
  generateTopTeeth();
  generateBottomTeeth();
  game.sound.play('levelStartSound');
  animateTeeth();

  muteCleanToothSound = false;

  //toothbrush is on the top of it all, so it shoudl be last.
  toothbrush = game.add.sprite(0, 0, 'toothbrush');
  toothbrush.animations.add('brush', [0, 1, 2, 3, 4, 5, 6, 7], 4, true);

  winningText = game.add.text(game.width / 2 - 128, (game.height / 2) - 64, '', { fontSize: '50px', fill: '#FFF', stroke: '#000', strokeThickness: 6 })
}

var frame = 0;
function update() {
  animateTeeth();
  updateToothbrushPosition();
  cleanTooth();
  checkForWin();
}

function initGroups(game){
  upGums = game.add.group();
  downGums = game.add.group();
  Teeth = game.add.group();
  sadTeeth = game.add.group();
  hurtTeeth = game.add.group();
}

function generateTopTeeth(){
  generateToothRow(FLIPPED, TOP_TOOTH_Y)
}

function generateBottomTeeth(){
  generateToothRow(STANDARD, BOTTOM_TOOTH_Y);
}

function generateToothRow(scale, y){
  for(var i=0; i < 10; i++){
    var gum = downGums.create(getGridPixel(2+i), y, 'gums');
    gum.scale.y = scale;
    var sprite = Teeth.create(getGridPixel(2 + i), y, 'happyTooth');
    sprite.animations.add('dance', [0,1,2,3], 10, true);
    var theTooth = toothFactory();
    sprite.tooth = theTooth;
    var timerStart = Math.random() * DECAY_TIME;
    toothStartTimers.push(setTimeout(function(theTooth){
      theTooth.decay();
      toothTimers.push(
        setInterval(
          function(tooth){
            tooth.decay()
          },
           DECAY_TIME,
           theTooth)
      );
    }, timerStart, sprite.tooth));
    sprite.scale.y = scale;
  }
}

function getGridPixel( gridNumber) {
  return ( gridNumber * TILE_SIZE );
}

function animateTeeth(){
  for (var i=0; i<Teeth.length; i++){
    updateToothSprite(Teeth.cursor)
    Teeth.cursor.play('dance');
    Teeth.next();
  }
}

function updateToothSprite(sprite) {
  if(sprite.tooth.refresh){
      sprite.tooth.refresh = false;
      sprite.animations.stop('dance');

    switch (sprite.tooth.state) {
      case CLEAN :
          sprite.loadTexture('happyTooth',0);
          if (!muteCleanToothSound) {
            game.sound.play('cleanToothSound');
          }
          break;
      case DIRTY :
          sprite.loadTexture('sadTooth',0);
          break;
      case DIRTIER :
          sprite.loadTexture('sadderTooth',0);
          break;
      case DIRTIEST :
          sprite.loadTexture('saddestTooth',0);
          break;
      default :
          sprite.loadTexture('cavityTooth',0);
      }
      sprite.animations.add('dance', [0,1,2,3], 10, true);
  }
}

function updateToothbrushPosition(){
  toothbrush.position.x = game.input.x - (TILE_SIZE / 4);
  toothbrush.position.y = game.input.y - (TILE_SIZE / 4);
}

function cleanTooth(){
  //get the bounding box of the toothbrush sprite, and shrink it to fit the
  //  area of the actual sprite
  var brushArea = toothbrush.getBounds();
  brushArea.y = brushArea.y + 15;
  brushArea.height = 1;
  brushArea.x = brushArea.x + 15;
  brushArea.width = 1;

  //loop through the teeth, are we on top of them?
  if (game.input.mousePointer.isDown){
    var inTooth = false;
    for (var i = 0; i<Teeth.length; i++){
      if (Phaser.Rectangle.intersects(brushArea, Teeth.cursor.getBounds())) {
        inTooth = true;
        Teeth.cursor.tooth.brush()
        break; //stop if we found one since it's only 1 pointer.
      }
      Teeth.next();
    }
    if(inTooth){
      toothbrush.animations.play('brush');
      brushingSound.resume();
    } else {
      toothbrush.animations.stop();
      toothbrush.frame = 0;
      brushingSound.pause();
    }
  } else {
    toothbrush.animations.stop();
    toothbrush.frame = 0;
    brushingSound.pause();
  }
}

function checkForWin(){
  var cavityCount = 0;
  var totalHealthy = Teeth.length;
  for(var i=0; i<Teeth.length; i++){
    if (Teeth.cursor.tooth.state == CAVITY){
      cavityCount += 1;
    }
    if(Teeth.cursor.tooth.state != CLEAN){
      totalHealthy -= 1;
    }
    Teeth.next();
  }
  if (cavityCount >= MAX_CAVITIES ){
    winningText.text = "You should take better care of your teeth!"
  } else if(totalHealthy + cavityCount == Teeth.length){
    winningText.text = 'All Clean!'
  } else {
    return;
  }
  //clear the ones that haven't been scheulded yet.
  for (var startIndex in toothStartTimers){
    clearTimeout(toothStartTimers[startIndex]);
  }
  toothStartTimers = [];

  for(var timerIndex in toothTimers) {
    clearInterval(toothTimers[timerIndex]);
  }
  toothTimers = [];
}
<commit_msg>aMerge branch 'master' of https://github.com/hackernight/gamejam2016<commit_after>var GRID_Y_MAX = 10;
var GRID_X_MAX = 14;
var TILE_SIZE = 64;
var TOOTH_FRAMES = 4;
var TOP_TOOTH_Y = getGridPixel(4);
var BOTTOM_TOOTH_Y = getGridPixel(6);
var FLIPPED=-1,STANDARD=1;
var DECAY_TIME = 35000;
var MAX_CAVITIES = 2;

var game = new Phaser.Game(896, 640, Phaser.AUTO, 'game', { preload: preload, create: create, update: update });
var Teeth, downGums, gumBlocks;
var mouse;
var toothTimers = [], toothStartTimers = [];
function preload() {
  game.load.spritesheet('happyTooth', 'assets/happyTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('sadTooth', 'assets/sadTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('sadderTooth', 'assets/sadderTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('saddestTooth', 'assets/saddestTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('cavityTooth', 'assets/cavityTooth.png', TILE_SIZE, TILE_SIZE);
  game.load.spritesheet('toothbrush', 'assets/toothBrush.png', TILE_SIZE, TILE_SIZE);
  game.load.image('gums', 'assets/gums.png');
  game.load.image('gumBlock', 'assets/gumTile.png');
  game.load.image('topLip', 'assets/topLips.png');
  game.load.image('bottomLip', 'assets/bottomLips.png');
  game.load.image('bg', 'assets/background.png');
  game.load.image('realBg', 'assets/realBackground.png');

  game.load.audio('brushingSound', 'assets/Sounds/brushSound.ogg');
  game.load.audio('levelStartSound', 'assets/Sounds/startLevel.ogg');
  game.load.audio('cleanToothSound', 'assets/Sounds/cleanTooth.ogg');
}

var toothbrush;
var winningText;
var brushingSound;
var muteCleanToothSound;
function create() {
  mouse = new Phaser.Pointer(game, 0, Phaser.CURSOR);
  game.physics.startSystem(Phaser.Physics.ARCADE);
  game.add.sprite(0, 0, 'realBg');
  game.add.sprite(0, 0, 'bg');
  brushingSound = game.add.audio('brushingSound');
  brushingSound.loop = true;
  brushingSound.play();
  brushingSound.pause();

  muteCleanToothSound = true;

  initGroups(game);
  Teeth.enableBody = true;
  generateTopTeeth();
  generateBottomTeeth();
  game.sound.play('levelStartSound');
  animateTeeth();

  muteCleanToothSound = false;

  game.add.sprite(0, 0, 'topLip');
  game.add.sprite(0, getGridPixel(6) + 36, 'bottomLip');

  //toothbrush is on the top of it all, so it shoudl be last.
  toothbrush = game.add.sprite(0, 0, 'toothbrush');
  toothbrush.animations.add('brush', [0, 1, 2, 3, 4, 5, 6, 7], 10, true);

  winningText = game.add.text(game.width / 2 - 128, (game.height / 2) - 64, '', { fontSize: '50px', fill: '#FFF', stroke: '#000', strokeThickness: 6 })
}

var frame = 0;
function update() {
  animateTeeth();
  updateToothbrushPosition();
  cleanTooth();
  checkForWin();
}

function initGroups(game){
  gumBlocks = game.add.group();
  downGums = game.add.group();
  Teeth = game.add.group();
  sadTeeth = game.add.group();
  hurtTeeth = game.add.group();
}

function generateTopTeeth(){
  generateToothRow(FLIPPED, TOP_TOOTH_Y)
}

function generateBottomTeeth(){
  generateToothRow(STANDARD, BOTTOM_TOOTH_Y);
}

function generateToothRow(scale, y){
  for(var i=0; i < 10; i++){
    if(scale == FLIPPED){
      var gumBlock = gumBlocks.create(getGridPixel(2+i), y - 128 , 'gumBlock');
    } else {
      var gumBlock = gumBlocks.create(getGridPixel(2+i), y + 64, 'gumBlock');
    }
    var gum = downGums.create(getGridPixel(2+i), y, 'gums');
    gum.scale.y = scale;
    var sprite = Teeth.create(getGridPixel(2 + i), y, 'happyTooth');
    sprite.animations.add('dance', [0,1,2,3], 10, true);
    var theTooth = toothFactory();
    sprite.tooth = theTooth;
    var timerStart = Math.random() * DECAY_TIME;
    toothStartTimers.push(setTimeout(function(theTooth){
      theTooth.decay();
      toothTimers.push(
        setInterval(
          function(tooth){
            tooth.decay()
          },
           DECAY_TIME,
           theTooth)
      );
    }, timerStart, sprite.tooth));
    sprite.scale.y = scale;
  }
}

function getGridPixel( gridNumber) {
  return ( gridNumber * TILE_SIZE );
}

function animateTeeth(){
  for (var i=0; i<Teeth.length; i++){
    updateToothSprite(Teeth.cursor)
    Teeth.cursor.play('dance');
    Teeth.next();
  }
}

function updateToothSprite(sprite) {
  if(sprite.tooth.refresh){
      sprite.tooth.refresh = false;
      sprite.animations.stop('dance');

    switch (sprite.tooth.state) {
      case CLEAN :
          sprite.loadTexture('happyTooth',0);
          if (!muteCleanToothSound) {
            game.sound.play('cleanToothSound');
          }
          break;
      case DIRTY :
          sprite.loadTexture('sadTooth',0);
          break;
      case DIRTIER :
          sprite.loadTexture('sadderTooth',0);
          break;
      case DIRTIEST :
          sprite.loadTexture('saddestTooth',0);
          break;
      default :
          sprite.loadTexture('cavityTooth',0);
      }
      sprite.animations.add('dance', [0,1,2,3], 10, true);
  }
}

function updateToothbrushPosition(){
  toothbrush.position.x = game.input.x - (TILE_SIZE / 4);
  toothbrush.position.y = game.input.y - (TILE_SIZE / 4);
}

function cleanTooth(){
  //get the bounding box of the toothbrush sprite, and shrink it to fit the
  //  area of the actual sprite
  var brushArea = toothbrush.getBounds();
  brushArea.y = brushArea.y + 15;
  brushArea.height = 1;
  brushArea.x = brushArea.x + 15;
  brushArea.width = 1;

  //loop through the teeth, are we on top of them?
  if (game.input.mousePointer.isDown){
    var inTooth = false;
    for (var i = 0; i<Teeth.length; i++){
      if (Phaser.Rectangle.intersects(brushArea, Teeth.cursor.getBounds())) {
        inTooth = true;
        Teeth.cursor.tooth.brush()
        break; //stop if we found one since it's only 1 pointer.
      }
      Teeth.next();
    }
    if(inTooth){
      toothbrush.animations.play('brush');
      brushingSound.resume();
    } else {
      toothbrush.animations.stop();
      toothbrush.frame = 0;
      brushingSound.pause();
    }
  } else {
    toothbrush.animations.stop();
    toothbrush.frame = 0;
    brushingSound.pause();
  }
}

function checkForWin(){
  var cavityCount = 0;
  var totalHealthy = Teeth.length;
  for(var i=0; i<Teeth.length; i++){
    if (Teeth.cursor.tooth.state == CAVITY){
      cavityCount += 1;
    }
    if(Teeth.cursor.tooth.state != CLEAN){
      totalHealthy -= 1;
    }
    Teeth.next();
  }
  if (cavityCount >= MAX_CAVITIES ){
    winningText.text = "You should take better care of your teeth!"
  } else if(totalHealthy + cavityCount == Teeth.length){
    winningText.text = 'All Clean!'
  } else {
    return;
  }
  //clear the ones that haven't been scheulded yet.
  for (var startIndex in toothStartTimers){
    clearTimeout(toothStartTimers[startIndex]);
  }
  toothStartTimers = [];

  for(var timerIndex in toothTimers) {
    clearInterval(toothTimers[timerIndex]);
  }
  toothTimers = [];
}
<|endoftext|>


<commit_before>var characters = [];
var player;
var npc = [];
var bg, table;
var speaker;

var PLAYER_SPEAKING = 99;
var BUTTON_DELAY = 1000;
var START_FADING = 10000;
var CHARACTER_FADE_TIME = 20000;
var SCREEN_FADE_TIME = 5000;

var lastTickTime, buttonLastPressed, buttonPressInterval, continuousMashingTime;
var playerFade, npcFade, screenFade;
var gameOver;

function startGame()
{
	speaker = -1;
	currentLine = null;
	convoLength = 0;
	lastTickTime = createjs.Ticker.getTime();
	buttonLastPressed = createjs.Ticker.getTime()-BUTTON_DELAY;
	buttonPressInterval = 0;
	continuousMashingTime = 0;
	playerFade = 0;
	npcFade = 0;
	screenFade = 0;
	gameOver = false;

	speechBubble.alpha = 0;

	player.x = 863;
	player.y = 705;
	player.alpha = 1;
	player.scaleX = -1;
	player.gotoAndPlay("neutral");

	npc[0].x = 170;
	npc[0].y = 705;
	npc[0].alpha = 1;
	npc[0].scaleX = 1;
	npc[0].gotoAndPlay("neutral");

	npc[1].x = 418;
	npc[1].y = 705;
	npc[1].alpha = 1;
	npc[1].scaleX = -1;
	npc[1].gotoAndPlay("neutral");

	npc[2].x = 640;
	npc[2].y = 705;
	npc[2].alpha = 1;
	npc[2].scaleX = -1;
	npc[2].gotoAndPlay("neutral");

	table.x = 512;
	table.y = 736;

	stage.addChild(bg);
	stage.addChild(npc[2]);
	stage.addChild(npc[1]);
	stage.addChild(npc[0]);
	stage.addChild(player);
	stage.addChild(table);
	stage.addChild(speechBubble);
	stage.addChild(clickyBox);

	currentScreen = "game";
}

function gameLoop(keyPressed)
{
	var timeSinceLastTick = createjs.Ticker.getTime() - lastTickTime;
	lastTickTime = createjs.Ticker.getTime();

	if (gameOver)
	{
		screenFade += timeSinceLastTick;
		clickyBox.alpha = screenFade/SCREEN_FADE_TIME;
		if (clickyBox.alpha >= 1)
		{
			endGame();
			return;
		}
	}

	if (!gameOver && keyPressed == "space")
	{
		if (playerFade)
		{
			playerFade = 0;
			player.alpha = 1;
		}
		buttonLastPressed = createjs.Ticker.getTime();
	}

	buttonPressInterval = createjs.Ticker.getTime() - buttonLastPressed;

	if (buttonPressInterval <= BUTTON_DELAY || (gameOver && speaker == PLAYER_SPEAKING))
	{
		if (speaker == PLAYER_SPEAKING)
		{
			if (!currentLine) addToSpeechBubble();

			continuousMashingTime += timeSinceLastTick;
			if (continuousMashingTime >= START_FADING)
			{
				npcFade += timeSinceLastTick;
				for (var i = 0; i < npc.length; i++)
				{
					npc[i].alpha = (CHARACTER_FADE_TIME-npcFade)/CHARACTER_FADE_TIME;
				}
				if (npc[0].alpha <= 0) gameOver = true;
			}
		}
		else playerStartSpeaking();

		if (gameOver) updateSpeechBubble(0);
		else updateSpeechBubble(Math.floor(buttonPressInterval/(BUTTON_DELAY/5)));
	}
	else
	{
		if (speaker == PLAYER_SPEAKING)
		{
			continuousMashingTime = 0;
			npcFade = 0;
			for (var i = 0; i < npc.length; i++)
			{
				npc[i].alpha = 1;
			}
			currentLine = null;
			player.gotoAndPlay("neutral");
		}
		if (!currentLine) pickSpeaker();
		updateSpeechBubble(0);

		if (buttonPressInterval >= START_FADING)
		{
			playerFade += timeSinceLastTick;
			player.alpha = (CHARACTER_FADE_TIME-playerFade)/CHARACTER_FADE_TIME;
			if (player.alpha <= 0) gameOver = true;
		}
	}
}

function playerStartSpeaking()
{
	currentLine = null;
	npc[speaker].gotoAndPlay("neutral");
	speaker = PLAYER_SPEAKING;
	player.gotoAndPlay("point-talk");
	turnToFaceSpeaker();
	initSpeechBubble();
}

function pickSpeaker()
{
	var lastSpeaker = speaker;
	speaker = Math.floor(Math.random()*npc.length);

	if (lastSpeaker == speaker)
	{
		addToSpeechBubble();
	}
	else
	{
		if (lastSpeaker >= 0 && lastSpeaker < npc.length)
		{
			npc[lastSpeaker].gotoAndPlay("neutral");
		}
		npc[speaker].gotoAndPlay("point-talk");
		turnToFaceSpeaker();
		initSpeechBubble();
	}
}

function turnToFaceSpeaker()
{
	if (speaker == 0)
	{
		npc[1].scaleX = -1;
		npc[2].scaleX = -1;
	}
	else if (speaker == 1)
	{
		npc[2].scaleX = -1;
	}
	else if (speaker == 2)
	{
		npc[1].scaleX = 1;
	}
	else
	{
		npc[1].scaleX = 1;
		npc[2].scaleX = 1;
	}
}

function endGame()
{
	stage.removeAllChildren();
	clickyBox.alpha = 0.01;
	showTitle();
}
<commit_msg>Bored facial expressions<commit_after>var characters = [];
var player;
var npc = [];
var bg, table;
var speaker;

var PLAYER_SPEAKING = 99;
var BUTTON_DELAY = 1000;
var START_FADING = 10000;
var CHARACTER_FADE_TIME = 20000;
var SCREEN_FADE_TIME = 5000;

var lastTickTime, buttonLastPressed, buttonPressInterval, continuousMashingTime;
var playerFade, npcFade, screenFade;
var gameOver;

function startGame()
{
	speaker = -1;
	currentLine = null;
	convoLength = 0;
	lastTickTime = createjs.Ticker.getTime();
	buttonLastPressed = createjs.Ticker.getTime()-BUTTON_DELAY;
	buttonPressInterval = 0;
	continuousMashingTime = 0;
	playerFade = 0;
	npcFade = 0;
	screenFade = 0;
	gameOver = false;

	speechBubble.alpha = 0;

	player.x = 863;
	player.y = 705;
	player.alpha = 1;
	player.scaleX = -1;
	player.gotoAndPlay("neutral");

	npc[0].x = 170;
	npc[0].y = 705;
	npc[0].alpha = 1;
	npc[0].scaleX = 1;
	npc[0].gotoAndPlay("neutral");

	npc[1].x = 418;
	npc[1].y = 705;
	npc[1].alpha = 1;
	npc[1].scaleX = -1;
	npc[1].gotoAndPlay("neutral");

	npc[2].x = 640;
	npc[2].y = 705;
	npc[2].alpha = 1;
	npc[2].scaleX = -1;
	npc[2].gotoAndPlay("neutral");

	table.x = 512;
	table.y = 736;

	stage.addChild(bg);
	stage.addChild(npc[2]);
	stage.addChild(npc[1]);
	stage.addChild(npc[0]);
	stage.addChild(player);
	stage.addChild(table);
	stage.addChild(speechBubble);
	stage.addChild(clickyBox);

	currentScreen = "game";
}

function gameLoop(keyPressed)
{
	var timeSinceLastTick = createjs.Ticker.getTime() - lastTickTime;
	lastTickTime = createjs.Ticker.getTime();

	if (gameOver)
	{
		screenFade += timeSinceLastTick;
		clickyBox.alpha = screenFade/SCREEN_FADE_TIME;
		if (clickyBox.alpha >= 1)
		{
			endGame();
			return;
		}
	}

	if (!gameOver && keyPressed == "space")
	{
		if (playerFade)
		{
			playerFade = 0;
			player.alpha = 1;
		}
		buttonLastPressed = createjs.Ticker.getTime();
	}

	buttonPressInterval = createjs.Ticker.getTime() - buttonLastPressed;

	if (buttonPressInterval <= BUTTON_DELAY || (gameOver && speaker == PLAYER_SPEAKING))
	{
		if (speaker == PLAYER_SPEAKING)
		{
			if (!currentLine) addToSpeechBubble();

			continuousMashingTime += timeSinceLastTick;
			if (continuousMashingTime >= START_FADING)
			{
				npcFade += timeSinceLastTick;
				for (var i = 0; i < npc.length; i++)
				{
					npc[i].gotoAndPlay("bored");
					npc[i].alpha = (CHARACTER_FADE_TIME-npcFade)/CHARACTER_FADE_TIME;
				}
				if (npc[0].alpha <= 0) gameOver = true;
			}
		}
		else playerStartSpeaking();

		if (gameOver) updateSpeechBubble(0);
		else updateSpeechBubble(Math.floor(buttonPressInterval/(BUTTON_DELAY/5)));
	}
	else
	{
		if (speaker == PLAYER_SPEAKING)
		{
			continuousMashingTime = 0;
			npcFade = 0;
			for (var i = 0; i < npc.length; i++)
			{
				npc[i].alpha = 1;
				npc[i].gotoAndPlay("neutral");
			}
			currentLine = null;
			player.gotoAndPlay("neutral");
		}
		if (!currentLine) pickSpeaker();
		updateSpeechBubble(0);

		if (buttonPressInterval >= START_FADING)
		{
			player.gotoAndPlay("bored");
			playerFade += timeSinceLastTick;
			player.alpha = (CHARACTER_FADE_TIME-playerFade)/CHARACTER_FADE_TIME;
			if (player.alpha <= 0) gameOver = true;
		}
	}
}

function playerStartSpeaking()
{
	currentLine = null;
	npc[speaker].gotoAndPlay("bored");
	speaker = PLAYER_SPEAKING;
	player.gotoAndPlay("point-talk");
	turnToFaceSpeaker();
	initSpeechBubble();
}

function pickSpeaker()
{
	var lastSpeaker = speaker;
	speaker = Math.floor(Math.random()*npc.length);

	if (lastSpeaker == speaker)
	{
		addToSpeechBubble();
	}
	else
	{
		if (lastSpeaker >= 0 && lastSpeaker < npc.length)
		{
			npc[lastSpeaker].gotoAndPlay("neutral");
		}
		npc[speaker].gotoAndPlay("point-talk");
		turnToFaceSpeaker();
		initSpeechBubble();
	}
}

function turnToFaceSpeaker()
{
	if (speaker == 0)
	{
		npc[1].scaleX = -1;
		npc[2].scaleX = -1;
	}
	else if (speaker == 1)
	{
		npc[2].scaleX = -1;
	}
	else if (speaker == 2)
	{
		npc[1].scaleX = 1;
	}
	else
	{
		npc[1].scaleX = 1;
		npc[2].scaleX = 1;
	}
}

function endGame()
{
	stage.removeAllChildren();
	clickyBox.alpha = 0.01;
	showTitle();
}
<|endoftext|>