<commit_before>(function (Raphael) {
  Raphael.fn.graph = {};

  Raphael.fn.graph.enable = function (types)
  {
    // by default only extend circle
    if (!types) types = ['circle'];

    // extend given types
    for (var i = 0; i < types.length; i++)
    {
      var type = types[i];
      this[type] = function (paper, fn)
      {
        return function ()
        {
          var element = fn.apply(paper, arguments);
          element.graph = new GraphExtension(element);
          return element;
        };
      }(this, this[type]);
    }

    return this;
  }

  var GraphExtension = function (element)
  {
    this.element = element;
    this.paper = element.paper;
  }

  GraphExtension.prototype.graph = function (g)
  {
    return this._graph = g || this._graph;
  }

  GraphExtension.prototype.edgeTo = function (el, weight)
  {
    if (this.graph() && el.graph.graph() && this.graph() !== el.graph.graph()) {
      this.graph().each(function (v)
      {
        // copy this graph to el's graph
        for (var u in this.adj(v))
        {
          var edge = this.get(v, u);
          el.graph.graph().set(v, this.vertex(u), edge);
        }

        v.graph.graph(el.graph.graph());
      });

    } else {
      // assign graph
      this.graph(el.graph.graph(this.graph() || el.graph.graph() || new Graph()));
    }

    // no loops, no multiedges
    if (this.element === el || this.graph().has(this.element, el))
      return;

    // create edge
    this.drawEdge(el);

    // attach listeners to redraw edges on drag
    this.setupVertex();
    el.graph.setupVertex();

    return this.element;
  }

  GraphExtension.prototype.edgesToRedraw = function ()
  {
    // edges (pairs) with any parent in the set

    if (!this.element.draggable) return;

    if (this.element.draggable.parent && this.element.draggable.parent._to_redraw)
    {
      return this.element.draggable.parent._to_redraw;
    }

    var to_redraw = []; // [[u, v], ...]
    var set_vertices = {}; //

    for (var i = 0; i < this.element.draggable.parent.items.length; i++)
      set_vertices[this.element.draggable.parent.items[i]] = 1;

    this.graph().each(function (v)
    {
      for (var u in this.adj(v))
      {
        if (u < v && (v in set_vertices || u in set_vertices))
        {
          to_redraw.push([this.vertex(u), this.vertex(v)]);
        }
      }
    });

    return this.element.draggable.parent._to_redraw = to_redraw;
  }

  GraphExtension.prototype.setupVertex = function ()
  {
    if (!this.element.draggable) return;

    if (this._setup_vertex) return;
    this._setup_vertex = 1;

    // drag start
    this.element.mousedown(function (event)
    {
      if (event.shiftKey)
      {
        // create set or get existing set
        var set = this.paper._set = this.paper._set || this.paper.set().draggable.enable();
        delete set._to_redraw;
        // gather other elements in the set
        var others = new Array();
        for (var i = 0; i < set.length; i++) {
          if (set[i] != this) {
            others.push(set[i]);
          }
        }
        if (others.length != set.length) {
          // disable old set
          set.draggable.disable();
          // create a new set without the element
          set = this.paper._set = this.paper.set().draggable.enable();
          for (var i = 0; i < others.length; i++) {
            set.push(others[i]);
          }
          this.attr('fill', 'blue');
          this.graph.colorNeighbors('blue');
        } else {
          // add this element to the set
          set.push(this);
          this.attr('fill', 'green');
          this.graph.colorNeighbors('red');
        }
      } else if (!this.graph.hasEnabledSet())
      {
        // check for current set
        if (this.paper._set)
        {
          var set = this.paper._set;
          delete this.paper._set;
          // disable the set
          set.draggable.disable();
          // return everything to original color
          this.graph.graph().each(function (v)
          {
            this.vertex(v).attr('fill', 'blue');
          });
        }
        // color neighbors the active-neighbor color
        this.graph.colorNeighbors('red');
      }
    });

    // dragging
    this.element.draggable.dragged(function ()
    {
      // bounding box constraints
      var x = this.attr('cx');
      var y = this.attr('cy');
      var r = this.attr('r');
      var w = this.paper.width;
      var h = this.paper.height;
      var y_max = h - r - 1;
      var x_max = w - r - 1;

      if (r && w && h && (x < r || x > x_max || y < r || y > y_max)) {
        // new and cx, cy
        var cx = Math.min(Math.max(r, x), x_max);
        var cy = Math.min(Math.max(r, y), y_max);

        if (this.graph.hasEnabledSet()) {
          // difference
          var dx = cx - x;
          var dy = cy - y;
          // move every element to valid position
          var items = this.draggable.parent.items;
          for (var i = 0; i < items.length; i++) {
            items[i].attr({
              cx: items[i].attr('cx') + dx,
              cy: items[i].attr('cy') + dy
            });
          }
        } else {
          // move this element to valid position
          this.attr({
            cx: cx,
            cy: cy
          });
        }
        // end dragging
        this.paper.draggable.clearCurrent();
        this.graph.dragEnd.call(this);
      }

      // check if we are in a set
      if (this.graph.hasEnabledSet())
      {
        // redraw edges with any parent in the set
        var to_redraw = this.graph.edgesToRedraw();
        for (var i = 0; i < to_redraw.length; i++)
        {
          to_redraw[i][0].graph.drawEdge(to_redraw[i][1]);
        }
      } else
      {
        this.graph.drawEdges();
      }
    });

    // drag end
    this.element.mouseup(this.dragEnd);
  }

  GraphExtension.prototype.dragEnd = function ()
  {
    if (!this.graph.hasEnabledSet())
    {
      // color neighbors the default color
      this.graph.colorNeighbors('blue');
    }
  }

  GraphExtension.prototype.hasEnabledSet = function ()
  {
    return this.element.draggable.parent && this.element.draggable.parent.draggable.enabled;
  }

  GraphExtension.prototype.isSetNeighbor = function (v)
  {
    return v.attr('fill') === 'green';
  }

  GraphExtension.prototype.isFringeNeighbor = function (v)
  {
    return v.attr('fill') === 'red';
  }

  GraphExtension.prototype.colorNeighbors = function (color)
  {
    for (var id in this.graph().adj(this.element))
    {
      var v = this.graph().vertex(id);
      if (!this.isSetNeighbor(v))
      {
        this.graph().vertex(id).attr('fill', color)
      }
    }

    return this.element;
  }

  GraphExtension.prototype.drawEdges = function ()
  {
    for (var id in this.graph().adj(this.element))
      this.drawEdge(this.graph().vertex(id));

    return this.element;
  }

  GraphExtension.prototype.drawEdge = function (el)
  {
    var x1 = this.element.attr('cx'),
      y1 = this.element.attr('cy'),
      x2 = el.attr('cx'),
      y2 = el.attr('cy');

    var path = ['M', x1, y1, 'L', x2, y2];

    var edge = this.graph().get(this.element, el);
    if (edge) {
      // move existing edge
      edge.attr('path', path);
      edge.x = edge.head.attr('x');
      edge.y = edge.head.attr('y');
      return this.element;
    } else {
      // create new edge
      edge = this.paper.path(path);
      edge.head = this.element;
      edge.x = x1; edge.y = y1;
      this.graph().set(this.element, el, edge);
      this.element.toFront();
      el.toFront();
      return this.element;
    }
  }

  Raphael.el.toString = function ()
  {
    // Graph needs toString() on elements to identify vertices
    return "Raphael Object #"+this.id;
  }
})(Raphael);
<commit_msg>added intersection detection courtesy Jason Davies<commit_after>(function (Raphael) {
  Raphael.fn.graph = {};

  Raphael.fn.graph.enable = function (types)
  {
    // by default only extend circle
    if (!types) types = ['circle'];

    // extend given types
    for (var i = 0; i < types.length; i++)
    {
      var type = types[i];
      this[type] = function (paper, fn)
      {
        return function ()
        {
          var element = fn.apply(paper, arguments);
          element.graph = new GraphExtension(element);
          return element;
        };
      }(this, this[type]);
    }

    return this;
  }

  var GraphExtension = function (element)
  {
    this.element = element;
    this.paper = element.paper;
  }

  GraphExtension.prototype.graph = function (g)
  {
    return this._graph = g || this._graph;
  }

  GraphExtension.prototype.edgeTo = function (el, weight)
  {
    if (this.graph() && el.graph.graph() && this.graph() !== el.graph.graph()) {
      this.graph().each(function (v)
      {
        // copy this graph to el's graph
        for (var u in this.adj(v))
        {
          var edge = this.get(v, u);
          el.graph.graph().set(v, this.vertex(u), edge);
        }

        v.graph.graph(el.graph.graph());
      });

    } else {
      // assign graph
      this.graph(el.graph.graph(this.graph() || el.graph.graph() || new Graph()));
    }

    // no loops, no multiedges
    if (this.element === el || this.graph().has(this.element, el))
      return;

    // create edge
    this.drawEdge(el);

    // attach listeners to redraw edges on drag
    this.setupVertex();
    el.graph.setupVertex();

    return this.element;
  }

  GraphExtension.prototype.edgesToRedraw = function ()
  {
    // edges (pairs) with any parent in the set

    if (!this.element.draggable) return;

    if (this.element.draggable.parent && this.element.draggable.parent._to_redraw)
    {
      return this.element.draggable.parent._to_redraw;
    }

    var to_redraw = []; // [[u, v], ...]
    var set_vertices = {}; //

    for (var i = 0; i < this.element.draggable.parent.items.length; i++)
      set_vertices[this.element.draggable.parent.items[i]] = 1;

    this.graph().each(function (v)
    {
      for (var u in this.adj(v))
      {
        if (u < v && (v in set_vertices || u in set_vertices))
        {
          to_redraw.push([this.vertex(u), this.vertex(v)]);
        }
      }
    });

    return this.element.draggable.parent._to_redraw = to_redraw;
  }

  GraphExtension.prototype.setupVertex = function ()
  {
    if (!this.element.draggable) return;

    if (this._setup_vertex) return;
    this._setup_vertex = 1;

    // drag start
    this.element.mousedown(function (event)
    {
      if (event.shiftKey)
      {
        // create set or get existing set
        var set = this.paper._set = this.paper._set || this.paper.set().draggable.enable();
        delete set._to_redraw;
        // gather other elements in the set
        var others = new Array();
        for (var i = 0; i < set.length; i++) {
          if (set[i] != this) {
            others.push(set[i]);
          }
        }
        if (others.length != set.length) {
          // disable old set
          set.draggable.disable();
          // create a new set without the element
          set = this.paper._set = this.paper.set().draggable.enable();
          for (var i = 0; i < others.length; i++) {
            set.push(others[i]);
          }
          this.attr('fill', 'blue');
          this.graph.colorNeighbors('blue');
        } else {
          // add this element to the set
          set.push(this);
          this.attr('fill', 'green');
          this.graph.colorNeighbors('red');
        }
      } else if (!this.graph.hasEnabledSet())
      {
        // check for current set
        if (this.paper._set)
        {
          var set = this.paper._set;
          delete this.paper._set;
          // disable the set
          set.draggable.disable();
          // return everything to original color
          this.graph.graph().each(function (v)
          {
            this.vertex(v).attr('fill', 'blue');
          });
        }
        // color neighbors the active-neighbor color
        this.graph.colorNeighbors('red');
      }
    });

    // dragging
    this.element.draggable.dragged(function ()
    {
      // bounding box constraints
      var x = this.attr('cx');
      var y = this.attr('cy');
      var r = this.attr('r');
      var w = this.paper.width;
      var h = this.paper.height;
      var y_max = h - r - 1;
      var x_max = w - r - 1;

      if (r && w && h && (x < r || x > x_max || y < r || y > y_max)) {
        // new and cx, cy
        var cx = Math.min(Math.max(r, x), x_max);
        var cy = Math.min(Math.max(r, y), y_max);

        if (this.graph.hasEnabledSet()) {
          // difference
          var dx = cx - x;
          var dy = cy - y;
          // move every element to valid position
          var items = this.draggable.parent.items;
          for (var i = 0; i < items.length; i++) {
            items[i].attr({
              cx: items[i].attr('cx') + dx,
              cy: items[i].attr('cy') + dy
            });
          }
        } else {
          // move this element to valid position
          this.attr({
            cx: cx,
            cy: cy
          });
        }
        // end dragging
        this.paper.draggable.clearCurrent();
        this.graph.dragEnd.call(this);
      }

      // check if we are in a set
      if (this.graph.hasEnabledSet())
      {
        // redraw edges with any parent in the set
        var to_redraw = this.graph.edgesToRedraw();
        for (var i = 0; i < to_redraw.length; i++)
        {
          to_redraw[i][0].graph.drawEdge(to_redraw[i][1]);
        }
      } else
      {
        this.graph.drawEdges();
      }
    });

    // drag end
    this.element.mouseup(this.dragEnd);
  }

  GraphExtension.prototype.dragEnd = function ()
  {
    if (!this.graph.hasEnabledSet())
    {
      // color neighbors the default color
      this.graph.colorNeighbors('blue');
    }
  }

  GraphExtension.prototype.hasEnabledSet = function ()
  {
    return this.element.draggable.parent && this.element.draggable.parent.draggable.enabled;
  }

  GraphExtension.prototype.isSetNeighbor = function (v)
  {
    return v.attr('fill') === 'green';
  }

  GraphExtension.prototype.isFringeNeighbor = function (v)
  {
    return v.attr('fill') === 'red';
  }

  GraphExtension.prototype.colorNeighbors = function (color)
  {
    for (var id in this.graph().adj(this.element))
    {
      var v = this.graph().vertex(id);
      if (!this.isSetNeighbor(v))
      {
        this.graph().vertex(id).attr('fill', color)
      }
    }

    return this.element;
  }

  GraphExtension.prototype.drawEdges = function ()
  {
    for (var id in this.graph().adj(this.element))
      this.drawEdge(this.graph().vertex(id));

    return this.element;
  }

  GraphExtension.prototype.drawEdge = function (el)
  {
    var x1 = this.element.attr('cx'),
      y1 = this.element.attr('cy'),
      x2 = el.attr('cx'),
      y2 = el.attr('cy');

    var path = ['M', x1, y1, 'L', x2, y2];

    var edge = this.graph().get(this.element, el);
    if (edge) {
      // move existing edge
      edge.attr('path', path);
      edge.x = edge.head.attr('x');
      edge.y = edge.head.attr('y');
      return this.element;
    } else {
      // create new edge
      edge = this.paper.path(path);
      edge.head = this.element;
      edge.x = x1; edge.y = y1;
      this.graph().set(this.element, el, edge);
      this.element.toFront();
      el.toFront();
      return this.element;
    }
  }

  GraphExtension.prototype.edges = function (fn)
  {
    this.graph().each(function (v)
    {
      for (var u in this.adj(v))
      {
        if (u < v) {
          fn(this.vertex(u), v);
        }
      }
    });
  }

  // calls fn(e1, e2) for every pair of intersecting edges (e1, e2)
  GraphExtension.prototype.intersecting = function (fn)
  {
    this.edges(function (u, v) {
      var uv = u.graph.graph().get(u, v);
      var uv_path = uv.attr('path');
      var a = [[uv_path[0][1], uv_path[0][2]], [uv_path[1][1], uv_path[1][2]]];
      u.graph.edges(function (s, t) {
        if (u != s && u != t && v != s && v != t && u < s) {
          var st = s.graph.graph().get(s, t);
          var st_path = st.attr('path');
          var b = [[st_path[0][1], st_path[0][2]], [st_path[1][1], st_path[1][2]]];
          if (intersects(a, b)) {
            fn(uv, st);
          }
        }
      });
    });
  }

  // Jason Davies (2011) http://www.jasondavies.com/planarity/
  // Returns true if two line segments intersect.
  // Based on http://stackoverflow.com/a/565282/64009
  function intersects(a, b) {
    // Check if the segments are exactly the same (or just reversed).
    if (a[0] === b[0] && a[1] === b[1] || a[0] === b[1] && a[1] === b[0]) return true;

    // Represent the segments as p + tr and q + us, where t and u are scalar
    // parameters.
    var p = a[0],
        r = [a[1][0] - p[0], a[1][1] - p[1]],
        q = b[0],
        s = [b[1][0] - q[0], b[1][1] - q[1]];

    // Solve p + tr = q + us to find an intersection point.
    // First, cross both sides with s:
    //   (p + tr) × s = (q + us) × s
    // We know that s × s = 0, so this can be rewritten as:
    //   t(r × s) = (q − p) × s
    // Then solve for t to get:
    //   t = (q − p) × s / (r × s)
    // Similarly, for u we get:
    //   u = (q − p) × r / (r × s)
    var rxs = cross(r, s),
        q_p = [q[0] - p[0], q[1] - p[1]],
        t = cross(q_p, s) / rxs,
        u = cross(q_p, r) / rxs,
        epsilon = 1e-6;

    return t > epsilon && t < 1 - epsilon && u > epsilon && u < 1 - epsilon;
  }

  function cross(a, b) {
    return a[0] * b[1] - a[1] * b[0];
  }

  Raphael.el.toString = function ()
  {
    // Graph needs toString() on elements to identify vertices
    return "Raphael Object #"+this.id;
  }
})(Raphael);
<|endoftext|>


<commit_before>const Client         = require('./../binary/base/client').Client;
const getLanguage    = require('./../binary/base/language').getLanguage;
const localize       = require('./../binary/base/localize').localize;
const url_for_static = require('./../binary/base/url').url_for_static;

class BinaryOneSignal {
    constructor() {
        this.OneSignal = window.OneSignal || [];
        this.options = {
            appId       : '8e2d0514-4c65-424e-b87e-4ffaaa61da21',
            // safari_web_id: 'YOUR_SAFARI_WEB_ID',
            path        : url_for_static('/'),
            autoRegister: true,
            notifyButton: {
                enable: false,
            },
            persistNotification: false,
            welcomeNotification: {
                title  : 'Binary.com',
                message: localize('Thank you for subscribing!'),
            },
            allowLocalhostAsSecureOrigin: true,
        };
        this.configure();
    }

    /*
     * Initializes OneSignal SDK
     * Notes:
     *  - do not call 'init' twice
     *  - 'init' call is required before any function can be used
     *  - log level can be set to 'trace/debug/info/warn/error' or 'silent' to disable all but in production
     *     - refer https://www.npmjs.com/package/loglevel
     */
    configure() {
        this.OneSignal.log.setLevel('silent'); // Disable all error logging
        this.OneSignal.push(() => {
            // Register the worker at root scope, pushed before 'init'
            this.OneSignal.SERVICE_WORKER_PARAM = { scope: url_for_static('/') };
        });
        this.OneSignal.push(['init', this.options]);
    }

    /*
     * Checks if a user has already accepted push notifications,
     * then send the user website language and Binary login_id to OneSignal
     */
    checkSubscription() {
        this.OneSignal.push(() => {
            if (window.location.hostname !== 'www.binary.com') return; // Use in production
            // If we're on an unsupported browser, do nothing
            if (!this.OneSignal.isPushNotificationsSupported()) {
                return;
            }
            this.OneSignal.isPushNotificationsEnabled()
                .then((isPushEnabled) => {
                    if (isPushEnabled) {
                        this.OneSignal.getTags((tags) => {
                            if (tags.language === undefined) {
                                this.OneSignal.sendTag('language', getLanguage().toLowerCase());
                            }
                            if (Client.is_logged_in() && tags.login_id === undefined) {
                                this.OneSignal.sendTag('login_id', Client.get('loginid'));
                            }
                        });
                    }
                });
        });
    }
}

export default new BinaryOneSignal();
<commit_msg>Fix error in logged_in and limit to production<commit_after>const Client         = require('./../binary/base/client').Client;
const getLanguage    = require('./../binary/base/language').getLanguage;
const localize       = require('./../binary/base/localize').localize;
const url_for_static = require('./../binary/base/url').url_for_static;

class BinaryOneSignal {
    constructor() {
        if (!isApplicable()) return;
        this.OneSignal = window.OneSignal || [];
        this.options = {
            appId       : '8e2d0514-4c65-424e-b87e-4ffaaa61da21',
            // safari_web_id: 'YOUR_SAFARI_WEB_ID',
            path        : url_for_static('/'),
            autoRegister: true,
            notifyButton: {
                enable: false,
            },
            persistNotification: false,
            welcomeNotification: {
                title  : 'Binary.com',
                message: localize('Thank you for subscribing!'),
            },
            allowLocalhostAsSecureOrigin: true,
        };
        this.configure();
    }

    /*
     * Initializes OneSignal SDK
     * Notes:
     *  - do not call 'init' twice
     *  - 'init' call is required before any function can be used
     *  - log level can be set to 'trace/debug/info/warn/error' or 'silent' to disable all but in production
     *     - refer https://www.npmjs.com/package/loglevel
     */
    configure() {
        this.OneSignal.log.setLevel('silent'); // Disable all error logging
        this.OneSignal.push(() => {
            // Register the worker at root scope, pushed before 'init'
            this.OneSignal.SERVICE_WORKER_PARAM = { scope: url_for_static('/') };
        });
        this.OneSignal.push(['init', this.options]);
    }

    /*
     * Checks if a user has already accepted push notifications,
     * then send the user website language and Binary login_id to OneSignal
     */
    checkSubscription() {
        if (!isApplicable()) return;
        this.OneSignal.push(() => {
            // If we're on an unsupported browser, do nothing
            if (!this.OneSignal.isPushNotificationsSupported()) {
                return;
            }
            this.OneSignal.isPushNotificationsEnabled()
                .then((isPushEnabled) => {
                    if (isPushEnabled) {
                        this.OneSignal.getTags((tags) => {
                            if (tags.language === undefined) {
                                this.OneSignal.sendTag('language', getLanguage().toLowerCase());
                            }
                            if (Client.is_logged_in() && tags.login_id === undefined) {
                                this.OneSignal.sendTag('login_id', Client.get('loginid'));
                            }
                        });
                    }
                });
        });
    }
}

const isApplicable = () => (window.location.hostname === 'www.binary.com' && !/logged_inws/i.test(window.location.pathname));

export default new BinaryOneSignal();
<|endoftext|>


<commit_before>"use strict";

let log = require('./public/lib/log');
let Deferred = require('./public/lib/Deferred');
let dbIO = require('./server/DatabaseIO');
let getExif = require('exif-async');

log('start reading exif data')

function isImage(row) {
	let fileName = row.path.toLowerCase();
	return fileName.endsWith('.jpg') || fileName.endsWith('.jpeg');
}

function updatePhotoExifData(photoId, exif) {
	return new Promise((resolve, reject) => {

		let deviceTag = exif.image.Model ? exif.image.Model.replace(/\0/g, '') : null;
		let exifDate = exif.exif.CreateDate;
		log('updating photo date: ' + photoId + ' ' + exifDate)

		let deferred1 = dbIO.updatePhoto([exifDate, photoId])
		let deferredAll = [deferred1]
		if (deviceTag) {
			deferredAll.push(dbIO.addOrGetTag(deviceTag).then((tagId) => {
				dbIO.addPhotoTag(photoId, tagId);
			}));
		}
		Deferred.all(deferredAll).then(resolve).catch(reject)
	});
}

/**
 * calls a function on an array but only X at the same time
 * @param arr
 * @param fnc
 * @param batchSize
 * @returns {Promise}
 */
function throttledProcess(arr, fnc, batchSize) {
	return new Promise((resolve, reject) => {
		function repeat() {
			let promiseList = arr.splice(0, batchSize).map(item => {
				return fnc(item)
			})
			Promise.all(promiseList).then(() => {
				console.log('processed batch', batchSize)
				if (arr.length === 0) {
					resolve()
					return;
				}
				repeat()
			}).catch(reject)
		}
	})
}

function updateExifInBatches() {
	let promise = new Promise(function (resolve, reject) {
		dbIO.readAllPhotos().then(data => {
			log('found photos: ' + data.length)

			function fnc(row) {
				return new Promise((res, rej) => {
					getExif(row.path).then(exif => {
						dbIO.updatePhoto([exif.exif.CreateDate, row.id]).then(res).catch(rej)
					}).catch(rej)
				});
			}

			let promise = throttledProcess(data.filter(row => isImage(row)), fnc, 10);
			promise.then(resolve).catch(reject)
		}).catch(reject)
	})
	return promise
}

function updateExif() {
	let promise = new Promise(function (resolve, reject) {
		dbIO.readAllPhotos().then(data => {
			log('found photos: ' + data.length)

			let promiseList = data.filter(row => isImage(row)).slice(0, 100).map(row => {
				//console.log('starting to read exif for: ', row.path)
				return new Promise((internResolve, internReject) => {
					getExif(row.path).then(exif => {
						internResolve([exif.exif.CreateDate, row.id]);
					}).catch(err => {
						console.error('error reading exif for ', row.path)
						internResolve(null)
					})
				})
			})
			Promise.all(promiseList).then((results) => {
				// console.log(results)
				let validResults = results.filter(result => result !== null);
				let promises = validResults.map(result => {
					return updatePhotoExifData(result.row.id, result.exif)
					// console.log()
				})
				Promise.all(promises).then(resolve).catch(reject)
			}).catch(reject)
		}).catch(reject)
	})
	return promise
}

dbIO.initialize().then(connection => {
	// dbIO.recreateTables(connection).then(() => {
	updateExifInBatches().then(() => {
		// indexFolder(folder).then(() => {
		process.exit(0)
	}).catch(err => {
		console.error(err)
		process.exit(1)
	})
	// });
}, console.error);

<commit_msg>improve batch processing of exifupdater<commit_after>"use strict";

let log = require('./public/lib/log');
let Deferred = require('./public/lib/Deferred');
let dbIO = require('./server/DatabaseIO');
let getExif = require('exif-async');

log('start reading exif data')

function isImage(row) {
	let fileName = row.path.toLowerCase();
	return fileName.endsWith('.jpg') || fileName.endsWith('.jpeg');
}

function updatePhotoExifData(photoId, exif) {
	return new Promise((resolve, reject) => {

		let deviceTag = exif.image.Model ? exif.image.Model.replace(/\0/g, '') : null;
		let exifDate = exif.exif.CreateDate;
		log('updating photo date: ' + photoId + ' ' + exifDate)

		let deferred1 = dbIO.updatePhoto([exifDate, photoId])
		let deferredAll = [deferred1]
		if (deviceTag) {
			deferredAll.push(dbIO.addOrGetTag(deviceTag).then((tagId) => {
				dbIO.addPhotoTag(photoId, tagId);
			}));
		}
		Deferred.all(deferredAll).then(resolve).catch(reject)
	});
}

/**
 * calls a function on an array but only X at the same time
 * @param arr the array to iteratively call the function for
 * @param fnc must return a promise
 * @param batchSize the number to process simultaneously
 * @returns {Promise}
 */
function throttledProcess(arr, fnc, batchSize) {
	return new Promise((resolve, reject) => {
		function recurse() {
			let promiseList = arr.splice(0, batchSize).map(item => {
				return fnc(item)
			})
			Promise.all(promiseList).then(() => {
				console.log('processed batch', batchSize)
				if (arr.length === 0) {
					resolve()
					return;
				}
				recurse()
			}).catch(reject)
		}

		recurse()
	})
}

function updateExifInBatches() {
	let promise = new Promise(function (resolve, reject) {
		dbIO.readAllPhotos().then(data => {
			log('found photos: ' + data.length)

			function fnc(row) {
				return new Promise((res, rej) => {
					getExif(row.path).then(exif => {
						updatePhotoExifData(row.id, exif).then(res).catch(rej)
					}).catch(err => {
						console.error('error reading exif for ', row.path)
						res()
					})
				});
			}

			let promise = throttledProcess(data.filter(row => isImage(row)), fnc, 100);
			promise.then(resolve).catch(reject)
		}).catch(reject)
	})
	return promise
}

function updateExif() {
	let promise = new Promise(function (resolve, reject) {
		dbIO.readAllPhotos().then(data => {
			log('found photos: ' + data.length)

			let promiseList = data.filter(row => isImage(row)).slice(0, 100).map(row => {
				//console.log('starting to read exif for: ', row.path)
				return new Promise((internResolve, internReject) => {
					getExif(row.path).then(exif => {
						internResolve([exif.exif.CreateDate, row.id]);
					}).catch(err => {
						console.error('error reading exif for ', row.path)
						internResolve(null)
					})
				})
			})
			Promise.all(promiseList).then((results) => {
				// console.log(results)
				let validResults = results.filter(result => result !== null);
				let promises = validResults.map(result => {
					return updatePhotoExifData(result.row.id, result.exif)
					// console.log()
				})
				Promise.all(promises).then(resolve).catch(reject)
			}).catch(reject)
		}).catch(reject)
	})
	return promise
}

dbIO.initialize().then(connection => {
	// dbIO.recreateTables(connection).then(() => {
	updateExifInBatches().then(() => {
		// indexFolder(folder).then(() => {
		process.exit(0)
	}).catch(err => {
		console.error(err)
		process.exit(1)
	})
	// });
}, console.error);

<|endoftext|>


<commit_before>var GoogleMap = {
	getLinkToAddress: function(addr) {
		if (addr instanceof Address)
			return 'http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=' + addr.toString();
		else
			return 'http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=' + addr;
	},
	getLinkToAddressDirection: function(destination, location) {
	}
};<commit_msg>added direction link to GoogleMap<commit_after>var GoogleMap = {
	getLinkToAddress: function(addr) {
		if (addr instanceof Address)
			return 'http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=' + addr.toString();
		else
			return 'http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=' + addr;
	},
	getLinkToAddressDirection: function(destination, location) {
		// http://maps.google.com/maps?f=d&source=s_d&saddr=417+N+Tatnall+St,+Wilmington,+DE+19801&daddr=427+N+Tatnall+St,+Wilmington,+DE+19801
		if (destination instanceof Address)
			destination = destination.toString();
		if (location instanceof Address)
			location = location.toString();
		return 'http://maps.google.com/maps?f=d&source=s_d&saddr=' + location + '&daddr=' + destination;
	}
};<|endoftext|>


<commit_before>jsture.Element = Class.extend( {

  init : function init(element) {
    this.element = element;
    this.setupMouseEventHandlers();
  },

  setupMouseEventHandlers: function setupMouseEventHandlers() {
    ProtoJS.Event.observe(this.element, 'mousedown',
                          this.handleMouseDown.scope(this));
    ProtoJS.Event.observe(this.element, 'mouseup',
                          this.handleMouseUp.scope(this));
    ProtoJS.Event.observe(document, 'mousemove',
                          this.handleMouseMove.scope(this));
  },

  getWidth : function getWith() {
    return this.element.offsetWidth;
  },

  getHeight : function getHeight() {
    return this.element.offsetHeight;
  },

  getLeft: function getLeft() {
    var elem = this.element;
    var left = 0;
    while( elem != null ) {
      left += elem.offsetLeft;
      elem = elem.offsetParent;
    }
    return left;
  },

  getTop : function getTop() {
    var elem = this.element;
    var top = 0;
    while( elem != null ) {
      top += elem.offsetTop;
      elem = elem.offsetParent;
    }
    return top;
  },

  getXY: function getXY(e) {
    var x,y;
    if( ProtoJS.Browser.IE ) {
      x = event.clientX + document.body.scrollLeft;
      y = event.clientY + document.body.scrollTop;
    } else {
      x = e.pageX;
      y = e.pageY;
    }
    return { x: x - this.getLeft(), y: y - this.getTop() };
  },

  handleMouseDown: function handleMouseDown(event) {
    this.mousepressed = true;
    var pos = this.getXY(event);
    this.fireEvent( "mousedown", pos );
    this.mousePos = pos;
  },

  handleMouseUp: function handleMouseUp(event) {
    this.mousepressed = false;
    var pos = this.getXY(event);
    this.fireEvent( "mouseup", pos );
    this.mousePos = pos;
  },

  handleMouseMove: function handleMouseMove(event) {
    if( this.mousepressed ) { this.handleMouseDrag(event); }
    var pos = this.getXY(event);
    if( pos ) {
      var mouseWasOver = this.mouseOver;
      this.mouseOver = ( pos.x >= 0 && pos.x <= this.getWidth() ) &&
                       ( pos.y >= 0 && pos.y <= this.getHeight() );
      if(this.mouseOver && !mouseWasOver) { this.fireEvent( "mouseEnter" );}
      if(!this.mouseOver && mouseWasOver) { this.fireEvent( "mouseLeave" );}
    }
  },

  handleMouseDrag: function handleMouseDrag(event) {
    var pos = this.getXY(event);
    this.fireEvent( "mousedrag", {
      x: pos.x,
      y: pos.y,
      dx: pos.x - this.mousePos.x,
      dy: pos.y - this.mousePos.y
    } );
    this.mousePos = pos;
  }

} );

ProtoJS.mix( ProtoJS.Event.Handling, jsture.Element.prototype );
<commit_msg>added support for iOS touch events<commit_after>jsture.Element = Class.extend( {

  init : function init(element) {
    this.element = element;
    this.setupMouseEventHandlers();
    this.setupTouchEventHandlers();
  },

  setupMouseEventHandlers: function setupMouseEventHandlers() {
    ProtoJS.Event.observe(this.element, 'mousedown',
                          this.handleMouseDown.scope(this));
    ProtoJS.Event.observe(this.element, 'mouseup',
                          this.handleMouseUp.scope(this));
    ProtoJS.Event.observe(document, 'mousemove',
                          this.handleMouseMove.scope(this));

  },

  setupTouchEventHandlers: function setupTouchEventHandlers() {
    ProtoJS.Event.observe(this.element, 'touchstart',
                          this.handleTouchStart.scope(this));
    ProtoJS.Event.observe(this.element, 'touchmove',
                          this.handleTouchMove.scope(this));
    ProtoJS.Event.observe(this.element, 'touchend',
                          this.handleTouchEnd.scope(this));
  },

  getWidth : function getWith() {
    return this.element.offsetWidth;
  },

  getHeight : function getHeight() {
    return this.element.offsetHeight;
  },

  getLeft: function getLeft() {
    var elem = this.element;
    var left = 0;
    while( elem != null ) {
      left += elem.offsetLeft;
      elem = elem.offsetParent;
    }
    return left;
  },

  getTop : function getTop() {
    var elem = this.element;
    var top = 0;
    while( elem != null ) {
      top += elem.offsetTop;
      elem = elem.offsetParent;
    }
    return top;
  },

  getXY: function getXY(e) {
    var x,y;
    if( ProtoJS.Browser.IE ) {
      x = event.clientX + document.body.scrollLeft;
      y = event.clientY + document.body.scrollTop;
    } else {
      x = e.pageX;
      y = e.pageY;
    }
    return { x: x - this.getLeft(), y: y - this.getTop() };
  },

  handleMouseDown: function handleMouseDown(event) {
    this.mousepressed = true;
    var pos = this.getXY(event);
    this.fireEvent( "mousedown", pos );
    this.mousePos = pos;
  },

  handleMouseUp: function handleMouseUp(event) {
    this.mousepressed = false;
    var pos = this.getXY(event);
    this.fireEvent( "mouseup", pos );
    this.mousePos = pos;
  },

  handleMouseMove: function handleMouseMove(event) {
    if( this.mousepressed ) { this.handleMouseDrag(event); }
    var pos = this.getXY(event);
    if( pos ) {
      var mouseWasOver = this.mouseOver;
      this.mouseOver = ( pos.x >= 0 && pos.x <= this.getWidth() ) &&
                       ( pos.y >= 0 && pos.y <= this.getHeight() );
      if(this.mouseOver && !mouseWasOver) { this.fireEvent( "mouseEnter" );}
      if(!this.mouseOver && mouseWasOver) { this.fireEvent( "mouseLeave" );}
    }
  },

  handleMouseDrag: function handleMouseDrag(event) {
    var pos = this.getXY(event);
    this.fireEvent( "mousedrag", {
      x: pos.x,
      y: pos.y,
      dx: pos.x - this.mousePos.x,
      dy: pos.y - this.mousePos.y
    } );
    this.mousePos = pos;
  },

  handleTouchStart: function handleTouchStart(event) {
    if( event.touches.length == 1 ) {
      this.handleMouseDown(event.touches[0]);
      event.preventDefault();
    }
  },

  handleTouchMove: function handleTouchMove(event) {
    if( event.touches.length == 1 ) {
      this.handleMouseDrag(event.touches[0]);
      event.preventDefault();
    }
  },

  handleTouchEnd: function handleTouchEnd(event) {
    this.handleMouseUp(event);
    event.preventDefault();
  }

} );

ProtoJS.mix( ProtoJS.Event.Handling, jsture.Element.prototype );
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */
/**
 * Crossfire
 * Firebug extension to add support for remote debug protocol.
 *
 */

FBL.ns(function() { with(FBL) {
    const SocketTransport = Components.classes["@almaden.ibm.com/crossfire/socket-transport;1"];

    /**
     * @name CrossfireModule
     * @namespace CrossfireModule
     * @module Firebug Module for Crossfire. This module acts as a controller
     * between Firebug and the remote debug connection.  It is responsible for
     * opening a connection to the remote debug host and dispatching any
     * command requests to the FirebugCommandAdaptor (@see FirebugCommandAdaptor.js).
     *
     * This module also adds context and debugger listeners and sends the
     * appropriate events to the remote host.
     */
    var CrossfireModule = extend(Firebug.Module, /**@lends CrossfireModule */ {
        contexts: [],
        dispatchName: "Crossfire",

        /** extends Firebug.Module */
        initialize: function() {
            var commandLine = Components.classes["@almaden.ibm.com/crossfire/command-line-handler;1"].getService().wrappedJSObject;
            var host = commandLine.getHost();
            var port = commandLine.getPort();
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE Got command-line args: host => " + host + " port => " + port);

            this.transport = SocketTransport.createInstance().wrappedJSObject;
            this.transport.open(host, port);

            this.transport.addListener(this);

            Firebug.Debugger.addListener(this);
            Firebug.Console.addListener(this);
            Firebug.Inspector.addListener(this);

            this.running = true;
        },

        // ----- Crossfire transport listener -----

        /**
         * @description
         * Listener function called by the transport when a request is
         * received.
         *
         * @description
         * Looks up the context by the request object's context_id
         * property and calls the requested command on that context's
         * command adaptor.
         */
        handleRequest: function( request) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE received request " + request.toSource());

            var command = request.command;

            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE handling command: " + command + ", with arguments: " + request.arguments );

            var response;
            if (command == "listcontexts") {
                response = this.listContexts();
            } else {
                var commandAdaptor;
                var contextId = request.context_id;
                for (var i = 0; i < this.contexts.length; i++) {
                    var context = this.contexts[i];
                    if (contextId == context.window.location.href) {
                        commandAdaptor = context.Crossfire.commandAdaptor;
                        break;
                    }
                }
                response = commandAdaptor[command].apply(commandAdaptor, [ request.arguments ]);
            }

            if (response) {
                if (FBTrace.DBG_CROSSFIRE)
                    FBTrace.sysout("CROSSFIRE sending response => " + response.toSource());
                this.transport.sendResponse(command, request.seq, response, this.running, true);
            } else {
                this.transport.sendResponse(command, request.seq, {}, this.running, false);
            }
        },

        /**
         *
         * @description send events generated by Firebug to the remote host.
         * @param context</context> context of this event.
         * @param eventName name of the event
         * @param arguments any arguments after the first two will be passed to the event handler.
         */
        handleEvent: function( context, eventName /*, [arg1 [, arg2] ...] */) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE handleEvent " + eventName);

            var args = Array.prototype.slice.apply(arguments, [2]);

            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE handleEvent arguments: " + args);

            var eventAdaptor = context.Crossfire.eventAdaptor;
            var eventData = eventAdaptor[eventName].apply(eventAdaptor, args);
            this.transport.sendEvent(eventName, eventData);
        },

        // ----- firebug listeners -----
        /*
        onSourceFileCreated: function( context, sourceFile) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  onSourceFileCreated");
            // send afterCompile event?
        },
        */

        // ----- context listeners -----
        /**
         * @description Add the new context to our list of contexts.
         * @param context
         */
        initContext: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  initContext");
            context.Crossfire = {};
            this.contexts.push(context);
        },

        /**
         * @description Create a new command adaptor for the context when it is loaded. Send "navigated" event.
         * @param context
         */
        loadedContext: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  loadedContext");
            var contextId = context.window.location.href;

            context.Crossfire["commandAdaptor"] = new Crossfire.FirebugCommandAdaptor(context);
            context.Crossfire["eventAdaptor"] = new Crossfire.FirebugEventAdaptor(context);

            //this.handleEvent("navigated");
        },

        /* @ignore
        showContext: function() {

        },
        */

        /**
         *  @description Remove the context from our list of contexts.
         *  @param context
         */
        destroyContext: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: destroyContext");
            var contextId = context.window.location.href;
            for (var i = 0; i < this.contexts.length; i++) {
                if (this.contexts[i].window.location.href == contextId) {
                    this.contexts.splice(i, 1);
                    break;
                }
            }
        },

        // ----- utils -----

        /**
         * listContexts method is called in response to a listcontexts command.
         * This method returns all the context id's that we know about.
         *
         * This is the only method that returns a protocol command response
         * that is not implemented in FirebugCommandAdaptor, because it is
         * not specific to one context.
         */
        listContexts: function() {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE listing " + this.contexts.length + " contexts...");
            var contextIds = [];
            for (var i = 0; i < this.contexts.length; i++) {
                contextIds.push(this.contexts[i].window.location.href);
            }
            return { "contexts": contextIds };
        },

        /**
         * Make a copy of a frame since the jsdIStackFrame's are ephemeral,
         * but our protocol is asynchronous so the original frame object may
         * be gone by the time the remote host requests it.
         */
        copyFrame: function copyFrame( frame) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("copy frame => " + frame);

            var frameCopy = {};

            // recursively copy scope chain
            function copyScope( aScope) {
                if (FBTrace.DBG_CROSSFIRE)
                    FBTrace.sysout("Copying scope => " + aScope);

                var copiedScope = {};
                try {
                    var listValue = {value: null}, lengthValue = {value: 0};
                    aScope.getProperties(listValue, lengthValue);

                    for (var i = 0; i < lengthValue.value; ++i) {
                        var prop = listValue.value[i];
                        var name = prop.name.getWrappedValue();
                        copiedScope[name.toString()] = prop.value.getWrappedValue();
                    }

                    if (aScope.jsParent) {
                        copiedScope.parent = copyScope(aScope.jsParent);
                    }
                } catch (ex) {
                    if (FBTrace.DBG_CROSSFIRE) FBTrace.sysout("Exception copying scope => " + e);
                }
                return copiedScope;
            }
            frameCopy["scope"] =  copyScope(frame.scope);

            if (frame && frame.isValid) {
                var thisObj = {};

                try {
                   var thisVal = frame.thisValue.getWrappedValue();
                   for (var p in thisVal) {
                       if (thisVal.hasOwnProperty(p)) {
                           thisObj[p] = thisVal[p];
                       }
                   }
                } catch( e) {
                    if (FBTrace.DBG_CROSSFIRE) FBTrace.sysout("Exception copying thisValue => " + e);
                     frameCopy["thisValue"] = frame.thisValue;
                }
                frameCopy["thisValue"] = thisObj;

                try {
                    frameCopy["callee"] = frame.callee.getWrappedValue();
                } catch( e) {
                    frameCopy["callee"] = frame.callee;
                }

                frameCopy["functionName"] = frame.functionName;

                frameCopy["line"] = frame.line;

                // recursively copy all the frames in the stack
                function copyStack( aFrame) {
                    if (FBTrace.DBG_CROSSFIRE)
                        FBTrace.sysout("CROSSFIRE copyStack: calling frame is => " + aFrame.callingFrame);
                    if (aFrame.callingFrame && aFrame.callingFrame.isValid) {
                        var stack = copyStack(aFrame.callingFrame);
                        stack.push(copyFrame(aFrame));
                        return stack;
                    } else {
                        return [ copyFrame(aFrame) ];
                    }
                }
                if (frame.callingFrame) {
                    var stack = copyStack(frame.callingFrame);
                    frameCopy["stack"] = stack;
                    frameCopy["frameIndex"] = stack.length -1;
                } else {
                    frameCopy["frameIndex"] = 0;
                }

            }
            return frameCopy;
        },

        // ----- Firebug Debugger listener -----

        /**
         * Copy the current frame (in case remote host requests it)
         * and send onBreak event.
         */
        onStartDebugging: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  onStartDebugging");

            var frame = context.currentFrame;
            var lineno = 1;
            var sourceFile = Firebug.SourceFile.getSourceFileByScript(context, frame.script)
            if (sourceFile) {
                var analyzer = sourceFile.getScriptAnalyzer(frame.script);
                if (analyzer)
                    lineno = analyzer.getSourceLineFromFrame(context, frame);
            }
            var href = sourceFile.href.toString();
            var contextId = context.window.location.href;

            var copiedFrame = this.copyFrame(frame);

            context.Crossfire.commandAdaptor.currentFrame = copiedFrame;

            this.handleEvent(context, "onBreak", href, lineno);
            this.running = false;
        },

        onStop: function(context, frame, type, rv) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  onStop");
        },

        /**
         * Send onResume event and set status 'running' to true.
         */
        onResume: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: onResume");
            context.Crossfire.commandAdaptor.currentFrame = null;
            this.handleEvent(context, "onResume");
            this.running = true;
        },

        /**
         * Send onToggleBreakpoint event.
         */
        onToggleBreakpoint: function(context, url, lineNo, isSet, props) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: onToggleBreakpoint");
            this.handleEvent(context, "onToggleBreakpoint");
        },

        /**
         * Send onToggleBreakpoint event.
         */
        onToggleErrorBreakpoint: function(context, url, lineNo, isSet, props) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: onToggleErrorBreakpoint");
            this.handleEvent(context, "onToggleBreakpoint");

        },

        onJSDActivtate: function() {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  onJSDActivtate");

        },

        onJSDDeactivate: function() {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: onJSDDeactivate");
        },

        // ----- Firebug Console listener -----

        /**
         * logFormatted listener.
         * @description Generates event packets based on the className (log,debug,info,warn,error).
         * @description The object or message logged is contained in the packet's data property.
         * The generated event names are:
         * 		onConsoleLog,
         * 		onConsoleDebug,
         * 		onConsoleInfo,
         * 		onConsoleWarn,
         * 		onConsoleError
         */
        logFormatted: function(context, objects, className, sourceLink) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE logFormatted");

            var win = context.window;
            var eventName = "onConsole" + className.substring(0,1).toUpperCase() + className.substring(1);
            var data = (win.wrappedJSObject?win.wrappedJSObject:win)._firebug.userObjects;

            this.handleEvent(context, eventName, data);
        },

        // ----- Firebug.Inspector Listener -----

        /**
         * @description Send onInspectNode event.
         */
        onInspectNode: function(context, node) {
            node = node.wrappedJSObject;
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE onInspectNode", node);
            this.handleEvent(context, "onInspectNode", node);
        },

        /* @ignore
        onStopInspecting: function(context, node) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE onStopInspecting");

            var contextId = context.window.location.href;
            this.transport.sendEvent("onStopInspecting", { "context_id": contextId });
        }
        */
    });

    // register module
    Firebug.registerModule(CrossfireModule);

//end FBL.ns()
}});<commit_msg>On shutdown, some contexts don't have windows<commit_after>/* See license.txt for terms of usage */
/**
 * Crossfire
 * Firebug extension to add support for remote debug protocol.
 *
 */

FBL.ns(function() { with(FBL) {
    const SocketTransport = Components.classes["@almaden.ibm.com/crossfire/socket-transport;1"];

    /**
     * @name CrossfireModule
     * @namespace CrossfireModule
     * @module Firebug Module for Crossfire. This module acts as a controller
     * between Firebug and the remote debug connection.  It is responsible for
     * opening a connection to the remote debug host and dispatching any
     * command requests to the FirebugCommandAdaptor (@see FirebugCommandAdaptor.js).
     *
     * This module also adds context and debugger listeners and sends the
     * appropriate events to the remote host.
     */
    var CrossfireModule = extend(Firebug.Module, /**@lends CrossfireModule */ {
        contexts: [],
        dispatchName: "Crossfire",

        /** extends Firebug.Module */
        initialize: function() {
            var commandLine = Components.classes["@almaden.ibm.com/crossfire/command-line-handler;1"].getService().wrappedJSObject;
            var host = commandLine.getHost();
            var port = commandLine.getPort();
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE Got command-line args: host => " + host + " port => " + port);

            this.transport = SocketTransport.createInstance().wrappedJSObject;
            this.transport.open(host, port);

            this.transport.addListener(this);

            Firebug.Debugger.addListener(this);
            Firebug.Console.addListener(this);
            Firebug.Inspector.addListener(this);

            this.running = true;
        },

        // ----- Crossfire transport listener -----

        /**
         * @description
         * Listener function called by the transport when a request is
         * received.
         *
         * @description
         * Looks up the context by the request object's context_id
         * property and calls the requested command on that context's
         * command adaptor.
         */
        handleRequest: function( request) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE received request " + request.toSource());

            var command = request.command;

            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE handling command: " + command + ", with arguments: " + request.arguments );

            var response;
            if (command == "listcontexts") {
                response = this.listContexts();
            } else {
                var commandAdaptor;
                var contextId = request.context_id;
                for (var i = 0; i < this.contexts.length; i++) {
                    var context = this.contexts[i];
                    if (contextId == context.window.location.href) {
                        commandAdaptor = context.Crossfire.commandAdaptor;
                        break;
                    }
                }
                response = commandAdaptor[command].apply(commandAdaptor, [ request.arguments ]);
            }

            if (response) {
                if (FBTrace.DBG_CROSSFIRE)
                    FBTrace.sysout("CROSSFIRE sending response => " + response.toSource());
                this.transport.sendResponse(command, request.seq, response, this.running, true);
            } else {
                this.transport.sendResponse(command, request.seq, {}, this.running, false);
            }
        },

        /**
         *
         * @description send events generated by Firebug to the remote host.
         * @param context</context> context of this event.
         * @param eventName name of the event
         * @param arguments any arguments after the first two will be passed to the event handler.
         */
        handleEvent: function( context, eventName /*, [arg1 [, arg2] ...] */) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE handleEvent " + eventName);

            var args = Array.prototype.slice.apply(arguments, [2]);

            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE handleEvent arguments: " + args);

            var eventAdaptor = context.Crossfire.eventAdaptor;
            var eventData = eventAdaptor[eventName].apply(eventAdaptor, args);
            this.transport.sendEvent(eventName, eventData);
        },

        // ----- firebug listeners -----
        /*
        onSourceFileCreated: function( context, sourceFile) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  onSourceFileCreated");
            // send afterCompile event?
        },
        */

        // ----- context listeners -----
        /**
         * @description Add the new context to our list of contexts.
         * @param context
         */
        initContext: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  initContext");
            context.Crossfire = {};
            this.contexts.push(context);
        },

        /**
         * @description Create a new command adaptor for the context when it is loaded. Send "navigated" event.
         * @param context
         */
        loadedContext: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  loadedContext");
            var contextId = context.window.location.href;

            context.Crossfire["commandAdaptor"] = new Crossfire.FirebugCommandAdaptor(context);
            context.Crossfire["eventAdaptor"] = new Crossfire.FirebugEventAdaptor(context);

            //this.handleEvent("navigated");
        },

        /* @ignore
        showContext: function() {

        },
        */

        /**
         *  @description Remove the context from our list of contexts.
         *  @param context
         */
        destroyContext: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: destroyContext");
            var contextId = context.window.location.href;
            for (var i = 0; i < this.contexts.length; i++) {
                if (this.contexts[i].window && this.contexts[i].window.location.href == contextId) {
                    this.contexts.splice(i, 1);
                    break;
                }
            }
        },

        // ----- utils -----

        /**
         * listContexts method is called in response to a listcontexts command.
         * This method returns all the context id's that we know about.
         *
         * This is the only method that returns a protocol command response
         * that is not implemented in FirebugCommandAdaptor, because it is
         * not specific to one context.
         */
        listContexts: function() {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE listing " + this.contexts.length + " contexts...");
            var contextIds = [];
            for (var i = 0; i < this.contexts.length; i++) {
                contextIds.push(this.contexts[i].window.location.href);
            }
            return { "contexts": contextIds };
        },

        /**
         * Make a copy of a frame since the jsdIStackFrame's are ephemeral,
         * but our protocol is asynchronous so the original frame object may
         * be gone by the time the remote host requests it.
         */
        copyFrame: function copyFrame( frame) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("copy frame => " + frame);

            var frameCopy = {};

            // recursively copy scope chain
            function copyScope( aScope) {
                if (FBTrace.DBG_CROSSFIRE)
                    FBTrace.sysout("Copying scope => " + aScope);

                var copiedScope = {};
                try {
                    var listValue = {value: null}, lengthValue = {value: 0};
                    aScope.getProperties(listValue, lengthValue);

                    for (var i = 0; i < lengthValue.value; ++i) {
                        var prop = listValue.value[i];
                        var name = prop.name.getWrappedValue();
                        copiedScope[name.toString()] = prop.value.getWrappedValue();
                    }

                    if (aScope.jsParent) {
                        copiedScope.parent = copyScope(aScope.jsParent);
                    }
                } catch (ex) {
                    if (FBTrace.DBG_CROSSFIRE) FBTrace.sysout("Exception copying scope => " + e);
                }
                return copiedScope;
            }
            frameCopy["scope"] =  copyScope(frame.scope);

            if (frame && frame.isValid) {
                var thisObj = {};

                try {
                   var thisVal = frame.thisValue.getWrappedValue();
                   for (var p in thisVal) {
                       if (thisVal.hasOwnProperty(p)) {
                           thisObj[p] = thisVal[p];
                       }
                   }
                } catch( e) {
                    if (FBTrace.DBG_CROSSFIRE) FBTrace.sysout("Exception copying thisValue => " + e);
                     frameCopy["thisValue"] = frame.thisValue;
                }
                frameCopy["thisValue"] = thisObj;

                try {
                    frameCopy["callee"] = frame.callee.getWrappedValue();
                } catch( e) {
                    frameCopy["callee"] = frame.callee;
                }

                frameCopy["functionName"] = frame.functionName;

                frameCopy["line"] = frame.line;

                // recursively copy all the frames in the stack
                function copyStack( aFrame) {
                    if (FBTrace.DBG_CROSSFIRE)
                        FBTrace.sysout("CROSSFIRE copyStack: calling frame is => " + aFrame.callingFrame);
                    if (aFrame.callingFrame && aFrame.callingFrame.isValid) {
                        var stack = copyStack(aFrame.callingFrame);
                        stack.push(copyFrame(aFrame));
                        return stack;
                    } else {
                        return [ copyFrame(aFrame) ];
                    }
                }
                if (frame.callingFrame) {
                    var stack = copyStack(frame.callingFrame);
                    frameCopy["stack"] = stack;
                    frameCopy["frameIndex"] = stack.length -1;
                } else {
                    frameCopy["frameIndex"] = 0;
                }

            }
            return frameCopy;
        },

        // ----- Firebug Debugger listener -----

        /**
         * Copy the current frame (in case remote host requests it)
         * and send onBreak event.
         */
        onStartDebugging: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  onStartDebugging");

            var frame = context.currentFrame;
            var lineno = 1;
            var sourceFile = Firebug.SourceFile.getSourceFileByScript(context, frame.script)
            if (sourceFile) {
                var analyzer = sourceFile.getScriptAnalyzer(frame.script);
                if (analyzer)
                    lineno = analyzer.getSourceLineFromFrame(context, frame);
            }
            var href = sourceFile.href.toString();
            var contextId = context.window.location.href;

            var copiedFrame = this.copyFrame(frame);

            context.Crossfire.commandAdaptor.currentFrame = copiedFrame;

            this.handleEvent(context, "onBreak", href, lineno);
            this.running = false;
        },

        onStop: function(context, frame, type, rv) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  onStop");
        },

        /**
         * Send onResume event and set status 'running' to true.
         */
        onResume: function( context) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: onResume");
            context.Crossfire.commandAdaptor.currentFrame = null;
            this.handleEvent(context, "onResume");
            this.running = true;
        },

        /**
         * Send onToggleBreakpoint event.
         */
        onToggleBreakpoint: function(context, url, lineNo, isSet, props) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: onToggleBreakpoint");
            this.handleEvent(context, "onToggleBreakpoint");
        },

        /**
         * Send onToggleBreakpoint event.
         */
        onToggleErrorBreakpoint: function(context, url, lineNo, isSet, props) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: onToggleErrorBreakpoint");
            this.handleEvent(context, "onToggleBreakpoint");

        },

        onJSDActivtate: function() {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE:  onJSDActivtate");

        },

        onJSDDeactivate: function() {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE: onJSDDeactivate");
        },

        // ----- Firebug Console listener -----

        /**
         * logFormatted listener.
         * @description Generates event packets based on the className (log,debug,info,warn,error).
         * @description The object or message logged is contained in the packet's data property.
         * The generated event names are:
         * 		onConsoleLog,
         * 		onConsoleDebug,
         * 		onConsoleInfo,
         * 		onConsoleWarn,
         * 		onConsoleError
         */
        logFormatted: function(context, objects, className, sourceLink) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE logFormatted");

            var win = context.window;
            var eventName = "onConsole" + className.substring(0,1).toUpperCase() + className.substring(1);
            var data = (win.wrappedJSObject?win.wrappedJSObject:win)._firebug.userObjects;

            this.handleEvent(context, eventName, data);
        },

        // ----- Firebug.Inspector Listener -----

        /**
         * @description Send onInspectNode event.
         */
        onInspectNode: function(context, node) {
            node = node.wrappedJSObject;
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE onInspectNode", node);
            this.handleEvent(context, "onInspectNode", node);
        },

        /* @ignore
        onStopInspecting: function(context, node) {
            if (FBTrace.DBG_CROSSFIRE)
                FBTrace.sysout("CROSSFIRE onStopInspecting");

            var contextId = context.window.location.href;
            this.transport.sendEvent("onStopInspecting", { "context_id": contextId });
        }
        */
    });

    // register module
    Firebug.registerModule(CrossfireModule);

//end FBL.ns()
}});<|endoftext|>


<commit_before>import Edit from './L.PM.Edit';

Edit.Circle = Edit.extend({
  initialize(layer) {
    this._layer = layer;
    this._enabled = false;
  },
  toggleEdit(options) {
    if (!this.enabled()) {
      this.enable(options);
    } else {
      this.disable();
    }
  },
  enabled() {
    return this._enabled;
  },
  enable(options) {
    L.Util.setOptions(this, options);

    this._map = this._layer._map;

    if (!this.enabled()) {
      // if it was already enabled, disable first
      // we don't block enabling again because new options might be passed
      this.disable();
    }

    // change state
    this._enabled = true;

    // // init markers
    this._initMarkers();

    // if polygon gets removed from map, disable edit mode
    this._layer.on('remove', e => {
      this.disable(e.target);
    });
  },
  disable(layer = this._layer) {
    // if it's not enabled, it doesn't need to be disabled
    if (!this.enabled()) {
      return false;
    }

    // prevent disabling if layer is being dragged
    if (layer.pm._dragging) {
      return false;
    }
    layer.pm._enabled = false;
    layer.pm._helperLayers.clearLayers();

    // clean up draggable
    layer.off('mousedown');
    layer.off('mouseup');

    // remove draggable class
    const el = layer._path ? layer._path : this._layer._renderer._container;
    L.DomUtil.removeClass(el, 'leaflet-pm-draggable');

    if (this._layerEdited) {
      this._layer.fire('pm:update', {});
    }
    this._layerEdited = false;

    return true;
  },
  _initMarkers() {
    const map = this._map;

    // cleanup old ones first
    if (this._helperLayers) {
      this._helperLayers.clearLayers();
    }

    // add markerGroup to map, markerGroup includes regular and middle markers
    this._helperLayers = new L.LayerGroup();
    this._helperLayers._pmTempLayer = true;
    this._helperLayers.addTo(map);

    // create marker for each coordinate
    const center = this._layer.getLatLng();
    const radius = this._layer._radius;

    const outer = this._getLatLngOnCircle(center, radius);

    this._centerMarker = this._createCenterMarker(center);
    this._outerMarker = this._createOuterMarker(outer);
    this._markers = [this._centerMarker, this._outerMarker];
    this._createHintLine(this._centerMarker, this._outerMarker);

    if (this.options.snappable) {
      this._initSnappableMarkers();
    }
  },
  _getLatLngOnCircle(center, radius) {
    const pointA = this._map.project(center);
    const pointB = L.point(pointA.x + radius, pointA.y);

    return this._map.unproject(pointB);
  },
  _resizeCircle() {
    this._syncHintLine();
    this._syncCircleRadius();
  },
  _moveCircle(e) {
    const center = e.latlng;
    this._layer.setLatLng(center);

    const radius = this._layer._radius;

    const outer = this._getLatLngOnCircle(center, radius);
    this._outerMarker.setLatLng(outer);
    this._syncHintLine();

    this._layer.fire('pm:centerplaced', {
      layer: this._layer,
      latlng: center,
    });
  },
  _onMarkerDragStart(e) {
    this._layer.fire('pm:markerdragstart', {
      markerEvent: e,
    });
  },
  _onMarkerDragEnd(e) {
    // fire edit event
    this._fireEdit();

    // fire markerdragend event
    this._layer.fire('pm:markerdragend', {
      markerEvent: e,
    });
  },
  _syncCircleRadius() {
    const A = this._centerMarker.getLatLng();
    const B = this._outerMarker.getLatLng();

    const distance = A.distanceTo(B);

    this._layer.setRadius(distance);
  },
  _syncHintLine() {
    const A = this._centerMarker.getLatLng();
    const B = this._outerMarker.getLatLng();

    // set coords for hintline from marker to last vertex of drawin polyline
    this._hintline.setLatLngs([A, B]);
  },
  _createHintLine(markerA, markerB) {
    const A = markerA.getLatLng();
    const B = markerB.getLatLng();
    this._hintline = L.polyline([A, B], this.options.hintlineStyle);
    this._hintline._pmTempLayer = true;
    this._helperLayers.addLayer(this._hintline);
  },
  _createCenterMarker(latlng) {
    const marker = this._createMarker(latlng);

    L.DomUtil.addClass(marker._icon, 'leaflet-pm-draggable');
    // TODO: switch back to move event once this leaflet issue is solved:
    // https://github.com/Leaflet/Leaflet/issues/6492
    marker.on('drag', this._moveCircle, this);
    // marker.on('contextmenu', this._removeMarker, this);

    return marker;
  },
  _createOuterMarker(latlng) {
    const marker = this._createMarker(latlng);

    marker.on('move', this._resizeCircle, this);

    return marker;
  },
  _createMarker(latlng) {
    const marker = new L.Marker(latlng, {
      draggable: true,
      icon: L.divIcon({ className: 'marker-icon' }),
    });

    marker._origLatLng = latlng;
    marker._pmTempLayer = true;

    marker.on('dragstart', this._onMarkerDragStart, this);
    marker.on('dragend', this._onMarkerDragEnd, this);

    this._helperLayers.addLayer(marker);

    return marker;
  },
  _fireEdit() {
    // fire edit event
    this._layer.fire('pm:edit');
    this._layerEdited = true;
  },
});
<commit_msg>Changed circle edit event from move to drag. Fixes #357<commit_after>import Edit from './L.PM.Edit';

Edit.Circle = Edit.extend({
  initialize(layer) {
    this._layer = layer;
    this._enabled = false;
  },
  toggleEdit(options) {
    if (!this.enabled()) {
      this.enable(options);
    } else {
      this.disable();
    }
  },
  enabled() {
    return this._enabled;
  },
  enable(options) {
    L.Util.setOptions(this, options);

    this._map = this._layer._map;

    if (!this.enabled()) {
      // if it was already enabled, disable first
      // we don't block enabling again because new options might be passed
      this.disable();
    }

    // change state
    this._enabled = true;

    // // init markers
    this._initMarkers();

    // if polygon gets removed from map, disable edit mode
    this._layer.on('remove', e => {
      this.disable(e.target);
    });
  },
  disable(layer = this._layer) {
    // if it's not enabled, it doesn't need to be disabled
    if (!this.enabled()) {
      return false;
    }

    // prevent disabling if layer is being dragged
    if (layer.pm._dragging) {
      return false;
    }
    layer.pm._enabled = false;
    layer.pm._helperLayers.clearLayers();

    // clean up draggable
    layer.off('mousedown');
    layer.off('mouseup');

    // remove draggable class
    const el = layer._path ? layer._path : this._layer._renderer._container;
    L.DomUtil.removeClass(el, 'leaflet-pm-draggable');

    if (this._layerEdited) {
      this._layer.fire('pm:update', {});
    }
    this._layerEdited = false;

    return true;
  },
  _initMarkers() {
    const map = this._map;

    // cleanup old ones first
    if (this._helperLayers) {
      this._helperLayers.clearLayers();
    }

    // add markerGroup to map, markerGroup includes regular and middle markers
    this._helperLayers = new L.LayerGroup();
    this._helperLayers._pmTempLayer = true;
    this._helperLayers.addTo(map);

    // create marker for each coordinate
    const center = this._layer.getLatLng();
    const radius = this._layer._radius;

    const outer = this._getLatLngOnCircle(center, radius);

    this._centerMarker = this._createCenterMarker(center);
    this._outerMarker = this._createOuterMarker(outer);
    this._markers = [this._centerMarker, this._outerMarker];
    this._createHintLine(this._centerMarker, this._outerMarker);

    if (this.options.snappable) {
      this._initSnappableMarkers();
    }
  },
  _getLatLngOnCircle(center, radius) {
    const pointA = this._map.project(center);
    const pointB = L.point(pointA.x + radius, pointA.y);

    return this._map.unproject(pointB);
  },
  _resizeCircle() {
    this._syncHintLine();
    this._syncCircleRadius();
  },
  _moveCircle(e) {
    const center = e.latlng;
    this._layer.setLatLng(center);

    const radius = this._layer._radius;

    const outer = this._getLatLngOnCircle(center, radius);
    this._outerMarker.setLatLng(outer);
    this._syncHintLine();

    this._layer.fire('pm:centerplaced', {
      layer: this._layer,
      latlng: center,
    });
  },
  _onMarkerDragStart(e) {
    this._layer.fire('pm:markerdragstart', {
      markerEvent: e,
    });
  },
  _onMarkerDragEnd(e) {
    // fire edit event
    this._fireEdit();

    // fire markerdragend event
    this._layer.fire('pm:markerdragend', {
      markerEvent: e,
    });
  },
  _syncCircleRadius() {
    const A = this._centerMarker.getLatLng();
    const B = this._outerMarker.getLatLng();

    const distance = A.distanceTo(B);

    this._layer.setRadius(distance);
  },
  _syncHintLine() {
    const A = this._centerMarker.getLatLng();
    const B = this._outerMarker.getLatLng();

    // set coords for hintline from marker to last vertex of drawin polyline
    this._hintline.setLatLngs([A, B]);
  },
  _createHintLine(markerA, markerB) {
    const A = markerA.getLatLng();
    const B = markerB.getLatLng();
    this._hintline = L.polyline([A, B], this.options.hintlineStyle);
    this._hintline._pmTempLayer = true;
    this._helperLayers.addLayer(this._hintline);
  },
  _createCenterMarker(latlng) {
    const marker = this._createMarker(latlng);

    L.DomUtil.addClass(marker._icon, 'leaflet-pm-draggable');
    // TODO: switch back to move event once this leaflet issue is solved:
    // https://github.com/Leaflet/Leaflet/issues/6492
    marker.on('drag', this._moveCircle, this);
    // marker.on('contextmenu', this._removeMarker, this);

    return marker;
  },
  _createOuterMarker(latlng) {
    const marker = this._createMarker(latlng);

    marker.on('drag', this._resizeCircle, this);

    return marker;
  },
  _createMarker(latlng) {
    const marker = new L.Marker(latlng, {
      draggable: true,
      icon: L.divIcon({ className: 'marker-icon' }),
    });

    marker._origLatLng = latlng;
    marker._pmTempLayer = true;

    marker.on('dragstart', this._onMarkerDragStart, this);
    marker.on('dragend', this._onMarkerDragEnd, this);

    this._helperLayers.addLayer(marker);

    return marker;
  },
  _fireEdit() {
    // fire edit event
    this._layer.fire('pm:edit');
    this._layerEdited = true;
  },
});
<|endoftext|>