<commit_before>var
  debug = require('debug')('kuzzle:broker:server'),
  fs = require('fs'),
  http = require('http'),
  net = require('net'),
  Promise = require('bluebird'),
  CircularList = require('easy-circular-list'),
  InternalError = require('kuzzle-common-objects').errors.InternalError,
  WS = require('ws').Server;

/**
 * Web Socket server implementation of Kuzzle's internal broker.
 *
 * @param brokerType
 * @param options
 * @param pluginsManager
 * @constructor
 */
function WSBrokerServer (brokerType, options, pluginsManager) {
  this.wss = null;
  this.rooms = {};
  this.handlers = {};
  this.pluginsManager = pluginsManager;
  this.eventName = brokerType;
  this.isDisabled = options.disabled === true;

  this.ws = cb => {
    var
      server = http.createServer(),
      initCB = () => {
        this.wss = new WS({ server }, {perMessageDeflate: false});
        cb();
      };

    this.wss = true;

    if (options.socket) {
      server.on('error', error => {

        if(error.code !== 'EADDRINUSE') {
          debug('[%s] broker server received an error:\n%O', this.eventName, error);

          throw error;
        }

        net.connect(options.socket, () => {
          // really in use, re-throw
          throw error;
        })
          .on('error', e => {
            if (e.code !== 'ECONNREFUSED') {
              debug('[%s] broker server can\'t open requested socket, seem to be already used by another process', this.eventName);

              throw e;
            }

            debug('[%s] broker server can\'t open requested socket, seem to be unused, trying to recreate it', this.eventName);

            fs.unlinkSync(options.socket);

            if (this.wss instanceof WS) {
              this.wss.close(() => {
                server.listen(options.socket);
              });
            }
            else {
              server.listen(options.socket);
            }
          });
      });

      debug('[%s] initialize broker server through socket "%s"', this.eventName, options.socket);

      server.listen(options.socket, initCB);
    }
    else if (options.port) {
      if (options.host) {
        debug('[%s] initialize broker server through net port "%s" on host "%s"', this.eventName, options.port, options.host);

        server.listen(options.port, options.host, initCB);
      }
      else {
        debug('[%s] initialize broker server through net port "%s"', this.eventName, options.port, options.host);

        server.listen(options.port, initCB);
      }
    }
    else {
      throw new InternalError(`Invalid configuration provided for ${this.eventName}. Either "port" or "socket" must be provided.`);
    }
  };

  this.onErrorHandlers = [];
  this.onCloseHandlers = [];
}

/**
 * Initializes the server by setting the underlying ws.WebSocket.Server up.
 *
 * @returns {Promise}
 */
WSBrokerServer.prototype.init = function wSBrokerServerInit () {
  if (this.isDisabled) {
    this.pluginsManager.trigger('log:warn', 'Internal broker disabled by configuration');
    return Promise.resolve();
  }

  if (this.wss) {
    return Promise.reject(new InternalError('Websocket server already started'));
  }

  return new Promise(resolve => {
    this.ws(() => {
      this.wss.on('connection', clientSocket => {

        debug('[%s][%s] broker server received a connection', this.eventName, clientSocket.upgradeReq ? clientSocket.upgradeReq.headers['sec-websocket-key'] : 'unknown identifier');

        clientSocket.on('message', msg => {
          msg = JSON.parse(msg);

          debug('[%s][%s] received a message though broker server connection:\n%O', this.eventName, clientSocket.upgradeReq ? clientSocket.upgradeReq.headers['sec-websocket-key'] : 'unknown identifier', msg);

          switch (msg.action) {
            // the listen action is called by the client to inform the server it
            // wants to be notified on the room activity
            case 'listen':
              if (this.rooms[msg.room] === undefined) {
                this.rooms[msg.room] = new CircularList([]);
              }
              if (this.rooms[msg.room].getArray().indexOf(clientSocket) === -1) {
                this.rooms[msg.room].add(clientSocket);
              }
              break;
            case 'unsubscribe':
              if (this.rooms[msg.room]) {
                this.rooms[msg.room].remove(clientSocket);
                if (this.rooms[msg.room].getSize() === 0) {
                  delete this.rooms[msg.room];
                }
              }
              break;

            // broadcast & send can be used in 2 ways:
            //   1 - (most common): pass a message to the server to a room on which
            //                      a callback was set to trigger a remote action
            //   2 - If some other clients have subscribed to the room, they will
            //       be also notified
            case 'send':
              this.dispatch(msg.room, msg.data);
              this.send(msg.room, msg.data, clientSocket);
              break;
            case 'broadcast':
              this.dispatch(msg.room, msg.data);
              this.broadcast(msg.room, msg.data, clientSocket);
              break;
          }
        });

        clientSocket.on('close', (code, message) => {
          debug('[%s][%s] broker server connection closed with code "%s" and message:\n%O', this.eventName, clientSocket.upgradeReq ? clientSocket.upgradeReq.headers['sec-websocket-key'] : 'unknown identifier', code, message);

          this.pluginsManager.trigger('log:info', `client disconnected [${code}] ${message}`);
          removeClient.call(this, clientSocket);
        });

        clientSocket.on('error', err => {
          debug('[%s][%s] broker server connection errored:\n%O', this.eventName, clientSocket.upgradeReq ? clientSocket.upgradeReq.headers['sec-websocket-key'] : 'unknown identifier', err);

          this.pluginsManager.trigger('log:error', err);
        });
      });

      this.wss.on('error', error => {
        debug('[%s] broker server errored:\n%O', this.eventName, error);

        this.pluginsManager.trigger('log:error', `Connection error: [${error.code}] ${error.message}`);
        this.onErrorHandlers.forEach(f => f());
      });

      resolve();
    });

  });
};

/**
 * Broadcasts `data` to *all* clients that have subscribed to the `room` but
 * the emitter.
 *
 * @param {string} room
 * @param {object} data
 * @param {WebSocket} emitterSocket
 * @returns {int} Number of clients the message was sent to ; -1 if the room does not exist.
 */
WSBrokerServer.prototype.broadcast = function wSBrokerServerBroadcast (room, data, emitterSocket) {
  var
    clients = 0,
    serializedMessage = JSON.stringify({
      room: room,
      data: data
    });

  debug('[%s] broadcast message though broker server in room "%s":\n%O', this.eventName, room, data);

  if (!this.rooms[room]) {
    return -1;
  }

  this.rooms[room].getArray().forEach(clientSocket => {
    if (clientSocket === emitterSocket) {
      return;
    }

    try {
      clientSocket.send(serializedMessage);
      clients++;
    }
    catch (err) {
      // could not broadcast to one child, we let the other ones recieve the message
      this.pluginsManager.trigger('log:error', err);
    }
  });

  return clients;
};

/**
 * Sends `data` to *one* of the *other* clients that has subscribed to the `room`.
 *
 * @param {string} room
 * @param {object} data
 * @param {WebSocket} emitterSocket
 * @returns {WebSocket|undefined} The socket to which the data was sent ; undefined if the room does not exist
 */
WSBrokerServer.prototype.send = function wSBrokerServerSend (room, data, emitterSocket) {
  var clientSocket;

  debug('[%s] sending message though broker server in room "%s":\n%O', this.eventName, room, data);

  if (!this.rooms[room]) {
    return;
  }

  clientSocket = this.rooms[room].getNext();

  if (clientSocket === emitterSocket) {
    if (this.rooms[room].getSize() === 1) {
      return;
    }

    clientSocket = this.rooms[room].getNext();
  }

  clientSocket.send(JSON.stringify({
    room: room,
    data: data
  }));

  return clientSocket;
};

/**
 * Calls all callbacks registered to `room` passing them `data` as argument.
 *
 * @param {string} room
 * @param {object} data
 * @returns {int} the number of triggered callbacks ; -1 if the room does not exist
 */
WSBrokerServer.prototype.dispatch = function wSBrokerServerDispatch (room, data) {
  debug('[%s] broker server dispatching data to room "%s":\n%O', this.eventName, room, data);

  if (!this.handlers[room]) {
    return -1;
  }
  this.handlers[room].forEach(cb => cb(data));

  return this.handlers[room].length;
};

/**
 * Attaches a callback to a `room`
 *
 * @param {string} room
 * @param {function} cb The callback to execute
 */
WSBrokerServer.prototype.listen = function wSBrokerServerListen (room, cb) {
  debug('[%s] broker server subscribed to room "%s"', this.eventName, room);

  if (this.handlers[room] === undefined) {
    this.handlers[room] = [];
  }
  this.handlers[room].push(cb);
};

/**
 * Returns a promise that resolves only when a first client registers itself
 * to the `room`.
 *
 * @param {string} room
 * @returns {Promise}
 */
WSBrokerServer.prototype.waitForClients = function wSBrokerServerWaitForClients (room) {
  var interval;

  if (this.rooms[room]) {
    return Promise.resolve();
  }

  return new Promise(resolve => {
    interval = setInterval(() => {
      if (this.rooms[room]) {
        clearInterval(interval);
        resolve();
      }
    }, 100);
  });
};

/**
 * Stops listening to `room` notifications
 *
 * @param {string} room
 */
WSBrokerServer.prototype.unsubscribe = function wSBrokerServerUnsubscribe (room) {
  debug('[%s] broker server unsubscribed to room "%s"', this.eventName, room);

  if (this.handlers[room]) {
    delete this.handlers[room];
  }
};

/**
 * Closes the server underlying Web socket.
 */
WSBrokerServer.prototype.close = function wSBrokerServerClose () {
  this.wss.close();
  this.wss = null;
};

/**
 * Returns the underlying Websocket.
 *
 * @returns {WS}
 */
WSBrokerServer.prototype.socket = function wSBrokerServerSocket () {
  return this.wss;
};

module.exports = WSBrokerServer;

/**
 * Given a client Web socket, closes it and removes all related subscribtions
 * and callbacks.
 *
 * @this WSBrokerServer
 * @param {WebSocket} clientSocket
 */
function removeClient (clientSocket) {
  clientSocket.close();

  Object.keys(this.rooms).forEach(roomId => {
    this.rooms[roomId].remove(clientSocket);
    if (this.rooms[roomId].getSize() === 0) {
      this.onCloseHandlers.forEach(f => f(roomId));
      delete this.rooms[roomId];
    }
  });
}

<commit_msg>removed unnecessary uses of "...call(this, ..."<commit_after>'use strict';

const
  debug = require('debug')('kuzzle:broker:server'),
  Promise = require('bluebird'),
  CircularList = require('easy-circular-list'),
  InternalError = require('kuzzle-common-objects').errors.InternalError;

// cannot be constant: stubbed in unit tests
let
  fs = require('fs'),
  http = require('http'),
  net = require('net'),
  WS = require('ws').Server;

/**
 * Web Socket server implementation of Kuzzle's internal broker.
 *
 * @param brokerType
 * @param options
 * @param pluginsManager
 * @constructor
 */
function WSBrokerServer (brokerType, options, pluginsManager) {
  this.wss = null;
  this.rooms = {};
  this.handlers = {};
  this.pluginsManager = pluginsManager;
  this.eventName = brokerType;
  this.isDisabled = options.disabled === true;

  this.ws = cb => {
    var
      server = http.createServer(),
      initCB = () => {
        this.wss = new WS({ server }, {perMessageDeflate: false});
        cb();
      };

    this.wss = true;

    if (options.socket) {
      server.on('error', error => {

        if(error.code !== 'EADDRINUSE') {
          debug('[%s] broker server received an error:\n%O', this.eventName, error);

          throw error;
        }

        net.connect(options.socket, () => {
          // really in use, re-throw
          throw error;
        })
          .on('error', e => {
            if (e.code !== 'ECONNREFUSED') {
              debug('[%s] broker server can\'t open requested socket, seem to be already used by another process', this.eventName);

              throw e;
            }

            debug('[%s] broker server can\'t open requested socket, seem to be unused, trying to recreate it', this.eventName);

            fs.unlinkSync(options.socket);

            if (this.wss instanceof WS) {
              this.wss.close(() => {
                server.listen(options.socket);
              });
            }
            else {
              server.listen(options.socket);
            }
          });
      });

      debug('[%s] initialize broker server through socket "%s"', this.eventName, options.socket);

      server.listen(options.socket, initCB);
    }
    else if (options.port) {
      if (options.host) {
        debug('[%s] initialize broker server through net port "%s" on host "%s"', this.eventName, options.port, options.host);

        server.listen(options.port, options.host, initCB);
      }
      else {
        debug('[%s] initialize broker server through net port "%s"', this.eventName, options.port, options.host);

        server.listen(options.port, initCB);
      }
    }
    else {
      throw new InternalError(`Invalid configuration provided for ${this.eventName}. Either "port" or "socket" must be provided.`);
    }
  };

  this.onErrorHandlers = [];
  this.onCloseHandlers = [];
}

/**
 * Initializes the server by setting the underlying ws.WebSocket.Server up.
 *
 * @returns {Promise}
 */
WSBrokerServer.prototype.init = function wSBrokerServerInit () {
  if (this.isDisabled) {
    this.pluginsManager.trigger('log:warn', 'Internal broker disabled by configuration');
    return Promise.resolve();
  }

  if (this.wss) {
    return Promise.reject(new InternalError('Websocket server already started'));
  }

  return new Promise(resolve => {
    this.ws(() => {
      this.wss.on('connection', clientSocket => {

        debug('[%s][%s] broker server received a connection', this.eventName, clientSocket.upgradeReq ? clientSocket.upgradeReq.headers['sec-websocket-key'] : 'unknown identifier');

        clientSocket.on('message', msg => {
          msg = JSON.parse(msg);

          debug('[%s][%s] received a message though broker server connection:\n%O', this.eventName, clientSocket.upgradeReq ? clientSocket.upgradeReq.headers['sec-websocket-key'] : 'unknown identifier', msg);

          switch (msg.action) {
            // the listen action is called by the client to inform the server it
            // wants to be notified on the room activity
            case 'listen':
              if (this.rooms[msg.room] === undefined) {
                this.rooms[msg.room] = new CircularList([]);
              }
              if (this.rooms[msg.room].getArray().indexOf(clientSocket) === -1) {
                this.rooms[msg.room].add(clientSocket);
              }
              break;
            case 'unsubscribe':
              if (this.rooms[msg.room]) {
                this.rooms[msg.room].remove(clientSocket);
                if (this.rooms[msg.room].getSize() === 0) {
                  delete this.rooms[msg.room];
                }
              }
              break;

            // broadcast & send can be used in 2 ways:
            //   1 - (most common): pass a message to the server to a room on which
            //                      a callback was set to trigger a remote action
            //   2 - If some other clients have subscribed to the room, they will
            //       be also notified
            case 'send':
              this.dispatch(msg.room, msg.data);
              this.send(msg.room, msg.data, clientSocket);
              break;
            case 'broadcast':
              this.dispatch(msg.room, msg.data);
              this.broadcast(msg.room, msg.data, clientSocket);
              break;
          }
        });

        clientSocket.on('close', (code, message) => {
          debug('[%s][%s] broker server connection closed with code "%s" and message:\n%O', this.eventName, clientSocket.upgradeReq ? clientSocket.upgradeReq.headers['sec-websocket-key'] : 'unknown identifier', code, message);

          this.pluginsManager.trigger('log:info', `client disconnected [${code}] ${message}`);
          removeClient(this, clientSocket);
        });

        clientSocket.on('error', err => {
          debug('[%s][%s] broker server connection errored:\n%O', this.eventName, clientSocket.upgradeReq ? clientSocket.upgradeReq.headers['sec-websocket-key'] : 'unknown identifier', err);

          this.pluginsManager.trigger('log:error', err);
        });
      });

      this.wss.on('error', error => {
        debug('[%s] broker server errored:\n%O', this.eventName, error);

        this.pluginsManager.trigger('log:error', `Connection error: [${error.code}] ${error.message}`);
        this.onErrorHandlers.forEach(f => f());
      });

      resolve();
    });

  });
};

/**
 * Broadcasts `data` to *all* clients that have subscribed to the `room` but
 * the emitter.
 *
 * @param {string} room
 * @param {object} data
 * @param {WebSocket} emitterSocket
 * @returns {int} Number of clients the message was sent to ; -1 if the room does not exist.
 */
WSBrokerServer.prototype.broadcast = function wSBrokerServerBroadcast (room, data, emitterSocket) {
  var
    clients = 0,
    serializedMessage = JSON.stringify({
      room: room,
      data: data
    });

  debug('[%s] broadcast message though broker server in room "%s":\n%O', this.eventName, room, data);

  if (!this.rooms[room]) {
    return -1;
  }

  this.rooms[room].getArray().forEach(clientSocket => {
    if (clientSocket === emitterSocket) {
      return;
    }

    try {
      clientSocket.send(serializedMessage);
      clients++;
    }
    catch (err) {
      // could not broadcast to one child, we let the other ones recieve the message
      this.pluginsManager.trigger('log:error', err);
    }
  });

  return clients;
};

/**
 * Sends `data` to *one* of the *other* clients that has subscribed to the `room`.
 *
 * @param {string} room
 * @param {object} data
 * @param {WebSocket} emitterSocket
 * @returns {WebSocket|undefined} The socket to which the data was sent ; undefined if the room does not exist
 */
WSBrokerServer.prototype.send = function wSBrokerServerSend (room, data, emitterSocket) {
  var clientSocket;

  debug('[%s] sending message though broker server in room "%s":\n%O', this.eventName, room, data);

  if (!this.rooms[room]) {
    return;
  }

  clientSocket = this.rooms[room].getNext();

  if (clientSocket === emitterSocket) {
    if (this.rooms[room].getSize() === 1) {
      return;
    }

    clientSocket = this.rooms[room].getNext();
  }

  clientSocket.send(JSON.stringify({
    room: room,
    data: data
  }));

  return clientSocket;
};

/**
 * Calls all callbacks registered to `room` passing them `data` as argument.
 *
 * @param {string} room
 * @param {object} data
 * @returns {int} the number of triggered callbacks ; -1 if the room does not exist
 */
WSBrokerServer.prototype.dispatch = function wSBrokerServerDispatch (room, data) {
  debug('[%s] broker server dispatching data to room "%s":\n%O', this.eventName, room, data);

  if (!this.handlers[room]) {
    return -1;
  }
  this.handlers[room].forEach(cb => cb(data));

  return this.handlers[room].length;
};

/**
 * Attaches a callback to a `room`
 *
 * @param {string} room
 * @param {function} cb The callback to execute
 */
WSBrokerServer.prototype.listen = function wSBrokerServerListen (room, cb) {
  debug('[%s] broker server subscribed to room "%s"', this.eventName, room);

  if (this.handlers[room] === undefined) {
    this.handlers[room] = [];
  }
  this.handlers[room].push(cb);
};

/**
 * Returns a promise that resolves only when a first client registers itself
 * to the `room`.
 *
 * @param {string} room
 * @returns {Promise}
 */
WSBrokerServer.prototype.waitForClients = function wSBrokerServerWaitForClients (room) {
  var interval;

  if (this.rooms[room]) {
    return Promise.resolve();
  }

  return new Promise(resolve => {
    interval = setInterval(() => {
      if (this.rooms[room]) {
        clearInterval(interval);
        resolve();
      }
    }, 100);
  });
};

/**
 * Stops listening to `room` notifications
 *
 * @param {string} room
 */
WSBrokerServer.prototype.unsubscribe = function wSBrokerServerUnsubscribe (room) {
  debug('[%s] broker server unsubscribed to room "%s"', this.eventName, room);

  if (this.handlers[room]) {
    delete this.handlers[room];
  }
};

/**
 * Closes the server underlying Web socket.
 */
WSBrokerServer.prototype.close = function wSBrokerServerClose () {
  this.wss.close();
  this.wss = null;
};

/**
 * Returns the underlying Websocket.
 *
 * @returns {WS}
 */
WSBrokerServer.prototype.socket = function wSBrokerServerSocket () {
  return this.wss;
};

module.exports = WSBrokerServer;

/**
 * Given a client Web socket, closes it and removes all related subscribtions
 * and callbacks.
 *
 * @this WSBrokerServer
 * @param {WSBrokerServer} broker
 * @param {WebSocket} clientSocket
 */
function removeClient (broker, clientSocket) {
  clientSocket.close();

  Object.keys(broker.rooms).forEach(roomId => {
    broker.rooms[roomId].remove(clientSocket);
    if (broker.rooms[roomId].getSize() === 0) {
      broker.onCloseHandlers.forEach(f => f(roomId));
      delete broker.rooms[roomId];
    }
  });
}
<|endoftext|>


<commit_before>'use strict';

angular.
  module('eventsApp').
  config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
    function routeConfig($stateProvider, $urlRouterProvider, $locationProvider) {
      $stateProvider
        .state("catalog", {
          url: "/catalog",
          template: "<event-list></event-list>",
          data: {
            pageTitle: "Catalog"
          }
        })
        .state("sessions", {
          url: "/sessions",
          template: "<sessions></sessions>",
          data: {
            pageTitle: "Sessions"
          },
          params: {
            eventid: "eventid"
          }
        });
      /*$locationProvider.html5Mode({
        enabled: true,
        requireBase: false
      });*/
      $urlRouterProvider.otherwise('/catalog');
    }
  ]);<commit_msg>url con id de evento<commit_after>'use strict';

angular.
  module('eventsApp').
  config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
    function routeConfig($stateProvider, $urlRouterProvider, $locationProvider) {
      $stateProvider
        .state("catalog", {
          url: "/catalog",
          template: "<event-list></event-list>",
          data: {
            pageTitle: "Catalog"
          }
        })
        .state("sessions", {
          url: "/sessions/:eventid",
          template: "<sessions></sessions>",
          data: {
            pageTitle: "Sessions"
          }
        });
      /*$locationProvider.html5Mode({
        enabled: true,
        requireBase: false
      });*/
      $urlRouterProvider.otherwise('/catalog');
    }
  ]);<|endoftext|>


<commit_before>
(function ($, cornerstone, cornerstoneWADOImageLoader) {

  "use strict";

  function getTransferSyntaxForContentType(contentType) {
    return '1.2.840.10008.1.2'; // hard code to ILE for now
  }

  function loadImage(imageId, options) {
    var start = new Date().getTime();

    var deferred = $.Deferred();

    var uri = imageId.substring(7);

    // check to make sure we have metadata for this imageId
    var metaData = cornerstoneWADOImageLoader.wadors.metaDataManager.get(imageId);
    if(metaData === undefined) {
      deferred.reject('no metadata for imageId ' + imageId);
      return deferred.promise();
    }

    // TODO: load bulk data items that we might need

    var mediaType;// = 'image/dicom+jp2';

    // get the pixel data from the server
    cornerstoneWADOImageLoader.wadors.getPixelData(uri, imageId, mediaType).then(function(result) {

      var transferSyntax = getTransferSyntaxForContentType(result.contentType);
      var pixelData = result.imageFrame.pixelData;
      var imagePromise = cornerstoneWADOImageLoader.createImage(imageId, pixelData, transferSyntax, options);
      imagePromise.then(function(image) {
        // add the loadTimeInMS property
        var end = new Date().getTime();
        image.loadTimeInMS = end - start;
        deferred.resolve(image);
      })
    }).fail(function(reason) {
      deferred.reject(reason);
    });

    return deferred.promise();
  }

  // register wadors scheme
  cornerstone.registerImageLoader('wadors', loadImage);

}($, cornerstone, cornerstoneWADOImageLoader));<commit_msg>wadors (loadimage) must return a deferred like wadouri does<commit_after>
(function ($, cornerstone, cornerstoneWADOImageLoader) {

  "use strict";

  function getTransferSyntaxForContentType(contentType) {
    return '1.2.840.10008.1.2'; // hard code to ILE for now
  }

  function loadImage(imageId, options) {
    var start = new Date().getTime();

    var deferred = $.Deferred();

    var uri = imageId.substring(7);

    // check to make sure we have metadata for this imageId
    var metaData = cornerstoneWADOImageLoader.wadors.metaDataManager.get(imageId);
    if(metaData === undefined) {
      deferred.reject('no metadata for imageId ' + imageId);
      return deferred.promise();
    }

    // TODO: load bulk data items that we might need

    var mediaType;// = 'image/dicom+jp2';

    // get the pixel data from the server
    cornerstoneWADOImageLoader.wadors.getPixelData(uri, imageId, mediaType).then(function(result) {

      var transferSyntax = getTransferSyntaxForContentType(result.contentType);
      var pixelData = result.imageFrame.pixelData;
      var imagePromise = cornerstoneWADOImageLoader.createImage(imageId, pixelData, transferSyntax, options);
      imagePromise.then(function(image) {
        // add the loadTimeInMS property
        var end = new Date().getTime();
        image.loadTimeInMS = end - start;
        deferred.resolve(image);
      })
    }).fail(function(reason) {
      deferred.reject(reason);
    });

    return deferred;
  }

  // register wadors scheme
  cornerstone.registerImageLoader('wadors', loadImage);

}($, cornerstone, cornerstoneWADOImageLoader));<|endoftext|>


<commit_before>/* @flow */

import _ from "lodash";
import { ansiToText } from "anser";

import { log, char_idx_to_js_idx } from "../../utils";
import type { Store } from "../../store";

type CompleteReply = {
  matches: Array<string>,
  cursor_start: number,
  cursor_end: number,
  metadata?: {
    _jupyter_types_experimental?: Array<{
      start?: number,
      end?: number,
      text: string,
      type?: string
    }>
  }
};

const iconHTML = `<img src='${__dirname}/../../../static/logo.svg' style='width: 100%;'>`;

const regexes = {
  // pretty dodgy, adapted from http://stackoverflow.com/a/8396658
  r: /([^\d\W]|[.])[\w.$]*$/,

  // adapted from http://stackoverflow.com/q/5474008
  python: /([^\d\W]|[\u00A0-\uFFFF])[\w.\u00A0-\uFFFF]*$/,

  // adapted from http://php.net/manual/en/language.variables.basics.php
  php: /[$a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/
};

function parseCompletions(results: CompleteReply, prefix: string) {
  const { matches, metadata } = results;
  let { cursor_start, cursor_end } = results;
  cursor_start = char_idx_to_js_idx(cursor_start, prefix);
  cursor_end = char_idx_to_js_idx(cursor_end, prefix);

  if (metadata && metadata._jupyter_types_experimental) {
    const comps = metadata._jupyter_types_experimental;
    if (comps.length > 0 && comps[0].text) {
      return _.map(comps, match => {
        const text = match.text;
        const start = match.start && match.end ? match.start : cursor_start;
        const end = match.start && match.end ? match.end : cursor_end;
        const replacementPrefix = prefix.slice(start, end);
        const replacedText = prefix.slice(0, start) + text;
        const type = match.type;
        return {
          text,
          replacementPrefix,
          replacedText,
          iconHTML: !type || type === "<unknown>" ? iconHTML : undefined,
          type
        };
      });
    }
  }

  const replacementPrefix = prefix.slice(cursor_start, cursor_end);

  return _.map(matches, match => {
    const text = match;
    const replacedText = prefix.slice(0, cursor_start) + text;
    return {
      text,
      replacementPrefix,
      replacedText,
      iconHTML
    };
  });
}

export function provideAutocompleteResults(
  store: Store
): atom$AutocompleteProvider {
  const autocompleteProvider = {
    selector: ".source",
    disableForSelector: ".comment",

    // The default provider has an inclusion priority of 0.
    inclusionPriority: 1,

    // The default provider has a suggestion priority of 1.
    get suggestionPriority() {
      return atom.config.get("Hydrogen.autocompleteSuggestionPriority");
    },

    // It won't suppress providers with lower priority.
    excludeLowerPriority: false,

    // Required: Return a promise, an array of suggestions, or null.
    getSuggestions({ editor, bufferPosition, prefix }) {
      if (!atom.config.get("Hydrogen.autocomplete")) return null;

      const kernel = store.kernel;
      if (!kernel || kernel.executionState !== "idle") return null;

      const line = editor.getTextInBufferRange([
        [bufferPosition.row, 0],
        bufferPosition
      ]);

      const regex = regexes[kernel.language];
      if (regex) {
        prefix = _.head(line.match(regex)) || "";
      } else {
        prefix = line;
      }

      // return if cursor is at whitespace
      if (prefix.trimRight().length < prefix.length) return null;

      let minimumWordLength = atom.config.get(
        "autocomplete-plus.minimumWordLength"
      );
      if (typeof minimumWordLength !== "number") {
        minimumWordLength = 3;
      }

      if (prefix.trim().length < minimumWordLength) return null;

      log("autocompleteProvider: request:", line, bufferPosition, prefix);

      return new Promise(resolve =>
        kernel.complete(prefix, results => {
          return resolve(parseCompletions(results, prefix));
        })
      );
    },

    getSuggestionDetailsOnSelect({
      text,
      replacementPrefix,
      replacedText,
      iconHTML,
      type
    }) {
      if (!atom.config.get("Hydrogen.showInspectorResultsInAutocomplete"))
        return null;

      const kernel = store.kernel;
      if (!kernel || kernel.executionState !== "idle") return null;

      return new Promise(resolve => {
        kernel.inspect(replacedText, replacedText.length, ({ data, found }) => {
          if (!found || !data["text/plain"]) resolve(null);
          resolve({
            text,
            replacementPrefix,
            replacedText,
            iconHTML,
            type,
            description: ansiToText(data["text/plain"])
          });
        });
      });
    }
  };

  return autocompleteProvider;
}
<commit_msg>Fixup #1658<commit_after>/* @flow */

import _ from "lodash";
import { ansiToText } from "anser";

import { log, char_idx_to_js_idx } from "../../utils";
import type { Store } from "../../store";

type CompleteReply = {
  matches: Array<string>,
  cursor_start: number,
  cursor_end: number,
  metadata?: {
    _jupyter_types_experimental?: Array<{
      start?: number,
      end?: number,
      text: string,
      type?: string
    }>
  }
};

const iconHTML = `<img src='${__dirname}/../../../static/logo.svg' style='width: 100%;'>`;

const regexes = {
  // pretty dodgy, adapted from http://stackoverflow.com/a/8396658
  r: /([^\d\W]|[.])[\w.$]*$/,

  // adapted from http://stackoverflow.com/q/5474008
  python: /([^\d\W]|[\u00A0-\uFFFF])[\w.\u00A0-\uFFFF]*$/,

  // adapted from http://php.net/manual/en/language.variables.basics.php
  php: /[$a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/
};

function parseCompletions(results: CompleteReply, prefix: string) {
  const { matches, metadata } = results;
  const cursor_start = results.cursor_start;
  const cursor_end = char_idx_to_js_idx(results.cursor_end, prefix);

  if (metadata && metadata._jupyter_types_experimental) {
    const comps = metadata._jupyter_types_experimental;
    if (comps.length > 0 && comps[0].text) {
      return _.map(comps, match => {
        const text = match.text;
        const start = match.start && match.end ? match.start : cursor_start;
        const end = match.start && match.end ? match.end : cursor_end;
        const replacementPrefix = prefix.slice(start, end);
        const replacedText = prefix.slice(0, start) + text;
        const type = match.type;
        return {
          text,
          replacementPrefix,
          replacedText,
          iconHTML: !type || type === "<unknown>" ? iconHTML : undefined,
          type
        };
      });
    }
  }

  const replacementPrefix = prefix.slice(cursor_start, cursor_end);

  return _.map(matches, match => {
    const text = match;
    const replacedText = prefix.slice(0, cursor_start) + text;
    return {
      text,
      replacementPrefix,
      replacedText,
      iconHTML
    };
  });
}

export function provideAutocompleteResults(
  store: Store
): atom$AutocompleteProvider {
  const autocompleteProvider = {
    selector: ".source",
    disableForSelector: ".comment",

    // The default provider has an inclusion priority of 0.
    inclusionPriority: 1,

    // The default provider has a suggestion priority of 1.
    get suggestionPriority() {
      return atom.config.get("Hydrogen.autocompleteSuggestionPriority");
    },

    // It won't suppress providers with lower priority.
    excludeLowerPriority: false,

    // Required: Return a promise, an array of suggestions, or null.
    getSuggestions({ editor, bufferPosition, prefix }) {
      if (!atom.config.get("Hydrogen.autocomplete")) return null;

      const kernel = store.kernel;
      if (!kernel || kernel.executionState !== "idle") return null;

      const line = editor.getTextInBufferRange([
        [bufferPosition.row, 0],
        bufferPosition
      ]);

      const regex = regexes[kernel.language];
      if (regex) {
        prefix = _.head(line.match(regex)) || "";
      } else {
        prefix = line;
      }

      // return if cursor is at whitespace
      if (prefix.trimRight().length < prefix.length) return null;

      let minimumWordLength = atom.config.get(
        "autocomplete-plus.minimumWordLength"
      );
      if (typeof minimumWordLength !== "number") {
        minimumWordLength = 3;
      }

      if (prefix.trim().length < minimumWordLength) return null;

      log("autocompleteProvider: request:", line, bufferPosition, prefix);

      return new Promise(resolve =>
        kernel.complete(prefix, results => {
          return resolve(parseCompletions(results, prefix));
        })
      );
    },

    getSuggestionDetailsOnSelect({
      text,
      replacementPrefix,
      replacedText,
      iconHTML,
      type
    }) {
      if (!atom.config.get("Hydrogen.showInspectorResultsInAutocomplete"))
        return null;

      const kernel = store.kernel;
      if (!kernel || kernel.executionState !== "idle") return null;

      return new Promise(resolve => {
        kernel.inspect(replacedText, replacedText.length, ({ data, found }) => {
          if (!found || !data["text/plain"]) resolve(null);
          resolve({
            text,
            replacementPrefix,
            replacedText,
            iconHTML,
            type,
            description: ansiToText(data["text/plain"])
          });
        });
      });
    }
  };

  return autocompleteProvider;
}
<|endoftext|>


<commit_before>/*
 * l10n.js
 * 2014-05-02
 *
 * By Eli Grey, http://eligrey.com
 * Licensed under the X11/MIT License
 *   See https://github.com/eligrey/l10n.js/blob/master/LICENSE.md
 */

/*global XMLHttpRequest, setTimeout, document, navigator, ActiveXObject*/

/*! @source http://purl.eligrey.com/github/l10n.js/blob/master/l10n.js*/

(function () {
"use strict";

var
  undef_type = "undefined"
, string_type = "string"
, nav = self.navigator
, String_ctr = String
, has_own_prop = Object.prototype.hasOwnProperty
, load_queues = {}
, localizations = {}
, FALSE = !1
, TRUE = !0
// the official format is application/vnd.oftn.l10n+json, though l10n.js will also
// accept application/x-l10n+json and application/l10n+json
, l10n_js_media_type = /^\s*application\/(?:vnd\.oftn\.|x-)?l10n\+json\s*(?:$|;)/i
, XHR

// property minification aids
, $locale = "locale"
, $default_locale = "defaultLocale"
, $to_locale_string = "toLocaleString"
, $to_lowercase = "toLowerCase"

, array_index_of = Array.prototype.indexOf || function (item) {
	var
	  len = this.length
	, i   = 0
	;

	for (; i < len; i++) {
		if (i in this && this[i] === item) {
			return i;
		}
	}

	return -1;
}
, request_JSON = function (uri) {
	var req = new XHR();

	// sadly, this has to be blocking to allow for a graceful degrading API
	req.open("GET", uri, FALSE);
	req.send(null);

	if (req.status !== 200) {
		// warn about error without stopping execution
		setTimeout(function () {
			// Error messages are not localized as not to cause an infinite loop
			var l10n_err = new Error("Unable to load localization data: " + uri);
			l10n_err.name = "Localization Error";
			throw l10n_err;
		}, 0);

		return {};
	} else {
		return JSON.parse(req.responseText);
	}
}
, load = String_ctr[$to_locale_string] = function (data) {
	// don't handle function.toLocaleString(indentationAmount:Number)
	if (arguments.length > 0 && typeof data !== "number") {
		if (typeof data === string_type) {
			load(request_JSON(data));
		} else if (data === FALSE) {
			// reset all localizations
			localizations = {};
		} else {
			// Extend current localizations instead of completely overwriting them
			var locale, localization, message;
			for (locale in data) {
				if (has_own_prop.call(data, locale)) {
					localization = data[locale];
					locale = locale[$to_lowercase]();

					if (!(locale in localizations) || localization === FALSE) {
						// reset locale if not existing or reset flag is specified
						localizations[locale] = {};
					}

					if (localization === FALSE) {
						continue;
					}

					// URL specified
					if (typeof localization === string_type) {
						if (String_ctr[$locale][$to_lowercase]().indexOf(locale) === 0) {
							localization = request_JSON(localization);
						} else {
							// queue loading locale if not needed
							if (!(locale in load_queues)) {
								load_queues[locale] = [];
							}
							load_queues[locale].push(localization);
							continue;
						}
					}

					for (message in localization) {
						if (has_own_prop.call(localization, message)) {
							localizations[locale][message] = localization[message];
						}
					}
				}
			}
		}
	}
	// Return what function.toLocaleString() normally returns
	return Function.prototype[$to_locale_string].apply(String_ctr, arguments);
}
, process_load_queue = function (locale) {
	var
	  queue = load_queues[locale]
	, i = 0
	, len = queue.length
	, localization
	;

	for (; i < len; i++) {
		localization = {};
		localization[locale] = request_JSON(queue[i]);
		load(localization);
	}

	delete load_queues[locale];
}
, use_default
, localize = String_ctr.prototype[$to_locale_string] = function () {
	var
	  using_default = use_default
	, current_locale = String_ctr[using_default ? $default_locale : $locale]
	, parts = current_locale[$to_lowercase]().split("-")
	, i = parts.length
	, this_val = this.valueOf()
	, locale
	;

	use_default = FALSE;

	// Iterate through locales starting at most-specific until a localization is found
	do {
		locale = parts.slice(0, i).join("-");
		// load locale if not loaded
		if (locale in load_queues) {
			process_load_queue(locale);
		}
		if (locale in localizations && this_val in localizations[locale]) {
			return localizations[locale][this_val];
		}
	}
	while (i --> 1);

	if (!using_default && String_ctr[$default_locale]) {
		use_default = TRUE;
		return localize.call(this_val);
	}

	return this_val;
}
;

if (typeof XMLHttpRequest === undef_type && typeof ActiveXObject !== undef_type) {
	var AXO = ActiveXObject;

	XHR = function () {
		try {
			return new AXO("Msxml2.XMLHTTP.6.0");
		} catch (xhrEx1) {}
		try {
			return new AXO("Msxml2.XMLHTTP.3.0");
		} catch (xhrEx2) {}
		try {
			return new AXO("Msxml2.XMLHTTP");
		} catch (xhrEx3) {}

		throw new Error("XMLHttpRequest not supported by this browser.");
	};
} else {
	XHR = XMLHttpRequest;
}

String_ctr[$default_locale] = String_ctr[$default_locale] || "";
String_ctr[$locale] = nav && (nav.language || nav.userLanguage) || "";

if (typeof document !== undef_type) {
	var
	  elts = document.getElementsByTagName("link")
	, i = elts.length
	, localization
	;

	while (i--) {
		var
		  elt = elts[i]
		, rel = (elt.getAttribute("rel") || "")[$to_lowercase]().split(/\s+/)
		;

		if (l10n_js_media_type.test(elt.type)) {
			if (array_index_of.call(rel, "localizations") !== -1) {
				// multiple localizations
				load(elt.getAttribute("href"));
			} else if (array_index_of.call(rel, "localization") !== -1) {
				// single localization
				localization = {};
				localization[(elt.getAttribute("hreflang") || "")[$to_lowercase]()] =
					elt.getAttribute("href");
				load(localization);
			}
		}
	}
}

}());
<commit_msg>Status codes can be inconsistent across browsers so it is safer to base success/failure of loading a JSON file on being able to successfully parse it. This deals with failed requests (missing files) as well as malformed jSON files.<commit_after>/*
 * l10n.js
 * 2014-05-02
 *
 * By Eli Grey, http://eligrey.com
 * Licensed under the X11/MIT License
 *   See https://github.com/eligrey/l10n.js/blob/master/LICENSE.md
 */

/*global XMLHttpRequest, setTimeout, document, navigator, ActiveXObject*/

/*! @source http://purl.eligrey.com/github/l10n.js/blob/master/l10n.js*/

(function () {
"use strict";

var
  undef_type = "undefined"
, string_type = "string"
, nav = self.navigator
, String_ctr = String
, has_own_prop = Object.prototype.hasOwnProperty
, load_queues = {}
, localizations = {}
, FALSE = !1
, TRUE = !0
// the official format is application/vnd.oftn.l10n+json, though l10n.js will also
// accept application/x-l10n+json and application/l10n+json
, l10n_js_media_type = /^\s*application\/(?:vnd\.oftn\.|x-)?l10n\+json\s*(?:$|;)/i
, XHR

// property minification aids
, $locale = "locale"
, $default_locale = "defaultLocale"
, $to_locale_string = "toLocaleString"
, $to_lowercase = "toLowerCase"

, array_index_of = Array.prototype.indexOf || function (item) {
	var
	  len = this.length
	, i   = 0
	;

	for (; i < len; i++) {
		if (i in this && this[i] === item) {
			return i;
		}
	}

	return -1;
}
, request_JSON = function (uri) {
	var req  = new XHR(),
		data = {};

	// sadly, this has to be blocking to allow for a graceful degrading API
	req.open("GET", uri, FALSE);
	req.send(null);

	// Status codes can be inconsistent across browsers so we simply try to parse
	// the response text and catch any errors. This deals with failed requests as
	// well as malformed json files.
	try {
		data = JSON.parse(req.responseText);
	} catch(e) {
		// warn about error without stopping execution
		setTimeout(function () {
			// Error messages are not localized as not to cause an infinite loop
			var l10n_err = new Error("Unable to load localization data: " + uri);
			l10n_err.name = "Localization Error";
			throw l10n_err;
		}, 0);
	}

	return data;
}
, load = String_ctr[$to_locale_string] = function (data) {
	// don't handle function.toLocaleString(indentationAmount:Number)
	if (arguments.length > 0 && typeof data !== "number") {
		if (typeof data === string_type) {
			load(request_JSON(data));
		} else if (data === FALSE) {
			// reset all localizations
			localizations = {};
		} else {
			// Extend current localizations instead of completely overwriting them
			var locale, localization, message;
			for (locale in data) {
				if (has_own_prop.call(data, locale)) {
					localization = data[locale];
					locale = locale[$to_lowercase]();

					if (!(locale in localizations) || localization === FALSE) {
						// reset locale if not existing or reset flag is specified
						localizations[locale] = {};
					}

					if (localization === FALSE) {
						continue;
					}

					// URL specified
					if (typeof localization === string_type) {
						if (String_ctr[$locale][$to_lowercase]().indexOf(locale) === 0) {
							localization = request_JSON(localization);
						} else {
							// queue loading locale if not needed
							if (!(locale in load_queues)) {
								load_queues[locale] = [];
							}
							load_queues[locale].push(localization);
							continue;
						}
					}

					for (message in localization) {
						if (has_own_prop.call(localization, message)) {
							localizations[locale][message] = localization[message];
						}
					}
				}
			}
		}
	}
	// Return what function.toLocaleString() normally returns
	return Function.prototype[$to_locale_string].apply(String_ctr, arguments);
}
, process_load_queue = function (locale) {
	var
	  queue = load_queues[locale]
	, i = 0
	, len = queue.length
	, localization
	;

	for (; i < len; i++) {
		localization = {};
		localization[locale] = request_JSON(queue[i]);
		load(localization);
	}

	delete load_queues[locale];
}
, use_default
, localize = String_ctr.prototype[$to_locale_string] = function () {
	var
	  using_default = use_default
	, current_locale = String_ctr[using_default ? $default_locale : $locale]
	, parts = current_locale[$to_lowercase]().split("-")
	, i = parts.length
	, this_val = this.valueOf()
	, locale
	;

	use_default = FALSE;

	// Iterate through locales starting at most-specific until a localization is found
	do {
		locale = parts.slice(0, i).join("-");
		// load locale if not loaded
		if (locale in load_queues) {
			process_load_queue(locale);
		}
		if (locale in localizations && this_val in localizations[locale]) {
			return localizations[locale][this_val];
		}
	}
	while (i --> 1);

	if (!using_default && String_ctr[$default_locale]) {
		use_default = TRUE;
		return localize.call(this_val);
	}

	return this_val;
}
;

if (typeof XMLHttpRequest === undef_type && typeof ActiveXObject !== undef_type) {
	var AXO = ActiveXObject;

	XHR = function () {
		try {
			return new AXO("Msxml2.XMLHTTP.6.0");
		} catch (xhrEx1) {}
		try {
			return new AXO("Msxml2.XMLHTTP.3.0");
		} catch (xhrEx2) {}
		try {
			return new AXO("Msxml2.XMLHTTP");
		} catch (xhrEx3) {}

		throw new Error("XMLHttpRequest not supported by this browser.");
	};
} else {
	XHR = XMLHttpRequest;
}

String_ctr[$default_locale] = String_ctr[$default_locale] || "";
String_ctr[$locale] = nav && (nav.language || nav.userLanguage) || "";

if (typeof document !== undef_type) {
	var
	  elts = document.getElementsByTagName("link")
	, i = elts.length
	, localization
	;

	while (i--) {
		var
		  elt = elts[i]
		, rel = (elt.getAttribute("rel") || "")[$to_lowercase]().split(/\s+/)
		;

		if (l10n_js_media_type.test(elt.type)) {
			if (array_index_of.call(rel, "localizations") !== -1) {
				// multiple localizations
				load(elt.getAttribute("href"));
			} else if (array_index_of.call(rel, "localization") !== -1) {
				// single localization
				localization = {};
				localization[(elt.getAttribute("hreflang") || "")[$to_lowercase]()] =
					elt.getAttribute("href");
				load(localization);
			}
		}
	}
}

}());
<|endoftext|>


<commit_before>/**
 * @ngdoc directive
 * @memberof ngmap
 * @name custom-marker
 * @param Attr2Options {service} convert html attribute to Gogole map api options
 * @param $timeout {service} AngularJS $timeout
 * @description
 *   Marker with html
 *   Requires:  map directive
 *   Restrict To:  Element
 *
 * @attr {String} position required, position on map
 * @attr {Number} z-index optional
 * @attr {Boolean} visible optional
 * @example
 *
 * Example:
 *   <map center="41.850033,-87.6500523" zoom="3">
 *     <custom-marker position="41.850033,-87.6500523">
 *

 *         Home
 *

 *     </custom-marker>
 *   </map>
 *
 */
/* global document */
(function() {
  'use strict';
  var parser, $timeout, $compile, NgMap;

  var CustomMarker = function(options) {
    options = options || {};

    this.el = document.createElement('div');
    this.el.style.display = 'inline-block';
    this.el.style.visibility = "hidden";
    this.visible = true;
    for (var key in options) { /* jshint ignore:line */
     this[key] = options[key];
    }
  };

  var setCustomMarker = function() {

    CustomMarker.prototype = new google.maps.OverlayView();

    CustomMarker.prototype.setContent = function(html, scope) {
      this.el.innerHTML = html;
      this.el.style.position = 'absolute';
      if (scope) {
        $compile(angular.element(this.el).contents())(scope);
      }
    };

    CustomMarker.prototype.getDraggable = function() {
      return this.draggable;
    };

    CustomMarker.prototype.setDraggable = function(draggable) {
      this.draggable = draggable;
    };

    CustomMarker.prototype.getPosition = function() {
      return this.position;
    };

    CustomMarker.prototype.setPosition = function(position) {
      position && (this.position = position); /* jshint ignore:line */

      if (this.getProjection() && typeof this.position.lng == 'function') {
        var posPixel = this.getProjection().fromLatLngToDivPixel(this.position);
        var _this = this;
        var setPosition = function() {
          var x = Math.round(posPixel.x - (_this.el.offsetWidth/2));
          var y = Math.round(posPixel.y - _this.el.offsetHeight - 10); // 10px for anchor
          _this.el.style.left = x + "px";
          _this.el.style.top = y + "px";
          _this.el.style.visibility = "visible";
        };
        if (_this.el.offsetWidth && _this.el.offsetHeight) {
          setPosition();
        } else {
          //delayed left/top calculation when width/height are not set instantly
          $timeout(setPosition, 300);
        }
      }
    };

    CustomMarker.prototype.setZIndex = function(zIndex) {
      zIndex && (this.zIndex = zIndex); /* jshint ignore:line */
      this.el.style.zIndex = this.zIndex;
    };

    CustomMarker.prototype.getVisible = function() {
      return this.visible;
    };

    CustomMarker.prototype.setVisible = function(visible) {
      this.el.style.display = visible ? 'inline-block' : 'none';
      this.visible = visible;
    };

    CustomMarker.prototype.addClass = function(className) {
      var classNames = this.el.className.trim().split(' ');
      (classNames.indexOf(className) == -1) && classNames.push(className); /* jshint ignore:line */
      this.el.className = classNames.join(' ');
    };

    CustomMarker.prototype.removeClass = function(className) {
      var classNames = this.el.className.split(' ');
      var index = classNames.indexOf(className);
      (index > -1) && classNames.splice(index, 1); /* jshint ignore:line */
      this.el.className = classNames.join(' ');
    };

    CustomMarker.prototype.onAdd = function() {
      this.getPanes().overlayMouseTarget.appendChild(this.el);
    };

    CustomMarker.prototype.draw = function() {
      this.setPosition();
      this.setZIndex(this.zIndex);
      this.setVisible(this.visible);
    };

    CustomMarker.prototype.onRemove = function() {
      this.el.parentNode.removeChild(this.el);
      //this.el = null;
    };
  };

  var linkFunc = function(orgHtml, varsToWatch) {
    //console.log('orgHtml', orgHtml, 'varsToWatch', varsToWatch);

    return function(scope, element, attrs, mapController) {
      mapController = mapController[0]||mapController[1];
      var orgAttrs = parser.orgAttributes(element);

      var filtered = parser.filter(attrs);
      var options = parser.getOptions(filtered, {scope: scope});
      var events = parser.getEvents(scope, filtered);

      /**
       * build a custom marker element
       */
      element[0].style.display = 'none';
      console.log("custom-marker options", options);
      var customMarker = new CustomMarker(options);

	  scope.$watch('[' + varsToWatch.join(',') + ']', function() {
	    customMarker.setContent(orgHtml, scope);
	  }, true);

	  customMarker.setContent(element[0].innerHTML, scope);
	  var classNames = element[0].firstElementChild.className;
	  customMarker.addClass('custom-marker');
	  customMarker.addClass(classNames);
	  console.log('customMarker', customMarker, 'classNames', classNames);

	  if (!(options.position instanceof google.maps.LatLng)) {
	    NgMap.getGeoLocation(options.position).then(
		  function(latlng) {
		    customMarker.setPosition(latlng);
		  }
	    );
	  }

      console.log("custom-marker events", "events");
      for (var eventName in events) { /* jshint ignore:line */
        google.maps.event.addDomListener(
          customMarker.el, eventName, events[eventName]);
      }
      mapController.addObject('customMarkers', customMarker);

      //set observers
      mapController.observeAttrSetObj(orgAttrs, attrs, customMarker);

      element.bind('$destroy', function() {
        //Is it required to remove event listeners when DOM is removed?
        mapController.deleteObject('customMarkers', customMarker);
      });

    }; // linkFunc
  };

  var customMarkerDirective = function(
      _$timeout_, _$compile_, Attr2MapOptions, _NgMap_
    )  {
    parser = Attr2MapOptions;
    $timeout = _$timeout_;
    $compile = _$compile_;
    NgMap = _NgMap_;

    return {
      restrict: 'E',
      require: ['?^map','?^ngMap'],
      compile: function(element) {
        setCustomMarker();
        element[0].style.display ='none';
        var orgHtml = element.html();
        var matches = orgHtml.match(/{{([^}]+)}}/g);
        var varsToWatch = [];
        //filter out that contains '::', 'this.'
        (matches || []).forEach(function(match) {
          var toWatch = match.replace('{{','').replace('}}','');
          if (match.indexOf('::') == -1 &&
            match.indexOf('this.') == -1 &&
            varsToWatch.indexOf(toWatch) == -1) {
            varsToWatch.push(match.replace('{{','').replace('}}',''));
          }
        });

        return linkFunc(orgHtml, varsToWatch);
      }
    }; // return
  };// function
  customMarkerDirective.$inject =
    ['$timeout', '$compile', 'Attr2MapOptions', 'NgMap'];

  angular.module('ngMap').directive('customMarker', customMarkerDirective);
})();
<commit_msg>#558, reverted changes<commit_after>/**
 * @ngdoc directive
 * @memberof ngmap
 * @name custom-marker
 * @param Attr2Options {service} convert html attribute to Gogole map api options
 * @param $timeout {service} AngularJS $timeout
 * @description
 *   Marker with html
 *   Requires:  map directive
 *   Restrict To:  Element
 *
 * @attr {String} position required, position on map
 * @attr {Number} z-index optional
 * @attr {Boolean} visible optional
 * @example
 *
 * Example:
 *   <map center="41.850033,-87.6500523" zoom="3">
 *     <custom-marker position="41.850033,-87.6500523">
 *

 *         Home
 *

 *     </custom-marker>
 *   </map>
 *
 */
/* global document */
(function() {
  'use strict';
  var parser, $timeout, $compile, NgMap;

  var CustomMarker = function(options) {
    options = options || {};

    this.el = document.createElement('div');
    this.el.style.display = 'inline-block';
    this.el.style.visibility = "hidden";
    this.visible = true;
    for (var key in options) { /* jshint ignore:line */
     this[key] = options[key];
    }
  };

  var setCustomMarker = function() {

    CustomMarker.prototype = new google.maps.OverlayView();

    CustomMarker.prototype.setContent = function(html, scope) {
      this.el.innerHTML = html;
      this.el.style.position = 'absolute';
      if (scope) {
        $compile(angular.element(this.el).contents())(scope);
      }
    };

    CustomMarker.prototype.getDraggable = function() {
      return this.draggable;
    };

    CustomMarker.prototype.setDraggable = function(draggable) {
      this.draggable = draggable;
    };

    CustomMarker.prototype.getPosition = function() {
      return this.position;
    };

    CustomMarker.prototype.setPosition = function(position) {
      position && (this.position = position); /* jshint ignore:line */

      if (this.getProjection() && typeof this.position.lng == 'function') {
        var posPixel = this.getProjection().fromLatLngToDivPixel(this.position);
        var _this = this;
        var setPosition = function() {
          var x = Math.round(posPixel.x - (_this.el.offsetWidth/2));
          var y = Math.round(posPixel.y - _this.el.offsetHeight - 10); // 10px for anchor
          _this.el.style.left = x + "px";
          _this.el.style.top = y + "px";
          _this.el.style.visibility = "visible";
        };
        if (_this.el.offsetWidth && _this.el.offsetHeight) {
          setPosition();
        } else {
          //delayed left/top calculation when width/height are not set instantly
          $timeout(setPosition, 300);
        }
      }
    };

    CustomMarker.prototype.setZIndex = function(zIndex) {
      zIndex && (this.zIndex = zIndex); /* jshint ignore:line */
      this.el.style.zIndex = this.zIndex;
    };

    CustomMarker.prototype.getVisible = function() {
      return this.visible;
    };

    CustomMarker.prototype.setVisible = function(visible) {
      this.el.style.display = visible ? 'inline-block' : 'none';
      this.visible = visible;
    };

    CustomMarker.prototype.addClass = function(className) {
      var classNames = this.el.className.trim().split(' ');
      (classNames.indexOf(className) == -1) && classNames.push(className); /* jshint ignore:line */
      this.el.className = classNames.join(' ');
    };

    CustomMarker.prototype.removeClass = function(className) {
      var classNames = this.el.className.split(' ');
      var index = classNames.indexOf(className);
      (index > -1) && classNames.splice(index, 1); /* jshint ignore:line */
      this.el.className = classNames.join(' ');
    };

    CustomMarker.prototype.onAdd = function() {
      this.getPanes().overlayMouseTarget.appendChild(this.el);
    };

    CustomMarker.prototype.draw = function() {
      this.setPosition();
      this.setZIndex(this.zIndex);
      this.setVisible(this.visible);
    };

    CustomMarker.prototype.onRemove = function() {
      this.el.parentNode.removeChild(this.el);
      //this.el = null;
    };
  };

  var linkFunc = function(orgHtml, varsToWatch) {
    //console.log('orgHtml', orgHtml, 'varsToWatch', varsToWatch);

    return function(scope, element, attrs, mapController) {
      mapController = mapController[0]||mapController[1];
      var orgAttrs = parser.orgAttributes(element);

      var filtered = parser.filter(attrs);
      var options = parser.getOptions(filtered, {scope: scope});
      var events = parser.getEvents(scope, filtered);

      /**
       * build a custom marker element
       */
      element[0].style.display = 'none';
      console.log("custom-marker options", options);
      var customMarker = new CustomMarker(options);

      $timeout(function() { //apply contents, class, and location after it is compiled

        scope.$watch('[' + varsToWatch.join(',') + ']', function() {
          customMarker.setContent(orgHtml, scope);
        }, true);

        customMarker.setContent(element[0].innerHTML, scope);
        var classNames = element[0].firstElementChild.className;
        customMarker.addClass('custom-marker');
        customMarker.addClass(classNames);
        console.log('customMarker', customMarker, 'classNames', classNames);

        if (!(options.position instanceof google.maps.LatLng)) {
          NgMap.getGeoLocation(options.position).then(
                function(latlng) {
                  customMarker.setPosition(latlng);
                }
          );
        }

      });

      console.log("custom-marker events", "events");
      for (var eventName in events) { /* jshint ignore:line */
        google.maps.event.addDomListener(
          customMarker.el, eventName, events[eventName]);
      }
      mapController.addObject('customMarkers', customMarker);

      //set observers
      mapController.observeAttrSetObj(orgAttrs, attrs, customMarker);

      element.bind('$destroy', function() {
        //Is it required to remove event listeners when DOM is removed?
        mapController.deleteObject('customMarkers', customMarker);
      });

    }; // linkFunc
  };

  var customMarkerDirective = function(
      _$timeout_, _$compile_, Attr2MapOptions, _NgMap_
    )  {
    parser = Attr2MapOptions;
    $timeout = _$timeout_;
    $compile = _$compile_;
    NgMap = _NgMap_;

    return {
      restrict: 'E',
      require: ['?^map','?^ngMap'],
      compile: function(element) {
        setCustomMarker();
        element[0].style.display ='none';
        var orgHtml = element.html();
        var matches = orgHtml.match(/{{([^}]+)}}/g);
        var varsToWatch = [];
        //filter out that contains '::', 'this.'
        (matches || []).forEach(function(match) {
          var toWatch = match.replace('{{','').replace('}}','');
          if (match.indexOf('::') == -1 &&
            match.indexOf('this.') == -1 &&
            varsToWatch.indexOf(toWatch) == -1) {
            varsToWatch.push(match.replace('{{','').replace('}}',''));
          }
        });

        return linkFunc(orgHtml, varsToWatch);
      }
    }; // return
  };// function
  customMarkerDirective.$inject =
    ['$timeout', '$compile', 'Attr2MapOptions', 'NgMap'];

  angular.module('ngMap').directive('customMarker', customMarkerDirective);
})();
<|endoftext|>


<commit_before>/**
 * Background
 *
 * This is main Electron process, started first thing when your app launches.
 * This script runs through entire life of your application. It doesn't have
 * any windows that you can see on screen, but we can open windows from here.
 */

import jetpack from 'fs-jetpack';

// Base electron modules
import { app, BrowserWindow, globalShortcut } from 'electron';

let childProcess = require('child_process');
let promisedExec = childProcess.exec;

// Development helper for showing Chromium Dev Tools
import devHelper from './vendor/electron_boilerplate/dev_helper';

// Special module holding environment variables which you declared
// in config/env_xxx.json file.
import env from './env';

import os from 'os';

let mainWindow;
app.on('ready', function () {

  mainWindow = new BrowserWindow({
    x: 0,
    y: 0,
    width: 800,
    height: 600,
  });

  /**
   * Hack to make fullscreen kiosk mode actually work.
   *
   * There is an active bug with Electron, kiosk mode, and Yosemite.
   * https://github.com/atom/electron/issues/1054
   * This hack makes kiosk mode actually work by waiting for the app to launch
   * and then issuing a call to go into kiosk mode after a few milliseconds.
   */
  if (env.name == 'production') {
    setTimeout(function () {
      mainWindow.setKiosk(true);
    }, 100);
  }

  /**
   * Show dev tools when we're not in production mode
   */
  if (env.name !== 'production') {
    devHelper.setDevMenu();
    mainWindow.openDevTools();
  }

  /**
   * Open the app
   */
  if (env.name === 'test') {
    mainWindow.loadURL('file://' + __dirname + '/spec.html');
  } else {
    const configFile = '/usr/local/etc/kiosk/config.json';
    loadWindowConfigFile(configFile);
  }

  /**
   * Keyboard shortcuts
   *
   * Ctrl or Command + f will switch you to the Finder.
   * We use the "switch to Finder" approach instead of a quit, because in most
   * of our Electron setups we have a launchd process that will relaunch the
   * app on quit. For maintenance, we probably just need to be able to get
   * to the Finder while the application remains running in the background.
   */
  const ret = globalShortcut.register('CommandOrControl+F', () => {
    console.log('Switching to Finder');
    promisedExec('open -a Finder');
  });
  if (!ret) {
    console.log('Keyboard registration failed');
  }

});

function loadWindowConfigFile(configFile) {
  const configFileObj = jetpack.read(configFile, 'json');
  console.log('configFileObj: ', configFileObj);
  if (configFileObj !== null) {
    loadWindowUptimeDelay(configFileObj);
  } else {
    console.log('Config file [' + configFile + '] not present.');
    mainWindow.loadURL('file://' + __dirname + '/config-error.html');
  }
}

function loadWindowUptimeDelay(configFileObj) {
  // Seconds since launch, when it will be safe to load the URL
  const nominalUptime = 300;

  // Seconds to wait if we are not in the nominal uptime window
  const launchDelay = 60;

  console.log('os.uptime(): ', os.uptime());
  console.log('nominalUptime: ', nominalUptime);

  if (os.uptime() > nominalUptime) {
    console.log('Launching immediately');
    mainWindow.loadURL(configFileObj.url);
  } else {
    console.log('Delaying launch ' + launchDelay + ' seconds');
    mainWindow.loadURL('file://' + __dirname + '/launch-delay.html');
    setTimeout(function () {
      mainWindow.loadURL(configFileObj.url);
    }, launchDelay * 1000);
  }

}

app.on('window-all-closed', function () {
  app.quit();
});
<commit_msg>Spelling fix<commit_after>/**
 * Background
 *
 * This is main Electron process, started first thing when your app launches.
 * This script runs through entire life of your application. It doesn't have
 * any windows that you can see on screen, but we can open windows from here.
 */

import jetpack from 'fs-jetpack';

// Base electron modules
import { app, BrowserWindow, globalShortcut } from 'electron';

let childProcess = require('child_process');
let promisedExec = childProcess.exec;

// Development helper for showing Chromium Dev Tools
import devHelper from './vendor/electron_boilerplate/dev_helper';

// Special module holding environment variables which you declared
// in config/env_xxx.json file.
import env from './env';

import os from 'os';

let mainWindow;
app.on('ready', function () {

  mainWindow = new BrowserWindow({
    x: 0,
    y: 0,
    width: 800,
    height: 600,
  });

  /**
   * Hack to make full-screen kiosk mode actually work.
   *
   * There is an active bug with Electron, kiosk mode, and Yosemite.
   * https://github.com/atom/electron/issues/1054
   * This hack makes kiosk mode actually work by waiting for the app to launch
   * and then issuing a call to go into kiosk mode after a few milliseconds.
   */
  if (env.name == 'production') {
    setTimeout(function () {
      mainWindow.setKiosk(true);
    }, 100);
  }

  /**
   * Show dev tools when we're not in production mode
   */
  if (env.name !== 'production') {
    devHelper.setDevMenu();
    mainWindow.openDevTools();
  }

  /**
   * Open the app
   */
  if (env.name === 'test') {
    mainWindow.loadURL('file://' + __dirname + '/spec.html');
  } else {
    const configFile = '/usr/local/etc/kiosk/config.json';
    loadWindowConfigFile(configFile);
  }

  /**
   * Keyboard shortcuts
   *
   * Ctrl or Command + f will switch you to the Finder.
   * We use the "switch to Finder" approach instead of a quit, because in most
   * of our Electron setups we have a launchd process that will relaunch the
   * app on quit. For maintenance, we probably just need to be able to get
   * to the Finder while the application remains running in the background.
   */
  const ret = globalShortcut.register('CommandOrControl+F', () => {
    console.log('Switching to Finder');
    promisedExec('open -a Finder');
  });
  if (!ret) {
    console.log('Keyboard registration failed');
  }

});

function loadWindowConfigFile(configFile) {
  const configFileObj = jetpack.read(configFile, 'json');
  console.log('configFileObj: ', configFileObj);
  if (configFileObj !== null) {
    loadWindowUptimeDelay(configFileObj);
  } else {
    console.log('Config file [' + configFile + '] not present.');
    mainWindow.loadURL('file://' + __dirname + '/config-error.html');
  }
}

function loadWindowUptimeDelay(configFileObj) {
  // Seconds since launch, when it will be safe to load the URL
  const nominalUptime = 300;

  // Seconds to wait if we are not in the nominal uptime window
  const launchDelay = 60;

  console.log('os.uptime(): ', os.uptime());
  console.log('nominalUptime: ', nominalUptime);

  if (os.uptime() > nominalUptime) {
    console.log('Launching immediately');
    mainWindow.loadURL(configFileObj.url);
  } else {
    console.log('Delaying launch ' + launchDelay + ' seconds');
    mainWindow.loadURL('file://' + __dirname + '/launch-delay.html');
    setTimeout(function () {
      mainWindow.loadURL(configFileObj.url);
    }, launchDelay * 1000);
  }

}

app.on('window-all-closed', function () {
  app.quit();
});
<|endoftext|>


<commit_before>/**
 * ReportError component tests.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import { createTestRegistry, provideModules } from '../../../tests/js/utils';
import {
	ERROR_CODE_MISSING_REQUIRED_SCOPE,
	ERROR_REASON_INSUFFICIENT_PERMISSIONS,
} from '../util/errors';
import { fireEvent, render } from '../../../tests/js/test-utils';
import ReportError from './ReportError';
import { MODULES_ANALYTICS } from '../modules/analytics/datastore/constants';

describe( 'ReportError', () => {
	let registry;
	let invalidateResolutionSpy;
	const moduleName = 'test-module';

	const errors = [
		{
			code: 'test-error-code',
			message: 'Test error message one',
			data: {
				reason: 'Data Error',
			},
			selectorData: {
				args: [
					{
						dimensions: [ 'ga:date' ],
						metrics: [ { expression: 'ga:users' } ],
						startDate: '2020-08-11',
						endDate: '2020-09-07',
					},
				],
				name: 'getReport',
				storeName: MODULES_ANALYTICS,
			},
		},
		{
			code: 'test-error-code',
			message: 'Test error message two',
			data: {
				reason: 'Data Error',
			},
			selectorData: {
				args: [
					{
						dimensions: [ 'ga:date' ],
						metrics: [ { expression: 'ga:users' } ],
						startDate: '2020-08-11',
						endDate: '2020-09-07',
					},
				],
				name: 'getReport',
				storeName: MODULES_ANALYTICS,
			},
		},
	];

	beforeEach( () => {
		registry = createTestRegistry();
		provideModules( registry, [
			{ slug: moduleName, name: 'Test Module' },
		] );
		invalidateResolutionSpy = jest.spyOn(
			registry.dispatch( MODULES_ANALYTICS ),
			'invalidateResolution'
		);
	} );

	afterEach( () => invalidateResolutionSpy.mockReset() );

	it( 'renders the error message', () => {
		const { container } = render(
			<ReportError
				moduleSlug={ moduleName }
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {},
				} }
			/>,
			{
				registry,
			}
		);

		expect( container.querySelector( 'p' ).textContent ).toEqual(
			'Test error message'
		);
	} );

	it( 'renders the error message without HTML tags', () => {
		const { container } = render(
			<ReportError
				moduleSlug={ moduleName }
				error={ {
					code: 'test-error-code',
					message:
						'
Test error message with HTML tags
',
					data: {},
				} }
			/>,
			{
				registry,
			}
		);

		expect( container.querySelector( 'p' ).textContent ).toEqual(
			'Test error message with HTML tags'
		);
	} );

	it( 'renders the insufficient permission error when ERROR_REASON_INSUFFICIENT_PERMISSIONS is provided as reason', () => {
		const { container } = render(
			<ReportError
				moduleSlug={ moduleName }
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: ERROR_REASON_INSUFFICIENT_PERMISSIONS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( container.querySelector( 'h3' ).textContent ).toEqual(
			'Insufficient permissions in Test Module'
		);
	} );

	it( "should not render the `Retry` button if the error's `selectorData.name` is not `getReport`", () => {
		const { queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: ERROR_REASON_INSUFFICIENT_PERMISSIONS,
					},
					selectorData: {
						args: [],
						name: 'getAccountID',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).not.toBeInTheDocument();
	} );

	it( 'should not render the `Retry` button if the error reason is `ERROR_REASON_INSUFFICIENT_PERMISSIONS`', () => {
		const { queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: ERROR_REASON_INSUFFICIENT_PERMISSIONS,
					},
					selectorData: {
						args: [],
						name: 'getAccountID',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).not.toBeInTheDocument();
	} );

	it( 'should not render the `Retry` button if the error reason is `ERROR_CODE_MISSING_REQUIRED_SCOPE`', () => {
		const { queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: ERROR_CODE_MISSING_REQUIRED_SCOPE,
					message: 'Test error message',
					data: {
						reason: '',
					},
					selectorData: {
						args: [],
						name: 'getAccountID',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).not.toBeInTheDocument();
	} );

	it( 'should not render the `Retry` button if the error is an auth error', () => {
		const { queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: '',
						reconnectURL: 'example.com',
					},
					selectorData: {
						args: [],
						name: 'getAccountID',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).not.toBeInTheDocument();
	} );

	it( 'should render the `Retry` button if the error selector name is `getReport`', () => {
		const { queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: '',
					},
					selectorData: {
						args: [
							{
								dimensions: [ 'ga:date' ],
								metrics: [ { expression: 'ga:users' } ],
								startDate: '2020-08-11',
								endDate: '2020-09-07',
							},
						],
						name: 'getReport',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).toBeInTheDocument();
	} );

	it( 'should dispatch the `invalidateResolution` action for each retry-able error', () => {
		const { queryByText, getByRole } = render(
			<ReportError
				moduleSlug="analytics"
				error={ [
					...errors,
					// The following error object is not retry-able.
					...[
						{
							code: ERROR_CODE_MISSING_REQUIRED_SCOPE,
							message: 'Test error message',
							data: {
								reason: '',
							},
							selectorData: {
								args: [],
								name: 'getAccountID',
								storeName: MODULES_ANALYTICS,
							},
						},
					],
				] }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).toBeInTheDocument();

		fireEvent.click( getByRole( 'button', { name: /retry/i } ) );

		// There are three error object is being passed to the prop.
		// Only two are retry-able.
		// So, there should be only two invalidateResolution calls.
		expect( invalidateResolutionSpy ).toHaveBeenCalledTimes( 2 );
	} );

	it( 'should list all the error descriptions one by one if errors are different', () => {
		const { queryByText, getByRole } = render(
			<ReportError moduleSlug="analytics" error={ errors } />,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).toBeInTheDocument();

		// Verify that the error descriptions are listed one by one if the errors are different.
		expect( queryByText( /Test error message one/i ) ).toBeInTheDocument();
		expect( queryByText( /Test error message two/i ) ).toBeInTheDocument();

		fireEvent.click( getByRole( 'button', { name: /retry/i } ) );

		expect( invalidateResolutionSpy ).toHaveBeenCalledTimes( 2 );
	} );

	it( 'should list only the unique error descriptions', () => {
		const { container, queryByText, getByRole } = render(
			<ReportError
				moduleSlug="analytics"
				error={ [ ...errors, ...errors ] }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).toBeInTheDocument();

		// Verify that the error descriptions are listed one by one if the errors are different.
		expect( queryByText( /Test error message one/i ) ).toBeInTheDocument();
		expect( queryByText( /Test error message two/i ) ).toBeInTheDocument();

		const errorDescriptionElement = container.querySelectorAll(
			'.googlesitekit-cta__description'
		);

		// Verify the child element count for the error description element is two.
		// However, the passed error array has four repetitive error objects.
		expect( errorDescriptionElement[ 0 ].childElementCount ).toBe( 2 );

		fireEvent.click( getByRole( 'button', { name: /retry/i } ) );
		expect( invalidateResolutionSpy ).toHaveBeenCalledTimes( 4 );
	} );
} );
<commit_msg>Update test for ReportError component.<commit_after>/**
 * ReportError component tests.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import { createTestRegistry, provideModules } from '../../../tests/js/utils';
import {
	ERROR_CODE_MISSING_REQUIRED_SCOPE,
	ERROR_REASON_INSUFFICIENT_PERMISSIONS,
} from '../util/errors';
import { fireEvent, render } from '../../../tests/js/test-utils';
import ReportError from './ReportError';
import { MODULES_ANALYTICS } from '../modules/analytics/datastore/constants';

describe( 'ReportError', () => {
	let registry;
	let invalidateResolutionSpy;
	const moduleName = 'test-module';

	const errors = [
		{
			code: 'test-error-code',
			message: 'Test error message one',
			data: {
				reason: 'Data Error',
			},
			selectorData: {
				args: [
					{
						dimensions: [ 'ga:date' ],
						metrics: [ { expression: 'ga:users' } ],
						startDate: '2020-08-11',
						endDate: '2020-09-07',
					},
				],
				name: 'getReport',
				storeName: MODULES_ANALYTICS,
			},
		},
		{
			code: 'test-error-code',
			message: 'Test error message two',
			data: {
				reason: 'Data Error',
			},
			selectorData: {
				args: [
					{
						dimensions: [ 'ga:date' ],
						metrics: [ { expression: 'ga:users' } ],
						startDate: '2020-08-11',
						endDate: '2020-09-07',
					},
				],
				name: 'getReport',
				storeName: MODULES_ANALYTICS,
			},
		},
	];

	beforeEach( () => {
		registry = createTestRegistry();
		provideModules( registry, [
			{ slug: moduleName, name: 'Test Module' },
		] );
		invalidateResolutionSpy = jest.spyOn(
			registry.dispatch( MODULES_ANALYTICS ),
			'invalidateResolution'
		);
	} );

	afterEach( () => invalidateResolutionSpy.mockReset() );

	it( 'renders the error message', () => {
		const { container } = render(
			<ReportError
				moduleSlug={ moduleName }
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {},
				} }
			/>,
			{
				registry,
			}
		);

		expect( container.querySelector( 'p' ).textContent ).toEqual(
			'Test error message'
		);
	} );

	it( 'renders the error message without HTML tags', () => {
		const { container } = render(
			<ReportError
				moduleSlug={ moduleName }
				error={ {
					code: 'test-error-code',
					message:
						'
Test error message with HTML tags
',
					data: {},
				} }
			/>,
			{
				registry,
			}
		);

		expect( container.querySelector( 'p' ).textContent ).toEqual(
			'Test error message with HTML tags'
		);
	} );

	it( 'renders the insufficient permission error when ERROR_REASON_INSUFFICIENT_PERMISSIONS is provided as reason', () => {
		const { container } = render(
			<ReportError
				moduleSlug={ moduleName }
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: ERROR_REASON_INSUFFICIENT_PERMISSIONS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( container.querySelector( 'h3' ).textContent ).toEqual(
			'Insufficient permissions in Test Module'
		);
	} );

	it( "should not render the `Retry` button if the error's `selectorData.name` is not `getReport`", () => {
		const { queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: ERROR_REASON_INSUFFICIENT_PERMISSIONS,
					},
					selectorData: {
						args: [],
						name: 'getAccountID',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).not.toBeInTheDocument();
	} );

	it( 'should not render the `Retry` button if the error reason is `ERROR_REASON_INSUFFICIENT_PERMISSIONS`', () => {
		const { queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: ERROR_REASON_INSUFFICIENT_PERMISSIONS,
					},
					selectorData: {
						args: [],
						name: 'getAccountID',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).not.toBeInTheDocument();
	} );

	it( 'should not render the `Retry` button if the error reason is `ERROR_CODE_MISSING_REQUIRED_SCOPE`', () => {
		const { queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: ERROR_CODE_MISSING_REQUIRED_SCOPE,
					message: 'Test error message',
					data: {
						reason: '',
					},
					selectorData: {
						args: [],
						name: 'getAccountID',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).not.toBeInTheDocument();
	} );

	it( 'should not render the `Retry` button if the error is an auth error', () => {
		const { queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: '',
						reconnectURL: 'example.com',
					},
					selectorData: {
						args: [],
						name: 'getAccountID',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( queryByText( /retry/i ) ).not.toBeInTheDocument();
	} );

	it( 'should render the `Retry` button if the error selector name is `getReport`', () => {
		const { getByRole } = render(
			<ReportError
				moduleSlug="analytics"
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: '',
					},
					selectorData: {
						args: [
							{
								dimensions: [ 'ga:date' ],
								metrics: [ { expression: 'ga:users' } ],
								startDate: '2020-08-11',
								endDate: '2020-09-07',
							},
						],
						name: 'getReport',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( getByRole( 'button', { name: /retry/i } ) ).toBeInTheDocument();
	} );

	it( 'should dispatch the `invalidateResolution` action for each retry-able error', () => {
		const { getByRole } = render(
			<ReportError
				moduleSlug="analytics"
				error={ [
					...errors,
					// The following error object is not retry-able.
					...[
						{
							code: ERROR_CODE_MISSING_REQUIRED_SCOPE,
							message: 'Test error message',
							data: {
								reason: '',
							},
							selectorData: {
								args: [],
								name: 'getAccountID',
								storeName: MODULES_ANALYTICS,
							},
						},
					],
				] }
			/>,
			{
				registry,
			}
		);

		expect( getByRole( 'button', { name: /retry/i } ) ).toBeInTheDocument();

		fireEvent.click( getByRole( 'button', { name: /retry/i } ) );

		// There are three error object is being passed to the prop.
		// Only two are retry-able.
		// So, there should be only two invalidateResolution calls.
		expect( invalidateResolutionSpy ).toHaveBeenCalledTimes( 2 );
	} );

	it( 'should list all the error descriptions one by one if errors are different', () => {
		const { queryByText, getByRole } = render(
			<ReportError moduleSlug="analytics" error={ errors } />,
			{
				registry,
			}
		);

		expect( getByRole( 'button', { name: /retry/i } ) ).toBeInTheDocument();

		// Verify that the error descriptions are listed one by one if the errors are different.
		expect( queryByText( /Test error message one/i ) ).toBeInTheDocument();
		expect( queryByText( /Test error message two/i ) ).toBeInTheDocument();

		fireEvent.click( getByRole( 'button', { name: /retry/i } ) );

		expect( invalidateResolutionSpy ).toHaveBeenCalledTimes( 2 );
	} );

	it( 'should list only the unique error descriptions', () => {
		const { container, queryByText, getByRole } = render(
			<ReportError
				moduleSlug="analytics"
				error={ [ ...errors, ...errors ] }
			/>,
			{
				registry,
			}
		);

		expect( getByRole( 'button', { name: /retry/i } ) ).toBeInTheDocument();

		// Verify that the error descriptions are listed one by one if the errors are different.
		expect( queryByText( /Test error message one/i ) ).toBeInTheDocument();
		expect( queryByText( /Test error message two/i ) ).toBeInTheDocument();

		const errorDescriptionElement = container.querySelectorAll(
			'.googlesitekit-cta__description'
		);

		// Verify the child element count for the error description element is two.
		// However, the passed error array has four repetitive error objects.
		expect( errorDescriptionElement[ 0 ].childElementCount ).toBe( 2 );

		fireEvent.click( getByRole( 'button', { name: /retry/i } ) );
		expect( invalidateResolutionSpy ).toHaveBeenCalledTimes( 4 );
	} );

	it( 'shold render `Get help` ulink without prefix text on non-retryable error', () => {
		const { getByRole, queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				// Non-Retryable Error
				error={ {
					code: ERROR_CODE_MISSING_REQUIRED_SCOPE,
					message: 'Test error message',
					data: {
						reason: '',
					},
					selectorData: {
						args: [],
						name: 'getAccountID',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect(
			getByRole( 'link', { name: /get help/i } )
		).toBeInTheDocument();
		expect( queryByText( /retry didn’t work/i ) ).not.toBeInTheDocument();
	} );

	it( 'should render `Get help` link with prefix text on retryable error', () => {
		const { getByRole, queryByText } = render(
			<ReportError
				moduleSlug="analytics"
				// Retryable Error
				error={ {
					code: 'test-error-code',
					message: 'Test error message',
					data: {
						reason: '',
					},
					selectorData: {
						args: [
							{
								dimensions: [ 'ga:date' ],
								metrics: [ { expression: 'ga:users' } ],
								startDate: '2020-08-11',
								endDate: '2020-09-07',
							},
						],
						name: 'getReport',
						storeName: MODULES_ANALYTICS,
					},
				} }
			/>,
			{
				registry,
			}
		);

		expect( getByRole( 'button', { name: /retry/i } ) ).toBeInTheDocument();
		expect(
			getByRole( 'link', { name: /get help/i } )
		).toBeInTheDocument();
		expect( queryByText( /retry didn’t work/i ) ).toBeInTheDocument();
	} );
} );
<|endoftext|>


<commit_before>chrome.app.runtime.onLaunched.addListener(function () {
	chrome.app.window.create('window.html', {
		id: "miniplayer",
		bounds: {
			width: 832,
			height: 468
		},
		innerBounds: {
			width: 832,
			height: 468
		}
	});
});

chrome.runtime.onMessageExternal.addListener(function (msg) {
	chrome.app.window.create('window.html', {
		id: "miniplayer",
		innerBounds: {
			width: 832,
			height: 468
		},
		frame: {color: '#000000'},
		alwaysOnTop: true
	},
			function (createdWindow) {
				var win = createdWindow.contentWindow;
				switch (msg.server)
				{
					case 'twitch.tv':
						win.onload = function () {
							win.document.querySelector('#content').innerHTML =
									'<webview src="http://player.twitch.tv/?channel=' + msg.profile + '" style="width:100vw;height:100vh"></webview>';
						};
						break;
					case 'hitbox.tv':
						win.onload = function () {
							win.document.querySelector('#content').innerHTML =
									'<webview src="http://www.hitbox.tv/embed/' + msg.profile + '" style="width:100vw;height:100vh"></webview>';
						};
						break;
					default:
						break;
				}
			}
	);
});<commit_msg>Close miniplayer before open another<commit_after>chrome.app.runtime.onLaunched.addListener(function () {
	chrome.app.window.create('window.html', {
		id: "miniplayer",
		bounds: {
			width: 832,
			height: 468
		},
		innerBounds: {
			width: 832,
			height: 468
		}
	});
});

chrome.runtime.onMessageExternal.addListener(function (msg) {
	if (chrome.app.window.get("miniplayer"))
		chrome.app.window.get("miniplayer").close();
	chrome.app.window.create('window.html', {
		id: "miniplayer",
		innerBounds: {
			width: 832,
			height: 468
		},
		frame: {color: '#000000'},
		alwaysOnTop: true
	},
			function (createdWindow) {
				var win = createdWindow.contentWindow;
				switch (msg.server)
				{
					case 'twitch.tv':
						win.onload = function () {
							win.document.querySelector('#content').innerHTML =
									'<webview src="http://player.twitch.tv/?channel=' + msg.profile + '" style="width:100vw;height:100vh"></webview>';
						};
						break;
					case 'hitbox.tv':
						win.onload = function () {
							win.document.querySelector('#content').innerHTML =
									'<webview src="http://www.hitbox.tv/embed/' + msg.profile + '" style="width:100vw;height:100vh"></webview>';
						};
						break;
					default:
						break;
				}
			}
	);
});<|endoftext|>


<commit_before>"use strict";
const fs = require('fs');
const url = require('url');
const path = require('path');
const request = require('request');
const mkdirp = require('mkdirp');
const rimraf = require('rimraf');
const exec = require('child_process').exec;

const publicDir = process.env.GITLAB_CE_PAGES_PUBLIC_DIR;
const privateToken = process.env.PAGE_PRIVATE_TOKEN;
const projectRoot = process.env.PROJECT_ROOT;

let gitlabUrl = process.env.GITLAB_URL || 'localhost';
gitlabUrl = gitlabUrl.replace(/\/*$/, '/');

function extract(artifactName, artifactPath, destination) {
  exec('unzip ' + artifactPath + ' -d ' + destination, (err, stdout, stderr) => {
    if (err) {
      console.error('unzip', artifactName, 'failed');
      console.error(err);
    } else {
      console.log('unzipped', artifactName, 'into', destination);
      if (projectRoot) {
        console.log('moving files out of', projectRoot);
        exec('cd ' + destination + ' && mv ' + projectRoot + ' PROJECT_ROOT && cd PROJECT_ROOT && mv ./* .. && cd .. && rm -rf PROJECT_ROOT',
          (err, stdout, stderr) => {
            if (err) {
              console.error('moving', projectRoot, 'failed');
              console.error(err);
            } else {
              console.log('moving', projectRoot, 'succeed');
            }
          }
        );
      }
    }
  });
}

function update(body, pageDir) {
  if (!privateToken) {
    console.log('missing private token');
    return;
  }
  mkdirp(pageDir, (err) => {
    if (err) {
      console.log('mkdir', pageDir, 'failed');
      return;
    }
    const pname = body.project_name.replace('.', '');
    const pid = body.project_id;
    const bid = body.build_id;
    const pnameSplit = pname.split(' / ');
    const options = {
      url: url.resolve(gitlabUrl, 'api/v3/projects/' + pid + '/builds/' + bid + '/artifacts'),
      headers: {
        'PRIVATE-TOKEN': privateToken
      }
    }
    console.log('options', options);
    const artifactName = bid + '.zip';
    const artifactPath = path.join(publicDir, artifactName);
    const artifactWriteStream = fs.createWriteStream(artifactPath);
    artifactWriteStream.on('close', (err) => {
      if (err) {
        console.log('download', artifactName, 'failed');
        return;
      }
      console.log(artifactName, 'downloaded');
      extract(artifactName, artifactPath, pageDir);
    });
    request
      .get(options)
      .pipe(artifactWriteStream);
  });
}

module.exports = {
  deploy: function(body) {
    const pname = body.project_name.replace('.', '');
    const pnameSplit = pname.split(' / ');
    const pageDir = path.join(publicDir, ...pnameSplit);
    fs.stat(pageDir, (err, stats) => {
      if (err) {
        update(body, pageDir);
      } else {
        rimraf(pageDir, () => {
          update(body, pageDir);
        })
      }
    });
  }
};
<commit_msg>remote unnecessary variables<commit_after>"use strict";
const fs = require('fs');
const url = require('url');
const path = require('path');
const request = require('request');
const mkdirp = require('mkdirp');
const rimraf = require('rimraf');
const exec = require('child_process').exec;

const publicDir = process.env.GITLAB_CE_PAGES_PUBLIC_DIR;
const privateToken = process.env.PAGE_PRIVATE_TOKEN;
const projectRoot = process.env.PROJECT_ROOT;

let gitlabUrl = process.env.GITLAB_URL || 'localhost';
gitlabUrl = gitlabUrl.replace(/\/*$/, '/');

function extract(artifactName, artifactPath, destination) {
  exec('unzip ' + artifactPath + ' -d ' + destination, (err, stdout, stderr) => {
    if (err) {
      console.error('unzip', artifactName, 'failed');
      console.error(err);
    } else {
      console.log('unzipped', artifactName, 'into', destination);
      if (projectRoot) {
        console.log('moving files out of', projectRoot);
        exec('cd ' + destination + ' && mv ' + projectRoot + ' PROJECT_ROOT && cd PROJECT_ROOT && mv ./* .. && cd .. && rm -rf PROJECT_ROOT',
          (err, stdout, stderr) => {
            if (err) {
              console.error('moving', projectRoot, 'failed');
              console.error(err);
            } else {
              console.log('moving', projectRoot, 'succeed');
            }
          }
        );
      }
    }
  });
}

function update(body, pageDir) {
  if (!privateToken) {
    console.log('missing private token');
    return;
  }
  mkdirp(pageDir, (err) => {
    if (err) {
      console.log('mkdir', pageDir, 'failed');
      return;
    }
    const pid = body.project_id;
    const bid = body.build_id;
    const options = {
      url: url.resolve(gitlabUrl, 'api/v3/projects/' + pid + '/builds/' + bid + '/artifacts'),
      headers: {
        'PRIVATE-TOKEN': privateToken
      }
    }
    console.log('options', options);
    const artifactName = bid + '.zip';
    const artifactPath = path.join(publicDir, artifactName);
    const artifactWriteStream = fs.createWriteStream(artifactPath);
    artifactWriteStream.on('close', (err) => {
      if (err) {
        console.log('download', artifactName, 'failed');
        return;
      }
      console.log(artifactName, 'downloaded');
      extract(artifactName, artifactPath, pageDir);
    });
    request
      .get(options)
      .pipe(artifactWriteStream);
  });
}

module.exports = {
  deploy: function(body) {
    const pname = body.project_name.replace('.', '');
    const pnameSplit = pname.split(' / ');
    const pageDir = path.join(publicDir, ...pnameSplit);
    fs.stat(pageDir, (err, stats) => {
      if (err) {
        update(body, pageDir);
      } else {
        rimraf(pageDir, () => {
          update(body, pageDir);
        })
      }
    });
  }
};
<|endoftext|>


<commit_before>exports = module.exports = function(credentials, keyring) {

  // TODO: Add a way to check if audience is logically self, and then fetch
  //       keys from KMS (ie Google) for HSM purposes.

  return function get(options, cb) {
    console.log('### COMMON KEYING');
    console.log(options);

    var opts = {};
    // TODO: Don't overload id and URL

    if (options.usage == 'sign' || options.usage == 'encrypt' || (options.usage == 'deriveKey' && !options.foo)) {
      // TODO: if no recipient, default to self
      opts.id = options.recipient.id;
      opts.url = options.recipient.identifier;
    } else if (options.usage == 'verify' || options.usage == 'decrypt' || options.usage == 'deriveKey') {
      opts.url = options.sender ? options.sender.id : 'http://localhost/';
    }

    credentials.get(options.sender || options.recipient, opts, function(err, cred) {
      //console.log('GOT CRED!');
      //console.log(err);
      //console.log(cred);

      if (err) { return cb(err); }
      if (typeof cred == 'string') {
        cred = { secret: cred }
      }
      return cb(null, [ cred ]);
    });

    //if (key)

    //return;

    //keyring.find(options, cb);
  };
};

// TODO: Break this down into
// 1. KMS for local private key pairs
// 2. Credential Store for shared secrets and other per-entity creds
// 3. pki/KeyServer for federated access to public keys

exports['@require'] = [
  'http://i.bixbyjs.org/security/CredentialManager',
  'http://i.bixbyjs.org/crypto/Keyring'
];
<commit_msg>Use new interface name.<commit_after>exports = module.exports = function(credentials, keyring) {

  // TODO: Add a way to check if audience is logically self, and then fetch
  //       keys from KMS (ie Google) for HSM purposes.

  return function get(options, cb) {
    console.log('### COMMON KEYING');
    console.log(options);

    var opts = {};
    // TODO: Don't overload id and URL

    if (options.usage == 'sign' || options.usage == 'encrypt' || (options.usage == 'deriveKey' && !options.foo)) {
      // TODO: if no recipient, default to self
      opts.id = options.recipient.id;
      opts.url = options.recipient.identifier;
    } else if (options.usage == 'verify' || options.usage == 'decrypt' || options.usage == 'deriveKey') {
      opts.url = options.sender ? options.sender.id : 'http://localhost/';
    }

    credentials.get(options.sender || options.recipient, opts, function(err, cred) {
      //console.log('GOT CRED!');
      //console.log(err);
      //console.log(cred);

      if (err) { return cb(err); }
      if (typeof cred == 'string') {
        cred = { secret: cred }
      }
      return cb(null, [ cred ]);
    });

    //if (key)

    //return;

    //keyring.find(options, cb);
  };
};

// TODO: Break this down into
// 1. KMS for local private key pairs
// 2. Credential Store for shared secrets and other per-entity creds
// 3. pki/KeyServer for federated access to public keys

exports['@require'] = [
  'http://i.bixbyjs.org/security/CredentialsStore',
  'http://i.bixbyjs.org/crypto/Keyring'
];
<|endoftext|>