<commit_before>import Stats from 'util/stats.min'
import { queue,EventEmitter } from 'util/_'

//资源加载
class Loader {
    constructor(arr) {
        this._images = {};
        this.task = [];
    }
    //加载图片
    load(arr,callback) {
        let self = this;
        for(let i = 0;i<arr.length;i++) {
            if( i == arr.length - 1 ){
                self.task.push(function(){
                    self._images[arr[i]] = new Image();
                    self._images[arr[i]].onload = function(){
                        callback();
                        return
                    }
                    self._images[arr[i]].src = arr[i];
                })
            } else {
                self.task.push(function(cb){
                    self._images[arr[i]] = new Image();
                    self._images[arr[i]].onload = function(){
                        cb();
                    }
                    self._images[arr[i]].src = arr[i];
                })
            }
        }

        return queue(self.task,this)
    }
    //获取图片
    pick(src) {
        if ( typeof this._images[src] != 'undefined' ){
            return  this._images[src];
        } else {
            throw new Error('请传入图片对象')
        }
    }
}

//舞台
class Stage extends EventEmitter {
    constructor(options) {
        super();
        this.dpr = window.devicePixelRatio || 1;
        //资源列表
        this.assets = options.list || null;
        //dom节点
        this.el = options.el;
        this.context = options.el.getContext('2d');
        //精灵字典
        this.sprites = [];
        //世界地图
        this.map = options.map || null;

        this.init();
    }
    init () {
        //event测试
        //this.on((content) => console.log(`get published content: ${content}`), 'Event test')

        //canvas外层容器宽高 利用css响应布局
        this._width = this.el.parentNode.clientWidth;
        this._height = this.el.parentNode.clientHeight;
        //真实宽高
        this.width = this.dpr * this._width;
        this.height = this.dpr * this._height;
        //初始化canvas元素
        this.el.style.width = `${this._width}px`;
        this.el.style.height = `${this._height}px`;
        this.el.width = ~~ this.width;
        this.el.height = ~~ this.height;
        //初始化loader
        this.im = new Loader(this.assets);

        //加载资源
        this.load();
    }
    dp (px) {
        return ~~ px * this.dpr
    }
    load () {
        //判断是否需要加载资源
        if( this.assets ){

            //加载周期
            this.on(()=>{this.update()},'load');
            //加载回调
            this.im.load(this.assets,()=>{this.emit(console.log('load success'),'load')});

            let loadTxt = 'Loading..';
            let textWidth = ~~ this.context.measureText(loadTxt).width * this.dpr;
            let textHeight =  15*this.dpr;

            let rx = ~~ ( this._width - textWidth ) / 2;
            let ry = ~~ ( this._height - textHeight ) / 2;

            let loadPx = 14;
            this.textAlign="center";
            //this.context.font = `400 ${loadPx*this.dpr}px 微软雅黑,Sans-Serif`;
            this.context.font = `normal small-caps 400 ${loadPx*this.dpr}px 'Lato', sans-serif`;

            this.context.fillStyle = '#ccc';

            this.context.fillText(loadTxt,rx*this.dpr,ry*this.dpr);

        } else {
            this.update();
        }

    }
    clear(x = 0, y = 0,width = this.width , height = this.height) {
        this.context.clearRect(x, y, width, height);
    }
    //主loop
    update(type,obj,x,y,rx,ry) {
        //event测试
        //this.emit('pub', 'Event test');

        this.clear();
        //todo MAP
        let t = this.im.pick('../assets/ji.jpg')
        this.context.drawImage(t,0,0,t.width,t.height);
    }
    //收集并重写精灵的行为
    draw() {
        //update type:text,filltext;image,drawImage 封装常用方法 保留坐标到this.store
    }
    //map
    //添加精灵元素
    addSprite (name,sprite) {
        this.sprites[name]=sprite;
    }
    //移除精灵元素
    removeSprite (name) {
        if ( this.sprites[name] ){
            delete this.sprites[name];
        }
    }
}

//精灵类
class Sprite {
    constructor (){

    }
}

const stats = new Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.right = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild( stats.domElement );
//stats.update()

window.onload = function(){
    new Stage({
        el:document.querySelector('#stage'),
        list:['../assets/ji.jpg']
    },function(){
        console.log('su!!')
    });
}

window.addEventListener('resize', () => {
    // s.init();
    // s.load(true);
});

if (module.hot) module.hot.accept();
<commit_msg>update<commit_after>import Stats from 'util/stats.min'
import { queue,EventEmitter } from 'util/_'

//资源加载
class Loader {
    constructor(arr) {
        this._images = {};
        this.task = [];
    }
    //加载图片
    load(arr,callback) {
        let self = this;
        for(let i = 0;i<arr.length;i++) {
            if( i == arr.length - 1 ){
                self.task.push(function(){
                    self._images[arr[i]] = new Image();
                    self._images[arr[i]].onload = function(){
                        callback();
                        return
                    }
                    self._images[arr[i]].src = arr[i];
                })
            } else {
                self.task.push(function(cb){
                    self._images[arr[i]] = new Image();
                    self._images[arr[i]].onload = function(){
                        cb();
                    }
                    self._images[arr[i]].src = arr[i];
                })
            }
        }

        return queue(self.task,this)
    }
    //获取图片
    pick(src) {
        if ( typeof this._images[src] != 'undefined' ){
            return  this._images[src];
        } else {
            throw new Error('请传入图片对象')
        }
    }
}

//舞台
class Stage extends EventEmitter {
    constructor(options) {
        super();
        this.dpr = window.devicePixelRatio || 1;
        //资源列表
        this.assets = options.list || null;
        //dom节点
        this.el = options.el;
        this.context = options.el.getContext('2d');
        //精灵字典
        this.sprites = [];
        //世界地图
        this.map = options.map || null;

        this.init();
    }
    init () {
        //event测试
        this.on((content) => console.log(`get published content: ${content}`), 'Event test')

        //canvas外层容器宽高 利用css响应布局
        this._width = this.el.parentNode.clientWidth;
        this._height = this.el.parentNode.clientHeight;
        //真实宽高
        this.width = this.dpr * this._width;
        this.height = this.dpr * this._height;
        //初始化canvas元素
        this.el.style.width = `${this._width}px`;
        this.el.style.height = `${this._height}px`;
        this.el.width = ~~ this.width;
        this.el.height = ~~ this.height;
        //初始化loader
        this.im = new Loader(this.assets);

        //加载资源
        this.load();
    }
    dp (px) {
        return ~~ px * this.dpr
    }
    load () {
        //判断是否需要加载资源
        if( this.assets ){

            //加载周期
            this.on(()=>{this.update()},'load');
            //加载回调
            this.im.load(this.assets,()=>{this.emit(console.log('load success'),'load')});

            let loadTxt = 'Loading..';
            let textWidth = ~~ this.context.measureText(loadTxt).width * this.dpr;
            let textHeight =  15*this.dpr;

            let rx = ~~ ( this._width - textWidth ) / 2;
            let ry = ~~ ( this._height - textHeight ) / 2;

            let loadPx = 14;
            this.textAlign="center";
            //this.context.font = `400 ${loadPx*this.dpr}px 微软雅黑,Sans-Serif`;
            this.context.font = `normal small-caps 400 ${loadPx*this.dpr}px 'Lato', sans-serif`;

            this.context.fillStyle = '#ccc';

            this.context.fillText(loadTxt,rx*this.dpr,ry*this.dpr);

        } else {
            this.update();
        }

    }
    clear(x = 0, y = 0,width = this.width , height = this.height) {
        this.context.clearRect(x, y, width, height);
    }
    //sprite behaviors
    update(type,obj,x,y,rx,ry) {
        //event测试
        this.emit('pub', 'Event test');

        this.clear();
        //todo MAP

        this.draw()

    }
    //sprite paint
    draw() {
        let t = this.im.pick('../assets/ji.jpg')
        this.context.drawImage(t,0,0,t.width,t.height);
    }
    //map
    //添加精灵元素
    addSprite (name,sprite) {
        this.sprites[name]=sprite;
    }
    //移除精灵元素
    removeSprite (name) {
        if ( this.sprites[name] ){
            delete this.sprites[name];
        }
    }
}

//精灵类
class Sprite {
    constructor(name, painter, behaviors){

    }
    update() {}
    draw() {}
}

const stats = new Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.right = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild( stats.domElement );
//stats.update()

window.onload = function(){
    new Stage({
        el:document.querySelector('#stage'),
        list:['../assets/ji.jpg']
    },function(){
        console.log('su!!')
    });
}

window.addEventListener('resize', () => {
    // s.init();
    // s.load(true);
});

if (module.hot) module.hot.accept();<|endoftext|>


<commit_before>/**
 * @file String helpers
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_EVENT_DATA*/ // gpf.events.EVENT_DATA
/*global _GPF_EVENT_END_OF_DATA*/ // gpf.events.EVENT_END_OF_DATA
/*global _GPF_EVENT_READY*/ // gpf.events.EVENT_READY
/*global _gpfAssert*/ // Assertion method
/*global _gpfDefine*/ // Shortcut for gpf.define
/*global _gpfEventsFire*/ // gpf.events.fire (internal, parameters must match)
/*global _gpfI*/ // gpf.interfaces
/*global _gpfStreamPipe*/ // gpf.stream.pipe
/*global _gpfStringCapitalize*/ // Capitalize the string
/*global _gpfStringEscapeFor*/ // Make the string content compatible with lang
/*global _gpfStringReplaceEx*/ // String replacement using dictionary map
/*exported _gpfStringStream*/ // IReadableStream & IWritableStream for string
/*#endif*/

//region String Array helpers

/**
 * Count how many strings must be concatenated to fit the requested size.
 * If the last string has too many characters, it is ignored and remaining will tell how many characters are left.
 *
 * @param {String[]} strings String array
 * @param {Number} size Number of characters to compute
 * @returns {Object} containing
 * - {Number} count Number of parts to get to fit the size
 * - {Number} remaining Number of characters not fitting
 */
function _gpfStringArrayCountToFit (strings, size) {
    var count = 0;
    strings.every(function (string) {
        var length = string.length;
        if (length <= size) {
            ++count;
            size -= length;
            return true;
        }
        return false;
    });
    return {
        count: count,
        remaining: size
    };
}

function _gpfStringsSafeSplice (strings, itemsCount) {
    if (0 < itemsCount) {
        return strings.splice(0, itemsCount);
    }
    return [];
}

/**
 * Splice the string array on the number of items and, if specified, takes characters on the next item.
 * Returns the concatenated string
 *
 * @param {String[]} strings String array
 * @param {Number} itemsCount Number of it
 * @param {Number} characterCount
 * @return {String}
 */
function _gpfStringArraySplice (strings, itemsCount, characterCount) {
    var result,
        string;
    _gpfAssert(itemsCount <= strings.length, "itemsCount within strings range");
    result = _gpfStringsSafeSplice(strings, itemsCount);
    if (strings.length && characterCount) {
        // Last item has to be cut, remove first item
        string = strings.shift();
        // Add the missing characters
        result.push(string.substr(0, characterCount));
        // Put back the remaining characters
        strings.unshift(string.substr(characterCount));
    }
    return result.join("");
}

/**
 * Extract the first characters of a string array
 *
 * @param {Strings[]} strings This array is modified after extraction
 * @param {Number} size Number of characters to get
 * @return {String}
 */
function _gpfStringArrayExtract (strings, size) {
    var parts = _gpfStringArrayCountToFit(strings, size);
    return _gpfStringArraySplice(strings, parts.count, parts.remaining);
}

//endregion

var
    /**
     * Implements IReadableStream & IWritableStream on top of a string (FIFO read / write)
     *
     * @class StringStream
     * @extends Object
     * @implements gpf.interfaces.IReadableStream, gpf.interfaces.IWritableStream
     */
    _GpfStringStream = _gpfDefine("StringStream", {
        "[Class]": [gpf.$InterfaceImplement(_gpfI.IReadableStream), gpf.$InterfaceImplement(_gpfI.IWritableStream)],
        "+": {

            // @param {String} [string=undefined] string
            constructor: function (string) {
                if ("string" === typeof string) {
                    this._buffer = [string];
                } else {
                    this._buffer = [];
                }
            },

            //region gpf.interfaces.IReadableStream

            // @inheritdoc gpf.interfaces.IReadableStream#read
            read: function (count, eventsHandler) {
                var result;
                if (0 === this._buffer.length) {
                    _gpfEventsFire.call(this, _GPF_EVENT_END_OF_DATA, {}, eventsHandler);
                } else {
                    result = _gpfStringArrayExtract(this._buffer, count);
                    _gpfEventsFire.call(this, _GPF_EVENT_DATA, {buffer: result}, eventsHandler);
                }
            },

            //endregion

            //region gpf.interfaces.IReadableStream

            // @inheritdoc gpf.interfaces.IWritableStream#read
            write: function (buffer, eventsHandler) {
                _gpfAssert("string" === typeof buffer && buffer.length, "String buffer must contain data");
                this._buffer.push(buffer);
                _gpfEventsFire.call(this, _GPF_EVENT_READY, {}, eventsHandler);
            },

            //endregion

            /**
             * Consolidate the result string
             * @return {String}
             */
            toString: function () {
                return this._buffer.join("");
            }

        },
        "-": {

            // @property {String[]} buffer
            _buffer: []

        }
    });

Object.assign(gpf, {

    /** sameas _gpfStringCapitalize */
    capitalize: _gpfStringCapitalize,

    /** sameas _gpfStringReplaceEx */
    replaceEx: _gpfStringReplaceEx,

    /** sameas _gpfStringEscapeFor */
    escapeFor: _gpfStringEscapeFor,

    /**
     * Extract the first characters of a string array
     *
     * @param {Strings[]} strings This array is modified after extraction
     * @param {Number} [size=0] size Number of characters to get, all if 0
     * @return {String}
     */
    stringExtractFromStringArray: _gpfStringArrayExtract,

    /**
     * Converts the string into a stream
     *
     * @param {String} that String to convert
     * @return {Object} Implementing gpf.interfaces.IReadableStream & gpf.interfaces.IWritableStream
     */
    stringToStream: function (that) {
        return new _GpfStringStream(that);
    },

    /**
     * Converts the stream into a string
     *
     * @param {gpf.interfaces.IReadableStream} stream
     * @param {gpf.events.Handler} eventsHandler
     *
     * @event gpf.events.EVENT_READY
     * finished reading the stream, the buffer is provided
     *
     * @eventParam {String} buffer
     */
    stringFromStream: function (stream, eventsHandler) {
        if (stream instanceof _GpfStringStream) {
            _gpfEventsFire(_GPF_EVENT_READY, {buffer: stream.toString()}, eventsHandler);
        } else {
            var stringStream = new _GpfStringStream();
            _gpfStreamPipe({
                readable: stream,
                writable: stringStream
            }, function (event) {
                if (_GPF_EVENT_READY === event.type) {
                    _gpfEventsFire(_GPF_EVENT_READY, {buffer: stringStream.toString()}, eventsHandler);
                } else {
                    _gpfEventsFire(event, {}, eventsHandler);
                }
            });
        }
    }

});

/*#ifndef(UMD)*/

gpf.internals._gpfStringArrayCountToFit = _gpfStringArrayCountToFit;
gpf.internals._gpfStringArraySplice = _gpfStringArraySplice;
gpf.internals._gpfStringArrayExtract = _gpfStringArrayExtract;

/*#endif*/
<commit_msg>Removes useless stuff<commit_after>/**
 * @file String helpers
 */
/*#ifndef(UMD)*/
"use strict";
/*global _gpfStringCapitalize*/ // Capitalize the string
/*global _gpfStringEscapeFor*/ // Make the string content compatible with lang
/*global _gpfStringReplaceEx*/ // String replacement using dictionary map
/*#endif*/

//region String Array helpers

Object.assign(gpf, {

    /** sameas _gpfStringCapitalize */
    capitalize: _gpfStringCapitalize,

    /** sameas _gpfStringReplaceEx */
    replaceEx: _gpfStringReplaceEx,

    /** sameas _gpfStringEscapeFor */
    escapeFor: _gpfStringEscapeFor

});
<|endoftext|>


<commit_before>import { dispatch as d3_dispatch } from 'd3-dispatch';

import _filter from 'lodash-es/filter';
import _uniqWith from 'lodash-es/uniqWith';

import { utilRebind } from '../util/rebind';

export function IssueManager(context) {
    var dispatch = d3_dispatch('reload'),
        self = {},
        issues = [],
        issuesByEntityId = {};

    self.featureApplicabilityOptions = ['edited', 'all'];

    var featureApplicability = context.storage('issue-features') || 'edited';

    self.getFeatureApplicability = function() {
        return featureApplicability;
    };

    self.setFeatureApplicability = function(applicability) {
        featureApplicability = applicability;
        context.storage('issue-features', applicability);
    };

    self.getIssues = function() {
        return issues;
    };

    self.getIssuesForEntityWithID = function(entityID) {
        if (!context.hasEntity(entityID)) {
            return [];
        }
        if (!issuesByEntityId[entityID]) {
            var entity = context.entity(entityID);
            issuesByEntityId[entityID] = context.history().validate([entity]);
        }
        return issuesByEntityId[entityID];
    };

    self.validate = function() {
        var changes = context.history().changes();
        var entitiesToCheck = changes.created.concat(changes.modified);
        issuesByEntityId = {};
        issues = [];
        for (var entityIndex in entitiesToCheck) {
            var entity = entitiesToCheck[entityIndex];
            var entityIssues = context.history().validate([entity]);
            issuesByEntityId[entity.id] = entityIssues;
            issues = issues.concat(entityIssues);
        }
        issues = _uniqWith(issues, function(issue1, issue2) {
            return issue1.id() === issue2.id();
        });
        dispatch.call('reload', self, issues);
    };

    return utilRebind(self, dispatch, 'on');
}
<commit_msg>Validate paths for edited nodes and relations for edited geometry<commit_after>import { dispatch as d3_dispatch } from 'd3-dispatch';

import _map from 'lodash-es/map';
import _flattenDeep from 'lodash-es/flattenDeep';
import _uniq from 'lodash-es/uniq';
import _uniqWith from 'lodash-es/uniqWith';

import { utilRebind } from '../util/rebind';

export function IssueManager(context) {
    var dispatch = d3_dispatch('reload'),
        self = {},
        issues = [],
        issuesByEntityId = {};

    self.featureApplicabilityOptions = ['edited', 'all'];

    var featureApplicability = context.storage('issue-features') || 'edited';

    self.getFeatureApplicability = function() {
        return featureApplicability;
    };

    self.setFeatureApplicability = function(applicability) {
        featureApplicability = applicability;
        context.storage('issue-features', applicability);
    };

    self.getIssues = function() {
        return issues;
    };

    self.getIssuesForEntityWithID = function(entityID) {
        if (!context.hasEntity(entityID)) {
            return [];
        }
        if (!issuesByEntityId[entityID]) {
            var entity = context.entity(entityID);
            issuesByEntityId[entityID] = context.history().validate([entity]);
        }
        return issuesByEntityId[entityID];
    };

    self.validate = function() {
        // clear cached issues
        issuesByEntityId = {};
        issues = [];

        var changes = context.history().changes();
        var entitiesToCheck = changes.created.concat(changes.modified);
        entitiesToCheck = _uniq(_flattenDeep(_map(entitiesToCheck, function(entity) {
            var entities = [entity];
            if (entity.type === 'node') {
                // validate ways if their nodes have changed
                entities = entities.concat(context.graph().parentWays(entity));
            }
            entities = _map(entities, function(entity) {
                if (entity.type !== 'relation') {
                    // validate relations if their geometries have changed
                    return [entity].concat(context.graph().parentRelations(entity));
                }
                return entity;
            });
            return entities;
        })));

        for (var entityIndex in entitiesToCheck) {
            var entity = entitiesToCheck[entityIndex];
            var entityIssues = context.history().validate([entity]);
            issuesByEntityId[entity.id] = entityIssues;
            issues = issues.concat(entityIssues);
        }
        issues = _uniqWith(issues, function(issue1, issue2) {
            return issue1.id() === issue2.id();
        });
        dispatch.call('reload', self, issues);
    };

    return utilRebind(self, dispatch, 'on');
}
<|endoftext|>


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

'use strict';

// Necessary libs
var request = require('request');
var assert  = require('assert');
var _       = require('underscore');

// Global
var gds;

// Init
module.exports = exports = gds = function init(config) {

  // Validate config
  assert.equal(typeof config, 'object',
    'You must specify the endpoint url when invoking this module');
  assert.ok(/^https?:/.test(config.url), 'url is not valid');

  // Handle URL Requests
  function apiCall(opts, callback) {
    if (!opts) var opts = {}

    // Debug
    opts.debug = (config.debug) ? config.debug : ((!opts.debug) ? false : opts.debug);

    // Force the URL
    opts.url = config.url + opts.url;

    // Auth
    opts.auth = {
      user: config.username,
      pass: config.password
    }

    // Debug Opts
    if (opts.debug) console.log(opts);

    return request(opts, function(error, response, body) {
      var returnObject = {
        error: error,
        response: response,
        body: body
      };

      if (opts.debug) console.log(returnObject);

      if (!callback) {
        return returnObject;
      }

      return callback(error, response, body)
    })
  }

  /*
  Vertices
   */

  // Create Vertice
  function createVertices(keyPairs, callback) {
    var opts = {
      url: '/vertices',
      method: 'POST'
    }
    return apiCall(opts, callback);
  }

  // List Vertices
  function listVertices(callback) {
    var opts = {
      url: '/vertices',
      method: 'GET'
    };
    return apiCall(opts, callback);
  }

  // Vertex by ID
  function vertexById(id, callback) {
    var opts = {
      url: '/vertices/' + id,
      method: 'GET'
    }
    return apiCall(opts, callback);
  }

  // Vertex by properties
  function vertexByProperties(properties, callback) {
    var opts = {
      url: '/vertices',
      method: 'GET',
      qs: properties
    }
    return apiCall(opts, callback);
  }

  var vertices = {
    create: createVertices,
    list: listVertices,
    get: vertexById,
    properties: vertexByProperties
  };

  /*
  Edges
   */

   // List Edges
   function listEdges(callback) {
     var opts = {
       url: '/edges',
       method: 'GET',
     };
     return apiCall(opts, callback);
   }

   // Edge by ID
   function edgeById(id, callback) {
     var opts = {
       url: '/edges/' + id,
       method: 'GET'
     }
     return apiCall(opts, callback);
   }

   var edges = {
     list: listEdges,
     get: edgeById,
   };

   /*
   Gremlin
    */

  // Gremlin Endpoint
  function gremlinQuery(traversal, callback) {
    var opts = {
      url: '/gremlin',
      method: 'POST',
      // @TODO: reimplement later
      // json: true,
      body: '{"gremlin": ""}',
      headers: {
        'Content-Type': 'application/json'
      }
    }

    // If traveral is string
    if (_.isArray(traversal)) {
      // Check first element is g
      if (traversal[0] != 'g') {
        traversal.unshift('g');
      }

      opts.body = JSON.stringify({gremlin:traversal.join('.')});
    }
    else {
      opts.body = JSON.stringify({gremlin:traversal});
    }

    return apiCall(opts, callback);
  }

  var gremlin = gremlinQuery;

  /*
  Input/Output
   */

  // Bulk Upload - GraphML
  function uploadGraphMl(graphml, callback) {

    if (typeof graphml != 'string' && !callback) var callback = graphml;

    var opts = {
      url: '/bulkload/graphml',
      method: 'POST',
      form: {graphml: graphml}
    }
    return apiCall(opts, callback);
  }

  //  Buld Upload - graphson
  function uploadGraphSON(graphson, callback) {

    if (typeof graphson != 'string' && !callback) var callback = graphson;

    var opts = {
      url: '/bulkload/graphson',
      method: 'POST',
      form: {graphson: graphson}
    }
    return apiCall(opts, callback);
  }

  // Extract
  function extractBulk(format, callback) {

    if (!callback) var callback = format;
    if (!format) var format = 'json';

    var opts = {
      url: '/extract',
      method: 'GET',
      headers: {
        'Content-Type': 'application/' + format
      }
    }

    return apiCall(opts, callback);
  }

  var io = {
    bulkload: {
      graphml: uploadGraphMl,
      graphson: uploadGraphSON
    },
    extract: extractBulk
  }

  // Return object
  return {
    vertices: vertices,
    edges: edges,
    gremlin: gremlin,
    io: io,
  }
}
<commit_msg>Change how the creates work<commit_after>// Licensed under the Apache License, Version 2.0 (the 'License'); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

'use strict';

// Necessary libs
var request = require('request');
var assert  = require('assert');
var _       = require('underscore');

// Global
var gds;

// Init
module.exports = exports = gds = function init(config) {

  // Validate config
  assert.equal(typeof config, 'object',
    'You must specify the endpoint url when invoking this module');
  assert.ok(/^https?:/.test(config.url), 'url is not valid');

  // Handle URL Requests
  function apiCall(opts, callback) {
    if (!opts) var opts = {}

    // Debug
    opts.debug = (config.debug) ? config.debug : ((!opts.debug) ? false : opts.debug);

    // Force the URL
    opts.url = config.url + opts.url;

    // Auth
    opts.auth = {
      user: config.username,
      pass: config.password
    }

    // Debug Opts
    if (opts.debug) console.log(opts);

    return request(opts, function(error, response, body) {
      var returnObject = {
        error: error,
        response: response,
        body: body
      };

      if (opts.debug) console.log(returnObject);

      if (!callback) {
        return returnObject;
      }

      return callback(error, response, body)
    })
  }

  /*
  Vertices
   */

  // Create Vertice
  function createVertices(keyPairs, callback) {
    var opts = {
      url: '/vertices',
      method: 'POST'
    }
    if (typeof callback == 'undefined') {
      callback = keyPairs;
    } else {
      opts.json = true;
      opts.body = keyPairs;
    }
    return apiCall(opts, callback);
  }

  // List Vertices
  function listVertices(callback) {
    var opts = {
      url: '/vertices',
      method: 'GET'
    };
    return apiCall(opts, callback);
  }

  // Vertex by ID
  function vertexById(id, callback) {
    var opts = {
      url: '/vertices/' + id,
      method: 'GET'
    }
    return apiCall(opts, callback);
  }

  // Vertex by properties
  function vertexByProperties(properties, callback) {
    var opts = {
      url: '/vertices',
      method: 'GET',
      qs: properties
    }
    return apiCall(opts, callback);
  }

  var vertices = {
    create: createVertices,
    list: listVertices,
    get: vertexById,
    properties: vertexByProperties
  };

  /*
  Edges
   */

  // Create Edge
  function createEdge(label, outV, inV, callback) {
    var opts = {
      url: '/edges',
      method: 'POST',
      json: true,
      body: {
        label: label,
        outV: outV,
        inV: inV,
      },
    };
    return apiCall(opts, callback);
  }

   // List Edges
   function listEdges(callback) {
     var opts = {
       url: '/edges',
       method: 'GET',
     };
     return apiCall(opts, callback);
   }

   // Edge by ID
   function edgeById(id, callback) {
     var opts = {
       url: '/edges/' + id,
       method: 'GET'
     }
     return apiCall(opts, callback);
   }

   var edges = {
     create: createEdge,
     list: listEdges,
     get: edgeById,
   };

   /*
   Gremlin
    */

  // Gremlin Endpoint
  function gremlinQuery(traversal, callback) {
    var opts = {
      url: '/gremlin',
      method: 'POST',
      // @TODO: reimplement later
      // json: true,
      body: '{"gremlin": ""}',
      headers: {
        'Content-Type': 'application/json'
      }
    }

    // If traveral is string
    if (_.isArray(traversal)) {
      // Check first element is g
      if (traversal[0] != 'g') {
        traversal.unshift('g');
      }

      opts.body = JSON.stringify({gremlin:traversal.join('.')});
    }
    else {
      opts.body = JSON.stringify({gremlin:traversal});
    }

    return apiCall(opts, callback);
  }

  var gremlin = gremlinQuery;

  /*
  Input/Output
   */

  // Bulk Upload - GraphML
  function uploadGraphMl(graphml, callback) {

    if (typeof graphml != 'string' && !callback) var callback = graphml;

    var opts = {
      url: '/bulkload/graphml',
      method: 'POST',
      form: {graphml: graphml}
    }
    return apiCall(opts, callback);
  }

  //  Buld Upload - graphson
  function uploadGraphSON(graphson, callback) {

    if (typeof graphson != 'string' && !callback) var callback = graphson;

    var opts = {
      url: '/bulkload/graphson',
      method: 'POST',
      form: {graphson: graphson}
    }
    return apiCall(opts, callback);
  }

  // Extract
  function extractBulk(format, callback) {

    if (!callback) var callback = format;
    if (!format) var format = 'json';

    var opts = {
      url: '/extract',
      method: 'GET',
      headers: {
        'Content-Type': 'application/' + format
      }
    }

    return apiCall(opts, callback);
  }

  var io = {
    bulkload: {
      graphml: uploadGraphMl,
      graphson: uploadGraphSON
    },
    extract: extractBulk
  }

  // Return object
  return {
    vertices: vertices,
    edges: edges,
    gremlin: gremlin,
    io: io,
  }
}
<|endoftext|>


<commit_before>var handlebars = require('handlebars');

var compile = function (str, options) {
  if (typeof str !== 'string') {
    return str;
  }

  var template = handlebars.compile(str);
  return function (locals) {
    return template(locals, {
      helpers: locals.blockHelpers,
      partials: null,
      data: null
    });
  };
};

// Express view template engine compliance

exports.compile = compile;

// Expose Handlebars and useful methods

exports.handlebars = handlebars;

exports.registerHelper = function () {
  handlebars.registerHelper.apply(handlebars, arguments);
};

exports.registerPartial = function () {
  handlebars.registerPartial.apply(handlebars, arguments);
};
<commit_msg>expose SafeString and Utils.<commit_after>var handlebars = require('handlebars');

var compile = function (str, options) {
  if (typeof str !== 'string') {
    return str;
  }

  var template = handlebars.compile(str);
  return function (locals) {
    return template(locals, {
      helpers: locals.blockHelpers,
      partials: null,
      data: null
    });
  };
};

// Express view template engine compliance

exports.compile = compile;

// Expose Handlebars and useful methods

exports.handlebars = handlebars;

exports.registerHelper = function () {
  handlebars.registerHelper.apply(handlebars, arguments);
};

exports.registerPartial = function () {
  handlebars.registerPartial.apply(handlebars, arguments);
};

exports.SafeString = handlebars.SafeString;
exports.Utils = handlebars.Utils;
<|endoftext|>


<commit_before>var net          = require('net');
var util         = require('util');
var EventEmitter = require('events').EventEmitter;
var Queue        = require('fastqueue');

var GET_SOCKET_PATH_CMD = 'i3 --get-socketpath';
var I3_MAGIC     = new Buffer('i3-ipc');
var I3_MESSAGE_HEADER_LENGTH = I3_MAGIC.length + 8;

function createStream(opts, callback) {
  var stream;
  if (opts && opts.stream)
    return callback(null, stream);
  if (opts && (opts.path || opts.host || opts.port)) {
    if (opts.path)
      stream = net.connect(opts.path);
    else
      stream = net.connect(opts.port, opts.host);
    var connected = false;
    stream.on('connect', function() {
      connected = true;
      callback(null, stream);
    });
    stream.once('error', function(err) {
      if (!connected) // otherwise handle in client
        callback(err);
    });
  } else {
    require('child_process').exec(GET_SOCKET_PATH_CMD, function(err, path) {
      path = path.replace('\n', '');
      if (err)
        return callback(err);
      createStream({path: path}, callback);
    });
  }
}

function I3Message(buff) {
  this.magic   = buff.slice(0, I3_MAGIC.length); // TODO assert magic is correct
  this.payloadLength = buff.readUInt32LE(I3_MAGIC.length);
  this.code    = buff.readUInt16LE(I3_MAGIC.length + 4); // TODO UInt31 here?
  this.payload = null;
  this.isEvent = (buff.readUInt8(I3_MAGIC.length + 7) & 0x80) == 0x80;
}

function encodeCommand(code, payload) {
  if (!payload)
    payload = '';
  var payloadOffset = I3_MAGIC.length + 8;
  var buf = new Buffer(payloadOffset + payload.length);
  I3_MAGIC.copy(buf);
  buf.writeUInt32LE(payload.length, 6);
  buf.writeUInt32LE(code, 10);
  buf.write(payload, payloadOffset);
  return buf;
}

function I3IpcClient(opts) {
  EventEmitter.call(this);
  var self = this;
  self._stream = null;
  self._commands = new Queue();
  self._handlers = new Queue();
  createStream(opts, function(err, stream) {

    if (err)
       return self.emit('error', err);

    self.emit('connect', self);
    self._stream = stream;
    self._pump(); // send queued commands
    self._waitHeader = true;

    self._stream.on('readable', function() {
      while(1) {
        if (self._waitHeader) {
          var header = self._stream.read(I3_MESSAGE_HEADER_LENGTH);
          if (header) {
            self._message = new I3Message(header);
            if (self._message.payloadLength == 0) {
              self._handleMessage();
            } else {
              self._waitHeader = false;
            }
          } else break;
        } else {
          var data = self._stream.read(self._message.payloadLength);
          if (data) {
            self._message.payload = data;
            self._handleMessage();
            self._waitHeader = true;
          } else break;
        }
      }
    });
  });
};

util.inherits(I3IpcClient, EventEmitter);

I3IpcClient.prototype._pump = function() {
  if (!this._stream) return;

  var command;
  while(command = this._commands.shift()) {
    this._stream.write(command.encoded);
    command.callback.encoded = command.encoded;
    this._handlers.push(command.callback);
  }
};

var noop = function() {};

I3IpcClient.prototype.message = function(cmd, payload, callback) {
  this._commands.push({
    encoded: encodeCommand(cmd, payload),
    callback: callback ? callback : noop
  });
  this._pump();
}

var commandNameFromCode = "COMMAND GET_WORKSPACES SUBSCRIBE GET_OUTPUTS GET_TREE GET_MARKS GET_BAR_CONFIG GET_VERSION".split(' ');
var commandCodeFromName = {};
commandNameFromCode.forEach(function(name, code) { commandCodeFromName[name] = code; });

var eventNameFromCode = "workspace output mode window barconfig_update".split(' ');
var eventCodeFromName = {};
eventNameFromCode.forEach(function(name, code) { eventCodeFromName[name] = code; });

I3IpcClient.prototype._handleMessage = function() {
  var message = this._message;

  var payload;
  try {
    payload = JSON.parse(message.payload.toString());
  } catch(e) {
    payload = e;
  }

  if (message.isEvent) {
     eventName = eventNameFromCode[message.code];
     // TODO: check if code is known
     if (payload instanceof Error)
       return this.emit('error', payload)
     this.emit(eventName, payload);
  } else {
     var handler = this._handlers.shift();
     if (!handler) {
       var error = new Error('Unknown reply');
       error.i3Message = message;
       this.emit('error', error);
     } else {
       if (payload instanceof Error)
         return handler(payload)
       handler(null, payload);
     }
     if (this._handlers.length == 0) {
       this.emit('drain');
     }
  }
};

var baseOn = I3IpcClient.prototype.on;
I3IpcClient.prototype.on = function(event, handler) {
  var self = this;
  var i3EventCode = eventCodeFromName[event];
  if (typeof i3EventCode !== "undefined") {
    this.message(commandCodeFromName.SUBSCRIBE, JSON.stringify([event]), function(err, resp) {
      baseOn.call(self, event, handler);
    });
  } else {
    baseOn.call(this, event, handler);
  }
}

module.exports.I3IpcClient = I3IpcClient;
module.exports.Commads = commandCodeFromName;
module.exports.Events  = eventCodeFromName;
<commit_msg>add the "binding" event<commit_after>var net          = require('net');
var util         = require('util');
var EventEmitter = require('events').EventEmitter;
var Queue        = require('fastqueue');

var GET_SOCKET_PATH_CMD = 'i3 --get-socketpath';
var I3_MAGIC     = new Buffer('i3-ipc');
var I3_MESSAGE_HEADER_LENGTH = I3_MAGIC.length + 8;

function createStream(opts, callback) {
  var stream;
  if (opts && opts.stream)
    return callback(null, stream);
  if (opts && (opts.path || opts.host || opts.port)) {
    if (opts.path)
      stream = net.connect(opts.path);
    else
      stream = net.connect(opts.port, opts.host);
    var connected = false;
    stream.on('connect', function() {
      connected = true;
      callback(null, stream);
    });
    stream.once('error', function(err) {
      if (!connected) // otherwise handle in client
        callback(err);
    });
  } else {
    require('child_process').exec(GET_SOCKET_PATH_CMD, function(err, path) {
      path = path.replace('\n', '');
      if (err)
        return callback(err);
      createStream({path: path}, callback);
    });
  }
}

function I3Message(buff) {
  this.magic   = buff.slice(0, I3_MAGIC.length); // TODO assert magic is correct
  this.payloadLength = buff.readUInt32LE(I3_MAGIC.length);
  this.code    = buff.readUInt16LE(I3_MAGIC.length + 4); // TODO UInt31 here?
  this.payload = null;
  this.isEvent = (buff.readUInt8(I3_MAGIC.length + 7) & 0x80) == 0x80;
}

function encodeCommand(code, payload) {
  if (!payload)
    payload = '';
  var payloadOffset = I3_MAGIC.length + 8;
  var buf = new Buffer(payloadOffset + payload.length);
  I3_MAGIC.copy(buf);
  buf.writeUInt32LE(payload.length, 6);
  buf.writeUInt32LE(code, 10);
  buf.write(payload, payloadOffset);
  return buf;
}

function I3IpcClient(opts) {
  EventEmitter.call(this);
  var self = this;
  self._stream = null;
  self._commands = new Queue();
  self._handlers = new Queue();
  createStream(opts, function(err, stream) {

    if (err)
       return self.emit('error', err);

    self.emit('connect', self);
    self._stream = stream;
    self._pump(); // send queued commands
    self._waitHeader = true;

    self._stream.on('readable', function() {
      while(1) {
        if (self._waitHeader) {
          var header = self._stream.read(I3_MESSAGE_HEADER_LENGTH);
          if (header) {
            self._message = new I3Message(header);
            if (self._message.payloadLength == 0) {
              self._handleMessage();
            } else {
              self._waitHeader = false;
            }
          } else break;
        } else {
          var data = self._stream.read(self._message.payloadLength);
          if (data) {
            self._message.payload = data;
            self._handleMessage();
            self._waitHeader = true;
          } else break;
        }
      }
    });
  });
};

util.inherits(I3IpcClient, EventEmitter);

I3IpcClient.prototype._pump = function() {
  if (!this._stream) return;

  var command;
  while(command = this._commands.shift()) {
    this._stream.write(command.encoded);
    command.callback.encoded = command.encoded;
    this._handlers.push(command.callback);
  }
};

var noop = function() {};

I3IpcClient.prototype.message = function(cmd, payload, callback) {
  this._commands.push({
    encoded: encodeCommand(cmd, payload),
    callback: callback ? callback : noop
  });
  this._pump();
}

var commandNameFromCode = "COMMAND GET_WORKSPACES SUBSCRIBE GET_OUTPUTS GET_TREE GET_MARKS GET_BAR_CONFIG GET_VERSION".split(' ');
var commandCodeFromName = {};
commandNameFromCode.forEach(function(name, code) { commandCodeFromName[name] = code; });

var eventNameFromCode = "workspace output mode window barconfig_update binding".split(' ');
var eventCodeFromName = {};
eventNameFromCode.forEach(function(name, code) { eventCodeFromName[name] = code; });

I3IpcClient.prototype._handleMessage = function() {
  var message = this._message;

  var payload;
  try {
    payload = JSON.parse(message.payload.toString());
  } catch(e) {
    payload = e;
  }

  if (message.isEvent) {
     eventName = eventNameFromCode[message.code];
     // TODO: check if code is known
     if (payload instanceof Error)
       return this.emit('error', payload)
     this.emit(eventName, payload);
  } else {
     var handler = this._handlers.shift();
     if (!handler) {
       var error = new Error('Unknown reply');
       error.i3Message = message;
       this.emit('error', error);
     } else {
       if (payload instanceof Error)
         return handler(payload)
       handler(null, payload);
     }
     if (this._handlers.length == 0) {
       this.emit('drain');
     }
  }
};

var baseOn = I3IpcClient.prototype.on;
I3IpcClient.prototype.on = function(event, handler) {
  var self = this;
  var i3EventCode = eventCodeFromName[event];
  if (typeof i3EventCode !== "undefined") {
    this.message(commandCodeFromName.SUBSCRIBE, JSON.stringify([event]), function(err, resp) {
      baseOn.call(self, event, handler);
    });
  } else {
    baseOn.call(this, event, handler);
  }
}

module.exports.I3IpcClient = I3IpcClient;
module.exports.Commads = commandCodeFromName;
module.exports.Events  = eventCodeFromName;
<|endoftext|>


<commit_before>function timeToStr(seconds) {
  var str = "";
  var hrs = Math.floor(seconds / 3600);
  var mins = Math.floor((seconds - hrs*3600)/ 60);
  var secs = Math.floor((seconds-hrs*3600-mins*60));

  return str + (hrs > 0 ? bufferZeros(hrs) + ":"  : "") + (mins > 0 ? bufferZeros(mins) + ":" : "") + bufferZeros(secs);
}

function bufferZeros(amount) {
  return ( amount < 10 ? "0" + amount : amount );
}

var raspberryjamApp = angular.module("raspberryjamApp", [
  'ngRoute',
  'raspberryjamControllers'
]);

function populatePlayer() {
  mopidy.playback.getCurrentTrack().done(function(track){
    if(track){
      $("#player-artist").html(track.artists.name.join(", "));
      $("#player-title").html(track.name);
      $("#player-length").html(timeToStr(track.length));
    }
  });
}

var mopidy;
$(document).ready(function(){
  $("#player-controls").height($("#player").height());

  //start mopidy
  mopidy = new Mopidy();

  mopidy.on(console.log.bind(console));

  mopidy.on("event:playbackStateChanged", function() {
    populatePlayer();
  });
});<commit_msg>moar dog (actually fixed syncing with frontend on player) again yay<commit_after>function timeToStr(seconds) {
  var str = "";
  var hrs = Math.floor(seconds / 3600);
  var mins = Math.floor((seconds - hrs*3600)/ 60);
  var secs = Math.floor((seconds-hrs*3600-mins*60));

  return str + (hrs > 0 ? bufferZeros(hrs) + ":"  : "") + (mins > 0 ? bufferZeros(mins) + ":" : "") + bufferZeros(secs);
}

function bufferZeros(amount) {
  return ( amount < 10 ? "0" + amount : amount );
}

var raspberryjamApp = angular.module("raspberryjamApp", [
  'ngRoute',
  'raspberryjamControllers'
]);

function populatePlayer() {
  mopidy.playback.getCurrentTrack().done(function(track){
    if(track){
      //do some fancy shit to get a list of the artist names
      $("#player-artist").html(track.artists.reduce(function(a, b){ return {name: a.name + ", " + b.name} }).name);
      $("#player-title").html(track.name);
      $("#player-length").html(timeToStr(track.length));
    }
  });
}

var mopidy;
$(document).ready(function(){
  $("#player-controls").height($("#player").height());

  //start mopidy
  mopidy = new Mopidy();

  mopidy.on(console.log.bind(console));

  mopidy.on("event:playbackStateChanged", function() {
    populatePlayer();
  });
});<|endoftext|>


<commit_before>"use strict";

var _ = require('lodash');
//var events = require('events');
//var util = require('util');
var Q = require('q');

/**
 * Job handle class (as returned from hive.do(), hive.job() )
 *
 * @param hive
 * @param jobData
 * @returns {Job}
 * @constructor
 */
var Job = function (hive, jobData) {
    var self = this;
    this.hive = hive;

    this._processEventBinded = this._processEvent.bind(this);

    /**
     * @private
     */
    this.resultDeferred = Q.defer();

    this._update(jobData);

    /*
    this.resultPromise = this.resultDeferred.promise.timeout(this.options.timeout,
        'Job handle timed out after ' + this.options.timeout + ' ms');
    */

    // register cleanup
    this.resultDeferred.promise.finally(function () {
        self.hive.redis.removeListener('job:' + self.jid, self._processEventBinded)
        if (self.duplicateJid) {
            self.hive.redis.removeListener('job:' + self.duplicateJid, self._processEventBinded)
        }
    })

    if (this.resultDeferred.promise.isPending()) {
        this.hive.redis.on('job:' + this.jid, this._processEventBinded)
    }

};

Job.prototype._update = function (jobData) {

    if(!(this.duplicateJid && this.duplicateJid == jobData.jid)){
        this.queue = jobData.queue;
        this.jid = jobData.jid;
        this.parent = jobData.parent;
        this.tags = _.toArray(jobData.tags);
        this.data = jobData.data;
        this.hash = jobData.hash || null;
        this.status = jobData.status;
        this.options = jobData.options || {};
        this.history = _.toArray(jobData.history);
    }

    if (jobData.duplicate) {
        if(!this.duplicateJid){
            this.duplicateJid = jobData.duplicate.jid;
            this.hive.redis.on('job:' + this.duplicateJid, this._processEventBinded)
        }

        if (jobData.duplicate.status == 'completed') {
            this.resultDeferred.resolve(jobData.duplicate.result);
        } else if (jobData.duplicate.status == 'failed') {
            this.resultDeferred.reject(new Error(jobData.duplicate.failedReason));
        } else if (jobData.duplicate.status == 'canceled') {
            this.resultDeferred.reject(new Error('Canceled'));
        }
    } else {
        if (jobData.status == 'completed') {
            this.resultDeferred.resolve(jobData.result);
        } else if (jobData.status == 'failed') {
            this.resultDeferred.reject(new Error(jobData.failedReason));
        }  else if (jobData.status == 'canceled') {
            this.resultDeferred.reject(new Error('Canceled'));
        }
    }

};

Job.prototype.update = function () {
    var self = this;

    return this.hive.redis.jobLoad(this.jid).then(function (jobData) {
        self._update(jobData)
    })

};

Job.prototype.cancel = function () {
    return this.hive.cancel(this)
};

/**
 * Get result promise
 *
 * @returns {Promise}
 */
Job.prototype.result = function () {
    return this.resultDeferred.promise;
};

/**
 *
 * @param event
 * @private
 */
Job.prototype._processEvent = function (event) {

    if (event && event.type) {

        switch (event.type) {
        /**
         * update job data on duplicate, completed and failed events
         */
            case 'duplicate':
            case 'completed':
            case 'failed':
            case 'canceled':
                this._update(event.job)
                break;
            case 'progress':
                this.resultDeferred.notify(event.progress || 0);
                break;
        }

    }
}

module.exports = Job;
<commit_msg>Much more detailed job rejection Error object<commit_after>"use strict";

var _ = require('lodash');
//var events = require('events');
//var util = require('util');
var Q = require('q');

/**
 * Job handle class (as returned from hive.do(), hive.job() )
 *
 * @param hive
 * @param jobData
 * @returns {Job}
 * @constructor
 */
var Job = function (hive, jobData) {
    var self = this;
    this.hive = hive;

    this._processEventBinded = this._processEvent.bind(this);

    /**
     * @private
     */
    this.resultDeferred = Q.defer();

    this._update(jobData);

    /*
    this.resultPromise = this.resultDeferred.promise.timeout(this.options.timeout,
        'Job handle timed out after ' + this.options.timeout + ' ms');
    */

    // register cleanup
    this.resultDeferred.promise.finally(function () {
        self.hive.redis.removeListener('job:' + self.jid, self._processEventBinded)
        if (self.duplicateJid) {
            self.hive.redis.removeListener('job:' + self.duplicateJid, self._processEventBinded)
        }
    })

    if (this.resultDeferred.promise.isPending()) {
        this.hive.redis.on('job:' + this.jid, this._processEventBinded)
    }

};

Job.prototype._makeError = function(message) {
    var err = new Error(message)
    err.queue = this.queue;
    err.jid = this.jid;
    err.history = this.history;

    return err;
}

Job.prototype._update = function (jobData) {

    if(!(this.duplicateJid && this.duplicateJid == jobData.jid)){
        this.queue = jobData.queue;
        this.jid = jobData.jid;
        this.parent = jobData.parent;
        this.tags = _.toArray(jobData.tags);
        this.data = jobData.data;
        this.hash = jobData.hash || null;
        this.status = jobData.status;
        this.options = jobData.options || {};
        this.history = _.toArray(jobData.history);
    }

    if (jobData.duplicate) {
        if(!this.duplicateJid){
            this.duplicateJid = jobData.duplicate.jid;
            this.hive.redis.on('job:' + this.duplicateJid, this._processEventBinded)
        }

        if (jobData.duplicate.status == 'completed') {
            this.resultDeferred.resolve(jobData.duplicate.result);
        } else if (jobData.duplicate.status == 'failed') {
            this.resultDeferred.reject(this._makeError(jobData.duplicate.failedReason));
        } else if (jobData.duplicate.status == 'canceled') {
            this.resultDeferred.reject(this._makeError('Canceled'));
        }
    } else {
        if (jobData.status == 'completed') {
            this.resultDeferred.resolve(jobData.result);
        } else if (jobData.status == 'failed') {
            this.resultDeferred.reject(this._makeError(jobData.failedReason));
        }  else if (jobData.status == 'canceled') {
            this.resultDeferred.reject(this._makeError('Canceled'));
        }
    }

};

Job.prototype.update = function () {
    var self = this;

    return this.hive.redis.jobLoad(this.jid).then(function (jobData) {
        self._update(jobData)
    })

};

Job.prototype.cancel = function () {
    return this.hive.cancel(this)
};

/**
 * Get result promise
 *
 * @returns {Promise}
 */
Job.prototype.result = function () {
    return this.resultDeferred.promise;
};

/**
 *
 * @param event
 * @private
 */
Job.prototype._processEvent = function (event) {

    if (event && event.type) {

        switch (event.type) {
        /**
         * update job data on duplicate, completed and failed events
         */
            case 'duplicate':
            case 'completed':
            case 'failed':
            case 'canceled':
                this._update(event.job)
                break;
            case 'progress':
                this.resultDeferred.notify(event.progress || 0);
                break;
        }

    }
}

module.exports = Job;
<|endoftext|>


<commit_before>
/*
 *  Guacamole - Clientless Remote Desktop
 *  Copyright (C) 2010  Michael Jumper
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

function GuacamoleClient(display) {

    var STATE_IDLE          = 0;
    var STATE_CONNECTING    = 1;
    var STATE_WAITING       = 2;
    var STATE_CONNECTED     = 3;
    var STATE_DISCONNECTING = 4;
    var STATE_DISCONNECTED  = 5;

    var currentState = STATE_IDLE;
    var stateChangeHandler = null;

    function setState(state) {
        if (state != currentState) {
            currentState = state;
            if (stateChangeHandler)
                stateChangeHandler(currentState);
        }
    }

    this.setOnStateChangeHandler = function(handler) {
        stateChangeHandler = handler;
    }

    function isConnected() {
        return currentState == STATE_CONNECTED
            || currentState == STATE_WAITING;
    }

    // Layers
    var background = null;
    var cursor = null;

    var cursorImage = null;
    var cursorHotspotX = 0;
    var cursorHotspotY = 0;

    // FIXME: Make object. Clean up.
    var cursorRectX = 0;
    var cursorRectY = 0;
    var cursorRectW = 0;
    var cursorRectH = 0;

    var cursorHidden = 0;

    function redrawCursor() {

        // Hide hardware cursor
        if (cursorHidden == 0) {
            display.className += " hideCursor";
            cursorHidden = 1;
        }

        // Erase old cursor
        cursor.clearRect(cursorRectX, cursorRectY, cursorRectW, cursorRectH);

        // Update rect
        cursorRectX = mouse.getX() - cursorHotspotX;
        cursorRectY = mouse.getY() - cursorHotspotY;
        cursorRectW = cursorImage.width;
        cursorRectH = cursorImage.height;

        // Draw new cursor
        cursor.drawImage(cursorRectX, cursorRectY, cursorImage);
    }

	/*****************************************/
	/*** Keyboard                          ***/
	/*****************************************/

    var keyboard = new GuacamoleKeyboard(document);

    this.disableKeyboard = function() {
        keyboard.setKeyPressedHandler(null);
        keyboard.setKeyReleasedHandler(null);
    };

    this.enableKeyboard = function() {
        keyboard.setKeyPressedHandler(
            function (keysym) {
                sendKeyEvent(1, keysym);
            }
        );

        keyboard.setKeyReleasedHandler(
            function (keysym) {
                sendKeyEvent(0, keysym);
            }
        );
    };

    // Enable keyboard by default
    this.enableKeyboard();

    function sendKeyEvent(pressed, keysym) {
        // Do not send requests if not connected
        if (!isConnected())
            return;

        sendMessage("key:" +  keysym + "," + pressed + ";");
    }

    this.pressKey = function(keysym) {
        sendKeyEvent(1, keysym);
    };

    this.releaseKey = function(keysym) {
        sendKeyEvent(0, keysym);
    };

	/*****************************************/
	/*** Mouse                             ***/
	/*****************************************/

    var mouse = new GuacamoleMouse(display);
    mouse.setButtonPressedHandler(
        function(mouseState) {
            sendMouseState(mouseState);
        }
    );

    mouse.setButtonReleasedHandler(
        function(mouseState) {
            sendMouseState(mouseState);
        }
    );

    mouse.setMovementHandler(
        function(mouseState) {

            // Draw client-side cursor
            if (cursorImage != null) {
                redrawCursor();
            }

            sendMouseState(mouseState);
        }
    );

    function sendMouseState(mouseState) {

        // Do not send requests if not connected
        if (!isConnected())
            return;

        // Build mask
        var buttonMask = 0;
        if (mouseState.getLeft())   buttonMask |= 1;
        if (mouseState.getMiddle()) buttonMask |= 2;
        if (mouseState.getRight())  buttonMask |= 4;
        if (mouseState.getUp())     buttonMask |= 8;
        if (mouseState.getDown())   buttonMask |= 16;

        // Send message
        sendMessage("mouse:" + mouseState.getX() + "," + mouseState.getY() + "," + buttonMask + ";");
    }

    var sendingMessages = 0;
    var outputMessageBuffer = "";

    function sendMessage(message) {

        // Add event to queue, restart send loop if finished.
        outputMessageBuffer += message;
        if (sendingMessages == 0)
            sendPendingMessages();

    }

    function sendPendingMessages() {

        if (outputMessageBuffer.length > 0) {

            sendingMessages = 1;

            var message_xmlhttprequest = new XMLHttpRequest();
            message_xmlhttprequest.open("POST", "inbound");
            message_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            message_xmlhttprequest.setRequestHeader("Content-length", outputMessageBuffer.length);

            // Once response received, send next queued event.
            message_xmlhttprequest.onreadystatechange = function() {
                if (message_xmlhttprequest.readyState == 4)
                    sendPendingMessages();
            }

            message_xmlhttprequest.send(outputMessageBuffer);
            outputMessageBuffer = ""; // Clear buffer

        }
        else
            sendingMessages = 0;

    }

	/*****************************************/
	/*** Clipboard                         ***/
	/*****************************************/

    this.setClipboard = function(data) {

        // Do not send requests if not connected
        if (!isConnected())
            return;

        sendMessage("clipboard:" + escapeGuacamoleString(data) + ";");
    }

    function desaturateFilter(data, width, height) {

        for (var i=0; i<data.length; i+=4) {

            // Get RGB values
            var r = data[i];
            var g = data[i+1];
            var b = data[i+2];

            // Desaturate
            var v = Math.max(r, g, b) / 2;
            data[i]   = v;
            data[i+1] = v;
            data[i+2] = v;

        }

    }

    var errorHandler = null;
    this.setErrorHandler = function(handler) {
        errorHandler = handler;
    };

    var errorEncountered = 0;
    function showError(error) {
        // Only display first error (avoid infinite error loops)
        if (errorEncountered == 0) {
            errorEncountered = 1;

            disconnect();

            // In case nothing has been rendered yet, use error style
            display.className += " error";

            // Show error by desaturating display
            if (background)
                background.filter(desaturateFilter);

            if (errorHandler)
                errorHandler(error);
        }
    }

    function handleErrors(message) {
        var errors = message.getErrors();
        for (var errorIndex=0; errorIndex<errors.length; errorIndex++)
            showError(errors[errorIndex].getMessage());
    }

    var clipboardHandler = null;
    var requests = 0;

    this.setClipboardHandler = function(handler) {
        clipboardHandler = handler;
    };

    function handleResponse(xmlhttprequest) {

        var nextRequest = null;

        var instructionStart = 0;
        var startIndex = 0;

        function parseResponse() {

            // Start next request as soon as possible
            if (xmlhttprequest.readyState >= 2 && nextRequest == null)
                nextRequest = makeRequest();

            // Parse stream when data is received and when complete.
            if (xmlhttprequest.readyState == 3 ||
                xmlhttprequest.readyState == 4) {

                // Halt on error during request
                if (xmlhttprequest.status == 0) {
                    showError("Request canceled by browser.");
                    return;
                }
                else if (xmlhttprequest.status != 200) {
                    showError("Error during request (HTTP " + xmlhttprequest.status + "): " + xmlhttprequest.statusText);
                    return;
                }

                var current = xmlhttprequest.responseText;
                var instructionEnd;

                while ((instructionEnd = current.indexOf(";", startIndex)) != -1) {

                    // Start next search at next instruction
                    startIndex = instructionEnd+1;

                    var instruction = current.substr(instructionStart,
                            instructionEnd - instructionStart);

                    instructionStart = startIndex;

                    var opcodeEnd = instruction.indexOf(":");

                    var opcode;
                    var parameters;
                    if (opcodeEnd == -1) {
                        opcode = instruction;
                        parameters = new Array();
                    }
                    else {
                        opcode = instruction.substr(0, opcodeEnd);
                        parameters = instruction.substr(opcodeEnd+1).split(",");
                    }

                    // If we're done parsing, handle the next response.
                    if (opcode.length == 0) {

                        if (isConnected()) {
                            delete xmlhttprequest;
                            if (nextRequest)
                                handleResponse(nextRequest);
                        }

                        break;
                    }

                    // Call instruction handler.
                    doInstruction(opcode, parameters);
                }

                // Start search at end of string.
                startIndex = current.length;

                delete instruction;
                delete parameters;

            }

        }

        xmlhttprequest.onreadystatechange = parseResponse;
        parseResponse();

    }

    function makeRequest() {

        // Download self
        var xmlhttprequest = new XMLHttpRequest();
        xmlhttprequest.open("POST", "outbound");
        xmlhttprequest.send(null);

        return xmlhttprequest;

    }

    function escapeGuacamoleString(str) {

        var escapedString = "";

        for (var i=0; i<str.length; i++) {

            var c = str.charAt(i);
            if (c == ",")
                escapedString += "\\c";
            else if (c == ";")
                escapedString += "\\s";
            else if (c == "\\")
                escapedString += "\\\\";
            else
                escapedString += c;

        }

        return escapedString;

    }

    function unescapeGuacamoleString(str) {

        var unescapedString = "";

        for (var i=0; i<str.length; i++) {

            var c = str.charAt(i);
            if (c == "\\" && i<str.length-1) {

                var escapeChar = str.charAt(++i);
                if (escapeChar == "c")
                    unescapedString += ",";
                else if (escapeChar == "s")
                    unescapedString += ";";
                else if (escapeChar == "\\")
                    unescapedString += "\\";
                else
                    unescapedString += "\\" + escapeChar;

            }
            else
                unescapedString += c;

        }

        return unescapedString;

    }

    var instructionHandlers = {

        "error": function(parameters) {
            showError(unescapeGuacamoleString(parameters[0]));
        },

        "name": function(parameters) {
            document.title = unescapeGuacamoleString(parameters[0]);
        },

        "clipboard": function(parameters) {
            clipboardHandler(unescapeGuacamoleString(parameters[0]));
        },

        "size": function(parameters) {

            var width = parseInt(parameters[0]);
            var height = parseInt(parameters[1]);

            // Update (set) display size
            if (display && (background == null || cursor == null)) {
                display.style.width = width + "px";
                display.style.height = height + "px";

                background = new Layer(width, height);
                cursor = new Layer(width, height);

                display.appendChild(background);
                display.appendChild(cursor);
            }

        },

        "rect": function(parameters) {

            var x = parseInt(parameters[0]);
            var y = parseInt(parameters[1]);
            var w = parseInt(parameters[2]);
            var h = parseInt(parameters[3]);
            var color = parameters[4];

            background.drawRect(
                x,
                y,
                w,
                h,
                color
            );

        },

        "png": function(parameters) {

            var x = parseInt(parameters[0]);
            var y = parseInt(parameters[1]);
            var data = parameters[2];

            background.draw(
                x,
                y,
                "data:image/png;base64," + data
            );

            // If received first update, no longer waiting.
            if (currentState == STATE_WAITING)
                setState(STATE_CONNECTED);

        },

        "copy": function(parameters) {

            var srcX = parseInt(parameters[0]);
            var srcY = parseInt(parameters[1]);
            var srcWidth = parseInt(parameters[2]);
            var srcHeight = parseInt(parameters[3]);
            var dstX = parseInt(parameters[4]);
            var dstY = parseInt(parameters[5]);

            background.copyRect(
                srcX,
                srcY,
                srcWidth,
                srcHeight,
                dstX,
                dstY
            );

        },

        "cursor": function(parameters) {

            var x = parseInt(parameters[0]);
            var y = parseInt(parameters[1]);
            var data = parameters[2];

            // Start cursor image load
            var image = new Image();
            image.onload = function() {
                cursorImage = image;
                cursorHotspotX = x;
                cursorHotspotY = y;
                redrawCursor();
            };
            image.src = "data:image/png;base64," + data

        }

    };

    function doInstruction(opcode, parameters) {

        var handler = instructionHandlers[opcode];
        if (handler)
            handler(parameters);

    }

    this.connect = function() {

        var message = "connect;";

        setState(STATE_CONNECTING);

        // Send connect message (synchronously... as necessary until handoff is implemented)
        var connect_xmlhttprequest = new XMLHttpRequest();
        connect_xmlhttprequest.open("POST", "inbound", false);
        connect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        connect_xmlhttprequest.setRequestHeader("Content-length", message.length);
        connect_xmlhttprequest.send(message);

        // Start reading data
        setState(STATE_WAITING);
        handleResponse(makeRequest());

    };

    function disconnect() {

        // Only attempt disconnection not disconnected.
        if (currentState != STATE_DISCONNECTED
                && currentState != STATE_DISCONNECTING) {

            var message = "disconnect;";
            setState(STATE_DISCONNECTING);

            // Send disconnect message (synchronously... as necessary until handoff is implemented)
            var disconnect_xmlhttprequest = new XMLHttpRequest();
            disconnect_xmlhttprequest.open("POST", "inbound", false);
            disconnect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            disconnect_xmlhttprequest.setRequestHeader("Content-length", message.length);
            disconnect_xmlhttprequest.send(message);

            setState(STATE_DISCONNECTED);
        }

    }

    this.disconnect = disconnect;

}
<commit_msg>Use new connect servlet<commit_after>
/*
 *  Guacamole - Clientless Remote Desktop
 *  Copyright (C) 2010  Michael Jumper
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

function GuacamoleClient(display) {

    var STATE_IDLE          = 0;
    var STATE_CONNECTING    = 1;
    var STATE_WAITING       = 2;
    var STATE_CONNECTED     = 3;
    var STATE_DISCONNECTING = 4;
    var STATE_DISCONNECTED  = 5;

    var currentState = STATE_IDLE;
    var stateChangeHandler = null;

    function setState(state) {
        if (state != currentState) {
            currentState = state;
            if (stateChangeHandler)
                stateChangeHandler(currentState);
        }
    }

    this.setOnStateChangeHandler = function(handler) {
        stateChangeHandler = handler;
    }

    function isConnected() {
        return currentState == STATE_CONNECTED
            || currentState == STATE_WAITING;
    }

    // Layers
    var background = null;
    var cursor = null;

    var cursorImage = null;
    var cursorHotspotX = 0;
    var cursorHotspotY = 0;

    // FIXME: Make object. Clean up.
    var cursorRectX = 0;
    var cursorRectY = 0;
    var cursorRectW = 0;
    var cursorRectH = 0;

    var cursorHidden = 0;

    function redrawCursor() {

        // Hide hardware cursor
        if (cursorHidden == 0) {
            display.className += " hideCursor";
            cursorHidden = 1;
        }

        // Erase old cursor
        cursor.clearRect(cursorRectX, cursorRectY, cursorRectW, cursorRectH);

        // Update rect
        cursorRectX = mouse.getX() - cursorHotspotX;
        cursorRectY = mouse.getY() - cursorHotspotY;
        cursorRectW = cursorImage.width;
        cursorRectH = cursorImage.height;

        // Draw new cursor
        cursor.drawImage(cursorRectX, cursorRectY, cursorImage);
    }

	/*****************************************/
	/*** Keyboard                          ***/
	/*****************************************/

    var keyboard = new GuacamoleKeyboard(document);

    this.disableKeyboard = function() {
        keyboard.setKeyPressedHandler(null);
        keyboard.setKeyReleasedHandler(null);
    };

    this.enableKeyboard = function() {
        keyboard.setKeyPressedHandler(
            function (keysym) {
                sendKeyEvent(1, keysym);
            }
        );

        keyboard.setKeyReleasedHandler(
            function (keysym) {
                sendKeyEvent(0, keysym);
            }
        );
    };

    // Enable keyboard by default
    this.enableKeyboard();

    function sendKeyEvent(pressed, keysym) {
        // Do not send requests if not connected
        if (!isConnected())
            return;

        sendMessage("key:" +  keysym + "," + pressed + ";");
    }

    this.pressKey = function(keysym) {
        sendKeyEvent(1, keysym);
    };

    this.releaseKey = function(keysym) {
        sendKeyEvent(0, keysym);
    };

	/*****************************************/
	/*** Mouse                             ***/
	/*****************************************/

    var mouse = new GuacamoleMouse(display);
    mouse.setButtonPressedHandler(
        function(mouseState) {
            sendMouseState(mouseState);
        }
    );

    mouse.setButtonReleasedHandler(
        function(mouseState) {
            sendMouseState(mouseState);
        }
    );

    mouse.setMovementHandler(
        function(mouseState) {

            // Draw client-side cursor
            if (cursorImage != null) {
                redrawCursor();
            }

            sendMouseState(mouseState);
        }
    );

    function sendMouseState(mouseState) {

        // Do not send requests if not connected
        if (!isConnected())
            return;

        // Build mask
        var buttonMask = 0;
        if (mouseState.getLeft())   buttonMask |= 1;
        if (mouseState.getMiddle()) buttonMask |= 2;
        if (mouseState.getRight())  buttonMask |= 4;
        if (mouseState.getUp())     buttonMask |= 8;
        if (mouseState.getDown())   buttonMask |= 16;

        // Send message
        sendMessage("mouse:" + mouseState.getX() + "," + mouseState.getY() + "," + buttonMask + ";");
    }

    var sendingMessages = 0;
    var outputMessageBuffer = "";

    function sendMessage(message) {

        // Add event to queue, restart send loop if finished.
        outputMessageBuffer += message;
        if (sendingMessages == 0)
            sendPendingMessages();

    }

    function sendPendingMessages() {

        if (outputMessageBuffer.length > 0) {

            sendingMessages = 1;

            var message_xmlhttprequest = new XMLHttpRequest();
            message_xmlhttprequest.open("POST", "inbound");
            message_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            message_xmlhttprequest.setRequestHeader("Content-length", outputMessageBuffer.length);

            // Once response received, send next queued event.
            message_xmlhttprequest.onreadystatechange = function() {
                if (message_xmlhttprequest.readyState == 4)
                    sendPendingMessages();
            }

            message_xmlhttprequest.send(outputMessageBuffer);
            outputMessageBuffer = ""; // Clear buffer

        }
        else
            sendingMessages = 0;

    }

	/*****************************************/
	/*** Clipboard                         ***/
	/*****************************************/

    this.setClipboard = function(data) {

        // Do not send requests if not connected
        if (!isConnected())
            return;

        sendMessage("clipboard:" + escapeGuacamoleString(data) + ";");
    }

    function desaturateFilter(data, width, height) {

        for (var i=0; i<data.length; i+=4) {

            // Get RGB values
            var r = data[i];
            var g = data[i+1];
            var b = data[i+2];

            // Desaturate
            var v = Math.max(r, g, b) / 2;
            data[i]   = v;
            data[i+1] = v;
            data[i+2] = v;

        }

    }

    var errorHandler = null;
    this.setErrorHandler = function(handler) {
        errorHandler = handler;
    };

    var errorEncountered = 0;
    function showError(error) {
        // Only display first error (avoid infinite error loops)
        if (errorEncountered == 0) {
            errorEncountered = 1;

            disconnect();

            // In case nothing has been rendered yet, use error style
            display.className += " error";

            // Show error by desaturating display
            if (background)
                background.filter(desaturateFilter);

            if (errorHandler)
                errorHandler(error);
        }
    }

    function handleErrors(message) {
        var errors = message.getErrors();
        for (var errorIndex=0; errorIndex<errors.length; errorIndex++)
            showError(errors[errorIndex].getMessage());
    }

    var clipboardHandler = null;
    var requests = 0;

    this.setClipboardHandler = function(handler) {
        clipboardHandler = handler;
    };

    function handleResponse(xmlhttprequest) {

        var nextRequest = null;

        var instructionStart = 0;
        var startIndex = 0;

        function parseResponse() {

            // Start next request as soon as possible
            if (xmlhttprequest.readyState >= 2 && nextRequest == null)
                nextRequest = makeRequest();

            // Parse stream when data is received and when complete.
            if (xmlhttprequest.readyState == 3 ||
                xmlhttprequest.readyState == 4) {

                // Halt on error during request
                if (xmlhttprequest.status == 0) {
                    showError("Request canceled by browser.");
                    return;
                }
                else if (xmlhttprequest.status != 200) {
                    showError("Error during request (HTTP " + xmlhttprequest.status + "): " + xmlhttprequest.statusText);
                    return;
                }

                var current = xmlhttprequest.responseText;
                var instructionEnd;

                while ((instructionEnd = current.indexOf(";", startIndex)) != -1) {

                    // Start next search at next instruction
                    startIndex = instructionEnd+1;

                    var instruction = current.substr(instructionStart,
                            instructionEnd - instructionStart);

                    instructionStart = startIndex;

                    var opcodeEnd = instruction.indexOf(":");

                    var opcode;
                    var parameters;
                    if (opcodeEnd == -1) {
                        opcode = instruction;
                        parameters = new Array();
                    }
                    else {
                        opcode = instruction.substr(0, opcodeEnd);
                        parameters = instruction.substr(opcodeEnd+1).split(",");
                    }

                    // If we're done parsing, handle the next response.
                    if (opcode.length == 0) {

                        if (isConnected()) {
                            delete xmlhttprequest;
                            if (nextRequest)
                                handleResponse(nextRequest);
                        }

                        break;
                    }

                    // Call instruction handler.
                    doInstruction(opcode, parameters);
                }

                // Start search at end of string.
                startIndex = current.length;

                delete instruction;
                delete parameters;

            }

        }

        xmlhttprequest.onreadystatechange = parseResponse;
        parseResponse();

    }

    function makeRequest() {

        // Download self
        var xmlhttprequest = new XMLHttpRequest();
        xmlhttprequest.open("POST", "outbound");
        xmlhttprequest.send(null);

        return xmlhttprequest;

    }

    function escapeGuacamoleString(str) {

        var escapedString = "";

        for (var i=0; i<str.length; i++) {

            var c = str.charAt(i);
            if (c == ",")
                escapedString += "\\c";
            else if (c == ";")
                escapedString += "\\s";
            else if (c == "\\")
                escapedString += "\\\\";
            else
                escapedString += c;

        }

        return escapedString;

    }

    function unescapeGuacamoleString(str) {

        var unescapedString = "";

        for (var i=0; i<str.length; i++) {

            var c = str.charAt(i);
            if (c == "\\" && i<str.length-1) {

                var escapeChar = str.charAt(++i);
                if (escapeChar == "c")
                    unescapedString += ",";
                else if (escapeChar == "s")
                    unescapedString += ";";
                else if (escapeChar == "\\")
                    unescapedString += "\\";
                else
                    unescapedString += "\\" + escapeChar;

            }
            else
                unescapedString += c;

        }

        return unescapedString;

    }

    var instructionHandlers = {

        "error": function(parameters) {
            showError(unescapeGuacamoleString(parameters[0]));
        },

        "name": function(parameters) {
            document.title = unescapeGuacamoleString(parameters[0]);
        },

        "clipboard": function(parameters) {
            clipboardHandler(unescapeGuacamoleString(parameters[0]));
        },

        "size": function(parameters) {

            var width = parseInt(parameters[0]);
            var height = parseInt(parameters[1]);

            // Update (set) display size
            if (display && (background == null || cursor == null)) {
                display.style.width = width + "px";
                display.style.height = height + "px";

                background = new Layer(width, height);
                cursor = new Layer(width, height);

                display.appendChild(background);
                display.appendChild(cursor);
            }

        },

        "rect": function(parameters) {

            var x = parseInt(parameters[0]);
            var y = parseInt(parameters[1]);
            var w = parseInt(parameters[2]);
            var h = parseInt(parameters[3]);
            var color = parameters[4];

            background.drawRect(
                x,
                y,
                w,
                h,
                color
            );

        },

        "png": function(parameters) {

            var x = parseInt(parameters[0]);
            var y = parseInt(parameters[1]);
            var data = parameters[2];

            background.draw(
                x,
                y,
                "data:image/png;base64," + data
            );

            // If received first update, no longer waiting.
            if (currentState == STATE_WAITING)
                setState(STATE_CONNECTED);

        },

        "copy": function(parameters) {

            var srcX = parseInt(parameters[0]);
            var srcY = parseInt(parameters[1]);
            var srcWidth = parseInt(parameters[2]);
            var srcHeight = parseInt(parameters[3]);
            var dstX = parseInt(parameters[4]);
            var dstY = parseInt(parameters[5]);

            background.copyRect(
                srcX,
                srcY,
                srcWidth,
                srcHeight,
                dstX,
                dstY
            );

        },

        "cursor": function(parameters) {

            var x = parseInt(parameters[0]);
            var y = parseInt(parameters[1]);
            var data = parameters[2];

            // Start cursor image load
            var image = new Image();
            image.onload = function() {
                cursorImage = image;
                cursorHotspotX = x;
                cursorHotspotY = y;
                redrawCursor();
            };
            image.src = "data:image/png;base64," + data

        }

    };

    function doInstruction(opcode, parameters) {

        var handler = instructionHandlers[opcode];
        if (handler)
            handler(parameters);

    }

    this.connect = function() {

        setState(STATE_CONNECTING);

        // Start tunnel and connect synchronously
        var connect_xmlhttprequest = new XMLHttpRequest();
        connect_xmlhttprequest.open("POST", "connect", false);
        connect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        connect_xmlhttprequest.setRequestHeader("Content-length", 0);
        connect_xmlhttprequest.send(null);

        // Start reading data
        setState(STATE_WAITING);
        handleResponse(makeRequest());

    };

    function disconnect() {

        // Only attempt disconnection not disconnected.
        if (currentState != STATE_DISCONNECTED
                && currentState != STATE_DISCONNECTING) {

            var message = "disconnect;";
            setState(STATE_DISCONNECTING);

            // Send disconnect message (synchronously... as necessary until handoff is implemented)
            var disconnect_xmlhttprequest = new XMLHttpRequest();
            disconnect_xmlhttprequest.open("POST", "inbound", false);
            disconnect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            disconnect_xmlhttprequest.setRequestHeader("Content-length", message.length);
            disconnect_xmlhttprequest.send(message);

            setState(STATE_DISCONNECTED);
        }

    }

    this.disconnect = disconnect;

}
<|endoftext|>