<commit_before>'use strict';

/* global apress, module, test, ok, throws */

module('Apress simple routing module',{
  setup: function() {
    this.status = false;
    var that = this;
    this.testRoute = function(routeToRegister, routeToFire) {
      routeToFire = routeToFire || routeToRegister;

      apress.addRoute(routeToRegister, function(param, param2){
        that.status = true;
        that.param = param;
        that.param2 = param2;
        apress.removeRoute(routeToRegister);
      });

      window.location.hash = '#!' + routeToFire;
      apress.hashTest();
    };
  },
  beforeEach:  function() {
    this.status = false;
    this.param = false;
  }
});

test('should run proper function for main route (`/`)', function() {
  this.testRoute('/');
  ok(this.status, 'proper route listener called');
});

test('should run proper function for simple route - `/foo`', function() {
  this.testRoute('/foo');
  ok(this.status, 'proper route listener called');
});

test('should NOT call route when removeRoute was called on simple route',
function() {
  this.testRoute('/foo2');
  ok(this.status, 'proper route listener called');

  this.status = false;
  apress.removeRoute('/foo2');
  apress.hashTest();
  ok(!this.status, 'listener wasn\'t called');
});

test(
'should run proper function for simple route with slash ant the ' +
  'end - `/foobar/`',
function() {
  this.testRoute('/foobar', '/foobar/');
  ok(this.status, 'proper route listener called');
});

test(
'should NOT run function for simple route `/foo` when ' +
  '`/foo/something` is called',
function() {
  this.testRoute('/foo', '/foo/bar');
  ok(!this.status, 'route listener wasn\'t called');
});

test('should run proper function for more complex route - `/foo/bar`',
function() {
  this.testRoute('/foo/bar');
  ok(this.status, 'proper route listener called');
});

test('should run ErrorPage listener if route cannot be found',
function() {
  apress.setErrorPage(function(){
    this.status = true;
  }.bind(this));

  window.location.hash = '#!PeperePutti';
  apress.hashTest();

  ok(this.status);
});

test('should throw error when route is not string or regexp',
function() {
  throws(function(){
    apress.addRoute(997, function(param){});
  });
});
<commit_msg>:wolf: multiple listener test<commit_after>'use strict';

/* global apress, module, test, ok, throws */

module('Apress simple routing module',{
  setup: function() {
    this.status = false;
    var that = this;
    this.testRoute = function(routeToRegister, routeToFire) {
      routeToFire = routeToFire || routeToRegister;

      apress.addRoute(routeToRegister, function(param, param2){
        that.status = true;
        that.param = param;
        that.param2 = param2;
        apress.removeRoute(routeToRegister);
      });

      window.location.hash = '#!' + routeToFire;
      apress.hashTest();
    };
  },
  beforeEach:  function() {
    this.status = false;
    this.param = false;
  }
});

test('should run proper function for main route (`/`)', function() {
  this.testRoute('/');
  ok(this.status, 'proper route listener called');
});

test('should run proper function for simple route - `/foo`', function() {
  this.testRoute('/foo');
  ok(this.status, 'proper route listener called');
});

test('should NOT call route when removeRoute was called on simple route',
function() {
  this.testRoute('/foo2');
  ok(this.status, 'proper route listener called');

  this.status = false;
  apress.removeRoute('/foo2');
  apress.hashTest();
  ok(!this.status, 'listener wasn\'t called');
});

test('should call multiple callbacks attached to the same route',
function() {
  var status1 = false;
  var status2 = false;
  var route = '/foo';

  apress.addRoute(route, function(){
    status1 = true;
  });

  apress.addRoute(route, function(){
    status2 = true;
  });

  window.location.hash = '#!' + route;
  apress.hashTest();

  ok(status1, 'first listener fired');
  ok(status2, 'second listener fired');
});

test(
'should run proper function for simple route with slash ant the ' +
  'end - `/foobar/`',
function() {
  this.testRoute('/foobar', '/foobar/');
  ok(this.status, 'proper route listener called');
});

test(
'should NOT run function for simple route `/foo` when ' +
  '`/foo/something` is called',
function() {
  this.testRoute('/foo', '/foo/bar');
  ok(!this.status, 'route listener wasn\'t called');
});

test('should run proper function for more complex route - `/foo/bar`',
function() {
  this.testRoute('/foo/bar');
  ok(this.status, 'proper route listener called');
});

test('should run ErrorPage listener if route cannot be found',
function() {
  apress.setErrorPage(function(){
    this.status = true;
  }.bind(this));

  window.location.hash = '#!PeperePutti';
  apress.hashTest();

  ok(this.status);
});

test('should throw error when route is not string or regexp',
function() {
  throws(function(){
    apress.addRoute(997, function(param){});
  });
});
<|endoftext|>


<commit_before>var _ = require('lodash'),
    Q = require('q'),
    events = require('events'),
    createRequest = require('./request');

module.exports = function(auth) {

    return function(config) {

        var emitter = new events.EventEmitter(),
            bamboo = createRequest({
                baseUrl: config.host + '/rest/api/latest/',
                timeout: config.timeout || 15000,
                headers: {
                    accept: "application/json",
                    authorization: auth.getBasicAuthHeader(config.auth)
                }
            });

        function go() {
            normalizePlanKeys(config.plans, bamboo)
                .then(loadResults(bamboo))
                .then(processResultsData)
                .then(addLinksToResults(config.host))
                .then(function(data) {
                    var passing = _.where(data, { success: true }).length,
                        failing = data.length - passing;

                    emitter.emit('data', {
                        passing: passing,
                        failing: failing,
                        builds: data
                    });
                })
                .catch(function(err) {
                    emitter.emit('error', err);
                });
        }

        process.nextTick(go);

        return emitter;
    };

}
module.exports.$inject = ['authManager'];

function normalizePlanKeys(keys, request) {
    var normalized = [],
        exp = /^([A-Z]+)-(\*|[A-Z]+)(\*|[0-9]+)*$/;

    keys.forEach(function(key) {
        var match = key.match(exp);

        if (!match) {
            key = Q.reject('Unknown plan key pattern: ' + key);
        } else if (match[2] !== '*' && match[3] !== '*') {
            key = Q(key);
        } else {
            key = request('project/' + match[1] + '?expand=plans.plan.branches&maxResults=200').then(function (project) {
                var subKeys = []
                project.plans.plan.forEach(function (plan) {
                    if (match[2] === '*' || match[2] === plan.key) {
                        subKeys.push(plan.key);
                    }
                    if (plan.branches && plan.branches.branch && match[3]) {
                        plan.branches.branch.forEach(function (branch) {
                            if (match[3] === '*' || match[2] + match[3] === branch.shortKey) {
                                subKeys.push(branch.key);
                            }
                        });
                    }
                });
                return subKeys;
            });
        }

        normalized.push(key);
    });

    return Q.all(normalized).then(function(keys) {
        return _.unique(_.flatten(keys));
    });
}

function loadResults(request) {
    return function(keys) {

        var requests = keys.map(function(key) {
            return request('result/' + key + '/latest?expand=changes')
                .catch(function(error) {
                    return null;
                });
        })

        return Q.all(requests).then(function(results) {
            return results.filter(function(result) {
                return result && result.plan && result.plan.enabled;
            });
        })
    }
}

function processResultsData(results) {
    return results.map(function(build) {
        return {
            planKey: build.plan.key,
            planName: build.plan.name,
            planShortName: build.plan.shortName,
            responsible: extractAuthorsFromChanges(build.changes.change),
            failBuildKey: build.key,
            isRefreshing: build.lifeCycleState === "NotBuilt",
            success : build.state === "Successful"
        }
    });
}

function extractAuthorsFromChanges(changes) {

    var authors = changes.map(function(changeset) {
        if (typeof changeset.author === "string") {
            var matches = changeset.author.match(/^(.*)\s+\<(.*)\>$/);
            if (matches) {
                return {
                    name: matches[1],
                    email: matches[2]
                };
            }
        }
    });

    authors = _.unique(authors, function (author) {
        return author.name
    });

    return authors;
}

function addLinksToResults(host) {
    return function(results) {
        results.forEach(function(result) {
            result.link = host + "/browse/" + result.planKey;
        });
        return results;
    }
}<commit_msg>Fix wrong parameter name<commit_after>var _ = require('lodash'),
    Q = require('q'),
    events = require('events'),
    createRequest = require('./request');

module.exports = function(auth) {

    return function(config) {

        var emitter = new events.EventEmitter(),
            bamboo = createRequest({
                baseUrl: config.host + '/rest/api/latest/',
                timeout: config.timeout || 15000,
                headers: {
                    accept: "application/json",
                    authorization: auth.getBasicAuthHeader(config.auth)
                }
            });

        function go() {
            normalizePlanKeys(config.plans, bamboo)
                .then(loadResults(bamboo))
                .then(processResultsData)
                .then(addLinksToResults(config.host))
                .then(function(data) {
                    var passing = _.where(data, { success: true }).length,
                        failing = data.length - passing;

                    emitter.emit('data', {
                        passing: passing,
                        failing: failing,
                        builds: data
                    });
                })
                .catch(function(err) {
                    emitter.emit('error', err);
                });
        }

        process.nextTick(go);

        return emitter;
    };

}
module.exports.$inject = ['authManager'];

function normalizePlanKeys(keys, request) {
    var normalized = [],
        exp = /^([A-Z]+)-(\*|[A-Z]+)(\*|[0-9]+)*$/;

    keys.forEach(function(key) {
        var match = key.match(exp);

        if (!match) {
            key = Q.reject('Unknown plan key pattern: ' + key);
        } else if (match[2] !== '*' && match[3] !== '*') {
            key = Q(key);
        } else {
            key = request('project/' + match[1] + '?expand=plans.plan.branches&max-results=200').then(function (project) {
                var subKeys = []
                project.plans.plan.forEach(function (plan) {
                    if (match[2] === '*' || match[2] === plan.key) {
                        subKeys.push(plan.key);
                    }
                    if (plan.branches && plan.branches.branch && match[3]) {
                        plan.branches.branch.forEach(function (branch) {
                            if (match[3] === '*' || match[2] + match[3] === branch.shortKey) {
                                subKeys.push(branch.key);
                            }
                        });
                    }
                });
                return subKeys;
            });
        }

        normalized.push(key);
    });

    return Q.all(normalized).then(function(keys) {
        return _.unique(_.flatten(keys));
    });
}

function loadResults(request) {
    return function(keys) {

        var requests = keys.map(function(key) {
            return request('result/' + key + '/latest?expand=changes')
                .catch(function(error) {
                    return null;
                });
        })

        return Q.all(requests).then(function(results) {
            return results.filter(function(result) {
                return result && result.plan && result.plan.enabled;
            });
        })
    }
}

function processResultsData(results) {
    return results.map(function(build) {
        return {
            planKey: build.plan.key,
            planName: build.plan.name,
            planShortName: build.plan.shortName,
            responsible: extractAuthorsFromChanges(build.changes.change),
            failBuildKey: build.key,
            isRefreshing: build.lifeCycleState === "NotBuilt",
            success : build.state === "Successful"
        }
    });
}

function extractAuthorsFromChanges(changes) {

    var authors = changes.map(function(changeset) {
        if (typeof changeset.author === "string") {
            var matches = changeset.author.match(/^(.*)\s+\<(.*)\>$/);
            if (matches) {
                return {
                    name: matches[1],
                    email: matches[2]
                };
            }
        }
    });

    authors = _.unique(authors, function (author) {
        return author.name
    });

    return authors;
}

function addLinksToResults(host) {
    return function(results) {
        results.forEach(function(result) {
            result.link = host + "/browse/" + result.planKey;
        });
        return results;
    }
}<|endoftext|>


<commit_before>geoModule.time = {}

geoModule.time.incrementTime = function (time, unit, delta) {

  if (unit == 'days') {
    time.setDate(time.getDate() + delta);
  }
  else if (unit == 'months') {
    time.setMonth(time.getMonth() + delta);
  }
  else if (unit == 'years') {
    time.setYear(time.getYear() + delta);
  }

  return time;
}
<commit_msg>Fixed time<commit_after>//////////////////////////////////////////////////////////////////////////////
/**
 * @module ogs.geo
 */

/*jslint devel: true, forin: true, newcap: true, plusplus: true*/
/*jslint white: true, indent: 2*/

/*global geoModule, ogs, inherit, $, HTMLCanvasElement, Image*/
/*global vglModule, document*/
//////////////////////////////////////////////////////////////////////////////

geoModule.time = {};

geoModule.time.incrementTime = function (time, unit, delta) {
  'use strict';

  if (unit === 'days') {
    time.setDate(time.getDate() + delta);
  }
  else if (unit === 'months') {
    time.setMonth(time.getMonth() + delta);
  }
  else if (unit === 'years') {
    time.setYear(time.getYear() + delta);
  }

  return time;
};
<|endoftext|>


<commit_before>var should = require('should');
var async = require('async');
var config = require('./config.js');
var utils = require('./utils');
var redis = require('redis'), rc = redis.createClient(6379, 'localhost');

var HOST = config.hostname;
var PORT = config.port;

var trans, trans1 = {};

describe('#PUT', function() {
  beforeEach(function(done) {

    trans1 = {
      'payload': '{\"spanish\": \"prueba1\", \"english\": ' +
          '\"test1\", \"to\": \"Mr Lopez\"}',
      'priority': 'H',
      'callback': 'http' + '://foo.bar',
      'queue': [
        { 'id': 'q1' },
        { 'id': 'q2' }
      ],
      'expirationDate': Math.round(new Date().getTime() / 1000 + 2)
    };

    var heads = {};
    heads['content-type'] = 'application/json';
    var options = { host: HOST, port: PORT,
      path: '/trans/', method: 'POST', headers: heads};

    utils.makeRequest(options, trans1, function(error, response, data) {
      data.should.have.property('data');
      trans = {id: data.data, value: trans1};
      done();
    });
  });

  after(function(done) {
    this.timeout(8000);

    rc.flushall(function(res) {
      rc.end();
      done();
    });
  });

  it('should change payload,callback and expirationDate', function(done) {

    var datos_PUT = {
      'payload': 'MESSAGE 1',
      'callback': 'www.fi.upm.es',
      'expirationDate': 1447483646
    };

    async.series([

      function(callback) {

        var heads = {};
        heads['content-type'] = 'application/json';
        heads['accept'] = 'application/json';
        var options = { host: HOST, port: PORT,
          path: '/trans/' + trans.id, method: 'PUT', headers: heads};

        utils.makeRequest(options, datos_PUT, function(error, response, data) {
          response.statusCode.should.be.equal(200);
          callback();
        });
      },

      function(callback) {

        var heads = {};
        heads['accept'] = 'application/json';
        var options = { host: HOST, port: PORT,
          path: '/trans/' + trans.id, method: 'GET', headers: heads};

        utils.makeRequest(options, null, function(error, response, data) {
          response.statusCode.should.be.equal(200);
          data.should.have.property('payload');
          data.should.have.property('callback');
          data.should.have.property('expirationDate');

          data.payload.should.be.equal('MESSAGE 1');
          data.callback.should.be.equal('www.fi.upm.es');
          data.expirationDate.should.be.equal('1447483646');

          callback();
        });
      }
    ],

        function() {
          done();
        });
  });

  it('should not change priority', function(done) {

    var datos_PUT = {
      'payload': 'MESSAGE 2',
      'priority': 'L',
      'expirationDate': 1447483646
    };

    async.series([

      function(callback) {

        var heads = {};
        heads['content-type'] = 'application/json';
        heads['accept'] = 'application/json';
        var options = { host: HOST, port: PORT,
          path: '/trans/' + trans.id, method: 'PUT', headers: heads};

        utils.makeRequest(options, datos_PUT, function(error, response, data) {
          response.statusCode.should.be.equal(200);
          callback();
        });
      },

      function(callback) {

        var heads = {};
        heads['accept'] = 'application/json';
        var options = { host: HOST, port: PORT,
          path: '/trans/' + trans.id, method: 'GET', headers: heads};

        utils.makeRequest(options, null, function(error, response, data) {
          response.statusCode.should.be.equal(200);

          data.should.have.property('payload');
          data.should.have.property('priority');
          data.should.have.property('expirationDate');

          data.payload.should.be.equal('MESSAGE 2');
          data.priority.should.not.be.equal('L');
          data.expirationDate.should.be.equal('1447483646');

          callback();
        });

      }
    ],

        function() {
          done();
        });
  });

});
<commit_msg>putTest more strcit<commit_after>var should = require('should');
var async = require('async');
var config = require('./config.js');
var utils = require('./utils');
var redis = require('redis'), rc = redis.createClient(6379, 'localhost');

var HOST = config.hostname;
var PORT = config.port;

var trans, trans1 = {};

describe('#PUT', function() {
  beforeEach(function(done) {

    trans1 = {
      'payload': '{\"spanish\": \"prueba1\", \"english\": ' +
          '\"test1\", \"to\": \"Mr Lopez\"}',
      'priority': 'H',
      'callback': 'http' + '://foo.bar',
      'queue': [
        { 'id': 'q1' },
        { 'id': 'q2' }
      ],
      'expirationDate': Math.round(new Date().getTime() / 1000 + 2)
    };

    var heads = {};
    heads['content-type'] = 'application/json';
    var options = { host: HOST, port: PORT,
      path: '/trans/', method: 'POST', headers: heads};

    utils.makeRequest(options, trans1, function(error, response, data) {
      should.not.exist(error);
      data.should.have.property('data');
      trans = {id: data.data, value: trans1};
      done();
    });
  });

  after(function(done) {
    this.timeout(8000);

    rc.flushall(function(res) {
      rc.end();
      done();
    });
  });

  it('should change payload,callback and expirationDate', function(done) {

    var datos_PUT = {
      'payload': 'MESSAGE 1',
      'callback': 'www.fi.upm.es',
      'expirationDate': 1447483646
    };

    async.series([

      function(callback) {

        var heads = {};
        heads['content-type'] = 'application/json';
        heads['accept'] = 'application/json';
        var options = { host: HOST, port: PORT,
          path: '/trans/' + trans.id, method: 'PUT', headers: heads};

        utils.makeRequest(options, datos_PUT, function(error, response, data) {
          response.statusCode.should.be.equal(200);
          callback();
        });
      },

      function(callback) {

        var heads = {};
        heads['accept'] = 'application/json';
        var options = { host: HOST, port: PORT,
          path: '/trans/' + trans.id, method: 'GET', headers: heads};

        utils.makeRequest(options, null, function(error, response, data) {
          response.statusCode.should.be.equal(200);
          data.should.have.property('payload');
          data.should.have.property('callback');
          data.should.have.property('expirationDate');

          data.payload.should.be.equal('MESSAGE 1');
          data.callback.should.be.equal('www.fi.upm.es');
          data.expirationDate.should.be.equal('1447483646');

          callback();
        });
      }
    ],

        function() {
          done();
        });
  });

  it('should not change priority', function(done) {

    var datos_PUT = {
      'payload': 'MESSAGE 2',
      'priority': 'L',
      'expirationDate': 1447483646
    };

    async.series([

      function(callback) {

        var heads = {};
        heads['content-type'] = 'application/json';
        heads['accept'] = 'application/json';
        var options = { host: HOST, port: PORT,
          path: '/trans/' + trans.id, method: 'PUT', headers: heads};

        utils.makeRequest(options, datos_PUT, function(error, response, data) {
          response.statusCode.should.be.equal(200);
          callback();
        });
      },

      function(callback) {

        var heads = {};
        heads['accept'] = 'application/json';
        var options = { host: HOST, port: PORT,
          path: '/trans/' + trans.id, method: 'GET', headers: heads};

        utils.makeRequest(options, null, function(error, response, data) {
          response.statusCode.should.be.equal(200);

          data.should.have.property('payload');
          data.should.have.property('priority');
          data.should.have.property('expirationDate');

          data.payload.should.be.equal('MESSAGE 2');
          data.priority.should.not.be.equal('L');
          data.expirationDate.should.be.equal('1447483646');

          callback();
        });

      }
    ],

        function() {
          done();
        });
  });

});
<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * A function scope holding all the functionality needed to convert a
 * Paper.js DOM to a SVG DOM.
 */
new function() {
    // TODO: Consider moving formatter into options object, and pass it along.
    var formatter;

    function setAttributes(node, attrs) {
        for (var key in attrs) {
            var val = attrs[key],
                namespace = SVGNamespaces[key];
            if (typeof val === 'number')
                val = formatter.number(val);
            if (namespace) {
                node.setAttributeNS(namespace, key, val);
            } else {
                node.setAttribute(key, val);
            }
        }
        return node;
    }

    function createElement(tag, attrs) {
        return setAttributes(
            document.createElementNS('http://www.w3.org/2000/svg', tag), attrs);
    }

    function getTransform(matrix, coordinates, center) {
        // Use new Base() so we can use Base#set() on it.
        var attrs = new Base(),
            trans = matrix.getTranslation();
        if (coordinates) {
            // If the item suppports x- and y- coordinates, we're taking out the
            // translation part of the matrix and move it to x, y attributes, to
            // produce more readable markup, and not have to use center points
            // in rotate(). To do so, SVG requries us to inverse transform the
            // translation point by the matrix itself, since they are provided
            // in local coordinates.
            matrix = matrix.shiftless();
            var point = matrix._inverseTransform(trans);
            attrs[center ? 'cx' : 'x'] = point.x;
            attrs[center ? 'cy' : 'y'] = point.y;
            trans = null;
        }
        if (!matrix.isIdentity()) {
            // See if we can decompose the matrix and can formulate it as a
            // simple translate/scale/rotate command sequence.
            var decomposed = matrix.decompose();
            if (decomposed && !decomposed.shearing) {
                var parts = [],
                    angle = decomposed.rotation,
                    scale = decomposed.scaling;
                if (trans && !trans.isZero())
                    parts.push('translate(' + formatter.point(trans) + ')');
                if (!Numerical.isZero(scale.x - 1)
                        || !Numerical.isZero(scale.y - 1))
                    parts.push('scale(' + formatter.point(scale) +')');
                if (angle)
                    parts.push('rotate(' + formatter.number(angle) + ')');
                attrs.transform = parts.join(' ');
            } else {
                attrs.transform = 'matrix(' + matrix.getValues().join(',') + ')';
            }
        }
        return attrs;
    }

    function exportGroup(item, options) {
        var attrs = getTransform(item._matrix),
            children = item._children;
        var node = createElement('g', attrs);
        for (var i = 0, l = children.length; i < l; i++) {
            var child = children[i];
            var childNode = exportSVG(child, options);
            if (childNode) {
                if (child.isClipMask()) {
                    var clip = createElement('clipPath');
                    clip.appendChild(childNode);
                    setDefinition(child, clip, 'clip');
                    setAttributes(node, {
                        'clip-path': 'url(#' + clip.id + ')'
                    });
                } else {
                    node.appendChild(childNode);
                }
            }
        }
        return node;
    }

    function exportRaster(item) {
        var attrs = getTransform(item._matrix, true),
            size = item.getSize();
        // Take into account that rasters are centered:
        attrs.x -= size.width / 2;
        attrs.y -= size.height / 2;
        attrs.width = size.width;
        attrs.height = size.height;
        attrs.href = item.toDataURL();
        return createElement('image', attrs);
    }

    function exportPath(item, options) {
        if (options.matchShapes) {
            var shape = item.toShape(false);
            if (shape)
                return exportShape(shape, options);
        }
        var segments = item._segments,
            type,
            attrs = getTransform(item._matrix);
        if (segments.length === 0)
            return null;
        if (item.isPolygon()) {
            if (segments.length >= 3) {
                type = item._closed ? 'polygon' : 'polyline';
                var parts = [];
                for(i = 0, l = segments.length; i < l; i++)
                    parts.push(formatter.point(segments[i]._point));
                attrs.points = parts.join(' ');
            } else {
                type = 'line';
                var first = segments[0]._point,
                    last = segments[segments.length - 1]._point;
                attrs.set({
                    x1: first.x,
                    y1: first.y,
                    x2: last.x,
                    y2: last.y
                });
            }
        } else {
            type = 'path';
            attrs.d = item.getPathData(null, options.precision);
        }
        return createElement(type, attrs);
    }

    function exportShape(item) {
        var type = item._type,
            radius = item._radius,
            attrs = getTransform(item._matrix, true, type !== 'rectangle');
        if (type === 'rectangle') {
            type = 'rect'; // SVG
            var size = item._size,
                width = size.width,
                height = size.height;
            attrs.x -= width / 2;
            attrs.y -= height / 2;
            attrs.width = width;
            attrs.height = height;
            if (radius.isZero())
                radius = null;
        }
        if (radius) {
            if (type === 'circle') {
                attrs.r = radius;
            } else {
                attrs.rx = radius.width;
                attrs.ry = radius.height;
            }
        }
        return createElement(type, attrs);
    }

    function exportCompoundPath(item, options) {
        var attrs = getTransform(item._matrix);
        var data = item.getPathData(null, options.precision);
        if (data)
            attrs.d = data;
        return createElement('path', attrs);
    }

    function exportPlacedSymbol(item, options) {
        var attrs = getTransform(item._matrix, true),
            symbol = item.getSymbol(),
            symbolNode = getDefinition(symbol, 'symbol'),
            definition = symbol.getDefinition(),
            bounds = definition.getBounds();
        if (!symbolNode) {
            symbolNode = createElement('symbol', {
                viewBox: formatter.rectangle(bounds)
            });
            symbolNode.appendChild(exportSVG(definition, options));
            setDefinition(symbol, symbolNode, 'symbol');
        }
        attrs.href = '#' + symbolNode.id;
        attrs.x += bounds.x;
        attrs.y += bounds.y;
        attrs.width = formatter.number(bounds.width);
        attrs.height = formatter.number(bounds.height);
        return createElement('use', attrs);
    }

    function exportGradient(color) {
        // NOTE: As long as the fillTransform attribute is not implemented,
        // we need to create a separate gradient object for each gradient,
        // even when they share the same gradient defintion.
        // http://www.svgopen.org/2011/papers/20-Separating_gradients_from_geometry/
        // TODO: Implement gradient merging in SVGImport
        var gradientNode = getDefinition(color, 'color');
        if (!gradientNode) {
            var gradient = color.getGradient(),
                radial = gradient._radial,
                origin = color.getOrigin().transform(),
                destination = color.getDestination().transform(),
                attrs;
            if (radial) {
                attrs = {
                    cx: origin.x,
                    cy: origin.y,
                    r: origin.getDistance(destination)
                };
                var highlight = color.getHighlight();
                if (highlight) {
                    highlight = highlight.transform();
                    attrs.fx = highlight.x;
                    attrs.fy = highlight.y;
                }
            } else {
                attrs = {
                    x1: origin.x,
                    y1: origin.y,
                    x2: destination.x,
                    y2: destination.y
                };
            }
            attrs.gradientUnits = 'userSpaceOnUse';
            gradientNode = createElement(
                    (radial ? 'radial' : 'linear') + 'Gradient', attrs);
            var stops = gradient._stops;
            for (var i = 0, l = stops.length; i < l; i++) {
                var stop = stops[i],
                    stopColor = stop._color,
                    alpha = stopColor.getAlpha();
                attrs = {
                    offset: stop._rampPoint,
                    'stop-color': stopColor.toCSS(true)
                };
                // See applyStyle for an explanation of why there are separated
                // opacity / color attributes.
                if (alpha < 1)
                    attrs['stop-opacity'] = alpha;
                gradientNode.appendChild(createElement('stop', attrs));
            }
            setDefinition(color, gradientNode, 'color');
        }
        return 'url(#' + gradientNode.id + ')';
    }

    function exportText(item) {
        var node = createElement('text', getTransform(item._matrix, true));
        node.textContent = item._content;
        return node;
    }

    var exporters = {
        Group: exportGroup,
        Layer: exportGroup,
        Raster: exportRaster,
        Path: exportPath,
        Shape: exportShape,
        CompoundPath: exportCompoundPath,
        PlacedSymbol: exportPlacedSymbol,
        PointText: exportText
    };

    function applyStyle(item, node, isRoot) {
        var attrs = {},
            parent = !isRoot && item.getParent();

        if (item._name != null)
            attrs.id = item._name;

        Base.each(SVGStyles, function(entry) {
            // Get a given style only if it differs from the value on the parent
            // (A layer or group which can have style values in SVG).
            var get = entry.get,
                type = entry.type,
                value = item[get]();
            if (entry.exportFilter
                    ? entry.exportFilter(item, value)
                    : !parent || !Base.equals(parent[get](), value)) {
                if (type === 'color' && value != null) {
                    // Support for css-style rgba() values is not in SVG 1.1, so
                    // separate the alpha value of colors with alpha into the
                    // separate fill- / stroke-opacity attribute:
                    var alpha = value.getAlpha();
                    if (alpha < 1)
                        attrs[entry.attribute + '-opacity'] = alpha;
                }
                attrs[entry.attribute] = value == null
                    ? 'none'
                    : type === 'number'
                        ? formatter.number(value)
                        : type === 'color'
                            ? value.gradient
                                ? exportGradient(value, item)
                                // true for noAlpha, see above
                                : value.toCSS(true)
                            : type === 'array'
                                ? value.join(',')
                                : type === 'lookup'
                                    ? entry.toSVG[value]
                                    : value;
            }
        });

        if (attrs.opacity === 1)
            delete attrs.opacity;

        if (!item._visible)
            attrs.visibility = 'hidden';

        return setAttributes(node, attrs);
    }

    var definitions;
    function getDefinition(item, type) {
        if (!definitions)
            definitions = { ids: {}, svgs: {} };
        return item && definitions.svgs[type + '-' + item._id];
    }

    function setDefinition(item, node, type) {
        // Make sure the definitions lookup is created before we use it.
        // This is required by 'clip', where getDefinition() is not called.
        if (!definitions)
            getDefinition();
        // Have different id ranges per type
        var id = definitions.ids[type] = (definitions.ids[type] || 0) + 1;
        // Give the svg node an id, and link to it from the item id.
        node.id = type + '-' + id;
        definitions.svgs[type + '-' + item._id] = node;
    }

    function exportDefinitions(node, options) {
        var svg = node,
            defs = null;
        if (definitions) {
            // We can only use svg nodes as defintion containers. Have the loop
            // produce one if it's a single item of another type (when calling
            // #exportSVG() on an item rather than a whole project)
            // jsdom in Node.js uses uppercase values for nodeName...
            svg = node.nodeName.toLowerCase() === 'svg' && node;
            for (var i in definitions.svgs) {
                // This code is inside the loop so we only create a container if
                // we actually have svgs.
                if (!defs) {
                    if (!svg) {
                        svg = createElement('svg');
                        svg.appendChild(node);
                    }
                    defs = svg.insertBefore(createElement('defs'),
                            svg.firstChild);
                }
                defs.appendChild(definitions.svgs[i]);
            }
            // Clear definitions at the end of export
            definitions = null;
        }
        return options.asString
                ? new XMLSerializer().serializeToString(svg)
                : svg;
    }

    function exportSVG(item, options, isRoot) {
        var exporter = exporters[item._class],
            node = exporter && exporter(item, options);
        if (node) {
            // Support onExportItem callback, to provide mechanism to handle
            // special attributes (e.g. inkscape:transform-center)
            var onExport = options.onExport;
            if (onExport)
                node = onExport(item, node, options) || node;
            var data = JSON.stringify(item._data);
            if (data && data  !== '{}')
                node.setAttribute('data-paper-data', data);
        }
        return node && applyStyle(item, node, isRoot);
    }

    function setOptions(options) {
        if (!options)
            options = {};
        formatter = new Formatter(options.precision);
        return options;
    }

    Item.inject({
        exportSVG: function(options) {
            options = setOptions(options);
            return exportDefinitions(exportSVG(this, options, true), options);
        }
    });

    Project.inject({
        exportSVG: function(options) {
            options = setOptions(options);
            var layers = this.layers,
                view = this.getView(),
                size = view.getViewSize(),
                node = createElement('svg', {
                    x: 0,
                    y: 0,
                    width: size.width,
                    height: size.height,
                    version: '1.1',
                    xmlns: 'http://www.w3.org/2000/svg',
                    'xmlns:xlink': 'http://www.w3.org/1999/xlink'
                }),
                parent = node,
                matrix = view._matrix;
            // If the view has a transformation, wrap all layers in a group with
            // that transformation applied to.
            if (!matrix.isIdentity())
                parent = node.appendChild(
                        createElement('g', getTransform(matrix)));
            for (var i = 0, l = layers.length; i < l; i++)
                parent.appendChild(exportSVG(layers[i], options, true));
            return exportDefinitions(node, options);
        }
    });
};
<commit_msg>Update SVGExport.js<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * A function scope holding all the functionality needed to convert a
 * Paper.js DOM to a SVG DOM.
 */
new function() {
    // TODO: Consider moving formatter into options object, and pass it along.
    var formatter;

    function setAttributes(node, attrs) {
        for (var key in attrs) {
            var val = attrs[key],
                namespace = SVGNamespaces[key];
            if (typeof val === 'number')
                val = formatter.number(val);
            if (namespace) {
                node.setAttributeNS(namespace, key, val);
            } else {
                node.setAttribute(key, val);
            }
        }
        return node;
    }

    function createElement(tag, attrs) {
        return setAttributes(
            document.createElementNS('http://www.w3.org/2000/svg', tag), attrs);
    }

    function getTransform(matrix, coordinates, center) {
        // Use new Base() so we can use Base#set() on it.
        var attrs = new Base(),
            trans = matrix.getTranslation();
        if (coordinates) {
            // If the item suppports x- and y- coordinates, we're taking out the
            // translation part of the matrix and move it to x, y attributes, to
            // produce more readable markup, and not have to use center points
            // in rotate(). To do so, SVG requries us to inverse transform the
            // translation point by the matrix itself, since they are provided
            // in local coordinates.
            matrix = matrix.shiftless();
            var point = matrix._inverseTransform(trans);
            attrs[center ? 'cx' : 'x'] = point.x;
            attrs[center ? 'cy' : 'y'] = point.y;
            trans = null;
        }
        if (!matrix.isIdentity()) {
            // See if we can decompose the matrix and can formulate it as a
            // simple translate/scale/rotate command sequence.
            var decomposed = matrix.decompose();
            if (decomposed && !decomposed.shearing) {
                var parts = [],
                    angle = decomposed.rotation,
                    scale = decomposed.scaling;
                if (trans && !trans.isZero())
                    parts.push('translate(' + formatter.point(trans) + ')');
                if (!Numerical.isZero(scale.x - 1)
                        || !Numerical.isZero(scale.y - 1))
                    parts.push('scale(' + formatter.point(scale) +')');
                if (angle)
                    parts.push('rotate(' + formatter.number(angle) + ')');
                attrs.transform = parts.join(' ');
            } else {
                attrs.transform = 'matrix(' + matrix.getValues().join(',') + ')';
            }
        }
        return attrs;
    }

    function exportGroup(item, options) {
        var attrs = getTransform(item._matrix),
            children = item._children;
        var node = createElement('g', attrs);
        for (var i = 0, l = children.length; i < l; i++) {
            var child = children[i];
            var childNode = exportSVG(child, options);
            if (childNode) {
                if (child.isClipMask()) {
                    var clip = createElement('clipPath');
                    clip.appendChild(childNode);
                    setDefinition(child, clip, 'clip');
                    setAttributes(node, {
                        'clip-path': 'url(#' + clip.id + ')'
                    });
                } else {
                    node.appendChild(childNode);
                }
            }
        }
        return node;
    }

    function exportRaster(item) {
        var attrs = getTransform(item._matrix, true),
            size = item.getSize();
        // Take into account that rasters are centered:
        attrs.x -= size.width / 2;
        attrs.y -= size.height / 2;
        attrs.width = size.width;
        attrs.height = size.height;
        attrs.href = item.toDataURL();
        return createElement('image', attrs);
    }

    function exportPath(item, options) {
        if (options.matchShapes) {
            var shape = item.toShape(false);
            if (shape)
                return exportShape(shape, options);
        }
        var segments = item._segments,
            type,
            attrs = getTransform(item._matrix);
        if (segments.length === 0)
            return null;
        if (item.isPolygon()) {
            if (segments.length >= 3) {
                type = item._closed ? 'polygon' : 'polyline';
                var parts = [];
                for(i = 0, l = segments.length; i < l; i++)
                    parts.push(formatter.point(segments[i]._point));
                attrs.points = parts.join(' ');
            } else {
                type = 'line';
                var first = segments[0]._point,
                    last = segments[segments.length - 1]._point;
                attrs.set({
                    x1: first.x,
                    y1: first.y,
                    x2: last.x,
                    y2: last.y
                });
            }
        } else {
            type = 'path';
            attrs.d = item.getPathData(null, options.precision);
        }
        return createElement(type, attrs);
    }

    function exportShape(item) {
        var type = item._type,
            radius = item._radius,
            attrs = getTransform(item._matrix, true, type !== 'rectangle');
        if (type === 'rectangle') {
            type = 'rect'; // SVG
            var size = item._size,
                width = size.width,
                height = size.height;
            attrs.x -= width / 2;
            attrs.y -= height / 2;
            attrs.width = width;
            attrs.height = height;
            if (radius.isZero())
                radius = null;
        }
        if (radius) {
            if (type === 'circle') {
                attrs.r = radius;
            } else {
                attrs.rx = radius.width;
                attrs.ry = radius.height;
            }
        }
        return createElement(type, attrs);
    }

    function exportCompoundPath(item, options) {
        var attrs = getTransform(item._matrix);
        var data = item.getPathData(null, options.precision);
        if (data)
            attrs.d = data;
        return createElement('path', attrs);
    }

    function exportPlacedSymbol(item, options) {
        var attrs = getTransform(item._matrix, true),
            symbol = item.getSymbol(),
            symbolNode = getDefinition(symbol, 'symbol'),
            definition = symbol.getDefinition(),
            bounds = definition.getBounds();
        if (!symbolNode) {
            symbolNode = createElement('symbol', {
                viewBox: formatter.rectangle(bounds)
            });
            symbolNode.appendChild(exportSVG(definition, options));
            setDefinition(symbol, symbolNode, 'symbol');
        }
        attrs.href = '#' + symbolNode.id;
        attrs.x += bounds.x;
        attrs.y += bounds.y;
        attrs.width = formatter.number(bounds.width);
        attrs.height = formatter.number(bounds.height);
        return createElement('use', attrs);
    }

    function exportGradient(color) {
        // NOTE: As long as the fillTransform attribute is not implemented,
        // we need to create a separate gradient object for each gradient,
        // even when they share the same gradient defintion.
        // http://www.svgopen.org/2011/papers/20-Separating_gradients_from_geometry/
        // TODO: Implement gradient merging in SVGImport
        var gradientNode = getDefinition(color, 'color');
        if (!gradientNode) {
            var gradient = color.getGradient(),
                radial = gradient._radial,
                origin = color.getOrigin().transform(),
                destination = color.getDestination().transform(),
                attrs;
            if (radial) {
                attrs = {
                    cx: origin.x,
                    cy: origin.y,
                    r: origin.getDistance(destination)
                };
                var highlight = color.getHighlight();
                if (highlight) {
                    highlight = highlight.transform();
                    attrs.fx = highlight.x;
                    attrs.fy = highlight.y;
                }
            } else {
                attrs = {
                    x1: origin.x,
                    y1: origin.y,
                    x2: destination.x,
                    y2: destination.y
                };
            }
            attrs.gradientUnits = 'userSpaceOnUse';
            gradientNode = createElement(
                    (radial ? 'radial' : 'linear') + 'Gradient', attrs);
            var stops = gradient._stops;
            for (var i = 0, l = stops.length; i < l; i++) {
                var stop = stops[i],
                    stopColor = stop._color,
                    alpha = stopColor.getAlpha();
                attrs = {
                    offset: stop._rampPoint,
                    'stop-color': stopColor.toCSS(true)
                };
                // See applyStyle for an explanation of why there are separated
                // opacity / color attributes.
                if (alpha < 1)
                    attrs['stop-opacity'] = alpha;
                gradientNode.appendChild(createElement('stop', attrs));
            }
            setDefinition(color, gradientNode, 'color');
        }
        return 'url(#' + gradientNode.id + ')';
    }

    function exportText(item) {
        var node = createElement('text', getTransform(item._matrix, true));
        node.textContent = item._content;
        return node;
    }

    var exporters = {
        Group: exportGroup,
        Layer: exportGroup,
        Raster: exportRaster,
        Path: exportPath,
        Shape: exportShape,
        CompoundPath: exportCompoundPath,
        PlacedSymbol: exportPlacedSymbol,
        PointText: exportText
    };

    function applyStyle(item, node, isRoot) {
        var attrs = {},
            parent = !isRoot && item.getParent();

        if (item._name != null)
            attrs.id = item._name;

        Base.each(SVGStyles, function(entry) {
            // Get a given style only if it differs from the value on the parent
            // (A layer or group which can have style values in SVG).
            var get = entry.get,
                type = entry.type,
                value = item[get]();
            if (entry.exportFilter
                    ? entry.exportFilter(item, value)
                    : !parent || !Base.equals(parent[get](), value)) {
                if (type === 'color' && value != null) {
                    // Support for css-style rgba() values is not in SVG 1.1, so
                    // separate the alpha value of colors with alpha into the
                    // separate fill- / stroke-opacity attribute:
                    var alpha = value.getAlpha();
                    if (alpha < 1)
                        attrs[entry.attribute + '-opacity'] = alpha;
                }
                attrs[entry.attribute] = value == null
                    ? 'none'
                    : type === 'number'
                        ? formatter.number(value)
                        : type === 'color'
                            ? value.gradient
                                ? exportGradient(value, item)
                                // true for noAlpha, see above
                                : value.toCSS(true)
                            : type === 'array'
                                ? value.join(',')
                                : type === 'lookup'
                                    ? entry.toSVG[value]
                                    : value;
            }
        });

        if (attrs.opacity === 1)
            delete attrs.opacity;

        if (!item._visible)
            attrs.visibility = 'hidden';

        return setAttributes(node, attrs);
    }

    var definitions;
    function getDefinition(item, type) {
        if (!definitions)
            definitions = { ids: {}, svgs: {} };
        return item && definitions.svgs[type + '-' + item._id];
    }

    function setDefinition(item, node, type) {
        // Make sure the definitions lookup is created before we use it.
        // This is required by 'clip', where getDefinition() is not called.
        if (!definitions)
            getDefinition();
        // Have different id ranges per type
        var id = definitions.ids[type] = (definitions.ids[type] || 0) + 1;
        // Give the svg node an id, and link to it from the item id.
        node.id = type + '-' + id;
        definitions.svgs[type + '-' + item._id] = node;
    }

    function exportDefinitions(node, options) {
        var svg = node,
            defs = null;
        if (definitions) {
            // We can only use svg nodes as defintion containers. Have the loop
            // produce one if it's a single item of another type (when calling
            // #exportSVG() on an item rather than a whole project)
            // jsdom in Node.js uses uppercase values for nodeName...
            svg = node.nodeName.toLowerCase() === 'svg' && node;
            for (var i in definitions.svgs) {
                // This code is inside the loop so we only create a container if
                // we actually have svgs.
                if (!defs) {
                    if (!svg) {
                        svg = createElement('svg');
                        svg.appendChild(node);
                    }
                    defs = svg.insertBefore(createElement('defs'),
                            svg.firstChild);
                }
                defs.appendChild(definitions.svgs[i]);
            }
            // Clear definitions at the end of export
            definitions = null;
        }
        return options.asString
                ? new XMLSerializer().serializeToString(svg)
                : svg;
    }

    function exportSVG(item, options, isRoot) {
        var exporter = exporters[item._class],
            node = exporter && exporter(item, options);
        if (node) {
            // Support onExportItem callback, to provide mechanism to handle
            // special attributes (e.g. inkscape:transform-center)
            var onExport = options.onExport;
            if (onExport)
                node = onExport(item, node, options) || node;
            var data = JSON.stringify(item._data);
            if (data && data !== '{}' && data != 'null')
                node.setAttribute('data-paper-data', data);
        }
        return node && applyStyle(item, node, isRoot);
    }

    function setOptions(options) {
        if (!options)
            options = {};
        formatter = new Formatter(options.precision);
        return options;
    }

    Item.inject({
        exportSVG: function(options) {
            options = setOptions(options);
            return exportDefinitions(exportSVG(this, options, true), options);
        }
    });

    Project.inject({
        exportSVG: function(options) {
            options = setOptions(options);
            var layers = this.layers,
                view = this.getView(),
                size = view.getViewSize(),
                node = createElement('svg', {
                    x: 0,
                    y: 0,
                    width: size.width,
                    height: size.height,
                    version: '1.1',
                    xmlns: 'http://www.w3.org/2000/svg',
                    'xmlns:xlink': 'http://www.w3.org/1999/xlink'
                }),
                parent = node,
                matrix = view._matrix;
            // If the view has a transformation, wrap all layers in a group with
            // that transformation applied to.
            if (!matrix.isIdentity())
                parent = node.appendChild(
                        createElement('g', getTransform(matrix)));
            for (var i = 0, l = layers.length; i < l; i++)
                parent.appendChild(exportSVG(layers[i], options, true));
            return exportDefinitions(node, options);
        }
    });
};
<|endoftext|>


<commit_before>/*******************************************************
 * NodeJS FFI bindings to ZCM
 * --------------------------
 * Could/Should be more efficent, but it should
 * suffice in the short-term
 ******************************************************/
var ffi = require('ffi');
var ref = require('ref');
var Struct = require('ref-struct');

// Define some types
var voidRef = ref.refType('void')
var charRef = ref.refType('char')
var recvBuf = Struct({
    zcm:   voidRef,
    utime: ref.types.ulonglong,
    len:   ref.types.size_t,
    data:  charRef,
});
var recvBufRef = ref.refType(recvBuf);

var libzcm = new ffi.Library('libzcm', {
    'zcm_create':     ['pointer', ['string']],
    'zcm_destroy':    ['void', ['pointer']],
    'zcm_publish':    ['int', ['pointer', 'string', 'pointer', 'int']],
    'zcm_subscribe':  ['int', ['pointer', 'string', 'pointer', 'pointer']],
    'zcm_start':      ['void', ['pointer']],
    'zcm_stop':       ['void', ['pointer']],
});

function makeDispatcher(cb)
{
    return function(rbuf, channel, usr) {
        // XXX This decoder makes a LOT of assumptions about the underlying machine
        //     These are not all correct for archs other than x86-64
        var zcmPtr = ref.readPointer(rbuf, 0);
        var utime  = ref.readUInt64LE(rbuf, 8);
        var len    = ref.readUInt64LE(rbuf, 16);
        var data   = ref.readPointer(rbuf, 24);
        var dataBuf = ref.reinterpret(data, len);
        cb(channel, new Buffer(dataBuf));
    }
}

function libzcmTransport(transport) {
    var z = libzcm.zcm_create(transport);
    if (z.isNull()) {
        console.log("Err: Failed to create transport '"+transport+"'");
        return {};
    }

    function publish(channel, data) {
        libzcm.zcm_publish.async(z, channel, data, data.length, function(err, res){});
    }

    function subscribe(channel, cb) {
        var funcPtr = ffi.Callback('void', [recvBufRef, 'string', 'pointer'], makeDispatcher(cb));
        process.on('exit', function() { funcPtr;}); // Force an extra ref to avoid Garbage Collection
        libzcm.zcm_subscribe(z, channel, funcPtr, null);
    }

    return {
        publish: publish,
        subscribe: subscribe
    };
}

function socketioTransport(http) {
    var io = require('socket.io')(http);

    // Channel -> Callback
    var callbacks = {};

    io.on('connection', function(socket){
        socket.on('client-to-server', function(data){
            var channel = data.channel;
            if (channel in callbacks)
                callbacks[channel](channel, data.msg);
        });
    });

    function publish(channel, msg) {
        io.emit('server-to-client', {
            channel: channel,
            msg: msg
        });
    }

    function subscribe(channel, cb) {
        callbacks[channel] = cb;
    }

    return {
        publish: publish,
        subscribe: subscribe
    };
}

function zcm_create(transport) {
    transport = transport || 'ipc';
    // NOTE: this is a hack to keep the program alive
    setInterval(function(){}, 100000);
    return libzcmTransport(transport);
}

function zcm_connect_client(http, zcmtypes, table)
{
    var zIPC = libzcmTransport('ipc');
    var zWebsock = socketioTransport(http);

    for (var channel in table) {
        var typename = table[channel];
        var type = zcmtypes[typename];
        if (!type) {
            console.log("Unknown type '"+typename+"' in connect_client()");
            continue;
        }
        zIPC.subscribe(channel, function(channel, data) {
            zWebsock.publish(channel, type.decode(data));
        });
        zWebsock.subscribe(channel, function(channel, msg) {
            zIPC.publish(channel, type.encode(msg));
        });
    }
}

exports.create = zcm_create;
exports.connect_client = zcm_connect_client;
<commit_msg>Fixed upp nodejs for start/stop/become changes<commit_after>/*******************************************************
 * NodeJS FFI bindings to ZCM
 * --------------------------
 * Could/Should be more efficent, but it should
 * suffice in the short-term
 ******************************************************/
var ffi = require('ffi');
var ref = require('ref');
var Struct = require('ref-struct');

// Define some types
var voidRef = ref.refType('void')
var charRef = ref.refType('char')
var recvBuf = Struct({
    zcm:   voidRef,
    utime: ref.types.ulonglong,
    len:   ref.types.size_t,
    data:  charRef,
});
var recvBufRef = ref.refType(recvBuf);

var libzcm = new ffi.Library('libzcm', {
    'zcm_create':     ['pointer', ['string']],
    'zcm_destroy':    ['void', ['pointer']],
    'zcm_publish':    ['int', ['pointer', 'string', 'pointer', 'int']],
    'zcm_subscribe':  ['int', ['pointer', 'string', 'pointer', 'pointer']],
    'zcm_start':      ['void', ['pointer']],
    'zcm_stop':       ['void', ['pointer']],
});

function makeDispatcher(cb)
{
    return function(rbuf, channel, usr) {
        // XXX This decoder makes a LOT of assumptions about the underlying machine
        //     These are not all correct for archs other than x86-64
        var zcmPtr = ref.readPointer(rbuf, 0);
        var utime  = ref.readUInt64LE(rbuf, 8);
        var len    = ref.readUInt64LE(rbuf, 16);
        var data   = ref.readPointer(rbuf, 24);
        var dataBuf = ref.reinterpret(data, len);
        cb(channel, new Buffer(dataBuf));
    }
}

function libzcmTransport(transport) {
    var z = libzcm.zcm_create(transport);
    if (z.isNull()) {
        console.log("Err: Failed to create transport '"+transport+"'");
        return {};
    }

    libzcm.zcm_start(z);

    function publish(channel, data) {
        libzcm.zcm_publish.async(z, channel, data, data.length, function(err, res){});
    }

    function subscribe(channel, cb) {
        var funcPtr = ffi.Callback('void', [recvBufRef, 'string', 'pointer'], makeDispatcher(cb));
        process.on('exit', function() { funcPtr;}); // Force an extra ref to avoid Garbage Collection
        libzcm.zcm_subscribe(z, channel, funcPtr, null);
    }

    return {
        publish: publish,
        subscribe: subscribe
    };
}

function socketioTransport(http) {
    var io = require('socket.io')(http);

    // Channel -> Callback
    var callbacks = {};

    io.on('connection', function(socket){
        socket.on('client-to-server', function(data){
            var channel = data.channel;
            if (channel in callbacks)
                callbacks[channel](channel, data.msg);
        });
    });

    function publish(channel, msg) {
        io.emit('server-to-client', {
            channel: channel,
            msg: msg
        });
    }

    function subscribe(channel, cb) {
        callbacks[channel] = cb;
    }

    return {
        publish: publish,
        subscribe: subscribe
    };
}

function zcm_create(transport) {
    transport = transport || 'ipc';
    // NOTE: this is a hack to keep the program alive
    setInterval(function(){}, 100000);
    return libzcmTransport(transport);
}

function zcm_connect_client(http, zcmtypes, table)
{
    var zIPC = libzcmTransport('ipc');
    var zWebsock = socketioTransport(http);

    for (var channel in table) {
        var typename = table[channel];
        var type = zcmtypes[typename];
        if (!type) {
            console.log("Unknown type '"+typename+"' in connect_client()");
            continue;
        }
        zIPC.subscribe(channel, function(channel, data) {
            zWebsock.publish(channel, type.decode(data));
        });
        zWebsock.subscribe(channel, function(channel, msg) {
            zIPC.publish(channel, type.encode(msg));
        });
    }
}

exports.create = zcm_create;
exports.connect_client = zcm_connect_client;
<|endoftext|>


<commit_before>//
// Record
//
BiwaScheme.debug = function(){}; //console.debug;
BiwaScheme.Record = Class.create({
  initialize: function(rtd, values){
    assert_record_td(rtd, "new Record");

    this.rtd = rtd;
    this.fields = values;
  },
  get: function(k){
    return this.fields[k]
  },
  set: function(k, v){
    this.fields[k] = v;
  },
  toString: function(){
    var contents = BiwaScheme.to_write(this.fields);
    return "#<Record "+this.rtd.name+" "+contents+">";
  }
});
BiwaScheme.isRecord = function(o){
  return (o instanceof BiwaScheme.Record);
};

// Record types
BiwaScheme.Record._DefinedTypes = new Hash();

BiwaScheme.Record.define_type = function(name_str, rtd, cd){
  return BiwaScheme.Record._DefinedTypes.set(name_str, {rtd: rtd, cd: cd});
};
BiwaScheme.Record.get_type = function(name_str){
  return BiwaScheme.Record._DefinedTypes.get(name_str);
};

// Record type descriptor
BiwaScheme.Record.RTD = Class.create({
  //                   Symbol RTD        Symbol Bool  Bool    Array
  initialize: function(name, parent_rtd, uid, sealed, opaque, fields){
    this.name = name;
    this.parent_rtd = parent_rtd;
    this.is_base_type = !parent_rtd;
    if(uid){
      this.uid = uid;
      this.generative = false;
    }
    else{
      this.uid = this._generate_new_uid();;
      this.generative = true;
    }

    this.sealed = !!sealed;
    this.opaque = parent_rtd.opaque || (!!opaque);

    this.fields = fields.map(function(field){
      return {name: field[0], mutable: !!field[1]};
    });
  },
  _generate_new_uid: function(){
    var n = (BiwaScheme.Record.RTD.last_uid++);
    return BiwaScheme.Sym("__record_td_uid_"+n);
  },
  toString: function(){
    return "#<RecordTD "+name+">";
  }
});
BiwaScheme.Record.RTD.last_uid = 0;
BiwaScheme.Record.RTD.NongenerativeRecords = new Hash();
BiwaScheme.isRecordTD = function(o){
  return (o instanceof BiwaScheme.Record.RTD);
};

// Record constructor descriptor
BiwaScheme.Record.CD = Class.create({
  initialize: function(rtd, parent_cd, protocol){
    this._check(rtd, parent_cd, protocol);
    this.rtd = rtd;
    this.parent_cd = parent_cd;
    if(protocol){
      this.has_custom_protocol = true;
      this.protocol = protocol;
    }
    else{
      this.has_custom_protocol = false;
      if(rtd.parent_rtd)
        this.protocol = this._default_protocol_for_derived_types();
      else
        this.protocol = this._default_protocol_for_base_types();
    }
  },

  _check: function(rtd, parent_cd, protocol){
    if(rtd.is_base_type && parent_cd)
      throw new Error("Record.CD.new: cannot specify parent cd of a base type");

    if(parent_cd && rtd.parent_rtd && (parent_cd.rtd != rtd.parent_rtd))
      throw new Error("Record.CD.new: mismatched parents between rtd and parent_cd");

    if(rtd.parent_rtd && !parent_cd && protocol)
      throw new Error("Record.CD.new: protocol must be #f when parent_cd is not given");

    if(parent_cd && parent_cd.has_custom_protocol && !protocol)
      throw new Error("Record.CD.new: protocol must be specified when parent_cd has a custom protocol");
  },

  _default_protocol_for_base_types: function(){
    // (lambda (p) p)
    // called with `p' as an argument
    return function(ar){
      var p = ar[0];
      assert_procedure(p, "_default_protocol/base");
      return p;
    };
  },

  _default_protocol_for_derived_types: function(){
    // (lambda (n)
    //   (lambda (a b x y s t)
    //     (let1 p (n a b x y) (p s t))))
    // called with `n' as an argument
    var rtd = this.rtd;
    return function(ar){
      var n = ar[0];
      assert_procedure(n, "_default_protocol/n");

      var ctor = function(args){
        var my_argc = rtd.fields.length;
        var ancestor_argc = args.length - my_argc;

        var ancestor_values = args.slice(0, ancestor_argc);
        var my_values       = args.slice(ancestor_argc);
        BiwaScheme.debug($H({ctor_args: args}).inspect());

        // (n a b x y) => p
        return new BiwaScheme.Call(n, ancestor_values, function(ar){
          var p = ar[0];
          assert_procedure(p, "_default_protocol/p");
          BiwaScheme.debug($H({ctor_p_my: my_values, ancestor_values: ancestor_values}).inspect());

          // (p s t) => record
          return new BiwaScheme.Call(p, my_values, function(ar){
            var record = ar[0];
            assert_record(record, "_default_protocol/result");

            return record;
          });
        });
      };
      return ctor;
    };
  },

  toString: function(){
    return "#<RecordCD "+this.rtd.name+">";
  },

  record_constructor: function(){
    var arg_for_protocol = (this.parent_cd ? this._make_n([], this.rtd)
                                           : this._make_p()).bind(this);

    return new BiwaScheme.Call(this.protocol, [arg_for_protocol], function(ar){
      var ctor = ar[0];
      assert_procedure(ctor, "record_constructor");
      return ctor;
    });
  },

  // Create the function `p' which is given to the protocol.
  _make_p: function(){
    return function(values){
      return new BiwaScheme.Record(this.rtd, values);
      // TODO: check argc
    };
  },

  // Create the function `n' which is given to the protocol.
  // When creating an instance of a derived type,
  // _make_n is called for each ancestor rtd's.
  _make_n: function(children_values, rtd){
    var parent_cd = this.parent_cd;

    if(parent_cd){
      // called from protocol (n)
      var n = function(args_for_n){
        BiwaScheme.debug($H({maken_n: args_for_n}).inspect());

        // called from protocol (p)
        var p = function(args_for_p){
          var values = [].concat(args_for_p[0]).concat(children_values)
          var parent_n = parent_cd._make_n(values, rtd);
          BiwaScheme.debug($H({maken_p: args_for_p}).inspect());

          return new BiwaScheme.Call(parent_cd.protocol, [parent_n], function(ar){
            var ctor = ar[0];
            assert_procedure(ctor, "_make_n");

            return new BiwaScheme.Call(ctor, args_for_n, function(ar){
              var record = ar[0];
              assert_record(record);
              BiwaScheme.debug($H({maken2_ar: ar}).inspect());
              return record;
            });
          });
        };
        return p;
      };
      return n;
    }
    else{
      var n = function(my_values){
        var values = my_values.concat(children_values);
        BiwaScheme.debug($H({base_n: values}).inspect());
        return new BiwaScheme.Record(rtd, values);
        // TODO: check argc
      };
      return n;
    }
  }
});

BiwaScheme.isRecordCD = function(o){
  return (o instanceof BiwaScheme.Record.CD);
};
<commit_msg>Removed debug code from record.js<commit_after>//
// Record
//
BiwaScheme.Record = Class.create({
  initialize: function(rtd, values){
    assert_record_td(rtd, "new Record");

    this.rtd = rtd;
    this.fields = values;
  },
  get: function(k){
    return this.fields[k]
  },
  set: function(k, v){
    this.fields[k] = v;
  },
  toString: function(){
    var contents = BiwaScheme.to_write(this.fields);
    return "#<Record "+this.rtd.name+" "+contents+">";
  }
});
BiwaScheme.isRecord = function(o){
  return (o instanceof BiwaScheme.Record);
};

// Record types
BiwaScheme.Record._DefinedTypes = new Hash();

BiwaScheme.Record.define_type = function(name_str, rtd, cd){
  return BiwaScheme.Record._DefinedTypes.set(name_str, {rtd: rtd, cd: cd});
};
BiwaScheme.Record.get_type = function(name_str){
  return BiwaScheme.Record._DefinedTypes.get(name_str);
};

// Record type descriptor
BiwaScheme.Record.RTD = Class.create({
  //                   Symbol RTD        Symbol Bool  Bool    Array
  initialize: function(name, parent_rtd, uid, sealed, opaque, fields){
    this.name = name;
    this.parent_rtd = parent_rtd;
    this.is_base_type = !parent_rtd;
    if(uid){
      this.uid = uid;
      this.generative = false;
    }
    else{
      this.uid = this._generate_new_uid();;
      this.generative = true;
    }

    this.sealed = !!sealed;
    this.opaque = parent_rtd.opaque || (!!opaque);

    this.fields = fields.map(function(field){
      return {name: field[0], mutable: !!field[1]};
    });
  },
  _generate_new_uid: function(){
    var n = (BiwaScheme.Record.RTD.last_uid++);
    return BiwaScheme.Sym("__record_td_uid_"+n);
  },
  toString: function(){
    return "#<RecordTD "+name+">";
  }
});
BiwaScheme.Record.RTD.last_uid = 0;
BiwaScheme.Record.RTD.NongenerativeRecords = new Hash();
BiwaScheme.isRecordTD = function(o){
  return (o instanceof BiwaScheme.Record.RTD);
};

// Record constructor descriptor
BiwaScheme.Record.CD = Class.create({
  initialize: function(rtd, parent_cd, protocol){
    this._check(rtd, parent_cd, protocol);
    this.rtd = rtd;
    this.parent_cd = parent_cd;
    if(protocol){
      this.has_custom_protocol = true;
      this.protocol = protocol;
    }
    else{
      this.has_custom_protocol = false;
      if(rtd.parent_rtd)
        this.protocol = this._default_protocol_for_derived_types();
      else
        this.protocol = this._default_protocol_for_base_types();
    }
  },

  _check: function(rtd, parent_cd, protocol){
    if(rtd.is_base_type && parent_cd)
      throw new Error("Record.CD.new: cannot specify parent cd of a base type");

    if(parent_cd && rtd.parent_rtd && (parent_cd.rtd != rtd.parent_rtd))
      throw new Error("Record.CD.new: mismatched parents between rtd and parent_cd");

    if(rtd.parent_rtd && !parent_cd && protocol)
      throw new Error("Record.CD.new: protocol must be #f when parent_cd is not given");

    if(parent_cd && parent_cd.has_custom_protocol && !protocol)
      throw new Error("Record.CD.new: protocol must be specified when parent_cd has a custom protocol");
  },

  _default_protocol_for_base_types: function(){
    // (lambda (p) p)
    // called with `p' as an argument
    return function(ar){
      var p = ar[0];
      assert_procedure(p, "_default_protocol/base");
      return p;
    };
  },

  _default_protocol_for_derived_types: function(){
    // (lambda (n)
    //   (lambda (a b x y s t)
    //     (let1 p (n a b x y) (p s t))))
    // called with `n' as an argument
    var rtd = this.rtd;
    return function(ar){
      var n = ar[0];
      assert_procedure(n, "_default_protocol/n");

      var ctor = function(args){
        var my_argc = rtd.fields.length;
        var ancestor_argc = args.length - my_argc;

        var ancestor_values = args.slice(0, ancestor_argc);
        var my_values       = args.slice(ancestor_argc);

        // (n a b x y) => p
        return new BiwaScheme.Call(n, ancestor_values, function(ar){
          var p = ar[0];
          assert_procedure(p, "_default_protocol/p");

          // (p s t) => record
          return new BiwaScheme.Call(p, my_values, function(ar){
            var record = ar[0];
            assert_record(record, "_default_protocol/result");

            return record;
          });
        });
      };
      return ctor;
    };
  },

  toString: function(){
    return "#<RecordCD "+this.rtd.name+">";
  },

  record_constructor: function(){
    var arg_for_protocol = (this.parent_cd ? this._make_n([], this.rtd)
                                           : this._make_p()).bind(this);

    return new BiwaScheme.Call(this.protocol, [arg_for_protocol], function(ar){
      var ctor = ar[0];
      assert_procedure(ctor, "record_constructor");
      return ctor;
    });
  },

  // Create the function `p' which is given to the protocol.
  _make_p: function(){
    return function(values){
      return new BiwaScheme.Record(this.rtd, values);
      // TODO: check argc
    };
  },

  // Create the function `n' which is given to the protocol.
  // When creating an instance of a derived type,
  // _make_n is called for each ancestor rtd's.
  _make_n: function(children_values, rtd){
    var parent_cd = this.parent_cd;

    if(parent_cd){
      // called from protocol (n)
      var n = function(args_for_n){

        // called from protocol (p)
        var p = function(args_for_p){
          var values = [].concat(args_for_p[0]).concat(children_values)
          var parent_n = parent_cd._make_n(values, rtd);

          return new BiwaScheme.Call(parent_cd.protocol, [parent_n], function(ar){
            var ctor = ar[0];
            assert_procedure(ctor, "_make_n");

            return new BiwaScheme.Call(ctor, args_for_n, function(ar){
              var record = ar[0];
              assert_record(record);
              return record;
            });
          });
        };
        return p;
      };
      return n;
    }
    else{
      var n = function(my_values){
        var values = my_values.concat(children_values);
        return new BiwaScheme.Record(rtd, values);
        // TODO: check argc
      };
      return n;
    }
  }
});

BiwaScheme.isRecordCD = function(o){
  return (o instanceof BiwaScheme.Record.CD);
};
<|endoftext|>


<commit_before>/* Put everything inside the GiDebug namespace. */

GiDebug = function() {

var debug_el_id = 'gidebug';

var is_open = false;
var use_touch_ui;
var drag_mode = null;
var min_width = 200;
var cmd_handler = null;

function debug_init(handler)
{
    cmd_handler = handler;
}

function debug_open()
{
    if (is_open)
        return;

    use_touch_ui = (window.TouchEvent != undefined);

    /* Figure out what the root div is called. The dialog box will be
       positioned in this div. We use the same default as GlkOte:
       "gameport". We also try to interrogate GlkOte to see if that
       default has been changed. */
    var root_el_id = 'gameport';
    var iface = window.Game;
    if (window.GlkOte)
        iface = window.GlkOte.getinterface();
    if (iface && iface.gameport)
        root_el_id = iface.gameport;

    var rootel = $('#'+root_el_id);
    if (!rootel.length)
        throw new Error('GiDebug: unable to find root element #' + root_el_id + '.');

    dia = $('<div>', { id: debug_el_id });
    var el, subel;

    function set_drag_effect(el, tag) {
        if (!use_touch_ui)
            el.on('mousedown', { tag:tag }, evhan_dragstart);
        else
            el.on('touchstart', { tag:tag }, evhan_dragstart);
    };

    el = $('<div>', { class: 'GiDebugHeader GiDebugRoundNE GiDebugRoundNW' });
    el.text('Debugging');
    dia.append(el);
    el.css({ cursor:'move' });
    set_drag_effect(el, 'position');

    subel = $('<div>', { class: 'GiDebugRightButton GiDebugRoundNE' });
    subel.css({ cursor:'e-resize' });
    el.append(subel);
    set_drag_effect(subel, 'width');

    el = $('<div>', { class: 'GiDebugFooter GiDebugRoundSE GiDebugRoundSW' });
    dia.append(el);
    el.css({ cursor:'s-resize' });
    set_drag_effect(el, 'height');

    subel = $('<div>', { class: 'GiDebugRightButton GiDebugRoundSE' });
    subel.css({ cursor:'se-resize' });
    el.append(subel);
    set_drag_effect(subel, 'size');

    el = $('<div>', { id: debug_el_id+'_body', class: 'GiDebugBody' });
    dia.append(el);

    subel = $('<div>', { id: debug_el_id+'_text', class: 'GiDebugText' });
    el.append(subel);

    subel = $('<div>', { class: 'GiDebugPrompt' });
    subel.text('>');
    el.append(subel);

    subel = $('<input>', { id: debug_el_id+'_input', type: 'text', class: 'GiDebugInput' });
    subel.attr({ autocapitalize:'off', 'aria-live':'off' });
    subel.on('keypress', function(ev) {
        if (ev.keyCode == 13) {
            evhan_input(ev);
        }
    });
    el.append(subel);

    rootel.append(dia);
    is_open = true;
}

function debug_output(ls)
{
    add_lines(ls);
}

function add_lines(ls)
{
    var textel = $('#'+debug_el_id+'_text');
    if (!textel.length)
        return;

    for (var ix=0; ix<ls.length; ix++) {
        var el = $('<div>');
        var val = ls[ix];
        val = val.replace(regex_long_whitespace, func_long_whitespace);
        el.text(val);
        textel.append(el);
    }

    textel.scrollTop(textel.get(0).scrollHeight);
}

var regex_long_whitespace = new RegExp('  +', 'g'); /* two or more spaces */

/* Given a run of N spaces (N >= 2), return N-1 non-breaking spaces plus
   a normal one. */
function func_long_whitespace(match) {
  var len = match.length;
  if (len == 1)
    return ' ';
  /* Evil trick I picked up from Prototype. Gives len-1 copies of NBSP. */
  var res = new Array(len).join('\xa0');
  return res + ' ';
}

function evhan_input(ev)
{
    var inputel = $('#'+debug_el_id+'_input');
    if (!inputel.length)
        return;

    var val = inputel.val().trim();
    inputel.val('');

    if (!val.length)
        return;

    add_lines(['> '+val]);

    if (cmd_handler)
        cmd_handler(val);
    else
        add_lines(['There is no debug command handler.']);
}

function event_pos(ev)
{
    if (!use_touch_ui)
        return { left:ev.clientX, top:ev.clientY };
    else
        return { left:ev.originalEvent.pageX, top:ev.originalEvent.pageY };
}

function evhan_dragstart(ev)
{
    if (drag_mode)
        return;

    var dia = $('#'+debug_el_id);
    if (!dia.length)
        return;

    drag_mode = ev.data.tag;

    ev.preventDefault();
    ev.stopPropagation();

    switch (drag_mode) {
    case 'position':
        drag_offset = dia.offset();
        break;
    case 'size':
    case 'width':
    case 'height':
        drag_offset = { left:dia.width(), top:dia.height() };
        break;
    }

    var pos = event_pos(ev);
    drag_offset.left = pos.left - drag_offset.left;
    drag_offset.top = pos.top - drag_offset.top;

    if (!use_touch_ui) {
        $('body').on('mousemove', evhan_dragdrag);
        $('body').on('mouseup', evhan_dragstop);
    }
    else {
        $('body').on('touchmove', evhan_dragdrag);
        $('body').on('touchend', evhan_dragstop);
        $('body').on('touchcancel', evhan_dragstop);
    }
}

function evhan_dragdrag(ev, ui)
{
    if (!drag_mode)
        return;

    var dia = $('#'+debug_el_id);
    if (!dia.length)
        return;

    var pos = event_pos(ev);
    pos.left -= drag_offset.left;
    pos.top -= drag_offset.top;

    switch (drag_mode) {
    case 'position':
        pos.top = Math.max(0, pos.top);
        dia.offset(pos);
        break;
    case 'size':
        dia.width(Math.max(min_width, pos.left));
        dia.height(Math.max(min_width, pos.top));
        break;
    case 'width':
        dia.width(Math.max(min_width, pos.left));
        break;
    case 'height':
        dia.height(Math.max(min_width, pos.top));
        break;
    }
}

function evhan_dragstop(ev, ui)
{
    if (!use_touch_ui) {
        $('body').off('mousemove');
        $('body').off('mouseup');
    }
    else {
        $('body').off('touchmove');
        $('body').off('touchend');
        $('body').off('touchcancel');
    }

    drag_mode = null;
}

/* End of GiDebug namespace function. Return the object which will
   become the GiDebug global. */
return {
    init: debug_init,
    open: debug_open,
    output: debug_output
};

}();

/* End of GiDebug library. */
<commit_msg>Comments.<commit_after>/* GiDebug -- a debug overlay interface for GlkOte
 * Designed by Andrew Plotkin <erkyrath@eblong.com>
 * <http://eblong.com/zarf/glk/glkote.html>
 *
 * This Javascript library is copyright 2017 by Andrew Plotkin.
 * It is distributed under the MIT license; see the "LICENSE" file.
 *
 * This library adds a simple debug console, overlaid onto the GlkOte
 * UI. Or it can be used with any HTML interface, really. GlkOte is set
 * up to activate the debug console if you set the "debug_commands" option
 * in the GlkOte game interface object.
 *
 * The library has these APIs:
 *
 * GiDebug.init(handler) -- activate the console
 *
 * Call this during initialization to set up the debug console. The
 * handler should be a function that accepts debug command strings.
 *
 * GiDebug.open() -- make the console visible
 *
 * The console is not initially visible, unless it generates output
 * on startup. Call this to make it visible.
 *
 * GiDebug.output(ls) -- display a list of text lines in the console
 *
 * Your command handler (and perhaps other parts of the game) calls this
 * to display output in the console. The argument is a *list* of lines of
 * text. (Don't call this with a bare string!)
 */

/* Put everything inside the GiDebug namespace. */

GiDebug = function() {

var debug_el_id = 'gidebug';

var is_open = false;
var use_touch_ui;
var drag_mode = null;
var min_width = 200;
var cmd_handler = null;

function debug_init(handler)
{
    cmd_handler = handler;
}

function debug_open()
{
    if (is_open)
        return;

    use_touch_ui = (window.TouchEvent != undefined);

    /* Figure out what the root div is called. The dialog box will be
       positioned in this div. We use the same default as GlkOte:
       "gameport". We also try to interrogate GlkOte to see if that
       default has been changed. */
    var root_el_id = 'gameport';
    var iface = window.Game;
    if (window.GlkOte)
        iface = window.GlkOte.getinterface();
    if (iface && iface.gameport)
        root_el_id = iface.gameport;

    var rootel = $('#'+root_el_id);
    if (!rootel.length)
        throw new Error('GiDebug: unable to find root element #' + root_el_id + '.');

    dia = $('<div>', { id: debug_el_id });
    var el, subel;

    function set_drag_effect(el, tag) {
        if (!use_touch_ui)
            el.on('mousedown', { tag:tag }, evhan_dragstart);
        else
            el.on('touchstart', { tag:tag }, evhan_dragstart);
    };

    el = $('<div>', { class: 'GiDebugHeader GiDebugRoundNE GiDebugRoundNW' });
    el.text('Debugging');
    dia.append(el);
    el.css({ cursor:'move' });
    set_drag_effect(el, 'position');

    subel = $('<div>', { class: 'GiDebugRightButton GiDebugRoundNE' });
    subel.css({ cursor:'e-resize' });
    el.append(subel);
    set_drag_effect(subel, 'width');

    el = $('<div>', { class: 'GiDebugFooter GiDebugRoundSE GiDebugRoundSW' });
    dia.append(el);
    el.css({ cursor:'s-resize' });
    set_drag_effect(el, 'height');

    subel = $('<div>', { class: 'GiDebugRightButton GiDebugRoundSE' });
    subel.css({ cursor:'se-resize' });
    el.append(subel);
    set_drag_effect(subel, 'size');

    el = $('<div>', { id: debug_el_id+'_body', class: 'GiDebugBody' });
    dia.append(el);

    subel = $('<div>', { id: debug_el_id+'_text', class: 'GiDebugText' });
    el.append(subel);

    subel = $('<div>', { class: 'GiDebugPrompt' });
    subel.text('>');
    el.append(subel);

    subel = $('<input>', { id: debug_el_id+'_input', type: 'text', class: 'GiDebugInput' });
    subel.attr({ autocapitalize:'off', 'aria-live':'off' });
    subel.on('keypress', function(ev) {
        if (ev.keyCode == 13) {
            evhan_input(ev);
        }
    });
    el.append(subel);

    rootel.append(dia);
    is_open = true;
}

function debug_output(ls)
{
    add_lines(ls);
}

function add_lines(ls)
{
    var textel = $('#'+debug_el_id+'_text');
    if (!textel.length)
        return;

    for (var ix=0; ix<ls.length; ix++) {
        var el = $('<div>');
        var val = ls[ix];
        val = val.replace(regex_long_whitespace, func_long_whitespace);
        el.text(val);
        textel.append(el);
    }

    textel.scrollTop(textel.get(0).scrollHeight);
}

var regex_long_whitespace = new RegExp('  +', 'g'); /* two or more spaces */

/* Given a run of N spaces (N >= 2), return N-1 non-breaking spaces plus
   a normal one. */
function func_long_whitespace(match) {
  var len = match.length;
  if (len == 1)
    return ' ';
  /* Evil trick I picked up from Prototype. Gives len-1 copies of NBSP. */
  var res = new Array(len).join('\xa0');
  return res + ' ';
}

function evhan_input(ev)
{
    var inputel = $('#'+debug_el_id+'_input');
    if (!inputel.length)
        return;

    var val = inputel.val().trim();
    inputel.val('');

    if (!val.length)
        return;

    add_lines(['> '+val]);

    if (cmd_handler)
        cmd_handler(val);
    else
        add_lines(['There is no debug command handler.']);
}

function event_pos(ev)
{
    if (!use_touch_ui)
        return { left:ev.clientX, top:ev.clientY };
    else
        return { left:ev.originalEvent.pageX, top:ev.originalEvent.pageY };
}

function evhan_dragstart(ev)
{
    if (drag_mode)
        return;

    var dia = $('#'+debug_el_id);
    if (!dia.length)
        return;

    drag_mode = ev.data.tag;

    ev.preventDefault();
    ev.stopPropagation();

    switch (drag_mode) {
    case 'position':
        drag_offset = dia.offset();
        break;
    case 'size':
    case 'width':
    case 'height':
        drag_offset = { left:dia.width(), top:dia.height() };
        break;
    }

    var pos = event_pos(ev);
    drag_offset.left = pos.left - drag_offset.left;
    drag_offset.top = pos.top - drag_offset.top;

    if (!use_touch_ui) {
        $('body').on('mousemove', evhan_dragdrag);
        $('body').on('mouseup', evhan_dragstop);
    }
    else {
        $('body').on('touchmove', evhan_dragdrag);
        $('body').on('touchend', evhan_dragstop);
        $('body').on('touchcancel', evhan_dragstop);
    }
}

function evhan_dragdrag(ev, ui)
{
    if (!drag_mode)
        return;

    var dia = $('#'+debug_el_id);
    if (!dia.length)
        return;

    var pos = event_pos(ev);
    pos.left -= drag_offset.left;
    pos.top -= drag_offset.top;

    switch (drag_mode) {
    case 'position':
        pos.top = Math.max(0, pos.top);
        dia.offset(pos);
        break;
    case 'size':
        dia.width(Math.max(min_width, pos.left));
        dia.height(Math.max(min_width, pos.top));
        break;
    case 'width':
        dia.width(Math.max(min_width, pos.left));
        break;
    case 'height':
        dia.height(Math.max(min_width, pos.top));
        break;
    }
}

function evhan_dragstop(ev, ui)
{
    if (!use_touch_ui) {
        $('body').off('mousemove');
        $('body').off('mouseup');
    }
    else {
        $('body').off('touchmove');
        $('body').off('touchend');
        $('body').off('touchcancel');
    }

    drag_mode = null;
}

/* End of GiDebug namespace function. Return the object which will
   become the GiDebug global. */
return {
    init: debug_init,
    open: debug_open,
    output: debug_output
};

}();

/* End of GiDebug library. */
<|endoftext|>


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

import CodedSetTableForm from './CodedSetTableForm';
import { responseSetProps } from '../prop-types/response_set_props';

export default class ResponseSetForm extends Component {
  constructor(props) {
    super(props);
    // TODO: Extract building of new response sets to
    // their own methods to clean things up.
    let version = 1;
    let versionIndependentId;
    let oid = this.props.responseSet.oid || '';
    if (props.action === 'extend') {
      oid = '';
    }
    if (props.action === 'revise') {
      version = this.props.responseSet.version + 1;
      versionIndependentId = this.props.responseSet.versionIndependentId;
    }
    let startingResponses;
    if (this.props.responseSet.responses) {
      startingResponses = filterResponses(this.props.responseSet.responses);
    } else {
      startingResponses = [{displayName: '', value: '', codeSystem: ''}];
    }
    this.state = {name: this.props.responseSet.name,
      oid,
      coded: this.props.responseSet.coded || false,
      description: this.props.responseSet.description || '',
      responsesAttributes: startingResponses,
      version: version,
      versionIndependentId: versionIndependentId
    };
  }

  render() {
    return (
      <form onSubmit={(e) => this.handleSubmit(e)}>

              Name
              <input type="text" value={this.state.name} name="name" id="name" onChange={this.handleChange('name')}/>

              OID
              <input type="text" value={this.state.oid} name="oid" id="oid" onChange={this.handleChange('oid')}/>

              Coded
              <input type="checkbox" value={this.state.coded} name="coded" id="coded" onChange={this.handleChange('coded')}/>

              Description
              <textarea value={this.state.description} name="description" id="description" onChange={this.handleChange('description')}/>

          <CodedSetTableForm itemWatcher={(r) => this.handleResponsesChange(r)}
                             initialItems={this.state.responsesAttributes}
                             parentName={'response_set'}
                             childName={'response'} />

            <input type="submit" value={`${this.props.action} Response Set`}/>

      </form>
    );
  }

  handleSubmit(event) {
    event.preventDefault();
    this.props.responseSetSubmitter(this.state, (response) => {
      // TODO: Handle when the saving response set fails.
      if (response.status === 201) {
        this.props.router.push(`/responseSets/${response.data.id}`);
      }
    });
  }

  handleResponsesChange(newResponses) {
    this.setState({responsesAttributes: newResponses});
  }

  handleChange(field) {
    return (event) => {
      let newState = {};
      newState[field] = event.target.value;
      this.setState(newState);
    };
  }
}

function filterResponses(responses) {
  return responses.map((nr) => {
    return {value: nr.value, codeSystem: nr.codeSystem, displayName: nr.displayName};
  });
}

ResponseSetForm.propTypes = {
  responseSet: responseSetProps.isRequired,
  responseSetSubmitter: PropTypes.func.isRequired,
  action: PropTypes.string.isRequired,
  router: PropTypes.object.isRequired
};
<commit_msg>Cleaned up the constructor<commit_after>import React, { Component, PropTypes } from 'react';

import CodedSetTableForm from './CodedSetTableForm';
import { responseSetProps } from '../prop-types/response_set_props';

export default class ResponseSetForm extends Component {
  constructor(props) {
    super(props);
    switch (this.props.action) {
      case 'revise':
        this.state = this.stateForRevise(this.props.responseSet);
        break;
      case 'extend':
        this.state = this.stateForExtend(this.props.responseSet);
        break;
      case 'new':
        this.state = this.stateForNew();
        break;
    }
  }

  stateForRevise(responseSet) {
    const name = responseSet.name || '';
    const oid = responseSet.oid || '';
    const coded = responseSet.coded || false;
    const description = responseSet.description || '';
    const responsesAttributes = filterResponses(responseSet.responses);
    const version = responseSet.version + 1;
    const versionIndependentId = responseSet.versionIndependentId;
    return {name, oid, description, coded, responsesAttributes,
      version, versionIndependentId};
  }

  stateForNew() {
    return {
      name: '', oid: '', coded: false, description: '',
      responsesAttributes: [{displayName: '', value: '', codeSystem: ''}],
      version: 1, versionIndependentId: null
    };
  }

  stateForExtend(responseSet) {
    const name = responseSet.name || '';
    const oid = '';
    const coded = responseSet.coded || false;
    const description = responseSet.description || '';
    const responsesAttributes = filterResponses(responseSet.responses);
    const version = 1;
    const versionIndependentId = null;
    return {name, oid, description, coded, responsesAttributes,
      version, versionIndependentId};
  }

  render() {
    return (
      <form onSubmit={(e) => this.handleSubmit(e)}>

              Name
              <input type="text" value={this.state.name} name="name" id="name" onChange={this.handleChange('name')}/>

              OID
              <input type="text" value={this.state.oid} name="oid" id="oid" onChange={this.handleChange('oid')}/>

              Coded
              <input type="checkbox" value={this.state.coded} name="coded" id="coded" onChange={this.handleChange('coded')}/>

              Description
              <textarea value={this.state.description} name="description" id="description" onChange={this.handleChange('description')}/>

          <CodedSetTableForm itemWatcher={(r) => this.handleResponsesChange(r)}
                             initialItems={this.state.responsesAttributes}
                             parentName={'response_set'}
                             childName={'response'} />

            <input type="submit" value={`${this.props.action} Response Set`}/>

      </form>
    );
  }

  handleSubmit(event) {
    event.preventDefault();
    this.props.responseSetSubmitter(this.state, (response) => {
      // TODO: Handle when the saving response set fails.
      if (response.status === 201) {
        this.props.router.push(`/responseSets/${response.data.id}`);
      }
    });
  }

  handleResponsesChange(newResponses) {
    this.setState({responsesAttributes: newResponses});
  }

  handleChange(field) {
    return (event) => {
      let newState = {};
      newState[field] = event.target.value;
      this.setState(newState);
    };
  }
}

function filterResponses(responses) {
  return responses.map((nr) => {
    return {value: nr.value, codeSystem: nr.codeSystem, displayName: nr.displayName};
  });
}

ResponseSetForm.propTypes = {
  responseSet: responseSetProps.isRequired,
  responseSetSubmitter: PropTypes.func.isRequired,
  action: PropTypes.string.isRequired,
  router: PropTypes.object.isRequired
};
<|endoftext|>


<commit_before>(function() {
  var root = this,
      Backbone = root.Backbone,
      Thorax = root.Thorax,
      _start = Backbone.History.prototype.start;

  Backbone.History.prototype.start = function() {
    //if this is a lumbar app, setup the module loader
    this.initBackboneLoader && this.initBackboneLoader();
    return _start.apply(this, arguments);
  };

  Thorax.addModuleMethods = function(module) {
    module.router = function(protoProps) {
      var router = Thorax.router(module.name, null, true);
      if (arguments.length === 0) {
        return router;
      }
      if (!router) {
        if (protoProps.prototype) {
          protoProps.prototype.name = module.name;
          protoProps.prototype.routes = module.routes;
          protoProps = new protoProps;
        } else {
          protoProps.name = module.name;
          protoProps.routes = module.routes;
        }
        return new Thorax.router(module.name, protoProps);
      } else {
        _.extend(router, protoProps);
        return router;
      }
    };
  };

})();<commit_msg>fixes for thorax/lumbar integration<commit_after>(function() {
  var root = this,
      Backbone = root.Backbone,
      Thorax = root.Thorax,
      _start = Backbone.History.prototype.start;

  Backbone.History.prototype.start = function() {
    //if this is a lumbar app, setup the module loader
    //this file must be included in the base module
    module.exports && module.exports.initBackboneLoader && module.exports.initBackboneLoader();
    return _start.apply(this, arguments);
  };

  Thorax.addModuleMethods = function(module) {
    var router;
    module.router = function(protoProps) {
      if (router || arguments.length === 0) {
        return router;
      }
      if (!router) {
        if (protoProps.prototype) {
          protoProps.prototype.name = module.name;
          protoProps.prototype.routes = module.routes;
          protoProps = new protoProps;
        } else {
          protoProps.name = module.name;
          protoProps.routes = module.routes;
        }
        return router = new (Thorax.router(module.name, protoProps));
      }
    };
  };

})();<|endoftext|>