<commit_before>var debug = require('../lib/debug');
var assert = require('chai').assert;
var nodemock = require('nodemock');
var net = require('net');
var msgpack = require('msgpack');
var http = require('http');
var Deferred = require('jsdeferred').Deferred;
var client = require('socket.io-client');
var express = require('express');

var FluentReceiver = require('../lib/droonga-protocol/receiver').FluentReceiver;
exports.FluentReceiver = FluentReceiver;

var Connection = require('../lib/droonga-protocol/connection').Connection;

var testSendPort = exports.testSendPort = 3333;
var testReceivePort = exports.testReceivePort = 3334;
var testServerPort = exports.testServerPort = 3335;
var testTag = exports.testTag = 'test';

function connectTo(port) {
  var deferred = new Deferred();
  var clientSocket = new net.Socket();
  clientSocket.on('error', function(error){
    clientSocket.destroy();
    deferred.fail(error);
  });
  clientSocket.connect(port, 'localhost', function(){
    deferred.call(clientSocket);
  });
  return deferred;
}
exports.connectTo = connectTo;
Deferred.register('connectTo', connectTo);

function sendPacketTo(packet, port) {
  var clientSocket;
  return connectTo(port)
    .next(function(newSocket) {
      clientSocket = newSocket;
      var packedPacket = msgpack.pack(packet);
      clientSocket.write(new Buffer(packedPacket));
    })
    .wait(0.01)
    .next(function() {
      clientSocket.destroy();
      clientSocket = undefined;
    })
    .error(function(error) {
      if (clientSocket) {
        clientSocket.destroy();
        clientSocket = undefined;
      }
      throw error;
    });
}
exports.sendPacketTo = sendPacketTo;
Deferred.register('sendPacketTo', sendPacketTo);

function setupServer(handlerOrServer) {
  var deferred = new Deferred();
  var server;
  if ('close' in handlerOrServer) { // it is a server
    server = handlerOrServer;
  } else { // it is a handler
    server = http.createServer(handlerOrServer);
  }
  server.listen(testServerPort, function() {
    deferred.call(server);
  });
  return deferred;
}
exports.setupServer = setupServer;
Deferred.register('setupServer', setupServer);

function sendRequest(method, path, postData, headers) {
  var deferred = new Deferred();

  var options = {
        host: 'localhost',
        port: testServerPort,
        path: path,
        method: method,
        headers: {}
      };

  if (headers) {
    for (var header in headers) {
      if (headers.hasOwnProperty(header))
        options.headers[header] = headers[header];
    }
  }

  Deferred.next(function() {
    var request = http.request(options, function(response) {
          var body = '';
          response.on('data', function(data) {
            body += data;
          });
          response.on('end', function() {
            deferred.call({
              statusCode: response.statusCode,
              body: body
            });
          });
        });
    request.on('error', function(error) {
      deferred.fail(error);
    });

    if (postData) request.write(postData);
    request.end();
  });

  return deferred;
}

function get(path, headers) {
  return sendRequest('GET', path, null, headers);
}
exports.get = get;
Deferred.register('get', function() { return get.apply(this, arguments); });

function post(path, body, headers) {
  return sendRequest('POST', path, body, headers);
}
exports.post = post;
Deferred.register('post', function() { return post.apply(this, arguments); });

function createClientSocket() {
  var deferred = new Deferred();
  var host = 'http://localhost:' + testServerPort;
  var options = { 'force new connection': true };
  var socket = client.connect(host, options);
  socket.on('connect', function() {
    deferred.call(socket);
  });
  return deferred;
}
exports.createClientSocket = createClientSocket;
Deferred.register('createClientSocket', createClientSocket);

function createClientSockets(count) {
  var sockets = [];
  return Deferred.next(function loop() {
    if (sockets.length < count) {
      return createClientSocket()
               .next(function(newSocket) {
                 sockets.push(newSocket);
               })
               .next(loop);
    } else {
      return sockets;
    }
  });
}
exports.createClientSockets = createClientSockets;
Deferred.register('createClientSockets', createClientSockets);

function createStubbedBackendConnection() {
  return {
    emitMessage: function(type, message, callback, options) {
      this.emitMessageCalledArguments.push({
        type:     type,
        message:  message,
        callback: callback,
        options:  options
      });
    },
    emitMessageCalledArguments: [],

    emit: function() {},
    on: function() {},
    removeListener: function() {},
    removeAllListeners: function() {},
    close: function() {}
  };
}
exports.createStubbedBackendConnection = createStubbedBackendConnection;

function setupApplication() {
  var application = express();
  var server;
  var backend;
  return setupServer(application)
    .next(function(newServer) {
      server = newServer;
    })
    .createBackend()
    .next(function(newBackend) {
      backend = newBackend;
      var connection = new Connection({
        tag:      testTag,
        defaultDataset: 'test-dataset',
        hostName: 'localhost',
        port:     testSendPort,
        receivePort: testReceivePort,
        maxRetyrCount: 3,
        retryDelay: 1
      });
      return {
        backend:     backend,
        server:      server,
        application: application,
        connection:  connection
      };
    });
}
exports.setupApplication = setupApplication;
Deferred.register('setupApplication', setupApplication);

function teardownApplication(params) {
  params = params || {};
  if (params.backend) {
    params.backend.close();
    params.backend = undefined;
  }
  if (params.application && params.application.connection) {
    params.application.connection.close();
    params.application = undefined;
  } else if (params.connection) {
    params.connection.close();
    params.connection = undefined;
  }
  if (params.server) {
    params.server.close();
    params.server = undefined;
  }
}
exports.teardownApplication = teardownApplication;
Deferred.register('teardownApplication', teardownApplication);

function createBackend() {
  var deferred = new Deferred();
  var backend = new FluentReceiver(testSendPort);

  backend.clearMessages = function() {
    this.received = [];
  };

  backend.clearMessages();
  backend.on('receive', function(data) {
    debug('test-utils.createBackend.receive %d', backend._id);
    backend.received.push(data);
    if (backend.reservedResponses.length > 0) {
      var response = backend.reservedResponses.shift();
      if (typeof response == 'function')
        response = response(data);
      sendPacketTo(response, testReceivePort);
    }
  });

  backend.reservedResponses = [];
  backend.reserveResponse = function(response) {
    backend.reservedResponses.push(response);
  };

  backend.assertReceived = function(expectedMessages) {
    assert.deepEqual(this.getMessages().map(function(message) {
                       return { type: message.type,
                                body: message.body };
                     }),
                     expectedMessages);
  };

  backend.getMessages = function() {
    return this.received.map(function(packet) {
      return packet[2];
    });
  };
  backend.getEvents = function() {
    return this.getMessages().map(function(envelope) {
      return envelope.type;
    });
  };
  backend.getBodies = function() {
    return this.getMessages().map(function(envelope) {
      return envelope.body;
    });
  };

  backend.sendMessage = function(type, body) {
    var response = createEnvelope(type, body);
    return sendPacketTo(createPacket(response), testReceivePort)
  };
  backend.sendResponse = function(request, type, body) {
    var response = createReplyEnvelope(request, type, body);
    return sendPacketTo(createPacket(response), testReceivePort)
  };

  backend.listen(function() {
    return deferred.call(backend);
  });

  return deferred;
}
exports.createBackend = createBackend;
Deferred.register('createBackend', createBackend);

function createEnvelope(type, body, options) {
  options = options || {};
  var now = new Date();
  var envelope = {
    id:         now.getTime(),
    date:       now.toISOString(),
    from:       'localhost:' + testReceivePort + '/' + testTag,
    statusCode: 200,
    dataset:    options.dataset || 'test-dataset',
    type:       type,
    body:       body
  };
  return envelope;
}
exports.createEnvelope = createEnvelope;

function createExpectedEnvelope(type, body, options) {
  var envelope = createEnvelope(type, body);
  envelope.id = TypeOf('string');
  envelope.from = new RegExp('^' + envelope.from + '\\?connection_id=\\d+$');
  envelope.date = InstanceOf(Date);
  if (options && options.dataset)
    envelope.dataset = options.dataset;
  if (options && options.requireReply)
    envelope.replyTo = envelope.from;
  return envelope;
}
exports.createExpectedEnvelope = createExpectedEnvelope;

function createReplyEnvelope(message, type, body) {
  var response = createEnvelope(type, body);
  response.inReplyTo = message.id;
  return response;
}
exports.createReplyEnvelope = createReplyEnvelope;

function createPacket(message, tag) {
  tag = tag || 'test.message';
  return [tag, Date.now(), message];
}
exports.createPacket = createPacket;

function createReplyPacket(requestPacket, envelope) {
  var tag = requestPacket[0];
  var timestamp = Date.now();
  var requestEnvelope = requestPacket[2];
  var replyEnvelope = Object.create(envelope);
  envelope.inReplyTo = requestEnvelope.id;
  return [tag, timestamp, replyEnvelope];
}
exports.createReplyPacket = createReplyPacket;

function TypeOf(typeString) {
  if (!(this instanceof TypeOf))
    return new TypeOf(typeString);

  this.typeString = typeString;
  if (typeString == 'date') {
    return new InstanceOf(Date);
  }
}
exports.TypeOf = TypeOf;

function InstanceOf(constructor) {
  if (!(this instanceof InstanceOf))
    return new InstanceOf(constructor);

  this.constructorFunction = constructor;
}
exports.InstanceOf = InstanceOf;

function assertEnvelopeEqual(actual, expected) {
  var vs = JSON.stringify(actual) + ' vs ' + JSON.stringify(expected);
  Object.keys(expected).forEach(function(key) {
    var actualValue = actual[key];
    var expectedValue = expected[key];
    if (expectedValue instanceof InstanceOf) {
      if (typeof actualValue == 'string') {
        // Try fo parse the value and create new instance.
        // If this process is failed, it can be an invalid value.
        actualValue = new expectedValue.constructorFunction(actualValue);
      }
      assert.instanceOf(actualValue,
                        expectedValue.constructorFunction,
                        key + ' / ' + vs);
    } else if (expectedValue instanceof TypeOf) {
      assert.typeOf(typeof actualValue,
                    expectedValue.typeString,
                    key + ' / ' + vs);
    } else if (expectedValue.constructor.toString().indexOf('function RegExp') > -1) {
      assert.match(actualValue, expectedValue, key + ' / ' + vs);
    } else {
      assert.deepEqual(actualValue, expectedValue, key + ' / ' + vs);
    }
  });
}
assert.envelopeEqual = assertEnvelopeEqual;

function sortKeys(original) {
  if (!original || typeof original != 'object')
    return original;

  if (Array.isArray(original))
    return original.map(sortKeys);

  var sorted = {};
  Object.keys(original).sort().forEach(function(key) {
    sorted[key] = sortKeys(original[key]);
  });
  return sorted;
}

// assert.deepEqual fails when the order of hash keys are different,
// even if they are "eaual" as JSON objects.
function assertEqualJSON(actual, expected) {
  this.deepEqual(sortKeys(actual), sortKeys(expected));
}
assert.equalJSON = assertEqualJSON;

exports.allElements = [
  'startTime',
  'elapsedTime',
  'count',
  'attributes',
  'records'
];
<commit_msg>Define missing "getRouteToSelf()" to stub connection<commit_after>var debug = require('../lib/debug');
var assert = require('chai').assert;
var nodemock = require('nodemock');
var net = require('net');
var msgpack = require('msgpack');
var http = require('http');
var Deferred = require('jsdeferred').Deferred;
var client = require('socket.io-client');
var express = require('express');

var FluentReceiver = require('../lib/droonga-protocol/receiver').FluentReceiver;
exports.FluentReceiver = FluentReceiver;

var Connection = require('../lib/droonga-protocol/connection').Connection;

var testSendPort = exports.testSendPort = 3333;
var testReceivePort = exports.testReceivePort = 3334;
var testServerPort = exports.testServerPort = 3335;
var testTag = exports.testTag = 'test';

function connectTo(port) {
  var deferred = new Deferred();
  var clientSocket = new net.Socket();
  clientSocket.on('error', function(error){
    clientSocket.destroy();
    deferred.fail(error);
  });
  clientSocket.connect(port, 'localhost', function(){
    deferred.call(clientSocket);
  });
  return deferred;
}
exports.connectTo = connectTo;
Deferred.register('connectTo', connectTo);

function sendPacketTo(packet, port) {
  var clientSocket;
  return connectTo(port)
    .next(function(newSocket) {
      clientSocket = newSocket;
      var packedPacket = msgpack.pack(packet);
      clientSocket.write(new Buffer(packedPacket));
    })
    .wait(0.01)
    .next(function() {
      clientSocket.destroy();
      clientSocket = undefined;
    })
    .error(function(error) {
      if (clientSocket) {
        clientSocket.destroy();
        clientSocket = undefined;
      }
      throw error;
    });
}
exports.sendPacketTo = sendPacketTo;
Deferred.register('sendPacketTo', sendPacketTo);

function setupServer(handlerOrServer) {
  var deferred = new Deferred();
  var server;
  if ('close' in handlerOrServer) { // it is a server
    server = handlerOrServer;
  } else { // it is a handler
    server = http.createServer(handlerOrServer);
  }
  server.listen(testServerPort, function() {
    deferred.call(server);
  });
  return deferred;
}
exports.setupServer = setupServer;
Deferred.register('setupServer', setupServer);

function sendRequest(method, path, postData, headers) {
  var deferred = new Deferred();

  var options = {
        host: 'localhost',
        port: testServerPort,
        path: path,
        method: method,
        headers: {}
      };

  if (headers) {
    for (var header in headers) {
      if (headers.hasOwnProperty(header))
        options.headers[header] = headers[header];
    }
  }

  Deferred.next(function() {
    var request = http.request(options, function(response) {
          var body = '';
          response.on('data', function(data) {
            body += data;
          });
          response.on('end', function() {
            deferred.call({
              statusCode: response.statusCode,
              body: body
            });
          });
        });
    request.on('error', function(error) {
      deferred.fail(error);
    });

    if (postData) request.write(postData);
    request.end();
  });

  return deferred;
}

function get(path, headers) {
  return sendRequest('GET', path, null, headers);
}
exports.get = get;
Deferred.register('get', function() { return get.apply(this, arguments); });

function post(path, body, headers) {
  return sendRequest('POST', path, body, headers);
}
exports.post = post;
Deferred.register('post', function() { return post.apply(this, arguments); });

function createClientSocket() {
  var deferred = new Deferred();
  var host = 'http://localhost:' + testServerPort;
  var options = { 'force new connection': true };
  var socket = client.connect(host, options);
  socket.on('connect', function() {
    deferred.call(socket);
  });
  return deferred;
}
exports.createClientSocket = createClientSocket;
Deferred.register('createClientSocket', createClientSocket);

function createClientSockets(count) {
  var sockets = [];
  return Deferred.next(function loop() {
    if (sockets.length < count) {
      return createClientSocket()
               .next(function(newSocket) {
                 sockets.push(newSocket);
               })
               .next(loop);
    } else {
      return sockets;
    }
  });
}
exports.createClientSockets = createClientSockets;
Deferred.register('createClientSockets', createClientSockets);

function createStubbedBackendConnection() {
  return {
    emitMessage: function(type, message, callback, options) {
      this.emitMessageCalledArguments.push({
        type:     type,
        message:  message,
        callback: callback,
        options:  options
      });
    },
    emitMessageCalledArguments: [],
    getRouteToSelf: function() {
      return 'localhost:' + testReceivePort + '/' + testTag;
    },

    emit: function() {},
    on: function() {},
    removeListener: function() {},
    removeAllListeners: function() {},
    close: function() {}
  };
}
exports.createStubbedBackendConnection = createStubbedBackendConnection;

function setupApplication() {
  var application = express();
  var server;
  var backend;
  return setupServer(application)
    .next(function(newServer) {
      server = newServer;
    })
    .createBackend()
    .next(function(newBackend) {
      backend = newBackend;
      var connection = new Connection({
        tag:      testTag,
        defaultDataset: 'test-dataset',
        hostName: 'localhost',
        port:     testSendPort,
        receivePort: testReceivePort,
        maxRetyrCount: 3,
        retryDelay: 1
      });
      return {
        backend:     backend,
        server:      server,
        application: application,
        connection:  connection
      };
    });
}
exports.setupApplication = setupApplication;
Deferred.register('setupApplication', setupApplication);

function teardownApplication(params) {
  params = params || {};
  if (params.backend) {
    params.backend.close();
    params.backend = undefined;
  }
  if (params.application && params.application.connection) {
    params.application.connection.close();
    params.application = undefined;
  } else if (params.connection) {
    params.connection.close();
    params.connection = undefined;
  }
  if (params.server) {
    params.server.close();
    params.server = undefined;
  }
}
exports.teardownApplication = teardownApplication;
Deferred.register('teardownApplication', teardownApplication);

function createBackend() {
  var deferred = new Deferred();
  var backend = new FluentReceiver(testSendPort);

  backend.clearMessages = function() {
    this.received = [];
  };

  backend.clearMessages();
  backend.on('receive', function(data) {
    debug('test-utils.createBackend.receive %d', backend._id);
    backend.received.push(data);
    if (backend.reservedResponses.length > 0) {
      var response = backend.reservedResponses.shift();
      if (typeof response == 'function')
        response = response(data);
      sendPacketTo(response, testReceivePort);
    }
  });

  backend.reservedResponses = [];
  backend.reserveResponse = function(response) {
    backend.reservedResponses.push(response);
  };

  backend.assertReceived = function(expectedMessages) {
    assert.deepEqual(this.getMessages().map(function(message) {
                       return { type: message.type,
                                body: message.body };
                     }),
                     expectedMessages);
  };

  backend.getMessages = function() {
    return this.received.map(function(packet) {
      return packet[2];
    });
  };
  backend.getEvents = function() {
    return this.getMessages().map(function(envelope) {
      return envelope.type;
    });
  };
  backend.getBodies = function() {
    return this.getMessages().map(function(envelope) {
      return envelope.body;
    });
  };

  backend.sendMessage = function(type, body) {
    var response = createEnvelope(type, body);
    return sendPacketTo(createPacket(response), testReceivePort)
  };
  backend.sendResponse = function(request, type, body) {
    var response = createReplyEnvelope(request, type, body);
    return sendPacketTo(createPacket(response), testReceivePort)
  };

  backend.listen(function() {
    return deferred.call(backend);
  });

  return deferred;
}
exports.createBackend = createBackend;
Deferred.register('createBackend', createBackend);

function createEnvelope(type, body, options) {
  options = options || {};
  var now = new Date();
  var envelope = {
    id:         now.getTime(),
    date:       now.toISOString(),
    from:       'localhost:' + testReceivePort + '/' + testTag,
    statusCode: 200,
    dataset:    options.dataset || 'test-dataset',
    type:       type,
    body:       body
  };
  return envelope;
}
exports.createEnvelope = createEnvelope;

function createExpectedEnvelope(type, body, options) {
  var envelope = createEnvelope(type, body);
  envelope.id = TypeOf('string');
  envelope.from = new RegExp('^' + envelope.from + '\\?connection_id=\\d+$');
  envelope.date = InstanceOf(Date);
  if (options && options.dataset)
    envelope.dataset = options.dataset;
  if (options && options.requireReply)
    envelope.replyTo = envelope.from;
  return envelope;
}
exports.createExpectedEnvelope = createExpectedEnvelope;

function createReplyEnvelope(message, type, body) {
  var response = createEnvelope(type, body);
  response.inReplyTo = message.id;
  return response;
}
exports.createReplyEnvelope = createReplyEnvelope;

function createPacket(message, tag) {
  tag = tag || 'test.message';
  return [tag, Date.now(), message];
}
exports.createPacket = createPacket;

function createReplyPacket(requestPacket, envelope) {
  var tag = requestPacket[0];
  var timestamp = Date.now();
  var requestEnvelope = requestPacket[2];
  var replyEnvelope = Object.create(envelope);
  envelope.inReplyTo = requestEnvelope.id;
  return [tag, timestamp, replyEnvelope];
}
exports.createReplyPacket = createReplyPacket;

function TypeOf(typeString) {
  if (!(this instanceof TypeOf))
    return new TypeOf(typeString);

  this.typeString = typeString;
  if (typeString == 'date') {
    return new InstanceOf(Date);
  }
}
exports.TypeOf = TypeOf;

function InstanceOf(constructor) {
  if (!(this instanceof InstanceOf))
    return new InstanceOf(constructor);

  this.constructorFunction = constructor;
}
exports.InstanceOf = InstanceOf;

function assertEnvelopeEqual(actual, expected) {
  var vs = JSON.stringify(actual) + ' vs ' + JSON.stringify(expected);
  Object.keys(expected).forEach(function(key) {
    var actualValue = actual[key];
    var expectedValue = expected[key];
    if (expectedValue instanceof InstanceOf) {
      if (typeof actualValue == 'string') {
        // Try fo parse the value and create new instance.
        // If this process is failed, it can be an invalid value.
        actualValue = new expectedValue.constructorFunction(actualValue);
      }
      assert.instanceOf(actualValue,
                        expectedValue.constructorFunction,
                        key + ' / ' + vs);
    } else if (expectedValue instanceof TypeOf) {
      assert.typeOf(typeof actualValue,
                    expectedValue.typeString,
                    key + ' / ' + vs);
    } else if (expectedValue.constructor.toString().indexOf('function RegExp') > -1) {
      assert.match(actualValue, expectedValue, key + ' / ' + vs);
    } else {
      assert.deepEqual(actualValue, expectedValue, key + ' / ' + vs);
    }
  });
}
assert.envelopeEqual = assertEnvelopeEqual;

function sortKeys(original) {
  if (!original || typeof original != 'object')
    return original;

  if (Array.isArray(original))
    return original.map(sortKeys);

  var sorted = {};
  Object.keys(original).sort().forEach(function(key) {
    sorted[key] = sortKeys(original[key]);
  });
  return sorted;
}

// assert.deepEqual fails when the order of hash keys are different,
// even if they are "eaual" as JSON objects.
function assertEqualJSON(actual, expected) {
  this.deepEqual(sortKeys(actual), sortKeys(expected));
}
assert.equalJSON = assertEqualJSON;

exports.allElements = [
  'startTime',
  'elapsedTime',
  'count',
  'attributes',
  'records'
];
<|endoftext|>


<commit_before>
/**
 * WPCOM module
 */

var WPCOM = require('../');
var assert = require('assert');

/**
 * Testing data
 */

var test = require('./data');
var util = require('./util');

/**
 * WPCOM object
 */

describe('WPCOM', function(){

  describe('sync', function(){

    it('should set the token', function(){
      var wpcom = new WPCOM(test.site.private.token);
      assert.equal('string', typeof wpcom.token);
      assert.equal(test.site.private.token, wpcom.token);
    });

  });

  describe('async', function(){

    describe('freshlyPressed()', function(){
      it('should require freshly pressed', function(done){
        var wpcom = util.wpcom();

        wpcom.freshlyPressed(function(err, data){
          if (err) throw err;

          // testing object
          assert.ok(data);
          assert.equal('number', typeof data.number);
          assert.ok(data.posts instanceof Array);
          done();
        });
      });

    });

  });

});
<commit_msg>test: remove token test<commit_after>
/**
 * WPCOM module
 */

var WPCOM = require('../');
var assert = require('assert');

/**
 * Testing data
 */

var test = require('./data');
var util = require('./util');

/**
 * WPCOM object
 */

describe('WPCOM', function(){

  describe('async', function(){

    describe('freshlyPressed()', function(){
      it('should require freshly pressed', function(done){
        var wpcom = util.wpcom();

        wpcom.freshlyPressed(function(err, data){
          if (err) throw err;

          // testing object
          assert.ok(data);
          assert.equal('number', typeof data.number);
          assert.ok(data.posts instanceof Array);
          done();
        });
      });

    });

  });

});
<|endoftext|>


<commit_before>/*global define*/
define(
	function()
	{
		var signals;
		var instructions = { };
		var valid_value_types = [ 'string', 'number' ];
		var valid_shapes = [ 'rect', 'circle', 'line' ];
		var reserved_keys = [ 'updated' ];

		function init( shared )
		{
			signals = shared.signals;

			signals['instructed'].add( checkInstructions );
			signals['looped'].add( drawInstructions );
		}

		function checkInstructions( obj )
		{
			for ( var id in obj )
			{
				if ( isValidInstruction( obj[id] ) )
				{
					if ( instructions[id] )
					{
						updateInstruction( id, obj[id] );
					}

					else
					{
						addInstruction( id, obj[id] );
					}
				}

				else
				{
					removeInstruction( id );
				}
			}
		}

		function updateInstruction( id, obj )
		{
			var updated = false;

			for ( var key in obj )
			{
				var new_value = obj[key];

				if ( valid_value_types.indexOf( typeof new_value ) !== -1 )
				{
					updated = true;
					instructions[id][key] = new_value;
				}
			}

			instructions[id].updated = updated;
		}

		function addInstruction( id, obj )
		{
			instructions[id] = obj;
			instructions[id].updated = true;
		}

		function removeInstruction( id )
		{
			instructions[id] = undefined;
		}

		function drawInstructions()
		{
			signals['draw'].dispatch( instructions );
		}

		function isValidInstruction( obj )
		{
			return ( typeof obj === 'object' && valid_shapes.indexOf( obj.shape ) !== -1 );
		}

		var i = {
			init: init
		};

		return i;
	}
);<commit_msg>flush cached instructions on updated inputs<commit_after>/*global define*/
define(
	function()
	{
		var signals;
		var instructions = { };
		var valid_value_types = [ 'string', 'number' ];
		var valid_shapes = [ 'rect', 'circle', 'line' ];
		var reserved_keys = [ 'updated' ];
		var flush = false;

		function init( shared )
		{
			signals = shared.signals;

			signals['instructed'].add( checkInstructions );
			signals['looped'].add( drawInstructions );
			signals['input-updated'].add( flushInstructions );
		}

		function checkInstructions( obj )
		{
			if ( flush )
			{
				instructions = { };

				flush = false;
			}

			for ( var id in obj )
			{
				if ( isValidInstruction( obj[id] ) )
				{
					if ( instructions[id] )
					{
						updateInstruction( id, obj[id] );
					}

					else
					{
						addInstruction( id, obj[id] );
					}
				}

				else
				{
					removeInstruction( id );
				}
			}
		}

		function updateInstruction( id, obj )
		{
			var updated = false;

			for ( var key in obj )
			{
				var new_value = obj[key];

				if ( valid_value_types.indexOf( typeof new_value ) !== -1 )
				{
					updated = true;
					instructions[id][key] = new_value;
				}
			}

			instructions[id].updated = updated;
		}

		function addInstruction( id, obj )
		{
			instructions[id] = obj;
			instructions[id].updated = true;
		}

		function removeInstruction( id )
		{
			instructions[id] = undefined;
		}

		function flushInstructions()
		{
			flush = true;
		}

		function drawInstructions()
		{
			signals['draw'].dispatch( instructions );
		}

		function isValidInstruction( obj )
		{
			return ( typeof obj === 'object' && valid_shapes.indexOf( obj.shape ) !== -1 );
		}

		var i = {
			init: init
		};

		return i;
	}
);<|endoftext|>


<commit_before>var ffmpeg = require('ffmpeg');
var fs = require('fs');
var ipfsAPI = require('ipfs-api')

function transcode(filename) {
    try {
        var process = new ffmpeg(filename);
        process.then(function(video) {
            console.log('ok');
            video
                .setVideoSize('50%')
//                .setVideoCodec('mpeg4')
                .setVideoFormat('avi')
                .setVideoBitRate('370K')
                //        .setAudioCodec('flv1')
                //        .setAudioChannels(2)
                .save('./b.avi', function(error, file) {
                    if (error) {
                        console.log(error);
                    }
                    if (!error) {
                        console.log('Video file: ' + file);
                    }
                });

        }, function(err) {
            console.log('Error: ' + err);
        });
    } catch (e) {
        console.log(e.code);
        console.log(e.msg);
    }
}

//transcode('a.avi');
upload('./b.mp4');

function upload(filename) {
    var filestream = fs.createReadStream(filename, {
        bufferSize: 128
    })
    var ipfs = ipfsAPI('/ip4/127.0.0.1/tcp/5001');
    ipfs.add(filestream, (err, res) => {
        if (err) {
            console.log(err);
        } else {
            console.log(res);
            var videohash = res[0].Hash;

            var video_metaobject = {
                title: "Test Video",
                description: "Description of the test video",
                hash: videohash,
                created: Math.floor(Date.now() / 1000)
            }
            console.log(video_metaobject);

            ipfs.add(new Buffer(JSON.stringify(video_metaobject)), (err, res) => {
                if (err) {
                    console.log(err);
                } else {
                    console.log('video metadata object is at ', res[0].Hash);
                }

            });

        }
    });

}<commit_msg>transcoder update<commit_after>var ffmpeg = require('ffmpeg');
var fs = require('fs');
var ipfsAPI = require('ipfs-api')

var ipfsnode = '/ip4/10.0.5.38/tcp/5001';

function transcode(filename) {
    try {
        var process = new ffmpeg(filename);
        process.then(function(video) {
            console.log('ok');
            video
                .setVideoSize('50%')
//                .setVideoCodec('mpeg4')
                .setVideoFormat('avi')
                .setVideoBitRate('370K')
                //        .setAudioCodec('flv1')
                //        .setAudioChannels(2)
                .save('./b.avi', function(error, file) {
                    if (error) {
                        console.log(error);
                    }
                    if (!error) {
                        console.log('Video file: ' + file);
                    }
                });

        }, function(err) {
            console.log('Error: ' + err);
        });
    } catch (e) {
        console.log(e.code);
        console.log(e.msg);
    }
}

//transcode('a.avi');
upload('./b.mp4');

function upload(filename) {
    var filestream = fs.createReadStream(filename, {
        bufferSize: 128
    })
    var ipfs = ipfsAPI(ipfsnode);
    ipfs.add(filestream, (err, res) => {
        if (err) {
            console.log(err);
        } else {
            console.log(res);
            var videohash = res[0].Hash;

            var video_metaobject = {
                title: "Test Video",
                description: "Description of the test video",
                hash: videohash,
                created: Math.floor(Date.now() / 1000)
            }
            console.log(video_metaobject);

            ipfs.add(new Buffer(JSON.stringify(video_metaobject)), (err, res) => {
                if (err) {
                    console.log(err);
                } else {
                    console.log('video metadata object is at ', res[0].Hash);
                }

            });

        }
    });

}<|endoftext|>


<commit_before>#!/usr/bin/env node
// original comes from https://github.com/nodejs/node/blob/master/tools/update-authors.js

// Usage: tools/update-author.js [--dry]
// Passing --dry will redirect output to stdout rather than write to 'AUTHORS'.
'use strict';
const {spawn} = require('child_process');
const fs = require('fs');
const readline = require('readline');

const log = spawn(
  'git',
  // Inspect author name/email and body.
  ['log', '--reverse', '--format=Author: %aN <%aE>\n%b'],
  {
    stdio: ['inherit', 'pipe', 'inherit']
  }
);
const rl = readline.createInterface({input: log.stdout});

let output;
if (process.argv.includes('--dry')) {
  output = process.stdout;
} else {
  output = fs.createWriteStream('AUTHORS');
}

output.write('# Authors ordered by first contribution.\n\n');

const seen = new Set();

const excludeEmails = [
  '<support@greenkeeper.io>',
  '<greenkeeper[bot]@users.noreply.github.com>'
];

// Support regular git author metadata, as well as `Author:` and
// `Co-authored-by:` in the message body. Both have been used in the past
// to indicate multiple authors per commit, with the latter standardized
// by GitHub now.
const authorRe = /(^Author:|^Co-authored-by:)\\s+(?<author>[^<]+)\\s+(?<email><[^>]+>)/i;

rl.on('line', line => {
  const match = line.match(authorRe);
  if (!match) return;

  const {author, email} = match.groups;

  if (seen.has(email) || excludeEmails.includes(email)) {
    return;
  }

  seen.add(email);
  output.write(`${author} ${email}\n`);
});

rl.on('close', () => {
  output.end('\n# Generated by scripts/update-authors.js\n');
});
<commit_msg>fix: regex in 'update-authors.js'<commit_after>#!/usr/bin/env node
// original comes from https://github.com/nodejs/node/blob/master/tools/update-authors.js

// Usage: tools/update-author.js [--dry]
// Passing --dry will redirect output to stdout rather than write to 'AUTHORS'.
'use strict';
const {spawn} = require('child_process');
const fs = require('fs');
const readline = require('readline');

const log = spawn(
  'git',
  // Inspect author name/email and body.
  ['log', '--reverse', '--format=Author: %aN <%aE>\n%b'],
  {
    stdio: ['inherit', 'pipe', 'inherit']
  }
);
const rl = readline.createInterface({input: log.stdout});

let output;
if (process.argv.includes('--dry')) {
  output = process.stdout;
} else {
  output = fs.createWriteStream('AUTHORS');
}

output.write('# Authors ordered by first contribution.\n\n');

const seen = new Set();

const excludeEmails = [
  '<support@greenkeeper.io>',
  '<greenkeeper[bot]@users.noreply.github.com>'
];

// Support regular git author metadata, as well as `Author:` and
// `Co-authored-by:` in the message body. Both have been used in the past
// to indicate multiple authors per commit, with the latter standardized
// by GitHub now.
const authorRe = /(^Author:|^Co-authored-by:)\s+(?<author>[^<]+)\s+(?<email><[^>]+>)/i;

rl.on('line', line => {
  const match = line.match(authorRe);
  if (!match) return;

  const {author, email} = match.groups;

  if (seen.has(email) || excludeEmails.includes(email)) {
    return;
  }

  seen.add(email);
  output.write(`${author} ${email}\n`);
});

rl.on('close', () => {
  output.end('\n# Generated by scripts/update-authors.js\n');
});
<|endoftext|>


<commit_before>Readium.Views.TocViewBase = Backbone.View.extend({

	el: "#readium-toc",

	initialize: function() {
		this.model.on("change", this.render, this);
		this.model.on("change:visible", this.setVisibility, this);
	},

	events: {
		"click a": "handleClick",
		"click #close-toc-button": "closeToc"
	},

	setVisibility: function() {
		this.$el.toggle(this.model.get("visible"));
	},

	handleClick: function(e) {
		e.preventDefault();
		href = $(e.currentTarget).attr("href");
		this.model.handleLink(href);
	},

	closeToc: function(e) {
		e.preventDefault();
		this.model.hide();
	}

});

Readium.Views.NcxTocView = Readium.Views.TocViewBase.extend({

	initialize: function() {
		Readium.Views.TocViewBase.prototype.initialize.call(this);
		this.nav_template = Handlebars.templates.ncx_nav_template;
	},

	render: function() {
		this.setVisibility();
		var ol = $("

");
		var navs = this.model.get("navs");
		for(var i = 0; i < navs.length; i++) {
			ol.append( this.nav_template(navs[i]) );
		}
		this.$('#toc-body').html("
" + (this.model.get("title") || "Contents") + "
")
		this.$('#toc-body').append(ol);
		this.$('#toc-body').append("
");
		return this;
	}

});

Readium.Views.XhtmlTocView = Readium.Views.TocViewBase.extend({

	// ------------------------------------------------------------------------------------ //
	//  "PUBLIC" METHODS (THE API)                                                          //
	// ------------------------------------------------------------------------------------ //

	render: function() {

		this.$('#toc-body').html( this.model.get("body").html() );
		this.formatPageListNavigation();
		this.$('#toc-body').append("
");
		return this;
	},

	// ------------------------------------------------------------------------------------ //
	//  "PRIVATE" HELPERS                                                                   //
	// ------------------------------------------------------------------------------------ //

	formatPageListNavigation : function () {

		var $navElements;
		var $pageListNavElement;
		var pageListData = [];

		// Search for a nav element with epub:type="page-list". A nav element of this type must not occur more than once.
		$navElements = this.$("nav");
		$pageListNavElement = $navElements.filter(function () {

			if ($(this).attr("epub:type") === 'page-list') {

				// Hide the standard XHTML page-list nav element, as we'll be displaying a select2 drop-down control for this.
				$(this).hide();
				return true;
			}
		});

		// Each nav element has a single ordered list of page numbers. Extract this data into an array so it can be
		//   loaded in the page-list control
		// TODO: span elements can be used to create sub-headings. Implement functionality to account for this at some point.
		$.each($('a', $pageListNavElement), function () {

			var $navTarget = $(this);
			pageListData.push({

				id : $navTarget.attr("href"),
				text : "Page-" + $navTarget.text()
			});
		});

		// Create the select2 control
		this.$("#toc-body").append("

");
		$("#page-list-select").select2({

			data : pageListData
		});

		$("#s2id_page-list-select").css("padding-left", "1.5em");
		$("#s2id_page-list-select").css("width", "20em");
	}
});<commit_msg>Select2 control can now be used to navigate to CFIs represented by each page.<commit_after>Readium.Views.TocViewBase = Backbone.View.extend({

	el: "#readium-toc",

	initialize: function() {
		this.model.on("change", this.render, this);
		this.model.on("change:visible", this.setVisibility, this);
	},

	events: {
		"click a": "handleClick",
		"click #close-toc-button": "closeToc"
	},

	setVisibility: function() {
		this.$el.toggle(this.model.get("visible"));
	},

	handleClick: function(e) {
		e.preventDefault();
		href = $(e.currentTarget).attr("href");
		this.model.handleLink(href);
	},

	handleSelect : function (e) {

		var href = e.val;
		this.model.handleLink(href);
	},

	closeToc: function(e) {
		e.preventDefault();
		this.model.hide();
	}

});

Readium.Views.NcxTocView = Readium.Views.TocViewBase.extend({

	initialize: function() {
		Readium.Views.TocViewBase.prototype.initialize.call(this);
		this.nav_template = Handlebars.templates.ncx_nav_template;
	},

	render: function() {
		this.setVisibility();
		var ol = $("

");
		var navs = this.model.get("navs");
		for(var i = 0; i < navs.length; i++) {
			ol.append( this.nav_template(navs[i]) );
		}
		this.$('#toc-body').html("
" + (this.model.get("title") || "Contents") + "
")
		this.$('#toc-body').append(ol);
		this.$('#toc-body').append("
");
		return this;
	}

});

Readium.Views.XhtmlTocView = Readium.Views.TocViewBase.extend({

	// ------------------------------------------------------------------------------------ //
	//  "PUBLIC" METHODS (THE API)                                                          //
	// ------------------------------------------------------------------------------------ //

	events : {

		"change #toc-body" : "handleSelect"
	},

	render: function() {

		this.$('#toc-body').html( this.model.get("body").html() );
		this.formatPageListNavigation();
		this.$('#toc-body').append("
");
		return this;
	},

	// ------------------------------------------------------------------------------------ //
	//  "PRIVATE" HELPERS                                                                   //
	// ------------------------------------------------------------------------------------ //

	formatPageListNavigation : function () {

		var $navElements;
		var $pageListNavElement;
		var pageListData = [];

		// Search for a nav element with epub:type="page-list". A nav element of this type must not occur more than once.
		$navElements = this.$("nav");
		$pageListNavElement = $navElements.filter(function () {

			if ($(this).attr("epub:type") === 'page-list') {

				// Hide the standard XHTML page-list nav element, as we'll be displaying a select2 drop-down control for this.
				$(this).hide();
				return true;
			}
		});

		// Each nav element has a single ordered list of page numbers. Extract this data into an array so it can be
		//   loaded in the page-list control
		// TODO: span elements can be used to create sub-headings. Implement functionality to account for this at some point.
		$.each($('a', $pageListNavElement), function () {

			var $navTarget = $(this);
			pageListData.push({

				id : $navTarget.attr("href"),
				text : "Page-" + $navTarget.text()
			});
		});

		// Create the select2 control
		this.$("#toc-body").append("

");
		$("#page-list-select").select2({

			data : pageListData
		});

		$("#s2id_page-list-select").css("padding-left", "1.5em");
		$("#s2id_page-list-select").css("width", "20em");

		// $("#toc-body").on("change", this.handleSelect);

	}
});<|endoftext|>


<commit_before>'use strict';

var listeners = [];

MeteorMathJax = {
  Helper    : MathJaxHelper,
  sourceUrl : 'https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML',
  /**
   * Notify all listeners that the MathJax script has been loaded.
   */
  ready : function () {
    if (!window.MathJax || !window.MathJax.Hub || typeof window.MathJax.Hub.Configured !== 'function') {
      throw new Error('Cannot call MeteorMathJax.ready() before MathJax is really loaded.');
    }
    // trigger all listeners
    while (listeners.length > 0) {
      listeners.pop().call(null, window.MathJax);
    }
  },
  /**
   * Call the given callback as soon as MathJax is loaded.
   * @param {Function} callback
   */
  onReady : function (callback) {
    if (!window.MathJax) {
      listeners.push(callback);
      window.MathJax = {
        AuthorInit: function () {
          // NOTE: Make sure any further tasks are scheduled after MathJax
          //       is fully configured and operational.
          MathJax.Hub.Register.StartupHook("Begin", function () {
            MeteorMathJax.ready();
          });
        }
      };
      // load the MathJax script
      $.getScript(this.sourceUrl);
    } else if (window.MathJax.Hub && typeof window.MathJax.Hub.Configured === 'function') {
      // it's already loaded ...
      callback(window.MathJax);
    } else {
      listeners.push(callback);
    }
  }
};

MeteorMathJax.onReady(function (MathJax) {
  MathJax.Hub.Config({
    skipStartupTypeset: true,
    showProcessingMessages: false,
    tex2jax: { inlineMath: [['$','$'],['\\(','\\)']] }
  });
});

function MathJaxHelper (options) {
  this.cache = {};
  this.options = {
    useCache: options.useCache !== undefined ? options.useCache : true,
    deferred: options.deferred !== undefined ? options.deferred : true,
  };
}

MathJaxHelper.prototype.getTemplate = function getTemplate () {

  var options = this.options;
  var cache = this.cache;

  var update = function (firstNode, lastNode) {
    var alreadyThere = false;
    $(firstNode).parent().contents().each(function (index, node) {
      // TODO add support for text nodes
      var cacheKey;
      if (node === firstNode) {
        alreadyThere = true;
      }
      if (alreadyThere && this.nodeType === 1) {
        cacheKey = options.useCache && node.innerHTML;
        if (options.useCache && cache[cacheKey]) {
          node.innerHTML = cache[cacheKey];
        } else {
          console.log('Typeset', this);
          MathJax.Hub.Queue(["Typeset", MathJax.Hub, this], function () {
            if (options.useCache)
              cache[cacheKey] = node.innerHTML;
          });
        }
      }
      return this !== lastNode;
    });
  };

  var template = new Template('mathjax', function () {
    var view = this, content = '';
    if (view.templateContentBlock) {
      content = Blaze._toText(view.templateContentBlock, HTML.TEXTMODE.STRING);
    }
    // NOTE: We can either return:
    //
    //       view.templateContentBlock
    //       or HTML.Raw(content);
    //
    return HTML.Raw(content);
  });

  template.onRendered(function () {
    var self = this;
    //----------------------------------------
    MeteorMathJax.onReady(function (MathJax) {
      if (options.deferred) {
        Meteor.defer(function () {
          update(self.firstNode, self.lastNode);
        });
      } else {
        update(self.firstNode, self.lastNode);
      }
    }); // ready
  });

  return template;
};

<commit_msg>Looks like "deferred" options is not needed<commit_after>'use strict';

var listeners = [];

MeteorMathJax = {
  Helper    : MathJaxHelper,
  sourceUrl : 'https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML',
  /**
   * Notify all listeners that the MathJax script has been loaded.
   */
  ready : function () {
    if (!window.MathJax || !window.MathJax.Hub || typeof window.MathJax.Hub.Configured !== 'function') {
      throw new Error('Cannot call MeteorMathJax.ready() before MathJax is really loaded.');
    }
    // trigger all listeners
    while (listeners.length > 0) {
      listeners.pop().call(null, window.MathJax);
    }
  },
  /**
   * Call the given callback as soon as MathJax is loaded.
   * @param {Function} callback
   */
  onReady : function (callback) {
    if (!window.MathJax) {
      listeners.push(callback);
      window.MathJax = {
        AuthorInit: function () {
          // NOTE: Make sure any further tasks are scheduled after MathJax
          //       is fully configured and operational.
          MathJax.Hub.Register.StartupHook("Begin", function () {
            MeteorMathJax.ready();
          });
        }
      };
      // load the MathJax script
      $.getScript(this.sourceUrl);
    } else if (window.MathJax.Hub && typeof window.MathJax.Hub.Configured === 'function') {
      // it's already loaded ...
      callback(window.MathJax);
    } else {
      listeners.push(callback);
    }
  }
};

MeteorMathJax.onReady(function (MathJax) {
  MathJax.Hub.Config({
    skipStartupTypeset: true,
    showProcessingMessages: false,
    tex2jax: { inlineMath: [['$','$'],['\\(','\\)']] }
  });
});

function MathJaxHelper (options) {
  this.cache = {};
  this.options = {
    useCache: options.useCache !== undefined ? options.useCache : true,
  };
}

MathJaxHelper.prototype.getTemplate = function getTemplate () {

  var options = this.options;
  var cache = this.cache;

  var update = function (firstNode, lastNode) {
    var alreadyThere = false;
    $(firstNode).parent().contents().each(function (index, node) {
      // TODO add support for text nodes
      var cacheKey;
      if (node === firstNode) {
        alreadyThere = true;
      }
      if (alreadyThere && this.nodeType === 1) {
        cacheKey = options.useCache && node.innerHTML;
        if (options.useCache && cache[cacheKey]) {
          node.innerHTML = cache[cacheKey];
        } else {
          MathJax.Hub.Queue(["Typeset", MathJax.Hub, this], function () {
            if (options.useCache)
              cache[cacheKey] = node.innerHTML;
          });
        }
      }
      return this !== lastNode;
    });
  };

  var template = new Template('mathjax', function () {
    var view = this, content = '';
    if (view.templateContentBlock) {
      content = Blaze._toText(view.templateContentBlock, HTML.TEXTMODE.STRING);
    }
    // NOTE: We can either return:
    //
    //       view.templateContentBlock
    //       or HTML.Raw(content);
    //
    return HTML.Raw(content);
  });

  template.onRendered(function () {
    var self = this;
    //----------------------------------------
    MeteorMathJax.onReady(function (MathJax) {
      update(self.firstNode, self.lastNode);
    }); // ready
  });

  return template;
};

<|endoftext|>


<commit_before>
/**
* Converts a value to a string appropriate for entry into a CSV table.  E.g., a string value will be surrounded by quotes.
* @param {string|number|object} theValue
* @param {string} sDelimiter The string delimiter.  Defaults to a double quote (") if omitted.
*/
function toCsvValue(theValue, sDelimiter) {
	var t = typeof (theValue), output;

	if (typeof (sDelimiter) === "undefined" || sDelimiter === null) {
		sDelimiter = '"';
	}

	if (t === "undefined" || t === null) {
		output = "";
	} else if (t === "string") {
		output = sDelimiter + theValue + sDelimiter;
	} else {
		output = String(theValue);
	}

	return output;
}

/**
* Converts an array of objects (with identical schemas) into a CSV table.
* @param {Array} objArray An array of objects.  Each object in the array must have the same property list.
* @param {string} sDelimiter The string delimiter.  Defaults to a double quote (") if omitted.
* @param {string} cDelimiter The column delimiter.  Defaults to a comma (,) if omitted.
* @return {string} The CSV equivalent of objArray.
*/
function toCsv(objArray, sDelimiter, cDelimiter) {
	var i, l, names = [], name, value, obj, row, output = "", n, nl;

	// Initialize default parameters.
	if (typeof (sDelimiter) === "undefined" || sDelimiter === null) {
		sDelimiter = '"';
	}
	if (typeof (cDelimiter) === "undefined" || cDelimiter === null) {
		cDelimiter = ",";
	}

	for (i = 0, l = objArray.length; i < l; i += 1) {
		// Get the names of the properties.
		obj = objArray[i];
		row = "";
		if (i === 0) {
			// Loop through the names
			for (name in obj) {
				if (obj.hasOwnProperty(name)) {
					names.push(name);
					row += [sDelimiter, name, sDelimiter, cDelimiter].join("");
				}
			}
			row = row.substring(0, row.length - 1);
			output += row;
		}

		output += "\n";
		row = "";
		for (n = 0, nl = names.length; n < nl; n += 1) {
			name = names[n];
			value = obj[name];
			if (n > 0) {
				row += ","
			}
			row += toCsvValue(value, '"');
		}
		output += row;
	}

	return output;
}

window.speciesReport = function( config ) {

	for( var column in config ) {

		this[ column ] = config[ column ];

	}

}

window.speciesReportCollection = function( speciesReports ) {

	var elements = [];

	for( var report in speciesReports ) {

		elements.push( report );

	}

	this.add = function( speciesReport ) {

		elements.push( speciesReport );

	}

	this.getAll = function() {

		return elements;

	}

}

window.onload = function() {

	var submitButton	= document.getElementById( "lagoonie-process" );
	var resetButton		= document.getElementById( "lagoonie-reset" );
	var speciesReports	= new window.speciesReportCollection();

	window.resetList	= function() {

		var textarea	= document.getElementById( "lagoonie-textarea" );

		textarea.value = "";

	}

	window.processList	= function() {

		var textarea	= document.getElementById( "lagoonie-textarea" ),
			listContent	= textarea.value,
			lines		= listContent.split(/\n/),
			result		= "",
			resultHTML	= document.getElementById( "lagoonie-result" );

		result = "
REPORT FOR: "+ lines[0] +"
"+ (lines.length-1) +" species observed.
"+
					"

Species Name	Observed	Notes
";

		for( var i = 1; i < lines.length; i++ ) {

			lines[i] = lines[i].trim();

			var chunks		= lines[i].split(' '),
				bandCode 	= chunks[0],
				count		= { total: 0, male: 0, female: 0, juvenile: 0, immature: 0, deceased: 0, notes: "" };

			if( !!! birdBrain[ bandCode ] ) {

				result += "
Unreadable line:	" + lines[i] + "
";

				continue;

			}

			for( var ii = 1; ii < chunks.length; ii++ ) {

				var	prevNote	= !! isNote ? isNote : false,
					isNote		= false;

				if( isNaN(chunks[ii]) ) {

					var chunkCount = "";

					for( var char = 0; char < chunks[ii].length; char++ ) {

						// todo: account for 'mmfmfmffmj'-style notation

						var character 		= chunks[ii][char],
							nextCharacter	= chunks[ii][char+1] ? chunks[ii][char+1] : null,
							breakFor		= false,
							addNotes		= function( singleCharacterChunk ) {

								if( !!singleCharacterChunk || (!!nextCharacter && isNaN(nextCharacter)) ) {

									count.notes 	+= ( count.notes && !prevNote ) ? "
" + chunks[ii].substring(char) + " " : chunks[ii].substring(char) + " ";
									isNote			= true;

									return true;

								}

								return false;

							}

						if( ! isNaN(character) ) {

							chunkCount += character;

						} else {

							switch( character ) {

								case "m":

									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.male += parseInt( chunkCount );
									else
										count.male++;

									break;

								case "f":

									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.female += parseInt( chunkCount );
									else
										count.female++;

									break;

								case "j":

									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.juvenile += parseInt( chunkCount );
									else
										count.juvenile++;

									break;

								case "i":

									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.immature += parseInt( chunkCount );
									else
										count.immature++;

									break;

								case "d":

									// append as note for eBird as well
									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.deceased += parseInt( chunkCount );
									else
										count.deceased++;

									break;

								default:

									if( addNotes(true) ) {

										breakFor = true;

										break;

									}

									break;

							}

							chunkCount = "";

						}

						if( !!breakFor )
							break;

					}

					continue;

				}

				count.total += parseInt( chunks[ii] );

			}

			var fullNotes 	= ( count.female ? count.female + "f " : "" ) + ( count.male ? count.male + "m " : "" ) + ( count.immature ? count.immature + "imm " : "" ) + ( count.juvenile ? count.juvenile + "juv" : "" ) + ( count.deceased ? count.deceased + "dec" : "" ) + count.notes + ( count.deceased ? count.deceased + " found deceased." : "" ),
				fullCount	= ( count.total + count.male + count.female + count.juvenile + count.immature + count.deceased );

			result += "
" + birdBrain[ bandCode ].name + "	" + ( count.total + count.male + count.female+count.juvenile + count.immature + count.deceased ) + " "+ ( count.female ? count.female + "f " : "" ) + ( count.male ? count.male + "m " : "" ) + ( count.immature ? count.immature + "imm " : "" ) + ( count.juvenile ? count.juvenile + "juv" : "" ) + ( count.deceased ? count.deceased + "dec" : "" ) + "	"+ count.notes + ( count.deceased ? count.deceased + " found deceased." : "" ) +"
";

			speciesReports.add( new window.speciesReport({

					"Common Name":					birdBrain[ bandCode ].name,
					"Genus":						"",
					"Species":						"",
					"Number":						fullCount,
					"Species Comments":				fullNotes,
					"Location Name":				"My test location",
					"Latitude":						"",
					"Longitude":					"",
					"Date":							"09/07/2013",
					"Start Time":					"13:30",
					"State/Province":				"ON",
					"Country Code":					"CA",
					"Protocol":						"Traveling",
					"Number of Observers":			1,
					"Duration":						60,
					"All observations reported?":	"Y",
					"Effort Distance Miles":		1,
					"Effort Area Acres":			"",
					"Submission Comments":			"This is a test.."

				})

			);

		}

		var csvResult = toCsv( speciesReports.getAll() ).split( "\n" ).slice( 1 ).join( "\n" );

		result += "
";

		result += "<textarea style='width: 25em; height: 15em;'>"+ csvResult +"</textarea>";

		resultHTML.innerHTML = result;

		speciesReports = new window.speciesReportCollection();

	}

	submitButton.addEventListener( 'touchend', window.processList );
	submitButton.addEventListener( 'click', window.processList );

	resetButton.addEventListener( 'touchend', window.resetList );
	resetButton.addEventListener( 'click', window.resetList );

}<commit_msg>Added processor for date, time, duration, distance<commit_after>
/**
* Converts a value to a string appropriate for entry into a CSV table.  E.g., a string value will be surrounded by quotes.
* @param {string|number|object} theValue
* @param {string} sDelimiter The string delimiter.  Defaults to a double quote (") if omitted.
*/
function toCsvValue(theValue, sDelimiter) {
	var t = typeof (theValue), output;

	if (typeof (sDelimiter) === "undefined" || sDelimiter === null) {
		sDelimiter = '"';
	}

	if (t === "undefined" || t === null) {
		output = "";
	} else if (t === "string") {
		output = sDelimiter + theValue + sDelimiter;
	} else {
		output = String(theValue);
	}

	return output;
}

/**
* Converts an array of objects (with identical schemas) into a CSV table.
* @param {Array} objArray An array of objects.  Each object in the array must have the same property list.
* @param {string} sDelimiter The string delimiter.  Defaults to a double quote (") if omitted.
* @param {string} cDelimiter The column delimiter.  Defaults to a comma (,) if omitted.
* @return {string} The CSV equivalent of objArray.
*/
function toCsv(objArray, sDelimiter, cDelimiter) {
	var i, l, names = [], name, value, obj, row, output = "", n, nl;

	// Initialize default parameters.
	if (typeof (sDelimiter) === "undefined" || sDelimiter === null) {
		sDelimiter = '"';
	}
	if (typeof (cDelimiter) === "undefined" || cDelimiter === null) {
		cDelimiter = ",";
	}

	for (i = 0, l = objArray.length; i < l; i += 1) {
		// Get the names of the properties.
		obj = objArray[i];
		row = "";
		if (i === 0) {
			// Loop through the names
			for (name in obj) {
				if (obj.hasOwnProperty(name)) {
					names.push(name);
					row += [sDelimiter, name, sDelimiter, cDelimiter].join("");
				}
			}
			row = row.substring(0, row.length - 1);
			output += row;
		}

		output += "\n";
		row = "";
		for (n = 0, nl = names.length; n < nl; n += 1) {
			name = names[n];
			value = obj[name];
			if (n > 0) {
				row += ","
			}
			row += toCsvValue(value, '"');
		}
		output += row;
	}

	return output;
}

window.speciesReport = function( config ) {

	for( var column in config ) {

		this[ column ] = config[ column ];

	}

}

window.speciesReportCollection = function( speciesReports ) {

	var elements = [];

	for( var report in speciesReports ) {

		elements.push( report );

	}

	this.add = function( speciesReport ) {

		elements.push( speciesReport );

	}

	this.getAll = function() {

		return elements;

	}

}

window.onload = function() {

	var submitButton	= document.getElementById( "lagoonie-process" );
	var resetButton		= document.getElementById( "lagoonie-reset" );
	var speciesReports	= new window.speciesReportCollection();

	window.resetList	= function() {

		var textarea	= document.getElementById( "lagoonie-textarea" );

		textarea.value = "";

	}

	window.processMetadata	= function( lines ) {

		var lineArr 	= lines[1].split(' '),
			location	= lines[0];

		return {

			location:	location,
			date:		lineArr[0],
			time:		lineArr[1],
			duration:	( !! lineArr[2] ) ? lineArr[2] : "",
			distance:	( !! lineArr[3] ) ? lineArr[3] : ""

		};

	}

	window.processList	= function() {

		var textarea	= document.getElementById( "lagoonie-textarea" ),
			listContent	= textarea.value,
			lines		= listContent.split(/\n/),
			result		= "",
			resultHTML	= document.getElementById( "lagoonie-result" ),
			metadata	= window.processMetadata( lines );

		// if km is appended to distance, convert to miles
		if( metadata.distance.search(/km/i) != -1 )
			metadata.distance = parseFloat( metadata.distance.slice(0, -2) * 0.6214 ).toFixed(2);

		result = "
REPORT FOR: "+ lines[0] +"
"+ (lines.length-1) +" species observed.
"+
					"

Species Name	Observed	Notes
";

		for( var i = 2; i < lines.length; i++ ) {

			lines[i] = lines[i].trim();

			var chunks		= lines[i].split(' '),
				bandCode 	= chunks[0],
				count		= { total: 0, male: 0, female: 0, juvenile: 0, immature: 0, deceased: 0, notes: "" };

			if( !!! birdBrain[ bandCode ] ) {

				result += "
Unreadable line:	" + lines[i] + "
";

				continue;

			}

			for( var ii = 1; ii < chunks.length; ii++ ) {

				var	prevNote	= !! isNote ? isNote : false,
					isNote		= false;

				if( isNaN(chunks[ii]) ) {

					var chunkCount = "";

					for( var char = 0; char < chunks[ii].length; char++ ) {

						// todo: account for 'mmfmfmffmj'-style notation

						var character 		= chunks[ii][char],
							nextCharacter	= chunks[ii][char+1] ? chunks[ii][char+1] : null,
							breakFor		= false,
							addNotes		= function( singleCharacterChunk ) {

								if( !!singleCharacterChunk || (!!nextCharacter && isNaN(nextCharacter)) ) {

									count.notes 	+= ( count.notes && !prevNote ) ? "
" + chunks[ii].substring(char) + " " : chunks[ii].substring(char) + " ";
									isNote			= true;

									return true;

								}

								return false;

							}

						if( ! isNaN(character) ) {

							chunkCount += character;

						} else {

							switch( character ) {

								case "m":

									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.male += parseInt( chunkCount );
									else
										count.male++;

									break;

								case "f":

									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.female += parseInt( chunkCount );
									else
										count.female++;

									break;

								case "j":

									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.juvenile += parseInt( chunkCount );
									else
										count.juvenile++;

									break;

								case "i":

									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.immature += parseInt( chunkCount );
									else
										count.immature++;

									break;

								case "d":

									// append as note for eBird as well
									if( addNotes() ) {

										breakFor = true;

										break;

									}

									if( chunkCount )
										count.deceased += parseInt( chunkCount );
									else
										count.deceased++;

									break;

								default:

									if( addNotes(true) ) {

										breakFor = true;

										break;

									}

									break;

							}

							chunkCount = "";

						}

						if( !!breakFor )
							break;

					}

					continue;

				}

				count.total += parseInt( chunks[ii] );

			}

			var fullNotes 	= ( count.female ? count.female + "f " : "" ) + ( count.male ? count.male + "m " : "" ) + ( count.immature ? count.immature + "imm " : "" ) + ( count.juvenile ? count.juvenile + "juv" : "" ) + ( count.deceased ? count.deceased + "dec" : "" ) + count.notes + ( count.deceased ? count.deceased + " found deceased." : "" ),
				fullCount	= ( count.total + count.male + count.female + count.juvenile + count.immature + count.deceased );

			result += "
" + birdBrain[ bandCode ].name + "	" + ( count.total + count.male + count.female+count.juvenile + count.immature + count.deceased ) + " "+ ( count.female ? count.female + "f " : "" ) + ( count.male ? count.male + "m " : "" ) + ( count.immature ? count.immature + "imm " : "" ) + ( count.juvenile ? count.juvenile + "juv" : "" ) + ( count.deceased ? count.deceased + "dec" : "" ) + "	"+ count.notes + ( count.deceased ? count.deceased + " found deceased." : "" ) +"
";

			var date = new Date();

			// assume protocol based on metadata given
			if( !! metadata.distance && !! metadata.duration )
				metadata.protocol	= "Traveling";
			else if( !! metadata.duration && ! metadata.distance )
				metadata.protocol	= "Stationary";
			else
				metadata.protocol	= "Casual";

			// adding year, assuming current year
			if( metadata.date.length == 5 )
				metadata.date += "-" + date.getFullYear();

			metadata.date = metadata.date.replace( /-/g, "/" );

			speciesReports.add( new window.speciesReport({

					"Common Name":					birdBrain[ bandCode ].name,
					"Genus":						"",
					"Species":						"",
					"Number":						fullCount,
					"Species Comments":				fullNotes,
					"Location Name":				metadata.location,
					"Latitude":						"",
					"Longitude":					"",
					"Date":							metadata.date,
					"Start Time":					metadata.time,
					"State/Province":				"ON",
					"Country Code":					"CA",
					"Protocol":						metadata.protocol,
					"Number of Observers":			1,
					"Duration":						metadata.duration,
					"All observations reported?":	"Y",
					"Effort Distance Miles":		metadata.distance,
					"Effort Area Acres":			"",
					"Submission Comments":			"List generated using Lagoonie, written by Rob Porter."

				})

			);

		}

		var csvResult = toCsv( speciesReports.getAll() ).split( "\n" ).slice( 1 ).join( "\n" );

		result += "
";

		result += "<textarea style='width: 25em; height: 15em;'>"+ csvResult +"</textarea>";

		resultHTML.innerHTML = result;

		speciesReports = new window.speciesReportCollection();

		encodedUri = encodeURI( "data:text/csv;charset=utf-8," + csvResult );

		var link = document.createElement("a");
		link.setAttribute("href", encodedUri);
		link.setAttribute("target", "_blank" );
		link.setAttribute("download", "ebird-ready.csv");
		link.innerHTML = "DOWNLOAD";

		resultHTML.appendChild( link );

		//link.click(); // This will download the data file named "my_data.csv".

	}

	submitButton.addEventListener( 'touchend', window.processList );
	submitButton.addEventListener( 'click', window.processList );

	resetButton.addEventListener( 'touchend', window.resetList );
	resetButton.addEventListener( 'click', window.resetList );

}<|endoftext|>


<commit_before>

// Immediately Invoked Function Expression (IIFE)
// So how then do we define more functions without cluttering the namespace and
// without exposing the implementation? This is a job for closures.
// closure vs. Immediately Invoked Function Expression: http://benalman.com/news/2010/11/immediately-invoked-function-expression/#iife
(function($) {

    var l_default_options = {
        'fields_insert_selector': '.lagoudia_div_form_fields'
    };

    var l_handle_field_by_field_type = {
        'text': function(htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendInputElement(name, 'text', recordFieldValue);
        },
        'textarea': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendTextareaElement(name, recordFieldValue, fieldDefinition.rows, fieldDefinition.cols);
        },
        'hidden': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendInputElement(name, 'hidden', recordFieldValue);
        },
        'yesnocheckboxes': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendBoxElements(name, 'radio', ['Yes', 'No'], ['Yes', 'No'], recordFieldValue);
        },
        'multiselect': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendBoxElements(name, 'checkbox', ['Basel', 'Luzern', 'Zürich', 'Genf', 'Chur'], ['1', '2', '3', '4', '5'], recordFieldValue);
        },
        'select': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendSelectElements(name, ['Basel', 'Luzern', 'Zürich', 'Genf', 'Chur'], ['1', '2', '3', '4', '5'], recordFieldValue);
        }
    };

    $.fn.lagoudia = function(action, options) {

        var l_combined_options = $.extend(l_default_options, options);

        assertRequiredLagoudiaOptions(l_combined_options);

        if (action == 'load') {
            lagoudiaLoad(this, l_combined_options);
        }
        else if (action == 'save') {
            lagoudiaSave(this, l_combined_options);
        }
        else {
            throw 'lagoudia: unknown action: ' + action;
        }
    };

    function assertRequiredLagoudiaOptions(combinedOptions) {

        if (combinedOptions.server_url == null) {
            throw 'lagoudia: required option "server_url" is not set';
        }

        if (combinedOptions.field_definitions == null) {
            throw 'lagoudia: required option "field_definitions" is not set';
        }
    }

    function assertProperty(data, propname, exceptionText) {

        if (!data.hasOwnProperty(propname)) {
            throw exceptionText;
        }
    }

    function lagoudiaLoad(t, options) {

        // get data from server
        $.get(options.server_url, options.server_data, function (record) {

            var l_html_string_builder = new HtmlStringBuilder();

            // iterate over all own properties of field definitions
            for (var l_field_name in options.field_definitions) {
                if (options.field_definitions.hasOwnProperty(l_field_name)) {

                    assertProperty(record, l_field_name, 'lagoudia: data coming from ' + options.server_url + ' has no property ' + l_field_name);

                    // current field defintion
                    var l_field_definition = options.field_definitions[l_field_name];
                    // current field value
                    var l_record_field_value = record[l_field_name];

                    handleField(l_html_string_builder, l_field_name, l_field_definition, record, l_record_field_value);
                }
            }

            t.append(l_html_string_builder.toString());
        });
    }

    function handleField(htmlStringBuilder, name, fieldDefinition, record, recordFieldValue) {

        // get fieldType, this can be a text or a function
        var l_field_type_text_or_function = fieldDefinition.fieldType;
        var l_field_type = null;

        if (l_field_type_text_or_function instanceof Function) {
            // call function to get field type
            // using a function it is possible that the type of one field depends on current record-data
            l_field_type = l_field_type_text_or_function(record);
        } else {
            // get field-type directly
            l_field_type = l_field_type_text_or_function;
        }

        assertProperty(l_handle_field_by_field_type, l_field_type, 'lagoudia: for field '+name+' there is no template with this name: ' + l_field_type);
        var l_handle_field_function = l_handle_field_by_field_type[l_field_type];

        l_handle_field_function(htmlStringBuilder, name, fieldDefinition, recordFieldValue);
    }

    function lagoudiaSave(t, options) {

        $.ajax(options.server_url + '?employee_id=20', {
            'type': 'PUT',
            'data': options.server_data,
            sucess: function(data, textStatus, jqXHR) {

            }

        });
    }

    // Initializes a new instance of the StringBuilder class
    // and appends the given value if supplied
    // ReSharper disable once InconsistentNaming
    function HtmlStringBuilder(value) {
        this.strings = new Array("");
        this.append(value);
    }

    // Appends the given value to the end of this instance.
    HtmlStringBuilder.prototype.append = function (value) {
        if (value) {
            this.strings.push(value);
        }
        return this;
    }

    HtmlStringBuilder.prototype.appendWithQuotes = function (value) {
        if (value) {
            this.append('\'').append(value).append('\'');
        }
        return this;
    }

    HtmlStringBuilder.prototype.htmlEncode = function (value) {

        // http://stackoverflow.com/questions/1219860/html-encoding-in-javascript-jquery
        return String(value)
                    .replace(/&/g, '&')
                    .replace(/"/g, '"')
                    .replace(/'/g, ''')
                    .replace(/</g, '<')
                    .replace(/>/g, '>');
    }

    HtmlStringBuilder.prototype.htmlDecode = function (value) {
        return $('<div/>').html(value).text();
    }

    HtmlStringBuilder.prototype.appendInputElement = function (name, type, value) {

        this.appendElement('input',
        {
            'type': type,
            'name': name,
            'value': this.htmlEncode(value),
            'class':'form-control'
        },
        '');

        return this;
    }

    HtmlStringBuilder.prototype.appendTextareaElement = function (name, value, rows, cols) {

        this.appendElement('textarea',
        {
            'cols': cols,
            'rows': rows,
            'name': name,
            'value': this.htmlEncode(value),
            'class': 'form-control'
        },
        '');

        return this;
    }

    HtmlStringBuilder.prototype.appendBoxElements = function (name, type, texts, values, selectedValue) {

        this.appendBeginElement('div', { 'class': 'form-control' });

        for (var l_i = 0; l_i < values.length; l_i++) {

            var l_html_attributes = {
                'type': type,
                'name': name,
                'value': values[l_i]
            };

            // also check if selectedValue is an array
            if ((selectedValue == values[l_i]) || (selectedValue.indexOf(values[l_i])!=-1)) {
                l_html_attributes.checked = 'checked';
            }

            this.appendElement('input',
            l_html_attributes,
            '');
            this.appendSpan(texts[l_i]);
        }

        this.appendEndElement('div');

        return this;
    }

    HtmlStringBuilder.prototype.appendSelectElements = function (name, texts, values, value) {

        this.appendBeginElement('select', { 'class': 'form-control', 'name': name });

        for (var l_i = 0; l_i < values.length; l_i++) {

            var l_html_attributes = {
                'value': values[l_i]
            };

            if (value == values[l_i]) {
                l_html_attributes.selected = 'selected';
            }

            this.appendElement('option',
            l_html_attributes,
            texts[l_i]);
        }

        this.appendEndElement('select');

        return this;
    }

    HtmlStringBuilder.prototype.appendLabel = function (name, displaylabel) {

        this.appendElement('label',
        {
        'for': name
        },
        displaylabel);

        return this;
    }

    HtmlStringBuilder.prototype.appendSpan = function (text) {

        this.appendElement('span',
        {
        },
        text);

        return this;
    }

    HtmlStringBuilder.prototype.appendElement = function (htmlElementName, htmlAttributes, value) {
        this.append('<').append(htmlElementName);

        for (var l_prop in htmlAttributes) {
            this.append(' ');
            this.append(l_prop).append('=').appendWithQuotes(htmlAttributes[l_prop]);
        }
        this.append(' ');

        this.append('>');
        this.append(this.htmlEncode(value));
        this.append('</').append(htmlElementName).append('>');
        return this;
    }

    HtmlStringBuilder.prototype.appendBeginElement = function (htmlElementName, htmlAttributes) {
        this.append('<').append(htmlElementName);

        for (var l_prop in htmlAttributes) {
            this.append(' ');
            this.append(l_prop).append('=').appendWithQuotes(htmlAttributes[l_prop]);
        }
        this.append(' ');

        this.append('>');
        return this;
    }

    HtmlStringBuilder.prototype.appendEndElement = function (htmlElementName) {

        this.append('</').append(htmlElementName).append('>');
        return this;
    }

    // Clears the string buffer
    HtmlStringBuilder.prototype.clear = function () {
        this.strings.length = 1;
    }

    // Converts this instance to a String.
    HtmlStringBuilder.prototype.toString = function () {
        return this.strings.join("");
    }

}(jQuery));

<commit_msg>small test change<commit_after>

// Immediately Invoked Function Expression (IIFE) (2)
// So how then do we define more functions without cluttering the namespace and
// without exposing the implementation? This is a job for closures.
// closure vs. Immediately Invoked Function Expression: http://benalman.com/news/2010/11/immediately-invoked-function-expression/#iife
(function($) {

    var l_default_options = {
        'fields_insert_selector': '.lagoudia_div_form_fields'
    };

    var l_handle_field_by_field_type = {
        'text': function(htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendInputElement(name, 'text', recordFieldValue);
        },
        'textarea': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendTextareaElement(name, recordFieldValue, fieldDefinition.rows, fieldDefinition.cols);
        },
        'hidden': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendInputElement(name, 'hidden', recordFieldValue);
        },
        'yesnocheckboxes': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendBoxElements(name, 'radio', ['Yes', 'No'], ['Yes', 'No'], recordFieldValue);
        },
        'multiselect': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendBoxElements(name, 'checkbox', ['Basel', 'Luzern', 'Zürich', 'Genf', 'Chur'], ['1', '2', '3', '4', '5'], recordFieldValue);
        },
        'select': function (htmlStringBuilder, name, fieldDefinition, recordFieldValue) {
            htmlStringBuilder.appendLabel(name, fieldDefinition.displaylabel);
            htmlStringBuilder.appendSelectElements(name, ['Basel', 'Luzern', 'Zürich', 'Genf', 'Chur'], ['1', '2', '3', '4', '5'], recordFieldValue);
        }
    };

    $.fn.lagoudia = function(action, options) {

        var l_combined_options = $.extend(l_default_options, options);

        assertRequiredLagoudiaOptions(l_combined_options);

        if (action == 'load') {
            lagoudiaLoad(this, l_combined_options);
        }
        else if (action == 'save') {
            lagoudiaSave(this, l_combined_options);
        }
        else {
            throw 'lagoudia: unknown action: ' + action;
        }
    };

    function assertRequiredLagoudiaOptions(combinedOptions) {

        if (combinedOptions.server_url == null) {
            throw 'lagoudia: required option "server_url" is not set';
        }

        if (combinedOptions.field_definitions == null) {
            throw 'lagoudia: required option "field_definitions" is not set';
        }
    }

    function assertProperty(data, propname, exceptionText) {

        if (!data.hasOwnProperty(propname)) {
            throw exceptionText;
        }
    }

    function lagoudiaLoad(t, options) {

        // get data from server
        $.get(options.server_url, options.server_data, function (record) {

            var l_html_string_builder = new HtmlStringBuilder();

            // iterate over all own properties of field definitions
            for (var l_field_name in options.field_definitions) {
                if (options.field_definitions.hasOwnProperty(l_field_name)) {

                    assertProperty(record, l_field_name, 'lagoudia: data coming from ' + options.server_url + ' has no property ' + l_field_name);

                    // current field defintion
                    var l_field_definition = options.field_definitions[l_field_name];
                    // current field value
                    var l_record_field_value = record[l_field_name];

                    handleField(l_html_string_builder, l_field_name, l_field_definition, record, l_record_field_value);
                }
            }

            t.append(l_html_string_builder.toString());
        });
    }

    function handleField(htmlStringBuilder, name, fieldDefinition, record, recordFieldValue) {

        // get fieldType, this can be a text or a function
        var l_field_type_text_or_function = fieldDefinition.fieldType;
        var l_field_type = null;

        if (l_field_type_text_or_function instanceof Function) {
            // call function to get field type
            // using a function it is possible that the type of one field depends on current record-data
            l_field_type = l_field_type_text_or_function(record);
        } else {
            // get field-type directly
            l_field_type = l_field_type_text_or_function;
        }

        assertProperty(l_handle_field_by_field_type, l_field_type, 'lagoudia: for field '+name+' there is no template with this name: ' + l_field_type);
        var l_handle_field_function = l_handle_field_by_field_type[l_field_type];

        l_handle_field_function(htmlStringBuilder, name, fieldDefinition, recordFieldValue);
    }

    function lagoudiaSave(t, options) {

        $.ajax(options.server_url + '?employee_id=20', {
            'type': 'PUT',
            'data': options.server_data,
            sucess: function(data, textStatus, jqXHR) {

            }

        });
    }

    // Initializes a new instance of the StringBuilder class
    // and appends the given value if supplied
    // ReSharper disable once InconsistentNaming
    function HtmlStringBuilder(value) {
        this.strings = new Array("");
        this.append(value);
    }

    // Appends the given value to the end of this instance.
    HtmlStringBuilder.prototype.append = function (value) {
        if (value) {
            this.strings.push(value);
        }
        return this;
    }

    HtmlStringBuilder.prototype.appendWithQuotes = function (value) {
        if (value) {
            this.append('\'').append(value).append('\'');
        }
        return this;
    }

    HtmlStringBuilder.prototype.htmlEncode = function (value) {

        // http://stackoverflow.com/questions/1219860/html-encoding-in-javascript-jquery
        return String(value)
                    .replace(/&/g, '&')
                    .replace(/"/g, '"')
                    .replace(/'/g, ''')
                    .replace(/</g, '<')
                    .replace(/>/g, '>');
    }

    HtmlStringBuilder.prototype.htmlDecode = function (value) {
        return $('<div/>').html(value).text();
    }

    HtmlStringBuilder.prototype.appendInputElement = function (name, type, value) {

        this.appendElement('input',
        {
            'type': type,
            'name': name,
            'value': this.htmlEncode(value),
            'class':'form-control'
        },
        '');

        return this;
    }

    HtmlStringBuilder.prototype.appendTextareaElement = function (name, value, rows, cols) {

        this.appendElement('textarea',
        {
            'cols': cols,
            'rows': rows,
            'name': name,
            'value': this.htmlEncode(value),
            'class': 'form-control'
        },
        '');

        return this;
    }

    HtmlStringBuilder.prototype.appendBoxElements = function (name, type, texts, values, selectedValue) {

        this.appendBeginElement('div', { 'class': 'form-control' });

        for (var l_i = 0; l_i < values.length; l_i++) {

            var l_html_attributes = {
                'type': type,
                'name': name,
                'value': values[l_i]
            };

            // also check if selectedValue is an array
            if ((selectedValue == values[l_i]) || (selectedValue.indexOf(values[l_i])!=-1)) {
                l_html_attributes.checked = 'checked';
            }

            this.appendElement('input',
            l_html_attributes,
            '');
            this.appendSpan(texts[l_i]);
        }

        this.appendEndElement('div');

        return this;
    }

    HtmlStringBuilder.prototype.appendSelectElements = function (name, texts, values, value) {

        this.appendBeginElement('select', { 'class': 'form-control', 'name': name });

        for (var l_i = 0; l_i < values.length; l_i++) {

            var l_html_attributes = {
                'value': values[l_i]
            };

            if (value == values[l_i]) {
                l_html_attributes.selected = 'selected';
            }

            this.appendElement('option',
            l_html_attributes,
            texts[l_i]);
        }

        this.appendEndElement('select');

        return this;
    }

    HtmlStringBuilder.prototype.appendLabel = function (name, displaylabel) {

        this.appendElement('label',
        {
        'for': name
        },
        displaylabel);

        return this;
    }

    HtmlStringBuilder.prototype.appendSpan = function (text) {

        this.appendElement('span',
        {
        },
        text);

        return this;
    }

    HtmlStringBuilder.prototype.appendElement = function (htmlElementName, htmlAttributes, value) {
        this.append('<').append(htmlElementName);

        for (var l_prop in htmlAttributes) {
            this.append(' ');
            this.append(l_prop).append('=').appendWithQuotes(htmlAttributes[l_prop]);
        }
        this.append(' ');

        this.append('>');
        this.append(this.htmlEncode(value));
        this.append('</').append(htmlElementName).append('>');
        return this;
    }

    HtmlStringBuilder.prototype.appendBeginElement = function (htmlElementName, htmlAttributes) {
        this.append('<').append(htmlElementName);

        for (var l_prop in htmlAttributes) {
            this.append(' ');
            this.append(l_prop).append('=').appendWithQuotes(htmlAttributes[l_prop]);
        }
        this.append(' ');

        this.append('>');
        return this;
    }

    HtmlStringBuilder.prototype.appendEndElement = function (htmlElementName) {

        this.append('</').append(htmlElementName).append('>');
        return this;
    }

    // Clears the string buffer
    HtmlStringBuilder.prototype.clear = function () {
        this.strings.length = 1;
    }

    // Converts this instance to a String.
    HtmlStringBuilder.prototype.toString = function () {
        return this.strings.join("");
    }

}(jQuery));

<|endoftext|>