<commit_before>/*global AppPort*/
/* jshint unused: false */
/**
 * Sidebar application.
 */
var SidebarApp = (function($, Backbone, _) {
  "use strict";

  /**
   * Application object
   * @type {Object}
   */
  var app = window.app = {
    // default options
    options: {},

    // app modules
    models: {},
    views: {},
    utils: {},

    start: function(options) {
      _.extend(this.options, options || {});
    }
  };

  // Add event support to the app
  _.extend(app, Backbone.Events);

  function SidebarApp(options) {
    options = options || {};

    this.port = new AppPort();

    this.user = new app.models.User();

    this.users = new app.models.UserSet();

    this.view = new app.views.AppView({
      user: this.user,
      users: this.users
    });

    navigator.id.watch({
      loggedInUser: null,
      onlogin: this._login.bind(this),
      onlogout: this._logout.bind(this)
    });

    // user events
    this.user.on("signout", this._onUserSignout.bind(this));

    // port events
    this.port.on('talkilla.users', this._onUserListReceived.bind(this));
    this.port.on("talkilla.login-success", this._onLoginSuccess.bind(this));
    this.port.on("talkilla.login-failure", this._onLoginFailure.bind(this));
    this.port.on("talkilla.logout-success", this._onLogoutSuccess.bind(this));
    this.port.on("talkilla.error", this._onError.bind(this));
    this.port.on("talkilla.websocket-error", this._onWebSocketError.bind(this));
    this.port.on("talkilla.presence-unavailable",
                 this._onPresenceUnavailable.bind(this));
    this.port.on("talkilla.chat-window-ready",
                 this._onChatWindowReady.bind(this));

    this.port.postEvent("talkilla.sidebar-ready");

    this._setupDebugLogging();
  }

  SidebarApp.prototype._login = function(assertion) {
    if (!this.user.isLoggedIn())
      this.port.postEvent('talkilla.login', {assertion: assertion});
  };

  SidebarApp.prototype._logout = function() {
    this.port.postEvent('talkilla.logout');
  };

  SidebarApp.prototype.openConversation = function(nick) {
    this.port.postEvent('talkilla.conversation-open', {
      user: this.user.get('nick'),
      peer: nick
    });
  };

  SidebarApp.prototype._onChatWindowReady = function() {
    this.port.postEvent('talkilla.user-nick', {nick: this.user.get('nick')});
  };

  SidebarApp.prototype._onLoginSuccess = function(data) {
    console.log("login success");
    $.cookie('nick', data.username, {expires: 10});
    this.user.set({nick: data.username, presence: "connected"});
    this.port.postEvent("talkilla.presence-request");
  };

  // XXX a lot of the steps that happen after various types of logouts and
  // failures are very very similar but not the same, and I suspect some
  // of this is intentional, and some of it is not.  One of the consequences
  // here is that the app itself can be left in a whole variety of mostly
  // similar but non-identical states.  My guess is that there should really
  // only be one or two states possible.  This needs some factoring out.
  // However, I suspect the factoring is going to be meaningfully effected by
  // our efforts to retry connections much of the time, so it probably makes
  // sense to do it as part of that card.

  SidebarApp.prototype._onLoginFailure = function(error) {
    app.utils.notifyUI('Failed to login while communicating with the server: ' +
      error, 'error');
    navigator.id.logout();
  };

  SidebarApp.prototype._onLogoutSuccess = function() {
    $.removeCookie('nick');
    this.user.clear();
    this.users.reset();
  };

  SidebarApp.prototype._onError = function(error) {
    app.utils.notifyUI('Error while communicating with the server: ' +
      error, 'error');
  };

  SidebarApp.prototype._onWebSocketError = function(error) {
    app.utils.notifyUI('Error while communicating with the WebSocket server: ' +
      error, 'error');
    this.user.clear();
  };

  SidebarApp.prototype._onPresenceUnavailable = function(code) {
    // 1000 is CLOSE_NORMAL, meaning that the app itself called close(),
    // (e.g. because the user clicked on logout), so there's no error
    // here.
    if (code !== 1000) {
      this.user.clear();
      app.utils.notifyUI('Sorry, the browser lost communication with ' +
                         'the server. CloseEvent code: ' + code);
    }
  };

  SidebarApp.prototype._onUserSignout = function() {
    // Reset all app data apart from the user model, as the views rely
    // on it for change notifications, and this saves re-initializing those
    // hooks.
    this.user.clear();
    this.users.reset();
  };

  SidebarApp.prototype._onUserListReceived = function(users) {
    this.users.reset(users);
  };

  SidebarApp.prototype._setupDebugLogging = function() {
    if (!app.options.DEBUG)
      return;

    // worker port events logging
    this.port.on('talkilla.debug', function(event) {
      console.log('worker event', event.label, event.data);
    });
  };

  return SidebarApp;
})(jQuery, Backbone, _);
<commit_msg>Remove console.log junk<commit_after>/*global AppPort*/
/* jshint unused: false */
/**
 * Sidebar application.
 */
var SidebarApp = (function($, Backbone, _) {
  "use strict";

  /**
   * Application object
   * @type {Object}
   */
  var app = window.app = {
    // default options
    options: {},

    // app modules
    models: {},
    views: {},
    utils: {},

    start: function(options) {
      _.extend(this.options, options || {});
    }
  };

  // Add event support to the app
  _.extend(app, Backbone.Events);

  function SidebarApp(options) {
    options = options || {};

    this.port = new AppPort();

    this.user = new app.models.User();

    this.users = new app.models.UserSet();

    this.view = new app.views.AppView({
      user: this.user,
      users: this.users
    });

    navigator.id.watch({
      loggedInUser: null,
      onlogin: this._login.bind(this),
      onlogout: this._logout.bind(this)
    });

    // user events
    this.user.on("signout", this._onUserSignout.bind(this));

    // port events
    this.port.on('talkilla.users', this._onUserListReceived.bind(this));
    this.port.on("talkilla.login-success", this._onLoginSuccess.bind(this));
    this.port.on("talkilla.login-failure", this._onLoginFailure.bind(this));
    this.port.on("talkilla.logout-success", this._onLogoutSuccess.bind(this));
    this.port.on("talkilla.error", this._onError.bind(this));
    this.port.on("talkilla.websocket-error", this._onWebSocketError.bind(this));
    this.port.on("talkilla.presence-unavailable",
                 this._onPresenceUnavailable.bind(this));
    this.port.on("talkilla.chat-window-ready",
                 this._onChatWindowReady.bind(this));

    this.port.postEvent("talkilla.sidebar-ready");

    this._setupDebugLogging();
  }

  SidebarApp.prototype._login = function(assertion) {
    if (!this.user.isLoggedIn())
      this.port.postEvent('talkilla.login', {assertion: assertion});
  };

  SidebarApp.prototype._logout = function() {
    this.port.postEvent('talkilla.logout');
  };

  SidebarApp.prototype.openConversation = function(nick) {
    this.port.postEvent('talkilla.conversation-open', {
      user: this.user.get('nick'),
      peer: nick
    });
  };

  SidebarApp.prototype._onChatWindowReady = function() {
    this.port.postEvent('talkilla.user-nick', {nick: this.user.get('nick')});
  };

  SidebarApp.prototype._onLoginSuccess = function(data) {
    $.cookie('nick', data.username, {expires: 10});
    this.user.set({nick: data.username, presence: "connected"});
    this.port.postEvent("talkilla.presence-request");
  };

  // XXX a lot of the steps that happen after various types of logouts and
  // failures are very very similar but not the same, and I suspect some
  // of this is intentional, and some of it is not.  One of the consequences
  // here is that the app itself can be left in a whole variety of mostly
  // similar but non-identical states.  My guess is that there should really
  // only be one or two states possible.  This needs some factoring out.
  // However, I suspect the factoring is going to be meaningfully effected by
  // our efforts to retry connections much of the time, so it probably makes
  // sense to do it as part of that card.

  SidebarApp.prototype._onLoginFailure = function(error) {
    app.utils.notifyUI('Failed to login while communicating with the server: ' +
      error, 'error');
    navigator.id.logout();
  };

  SidebarApp.prototype._onLogoutSuccess = function() {
    $.removeCookie('nick');
    this.user.clear();
    this.users.reset();
  };

  SidebarApp.prototype._onError = function(error) {
    app.utils.notifyUI('Error while communicating with the server: ' +
      error, 'error');
  };

  SidebarApp.prototype._onWebSocketError = function(error) {
    app.utils.notifyUI('Error while communicating with the WebSocket server: ' +
      error, 'error');
    this.user.clear();
  };

  SidebarApp.prototype._onPresenceUnavailable = function(code) {
    // 1000 is CLOSE_NORMAL, meaning that the app itself called close(),
    // (e.g. because the user clicked on logout), so there's no error
    // here.
    if (code !== 1000) {
      this.user.clear();
      app.utils.notifyUI('Sorry, the browser lost communication with ' +
                         'the server. CloseEvent code: ' + code);
    }
  };

  SidebarApp.prototype._onUserSignout = function() {
    // Reset all app data apart from the user model, as the views rely
    // on it for change notifications, and this saves re-initializing those
    // hooks.
    this.user.clear();
    this.users.reset();
  };

  SidebarApp.prototype._onUserListReceived = function(users) {
    this.users.reset(users);
  };

  SidebarApp.prototype._setupDebugLogging = function() {
    if (!app.options.DEBUG)
      return;

    // worker port events logging
    this.port.on('talkilla.debug', function(event) {
      console.log('worker event', event.label, event.data);
    });
  };

  return SidebarApp;
})(jQuery, Backbone, _);
<|endoftext|>


<commit_before>// RFC4648 url-safe base-64 encoding
var URL64Code =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
var selectionLink;
var article;

document.addEventListener("selectionchange", renderLinkedSelection);
window.addEventListener("resize", renderLinkedSelection);
window.addEventListener("hashchange", scrollToWindowLocation);
window.addEventListener("load", scrollToWindowLocation);

function onClickHash(event) {
  scrollToSelectionHash(new URL(event.target.href));
}

function scrollToWindowLocation() {
  scrollToSelectionHash(window.location);
}

// Given a URL with a selection hash, decode it, apply it, and scroll to it.
function scrollToSelectionHash(url) {
  var match = url.hash.match(/^#sel-([A-Za-z0-9-_]+)$/);
  if (!match) {
    return;
  }
    var selection = document.getSelection();
    var range = decodeRange(match[1]);
    var rect = range.getBoundingClientRect();
    var topOffset = Math.max(
      20,
      Math.floor((window.innerHeight - rect.height) * 0.4)
    );
    window.scrollTo(0, window.scrollY + rect.y - topOffset);
    selection.empty();
    selection.addRange(range);

}

// If there is currently a selection on the page, render a link encoding it.
function renderLinkedSelection() {
  var selection = document.getSelection();
  if (selection.isCollapsed) {
    if (selectionLink) {
      selectionLink.parentNode.removeChild(selectionLink);
      selectionLink = null;
    }
    return;
  }
  var range = selection.getRangeAt(0);
  var rect = range.getBoundingClientRect();
  var encoded = encodeRange(range);
  if (!article) {
    article = document.getElementsByTagName("article")[0];
  }
  if (!selectionLink) {
    selectionLink = document.createElement("a");
    selectionLink.className = "selection-link";
    selectionLink.innerText = "\u201F";
    document.body.appendChild(selectionLink);
  }
  var left = article.getBoundingClientRect().x;
  selectionLink.href = "#sel-" + encoded;
  selectionLink.onclick = onClickHash;
  selectionLink.style.left = Math.floor(left + window.scrollX - 37) + "px";
  selectionLink.style.top = Math.floor(rect.y + window.scrollY - 3) + "px";
}

// Encodes the range of a selection on the page as a string. The string is a
// URL-safe Base64 encoded hexad stream. While we could have used a byte stream,
// using hexads removes the need to convert Base64's hexads to bytes.
// A range is encoded as three lists of unsigned ints. The first list is the
// tree traversal path to the common ancestor node of the selection. The second
// is the tree traversal path from the common node to the start container,
// followed by the index into the text at that node, and the third is from the
// common node to the end container and the end text index.
function encodeRange(range) {
  var encoded = "";
  var startPath = encodeRangePoint(range.startContainer, range.startOffset);
  var endPath = encodeRangePoint(range.endContainer, range.endOffset);
  var commonPath = getCommonPath(startPath, endPath);
  writeList(commonPath);
  writeList(startPath.slice(commonPath.length));
  writeList(endPath.slice(commonPath.length));
  return encoded;

  // Unsigned ints are represented in a go-style varint encoding. Each hexad
  // holds 5 bits of value and a MSB indicating if there are subsequent hexads
  // representing this int.
  function writeInt(number) {
    do {
      encoded += URL64Code[(number & 0x1f) | (number > 0x1f ? 0x20 : 0)];
      number >>= 5;
    } while (number > 0);
  }

  // Lists are written as one int indicating the list's length, followed by each
  // element in that list.
  function writeList(list) {
    writeInt(list.length);
    for (var i = 0; i < list.length; i++) {
      writeInt(list[i]);
    }
  }
}

function decodeRange(encoded) {
  var URL64Decode = new Array(64);
  for (var i = 0; i < 64; i++) {
    URL64Decode[URL64Code.charCodeAt(i)] = i;
  }
  var offset = 0;
  var commonPath = readList();
  var startPoint = decodeRangePoint(commonPath.concat(readList()));
  var endPoint = decodeRangePoint(commonPath.concat(readList()));
  var range = document.createRange();
  range.setStart(startPoint[0], startPoint[1]);
  range.setEnd(endPoint[0], endPoint[1]);
  return range;

  function readInt() {
    var number = 0;
    var sign = 0;
    while (true) {
      var byte = URL64Decode[encoded.charCodeAt(offset++)];
      number |= (byte & 0x1f) << sign;
      sign += 5;
      if (byte < 0x20) {
        return number;
      }
    }
  }

  function readList() {
    var length = readInt();
    var list = new Array(length);
    for (var i = 0; i < length; i++) {
      list[i] = readInt();
    }
    return list;
  }
}

// A range point is a tuple of a node, and offset into that node. We encode it
// as a list of integers representing the tree traversal path from the document
// body, followed by the text offset.
function encodeRangePoint(node, offset) {
  var path = [offset];
  while (node != document.body) {
    var parentNode = node.parentNode;
    path.push(Array.prototype.indexOf.call(parentNode.childNodes, node));
    node = parentNode;
  }
  return path.reverse();
}

function decodeRangePoint(path) {
  var node = document.body;
  for (var i = 0; i < path.length - 1 && node; i++) {
    node = node.childNodes[path[i]];
  }
  return [node, path[path.length - 1]];
}

// Given two arrays of integers, returns the common prefix of the two.
function getCommonPath(p1, p2) {
  var i = 0;
  while (i < p1.length && i < p2.length && p1[i] === p2[i]) {
    i++;
  }
  return p1.slice(0, i);
}
<commit_msg>format<commit_after>// RFC4648 url-safe base-64 encoding
var URL64Code =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
var selectionLink;
var article;

document.addEventListener("selectionchange", renderLinkedSelection);
window.addEventListener("resize", renderLinkedSelection);
window.addEventListener("hashchange", scrollToWindowLocation);
window.addEventListener("load", scrollToWindowLocation);

function onClickHash(event) {
  scrollToSelectionHash(new URL(event.target.href));
}

function scrollToWindowLocation() {
  scrollToSelectionHash(window.location);
}

// Given a URL with a selection hash, decode it, apply it, and scroll to it.
function scrollToSelectionHash(url) {
  var match = url.hash.match(/^#sel-([A-Za-z0-9-_]+)$/);
  if (!match) {
    return;
  }
  var selection = document.getSelection();
  var range = decodeRange(match[1]);
  var rect = range.getBoundingClientRect();
  var topOffset = Math.max(
    20,
    Math.floor((window.innerHeight - rect.height) * 0.4)
  );
  window.scrollTo(0, window.scrollY + rect.y - topOffset);
  selection.empty();
  selection.addRange(range);
}

// If there is currently a selection on the page, render a link encoding it.
function renderLinkedSelection() {
  var selection = document.getSelection();
  if (selection.isCollapsed) {
    if (selectionLink) {
      selectionLink.parentNode.removeChild(selectionLink);
      selectionLink = null;
    }
    return;
  }
  var range = selection.getRangeAt(0);
  var rect = range.getBoundingClientRect();
  var encoded = encodeRange(range);
  if (!article) {
    article = document.getElementsByTagName("article")[0];
  }
  if (!selectionLink) {
    selectionLink = document.createElement("a");
    selectionLink.className = "selection-link";
    selectionLink.innerText = "\u201F";
    document.body.appendChild(selectionLink);
  }
  var left = article.getBoundingClientRect().x;
  selectionLink.href = "#sel-" + encoded;
  selectionLink.onclick = onClickHash;
  selectionLink.style.left = Math.floor(left + window.scrollX - 37) + "px";
  selectionLink.style.top = Math.floor(rect.y + window.scrollY - 3) + "px";
}

// Encodes the range of a selection on the page as a string. The string is a
// URL-safe Base64 encoded hexad stream. While we could have used a byte stream,
// using hexads removes the need to convert Base64's hexads to bytes.
// A range is encoded as three lists of unsigned ints. The first list is the
// tree traversal path to the common ancestor node of the selection. The second
// is the tree traversal path from the common node to the start container,
// followed by the index into the text at that node, and the third is from the
// common node to the end container and the end text index.
function encodeRange(range) {
  var encoded = "";
  var startPath = encodeRangePoint(range.startContainer, range.startOffset);
  var endPath = encodeRangePoint(range.endContainer, range.endOffset);
  var commonPath = getCommonPath(startPath, endPath);
  writeList(commonPath);
  writeList(startPath.slice(commonPath.length));
  writeList(endPath.slice(commonPath.length));
  return encoded;

  // Unsigned ints are represented in a go-style varint encoding. Each hexad
  // holds 5 bits of value and a MSB indicating if there are subsequent hexads
  // representing this int.
  function writeInt(number) {
    do {
      encoded += URL64Code[(number & 0x1f) | (number > 0x1f ? 0x20 : 0)];
      number >>= 5;
    } while (number > 0);
  }

  // Lists are written as one int indicating the list's length, followed by each
  // element in that list.
  function writeList(list) {
    writeInt(list.length);
    for (var i = 0; i < list.length; i++) {
      writeInt(list[i]);
    }
  }
}

function decodeRange(encoded) {
  var URL64Decode = new Array(64);
  for (var i = 0; i < 64; i++) {
    URL64Decode[URL64Code.charCodeAt(i)] = i;
  }
  var offset = 0;
  var commonPath = readList();
  var startPoint = decodeRangePoint(commonPath.concat(readList()));
  var endPoint = decodeRangePoint(commonPath.concat(readList()));
  var range = document.createRange();
  range.setStart(startPoint[0], startPoint[1]);
  range.setEnd(endPoint[0], endPoint[1]);
  return range;

  function readInt() {
    var number = 0;
    var sign = 0;
    while (true) {
      var byte = URL64Decode[encoded.charCodeAt(offset++)];
      number |= (byte & 0x1f) << sign;
      sign += 5;
      if (byte < 0x20) {
        return number;
      }
    }
  }

  function readList() {
    var length = readInt();
    var list = new Array(length);
    for (var i = 0; i < length; i++) {
      list[i] = readInt();
    }
    return list;
  }
}

// A range point is a tuple of a node, and offset into that node. We encode it
// as a list of integers representing the tree traversal path from the document
// body, followed by the text offset.
function encodeRangePoint(node, offset) {
  var path = [offset];
  while (node != document.body) {
    var parentNode = node.parentNode;
    path.push(Array.prototype.indexOf.call(parentNode.childNodes, node));
    node = parentNode;
  }
  return path.reverse();
}

function decodeRangePoint(path) {
  var node = document.body;
  for (var i = 0; i < path.length - 1 && node; i++) {
    node = node.childNodes[path[i]];
  }
  return [node, path[path.length - 1]];
}

// Given two arrays of integers, returns the common prefix of the two.
function getCommonPath(p1, p2) {
  var i = 0;
  while (i < p1.length && i < p2.length && p1[i] === p2[i]) {
    i++;
  }
  return p1.slice(0, i);
}
<|endoftext|>


<commit_before>function numberFormater(val, row) {
    if (val > 0) {
        return (val * 100).toFixed(2);
    }

    return 0;
}

function adDateFormatter(value) {
    var d = new Date(value);
    return d.format('yyyy-MM-dd');
}<commit_msg>change default format of datebox<commit_after>function numberFormater(val, row) {
    if (val > 0) {
        return (val * 100).toFixed(2);
    }

    return 0;
}

function adDateFormatter(value) {
    var d = new Date(value);
    return d.format('yyyy-MM-dd');
}

$.fn.datebox.defaults.formatter = function(date){
    var y = date.getFullYear();
    var m = date.getMonth()+1;
    var d = date.getDate();
    //return m+'/'+d+'/'+y;
    return y + '-' + m + '-' + d;
}

$.fn.datebox.defaults.parser = function(s){
    if (!s) return new Date();
    var ss = (s.split('-'));
    var y = parseInt(ss[0],10);
    var m = parseInt(ss[1],10);
    var d = parseInt(ss[2],10);
    if (!isNaN(y) && !isNaN(m) && !isNaN(d)){
        return new Date(y,m-1,d);
    } else {
        return new Date();
    }
}<|endoftext|>


<commit_before>define('require-config',[], function() {
  "use strict";

  console.log('require-config.');

  require.config({
    baseUrl: './static'
  });

  return {
    "paths": {
      "txt": "libs/require/plugins/text",
      "css": "libs/require/plugins/css",
      "jquery": "libs/jquery/jquery-2.1.0.min",
      "jquery.autosize": "libs/jquery/plugins/jquery.autosize.min",
      "bootstrap": "libs/bootstrap/bootstrap-3.1.1.min",
      "bootstrap.mods": "mods/bootstrap.mods",
      "bootbox": "libs/bootbox/bootbox.min",
      "underscore": "libs/underscore/underscore-1.6.0.min",
      "backbone": "libs/backbone/backbone-1.1.2.min",
      "sha256": "libs/movabletype/sha256",
      "aes": "libs/movabletype/aes",
      "add2home": "libs/add2home/add2home",
      "dropbox": "libs/dropbox/dropbox-0.10.2",
      "ace": "//cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace",
      "codemirror": "libs/codemirror/codemirror-4.8.0",
      "cm.placeholder": "libs/codemirror/placeholder"
    },
    "shim": {
      "jquery": ["globals/console"],
      "jquery.autosize": ["jquery"],
      "backbone": ["underscore", "jquery"],
      "bootstrap": ["jquery"],
      "bootstrap.mods": ["bootstrap"],
      "ace": ["jquery"],
      "codemirror": ["jquery"],
    }
  };
});
<commit_msg>Update require-config.js<commit_after>define('require-config',[], function() {
  "use strict";

  console.log('require-config.');

  require.config({
    baseUrl: './static'
  });

  return {
    "paths": {
      "txt": "libs/require/plugins/text",
      "css": "libs/require/plugins/css",
      "jquery": "libs/jquery/jquery-2.1.0.min",
      "jquery.autosize": "libs/jquery/plugins/jquery.autosize.min",
      "bootstrap": "libs/bootstrap/bootstrap-3.1.1.min",
      "bootstrap.mods": "mods/bootstrap.mods",
      "bootbox": "libs/bootbox/bootbox.min",
      "underscore": "libs/underscore/underscore-1.6.0.min",
      "backbone": "libs/backbone/backbone-1.1.2.min",
      "sha256": "libs/movabletype/sha256",
      "aes": "libs/movabletype/aes",
      "add2home": "libs/add2home/add2home",
      "dropbox": "libs/dropbox/dropbox-0.10.2",
      "ace": "//cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace",
      "codemirror": "libs/codemirror/codemirror-4.8.0",
      "cm.placeholder": "libs/codemirror/placeholder",
      "cm.vim": "libs/codemirror/vim"
    },
    "shim": {
      "jquery": ["globals/console"],
      "jquery.autosize": ["jquery"],
      "backbone": ["underscore", "jquery"],
      "bootstrap": ["jquery"],
      "bootstrap.mods": ["bootstrap"],
      "ace": ["jquery"],
      "codemirror": ["jquery"],
    }
  };
});
<|endoftext|>


<commit_before>/**
 * Created by testp1 on 25/04/16.
 */

(function() {
    tplbEditor = function () {
        return new tplbEditor.fn.init();
    };
    tplbEditor.fn = tplbEditor.prototype = {
        constructor:tplbEditor,
    };
    init = tplbEditor.fn.init = function() {
        return this;
    };
    tplbEditor.onClick = function (evt) {
        tplbEditor.pageX=evt.pageX;
        tplbEditor.pageY=evt.pageY;
    };
    tplbEditor.onKeyPress = function (evt) {
        /* this test that alt-arrow and ctrl-alt-arrow keys do not trigger significant firfox browser behavior so they can be used to trigger the most common authoring feauture :
           - alt-arrow keys : insert a new template (via a template choice context menu) :
             - down arrow : at the current position (offset) in the focusNode if one is defined (for exemple if caret is in the text of the element), otherwise at the beginning of the element
             - right arrow : after the focusNode if its an element or the focusNode parent if the focusNode is '#text'
             - up arrow : at the end of the focusNode parent or grand parent if the focusNode is '#text'
             - left arrow : before the focusNode if its an element or the focusNode parent if the focusNode is '#text'
           - ctrl-alt-arrow keys : select another element in the element structure (via a display of the selected element border and path in the element structure):
            - up arrow : the focusNode parent
            - left arrow : the element before the focusNode if its an element or before the focusNode parent if the focusNode is '#text'
            - right arrow : the element after the focusNode if its an element or the focusNode parent if the focusNode is '#text'
            - down arrow : the first focusNode child element if its an element or nothing if the focusNode is '#text'
           - other context menu (and associated keyboard shortcuts) will be defined to : select a range of brother element, delete or cut and pazst them...
          */
        /* some test alerts...
        alert('alt :' + evt.altKey);
        alert('key : ' + evt.key);
        alert('ctrl : ' + evt.ctrlKey);
        var theSel = document.getSelection();
        var theNode = theSel.focusNode;
        alert('node : ' + theNode.nodeName);
        */
        if (evt.defaultPrevented) {
                return; // Should do nothing if the key event was already consumed.
            }

            if (evt.altKey) {

                //var thePos = document.getSelection().
                //var x = this.getSelection().
                //var $this = $(this);
                //$this.contextMenu();
                //var evtCtx = $.Event("contextmenu", { data: evt.data, pageX: tplbEditor.pageX, pageY: tplbEditor.pageY });
                //$this.trigger(evtCtx);
                //jQuery(document.activeElement).triggerHandler('contextmenu',{pageX:tplbEditor.clientX,pageY:tplbEditor.clientY});
                //.contextMenu(this.getCursorPosition());
                    //.parent().parent().triggerHandler('contextmenu');
                    //.parent().parent().contextMenu(this.getCursorPosition());
                //parent().triggerHandler('contextmenu');

/*
// cf cette page https://developer.mozilla.org/fr/docs/Web/API/KeyboardEvent
*/
                //var codeOfCharE = 'e'.charCodeAt(0);
                switch (evt.key) {
                        case 'Down':
                            var $this = $(this);
                            $this.contextMenu();
                            //jQuery(getSelection().focusNode).contextMenu();
                            break;
                        default:
                            return; // Quit when this doesn't handle the key event.
                    }
                    //return; // Quit when this doesn't handle the key event.
            }

            // Consume the event for suppressing "double action".
            //evt.preventDefault();
            return;
//        alert('tplbEditor.onKeyPress');
 //       alert(evt.target.localName);
  //      alert(getSelection().focusNode.nodeName);
    };
    tplbEditor.addTemplate = function (templateId) {
        var currentNode;
        if (tplbEditor.selectedNode)
            currentNode = tplbEditor.selectedNode;
        /* does not work anymore with jquery contextMenu plugin
          else if (ctxMenuEvt) currentNode = $(evt.target);
           */
        else
            currentNode = document.getSelection().focusNode;
        if (currentNode.localName=='p'||(currentNode.parentNode && currentNode.parentNode.localName=='p')) {
            alert('a DIV template element cannot be inserted inside a Paragraph element. Please select a parent element with the "Select parent" context menu to select a parent element that can include a DIV.');
            return;
        }
        var template = document.querySelector('#' + templateId);
        var clone = template.content.cloneNode(true);
        //$('div',clone).attr('style','border-style:dotted');
        var theDiv=$('div',clone);
        theDiv.attr('contextmenu','template-editor-contextmenu');
        //theDiv.keypress(tplbEditor.onKeyPress);
        //theDiv.children().attr('onkeypress','alert("ici")');
        currentNode.append(clone);
        tplbEditor.removeSelection();
    };
    tplbEditor.selectParent = function () {
        /* does not work anymore with jquery contextMenu plugin
                    var evt = ctxMenuEvt;
                     */
            var par;
                if (tplbEditor.selectedNode) {
                    par = tplbEditor.selectedNode.parent();
                    tplbEditor.removeSelection();
                }
        /* does not work anymore with jquery contextMenu plugin
                        else  if (evt) par=$(evt.target).parent();
                         */
                else par=$(document.getSelection().focusNode).parent();
            par.css('border-style','dotted');
            tplbEditor.selectedNode=par;
        };
    tplbEditor.removeSelection = function () {
            if (tplbEditor.selectedNode) {
                tplbEditor.selectedNode.css('border-style','');
                tplbEditor.selectedNode=null;
            }
        };
    init.prototype = tplbEditor.fn;
    window.tplbEditor=tplbEditor;
    return tplbEditor;
}());

/* does not work anymore with jquery contextMenu plugin
addEventListener('contextmenu',function(evt){
    window.ctxMenuEvt=evt;
});
*/
jQuery( document ).ready(function() {
    try {
        jQuery('body').keyup(
            tplbEditor.onKeyPress
        ).click(
            tplbEditor.onClick
        );

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

                jQuery.contextMenu({
                    selector: 'body',
                    callback: function(key, options) {
                        var m = "clicked: " + key + "on a " + this.localName;
                        window.console && console.log(m) || alert(m);
                    },
/*                    position: function($menu,x,y){
                        var dbgx= x;
                        var dbgy=y;
                    },*/
                    determinePosition: function($menu){
                        $menu.offset({top : tplbEditor.pageY, left : tplbEditor.pageX});
                    },
                    items: {
                        /*"edit": {name: "Edit", icon: "edit"},
                        "cut": {name: "Cut", icon: "cut"},
                        copy: {name: "Copy", icon: "copy"},
                        "paste": {name: "Paste", icon: "paste"},
                        "delete": {name: "Delete", icon: "delete"},
                        "sep1": "---------",
                        "quit": {name: "Quit", icon: function(){
                            return 'context-menu-icon context-menu-icon-quit';
                        }},*/
                        InsertSubmenu: {
                                name: "Insert (Alt-DownArrow)",
                                items : {
                                    "insert-business-request":
                                    {
                                        name: "Business Request",
                                            icon: function () {
                                            return 'context-menu-icon context-menu-icon-quit';
                                        },
                                        callback: function(){
                                            tplbEditor.addTemplate('business-request');
                                            alert('Prototype level implemented : will insert a new business request template at the current position : a new editable business request template should appear in the document. You can also try the shortcut Alt-down that will display, in this proto, the global context menu at the mouse position and later only this sub menu.');
                                        }
                                    },
                                    "business-request-ref": {
                                        name: "Business Request Reference",
                                            icon: function(){
                                            return 'context-menu-icon context-menu-icon-quit';
                                        },
                                        callback: function(){
                                            alert ('Not Yet Implemented : will display a screen  to select an existing business request in the document database and create a reference to the selected business request at the current position, with a default behavior "inline" or "navigate". "Inline" reference will dynamically include the business request in place of the reference, "Navigate" will navigate from the reference to the request. These two behaviors can be toggled.');
                                        }
                                    },
                                    "symfony-controller": {
                                        name: "Symfony Controller",
                                            icon: function(){
                                            return 'context-menu-icon context-menu-icon-quit';
                                        },
                                        callback: function(){
                                            alert ('Not Yet Implemented : will display a screen  to select an existing Symfony Contoller in the (Git) source repository database and create a reference to the selected controller at the current position, with the same "inline" or "navigate" behaviors, as for document elements like business request elements. The goal is to organise a software platform documentation as a repository of document elements linked together, enabling breakthrough traceability between business/user requirements and their code implementation, with minimal documenting process cost for authors : just create the/ focus on value added document element without the charge of extra documenting management tasks. Further more , conversion of the document elements to markdown or other wiki formats will be available to ensure flexible integration in software platform management solutions like Github, Redmine, Trello...');
                                        }
                                    }

                                }
                        },
                        InsertAfterSubmenu: {
                            name: "Insert after (Alt-RightArrow)",
                            items : {
                                "insert-after-business-request":
                                {
                                    name: "Business Request",
                                    icon: function () {
                                        return 'context-menu-icon context-menu-icon-quit';
                                    },
                                    callback: function(){
                                        alert('No yet implemented : will do the same as the Insert menu but after the current element of the document structure. Sub menus to insert before the current element (left) or in the current element parent (up) will be added too, together with menus to navigate and select elements in the whole document structure (Ctrl-Alt-Up, left, right...), so that combined with the insertion menus, one can quickly edit a whole document structure without the "lost in the structure" effect.');
                                    }
                                }
                            }
                        },
                        "select-parent":
                        {
                            name: "Select parent (Ctrl-Alt-UpArrow)",
                            icon: function () {
                                return 'context-menu-icon context-menu-icon-quit';
                            },
                            callback: function(){
                                tplbEditor.selectParent();
                                alert('Prototype level implemented : select the parent of the current element to enable insertion in it or other element selection in it . The parent element box borders are now visible (dotted lines).');
                            }
                        }

                    }
                });
            ////////////////////////
        } catch (e) {
            alert ('error');
        }
    });
<commit_msg>- test of assetic : commented as it doesn't work : details in french :   - Assetic est bugué pour le moment : après 1 journée de tentatives diverses, les fichier "ouput" des blocs twig "javascipts" et "stylesheet" tel que décrit dans les best practices ne sont pas dumper tel que décrit dans ces best practices, malgrè les nettoyage de cache et autre disable/enable du controller assetic tel que préconnisé dans les post sur google, bcp de post de signalement de ce bug sans réponse de solution qui a marché....  - Code doc editor (nickname "codoc") :    - very early prototyping of an editing context menu that can be triggered by a specific keyboard event ("Ctrl <anychar>" in this proto version...). The context menu is displayed where the mouse is to minimise mouse use. The menu items can be be navigated with keyboard arrows and enter to trigger the item action, sothat this menu can be totaly used either by the mouse or by the mouse or the keyboard, enabling fast "au fil de l'eau" authoring of the document content and structure whithout mouse interruption (this encourage to write more doc for the same time, which is a real issue for software documenting ;).     - the jquery plugin contextMenu plugin (https://swisnl.github.io/jQuery-contextMenu) has been integrated for that.   - Symfony demo fix : the cache of classe in app_dev.php has been commented, as it was not consistent with the code examples to disable class caching given in the best practices documentation.<commit_after>/**
 * Created by testp1 on 25/04/16.
 */

(function() {
    tplbEditor = function () {
        return new tplbEditor.fn.init();
    };
    tplbEditor.fn = tplbEditor.prototype = {
        constructor:tplbEditor,
    };
    init = tplbEditor.fn.init = function() {
        return this;
    };
    tplbEditor.onClick = function (evt) {
        //this check if it is a click on a context menu item (or a descendant element of the item like a span...), and if yes does nothing as the focusNode does not change in this case.
        var isMenuItem=$(evt.target).closest('.context-menu-item').length;
        if (!isMenuItem) {
        tplbEditor.pageX = evt.pageX;
        tplbEditor.pageY = evt.pageY;
        tplbEditor.removeSelection();
        tplbEditor.selectedNode = $(document.getSelection().focusNode);
        }
    };
    tplbEditor.onKeyPress = function (evt) {
        /* this test that alt-arrow and ctrl-alt-arrow keys do not trigger significant firfox browser behavior so they can be used to trigger the most common authoring feauture :
           - alt-arrow keys : insert a new template (via a template choice context menu) :
             - down arrow : at the current position (offset) in the focusNode if one is defined (for exemple if caret is in the text of the element), otherwise at the beginning of the element
             - right arrow : after the focusNode if its an element or the focusNode parent if the focusNode is '#text'
             - up arrow : at the end of the focusNode parent or grand parent if the focusNode is '#text'
             - left arrow : before the focusNode if its an element or the focusNode parent if the focusNode is '#text'
           - ctrl-alt-arrow keys : select another element in the element structure (via a display of the selected element border and path in the element structure):
            - up arrow : the focusNode parent
            - left arrow : the element before the focusNode if its an element or before the focusNode parent if the focusNode is '#text'
            - right arrow : the element after the focusNode if its an element or the focusNode parent if the focusNode is '#text'
            - down arrow : the first focusNode child element if its an element or nothing if the focusNode is '#text'
           - other context menu (and associated keyboard shortcuts) will be defined to : select a range of brother element, delete or cut and pazst them...
          */
        /* some test alerts...
        alert('alt :' + evt.altKey);
        alert('key : ' + evt.key);
        alert('ctrl : ' + evt.ctrlKey);
        var theSel = document.getSelection();
        var theNode = theSel.focusNode;
        alert('node : ' + theNode.nodeName);
        */
        if (evt.defaultPrevented) {
                return; // Should do nothing if the key event was already consumed.
            }

            if (evt.altKey) {

                //var thePos = document.getSelection().
                //var x = this.getSelection().
                //var $this = $(this);
                //$this.contextMenu();
                //var evtCtx = $.Event("contextmenu", { data: evt.data, pageX: tplbEditor.pageX, pageY: tplbEditor.pageY });
                //$this.trigger(evtCtx);
                //jQuery(document.activeElement).triggerHandler('contextmenu',{pageX:tplbEditor.clientX,pageY:tplbEditor.clientY});
                //.contextMenu(this.getCursorPosition());
                    //.parent().parent().triggerHandler('contextmenu');
                    //.parent().parent().contextMenu(this.getCursorPosition());
                //parent().triggerHandler('contextmenu');

/*
// cf cette page https://developer.mozilla.org/fr/docs/Web/API/KeyboardEvent
*/
                //var codeOfCharE = 'e'.charCodeAt(0);
                switch (evt.key) {
                        case 'Down':
                            var $this = $(this);
                            $this.contextMenu();
                            //jQuery(getSelection().focusNode).contextMenu();
                            break;
                        default:
                            return; // Quit when this doesn't handle the key event.
                    }
                    //return; // Quit when this doesn't handle the key event.
            }

            // Consume the event for suppressing "double action".
            //evt.preventDefault();
            return;
//        alert('tplbEditor.onKeyPress');
 //       alert(evt.target.localName);
  //      alert(getSelection().focusNode.nodeName);
    };
    tplbEditor.addTemplate = function (templateId) {
        var currentNode;
        if (tplbEditor.selectedNode)
            currentNode = tplbEditor.selectedNode;
        /* does not work anymore with jquery contextMenu plugin
          else if (ctxMenuEvt) currentNode = $(evt.target);
           */
        else
            currentNode = document.getSelection().focusNode;
        if (currentNode.localName=='p'||(currentNode.parentNode && currentNode.parentNode.localName=='p')) {
            alert('a DIV template element cannot be inserted inside a Paragraph element. Please select a parent element with the "Select parent" context menu to select a parent element that can include a DIV.');
            return;
        }
        var template = document.querySelector('#' + templateId);
        var clone = template.content.cloneNode(true);
        //$('div',clone).attr('style','border-style:dotted');
        var theDiv=$('div',clone);
        theDiv.attr('contextmenu','template-editor-contextmenu');
        //theDiv.keypress(tplbEditor.onKeyPress);
        //theDiv.children().attr('onkeypress','alert("ici")');
        currentNode.append(clone);
        tplbEditor.removeSelection();
    };
    tplbEditor.selectParent = function () {
        /* does not work anymore with jquery contextMenu plugin
                    var evt = ctxMenuEvt;
                     */
            var par;
                if (tplbEditor.selectedNode) {
                    par = tplbEditor.selectedNode.parent();
                    tplbEditor.removeSelection();
                }
        /* does not work anymore with jquery contextMenu plugin
                        else  if (evt) par=$(evt.target).parent();
                         */
                else par=$(document.getSelection().focusNode).parent();
            par.css('border-style','dotted');
            tplbEditor.selectedNode=par;
        };
    tplbEditor.removeSelection = function () {
            if (tplbEditor.selectedNode) {
                tplbEditor.selectedNode.css('border-style','');
                tplbEditor.selectedNode=null;
            }
        };
    init.prototype = tplbEditor.fn;
    window.tplbEditor=tplbEditor;
    return tplbEditor;
}());

/* does not work anymore with jquery contextMenu plugin
addEventListener('contextmenu',function(evt){
    window.ctxMenuEvt=evt;
});
*/
jQuery( document ).ready(function() {
    try {
        jQuery('body').keyup(
            tplbEditor.onKeyPress
        ).click(
            tplbEditor.onClick
        );

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

                jQuery.contextMenu({
                    selector: 'body',
                    callback: function(key, options) {
                        var m = "clicked: " + key + "on a " + this.localName;
                        window.console && console.log(m) || alert(m);
                    },
/*                    position: function($menu,x,y){
                        var dbgx= x;
                        var dbgy=y;
                    },*/
                    determinePosition: function($menu){
                        $menu.offset({top : tplbEditor.pageY, left : tplbEditor.pageX});
                    },
                    items: {
                        /*"edit": {name: "Edit", icon: "edit"},
                        "cut": {name: "Cut", icon: "cut"},
                        copy: {name: "Copy", icon: "copy"},
                        "paste": {name: "Paste", icon: "paste"},
                        "delete": {name: "Delete", icon: "delete"},
                        "sep1": "---------",
                        "quit": {name: "Quit", icon: function(){
                            return 'context-menu-icon context-menu-icon-quit';
                        }},*/
                        InsertSubmenu: {
                                name: "Insert (Alt-DownArrow)",
                                items : {
                                    "insert-business-request":
                                    {
                                        name: "Business Request",
                                            icon: function () {
                                            return 'context-menu-icon context-menu-icon-quit';
                                        },
                                        callback: function(){
                                            tplbEditor.addTemplate('business-request');
                                            alert('Prototype level implemented : will insert a new business request template at the current position : a new editable business request template should appear in the document. You can also try the shortcut Alt-down that will display, in this proto, the global context menu at the mouse position and later only this sub menu.');
                                        }
                                    },
                                    "business-request-ref": {
                                        name: "Business Request Reference",
                                            icon: function(){
                                            return 'context-menu-icon context-menu-icon-quit';
                                        },
                                        callback: function(){
                                            alert ('Not Yet Implemented : will display a screen  to select an existing business request in the document database and create a reference to the selected business request at the current position, with a default behavior "inline" or "navigate". "Inline" reference will dynamically include the business request in place of the reference, "Navigate" will navigate from the reference to the request. These two behaviors can be toggled.');
                                        }
                                    },
                                    "symfony-controller": {
                                        name: "Symfony Controller",
                                            icon: function(){
                                            return 'context-menu-icon context-menu-icon-quit';
                                        },
                                        callback: function(){
                                            alert ('Not Yet Implemented : will display a screen  to select an existing Symfony Contoller in the (Git) source repository database and create a reference to the selected controller at the current position, with the same "inline" or "navigate" behaviors, as for document elements like business request elements. The goal is to organise a software platform documentation as a repository of document elements linked together, enabling breakthrough traceability between business/user requirements and their code implementation, with minimal documenting process cost for authors : just create the/ focus on value added document element without the charge of extra documenting management tasks. Further more , conversion of the document elements to markdown or other wiki formats will be available to ensure flexible integration in software platform management solutions like Github, Redmine, Trello...');
                                        }
                                    }

                                }
                        },
                        InsertAfterSubmenu: {
                            name: "Insert after (Alt-RightArrow)",
                            items : {
                                "insert-after-business-request":
                                {
                                    name: "Business Request",
                                    icon: function () {
                                        return 'context-menu-icon context-menu-icon-quit';
                                    },
                                    callback: function(){
                                        alert('No yet implemented : will do the same as the Insert menu but after the current element of the document structure. Sub menus to insert before the current element (left) or in the current element parent (up) will be added too, together with menus to navigate and select elements in the whole document structure (Ctrl-Alt-Up, left, right...), so that combined with the insertion menus, one can quickly edit a whole document structure without the "lost in the structure" effect.');
                                    }
                                }
                            }
                        },
                        "select-parent":
                        {
                            name: "Select parent (Ctrl-Alt-UpArrow)",
                            icon: function () {
                                return 'context-menu-icon context-menu-icon-quit';
                            },
                            callback: function(){
                                tplbEditor.selectParent();
                                alert('Prototype level implemented : select the parent of the current element to enable insertion in it or other element selection in it . The parent element box borders are now visible (dotted lines).');
                            }
                        }

                    }
                });
            ////////////////////////
        } catch (e) {
            alert ('error');
        }
    });
<|endoftext|>


<commit_before>goog.require('goog.color');
goog.require('goog.debug.errorHandlerWeakDep');
goog.require('webglmaps.Layer');
goog.require('webglmaps.Map');
goog.require('webglmaps.MouseNavigation');
goog.require('webglmaps.TileUrl');

goog.provide('webglmaps.main');

/**
 * @typedef {Object}
 */
goog.debug.ErrorHandler = goog.debug.errorHandlerWeakDep;

/**
 * @param {HTMLCanvasElement} canvas Canvas.
 */
webglmaps.main = function(canvas) {

  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;

  var bgColor = goog.color.hexToRgb('#fff');
  var map = new webglmaps.Map(canvas, 256, bgColor);

  var layer, tileUrl;
  if (true) {
    tileUrl = webglmaps.tileurl.fromTemplate(
        'http://localhost:8000/data/image/0/tiles/{z}/{x}/{y}');
    layer = new webglmaps.Layer(tileUrl, 0, 8);
  } else {
    tileUrl = webglmaps.tileurl.fromTileUrls([
      webglmaps.tileurl.fromTemplate('http://mt0.google.com' +
          '/vt/lyrs=t@128,r@167000000&hl=en&x={x}&y={y}&z={z}&s=Gali'),
      webglmaps.tileurl.fromTemplate('http://mt1.google.com' +
          '/vt/lyrs=t@128,r@167000000&hl=en&x={x}&y={y}&z={z}&s=Gali'),
      webglmaps.tileurl.fromTemplate('http://mt2.google.com' +
          '/vt/lyrs=t@128,r@167000000&hl=en&x={x}&y={y}&z={z}&s=Gali'),
      webglmaps.tileurl.fromTemplate('http://mt3.google.com' +
          '/vt/lyrs=t@128,r@167000000&hl=en&x={x}&y={y}&z={z}&s=Gali')
    ]);
    layer = new webglmaps.Layer(tileUrl, 0, 16);
  }
  map.addLayer(layer);
  var mouseNavigation = new webglmaps.MouseNavigation();
  mouseNavigation.setMap(map);

};
goog.exportSymbol('webglmaps.main', webglmaps.main);
<commit_msg>Use OpenStreetMap tiles for demo<commit_after>goog.require('goog.color');
goog.require('goog.debug.errorHandlerWeakDep');
goog.require('webglmaps.Layer');
goog.require('webglmaps.Map');
goog.require('webglmaps.MouseNavigation');
goog.require('webglmaps.TileUrl');

goog.provide('webglmaps.main');

/**
 * @typedef {Object}
 */
goog.debug.ErrorHandler = goog.debug.errorHandlerWeakDep;

/**
 * @define {boolean} Use local tileserver.
 */
webglmaps.USE_LOCAL_TILESERVER = false;

/**
 * @param {HTMLCanvasElement} canvas Canvas.
 */
webglmaps.main = function(canvas) {

  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;

  var bgColor = goog.color.hexToRgb('#fff');
  var map = new webglmaps.Map(canvas, 256, bgColor);

  var layer, tileUrl;
  if (webglmaps.USE_LOCAL_TILESERVER) {
    tileUrl = webglmaps.tileurl.fromTemplate(
        'http://localhost:8000/data/image/0/tiles/{z}/{x}/{y}');
    layer = new webglmaps.Layer(tileUrl, 0, 8);
  } else {
    tileUrl = webglmaps.tileurl.fromTileUrls([
      webglmaps.tileurl.fromTemplate(
          'http://a.tile.openstreetmap.org/{z}/{x}/{y}.png'),
      webglmaps.tileurl.fromTemplate(
          'http://b.tile.openstreetmap.org/{z}/{x}/{y}.png'),
      webglmaps.tileurl.fromTemplate(
          'http://c.tile.openstreetmap.org/{z}/{x}/{y}.png')
    ]);
    layer = new webglmaps.Layer(tileUrl, 0, 18);
  }
  map.addLayer(layer);
  var mouseNavigation = new webglmaps.MouseNavigation();
  mouseNavigation.setMap(map);

};
goog.exportSymbol('webglmaps.main', webglmaps.main);
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

var exec = require('child_process').exec;

var cmdDriveWwid = 'ls -l /dev/disk/by-id';
var cmdVdInfo = 'ls -l /dev/disk/by-path';
var cmdScsiId = 'lsscsi';
var options = {
    timeout: 10000 //10 seconds
};

/**
 * Parse the Drive WWID output
 * @param {String} idList - stdout for command 'ls -l /dev/disk/by-id'
 * @return {Object} include device name, Linux and ESXi WWIDs for each disks
 */
function parseDriveWwid(idList) {
    //idList example
    //"lrwxrwxrwx. 1 root root  9 Nov 18 20:30 ata-SATADOM-SV_3SE_20150522AA9992050085 -> ../../sdb"
    //returned string example
    // "ata-SATADOM-SV_3SE_20150522AA9992050085->../../sdb"
    var lines = idList.split('\n').map(function(line) {
        var split = line.split(/\s+/);
        return [split[8],split[10]].join('->');
    });

    //According to SCSI-3 spec, vendor specified logic unit name string is 60
    var scsiLines = [], sataLines = [], wwnLines = [], requiredStrLen = 60;
    lines.forEach(function(line){
        if ( line && !(line.match('part'))){
            var nameIndex = line.lastIndexOf('/'), idIndex = line.lastIndexOf('->');
            if (line.indexOf('scsi') === 0) {
                scsiLines.push([line.slice(nameIndex + 1), line.slice(0, idIndex)]);
            }
            else if (line.indexOf('ata') === 0) {
                sataLines.push([line.slice(nameIndex + 1), line.slice(0, idIndex)]);
            }
            else if (line.indexOf('wwn') === 0) {
                wwnLines.push([line.slice(nameIndex + 1), line.slice(0, idIndex)]);
            }
        }
    });

    //wwnLine example: wwn-0x5000cca23de9e287 -> ../../sdb
    //esxiWwn example: ["sdb", "naa.5000cca23de9e287"]
    var esxiWwn = wwnLines.map(function(wwnLine) {
        var line = wwnLine[1];
        var split = line.split(/-/);
        return [wwnLine[0], 'naa.' + split[1].slice(2)];
    });

    //ESXi SATA WWID should be ('t10.ATA_____' + VendorInfo + Sub + SerialNumber)
    //VendorInfo + Sub + SerialNumber should be 60 characters.
    //Sub is made of N(N = 60 - VendorInfo - SerialNumber) underline '_' symbols
    //ESXi SATA WWID should finally replace remaing dashs '-' with '2D', '3D' ...
    //esxiLine example:
    //["sda", "ata-32GB_SATA_Flash_Drive_B061430580090000000F"]
    //esxiSata example
    //["sda", "t10.ATA_____32GB_SATA_Flash_Drive___________________B061430580090000000F"]
    //Todo: confrim above analysis is correct for all SATA disks.
    var esxiSata = sataLines.map(function(esxiLine) {
        var line = esxiLine[1];
        var headIndex = line.indexOf('-'), snIndex = line.lastIndexOf('_');
        var headStr = ['t10.', line.slice(0, headIndex).toUpperCase(), '_____'].join(''),
            vendorStr = line.slice(headIndex + 1, snIndex + 1),
            snStr = line.slice(snIndex + 1),
            dashStr = '';
        for (var i = 0; i< requiredStrLen - vendorStr.length - snStr.length; i += 1){
            dashStr += '_';
        }
        var strLine = [headStr, vendorStr, dashStr, snStr].join('');
        //return strLine.replace('-', '2D');
        //ESXi driveid replaces Nth '-' with 'ND' like 2D, 3D
        var strArray = strLine.split('-');
        if (strArray.length !== 1) {
            strLine = strArray[0];
            for (i = 0; i < strArray.length -1; i += 1){
                strLine = [strLine, (i + 2).toString(), 'D', strArray[i + 1]].join('');
            }
        }
        return [esxiLine[0], strLine];
    });

    //If one device Name is mapped to both WWN and SATA array, use WWN element instead
    esxiWwn.forEach(function(line) {
        esxiSata.forEach(function(subline){
            if (line[0] === subline[0]){
                subline [1] = line[1];
            }
        });
    });

    //esxiLine example: ["sda", "scsi-35000c500725f45d7"]
    //esxiScsi example: ["sda", "naa.5000c500725f45d7"]
    var esxiScsi = scsiLines.map(function(esxiLine) {
        var line = esxiLine[1];
        var split = line.split(/-|_/);
        return [esxiLine[0], 'naa.' + split[1].slice(1)];
    });

    //linuxLine example: ["sda", "scsi-35000c500725f45d7"]
    //linuxParsed example: ["sda", "/dev/disk/by-id/scsi-35000c500725f45d7"]
    var linuxParsed = sataLines.concat(scsiLines).map(function(linuxLine) {
        return [linuxLine[0], '/dev/disk/by-id/' + linuxLine[1]];
    });

    return {esxiDriveIds: esxiSata.concat(esxiScsi), linuxDriveIds: linuxParsed};
}

/**
 * Parse Virtual Drive output via by-path output
 * @param {String} pathList - stdout for command 'ls -l /dev/disk/by-path'
 * @return {Array} include device name, virtual disk name and scsi ID for each disk
 */
function parseVdInfo(pathList) {
    var lines = pathList.split('\n').map(function(line) {
        var split = line.split(/\s+/);
        return [split[8],split[10]].join('->');
    });
    var pciLines = [];
    lines.forEach(function(line){
        if ( line && !(line.match('part'))){
            var nameIndex = line.lastIndexOf('/'), idIndex = line.lastIndexOf('->');
            if (line.indexOf('pci') === 0) {
                pciLines.push([line.slice(nameIndex + 1), line.slice(0,idIndex)]);
            }
        }
    });

    return pciLines.map(function(line) {
        var scsiId = line[1].slice(line[1].lastIndexOf('-') + 1), vdStr;
        if (scsiId.split(':').length === 4){
            var scsiIdArray = scsiId.split(':');
            vdStr = ['/c', scsiIdArray[0], '/v', scsiIdArray[2]].join('');
        }
        return [line[0], vdStr, scsiId];
    });
}

/**
 * Parse scsi ID output via lsscsi command
 * @param {String} lsscsiList - stdout for command 'lsscsi'
 * @return {Array} include device name and scsi info for each disk
 */
function parseScsiInfo(lsscsiList) {
    var lines = lsscsiList.split('\n');
    return lines.map(function(line) {
        if(line){
            return [line.slice(line.lastIndexOf('/') + 1).replace(' ', ''),
                line.slice(1, line.indexOf(']'))];
        }
    });
}

/**
 * Build the drive mapping table
 * @param {String} wwidData
 * @param {String} vdData
 * @param {String} scsiData
 * @return 0 if success, otherwise failed.
 */
function buildDriveMap(wwidData, vdData, scsiData) {
    var parsedWwids = parseDriveWwid(wwidData),
        scsiList = parseScsiInfo(scsiData),
        vdList = parseVdInfo(vdData);
    var linuxWwids = parsedWwids.linuxDriveIds, esxiWwids = parsedWwids.esxiDriveIds;
    var driveIds=[];
    esxiWwids.forEach(function(esxiWwid){
        var vd = '', scsiId = '', diskPath = esxiWwid[0];
        vdList.forEach(function(elem){
            if (typeof elem !== 'undefined') {
                if (elem[0] === diskPath) {
                    vd = elem[1];
                }
            }
        });
        scsiList.forEach(function(elem){
            if (typeof elem !== 'undefined'){
                if(elem[0] === diskPath){
                    scsiId = elem[1];
                }
            }
        });
        driveIds.push({"scsiId": scsiId, "virtualDisk": vd,
            "esxiWwid": esxiWwid[1], "devName": diskPath});
    });

    linuxWwids.forEach(function(linuxWwid, k){
        driveIds[k].identifier = k;
        driveIds[k].linuxWwid = linuxWwid[1];
    });
    console.log(JSON.stringify(driveIds));
    return 0;
}

function run() {
    var wwidData, vdData, scsiData;
    try {
        exec(cmdDriveWwid, options, function (err0, stdout0) {
            if (err0) {
                console.error(err0.toString());
                process.exit(1);
            }
            wwidData = stdout0;
            exec(cmdVdInfo, options, function (err1, stdout1) {
                if (err1) {
                    console.error(err1.toString());
                    process.exit(1);
                }
                vdData = stdout1;
                exec(cmdScsiId, options, function (err2, stdout2) {
                    if (err2) {
                        console.error(err2.toString());
                        process.exit(1);
                    }
                    scsiData = stdout2;
                    if (buildDriveMap(wwidData, vdData, scsiData)) {
                        console.error('build drive map failed, wwidData=' +
                            wwidData + '\nvdData=' + vdData);
                        process.exit(1);
                    }
                    else {
                        process.exit(0);
                    }
                });
            });
        });
    }
    catch (e) {
        console.error(e.message);
        process.exit(1);
    }
}

return run();
<commit_msg>Solve the problem if only SATADOM is installed<commit_after>#!/usr/bin/env node

'use strict';

var exec = require('child_process').exec;

var cmdDriveWwid = 'ls -l /dev/disk/by-id';
var cmdVdInfo = 'ls -l /dev/disk/by-path';
var cmdScsiId = 'lsscsi';
var options = {
    timeout: 10000 //10 seconds
};

/**
 * Parse the Drive WWID output
 * @param {String} idList - stdout for command 'ls -l /dev/disk/by-id'
 * @return {Object} include device name, Linux and ESXi WWIDs for each disks
 */
function parseDriveWwid(idList) {
    //idList example
    //"lrwxrwxrwx. 1 root root  9 Nov 18 20:30 ata-SATADOM-SV_3SE_20150522AA9992050085 -> ../../sdb"
    //returned string example
    // "ata-SATADOM-SV_3SE_20150522AA9992050085->../../sdb"
    var lines = idList.split('\n').map(function(line) {
        var split = line.split(/\s+/);
        return [split[8],split[10]].join('->');
    });

    //According to SCSI-3 spec, vendor specified logic unit name string is 60
    var scsiLines = [], sataLines = [], wwnLines = [], requiredStrLen = 60;
    lines.forEach(function(line){
        if ( line && !(line.match('part'))){
            var nameIndex = line.lastIndexOf('/'), idIndex = line.lastIndexOf('->');
            if (line.indexOf('scsi') === 0) {
                scsiLines.push([line.slice(nameIndex + 1), line.slice(0, idIndex)]);
            }
            else if (line.indexOf('ata') === 0) {
                sataLines.push([line.slice(nameIndex + 1), line.slice(0, idIndex)]);
            }
            else if (line.indexOf('wwn') === 0) {
                wwnLines.push([line.slice(nameIndex + 1), line.slice(0, idIndex)]);
            }
        }
    });

    //wwnLine example: wwn-0x5000cca23de9e287 -> ../../sdb
    //esxiWwn example: ["sdb", "naa.5000cca23de9e287"]
    var esxiWwn = wwnLines.map(function(wwnLine) {
        var line = wwnLine[1];
        var split = line.split(/-/);
        return [wwnLine[0], 'naa.' + split[1].slice(2)];
    });

    //ESXi SATA WWID should be ('t10.ATA_____' + VendorInfo + Sub + SerialNumber)
    //VendorInfo + Sub + SerialNumber should be 60 characters.
    //Sub is made of N(N = 60 - VendorInfo - SerialNumber) underline '_' symbols
    //ESXi SATA WWID should finally replace remaing dashs '-' with '2D', '3D' ...
    //esxiLine example:
    //["sda", "ata-32GB_SATA_Flash_Drive_B061430580090000000F"]
    //esxiSata example
    //["sda", "t10.ATA_____32GB_SATA_Flash_Drive___________________B061430580090000000F"]
    //Todo: confrim above analysis is correct for all SATA disks.
    var esxiSata = sataLines.map(function(esxiLine) {
        var line = esxiLine[1];
        var headIndex = line.indexOf('-'), snIndex = line.lastIndexOf('_');
        var headStr = ['t10.', line.slice(0, headIndex).toUpperCase(), '_____'].join(''),
            vendorStr = line.slice(headIndex + 1, snIndex + 1),
            snStr = line.slice(snIndex + 1),
            dashStr = '';
        for (var i = 0; i< requiredStrLen - vendorStr.length - snStr.length; i += 1){
            dashStr += '_';
        }
        var strLine = [headStr, vendorStr, dashStr, snStr].join('');
        //return strLine.replace('-', '2D');
        //ESXi driveid replaces Nth '-' with 'ND' like 2D, 3D
        var strArray = strLine.split('-');
        if (strArray.length !== 1) {
            strLine = strArray[0];
            for (i = 0; i < strArray.length -1; i += 1){
                strLine = [strLine, (i + 2).toString(), 'D', strArray[i + 1]].join('');
            }
        }
        return [esxiLine[0], strLine];
    });

    //If one device Name is mapped to both WWN and SATA array, use WWN element instead
    esxiWwn.forEach(function(line) {
        esxiSata.forEach(function(subline){
            if (line[0] === subline[0]){
                subline [1] = line[1];
            }
        });
    });

    //esxiLine example: ["sda", "scsi-35000c500725f45d7"]
    //esxiScsi example: ["sda", "naa.5000c500725f45d7"]
    var esxiScsi = scsiLines.map(function(esxiLine) {
        var line = esxiLine[1];
        var split = line.split(/-|_/);
        return [esxiLine[0], 'naa.' + split[1].slice(1)];
    });

    //linuxLine example: ["sda", "scsi-35000c500725f45d7"]
    //linuxParsed example: ["sda", "/dev/disk/by-id/scsi-35000c500725f45d7"]
    var linuxParsed = sataLines.concat(scsiLines).map(function(linuxLine) {
        return [linuxLine[0], '/dev/disk/by-id/' + linuxLine[1]];
    });

    return {esxiDriveIds: esxiSata.concat(esxiScsi), linuxDriveIds: linuxParsed};
}

/**
 * Parse Virtual Drive output via by-path output
 * @param {String} pathList - stdout for command 'ls -l /dev/disk/by-path'
 * @return {Array} include device name, virtual disk name and scsi ID for each disk
 */
function parseVdInfo(pathList) {
    var lines = pathList.split('\n').map(function(line) {
        var split = line.split(/\s+/);
        return [split[8],split[10]].join('->');
    });
    var pciLines = [];
    lines.forEach(function(line){
        if ( line && !(line.match('part'))){
            var nameIndex = line.lastIndexOf('/'), idIndex = line.lastIndexOf('->');
            if (line.indexOf('pci') === 0) {
                pciLines.push([line.slice(nameIndex + 1), line.slice(0,idIndex)]);
            }
        }
    });

    return pciLines.map(function(line) {
        var scsiId = line[1].slice(line[1].lastIndexOf('-') + 1), vdStr;
        if (scsiId.split(':').length === 4){
            var scsiIdArray = scsiId.split(':');
            vdStr = ['/c', scsiIdArray[0], '/v', scsiIdArray[2]].join('');
        }
        return [line[0], vdStr, scsiId];
    });
}

/**
 * Parse scsi ID output via lsscsi command
 * @param {String} lsscsiList - stdout for command 'lsscsi'
 * @return {Array} include device name and scsi info for each disk
 */
function parseScsiInfo(lsscsiList) {
    var lines = lsscsiList.split('\n');
    return lines.map(function(line) {
        if(line){
            return [line.slice(line.lastIndexOf('/') + 1).replace(' ', ''),
                line.slice(1, line.indexOf(']'))];
        }
    });
}

/**
 * Build the drive mapping table
 * @param {String} wwidData
 * @param {String} vdData
 * @param {String} scsiData
 * @return 0 if success, otherwise failed.
 */
function buildDriveMap(wwidData, vdData, scsiData) {
    var parsedWwids = parseDriveWwid(wwidData),
        scsiList = parseScsiInfo(scsiData),
        vdList = parseVdInfo(vdData);
    var linuxWwids = parsedWwids.linuxDriveIds, esxiWwids = parsedWwids.esxiDriveIds;
    var driveIds=[];
    esxiWwids.forEach(function(esxiWwid){
        var vd = '', scsiId = '', diskPath = esxiWwid[0];
        vdList.forEach(function(elem){
            if (typeof elem !== 'undefined') {
                if (elem[0] === diskPath) {
                    vd = elem[1];
                }
            }
        });
        scsiList.forEach(function(elem){
            if (typeof elem !== 'undefined'){
                if(elem[0] === diskPath){
                    scsiId = elem[1];
                }
            }
        });
        driveIds.push({"scsiId": scsiId, "virtualDisk": vd,
            "esxiWwid": esxiWwid[1], "devName": diskPath});
    });

    linuxWwids.forEach(function(linuxWwid, k){
        driveIds[k].identifier = k;
        driveIds[k].linuxWwid = linuxWwid[1];
    });
    console.log(JSON.stringify(driveIds));
    return 0;
}

function run() {
    var wwidData, vdData, scsiData;
    try {
        exec(cmdDriveWwid, options, function (err0, stdout0) {
            if (err0) {
                console.error(err0.toString());
                process.exit(1);
            }
            wwidData = stdout0;
            exec(cmdVdInfo, options, function (err1, stdout1) {
                if (err1) {
                    var errStr= "ls: cannot access /dev/disk/by-path: No such file or directory";
                    //"/dev/disk/by-path" doesn't exist means only SATADOM exists, no HDDs
                    // Ignore this error and use null string for vdData
                    if (err1.toString().search(errStr) !== -1){
                        vdData = '';
                    }
                    else {
                        console.error(err1.toString());
                        process.exit(1);
                    }
                }
                else {
                    vdData = stdout1;
                }
                exec(cmdScsiId, options, function (err2, stdout2) {
                    if (err2) {
                        console.error(err2.toString());
                        process.exit(1);
                    }
                    scsiData = stdout2;
                    if (buildDriveMap(wwidData, vdData, scsiData)) {
                        console.error('build drive map failed, wwidData=' +
                            wwidData + '\nvdData=' + vdData);
                        process.exit(1);
                    }
                    else {
                        process.exit(0);
                    }
                });
            });
        });
    }
    catch (e) {
        console.error(e.message);
        process.exit(1);
    }
}

return run();
<|endoftext|>


<commit_before>// Websocket server which handles data to/from the inspector
var fs = require('fs');
var express = require('express');
var remoteDebugger = express();
var remoteDebugServer = require('http').Server(remoteDebugger);
var remoteDebugSocket = require('socket.io')(remoteDebugServer);
var inspectorPath = __dirname + '/../node_modules/ember-extension/dist_websocket/';

var inspectorHtml = fs.readFileSync(inspectorPath + 'panes/index.html').toString();

remoteDebugger.use('/', express.static(inspectorPath));
remoteDebugger.get('/', function(req, res) {
  res.end(inspectorHtml);
});

var inspectorSocket = null;

module.exports = {
  setSocketScript: function(socketScript) {
    inspectorHtml = inspectorHtml.replace('{{ remote-port }}', socketScript)
  },

  start: function(port, host) {
    remoteDebugServer.listen(port, host, function(){
      console.log('Ember inspector available on http://' + host + ':' + port + '.');
    });

    remoteDebugSocket.on('connect', function(socket){
      socket.on('debugmsg', function(msg){
        if(msg.from==='devtools') {
          inspectorSocket = socket;
          remoteDebugSocket.emit('debugmsg', msg);
        }
        else if(inspectorSocket) {
          inspectorSocket.emit('debugmsg', msg);
        }
      });
    });
  }
}<commit_msg>Better name for message<commit_after>// Websocket server which handles data to/from the inspector
var fs = require('fs');
var express = require('express');
var remoteDebugger = express();
var remoteDebugServer = require('http').Server(remoteDebugger);
var remoteDebugSocket = require('socket.io')(remoteDebugServer);
var inspectorPath = __dirname + '/../node_modules/ember-extension/dist_websocket/';

var inspectorHtml = fs.readFileSync(inspectorPath + 'panes/index.html').toString();

remoteDebugger.use('/', express.static(inspectorPath));
remoteDebugger.get('/', function(req, res) {
  res.end(inspectorHtml);
});

var inspectorSocket = null;

module.exports = {
  setSocketScript: function(socketScript) {
    inspectorHtml = inspectorHtml.replace('{{ remote-port }}', socketScript)
  },

  start: function(port, host) {
    remoteDebugServer.listen(port, host, function(){
      console.log('Ember inspector available on http://' + host + ':' + port + '.');
    });

    remoteDebugSocket.on('connect', function(socket){
      socket.on('emberInspectorMessage', function(msg){
        if(msg.from==='devtools') {
          inspectorSocket = socket;
          remoteDebugSocket.emit('emberInspectorMessage', msg);
        }
        else if(inspectorSocket) {
          inspectorSocket.emit('emberInspectorMessage', msg);
        }
      });
    });
  }
}<|endoftext|>


<commit_before>/* Headless server, for use with Pageshot:
 * https://github.com/mozilla-services/pageshot
 * relies on the server module from AutoInstaller
 * https://github.com/palant/autoinstaller/blob/master/lib/server.js
 *
 * Accepts requests on the assigned port, from allowed IPs, and runs the given
 * function
 * usage to send a URL:
 * curl --data 'http://www.asdf.com' -H 'Expect:' localhost:7777
 *
 * The server takes the following args, more info can be found in server.js:
 *    port:        port to listen on, integer
 *    allowedIPs   list of IPs to allow to talk to the server, space or comma separated string
 *    callback     function to be called on the data passed to the
 *    let blah = new Server(port, allowedIPs, callback)
 */

var port = 7777;
var allowedIPs = "127.0.0.1";
var callback = openTab;

const tabs = require("sdk/tabs");

const { Server } = require("./server");
const { autoShot } = require("./shooter");

var backend;

exports.init = function init(prefs) {
  // set global backend, extractTab needs it
  backend = prefs.backend;
  let server = new Server(port, allowedIPs, callback);
};

function openTab(url) {
  // Opens a tab and registers extractTab to the load event
  tabs.open({
    "url": url,
    "onLoad": function (tab) {
      autoShot(tab, backend);
    }
  });
}
<commit_msg>added some logging<commit_after>/* Headless server, for use with Pageshot:
 * https://github.com/mozilla-services/pageshot
 * relies on the server module from AutoInstaller
 * https://github.com/palant/autoinstaller/blob/master/lib/server.js
 *
 * Accepts requests on the assigned port, from allowed IPs, and runs the given
 * function
 * usage to send a URL:
 * curl --data 'http://www.asdf.com' -H 'Expect:' localhost:7777
 *
 * The server takes the following args, more info can be found in server.js:
 *    port:        port to listen on, integer
 *    allowedIPs   list of IPs to allow to talk to the server, space or comma separated string
 *    callback     function to be called on the data passed to the
 *    let blah = new Server(port, allowedIPs, callback)
 */

var port = 7777;
var allowedIPs = "127.0.0.1";
var callback = openTab;

const tabs = require("sdk/tabs");

const { Server } = require("./server");
const { autoShot } = require("./shooter");

var backend;

exports.init = function init(prefs) {
  console.info("starting headless server");
  // set global backend, extractTab needs it
  backend = prefs.backend;
  let server = new Server(port, allowedIPs, callback);
  console.info("headless server listening on PORT".replace('PORT', port));
};

function openTab(url) {
  // Opens a tab and registers extractTab to the load event
  tabs.open({
    "url": url,
    "onLoad": function (tab) {
      autoShot(tab, backend);
    }
  });
}
<|endoftext|>


<commit_before>/* Headless server, for use with Pageshot:
 *  https://github.com/mozilla-services/pageshot
 * Relies on the server module from mozilla testing:
 *  http://mxr.mozilla.org/mozilla-central/source/netwerk/test/httpserver/
 *
 * Listening IP address may be assigned to httpd, by default it is localhost.
 * The default is used in this implementation.
 *    For more info:
 *    http://mxr.mozilla.org/mozilla-central/source/netwerk/test/httpserver/nsIHttpServer.idl#282
 *
 * TODO:
 *    Documentation
 *    Check URL before opening
 *    Fix autoShot - currently it leaves some errors about attrs
 *    Add preference for whether or not headless should run
 *    Reimplement contentServerString?
 *
 * General usage:
 * When you make an HTTP request to this server on the appropriate port it will
 * look for a query string and attempt to open the string as a URL, return a
 * URL of where to find it when processing is done, and process the tab with
 * an automatic shot function.
 *
 * Generally CSS parsing is enabled on this branch, which is EXPERIMENTAL.
 *
 * Syntax, assuming default IP, PORT, and target URL of asdf.com:
 *    curl 'http://localhost:10082/?http://www.asdf.com'
 *
 * Usage without X:
 * To use this without X, start the server as normal. Then, in the bin/
 * directory, run `sh ephemeral-x.sh ./run-addon`.
 */

const { Cc, Ci, Cu } = require("chrome");
const tabs = require("sdk/tabs");

const HTTPD_MOD_URL = module.uri.replace("/headless.js", "/httpd.jsm");
const { nsHttpServer } = Cu.import(HTTPD_MOD_URL);

const { randomString } = require("./randomstring");
const { autoShot, RANDOM_STRING_LENGTH, urlDomainForId } = require("./shooter");
const { prefs } = require("sdk/simple-prefs");

var ip = prefs.httpServerIp;
var port = prefs.httpServerPort;
var backend = prefs.backend;    // set global backend, handleRequest needs it

exports.init = function init() {
  /* Initializes the backend server, which listens for requests made to / and
   * passes them to the handleRequest function below
   */
  if (!prefs.startHttpServer) { return; }
  console.info("starting headless server on IP:PORT"
                                                    .replace('IP', ip)
                                                    .replace('PORT', port));
  var server = new nsHttpServer();
  if (ip != "localhost") { server.identity.add("http", ip, port); }
  server.start(port);
  server.registerPathHandler('/', handleRequest);
  server.registerPathHandler('/readable/', handleReadableRequest);
};

function handleRequest(request, response) {
  /* Takes a request from the server, makes the response asynchronous so the
   * client waits for a response, processes the query string from the request
   * as a URL with the function autoShot from shooter.js and finally returns a
   * URL which the processed content may be found at
   */
  response.processAsync();
  var url = request._queryString;
  var backendUrl = randomString(RANDOM_STRING_LENGTH) + "/" + urlDomainForId(url);
  console.log('recieved request: URL -> BACK'
                .replace('URL', url).replace('BACK', backendUrl));
  tabs.open({
    "url": url,
    "onLoad": function (tab) {
      autoShot(tab, backend, backendUrl);
      tab.on("close", function (a) {
        console.log('completed processing BACK'.replace('BACK', backendUrl));
        response.setStatusLine("1.1", 200, "OK");
        response.write(backendUrl + '\n');
        response.finish();
      });
    }
  });
}

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

function handleReadableRequest(request, response) {
  var fired = false;        // Assign local variable fired, because onload gets tricky
  response.processAsync();  // Tell response handler this is going to take a while
  var url = request._queryString; // Grab the passed URL
  var backendUrl = randomString(RANDOM_STRING_LENGTH) + "/" + urlDomainForId(url); // Create backend url, usually happens in shooter.js
  console.log('recieved request: URL -> BACK'   // Log both URLs
                .replace('URL', url).replace('BACK', backendUrl));

  tabs.open({                   // Open a tab
    "url": url,
    "onOpen": function (tab) {  // When the tab opens, run this on it
      tab.on("load", function (tab) {
        if (!fired) {           // If it hasn't fired, click on readable button
          fired = true;
          var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
                             .getService(Ci.nsIWindowMediator);
          var browserWindow = wm.getMostRecentWindow("navigator:browser");
          browserWindow.document.getElementById("reader-mode-button").click();
        } else {                // If it has fired, remove the toolbar
          var worker = tab.attach({
            contentScript:
              'var toolbar = document.getElementById("reader-toolbar");\n' +
              'toolbar.parentElement.removeChild(toolbar);\n' +
              'self.port.emit("done");'
          });
          worker.port.on("done", function () { // When the worker emits done, wait a bit then fire autoshot
            console.log('readability should be finished');
            sleep(prefs.readableSleep); // Sleep is required because if you fire autoShot immediately the DOM comes up empty
            autoShot(tab, backend, backendUrl);
          });
        }
      });

      tab.on("close", function () {     // When the tab is closed we know autoshot is done, so return the URL
        console.log('completed processing BACK'.replace('BACK', backendUrl));
        response.setStatusLine("1.1", 200, "OK");
        response.write(backendUrl + '\n');
        response.finish();
      });
    }
  });
}
<commit_msg>Syntactic (es6) fixups<commit_after>/* globals module */
/* Headless server, for use with Pageshot:
 *  https://github.com/mozilla-services/pageshot
 * Relies on the server module from mozilla testing:
 *  http://mxr.mozilla.org/mozilla-central/source/netwerk/test/httpserver/
 *
 * Listening IP address may be assigned to httpd, by default it is localhost.
 * The default is used in this implementation.
 *    For more info:
 *    http://mxr.mozilla.org/mozilla-central/source/netwerk/test/httpserver/nsIHttpServer.idl#282
 *
 * TODO:
 *    Documentation
 *    Check URL before opening
 *    Fix autoShot - currently it leaves some errors about attrs
 *    Add preference for whether or not headless should run
 *    Reimplement contentServerString?
 *
 * General usage:
 * When you make an HTTP request to this server on the appropriate port it will
 * look for a query string and attempt to open the string as a URL, return a
 * URL of where to find it when processing is done, and process the tab with
 * an automatic shot function.
 *
 * Generally CSS parsing is enabled on this branch, which is EXPERIMENTAL.
 *
 * Syntax, assuming default IP, PORT, and target URL of asdf.com:
 *    curl 'http://localhost:10082/?http://www.asdf.com'
 *
 * Usage without X:
 * To use this without X, start the server as normal. Then, in the bin/
 * directory, run `sh ephemeral-x.sh ./run-addon`.
 */

const { Cc, Ci, Cu } = require("chrome");
const tabs = require("sdk/tabs");

const HTTPD_MOD_URL = module.uri.replace("/headless.js", "/httpd.jsm");
const { nsHttpServer } = Cu.import(HTTPD_MOD_URL);

const { randomString } = require("./randomstring");
const { autoShot, RANDOM_STRING_LENGTH, urlDomainForId } = require("./shooter");
const { prefs } = require("sdk/simple-prefs");

var ip = prefs.httpServerIp;
var port = prefs.httpServerPort;
var backend = prefs.backend;    // set global backend, handleRequest needs it

exports.init = function init() {
  /* Initializes the backend server, which listens for requests made to / and
   * passes them to the handleRequest function below
   */
  if (!prefs.startHttpServer) { return; }
  console.info(`starting headless server on http://${ip}:${port}`);
  var server = new nsHttpServer();
  if (ip != "localhost") { server.identity.add("http", ip, port); }
  server.start(port);
  server.registerPathHandler('/', handleRequest);
  server.registerPathHandler('/readable/', handleReadableRequest);
};

function handleRequest(request, response) {
  /* Takes a request from the server, makes the response asynchronous so the
   * client waits for a response, processes the query string from the request
   * as a URL with the function autoShot from shooter.js and finally returns a
   * URL which the processed content may be found at
   */
  response.processAsync();
  var url = request._queryString;
  var backendUrl = randomString(RANDOM_STRING_LENGTH) + "/" + urlDomainForId(url);
  console.log('recieved request: URL -> BACK'
                .replace('URL', url).replace('BACK', backendUrl));
  tabs.open({
    url: url,
    onLoad: function (tab) {
      autoShot(tab, backend, backendUrl);
      tab.on("close", function (a) {
        console.log(`completed processing ${backendUrl}`);
        response.setStatusLine("1.1", 200, "OK");
        response.write(backendUrl + '\n');
        response.finish();
      });
    }
  });
}

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if (Date().now() - start > milliseconds){
      break;
    }
  }
}

function handleReadableRequest(request, response) {
  var fired = false;        // Assign local variable fired, because onload gets tricky
  response.processAsync();  // Tell response handler this is going to take a while
  var url = request._queryString; // Grab the passed URL
  var backendUrl = randomString(RANDOM_STRING_LENGTH) + "/" + urlDomainForId(url); // Create backend url, usually happens in shooter.js
  console.log(`recieved request: ${url} -> ${backendUrl}`);
  tabs.open({                   // Open a tab
    url: url,
    onOpen: function (tab) {  // When the tab opens, run this on it
      tab.on("load", function (tab) {
        if (!fired) {           // If it hasn't fired, click on readable button
          fired = true;
          var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
                             .getService(Ci.nsIWindowMediator);
          var browserWindow = wm.getMostRecentWindow("navigator:browser");
          browserWindow.document.getElementById("reader-mode-button").click();
        } else {                // If it has fired, remove the toolbar
          var worker = tab.attach({
            contentScript: `
              var toolbar = document.getElementById("reader-toolbar");
              toolbar.parentElement.removeChild(toolbar);
              self.port.emit("done");`
          });
          worker.port.on("done", function () { // When the worker emits done, wait a bit then fire autoshot
            console.log('readability should be finished');
            sleep(prefs.readableSleep); // Sleep is required because if you fire autoShot immediately the DOM comes up empty
            autoShot(tab, backend, backendUrl);
          });
        }
      });

      tab.on("close", function () {     // When the tab is closed we know autoshot is done, so return the URL
        console.log(`completed processing ${backendUrl}`);
        response.setStatusLine("1.1", 200, "OK");
        response.write(backendUrl + '\n');
        response.finish();
      });
    }
  });
}
<|endoftext|>


<commit_before>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

// Utility function that allows modes to be combined. The mode given
// as the base argument takes care of most of the normal mode
// functionality, but a second (typically simple) mode is used, which
// can override the style of text. Both modes get to parse all of the
// text, but when both assign a non-null style to a piece of code, the
// overlay wins, unless the combine argument was true and not overridden,
// or state.overlay.combineTokens was true, in which case the styles are
// combined.

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.overlayMode = function(base, overlay, combine) {
  return {
    startState: function() {
      return {
        base: CodeMirror.startState(base),
        overlay: CodeMirror.startState(overlay),
        basePos: 0, baseCur: null,
        overlayPos: 0, overlayCur: null,
        streamSeen: null
      };
    },
    copyState: function(state) {
      return {
        base: CodeMirror.copyState(base, state.base),
        overlay: CodeMirror.copyState(overlay, state.overlay),
        basePos: state.basePos, baseCur: null,
        overlayPos: state.overlayPos, overlayCur: null
      };
    },

    token: function(stream, state) {
      if (stream != state.streamSeen ||
          Math.min(state.basePos, state.overlayPos) < stream.start) {
        state.streamSeen = stream;
        state.basePos = state.overlayPos = stream.start;
      }

      if (stream.start == state.basePos) {
        state.baseCur = base.token(stream, state.base);
        state.basePos = stream.pos;
      }
      if (stream.start == state.overlayPos) {
        stream.pos = stream.start;
        state.overlayCur = overlay.token(stream, state.overlay);
        state.overlayPos = stream.pos;
      }
      stream.pos = Math.min(state.basePos, state.overlayPos);

      // state.overlay.combineTokens always takes precedence over combine,
      // unless set to null
      if (state.overlayCur == null) return state.baseCur;
      else if (state.baseCur != null &&
               state.overlay.combineTokens ||
               combine && state.overlay.combineTokens == null)
        return state.baseCur + " " + state.overlayCur;
      else return state.overlayCur;
    },

    indent: base.indent && function(state, textAfter) {
      return base.indent(state.base, textAfter);
    },
    electricChars: base.electricChars,

    innerMode: function(state) { return {state: state.base, mode: base}; },

    blankLine: function(state) {
      if (base.blankLine) base.blankLine(state.base);
      if (overlay.blankLine) overlay.blankLine(state.overlay);
    }
  };
};

});
<commit_msg>[overlay addon] Fix the `combine` option for overlay modes inside blankLines<commit_after>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

// Utility function that allows modes to be combined. The mode given
// as the base argument takes care of most of the normal mode
// functionality, but a second (typically simple) mode is used, which
// can override the style of text. Both modes get to parse all of the
// text, but when both assign a non-null style to a piece of code, the
// overlay wins, unless the combine argument was true and not overridden,
// or state.overlay.combineTokens was true, in which case the styles are
// combined.

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.overlayMode = function(base, overlay, combine) {
  return {
    startState: function() {
      return {
        base: CodeMirror.startState(base),
        overlay: CodeMirror.startState(overlay),
        basePos: 0, baseCur: null,
        overlayPos: 0, overlayCur: null,
        streamSeen: null
      };
    },
    copyState: function(state) {
      return {
        base: CodeMirror.copyState(base, state.base),
        overlay: CodeMirror.copyState(overlay, state.overlay),
        basePos: state.basePos, baseCur: null,
        overlayPos: state.overlayPos, overlayCur: null
      };
    },

    token: function(stream, state) {
      if (stream != state.streamSeen ||
          Math.min(state.basePos, state.overlayPos) < stream.start) {
        state.streamSeen = stream;
        state.basePos = state.overlayPos = stream.start;
      }

      if (stream.start == state.basePos) {
        state.baseCur = base.token(stream, state.base);
        state.basePos = stream.pos;
      }
      if (stream.start == state.overlayPos) {
        stream.pos = stream.start;
        state.overlayCur = overlay.token(stream, state.overlay);
        state.overlayPos = stream.pos;
      }
      stream.pos = Math.min(state.basePos, state.overlayPos);

      // state.overlay.combineTokens always takes precedence over combine,
      // unless set to null
      if (state.overlayCur == null) return state.baseCur;
      else if (state.baseCur != null &&
               state.overlay.combineTokens ||
               combine && state.overlay.combineTokens == null)
        return state.baseCur + " " + state.overlayCur;
      else return state.overlayCur;
    },

    indent: base.indent && function(state, textAfter) {
      return base.indent(state.base, textAfter);
    },
    electricChars: base.electricChars,

    innerMode: function(state) { return {state: state.base, mode: base}; },

    blankLine: function(state) {
      var baseToken, overlayToken;
      if (base.blankLine) baseToken = base.blankLine(state.base);
      if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay);

      return overlayToken == null ?
        baseToken :
        (combine ? baseToken + " " + overlayToken : overlayToken);
    }
  };
};

});
<|endoftext|>