<commit_before>/* eslint-disable space-before-keywords  */
"use strict";

var resources = {}, svgData = {}, minify, $;

var async        = require("async");
var autoprefixer = require("autoprefixer");
var cheerio      = require("cheerio");
var cleanCSS     = require("clean-css");
var crypto       = require("crypto");
var fs           = require("graceful-fs");
var htmlMinifier = require("html-minifier");
var jb           = require("json-buffer");
var mime         = require("mime-types").lookup;
var path         = require("path");
var postcss      = require("postcss");
var uglify       = require("uglify-js");
var vm           = require("vm");
var zlib         = require("zlib");

var templates    = require("./templates");
var pkg          = require("./../package.json");
var paths        = require("./paths.js").get();

var themesPath   = path.join(paths.mod, "/node_modules/codemirror/theme");
var modesPath    = path.join(paths.mod, "/node_modules/codemirror/mode");

var opts = {
  get uglify() {
    return {
      fromString: true,
      mangle: true,
      compress: {
        unsafe: true,
        screw_ie8: true,
        sequences: true,
        dead_code: true,
        conditionals: true,
        booleans: true,
        unused: true,
        if_return: true,
        join_vars: true,
      },
    };
  },
  get cleanCSS() {
    return {
      keepSpecialComments : 0,
      roundingPrecision: 3,
      rebase: false,
    };
  },
  get autoprefixer() {
    return {
      browsers: ["last 2 versions"],
      cascade: false,
    };
  },
  get htmlMinifier() {
    return {
      removeComments: true,
      collapseWhitespace: true,
      collapseBooleanAttributes: true,
      removeAttributeQuotes: true,
      removeOptionalTags: true,
      removeRedundantAttributes: true,
      caseSensitive: true,
      minifyCSS: cleanCSS,
    };
  }
};

cleanCSS = new cleanCSS(opts.cleanCSS);

resources.files = {
  css: [
    "client/style.css",
    "client/sprites.css",
    "client/tooltips.css",
  ],
  js: [
    "node_modules/handlebars/dist/handlebars.runtime.min.js",
    "node_modules/jquery/dist/jquery.js",
    "node_modules/draggabilly/dist/draggabilly.pkgd.min.js",
    "node_modules/mousetrap/mousetrap.min.js",
    "node_modules/file-extension/file-extension.js",
    "node_modules/uppie/uppie.js",
    "client/client.js",
  ],
  html: [
    "client/html/base.html",
    "client/html/auth.html",
    "client/html/main.html",
  ],
  other: [
    "client/images/logo.svg",
    "client/images/logo16.png",
    "client/images/logo32.png",
    "client/images/logo128.png",
    "client/images/logo152.png",
    "client/images/logo180.png",
    "client/images/logo192.png",
    "client/images/favicon.ico",
    "client/images/sprites.png",
  ]
};

// On-demand loadable libs. Will be available as ?!/lib/[prop]
var libs = {
  "vjs.js": "node_modules/video.js/dist/video-js/video.js",
  "vjs.css": "node_modules/video.js/dist/video-js/video-js.min.css",
  "vjs.swf": "node_modules/video.js/dist/video-js/video-js.swf",
  "font/vjs.eot": "node_modules/video.js/dist/video-js/font/vjs.eot",
  "font/vjs.svg": "node_modules/video.js/dist/video-js/font/vjs.svg",
  "font/vjs.ttf": "node_modules/video.js/dist/video-js/font/vjs.ttf",
  "font/vjs.woff": "node_modules/video.js/dist/video-js/font/vjs.woff",
  "cm.js": [
    "node_modules/codemirror/lib/codemirror.js",
    "node_modules/codemirror/mode/meta.js",
    "node_modules/codemirror/addon/dialog/dialog.js",
    "node_modules/codemirror/addon/selection/active-line.js",
    "node_modules/codemirror/addon/selection/mark-selection.js",
    "node_modules/codemirror/addon/search/searchcursor.js",
    "node_modules/codemirror/addon/edit/matchbrackets.js",
    "node_modules/codemirror/addon/search/search.js",
    "node_modules/codemirror/keymap/sublime.js"
  ],
  "cm.css": "node_modules/codemirror/lib/codemirror.css"
};

resources.init = function init(doMinify, cacheVersion, cb) {
  minify = doMinify;
  if (!minify) return compile(cb);
  canUseCache(cacheVersion, function (can) {
    if (!can) return compile(cb);
    fs.readFile(paths.cache, function (err, data) {
      if (err) return cb(err);
      try {
        var cache = jb.parse(data);
        cb(null, cache);
      } catch (e) {
        compile(cb);
      }
    });
  });
};

function compile(cb) {
  async.series([compileAll, readThemes, readModes, readLibs], function (err, results) {
    if (err) return cb(err);
    var cache = {res: results[0], themes: {}, modes: {}, lib: {}};

    Object.keys(results[1]).forEach(function (theme) {
      cache.themes[theme] = {data: results[1][theme], etag: etag(), mime: mime("css")};
    });

    Object.keys(results[2]).forEach(function (mode) {
      cache.modes[mode] = {data: results[2][mode], etag: etag(), mime: mime("js")};
    });

    Object.keys(results[3]).forEach(function (file) {
      cache.lib[file] = {data: results[3][file], etag: etag(), mime: mime(path.basename(file))};
    });

    addGzip(cache, function (err, cache) {
      cache.etags = {};
      if (minify) fs.writeFile(paths.cache, jb.stringify(cache));
      cb(err, cache);
    });
  });
}

// Create gzip compressed data
function addGzip(cache, callback) {
  var types = Object.keys(cache), funcs = [];
  types.forEach(function (type) {
    funcs.push(function (cb) {
      gzipMap(cache[type], cb);
    });
  });
  async.parallel(funcs, function (err, results) {
    if (err) return callback(err);
    types.forEach(function (type, index) {
      cache[type] = results[index];
    });
    callback(null, cache);
  });
}

function gzipMap(map, callback) {
  var names = Object.keys(map), funcs = [];
  names.forEach(function (name) {
    funcs.push(function (cb) {
      gzip(map[name].data, cb);
    });
  });
  async.parallel(funcs, function (err, results) {
    if (err) return callback(err);
    names.forEach(function (name, index) {
      map[name].gzip = results[index];
    });
    callback(null, map);
  });
}

function gzip(data, callback) {
  zlib.gzip(data, function (err, gzipped) {
    if (err) return callback(err);
    callback(null, gzipped);
  });
}

function canUseCache(cacheVersion, cb) {
  if (cacheVersion !== pkg.version) return false;
  var lastChange, files = [];
  Object.keys(resources.files).forEach(function (type) {
    resources.files[type].forEach(function (file) {
      files.push(path.join(paths.mod, file));
    });
  });
  Object.keys(libs).forEach(function (file) {
    if (typeof libs[file] === "string") {
      files.push(path.join(paths.mod, libs[file]));
    } else {
      libs[file].forEach(function (file) {
        files.push(path.join(paths.mod, file));
      });
    }
  });
  async.map(files, function (file, cb) {
    fs.stat(file, function (err, stats) {
      cb(null, err ? 0 : stats.mtime.getTime());
    });
  }, function (err, times) {
    if (err) return cb(err);
    lastChange = Math.max.apply(Math, times);
    fs.stat(paths.cache, function (err, stats) {
      if (err) return cb(false);
      cb(stats.mtime.getTime() > lastChange);
    });
  });
}

function readThemes(callback) {
  var themes = {};
  fs.readdir(themesPath, function (err, filenames) {
    if (err) return callback(err);

    var files = filenames.map(function (name) {
      return path.join(themesPath, name);
    });

    async.map(files, fs.readFile, function (err, data) {
      if (err) return callback(err);

      filenames.forEach(function (name, index) {
        var css = String(data[index]);
        themes[name.replace(/\.css$/, "")] = new Buffer(minify ? cleanCSS.minify(css).styles : css);
      });

      // add our own theme
      fs.readFile(path.join(paths.mod, "/client/cmtheme.css"), function (err, css) {
        if (err) return callback(err);
        themes.droppy = new Buffer(minify ? cleanCSS.minify(css).styles : css);
        callback(null, themes);
      });
    });
  });
}

function readModes(callback) {
  var modes = {};

  // parse meta.js from CM for supported modes
  fs.readFile(path.join(paths.mod, "/node_modules/codemirror/mode/meta.js"), function (err, js) {
    if (err) return callback(err);

    // Extract modes from CodeMirror
    var sandbox = {CodeMirror : {}};
    vm.runInNewContext(js, sandbox);
    sandbox.CodeMirror.modeInfo.forEach(function (entry) {
      if (entry.mode !== "null") modes[entry.mode] = null;
    });

    async.map(Object.keys(modes), function (mode, cb) {
      fs.readFile(path.join(modesPath, mode, mode + ".js"), function (err, data) {
        cb(err, minify ? new Buffer(uglify.minify(data.toString(), opts.uglify).code) : data);
      });
    }, function (err, result) {
      Object.keys(modes).forEach(function (mode, i) {
        modes[mode] = result[i];
      });
      callback(err, modes);
    });
  });
}

function readLibs(callback) {
  var out = {};
  async.each(Object.keys(libs), function (dest, cb) {
    if (Array.isArray(libs[dest])) {
      async.map(libs[dest], function (p, innercb) {
        fs.readFile(path.join(paths.mod, p), innercb);
      }, function (err, data) {
        out[dest] = Buffer.concat(data);
        cb(err);
      });
    } else {
      fs.readFile(path.join(paths.mod, libs[dest]), function (err, data) {
        out[dest] = data;
        cb(err);
      });
    }
  }, function (err) {
    if (minify) {
      Object.keys(out).forEach(function (file) {
        if (/\.js$/.test(file)) {
          out[file] = new Buffer(uglify.minify(out[file].toString(), opts.uglify).code);
        } else if (/\.css$/.test(file)) {
          out[file] = new Buffer(cleanCSS.minify(out[file].toString()).styles);
        }
      });
    }
    callback(err, out);
  });
}

function readSVG() {
  fs.readdirSync(paths.svg).forEach(function (name) {
    var className = name.slice(0, name.length - ".svg".length);
    $ = cheerio.load(fs.readFileSync(path.join(paths.svg, name)).toString(), {xmlMode: true});
    $("svg").addClass(className);
    svgData[className] = $.html();
  });
}

function addSVG(html) {
  $ = cheerio.load(html);
  $("svg").each(function () {
    $(this).replaceWith(svgData[$(this).attr("class")]);
  });
  return $.html();
}

resources.compileJS = function compileJS() {
  var js = "";
  resources.files.js.forEach(function (file) {
    js += fs.readFileSync(path.join(paths.mod, file)).toString("utf8") + ";";
  });

  // Add SVG object
  js = js.replace("/* {{ svg }} */", "droppy.svg = " + JSON.stringify(svgData) + ";");

  // Add Handlebars precompiled templates
  var temps = fs.readdirSync(paths.templates).map(function (p) {
    return path.join(paths.templates, p);
  });
  js = js.replace("/* {{ templates }} */", templates.compile(temps));

  // Minify
  if (minify) js = uglify.minify(js, opts.uglify).code;

  return {data: new Buffer(js), etag: etag(), mime: mime("js")};
};

resources.compileCSS = function compileCSS() {
  var css = "";
  resources.files.css.forEach(function (file) {
    css += fs.readFileSync(path.join(paths.mod, file)).toString("utf8") + "\n";
  });

  // Vendor prefixes
  css = postcss([autoprefixer]).process(css).css;

  // Minify
  if (minify) css = cleanCSS.minify(css).styles;

  return {data: new Buffer(css), etag: etag(), mime: mime("css")};
};

resources.compileHTML = function compileHTML(res) {
  var html = {};
  var min = function min(html) {
    return minify ? htmlMinifier.minify(html, opts.htmlMinifier) : html;
  };

  resources.files.html.forEach(function (file) {
    var data = fs.readFileSync(path.join(paths.mod, file)).toString("utf8")
      .replace(/\{\{version\}\}/gm, pkg.version)
      .replace(/\{\{name\}\}/gm, pkg.name)
      .replace(/\{\{engine\}\}/gm, require("detect-engine") + " " + process.version.substring(1));
    html[path.basename(file)] = addSVG(data);
  });

  // Combine pages
  $ = cheerio.load(html["base.html"]);
  $("html").attr("data-type", "main");
  res["main.html"] = {
    data: new Buffer(min($("#page").replaceWith(html["main.html"]).end().html())),
    etag: etag(),
    mime: mime("html")
  };

  $ = cheerio.load(html["base.html"]);
  $("html").attr("data-type", "auth");
  res["auth.html"] = {
    data: new Buffer(min($("#page").replaceWith(html["auth.html"]).end().html())),
    etag: etag(),
    mime: mime("html")
  };

  $ = cheerio.load(html["base.html"]);
  $("html").attr("data-type", "firstrun");
  res["firstrun.html"] = {
    data: new Buffer(min($("#page").replaceWith(html["auth.html"]).end().html())),
    etag: etag(),
    mime: mime("html")
  };

  return res;
};

function compileAll(callback) {
  var res = {};

  readSVG();
  res["client.js"] = resources.compileJS();
  res["style.css"] = resources.compileCSS();
  res = resources.compileHTML(res);

  // Read misc files
  resources.files.other.forEach(function (file) {
    var data, date;
    var name = path.basename(file);
    var fullPath = path.join(paths.mod, file);

    try {
      data = fs.readFileSync(fullPath);
      date = fs.statSync(fullPath).mtime;
    } catch (err) {
      callback(err);
    }

    res[name] = {
      data: data,
      etag: crypto.createHash("md5").update(String(date)).digest("hex"),
      mime: mime(name)
    };
  });
  callback(null, res);
}

function etag() {
  return crypto.createHash("md5").update(String(Date.now())).digest("hex");
}

module.exports = resources;
<commit_msg>fix cache check<commit_after>/* eslint-disable space-before-keywords  */
"use strict";

var resources = {}, svgData = {}, minify, $;

var async        = require("async");
var autoprefixer = require("autoprefixer");
var cheerio      = require("cheerio");
var cleanCSS     = require("clean-css");
var crypto       = require("crypto");
var fs           = require("graceful-fs");
var htmlMinifier = require("html-minifier");
var jb           = require("json-buffer");
var mime         = require("mime-types").lookup;
var path         = require("path");
var postcss      = require("postcss");
var uglify       = require("uglify-js");
var vm           = require("vm");
var zlib         = require("zlib");

var templates    = require("./templates");
var pkg          = require("./../package.json");
var paths        = require("./paths.js").get();

var themesPath   = path.join(paths.mod, "/node_modules/codemirror/theme");
var modesPath    = path.join(paths.mod, "/node_modules/codemirror/mode");

var opts = {
  get uglify() {
    return {
      fromString: true,
      mangle: true,
      compress: {
        unsafe: true,
        screw_ie8: true,
        sequences: true,
        dead_code: true,
        conditionals: true,
        booleans: true,
        unused: true,
        if_return: true,
        join_vars: true,
      },
    };
  },
  get cleanCSS() {
    return {
      keepSpecialComments : 0,
      roundingPrecision: 3,
      rebase: false,
    };
  },
  get autoprefixer() {
    return {
      browsers: ["last 2 versions"],
      cascade: false,
    };
  },
  get htmlMinifier() {
    return {
      removeComments: true,
      collapseWhitespace: true,
      collapseBooleanAttributes: true,
      removeAttributeQuotes: true,
      removeOptionalTags: true,
      removeRedundantAttributes: true,
      caseSensitive: true,
      minifyCSS: cleanCSS,
    };
  }
};

cleanCSS = new cleanCSS(opts.cleanCSS);

resources.files = {
  css: [
    "client/style.css",
    "client/sprites.css",
    "client/tooltips.css",
  ],
  js: [
    "node_modules/handlebars/dist/handlebars.runtime.min.js",
    "node_modules/jquery/dist/jquery.js",
    "node_modules/draggabilly/dist/draggabilly.pkgd.min.js",
    "node_modules/mousetrap/mousetrap.min.js",
    "node_modules/file-extension/file-extension.js",
    "node_modules/uppie/uppie.js",
    "client/client.js",
  ],
  html: [
    "client/html/base.html",
    "client/html/auth.html",
    "client/html/main.html",
  ],
  other: [
    "client/images/logo.svg",
    "client/images/logo16.png",
    "client/images/logo32.png",
    "client/images/logo128.png",
    "client/images/logo152.png",
    "client/images/logo180.png",
    "client/images/logo192.png",
    "client/images/favicon.ico",
    "client/images/sprites.png",
  ]
};

// On-demand loadable libs. Will be available as ?!/lib/[prop]
var libs = {
  "vjs.js": "node_modules/video.js/dist/video-js/video.js",
  "vjs.css": "node_modules/video.js/dist/video-js/video-js.min.css",
  "vjs.swf": "node_modules/video.js/dist/video-js/video-js.swf",
  "font/vjs.eot": "node_modules/video.js/dist/video-js/font/vjs.eot",
  "font/vjs.svg": "node_modules/video.js/dist/video-js/font/vjs.svg",
  "font/vjs.ttf": "node_modules/video.js/dist/video-js/font/vjs.ttf",
  "font/vjs.woff": "node_modules/video.js/dist/video-js/font/vjs.woff",
  "cm.js": [
    "node_modules/codemirror/lib/codemirror.js",
    "node_modules/codemirror/mode/meta.js",
    "node_modules/codemirror/addon/dialog/dialog.js",
    "node_modules/codemirror/addon/selection/active-line.js",
    "node_modules/codemirror/addon/selection/mark-selection.js",
    "node_modules/codemirror/addon/search/searchcursor.js",
    "node_modules/codemirror/addon/edit/matchbrackets.js",
    "node_modules/codemirror/addon/search/search.js",
    "node_modules/codemirror/keymap/sublime.js"
  ],
  "cm.css": "node_modules/codemirror/lib/codemirror.css"
};

resources.init = function init(doMinify, cacheVersion, cb) {
  minify = doMinify;
  if (!minify) return compile(cb);
  canUseCache(cacheVersion, function (can) {
    if (!can) return compile(cb);
    fs.readFile(paths.cache, function (err, data) {
      if (err) return cb(err);
      try {
        var cache = jb.parse(data);
        cb(null, cache);
      } catch (e) {
        compile(cb);
      }
    });
  });
};

function compile(cb) {
  async.series([compileAll, readThemes, readModes, readLibs], function (err, results) {
    if (err) return cb(err);
    var cache = {res: results[0], themes: {}, modes: {}, lib: {}};

    Object.keys(results[1]).forEach(function (theme) {
      cache.themes[theme] = {data: results[1][theme], etag: etag(), mime: mime("css")};
    });

    Object.keys(results[2]).forEach(function (mode) {
      cache.modes[mode] = {data: results[2][mode], etag: etag(), mime: mime("js")};
    });

    Object.keys(results[3]).forEach(function (file) {
      cache.lib[file] = {data: results[3][file], etag: etag(), mime: mime(path.basename(file))};
    });

    addGzip(cache, function (err, cache) {
      cache.etags = {};
      if (minify) fs.writeFile(paths.cache, jb.stringify(cache));
      cb(err, cache);
    });
  });
}

// Create gzip compressed data
function addGzip(cache, callback) {
  var types = Object.keys(cache), funcs = [];
  types.forEach(function (type) {
    funcs.push(function (cb) {
      gzipMap(cache[type], cb);
    });
  });
  async.parallel(funcs, function (err, results) {
    if (err) return callback(err);
    types.forEach(function (type, index) {
      cache[type] = results[index];
    });
    callback(null, cache);
  });
}

function gzipMap(map, callback) {
  var names = Object.keys(map), funcs = [];
  names.forEach(function (name) {
    funcs.push(function (cb) {
      gzip(map[name].data, cb);
    });
  });
  async.parallel(funcs, function (err, results) {
    if (err) return callback(err);
    names.forEach(function (name, index) {
      map[name].gzip = results[index];
    });
    callback(null, map);
  });
}

function gzip(data, callback) {
  zlib.gzip(data, function (err, gzipped) {
    if (err) return callback(err);
    callback(null, gzipped);
  });
}

function canUseCache(cacheVersion, cb) {
  if (cacheVersion !== pkg.version) return cb(false);
  var lastChange, files = [];
  Object.keys(resources.files).forEach(function (type) {
    resources.files[type].forEach(function (file) {
      files.push(path.join(paths.mod, file));
    });
  });
  Object.keys(libs).forEach(function (file) {
    if (typeof libs[file] === "string") {
      files.push(path.join(paths.mod, libs[file]));
    } else {
      libs[file].forEach(function (file) {
        files.push(path.join(paths.mod, file));
      });
    }
  });
  async.map(files, function (file, cb) {
    fs.stat(file, function (err, stats) {
      cb(null, err ? 0 : stats.mtime.getTime());
    });
  }, function (err, times) {
    if (err) return cb(err);
    lastChange = Math.max.apply(Math, times);
    fs.stat(paths.cache, function (err, stats) {
      if (err) return cb(false);
      cb(stats.mtime.getTime() > lastChange);
    });
  });
}

function readThemes(callback) {
  var themes = {};
  fs.readdir(themesPath, function (err, filenames) {
    if (err) return callback(err);

    var files = filenames.map(function (name) {
      return path.join(themesPath, name);
    });

    async.map(files, fs.readFile, function (err, data) {
      if (err) return callback(err);

      filenames.forEach(function (name, index) {
        var css = String(data[index]);
        themes[name.replace(/\.css$/, "")] = new Buffer(minify ? cleanCSS.minify(css).styles : css);
      });

      // add our own theme
      fs.readFile(path.join(paths.mod, "/client/cmtheme.css"), function (err, css) {
        if (err) return callback(err);
        themes.droppy = new Buffer(minify ? cleanCSS.minify(css).styles : css);
        callback(null, themes);
      });
    });
  });
}

function readModes(callback) {
  var modes = {};

  // parse meta.js from CM for supported modes
  fs.readFile(path.join(paths.mod, "/node_modules/codemirror/mode/meta.js"), function (err, js) {
    if (err) return callback(err);

    // Extract modes from CodeMirror
    var sandbox = {CodeMirror : {}};
    vm.runInNewContext(js, sandbox);
    sandbox.CodeMirror.modeInfo.forEach(function (entry) {
      if (entry.mode !== "null") modes[entry.mode] = null;
    });

    async.map(Object.keys(modes), function (mode, cb) {
      fs.readFile(path.join(modesPath, mode, mode + ".js"), function (err, data) {
        cb(err, minify ? new Buffer(uglify.minify(data.toString(), opts.uglify).code) : data);
      });
    }, function (err, result) {
      Object.keys(modes).forEach(function (mode, i) {
        modes[mode] = result[i];
      });
      callback(err, modes);
    });
  });
}

function readLibs(callback) {
  var out = {};
  async.each(Object.keys(libs), function (dest, cb) {
    if (Array.isArray(libs[dest])) {
      async.map(libs[dest], function (p, innercb) {
        fs.readFile(path.join(paths.mod, p), innercb);
      }, function (err, data) {
        out[dest] = Buffer.concat(data);
        cb(err);
      });
    } else {
      fs.readFile(path.join(paths.mod, libs[dest]), function (err, data) {
        out[dest] = data;
        cb(err);
      });
    }
  }, function (err) {
    if (minify) {
      Object.keys(out).forEach(function (file) {
        if (/\.js$/.test(file)) {
          out[file] = new Buffer(uglify.minify(out[file].toString(), opts.uglify).code);
        } else if (/\.css$/.test(file)) {
          out[file] = new Buffer(cleanCSS.minify(out[file].toString()).styles);
        }
      });
    }
    callback(err, out);
  });
}

function readSVG() {
  fs.readdirSync(paths.svg).forEach(function (name) {
    var className = name.slice(0, name.length - ".svg".length);
    $ = cheerio.load(fs.readFileSync(path.join(paths.svg, name)).toString(), {xmlMode: true});
    $("svg").addClass(className);
    svgData[className] = $.html();
  });
}

function addSVG(html) {
  $ = cheerio.load(html);
  $("svg").each(function () {
    $(this).replaceWith(svgData[$(this).attr("class")]);
  });
  return $.html();
}

resources.compileJS = function compileJS() {
  var js = "";
  resources.files.js.forEach(function (file) {
    js += fs.readFileSync(path.join(paths.mod, file)).toString("utf8") + ";";
  });

  // Add SVG object
  js = js.replace("/* {{ svg }} */", "droppy.svg = " + JSON.stringify(svgData) + ";");

  // Add Handlebars precompiled templates
  var temps = fs.readdirSync(paths.templates).map(function (p) {
    return path.join(paths.templates, p);
  });
  js = js.replace("/* {{ templates }} */", templates.compile(temps));

  // Minify
  if (minify) js = uglify.minify(js, opts.uglify).code;

  return {data: new Buffer(js), etag: etag(), mime: mime("js")};
};

resources.compileCSS = function compileCSS() {
  var css = "";
  resources.files.css.forEach(function (file) {
    css += fs.readFileSync(path.join(paths.mod, file)).toString("utf8") + "\n";
  });

  // Vendor prefixes
  css = postcss([autoprefixer]).process(css).css;

  // Minify
  if (minify) css = cleanCSS.minify(css).styles;

  return {data: new Buffer(css), etag: etag(), mime: mime("css")};
};

resources.compileHTML = function compileHTML(res) {
  var html = {};
  var min = function min(html) {
    return minify ? htmlMinifier.minify(html, opts.htmlMinifier) : html;
  };

  resources.files.html.forEach(function (file) {
    var data = fs.readFileSync(path.join(paths.mod, file)).toString("utf8")
      .replace(/\{\{version\}\}/gm, pkg.version)
      .replace(/\{\{name\}\}/gm, pkg.name)
      .replace(/\{\{engine\}\}/gm, require("detect-engine") + " " + process.version.substring(1));
    html[path.basename(file)] = addSVG(data);
  });

  // Combine pages
  $ = cheerio.load(html["base.html"]);
  $("html").attr("data-type", "main");
  res["main.html"] = {
    data: new Buffer(min($("#page").replaceWith(html["main.html"]).end().html())),
    etag: etag(),
    mime: mime("html")
  };

  $ = cheerio.load(html["base.html"]);
  $("html").attr("data-type", "auth");
  res["auth.html"] = {
    data: new Buffer(min($("#page").replaceWith(html["auth.html"]).end().html())),
    etag: etag(),
    mime: mime("html")
  };

  $ = cheerio.load(html["base.html"]);
  $("html").attr("data-type", "firstrun");
  res["firstrun.html"] = {
    data: new Buffer(min($("#page").replaceWith(html["auth.html"]).end().html())),
    etag: etag(),
    mime: mime("html")
  };

  return res;
};

function compileAll(callback) {
  var res = {};

  readSVG();
  res["client.js"] = resources.compileJS();
  res["style.css"] = resources.compileCSS();
  res = resources.compileHTML(res);

  // Read misc files
  resources.files.other.forEach(function (file) {
    var data, date;
    var name = path.basename(file);
    var fullPath = path.join(paths.mod, file);

    try {
      data = fs.readFileSync(fullPath);
      date = fs.statSync(fullPath).mtime;
    } catch (err) {
      callback(err);
    }

    res[name] = {
      data: data,
      etag: crypto.createHash("md5").update(String(date)).digest("hex"),
      mime: mime(name)
    };
  });
  callback(null, res);
}

function etag() {
  return crypto.createHash("md5").update(String(Date.now())).digest("hex");
}

module.exports = resources;
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright (c) 2018 Google Inc. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */

'use strict';

defineParticle(({DomParticle, html, log}) => {
  const host = `social-edit-post`;

  const template = html`

    <icon on-click="onDeletePost">delete</icon>
    <firebase-upload active accept="image/*" on-upload="onAttachPhoto"><icon>attach_file</icon></firebase-upload>
    <icon primary active$="{{saveButtonActive}}" on-click="onSavePost">done</icon>

  <textarea value="{{message}}" on-input="onTextInput"></textarea>

  `.trim();

  return class extends DomParticle {
    get template() {
      return template;
    }
    willReceiveProps({post}, state) {
      state.message = post && post.message;
      state.image = post && post.image;
    }
    render({user, post}, {message, image, savePost}) {
      if (savePost) {
        this.savePost(user, message, image);
      }
      const saveButtonActive = Boolean(message && (message.trim().length > 0));
      const model = {saveButtonActive, message, image: image || ''};
      return model;
    }
    setHandle(name, data) {
      const handle = this._views.get(name);
      handle.set(new (handle.entityClass)(data));
    }
    savePost(user, message, image) {
      this.setHandle(
          'post',
          {message, image, createdTimestamp: Date.now(), author: user.id});
      this.setState({savePost: false});
    }
    onTextInput(e) {
      this.setIfDirty({message: e.data.value});
    }
    // TODO(wkorman): Add onDeletePost.
    onSavePost(e) {
      this.setIfDirty({savePost: true});
    }
    onAttachPhoto(e) {
      const image = e.data.value;
      this.setIfDirty({image});
    }
  };
});
<commit_msg>Preserve post editing state on props update.<commit_after>/**
 * @license
 * Copyright (c) 2018 Google Inc. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */

'use strict';

defineParticle(({DomParticle, html, log}) => {
  const host = `social-edit-post`;

  const template = html`

    <icon on-click="onDeletePost">delete</icon>
    <firebase-upload active accept="image/*" on-upload="onAttachPhoto"><icon>attach_file</icon></firebase-upload>
    <icon primary active$="{{saveButtonActive}}" on-click="onSavePost">done</icon>

  <textarea value="{{message}}" on-input="onTextInput"></textarea>

`;

  return class extends DomParticle {
    get template() {
      return template;
    }
    render({user, post}, {message, image, savePost}) {
      if (savePost) {
        this.savePost(user, message, image);
      }
      const saveButtonActive = Boolean(message && (message.trim().length > 0));
      const model = {saveButtonActive, message: message || '', image: image || ''};
      return model;
    }
    setHandle(name, data) {
      const handle = this._views.get(name);
      handle.set(new (handle.entityClass)(data));
    }
    savePost(user, message, image) {
      this.setHandle(
          'post',
          {message, image, createdTimestamp: Date.now(), author: user.id});
      this.setState({savePost: false, message: '', image: ''});
    }
    onTextInput(e) {
      this.setIfDirty({message: e.data.value});
    }
    // TODO(wkorman): Add onDeletePost.
    onSavePost(e) {
      this.setIfDirty({savePost: true});
    }
    onAttachPhoto(e) {
      const image = e.data.value;
      this.setIfDirty({image});
    }
  };
});
<|endoftext|>


<commit_before>var React = require('react');
var superagent = require('superagent');
var type = require('type');
var d = React.DOM;

var hyper = React.createClass({displayName: 'hyper',
  getInitialState: function() {
    return {
      status: 0,
      headers: {},
      body: {},
      time: 0
    };
  },

  componentDidMount: function() {
    var self = this;
    if (window.location.hash) this.handleAction(window.location.hash.replace('#', ''));
    window.onhashchange = function() {
      var url = window.location.hash.replace('#', '');
      if (self.state.url !== url) self.handleAction(url);
    };
  },

  handleAction: function(href, method, data) {
    var self = this;
    var start = new Date();
    method = (method || 'GET').toUpperCase();
    var req = superagent(method, href);

    if (data && method === 'GET') req.query(data);
    if (data && method !== 'GET') req.send(data);

    req.end(function(err, res) {
      if (err) return self.setState({err: err});

      self.setState({
        status: res.status,
        headers: res.headers,
        body: res.body,
        time: (new Date()) - start,
        url: href,
        data: data,
        err: null
      });
      window.location.hash = href;
    });
    return false;
  },

  render: function() {
    var s = this.state;
    var self = this;

    function createAction(action, method, params) {
      return self.handleAction.bind(self, action, method, params);
    }

    function changeUrl(e) {
      var val = e.target.value;
      self.setState({url: val});
    }

    function onSubmit() {
      self.handleAction(self.state.url);
      return false;
    }

    return d.div({'className': ''},
      d.form({className: 'url', onSubmit: onSubmit},
        d.input({name: 'url', type: 'url', placeholder: 'http://', onChange: changeUrl, value: this.state.url})),
      (s.err ? d.div({className: 'error'}, d.pre(null, s.err.message), d.pre(null, s.err.stack)) : null),
      d.div({'className': 'status'}, 'status: ', s.status),
      d.div({'className': 'time'}, 'response time: ', s.time, 'ms'),
      d.div({'className': 'headers'},
        d.ul(null, Object.keys(s.headers).map(function(key) {
          return d.li({key: key}, key, ': ', s.headers[key]);
        }))
      ),
      d.pre({'className': 'body'}, body(s.body, createAction, this.forceUpdate.bind(this)))
    );
  }
});

function body(content, transition, force) {
  var t = type(content);
  var className = 'level ' + t;
  if (t === 'string') return string(content, transition);
  if (t === 'number') return d.div({className: className}, '' + content);
  if (t === 'boolean') return d.div({className: className}, '' + content);
  if (t === 'array') return d.div({className: className},
    content.map(function(val, i) {
      return d.div({className: 'item', key: i}, body(val, transition));
    })
  );
  if (t !== 'object') return d.div({className: className}, content);

  if (content.action) return form(content, transition, force);

  if (content.src) return image(content, transition, force);

  return object(content, transition, force);
}

var links = /^http[s]?:\/\/|^\//;
function string(str, transition) {
  var content = links.test(str)
    ? d.a({href: str, onClick: transition(str)}, str)
    : str;
  return d.div({className: 'level string'}, content);
}

function form(content, transition, force) {
  var ic = 'item';
  var kc = 'level key';
  var inputs = content.input || {};

  function onSubmit(e) {
    var form = e.target;
    var values = {};
    Object.keys(inputs).forEach(function(key) {
      values[key] = inputs[key].value;
    });
    transition(content.action, content.method, values)();
    return false;
  }

  function onChange(key) {
    return function(e) {
      var val = e.target.value;
      inputs[key].value = val;
      force();
      return true;
    };
  }

  return d.form({className: 'object form level', onSubmit: onSubmit},
    d.div({className: ic, key: 'action'}, d.div({className: kc}, 'action'), string(content.action, transition)),
    d.div({className: ic, key: 'method'}, d.div({className: kc}, 'method'), string(content.method || 'GET',  transition)),
    d.div({className: ic, key: 'input'}, d.div({className: kc}, 'input'),
      d.div({className: 'object level'},
        Object.keys(inputs).map(function(key) {
          return d.div({className: ic},
            d.div({className: kc}, key),
            input(key, inputs[key], transition, onChange));
        })
      )
    ),
    d.div({className: ic, key: 'submit'},
      d.input({className: 'level', type: 'submit', value: 'submit'})
    )
  );
}

function input(key, c, transition, onChange) {
  var opts = c.options || [];
  // opts.unshift(null);

  c.required = c.required ? 'required' : undefined;
  c.type = c.type || 'text';

  var props = {
    className: 'level',
    name: key,
    value: c.value,
    onChange: onChange(key)
  };

  var inp = c.type === 'select'
    ? d.select(props,
       (c.options || []).map(function(option) {
         if (!option) return d.option({key: 'blank'}, '');
         return d.option({value: option.value, required: c.required, key: option.name}, option.name || option.value);
       }))
    : d.input(merge(props, c));

  return d.div({key: key, className: 'object level'},
    kvs(c, transition),
    d.div({className: 'item'}, inp)
  );
}

function object(content, transition, force) {
  return d.div({className: 'object level'}, kvs(content, transition, force));
}

function kvs(content, transition, force) {
  return Object.keys(content).map(function(key) {
    if (!content[key]) return;
    return d.div({className: 'item', key: key}, d.div({className: 'level key'}, key), body(content[key], transition, force));
  });
}

function image(content, transition, force) {
  return d.div({className: 'object level'},
    kvs(content, transition, force),
    d.div({className: 'item'},
    d.img({src: content.src, className: 'item level'})));
}

function merge(a, b) {
  if (b) {
    for (var k in b) {
      if (!a[k]) a[k] = b[k];
    }
  }
  return a;
}

React.renderComponent(
  hyper(),
  document.getElementById('main')
);
<commit_msg>be a little more graceful about errors<commit_after>var React = require('react');
var superagent = require('superagent');
var type = require('type');
var d = React.DOM;

var hyper = React.createClass({displayName: 'hyper',
  getInitialState: function() {
    return {
      status: 0,
      headers: {},
      body: {},
      time: 0
    };
  },

  componentDidMount: function() {
    var self = this;
    if (window.location.hash) this.handleAction(window.location.hash.replace('#', ''));
    window.onhashchange = function() {
      var url = window.location.hash.replace('#', '');
      if (self.state.url !== url) self.handleAction(url);
    };
  },

  handleAction: function(href, method, data) {
    var self = this;
    var start = new Date();
    method = (method || 'GET').toUpperCase();
    var req = superagent(method, href);

    req.set('cache-control', 'max-age=0');

    if (data && method === 'GET') req.query(data);
    if (data && method !== 'GET') req.send(data);

    req.end(function(err, res) {
      if (err) return self.setState({err: err});

      self.setState({
        status: res.status,
        headers: res.headers,
        body: res.body,
        text: res.text,
        time: (new Date()) - start,
        url: href,
        data: data,
        err: null
      });
      window.location.hash = href;
    });
    return false;
  },

  render: function() {
    var s = this.state;
    var self = this;

    function createAction(action, method, params) {
      return self.handleAction.bind(self, action, method, params);
    }

    function changeUrl(e) {
      var val = e.target.value;
      self.setState({url: val});
    }

    function onSubmit() {
      self.handleAction(self.state.url);
      return false;
    }

    var content;
    try {
      content = d.pre({'className': 'body'}, body(s.body, createAction, this.forceUpdate.bind(this)));
    } catch (err) {
      content = [error(err), d.pre({className: 'bodt'}, s.text)];
    };

    return d.div({'className': ''},
      d.form({className: 'url', onSubmit: onSubmit},
        d.input({name: 'url', type: 'url', placeholder: 'http://', onChange: changeUrl, value: this.state.url})),
      d.div({'className': 'status'}, 'status: ', s.status),
      d.div({'className': 'time'}, 'response time: ', s.time, 'ms'),
      d.div({'className': 'headers'},
        d.ul(null, Object.keys(s.headers).map(function(key) {
          return d.li({key: key}, key, ': ', s.headers[key]);
        }))
      ),
      content
    );
  }
});

function body(content, transition, force) {
  var t = type(content);
  var className = 'level ' + t;
  if (t === 'string') return string(content, transition);
  if (t === 'number') return d.div({className: className}, '' + content);
  if (t === 'boolean') return d.div({className: className}, '' + content);
  if (t === 'array') return d.div({className: className},
    content.map(function(val, i) {
      return d.div({className: 'item', key: i}, body(val, transition));
    })
  );
  if (t !== 'object') return d.div({className: className}, content);

  if (content.action) return form(content, transition, force);

  if (content.src) return image(content, transition, force);

  return object(content, transition, force);
}

var links = /^http[s]?:\/\/|^\//;
function string(str, transition) {
  var content = links.test(str)
    ? d.a({href: str, onClick: transition(str)}, str)
    : str;
  return d.div({className: 'level string'}, content);
}

function form(content, transition, force) {
  var ic = 'item';
  var kc = 'level key';
  var inputs = content.input || {};

  function onSubmit(e) {
    var form = e.target;
    var values = {};
    Object.keys(inputs).forEach(function(key) {
      values[key] = inputs[key].value;
    });
    transition(content.action, content.method, values)();
    return false;
  }

  function onChange(key) {
    return function(e) {
      var val = e.target.value;
      inputs[key].value = val;
      force();
      return true;
    };
  }

  return d.form({className: 'object form level', onSubmit: onSubmit},
    d.div({className: ic, key: 'action'}, d.div({className: kc}, 'action'), string(content.action, transition)),
    d.div({className: ic, key: 'method'}, d.div({className: kc}, 'method'), string(content.method || 'GET',  transition)),
    d.div({className: ic, key: 'input'}, d.div({className: kc}, 'input'),
      d.div({className: 'object level'},
        Object.keys(inputs).map(function(key) {
          return d.div({className: ic},
            d.div({className: kc}, key),
            input(key, inputs[key], transition, onChange));
        })
      )
    ),
    d.div({className: ic, key: 'submit'},
      d.input({className: 'level', type: 'submit', value: 'submit'})
    )
  );
}

function input(key, c, transition, onChange) {
  var opts = c.options || [];
  // opts.unshift(null);

  c.required = c.required ? 'required' : undefined;
  c.type = c.type || 'text';

  var props = {
    className: 'level',
    name: key,
    value: c.value,
    onChange: onChange(key)
  };

  var inp = c.type === 'select'
    ? d.select(props,
       (c.options || []).map(function(option) {
         if (!option) return d.option({key: 'blank'}, '');
         return d.option({value: option.value, required: c.required, key: option.name}, option.name || option.value);
       }))
    : d.input(merge(props, c));

  return d.div({key: key, className: 'object level'},
    kvs(c, transition),
    d.div({className: 'item'}, inp)
  );
}

function object(content, transition, force) {
  return d.div({className: 'object level'}, kvs(content, transition, force));
}

function kvs(content, transition, force) {
  return Object.keys(content).map(function(key) {
    if (!content[key]) return;
    return d.div({className: 'item', key: key}, d.div({className: 'level key'}, key), body(content[key], transition, force));
  });
}

function image(content, transition, force) {
  return d.div({className: 'object level'},
    kvs(content, transition, force),
    d.div({className: 'item'},
    d.img({src: content.src, className: 'item level'})));
}

function error(err) {
  return err
    ? d.div({className: 'error'}, d.pre(null, err.message), d.pre(null, err.stack))
    : null;
}

function merge(a, b) {
  if (b) {
    for (var k in b) {
      if (!a[k]) a[k] = b[k];
    }
  }
  return a;
}

React.renderComponent(
  hyper(),
  document.getElementById('main')
);
<|endoftext|>


<commit_before>var React                       = require('react-tools/build/modules/React'),
    contentEditableLineMetrics  = require('../content-editable-line-metrics'),
    textNodes                   = require('../content-editable-text-nodes'),
    Focusable                   = require('../focusable');

function generateAnnotationMarkup(annotation) {
  return '' +
    annotation.content +
    '';
}

module.exports = React.createClass({
  mixins: [Focusable],

  getContent: function() {
    return this.getDOMNode().textContent;
  },

  getAnnotations: function() {
    var nodes = textNodes(this.getDOMNode()),
        annotations = [];

    for (var i = 0, length = nodes.length; i < length; i++) {
      var node = nodes[i],
          annotationType = nodes[i].parentNode.dataset.annotationType;

      console.log(node, annotationType, node.__index);

      if (annotationType && node.__length > 0)
        annotations.push({
          type: annotationType,
          range: [node.__index, node.__index + node.__length]
        });
    }

    return annotations;
  },

  getCaretPosition: function() {
    return contentEditableLineMetrics(this.getDOMNode());
  },

  renderAnnotatedContent: function(content) {
    var text = this.props.content.trim(),
        annotations = this.props.annotations,
        nodes = [];

    // assume they are sorted by its range
    if (annotations && annotations.length > 0) {
      if (annotations[0].range[0] > 0) {
        nodes.push(text.substring(0, annotations[0].range[0]));
      }

      for (var i = 0, length = annotations.length; i < length; i++) {
        var annotation = annotations[i];
        nodes.push(generateAnnotationMarkup({
          type: annotation.type,
          content: text.substring.apply(text, annotation.range)
        }));
      }

      var last = annotations[annotations.length - 1].range;

      if (last[1] < text.length)
        nodes.push(text.substring(last[1], text.length));

    } else {
      nodes.push(text);
    }
    return nodes.join('');
  },

  render: function() {
    var content = this.renderAnnotatedContent();
    return this.transferPropsTo(
      React.DOM.div({
        contentEditable: "true",
        className: "Editable",
        dangerouslySetInnerHTML: {__html: content}
      }));
  }
});
<commit_msg>remove debug log<commit_after>var React                       = require('react-tools/build/modules/React'),
    contentEditableLineMetrics  = require('../content-editable-line-metrics'),
    textNodes                   = require('../content-editable-text-nodes'),
    Focusable                   = require('../focusable');

function generateAnnotationMarkup(annotation) {
  return '' +
    annotation.content +
    '';
}

module.exports = React.createClass({
  mixins: [Focusable],

  getContent: function() {
    return this.getDOMNode().textContent;
  },

  getAnnotations: function() {
    var nodes = textNodes(this.getDOMNode()),
        annotations = [];

    for (var i = 0, length = nodes.length; i < length; i++) {
      var node = nodes[i],
          annotationType = nodes[i].parentNode.dataset.annotationType;

      if (annotationType && node.__length > 0)
        annotations.push({
          type: annotationType,
          range: [node.__index, node.__index + node.__length]
        });
    }

    return annotations;
  },

  getCaretPosition: function() {
    return contentEditableLineMetrics(this.getDOMNode());
  },

  renderAnnotatedContent: function(content) {
    var text = this.props.content.trim(),
        annotations = this.props.annotations,
        nodes = [];

    // assume they are sorted by its range
    if (annotations && annotations.length > 0) {
      if (annotations[0].range[0] > 0) {
        nodes.push(text.substring(0, annotations[0].range[0]));
      }

      for (var i = 0, length = annotations.length; i < length; i++) {
        var annotation = annotations[i];
        nodes.push(generateAnnotationMarkup({
          type: annotation.type,
          content: text.substring.apply(text, annotation.range)
        }));
      }

      var last = annotations[annotations.length - 1].range;

      if (last[1] < text.length)
        nodes.push(text.substring(last[1], text.length));

    } else {
      nodes.push(text);
    }
    return nodes.join('');
  },

  render: function() {
    var content = this.renderAnnotatedContent();
    return this.transferPropsTo(
      React.DOM.div({
        contentEditable: "true",
        className: "Editable",
        dangerouslySetInnerHTML: {__html: content}
      }));
  }
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';

export default class Paddle extends Component {
  render() {
    return
Paddle
;
  }
}
<commit_msg>update paddle<commit_after>
export default class Paddle {
  constructor(args) {
    this.position = args.position;
  }
}
<|endoftext|>


<commit_before>function Feedback(canvas) {
    /* Init WebGL */
    var igloo = this.igloo = new Igloo(canvas);
    var gl = igloo.gl;
    gl.disable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.ONE, gl.ONE);
    gl.blendEquation(gl.FUNC_ADD);

    /* Defaults */
    this._scale = 0.98;
    this._rotate = 2.5;
    this._affine = null;
    this.setAffine();

    /* User poking */
    this.pointer = 0.1;
    this.colorspeed = 0.06;
    this.mousecolor = Feedback.randomColor();
    this.mouse = [0, 0];

    this.buffers = {
        quad: igloo.array(Igloo.QUAD2)
    };
    this.programs = {
        step:   igloo.program('glsl/quad.vert', 'glsl/feedback.frag'),
        circle: igloo.program('glsl/quad.vert', 'glsl/circle.frag'),
        square: igloo.program('glsl/quad.vert', 'glsl/square.frag')
    };
    this.textures = {
        state: igloo.texture().blank(canvas.width, canvas.height)
    };

    var _this = this;
    $(canvas).on('mousemove', function(event) {
        var $target = $(event.target),
            offset = $target.offset(),
            border = 1,
            x = event.pageX - offset.left - border,
            y = $target.height() - (event.pageY - offset.top - border);
        _this.mouse = [
            x / $target.width() * 2 - 1,
            y / $target.height() * 2 - 1
        ];
    });

    this.timer = null;
}

Feedback.IDENTITY3 = mat3.create();

Feedback.affine = function(tx, ty, sx, sy, a) {
    var m  = mat3.create();
    mat3.translate(m, m, [tx, ty]);
    mat3.rotate(m, m, a);
    mat3.scale(m, m, [sx, sy]);
    return m;
};

Feedback.randomColor = function() {
    var r = RNG.$;
    return [r.uniform(), r.uniform(), r.uniform(), r.uniform() * 0.5 + 0.5];
};

Feedback.perturb = function(color, rate) {
    for (var i = 0; i < 4; i++) {
        color[i] += RNG.$.normal() * rate;
        color[i] = Math.min(Math.max(color[i], 0), 1);
    }
    color[3] = Math.max(color[3], 0.5);
};

Feedback.prototype.setAffine = function() {
    var s = 1 / this._scale;
    this._affine = Feedback.affine(0, 0, s, s, this._rotate);
    return this;
};

Feedback.prototype.draw = function() {
    var gl = this.igloo.gl, w = gl.canvas.width, h = gl.canvas.height;
    this.textures.state.bind(0);
    this.programs.step.use()
        .attrib('quad', this.buffers.quad, 2)
        .uniformi('state', 0)
        .matrix('placement', Feedback.IDENTITY3)
        .matrix('transform', this._affine)
        .draw(gl.TRIANGLE_STRIP, Igloo.QUAD2.length / 2);
    this.fill('circle', this.mousecolor, this.mouse[0], this.mouse[1],
              this.pointer, this.pointer, 0);
    Feedback.perturb(this.mousecolor, this.colorspeed);
    if (RNG.$.random(5) === 0) this.disturb();
    this.textures.state.copy(0, 0, w, h);
    return this;
};

Feedback.prototype.disturb = function() {
    var type = RNG.$.uniform() < 0.5 ? 'square' : 'circle',
        color = Feedback.randomColor(),
        x = RNG.$.uniform() * 2 - 1,
        y = RNG.$.uniform() * 2 - 1,
        s = RNG.$.normal() * 0.16,
        a = RNG.$.uniform() * Math.PI * 2;
    color[3] *= 0.25;
    this.fill(type, color, x, y, s, s, a);
};

Feedback.prototype.fill = function(type, color, tx, ty, sx, sy, a) {
    var gl = this.igloo.gl;
    this.programs[type].use()
        .attrib('quad', this.buffers.quad, 2)
        .uniform('color', color)
        .matrix('placement', Feedback.affine(tx, ty, sx, sy, a))
        .matrix('transform', this._affine)
        .draw(gl.TRIANGLE_STRIP, Igloo.QUAD2.length / 2);
};

Feedback.prototype.start = function() {
    var _this = this;
    if (this.timer == null) {
        this.timer = window.setInterval(function() {
            _this.draw();
        }, 150);
    }
    return this;
};

Feedback.prototype.stop = function() {
    window.clearInterval(this.timer);
    this.timer = null;
    return this;
};

var feedback = null;
$(document).ready(function() {
    feedback = new Feedback($('#display')[0]);
    feedback.draw().start();
});
<commit_msg>Use requestAnimationFrame().<commit_after>function Feedback(canvas) {
    /* Init WebGL */
    var igloo = this.igloo = new Igloo(canvas);
    var gl = igloo.gl;
    gl.disable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.ONE, gl.ONE);
    gl.blendEquation(gl.FUNC_ADD);

    /* Defaults */
    this._scale = 0.98;
    this._rotate = 2.5;
    this._affine = null;
    this.setAffine();

    /* User poking */
    this.pointer = 0.1;
    this.colorspeed = 0.01;
    this.mousecolor = Feedback.randomColor();
    this.mouse = [0, 0];

    this.buffers = {
        quad: igloo.array(Igloo.QUAD2)
    };
    this.programs = {
        step:   igloo.program('glsl/quad.vert', 'glsl/feedback.frag'),
        circle: igloo.program('glsl/quad.vert', 'glsl/circle.frag'),
        square: igloo.program('glsl/quad.vert', 'glsl/square.frag')
    };
    this.textures = {
        state: igloo.texture().blank(canvas.width, canvas.height)
    };

    var _this = this;
    $(canvas).on('mousemove', function(event) {
        var $target = $(event.target),
            offset = $target.offset(),
            border = 1,
            x = event.pageX - offset.left - border,
            y = $target.height() - (event.pageY - offset.top - border);
        _this.mouse = [
            x / $target.width() * 2 - 1,
            y / $target.height() * 2 - 1
        ];
    });

    this.running = false;
    this.last = 0;
    this.delay = 0;
}

Feedback.IDENTITY3 = mat3.create();

Feedback.affine = function(tx, ty, sx, sy, a) {
    var m  = mat3.create();
    mat3.translate(m, m, [tx, ty]);
    mat3.rotate(m, m, a);
    mat3.scale(m, m, [sx, sy]);
    return m;
};

Feedback.randomColor = function() {
    var r = RNG.$;
    return [r.uniform(), r.uniform(), r.uniform(), r.uniform() * 0.5 + 0.5];
};

Feedback.perturb = function(color, rate) {
    for (var i = 0; i < 4; i++) {
        color[i] += RNG.$.normal() * rate;
        color[i] = Math.min(Math.max(color[i], 0), 1);
    }
    color[3] = Math.max(color[3], 0.5);
};

Feedback.prototype.setAffine = function() {
    var s = 1 / this._scale;
    this._affine = Feedback.affine(0, 0, s, s, this._rotate);
    return this;
};

Feedback.prototype.draw = function() {
    var gl = this.igloo.gl, w = gl.canvas.width, h = gl.canvas.height;
    this.textures.state.bind(0);
    this.programs.step.use()
        .attrib('quad', this.buffers.quad, 2)
        .uniformi('state', 0)
        .matrix('placement', Feedback.IDENTITY3)
        .matrix('transform', this._affine)
        .draw(gl.TRIANGLE_STRIP, Igloo.QUAD2.length / 2);
    this.fill('circle', this.mousecolor, this.mouse[0], this.mouse[1],
              this.pointer, this.pointer, 0);
    Feedback.perturb(this.mousecolor, this.colorspeed);
    if (RNG.$.random(5) === 0) this.disturb();
    this.textures.state.copy(0, 0, w, h);
    return this;
};

Feedback.prototype.disturb = function() {
    var type = RNG.$.uniform() < 0.5 ? 'square' : 'circle',
        color = Feedback.randomColor(),
        x = RNG.$.uniform() * 2 - 1,
        y = RNG.$.uniform() * 2 - 1,
        s = RNG.$.normal() * 0.16,
        a = RNG.$.uniform() * Math.PI * 2;
    color[3] *= 0.25;
    this.fill(type, color, x, y, s, s, a);
};

Feedback.prototype.fill = function(type, color, tx, ty, sx, sy, a) {
    var gl = this.igloo.gl;
    this.programs[type].use()
        .attrib('quad', this.buffers.quad, 2)
        .uniform('color', color)
        .matrix('placement', Feedback.affine(tx, ty, sx, sy, a))
        .matrix('transform', this._affine)
        .draw(gl.TRIANGLE_STRIP, Igloo.QUAD2.length / 2);
};

Feedback.prototype.frame = function() {
    var _this = this;
    window.requestAnimationFrame(function() {
        if (Date.now() - _this.last > _this.delay) {
            _this.draw();
            _this.last = Date.now();
        }
        if (_this.running) _this.frame();
    });
};

Feedback.prototype.start = function() {
    if (this.running == false) {
        this.running = true;
        this.frame();
    }
    return this;
};

Feedback.prototype.stop = function() {
    this.running = false;
    return this;
};

var feedback = null;
$(document).ready(function() {
    feedback = new Feedback($('#display')[0]);
    feedback.draw().start();
});
<|endoftext|>


<commit_before>// Copyright (C) 2013:
//    Owen Campbell-Moore <owencm@chromium.org>
//
// Use of this source code is governed by
//    http://www.apache.org/licenses/LICENSE-2.0
//
// This adds navigator.coinManager, the interface to the coins API. It also replaces
// the alert function with one tariffed by coins. Coins are awarded each visit and
// depreciate over time.
//
// I also added the function pretendLastVisitWasNDaysAgo so you can see the simulated
// effect of revisiting this page many days later.
//
// Note: this also adds localstorage.coinCountPrivate and localstorage.lastVisited
// which wouldn't be visible in a real implementation.

// TODO(owencm): Promisify me and tidy up, especially unclear logging
(function() {

	// The private API implementation, of which a subset will be exposed publically
	var CoinManagerPrivate = function(){
		// Every day we set coins to round(coins*coinDeprecationRate)
		var coinDepreciationRate = 0.9;
		// Set up localstorage, depreciate and award coins since last visit
		var init = function () {
			if (!localStorage.coinCountPrivate) {
				localStorage.coinCountPrivate = 0;
			}
			// If you've never visited before, set the visit as 1970
			if (!localStorage.lastVisited) {
				localStorage.lastVisited = 0;
			}
			var now = (new Date).getTime();
			var daysSinceLastVisit = Math.round((now - localStorage.lastVisited)/(1000*60*60*24));
			console.log(daysSinceLastVisit + ' days since you last visited.');
			console.log('You have ' + getCoinCount() + ' coins');

			// Depreciate the sites coins. If you've never visited before this has no effect.
			depreciateCoins(daysSinceLastVisit, coinDepreciationRate);

			// Award coins due to this visit
			grantCoins(calulateVisitCoins(daysSinceLastVisit), 'because you visited the site');
			// Set last visited time to now
			localStorage.lastVisited = (new Date).getTime();
		};
		// Depreciates coins proportionally to the amount of time since you last visited the site
		var depreciateCoins = function (numDays, depreciationRate) {
			// Do with a for loop so rounding is applied within each loop, not afterwards if you were to use a power
			var lastCoinCount;
			// TODO(owencm): Reqrite with a while loop to avoid the weird break
			for (var i = 0; i < numDays; i++) {
				var newCoinCount = Math.round(localStorage.coinCountPrivate*depreciationRate)
				// If it's not changing any more, break.
				if (newCoinCount == lastCoinCount) {
					break;
				} else {
					setCoinCount(newCoinCount);
				}
				lastCoinCount = newCoinCount;
			}
			console.log('Due to depreciation you now have ' + getCoinCount());
		}
		var calulateVisitCoins = function (numDays) {
			// The number of coins you receive is inversely proportional to when you last visited the site, but you only get them on the first visit in a day
			// If this is your first visit today you get coinz
			// TODO(owencm): change this to first visit in 12 hours
			var visitCoins = 0;
			if (numDays > 0) {
				// Add a Math.max to prevent this going negative if numDays > 31
				visitCoins = Math.max(0, Math.round(0.5+(30-numDays)/2));
			}
			return visitCoins;
		}
		var spendCoins = function (numCoins) {
			if (parseInt(localStorage.coinCountPrivate) < numCoins) {
				throw new Error('Not Enough Coins');
			}
			setCoinCount(getCoinCount() - numCoins);
			console.log('You spent ' + numCoins + ' coins and now have ' + getCoinCount());
		};
		var grantCoins = function (numCoins, reason) {
			localStorage.coinCountPrivate = parseInt(localStorage.coinCountPrivate) + numCoins;
			console.log('You gained ' + numCoins + ' coins and now have ' + getCoinCount() + ' ' + reason);
		}
		var setCoinCount = function (numCoins) {
			localStorage.coinCountPrivate = numCoins;
			console.log('Coin count set to ' + numCoins);
		}
		var getCoinCount = function () {
			return parseInt(localStorage.coinCountPrivate);
		};
		var getCoinDepreciationRate = function () {
			return coinDepreciationRate;
		};
		var requestExtraCoins = function () {
			if (confirm('This site wants to use more resources. Is that OK?')) {
				grantCoins(30, 'because you prompted for them.');
				console.log('You now have ' + getCoinCount() + ' coins due to your request');
				return true;
			} else {
				console.log('Your request for more coins was denied.');
				return false;
			}
		}
		init();
		return {getCoinCount: getCoinCount, getCoinDepreciationRate: getCoinDepreciationRate, spendCoins: spendCoins, grantCoins: grantCoins, requestExtraCoins: requestExtraCoins};
	};

	var coinManagerPrivate = CoinManagerPrivate();

	// Add the public API to the window
	navigator.coinManager = {getCoinCount: coinManagerPrivate.getCoinCount, getCoinDepreciationRate: coinManagerPrivate.getCoinDepreciationRate, requestExtraCoins: coinManagerPrivate.requestExtraCoins};

	// Replace the standard alert function with a tariffed function. You could do this for other functions here.
	var oldAlert = alert;
	alert = function () {
		// This will throw an error if you don't have enough coins.
		coinManagerPrivate.spendCoins(1);
		oldAlert.apply(this, arguments);
	};
})();

var pretendLastVisitWasNDaysAgo = function (numDays) {
	localStorage.lastVisited = (new Date).getTime() - numDays*24*60*60*1000;
	console.log('Your last visit date is set. Refresh to see the effect');
}
<commit_msg>Update a couple of comments<commit_after>// Copyright (C) 2013:
//    Owen Campbell-Moore <owencm@chromium.org>
//
// Use of this source code is governed by
//    http://www.apache.org/licenses/LICENSE-2.0
//
// This adds navigator.coinManager, the interface to the coins API. It also replaces
// the alert function with one tariffed by coins. Coins are awarded each visit and
// depreciate over time.
//
// I also added the function pretendLastVisitWasNDaysAgo so you can see the simulated
// effect of revisiting this page many days later.
//
// Note: this also adds localstorage.coinCountPrivate and localstorage.lastVisited
// which wouldn't be visible in a real implementation.

// TODO(owencm): Please tidy me up, fix messy logging, add SW support and a nicer way
// of specifying which APIs/methods now require coins.
(function() {

	// The private API implementation, of which a subset will be exposed publically
	var CoinManagerPrivate = function(){
		// Every day we set coins to round(coins*coinDeprecationRate)
		var coinDepreciationRate = 0.9;
		// Set up localstorage, depreciate and award coins since last visit
		var init = function () {
			if (!localStorage.coinCountPrivate) {
				localStorage.coinCountPrivate = 0;
			}
			// If you've never visited before, set the visit as 1970
			if (!localStorage.lastVisited) {
				localStorage.lastVisited = 0;
			}
			var now = (new Date).getTime();
			var daysSinceLastVisit = Math.round((now - localStorage.lastVisited)/(1000*60*60*24));
			console.log(daysSinceLastVisit + ' days since you last visited.');
			console.log('You have ' + getCoinCount() + ' coins');

			// Depreciate the sites coins. If you've never visited before this has no effect.
			depreciateCoins(daysSinceLastVisit, coinDepreciationRate);

			// Award coins due to this visit
			grantCoins(calulateVisitCoins(daysSinceLastVisit), 'because you visited the site');
			// Set last visited time to now
			localStorage.lastVisited = (new Date).getTime();
		};
		// Depreciates coins proportionally to the amount of time since you last visited the site
		var depreciateCoins = function (numDays, depreciationRate) {
			// Do with a for loop so rounding is applied within each loop, not afterwards if you were to use a power
			var lastCoinCount;
			// TODO(owencm): Reqrite with a while loop to avoid the weird break
			for (var i = 0; i < numDays; i++) {
				var newCoinCount = Math.round(localStorage.coinCountPrivate*depreciationRate)
				// If it's not changing any more, break.
				if (newCoinCount == lastCoinCount) {
					break;
				} else {
					setCoinCount(newCoinCount);
				}
				lastCoinCount = newCoinCount;
			}
			console.log('Due to depreciation you now have ' + getCoinCount());
		}
		var calulateVisitCoins = function (numDays) {
			// The number of coins you receive is inversely proportional to when you last visited the site, but you only get them on the first visit in a day
			// If this is your first visit today you get coinz
			// TODO(owencm): change this to first visit in 12 hours
			var visitCoins = 0;
			if (numDays > 0) {
				// Add a Math.max to prevent this going negative if numDays > 31
				visitCoins = Math.max(0, Math.round(0.5+(30-numDays)/2));
			}
			return visitCoins;
		}
		var spendCoins = function (numCoins) {
			if (parseInt(localStorage.coinCountPrivate) < numCoins) {
				throw new Error('Not Enough Coins');
			}
			setCoinCount(getCoinCount() - numCoins);
			console.log('You spent ' + numCoins + ' coins and now have ' + getCoinCount());
		};
		var grantCoins = function (numCoins, reason) {
			localStorage.coinCountPrivate = parseInt(localStorage.coinCountPrivate) + numCoins;
			console.log('You gained ' + numCoins + ' coins and now have ' + getCoinCount() + ' ' + reason);
		}
		var setCoinCount = function (numCoins) {
			localStorage.coinCountPrivate = numCoins;
			console.log('Coin count set to ' + numCoins);
		}
		var getCoinCount = function () {
			return parseInt(localStorage.coinCountPrivate);
		};
		var getCoinDepreciationRate = function () {
			return coinDepreciationRate;
		};
		var requestExtraCoins = function () {
			if (confirm('This site wants to use more resources. Is that OK?')) {
				grantCoins(30, 'because you prompted for them.');
				console.log('You now have ' + getCoinCount() + ' coins due to your request');
				return true;
			} else {
				console.log('Your request for more coins was denied.');
				return false;
			}
		}
		init();
		return {getCoinCount: getCoinCount, getCoinDepreciationRate: getCoinDepreciationRate, spendCoins: spendCoins, grantCoins: grantCoins, requestExtraCoins: requestExtraCoins};
	};

	var coinManagerPrivate = CoinManagerPrivate();

	// Add the public API to the window
	navigator.coinManager = {getCoinCount: coinManagerPrivate.getCoinCount, getCoinDepreciationRate: coinManagerPrivate.getCoinDepreciationRate, requestExtraCoins: coinManagerPrivate.requestExtraCoins};

	// Replace the standard alert function with a tariffed function. You could do this for other functions here.
	var oldAlert = alert;
	alert = function () {
		// This will throw an error if you don't have enough coins.
		coinManagerPrivate.spendCoins(1);
		oldAlert.apply(this, arguments);
	};
})();

// This is just a useful debug function to pretend you last visited the site a while ago and see the affect on coins.
var pretendLastVisitWasNDaysAgo = function (numDays) {
	localStorage.lastVisited = (new Date).getTime() - numDays*24*60*60*1000;
	console.log('Your last visit date is set. Refresh to see the effect');
}
<|endoftext|>


<commit_before>imagespace.views.SearchView = imagespace.View.extend({
    events: {
        'change .im-view-list': function (event) {
            localStorage.setItem('viewMode', 'list');
            this.viewMode = 'list';
            this.render();
        },

        'change .im-view-grid': function (event) {
            localStorage.setItem('viewMode', 'grid');
            this.viewMode = 'grid';
            this.render();
        }
    },

    initialize: function (settings) {
        girder.cancelRestRequests('fetch');
        this.$el = window.app.$('#g-app-body-container');
        this.collection = settings.collection;
        this.viewMode = localStorage.getItem('viewMode') || 'grid';
        this.collection.on('g:changed', _.bind(this.render, this));
        this.collection.fetch(settings.collection.params || {});
    },

    render: function () {
        this.$el.html(imagespace.templates.search({
            viewMode: this.viewMode,
            showText: true,
            collection: this.collection
        }));

        this.collection.each(function (image) {
            var imageView = new imagespace.views.ImageView({
                model: image,
                viewMode: this.viewMode,
                parentView: this
            });

            this.$('#im-search-results').append(imageView.render().el);
        }, this);

        return this;
    }

});

imagespace.router.route('search/:query', 'search', function (query) {
    imagespace.headerView.render({query: query});
    $('.alert-info').html('Searching ').removeClass('hidden');

    new imagespace.views.SearchView({
        collection: imagespace.getSearchResultCollectionFromQuery(query),
        parentView: window.app
    });
});

imagespace.router.route('search/:url/:mode', 'search', function (url, mode) {
    // Replace Girder token with current session's token if necessary
    var parts = url.split('&token=');
    if (parts.length === 2) {
        url = parts[0] + '&token=' + girder.cookie.find('girderToken');
    }

    var performSearch = function (image) {
        image.imageUrl = url;

        imagespace.headerView.render({
            url: url,
            mode: mode,
            image: (url.indexOf('girder') !== -1) ?
                new imagespace.models.UploadedImageModel(image) :
                new imagespace.models.SearchResultModel(image)
        });

        girder.events.trigger('g:navigateTo', imagespace.views.SearchView, {
            collection: imagespace.searches[mode].search(image)
        });

        $('.alert-info').addClass('hidden');
        imagespace.userDataView.render();
    };

    girder.restRequest({
        path: 'imagesearch',
        data: {
            query: 'id:"' + imagespace.urlToSolrId(url) + '"'
        }
    }).done(function (results) {
        var q;
        results = imagespace.processResponse(results);
        if (results.numFound === 0) {
            $('.alert-info').html('Computing features ').removeClass('hidden');
            girder.restRequest({
                path: 'imagefeatures',
                data: {
                    url: url
                },
                method: 'POST'
            }).done(function (features) {
                $('.alert-info').addClass('hidden');
                performSearch(features);
            });
        } else {
            performSearch(_.first(results.docs));
        }
    });
});
<commit_msg>Fix spinner<commit_after>imagespace.views.SearchView = imagespace.View.extend({
    events: {
        'change .im-view-list': function (event) {
            localStorage.setItem('viewMode', 'list');
            this.viewMode = 'list';
            this.render();
        },

        'change .im-view-grid': function (event) {
            localStorage.setItem('viewMode', 'grid');
            this.viewMode = 'grid';
            this.render();
        }
    },

    initialize: function (settings) {
        girder.cancelRestRequests('fetch');
        this.$el = window.app.$('#g-app-body-container');
        this.collection = settings.collection;
        this.viewMode = localStorage.getItem('viewMode') || 'grid';
        this.collection.on('g:changed', _.bind(this.render, this));
        this.collection.fetch(settings.collection.params || {});
    },

    render: function () {
        this.$el.html(imagespace.templates.search({
            viewMode: this.viewMode,
            showText: true,
            collection: this.collection
        }));

        this.collection.each(function (image) {
            var imageView = new imagespace.views.ImageView({
                model: image,
                viewMode: this.viewMode,
                parentView: this
            });

            this.$('#im-search-results').append(imageView.render().el);
        }, this);

        $('.alert-info').addClass('hidden');

        return this;
    }

});

imagespace.router.route('search/:query', 'search', function (query) {
    imagespace.headerView.render({query: query});
    $('.alert-info').html('Searching ').removeClass('hidden');

    new imagespace.views.SearchView({
        collection: imagespace.getSearchResultCollectionFromQuery(query),
        parentView: window.app
    });
});

imagespace.router.route('search/:url/:mode', 'search', function (url, mode) {
    // Replace Girder token with current session's token if necessary
    var parts = url.split('&token=');
    if (parts.length === 2) {
        url = parts[0] + '&token=' + girder.cookie.find('girderToken');
    }

    var performSearch = function (image) {
        image.imageUrl = url;

        imagespace.headerView.render({
            url: url,
            mode: mode,
            image: (url.indexOf('girder') !== -1) ?
                new imagespace.models.UploadedImageModel(image) :
                new imagespace.models.SearchResultModel(image)
        });

        girder.events.trigger('g:navigateTo', imagespace.views.SearchView, {
            collection: imagespace.searches[mode].search(image)
        });

        $('.alert-info').addClass('hidden');
        imagespace.userDataView.render();
    };

    girder.restRequest({
        path: 'imagesearch',
        data: {
            query: 'id:"' + imagespace.urlToSolrId(url) + '"'
        }
    }).done(function (results) {
        var q;
        results = imagespace.processResponse(results);
        if (results.numFound === 0) {
            $('.alert-info').html('Computing features ').removeClass('hidden');
            girder.restRequest({
                path: 'imagefeatures',
                data: {
                    url: url
                },
                method: 'POST'
            }).done(function (features) {
                $('.alert-info').addClass('hidden');
                performSearch(features);
            });
        } else {
            performSearch(_.first(results.docs));
        }
    });
});
<|endoftext|>


<commit_before>var pause = undefined;
var play = undefined;
var video = undefined;
var canvas = undefined;
var tapesound = undefined;
var staticsound = undefined;

function endstatic()
{
  document.body.style.backgroundImage = "none";
  document.body.style.backgroundColor = "black";

  staticsound.pause();
}

function videoloop()
{
    if (video && !video.paused && !video.ended) {
        context.drawImage(video, 0, 0, canvas.width, canvas.height);
        setTimeout(videoloop, 1000 / 30);
    }
}

function startvid()
{
  canvas.style.display = "inline";
  video.play();
}

function playoff()
{
  play.style.display = "none";
}

function startsound()
{
  tapesound.play();
}

function onplay(e)
{
  pause.style.display = "none";
  play.style.display = "inline";

  setTimeout(playoff, 7000);
  setTimeout(startvid, 5000);
  setTimeout(endstatic, 2000);
  setTimeout(startsound, 1000);
}

function reset()
{
  pause.style.display = "inline";
  play.style.display = "none";
  canvas.style.display = "none";

  video.currentTime = 0;
  video.pause();

  tapesound.currentTime = 0;
  tapesound.pause();

  staticsound.play();

  var string = "/img/tiled static.gif";
  document.body.style.backgroundImage = "url('" + string + "')";
  document.body.style.backgroundColor = "white";
}

window.onload = function()
{
  pause = document.getElementById("pause");
  play = document.getElementById("play");
  console.log("load successed");
  pause.onclick = onplay;

  tapesound = document.createElement("audio");
  tapesound.src = "/tapefeed.mp3";
  tapesound.pause();

  staticsound = document.createElement("audio");
  staticsound.src = "";
  staticsound.loop = true;
  staticsound.play();

  video = document.createElement("video");
  video.src = "/Testing video.mp4";
  video.pause();
  video.addEventListener('play',function(){
        videoloop();
    },false);
  video.addEventListener('ended',function(){
        reset();
    },false);

  canvas = document.getElementById("canvas");
  context = canvas.getContext("2d");

  canvas.width = canvas.clientWidth;
  canvas.height = canvas.clientHeight;

  context.clearRect(0, 0, canvas.width, canvas.height);
}

<commit_msg>Removing static sound for now, no sound<commit_after>var pause = undefined;
var play = undefined;
var video = undefined;
var canvas = undefined;
var tapesound = undefined;
// var staticsound = undefined;

function endstatic()
{
  document.body.style.backgroundImage = "none";
  document.body.style.backgroundColor = "black";

//  staticsound.pause();
}

function videoloop()
{
    if (video && !video.paused && !video.ended) {
        context.drawImage(video, 0, 0, canvas.width, canvas.height);
        setTimeout(videoloop, 1000 / 30);
    }
}

function startvid()
{
  canvas.style.display = "inline";
  video.play();
}

function playoff()
{
  play.style.display = "none";
}

function startsound()
{
  tapesound.play();
}

function onplay(e)
{
  pause.style.display = "none";
  play.style.display = "inline";

  setTimeout(playoff, 7000);
  setTimeout(startvid, 5000);
//  setTimeout(endstatic, 2000);
  setTimeout(startsound, 1000);
}

function reset()
{
  pause.style.display = "inline";
  play.style.display = "none";
  canvas.style.display = "none";

  video.currentTime = 0;
  video.pause();

  tapesound.currentTime = 0;
  tapesound.pause();

 // staticsound.play();

  var string = "/img/tiled static.gif";
  document.body.style.backgroundImage = "url('" + string + "')";
  document.body.style.backgroundColor = "white";
}

window.onload = function()
{
  pause = document.getElementById("pause");
  play = document.getElementById("play");
  console.log("load successed");
  pause.onclick = onplay;

  tapesound = document.createElement("audio");
  tapesound.src = "/tapefeed.mp3";
  tapesound.pause();

//  staticsound = document.createElement("audio");
//  staticsound.src = "";
//  staticsound.loop = true;
//  staticsound.play();

  video = document.createElement("video");
  video.src = "/Testing video.mp4";
  video.pause();
  video.addEventListener('play',function(){
        videoloop();
    },false);
  video.addEventListener('ended',function(){
        reset();
    },false);

  canvas = document.getElementById("canvas");
  context = canvas.getContext("2d");

  canvas.width = canvas.clientWidth;
  canvas.height = canvas.clientHeight;

  context.clearRect(0, 0, canvas.width, canvas.height);
}

<|endoftext|>


<commit_before>import moment from 'moment'
import chalk from 'chalk'
import format from '../time'
import pad from 'pad'
import { hashPattern } from '../entry'

export {write as write}
export {getOutputs as getOutputs}

function write(entry) {
  const {detailed} = getOutputs(entry)

  console.log(detailed)
}

function getOutputs(entry) {
  const timePattern = new RegExp(/\s*/.source + entry.time + /\s*/.source, 'g')
  const id = `${chalk.gray(pad(entry._id, 10))}`
  const date = `${chalk.yellow(pad(moment(entry.from).format('ddd MMM DD'),9))}`
  const timeFrom = moment(entry.from)
  const timeTo = moment(entry.to)
  const time = `${timeFrom.format('hh:mma')}-${timeTo.format('hh:mma')}`
  const duration = chalk.green(format(entry.duration.minutes))
  const msg = entry.message
    .replace(hashPattern, chalk.cyan('$1'))
    .replace(timePattern, '')
  const tags = chalk.cyan([...entry.tags].join(' '))

  const detailed = `${id} ${date} ${time} ${duration} ${msg}`
  const simple = `${id} ${time} ${duration} ${msg}`

  return {id, date, duration, msg, tags, detailed, simple}
}
<commit_msg>Fix time extraction taking away needed spaces<commit_after>import moment from 'moment'
import chalk from 'chalk'
import format from '../time'
import pad from 'pad'
import { hashPattern } from '../entry'

export {write as write}
export {getOutputs as getOutputs}

function write(entry) {
  const {detailed} = getOutputs(entry)

  console.log(detailed)
}

function getOutputs(entry) {
  const timePattern = new RegExp(/\s*/.source + entry.time + /\s*/.source, 'g')
  const id = `${chalk.gray(pad(entry._id, 10))}`
  const date = `${chalk.yellow(pad(moment(entry.from).format('ddd MMM DD'),9))}`
  const timeFrom = moment(entry.from)
  const timeTo = moment(entry.to)
  const time = `${timeFrom.format('hh:mma')}-${timeTo.format('hh:mma')}`
  const duration = chalk.green(format(entry.duration.minutes))
  const msg = entry.message
    .replace(hashPattern, chalk.cyan('$1'))
    .replace(timePattern, ' ')
    .trim()
  const tags = chalk.cyan([...entry.tags].join(' '))

  const detailed = `${id} ${date} ${time} ${duration} ${msg}`
  const simple = `${id} ${time} ${duration} ${msg}`

  return {id, date, duration, msg, tags, detailed, simple}
}
<|endoftext|>


<commit_before>function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}

function loadReusableComponents() {
  //insert elements, even before Polymer is loaded

  //load uq favicon to replace the exlibris logo
  loadUQFavicon();

  //show notification bar if user is not logged in
  loadSigninNotification();

  //first element of the original document
  var firstElement = document.body.children[0];

  // insert alerts after body-tag
  var alerts = document.querySelector('uqlibrary-alerts');
  if (!alerts) {
    //as a back up insert header if it's not defined already
    alerts = document.createElement('uqlibrary-alerts');
    document.body.insertBefore(alerts, firstElement);
  }

  // insert header after alerts
  var header = document.createElement('uq-minimal-header');
  document.body.insertBefore(header, firstElement);

  // insert sub footer before body-tag
  var subFooter = document.createElement('uql-connect-footer');
  document.body.appendChild(subFooter);

  // insert footer before body-tag
  var footer = document.createElement('uq-minimal-footer');
  document.body.appendChild(footer);

  window.addEventListener('WebComponentsReady', function() {
    // when polymer is ready - configure elements
    header.showLoginButton = false;
  });

}

function loadUQFavicon() {
  var link = document.createElement('link');
  link.type = 'image/x-icon';
  link.rel = 'shortcut icon';
  link.href = '//assets.library.uq.edu.au/reusable-components/resources/favicon.ico';
  document.getElementsByTagName('head')[0].appendChild(link);
  link.rel = 'icon'; //for IE
  document.getElementsByTagName('head')[0].appendChild(link);

}

function moveActions(){
  var actions = document.querySelectorAll('.EXLTabHeaderButtonSendTo');
  var results = document.querySelectorAll('.EXLResultTabs');

  for(var index = 0; index < actions.length; index++){
    results[index].appendChild(actions[index]);
  }

}

/* Call primo defined method isUserLoggedIn() to check users login status, show the notification if the user is not logged in */
function loadSigninNotification() {
  if (isUserLoggedIn())
    return;
  if( $('#signInPrompt').length > 0) /* prevents a double sign-in on some pages */
    return;
  if( $('body').hasClass('MyAccount') ) /* don't repeat sign-in prompt on E-Shelf page */
    return;

  /* get the login address from the signin link already generated by primo */
  var signInLink = $('#exlidSignIn a').attr('href');

  //put the notification bar in the feedback area which is sitting right after search bar
  var container = $('#exlidHeaderSystemFeedback');
  container.prepend('

Log in to access full text, more search results and more services
');
}

ready(loadReusableComponents);<commit_msg>primo results 'actions' manipulations<commit_after>function ready(fn) {
  if (document.readyState != 'loading') {
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}

function loadReusableComponents() {
  loadUQFavicon();

  //show notification bar if user is not logged in
  loadSigninNotification();

  moveActions();

  //first element of the original document
  var firstElement = document.body.children[0];

  // insert alerts after body-tag
  var alerts = document.querySelector('uqlibrary-alerts');
  if (!alerts) {
    //as a back up insert header if it's not defined already
    alerts = document.createElement('uqlibrary-alerts');
    document.body.insertBefore(alerts, firstElement);
  }

  // insert header after alerts
  var header = document.createElement('uq-minimal-header');
  document.body.insertBefore(header, firstElement);

  // insert sub footer before body-tag
  var subFooter = document.createElement('uql-connect-footer');
  document.body.appendChild(subFooter);

  // insert footer before body-tag
  var footer = document.createElement('uq-minimal-footer');
  document.body.appendChild(footer);

  window.addEventListener('WebComponentsReady', function () {
    // when polymer is ready - configure elements
    header.showLoginButton = false;
  });
}

function loadUQFavicon() {
  var link = document.createElement('link');
  link.type = 'image/x-icon';
  link.rel = 'shortcut icon';
  link.href = '//assets.library.uq.edu.au/reusable-components/resources/favicon.ico';
  document.getElementsByTagName('head')[0].appendChild(link);
  link.rel = 'icon'; //for IE
  document.getElementsByTagName('head')[0].appendChild(link);
}

function moveActions() {
  var actions = document.querySelectorAll('.EXLTabHeaderButtonSendTo');
  var results = document.querySelectorAll('.EXLResultTabs');

  for (var index = 0; index < actions.length; index++) {
    results[index].appendChild(actions[index]);
  }
}

/* Call primo defined method isUserLoggedIn() to check users login status, show the notification if the user is not logged in */
function loadSigninNotification() {
  if (isUserLoggedIn())
    return;
  if ($('#signInPrompt').length > 0) /* prevents a double sign-in on some pages */
    return;
  if ($('body').hasClass('MyAccount')) /* don't repeat sign-in prompt on E-Shelf page */
    return;

  /* get the login address from the signin link already generated by primo */
  var signInLink = $('#exlidSignIn a').attr('href');

  //put the notification bar in the feedback area which is sitting right after search bar
  var container = $('#exlidHeaderSystemFeedback');
  container.prepend('

Log in to access full text, more search results and more services
');
}

ready(loadReusableComponents);

/* MOVE THE ITEM ACTIONS OUT OF THE TABS
 -----------------------------------------------------------------
 The following code moves the Item Actions (Share/Save) menu out
 of Primo's tabs and places it with the result records for easy
 access. The actions are stored in a dropdown menu but other
 buttons can be added directly to the created toolbar.

 Last edited 2016.02.22 by Kate Deibel
 */

/* -------------------------------------- */
/* UNCOMMENT ONE OF THE TWO OPTIONS BELOW */
/* -------------------------------------- */

/* OPTION 1: Uncomment the code below if using the MutationSupport widget */
//AddMutation('tr.EXLResult td.EXLSummary', addItemActionsToResult, false); // Brief Results
//AddMutation('.EXLFullView .EXLResult .EXLTabHeaderButtonSendToList', addItemActionsToResult); // Full Display

/* OPTION 2: Uncomment the code below if NOT using MutationSupport */
jQuery(document).ready(function () {
  jQuery('tr.EXLResult td.EXLSummary').each(function (i, elem) {
    addItemActionsToResult(elem);
  });
  jQuery('.EXLFullView .EXLResult .EXLTabHeaderButtonSendToList').each(function (i, elem) {
    addItemActionsToResult(elem);
  });
});

/* Main generator function for moving the item actions (Share/Save) out
 of the tabs.
 */
function addItemActionsToResult(elem) {
  /* set parameters */
  var $result;
  if (isFullDisplay()) {
    $result = jqLocal('.EXLResult');
  }
  else {
    $result = jqLocal(elem).parent();
  }
  /* create the tool generator */
  var toolsGen = new PrimoItemTools($result);
  /* generate the toolbar */
  var toolbarObject = generateToolbar($result, toolsGen);
  $result.find('.EXLSummaryFields').prepend(toolbarObject.toolbar);
  toolbarObject.dropdown.FitDropDown();

  /* if on brief display, add a click event to the default e-shelf link to to toggle
   the new e-shelf buttons */
  if (!isFullDisplay()) {
    $result.find('td.EXLMyShelfStar a').on('click', {index: toolsGen.index}, function (event) {
      var $stars = jQuery('.eshelf-button-class-' + event.data.index);
      $stars.each(function (i, elem) {
        var $this = jQuery(elem);
        if ($this.hasClass('off_shelf')) {
          $this.attr('title', 'Remove record from e-Shelf');
        }
        else {
          $this.attr('title', 'Add record to e-Shelf');
        }
        $this.toggleClass('on_shelf off_shelf');
      });
      return false;
    });
  }
}

/* Helper function for moving the toolbar.
 NOTE:
 If you wish to have buttons outside of the dropdown menu, you can insert
 them here as indicated by the comments.
 */
function generateToolbar($result, toolsGen) {
  /********************************************************
   Configure the button text and hovertext for the dropdown menu
   ********************************************************/
  var buttonText = 'Share/Save';
  var buttonTitle = 'Show actions for this item';
  /********** END EDITABLE CODE **********/

  var index = toolsGen.index;
  /* ids */
  var containerID = 'localidItemToolsContainer-' + (index);
  var dropdownID = 'item-tools-dropdown-' + (index);

  /* create the toolbar */
  var toolbarContainer = jqLocal('
');
  toolbarContainer.attr('id', containerID);
  var toolbar = jqLocal('
');
  toolbarContainer.append(toolbar);

  /********************************************************
   Add a tool button to the toolbar (not in the dropdown)
   ********************************************************/
  //toolbar.append( generateInlineItemToolButton(toolsGen.eShelf(), index) );
  //toolbar.append( generateInlineItemToolButton(toolsGen.Permalink(), index) );
  //toolbar.append( generateInlineItemToolButton(toolsGen.Citation(), index) )
  /********** END EDITABLE CODE **********/

  /* create the dropdown */
  var dropdownMenu = jqLocal('
');

  /* Handle the z-index so that menus properly overlap each other */
  dropdownMenu.css('z-index', 150 - (index % 50));

  /* Load the tools into the dropdown */
  var dropdownWidget = generateItemToolDropdown(toolsGen, dropdownID, buttonText, buttonTitle);

  dropdownMenu.append(dropdownWidget.GetMenu());
  toolbar.append(dropdownMenu);

  /* ensure that the dropdown has proper width */
  dropdownWidget.FitDropDown();

  return {toolbar: toolbarContainer, dropdown: dropdownWidget};
}

/* Helper function for generating an inline item tool button (one not in the
 dropdown menu)
 */
function generateInlineItemToolButton(tool, index) {
  var toolDiv = jqLocal('
');
  /* adjust the id and name to reflect that this is a toolbar item */
  tool.attr('id', tool.attr('id') + '-toolbar');
  tool.attr('name', tool.attr('name') + '-toolbar');
  /* z-index maxes at 150 for tool items, so we subtract index % 50 to make
   proper overlapping */
  tool.css('z-index', (150 - (index % 50)));
  toolDiv.append(tool);
  return toolDiv;
}

/* Generate the item action dropdown menu (Share/Save).
 You control what appears and their ordering.
 */
function generateItemToolDropdown(toolsGen, id, text, title) {
  var dropdown = new PrimoDropDown(id);
  dropdown.ButtonTitle(title);
  dropdown.ButtonText('', text, 'Click/Enter to show actions');

  /********************************************************
   Add the tool buttons to the dropdown. You control the
   order and what appears.
   ********************************************************/
  dropdown.AddButtonItem(toolsGen.eShelf());
  dropdown.AddButtonItem(toolsGen.Email());
  dropdown.AddButtonItem(toolsGen.Print());
  dropdown.AddButtonItem(toolsGen.Permalink());
  dropdown.AddButtonItem(toolsGen.Citation());
  dropdown.AddButtonItem(toolsGen.EndNote());
  dropdown.AddButtonItem(toolsGen.RefWorks());
  dropdown.AddButtonItem(toolsGen.EasyBib());
  dropdown.AddButtonItem(toolsGen.ExportRIS());
  /********** END EDITABLE CODE **********/

  return dropdown;
}<|endoftext|>


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

  var can = require('can');

  return can.Component.extend({
    tag: 'edit-contact',
    template: can.view('edit-contact'),

    scope: {
      cancel: function(context) {
        context.contact.restore();
        window.history.back();
      },
      save: function(context) {
        var contact = context.contact;
        if (contact.isNew() || contact.isDirty()) {
          contact.save();
        }
        window.history.back();
      }
    },
    events: {
      '{can.route} contact_id': function(route, event, contact_id) {
        if (contact_id === undefined) {
          return;
        }
        var contact = null;
        if (contact_id === 'new') {
          contact = new Contact();
        }
        else {
          contact = Contact.store[contact_id];
          contact.backup();
        }
        this.scope.attr('contact', contact);
      }
    }
  });
});
<commit_msg>Avoiding referencing Contact model from the global namespace<commit_after>define(function(require) {
  'use strict';

  var can = require('can');

  var models = require('models');
  return can.Component.extend({
    tag: 'edit-contact',
    template: can.view('edit-contact'),

    scope: {
      cancel: function(context) {
        context.contact.restore();
        window.history.back();
      },
      save: function(context) {
        var contact = context.contact;
        if (contact.isNew() || contact.isDirty()) {
          contact.save();
        }
        window.history.back();
      }
    },
    events: {
      '{can.route} contact_id': function(route, event, contact_id) {
        if (contact_id === undefined) {
          return;
        }
        var contact = null;
        if (contact_id === 'new') {
          contact = new models.Contact();
        }
        else {
          contact = models.Contact.store[contact_id];
          contact.backup();
        }
        this.scope.attr('contact', contact);
      }
    }
  });
});
<|endoftext|>