<commit_before>describe('Expandable', function () {
	var expandable = [
		$("#expandable-1").expandable(),
		$("#expandable-2").expandable({'icon': false}),
		$("#expandable-3").expandable({'open': true })
	];

	it('Should be defined', function () {
		expect(ch.util.hasOwn(ch, 'Expandable')).toBeTruthy();
		expect(typeof ch.Expandable).toEqual('function');
	});

	describe('By defult', function () {
		it('Shold have a icon', function () {
			expect(document.querySelector('.ch-expandable-trigger.ch-expandable-ico').nodeType).toEqual(1);
		});

		it('Shold be closed', function () {
			expect(document.querySelector('.ch-expandable-content.ch-hide').nodeType).toEqual(1);
		});
	});

	describe('Shold have the following public properties:', function () {
		var widget = expandable[0];

		it('.element', function () {
			expect(ch.util.hasOwn(widget, 'element')).toBeTruthy();
			expect(widget.element.nodeType).toEqual(1);
		});

		it('.type / .name', function () {
			expect(ch.util.hasOwn(widget, 'type')).toBeTruthy();
			expect(typeof widget.type).toEqual('string');
			expect(widget.type).toEqual('expandable');
		});

		it('.constructor', function () {
			expect(ch.util.hasOwn(widget, 'constructor')).toBeTruthy();
			expect(typeof widget.constructor).toEqual('function');
		});

		it('.uid', function () {
			expect(typeof widget.uid).toEqual('number');
		});

	});

	describe('Shold have the following public methods:', function () {
		var widget = expandable[0];

		it('.hide()', function () {
			expect(ch.util.hasOwn(widget, 'hide')).toBeTruthy();
		});

		it('.isActive()', function () {
			expect(ch.util.hasOwn(widget, 'isActive')).toBeTruthy();
		});

		it('.off()', function () {
			expect(ch.util.hasOwn(widget, 'off')).toBeTruthy();
		});

		it('.on()', function () {
			expect(ch.util.hasOwn(widget, 'on')).toBeTruthy();
		});

		it('.once()', function () {
			expect(ch.util.hasOwn(widget, 'once')).toBeTruthy();
		});

		it('.show()', function () {
			expect(ch.util.hasOwn(widget, 'show')).toBeTruthy();
		});

		it('.trigger()', function () {
			expect(ch.util.hasOwn(widget, 'trigger')).toBeTruthy();
		});
	});

	describe('Shold have the following ID and Classnames:', function () {

		it('#ch-expandable-1', function () {
			expect(document.querySelector('#ch-expandable-1').nodeType).toEqual(1);
		});

		it('.ch-expandable', function () {
			expect(document.querySelector('.ch-expandable').nodeType).toEqual(1);
		});

		it('.ch-expandable-trigger', function () {
			expect(document.querySelector('.ch-expandable-trigger').nodeType).toEqual(1);
		});

		it('.ch-user-no-select', function () {
			expect(document.querySelector('.ch-expandable-trigger.ch-user-no-select').nodeType).toEqual(1);
		});

		it('.ch-expandable-content', function () {
			expect(document.querySelector('.ch-expandable-content').nodeType).toEqual(1);
		});

		it('.ch-expandable-ico', function () {
			expect(document.querySelector('.ch-expandable-trigger.ch-expandable-ico').nodeType).toEqual(1);
		});

		it('.ch-hide', function () {
			expect(document.querySelector('.ch-expandable-content.ch-hide').nodeType).toEqual(1);
		});
	});

});<commit_msg>Expandable: Adds test to public methods<commit_after>describe('Expandable', function () {
	var expandable = [
		$("#expandable-1").expandable(),
		$("#expandable-2").expandable({'icon': false}),
		$("#expandable-3").expandable({'open': true })
	];

	it('Should be defined', function () {
		expect(ch.util.hasOwn(ch, 'Expandable')).toBeTruthy();
		expect(typeof ch.Expandable).toEqual('function');
	});

	describe('Shold have the following public properties:', function () {

		it('.element', function () {
			expect(ch.util.hasOwn(expandable[0], 'element')).toBeTruthy();
			expect(expandable[0].element.nodeType).toEqual(1);
		});

		it('.type / .name', function () {
			expect(ch.util.hasOwn(expandable[0], 'type')).toBeTruthy();
			expect(typeof expandable[0].type).toEqual('string');
			expect(expandable[0].type).toEqual('expandable');
		});

		it('.constructor', function () {
			expect(ch.util.hasOwn(expandable[0], 'constructor')).toBeTruthy();
			expect(typeof expandable[0].constructor).toEqual('function');
		});

		it('.uid', function () {
			expect(typeof expandable[0].uid).toEqual('number');
		});

	});

	describe('Shold have the following public methods:', function () {

		it('.hide()', function () {
			expect(ch.util.hasOwn(expandable[0], 'hide')).toBeTruthy();
		});

		it('.isActive()', function () {
			expect(ch.util.hasOwn(expandable[0], 'isActive')).toBeTruthy();
		});

		it('.off()', function () {
			expect(ch.util.hasOwn(expandable[0], 'off')).toBeTruthy();
		});

		it('.on()', function () {
			expect(ch.util.hasOwn(expandable[0], 'on')).toBeTruthy();
		});

		it('.once()', function () {
			expect(ch.util.hasOwn(expandable[0], 'once')).toBeTruthy();
		});

		it('.show()', function () {
			expect(ch.util.hasOwn(expandable[0], 'show')).toBeTruthy();
		});

		it('.trigger()', function () {
			expect(ch.util.hasOwn(expandable[0], 'trigger')).toBeTruthy();
		});
	});

	describe('Shold have the following ID and Classnames:', function () {

		it('#ch-expandable-1', function () {
			expect(document.querySelector('#ch-expandable-1').nodeType).toEqual(1);
		});

		it('.ch-expandable', function () {
			expect(document.querySelector('.ch-expandable').nodeType).toEqual(1);
		});

		it('.ch-expandable-trigger', function () {
			expect(document.querySelector('.ch-expandable-trigger').nodeType).toEqual(1);
		});

		it('.ch-user-no-select', function () {
			expect(document.querySelector('.ch-expandable-trigger.ch-user-no-select').nodeType).toEqual(1);
		});

		it('.ch-expandable-content', function () {
			expect(document.querySelector('.ch-expandable-content').nodeType).toEqual(1);
		});

		it('.ch-expandable-ico', function () {
			expect(document.querySelector('.ch-expandable-trigger.ch-expandable-ico').nodeType).toEqual(1);
		});

		it('.ch-hide', function () {
			expect(document.querySelector('.ch-expandable-content.ch-hide').nodeType).toEqual(1);
		});
	});

	describe('By defult', function () {
		it('Shold have a icon', function () {
			expect(document.querySelector('.ch-expandable-trigger.ch-expandable-ico').nodeType).toEqual(1);
		});

		it('Shold be closed', function () {
			expect(document.querySelector('.ch-expandable-content.ch-hide').nodeType).toEqual(1);
		});
	});

	describe('Show method', function () {
		it('Show', function () {
			expect(document.querySelector('#expandable-1 .ch-expandable-trigger-on')).toBe(null);
			expandable[0].show();
			expect(document.querySelector('#expandable-1 .ch-expandable-trigger-on').nodeType).toEqual(1);
		});
	});

	describe('Hide method', function () {
		it('Hide', function () {
			expandable[0].hide();
			expect(document.querySelector('#expandable-1 .ch-expandable-trigger-on')).toBe(null);
		});
	});

	describe('A intance configured without icon', function () {
		it('Shouldn\'t have the icon classname', function () {
			expect(document.querySelector('#expandable-2 .ch-expandable-trigger.ch-expandable-ico')).toBe(null);
		});
	});

	describe('A instance configured open by default', function () {
		it('Should have the open classname', function () {
			expect(document.querySelector('#expandable-3 .ch-expandable-trigger-on').nodeType).toEqual(1);
		});
	});

});<|endoftext|>


<commit_before>
        // node built in
var   path = require('path')
    , crypto = require('crypto')
        // lib code
    , query = require('./query')
    , debug = require('./debug')
    , state = require('../haxe-state')
    , signatures = require('../parsing/signatures')
    , escape = require('../utils/escape-html')
        // dep code
    , xml2js = require('xml2js')
    , fs = require('fs-extra')

module.exports = {

    selector: '.source.haxe',
    disableForSelector: '.source.haxe .comment',
    inclusionPriority: 1,
    excludeLowerPriority: true,
    prefixes:['.','('],

    rootIndex: null,

    getSuggestions : function(opt) {

        if(!state.hxml_cwd) return [];
        if(!state.hxml_content && !state.hxml_file) return [];

        var _file = opt.editor.buffer.file.path;
        if(!_file) return [];

        return new Promise( function(resolve, reject) {

            var buffer_pos = opt.bufferPosition.toArray();
            var pretext = opt.editor.getTextInBufferRange( [ [0,0], buffer_pos] );
            var index = pretext.length;

            // var info = this.infoFromIndexInText(index, text);
            // if(info) {
            //     index = info.index
            // }
            //
            // console.log(info);
            //
            //     // Check if we should run haxe autocomplete again
            // if(this.rootIndex !== null) {
            //     if(this.rootIndex == index) {
            //         var filtered = this.filter(this.suggestions, opt, info);
            //         return resolve(filtered);
            //     }
            // }

            // var suggestions = []

            var save_info = this.save_for_completion(opt.editor, _file);

            var fetch = query.get({
                file: save_info.file,
                byte: index,
                add_args:[]
            });

            fetch.then(function(data) {

                var parse = this.parseSuggestions(opt, data);

                    parse.then(function(result){
                        resolve(result);
                    }).catch(function(e) {
                        reject(e);
                    });

            }.bind(this)).catch(reject).then(function() {

                this.restore_post_completion(save_info);

            }.bind(this)); //then

        }.bind(this));  //promise

    }, //getSuggestions

    save_for_completion:function(_editor, _file) {

        var filepath = path.dirname(_file);
        var filename = path.basename(_file);
        var tmpname = '.' + filename;
        var tempfile = path.join(filepath, tmpname);

        fs.copySync(_file, tempfile);

        var _code = _editor.getText();
        var b = new Buffer(_code, 'utf-8');
        var freal = fs.openSync(_file, 'w');
                    fs.writeSync(freal, b, 0, b.length, 0);
                    fs.closeSync(freal);
            freal = null;

        return {
            tempfile: tempfile,
            file: _file
        }

    }, //save_for_completion

    restore_post_completion:function(save_info) {

        debug.query('remove ' + save_info.tempfile);

        if(fs.existsSync(save_info.tempfile)) {
            fs.deleteSync(save_info.tempfile);
        }

    }, //restore_post_completion

    parseSuggestions: function(opt, content) {

        return new Promise(function(resolve,reject) {

            if(content.indexOf('<list>') == -1) {

                    //usually an error, like "No completion point" etc.
                resolve([{text:content, rightLabel:'?'}]);

            } else {

                xml2js.parseString(content, function (err, json) {

                        //:todo: care about err
                    var items = this.parseJSON(json);
                    var suggestions = [];

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

                        var item = items[i];
                        var name = item.name;
                        var right = item.info.sig;

                        if(item.info.ret) {
                            right = item.info.sig + ':' + item.info.ret;
                        }

                        suggestions.push({
                             text: escape(name),
                             replacementPrefix: '',
                             rightLabel: right
                        });

                    } //each item

                    resolve(suggestions);

                }.bind(this)); //parseString

            } //contains <list>

        }.bind(this)); //promise

    }, //parseSuggestions

    parseJSON: function(json) {

        var results = [];
        var cnt = json.list.i.length;

        for(var idx = 0; idx < cnt; ++idx) {

            var node = json.list.i[idx];
            var name = node.$.n;
            var type = node.t.length ? node.t[0] : null;

            results.push({
                name:name,
                info:signatures.parseType(type)
            });

        } //for each in list

        return results;

    }, //parseJSON

} //module.exports
<commit_msg>handle simple arg parsing to display args in formatted list<commit_after>
        // node built in
var   path = require('path')
    , crypto = require('crypto')
        // lib code
    , query = require('./query')
    , debug = require('./debug')
    , state = require('../haxe-state')
    , signatures = require('../parsing/signatures')
    , escape = require('../utils/escape-html')
        // dep code
    , xml2js = require('xml2js')
    , fs = require('fs-extra')

module.exports = {

    selector: '.source.haxe',
    disableForSelector: '.source.haxe .comment',
    inclusionPriority: 1,
    excludeLowerPriority: true,
    prefixes:['.','('],

    rootIndex: null,

    getSuggestions : function(opt) {

        if(!state.hxml_cwd) return [];
        if(!state.hxml_content && !state.hxml_file) return [];

        var _file = opt.editor.buffer.file.path;
        if(!_file) return [];

        return new Promise( function(resolve, reject) {

            var buffer_pos = opt.bufferPosition.toArray();
            var pretext = opt.editor.getTextInBufferRange( [ [0,0], buffer_pos] );
            var index = pretext.length;

            // var info = this.infoFromIndexInText(index, text);
            // if(info) {
            //     index = info.index
            // }
            //
            // console.log(info);
            //
            //     // Check if we should run haxe autocomplete again
            // if(this.rootIndex !== null) {
            //     if(this.rootIndex == index) {
            //         var filtered = this.filter(this.suggestions, opt, info);
            //         return resolve(filtered);
            //     }
            // }

            // var suggestions = []

            var save_info = this.save_for_completion(opt.editor, _file);

            var fetch = query.get({
                file: save_info.file,
                byte: index,
                add_args:[]
            });

            fetch.then(function(data) {

                var parse = this.parseSuggestions(opt, data);

                    parse.then(function(result){
                        resolve(result);
                    }).catch(function(e) {
                        reject(e);
                    });

            }.bind(this)).catch(reject).then(function() {

                this.restore_post_completion(save_info);

            }.bind(this)); //then

        }.bind(this));  //promise

    }, //getSuggestions

    save_for_completion:function(_editor, _file) {

        var filepath = path.dirname(_file);
        var filename = path.basename(_file);
        var tmpname = '.' + filename;
        var tempfile = path.join(filepath, tmpname);

        fs.copySync(_file, tempfile);

        var _code = _editor.getText();
        var b = new Buffer(_code, 'utf-8');
        var freal = fs.openSync(_file, 'w');
                    fs.writeSync(freal, b, 0, b.length, 0);
                    fs.closeSync(freal);
            freal = null;

        return {
            tempfile: tempfile,
            file: _file
        }

    }, //save_for_completion

    restore_post_completion:function(save_info) {

        debug.query('remove ' + save_info.tempfile);

        if(fs.existsSync(save_info.tempfile)) {
            fs.deleteSync(save_info.tempfile);
        }

    }, //restore_post_completion

    parseSuggestions: function(opt, content) {

        return new Promise(function(resolve,reject) {

            var has_list = content.indexOf('<list>') != -1;
            var has_type = content.indexOf('<type>') != -1;
            if(!has_list && !has_type) {

                    //usually an error, like "No completion point" etc.
                resolve([{text:content, rightLabel:'?'}]);

            } else {

                xml2js.parseString(content, function (err, json) {

                        //:todo: care about err
                    var items = this.parseJSON(json);
                    var suggestions = [];

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

                        var item = items[i];
                        var name = item.name;
                        var right = item.info.sig;

                        if(item.info.ret) {
                            right = item.info.sig + ':' + item.info.ret;
                        }

                        if(!item.name) {
                            right = '';
                            name = item.info.sig;
                        }

                        suggestions.push({
                             text: escape(name),
                             replacementPrefix: '',
                             rightLabel: right
                        });

                    } //each item

                    resolve(suggestions);

                }.bind(this)); //parseString

            } //contains <list>

        }.bind(this)); //promise

    }, //parseSuggestions

    parseJSON: function(json) {

        var results = [];
        var list = [];

        if(json.list) {
            for(var i = 0; i < json.list.i.length; ++i) {
                var node = json.list.i[i];
                var name = node.$.n;
                var type = node.t.length ? node.t[0] : null;
                list.push({ name:name, type:type });
            }
        } else if(json.type) {
            var argtypes = String(json.type).trim();
            var info = signatures.parseType(argtypes);
            for(var i = 0; i < info.args.length; ++i) {
                var arg = info.args[i];
                var parts = arg.split(':').map(function(a){ return a.trim(); });
                list.push({ name:parts[0], type:parts[1] });
            }
        }

        var cnt = list.length;
        for(var idx = 0; idx < cnt; ++idx) {

            var item = list[idx];

            results.push({
                name:item.name,
                info:signatures.parseType(item.type)
            });

        } //for each in list

        return results;

    }, //parseJSON

} //module.exports
<|endoftext|>


<commit_before>import io from 'socket.io';
import child_process from 'child_process';
import os from 'os';

var spawn = child_process.spawn,
    ifaces = os.networkInterfaces();

export default class App {

  constructor() {
    var self = this;
    this.createIoServer();
    this.users = 0;

    this.debug = (process.platform === 'darwin');

    this.options = {
      defaultMode: 'dashboard'
    }

    this.modes = {
      dashboard: {
        start: data => this.onStartDashboard(data),
        stop: data => this.onStopDashboard(data)
      },
      mediacenter: {
        start: data => this.onStartMediacenter(data),
        stop: data => this.onStopMediacenter(data)
      },
      emulstation: {
        start: data => this.onStartEmulstation(data),
        stop: data => this.onStopEmulstation(data)
      },
      audiorepeater: {
        start: data => this.onStartAirReplay(data),
        stop: data => this.onStopAirReplay(data)
      }
    };

    // SocketIo Events
    this.actions = {
      'disconnect': data => this.onClientDisconnect(data),
      'dashboard': data => this.changeMode('dashboard'),
      'mediacenter': data => this.changeMode('mediacenter'),
      'emulstation': data => this.changeMode('emulstation'),
      'audiorepeater': data => this.changeMode('audiorepeater'),
      'get:ip': (data, socket) => self.getIpAdress(data, socket),
      'reboot': (data, socket) => (data, socket) => { child_process.exec('sudo reboot', () => {
                                        console.log(arguments);
                                      }
                                    );
                                  } (data, socket)
    };

    this.startMode();
  }

  createIoServer() {
    this.io = io();
    this.io.on('connection', socket => this.onClientConnect(socket));
    this.io.listen(3033);
  }

  onClientConnect(socket) {
    this.users++;
    this.bindSocketEvents(socket);
    this.io.sockets.emit('client:connected', {
      totalClients: this.users
    });
  }

  onClientDisconnect() {
    this.users--;
    this.io.sockets.emit('client:disconnect', {
      totalClients: this.users
    });
  }

  startMode(mode) {
    this.currentMode = mode = mode || this.options.defaultMode;
    if (this.modes[mode] && typeof this.modes[mode].start === 'function') {
      this.modes[mode].start();
    }
  }

  changeMode(mode) {
    var oldMode = this.currentMode || false;
    if (oldMode === mode) return false;
    if (oldMode && typeof this.modes[oldMode].stop === 'function') {
      this.modes[oldMode].stop(data => this.startMode(mode));
    } else {
      this.startMode(mode);
    }
  }

  // Modes events ---- START
  onStartDashboard() {
    console.log('Dashboard Start');
    this.spawnChromeStart();
  }

  onStopDashboard(cb) {
    console.log('Dashboard stop');
    this.spawnChromeStop(cb);
  }

  onStartEmulstation() {
    console.log('Emulstation start');

    if(this.debug) return false;
    this.spawnEmulstation(
      out => console.log(out),
      err => console.log(err),
      close => console.log('Emulstation close')
    );

    this.spawnVirtualController(
      out => console.log(out),
      err => console.log(err),
      close => console.log('Virtual controller close')
    );
  }

  onStopEmulstation(cb) {
    console.log('Emulstation stop');
    if(this.debug) return cb ? cb() : false;
    this.killEmulstation();
    console.log('Virtual controller close');
    this.killVirtualController();
    if (cb) cb();
  }

  onStartMediacenter(cb){
    console.log('Mediacenter start');
    if(this.debug) return false;
    this.spawnKodi(cb);
  }

  onStopMediacenter(cb){
    console.log('Mediacenter stop');
    if(this.debug) return cb ? cb() : false;
    this.killKodi(cb);
  }

  onStartAirReplay(cb){
    console.log('Airplay start');
    if(this.debug) return false;
    this.spawnShairport(cb);
  }

  onStopAirReplay(cb){
    console.log('Airplay stop');
    if(this.debug) return cb ? cb() : false;
    this.killShairport(cb);
  }
  // Modes events ---- STOP

  // Spawn actions ---- START
  spawnChromeStart() {
    // su - pi -c 'startx' &
    if(this.debug) return false;
    this.spawnFromPi('startx');
  }

  spawnChromeStop(cb) {
    if(this.debug) return cb ? cb() : false;
    this.runScriptUtil(
      'utils/stopx.sh',
      false,
      false,
      cb ? close => cb(close) : false
    );
  }

  spawnShairport(cb) {
    this.spawn('shairport-sync', cb);
  }

  killShairport(cb) {
    this.kill(cb);
  }

  spawnKodi(cb) {
    this.spawn('kodi', cb);
  }

  killKodi(cb) {
    this.kill(cb);
  }

  spawnEmulstation(out, err, close) {
    this.emulstation = spawn('emulationstation', {
      cwd: __dirname
    });

    if (out) this.emulstation.stdout.on('data', out.toString('utf8'));
    if (err) this.emulstation.stderr.on('data', err.toString('utf8'));
    if (close) this.emulstation.on('close', close);
  }

  killEmulstation() {
    if (this.kodi) {
      this.emulstation.stdin.pause();
      this.emulstation.kill();
      this.emulstation = false;
    }
  }

  spawnVirtualController(out, err, close) {
    this.vcontroller = spawn('sudo', ['node', 'main.js'], {
      cwd: __dirname + '/../../virtual-gamepads/'
    });

    if (out) this.vcontroller.stdout.on('data', out.toString('utf8'));
    if (err) this.vcontroller.stderr.on('data', err.toString('utf8'));
    if (close) this.vcontroller.on('close', close);
  }

  killVirtualController() {
    if (this.vcontroller) {
      this.vcontroller.stdin.pause();
      this.vcontroller.kill();
      this.vcontroller = false;
    }
  }

  runScriptUtil(script, out, err, close) {
    // su - pi -c "sh ~/momo/utils/chromium_start.sh"
    var chrome = spawn('bash', [`${__dirname}/../${script}`] );

    chrome.stdout.on('data', out ?
                             _out => out(_out.toString('utf8')) :
                             _out => console.log(_out.toString('utf8')) );

    chrome.stderr.on('data', err ?
                            _err => err(_err.toString('utf8')) :
                            _err => console.log(_err.toString('utf8')) );

    chrome.on('close', close ?
                            _close => close(_close) :
                            _close => console.log(_close) );
  }

  startService(service, cb){
    this.spawnFromPi(`/etc/init.d/${service} start`, cb);
  }

  stopService(service, cb){
    this.spawnFromPi(`/etc/init.d/${service} stop`, cb);
  }

  spawn(command, cb){
    this.active_process = spawn(command, {
      cwd: __dirname+'/../'
    });

    this.active_process.stdout.on('data', out => console.log(out.toString('utf8')) );
    this.active_process.stderr.on('data', err => console.log(err.toString('utf8')) );
    this.active_process.on('close', cb ? close => cb(close) : close => console.log(close) );
  }

  kill(cb){
    if(this.active_process){
      this.active_process.stdin.pause();
      this.active_process.kill();
      this.active_process = false;
      if(cb) cb();
    }
  }

  spawnFromPi(command, cb){
    var _process = spawn('su', ['-', 'pi', '-c', `\'${command}\'`], {
      cwd: __dirname+'/../'
    });

    _process.stdout.on('data', out => console.log(out.toString('utf8')) );
    _process.stderr.on('data', err => console.log(err.toString('utf8')) );
    _process.on('close', cb ? close => cb(close) : close => console.log(close) );
  }

  bindSocketEvents(socket) {
    for (let event in this.actions) {
      socket.on(event, data => this.actions[event](data, socket));
    }
  }

  // Spawn actions ---- END
  getIpAdress(data, socket){
    Object.keys(ifaces).forEach((ifname) => {
      var alias = 0;

      ifaces[ifname].forEach((iface) => {
        if ('IPv4' !== iface.family || iface.internal !== false) {
          // skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
          return;
        }

        if (alias >= 1) {
          // this single interface has multiple ipv4 addresses
          socket.emit('server:ip', {serverIp: iface.address});
          console.log(ifname + ':' + alias, iface.address);
        } else {
          // this interface has only one ipv4 adress
          socket.emit('server:ip', {serverIp: iface.address});
          console.log(ifname, iface.address);
        }
      });
    });
  }

}
<commit_msg>Fix user for Media Center<commit_after>import io from 'socket.io';
import child_process from 'child_process';
import os from 'os';

var spawn = child_process.spawn,
    ifaces = os.networkInterfaces();

export default class App {

  constructor() {
    var self = this;
    this.createIoServer();
    this.users = 0;

    this.debug = (process.platform === 'darwin');

    this.options = {
      defaultMode: 'dashboard'
    }

    this.modes = {
      dashboard: {
        start: data => this.onStartDashboard(data),
        stop: data => this.onStopDashboard(data)
      },
      mediacenter: {
        start: data => this.onStartMediacenter(data),
        stop: data => this.onStopMediacenter(data)
      },
      emulstation: {
        start: data => this.onStartEmulstation(data),
        stop: data => this.onStopEmulstation(data)
      },
      audiorepeater: {
        start: data => this.onStartAirReplay(data),
        stop: data => this.onStopAirReplay(data)
      }
    };

    // SocketIo Events
    this.actions = {
      'disconnect': data => this.onClientDisconnect(data),
      'dashboard': data => this.changeMode('dashboard'),
      'mediacenter': data => this.changeMode('mediacenter'),
      'emulstation': data => this.changeMode('emulstation'),
      'audiorepeater': data => this.changeMode('audiorepeater'),
      'get:ip': (data, socket) => self.getIpAdress(data, socket),
      'reboot': (data, socket) => (data, socket) => { child_process.exec('sudo reboot', () => {
                                        console.log(arguments);
                                      }
                                    );
                                  } (data, socket)
    };

    this.startMode();
  }

  createIoServer() {
    this.io = io();
    this.io.on('connection', socket => this.onClientConnect(socket));
    this.io.listen(3033);
  }

  onClientConnect(socket) {
    this.users++;
    this.bindSocketEvents(socket);
    this.io.sockets.emit('client:connected', {
      totalClients: this.users
    });
  }

  onClientDisconnect() {
    this.users--;
    this.io.sockets.emit('client:disconnect', {
      totalClients: this.users
    });
  }

  startMode(mode) {
    this.currentMode = mode = mode || this.options.defaultMode;
    if (this.modes[mode] && typeof this.modes[mode].start === 'function') {
      this.modes[mode].start();
    }
  }

  changeMode(mode) {
    var oldMode = this.currentMode || false;
    if (oldMode === mode) return false;
    if (oldMode && typeof this.modes[oldMode].stop === 'function') {
      this.modes[oldMode].stop(data => this.startMode(mode));
    } else {
      this.startMode(mode);
    }
  }

  // Modes events ---- START
  onStartDashboard() {
    console.log('Dashboard Start');
    this.spawnChromeStart();
  }

  onStopDashboard(cb) {
    console.log('Dashboard stop');
    this.spawnChromeStop(cb);
  }

  onStartEmulstation() {
    console.log('Emulstation start');

    if(this.debug) return false;
    this.spawnEmulstation(
      out => console.log(out),
      err => console.log(err),
      close => console.log('Emulstation close')
    );

    this.spawnVirtualController(
      out => console.log(out),
      err => console.log(err),
      close => console.log('Virtual controller close')
    );
  }

  onStopEmulstation(cb) {
    console.log('Emulstation stop');
    if(this.debug) return cb ? cb() : false;
    this.killEmulstation();
    console.log('Virtual controller close');
    this.killVirtualController();
    if (cb) cb();
  }

  onStartMediacenter(cb){
    console.log('Mediacenter start');
    if(this.debug) return false;
    this.spawnKodi(cb);
  }

  onStopMediacenter(cb){
    console.log('Mediacenter stop');
    if(this.debug) return cb ? cb() : false;
    this.killKodi(cb);
  }

  onStartAirReplay(cb){
    console.log('Airplay start');
    if(this.debug) return false;
    this.spawnShairport(cb);
  }

  onStopAirReplay(cb){
    console.log('Airplay stop');
    if(this.debug) return cb ? cb() : false;
    this.killShairport(cb);
  }
  // Modes events ---- STOP

  // Spawn actions ---- START
  spawnChromeStart() {
    // su - pi -c 'startx' &
    if(this.debug) return false;
    this.spawnFromPi('startx');
  }

  spawnChromeStop(cb) {
    if(this.debug) return cb ? cb() : false;
    this.runScriptUtil(
      'utils/stopx.sh',
      false,
      false,
      cb ? close => cb(close) : false
    );
  }

  spawnShairport(cb) {
    this.spawn('shairport-sync', cb);
  }

  killShairport(cb) {
    this.kill(cb);
  }

  spawnKodi(cb) {
    this.spawnFromPi('kodi', cb);
  }

  killKodi(cb) {
    this.kill(cb);
  }

  spawnEmulstation(out, err, close) {
    this.emulstation = spawn('emulationstation', {
      cwd: __dirname
    });

    if (out) this.emulstation.stdout.on('data', out.toString('utf8'));
    if (err) this.emulstation.stderr.on('data', err.toString('utf8'));
    if (close) this.emulstation.on('close', close);
  }

  killEmulstation() {
    if (this.kodi) {
      this.emulstation.stdin.pause();
      this.emulstation.kill();
      this.emulstation = false;
    }
  }

  spawnVirtualController(out, err, close) {
    this.vcontroller = spawn('sudo', ['node', 'main.js'], {
      cwd: __dirname + '/../../virtual-gamepads/'
    });

    if (out) this.vcontroller.stdout.on('data', out.toString('utf8'));
    if (err) this.vcontroller.stderr.on('data', err.toString('utf8'));
    if (close) this.vcontroller.on('close', close);
  }

  killVirtualController() {
    if (this.vcontroller) {
      this.vcontroller.stdin.pause();
      this.vcontroller.kill();
      this.vcontroller = false;
    }
  }

  runScriptUtil(script, out, err, close) {
    // su - pi -c "sh ~/momo/utils/chromium_start.sh"
    var chrome = spawn('bash', [`${__dirname}/../${script}`] );

    chrome.stdout.on('data', out ?
                             _out => out(_out.toString('utf8')) :
                             _out => console.log(_out.toString('utf8')) );

    chrome.stderr.on('data', err ?
                            _err => err(_err.toString('utf8')) :
                            _err => console.log(_err.toString('utf8')) );

    chrome.on('close', close ?
                            _close => close(_close) :
                            _close => console.log(_close) );
  }

  startService(service, cb){
    this.spawnFromPi(`/etc/init.d/${service} start`, cb);
  }

  stopService(service, cb){
    this.spawnFromPi(`/etc/init.d/${service} stop`, cb);
  }

  spawn(command, cb){
    this.active_process = spawn(command, {
      cwd: __dirname+'/../'
    });

    var _close_cb = (close) => {
      this.active_process = false;
      return cb ? cb(close) : console.log(close);
    };

    this.active_process.stdout.on('data', out => console.log(out.toString('utf8')) );
    this.active_process.stderr.on('data', err => console.log(err.toString('utf8')) );
    this.active_process.on('close', _close_cb );
  }

  kill(cb){
    if(this.active_process){
      this.active_process.stdin.pause();
      this.active_process.kill();
      this.active_process = false;
      if(cb) cb();
    }
  }

  spawnFromPi(command, cb){
    var _process = spawn('su', ['-', 'pi', '-c', `\'${command}\'`], {
      cwd: __dirname+'/../'
    }),
    _close_cb = (close) => {
      this.active_process = false;
      return cb ? cb(close) : console.log(close);
    };

    _process.stdout.on('data', out => console.log(out.toString('utf8')) );
    _process.stderr.on('data', err => console.log(err.toString('utf8')) );
    _process.on('close', _close_cb );

    this.active_process = _process;
  }

  bindSocketEvents(socket) {
    for (let event in this.actions) {
      socket.on(event, data => this.actions[event](data, socket));
    }
  }

  // Spawn actions ---- END
  getIpAdress(data, socket){
    Object.keys(ifaces).forEach((ifname) => {
      var alias = 0;

      ifaces[ifname].forEach((iface) => {
        if ('IPv4' !== iface.family || iface.internal !== false) {
          // skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
          return;
        }

        if (alias >= 1) {
          // this single interface has multiple ipv4 addresses
          socket.emit('server:ip', {serverIp: iface.address});
          console.log(ifname + ':' + alias, iface.address);
        } else {
          // this interface has only one ipv4 adress
          socket.emit('server:ip', {serverIp: iface.address});
          console.log(ifname, iface.address);
        }
      });
    });
  }

}
<|endoftext|>


<commit_before>import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {bindActionCreators} from 'redux'
import {connect} from 'react-redux'
import isEqual from 'lodash/isEqual'
import Container from '../dnd/Container'
import Draggable from '../dnd/Draggable'
import uuidv1 from 'uuid/v1'
import Popover from '@terebentina/react-popover'

import Loader from './Loader'
import Card from './Card'
import NewCard from './NewCard'
import {AddCardLink, LaneFooter, LaneHeader, RightContent, ScrollableLane, Section, Title} from '../styles/Base'

import * as laneActions from '../actions/LaneActions'
import {
  CollapseBtn,
  DeleteWrapper,
  ExpandBtn,
  GenDelButton,
  LaneMenuContent,
  LaneMenuHeader,
  LaneMenuItem,
  LaneMenuTitle,
  MenuButton
} from '../styles/Elements'
import classNames from 'classnames'

class Lane extends Component {
  state = {
    loading: false,
    currentPage: this.props.currentPage,
    addCardMode: false,
    collapsed: false,
    isDraggingOver: false
  }

  handleScroll = evt => {
    const node = evt.target
    const elemScrolPosition = node.scrollHeight - node.scrollTop - node.clientHeight
    const {onLaneScroll} = this.props
    if (elemScrolPosition <= 0 && onLaneScroll && !this.state.loading) {
      const {currentPage} = this.state
      this.setState({loading: true})
      const nextPage = currentPage + 1
      onLaneScroll(nextPage, this.props.id).then(moreCards => {
        if (!moreCards || moreCards.length === 0) {
          // if no cards present, stop retrying until user action
          node.scrollTop = node.scrollTop - 100
        } else {
          this.props.actions.paginateLane({
            laneId: this.props.id,
            newCards: moreCards,
            nextPage: nextPage
          })
        }
        this.setState({loading: false})
      })
    }
  }

  sortCards(cards, sortFunction) {
    if (!cards) return []
    if (!sortFunction) return cards
    return cards.concat().sort(function(card1, card2) {
      return sortFunction(card1, card2)
    })
  }

  laneDidMount = node => {
    if (node) {
      node.addEventListener('scroll', this.handleScroll)
    }
  }

  componentWillReceiveProps(nextProps) {
    if (!isEqual(this.props.cards, nextProps.cards)) {
      this.setState({
        currentPage: nextProps.currentPage
      })
    }
  }

  removeCard = (laneId, cardId) => {
    this.props.actions.removeCard({laneId: laneId, cardId: cardId})
  }

  handleCardClick = (e, card) => {
    const {onCardClick} = this.props
    onCardClick && onCardClick(card.id, card.metadata, card.laneId)
    e.stopPropagation()
  }

  showEditableCard = () => {
    this.setState({addCardMode: true})
  }

  hideEditableCard = () => {
    this.setState({addCardMode: false})
  }

  addNewCard = params => {
    const laneId = this.props.id
    const id = uuidv1()
    this.hideEditableCard()
    let card = {id, ...params}
    this.props.actions.addCard({laneId, card})
    this.props.onCardAdd(card, laneId)
  }

  renderAddCardLink = () => {
    const {addCardLink, addCardTitle} = this.props
    if (addCardLink) {
      return {addCardLink}
    } else {
      return <AddCardLink onClick={this.showEditableCard}>{addCardTitle}</AddCardLink>
    }
  }

  renderNewCard = () => {
    const {newCardTemplate, id} = this.props
    if (newCardTemplate) {
      const newCardWithProps = React.cloneElement(newCardTemplate, {
        onCancel: this.hideEditableCard,
        onAdd: this.addNewCard,
        laneId: id
      })
      return {newCardWithProps}
    } else {
      return <NewCard onCancel={this.hideEditableCard} onAdd={this.addNewCard} />
    }
  }

  onDragStart = ({payload}) => {
    const {handleDragStart} = this.props
    handleDragStart && handleDragStart(payload.id, payload.laneId)
  }

  shouldAcceptDrop = sourceContainerOptions => {
    return this.props.droppable && sourceContainerOptions.groupName === this.groupName
  }

  get groupName() {
    const {boardId} = this.props
    return `TrelloBoard${boardId}Lane`
  }

  onDragEnd = (laneId, result) => {
    const {handleDragEnd} = this.props
    const {addedIndex, payload} = result
    this.setState({isDraggingOver: false})
    if (addedIndex != null) {
      this.props.actions.moveCardAcrossLanes({
        fromLaneId: payload.laneId,
        toLaneId: laneId,
        cardId: payload.id,
        index: addedIndex
      })
      handleDragEnd && handleDragEnd(payload.id, payload.laneId, laneId, addedIndex, payload)
    }
  }

  renderDragContainer = isDraggingOver => {
    const {laneSortFunction, editable, hideCardDeleteIcon, tagStyle, cardStyle, draggable, cardDraggable, cards, cardDragClass, id} = this.props
    const {addCardMode, collapsed} = this.state

    const showableCards = collapsed ? [] : cards

    const cardList = this.sortCards(showableCards, laneSortFunction).map((card, idx) => {
      const cardToRender = (
        <Card
          key={card.id}
          index={idx}
          customCardLayout={this.props.customCardLayout}
          customCard={this.props.children}
          tagStyle={tagStyle}
          cardStyle={cardStyle}
          removeCard={this.removeCard}
          onClick={e => this.handleCardClick(e, card)}
          onDelete={this.props.onCardDelete}
          editable={editable}
          hideCardDeleteIcon={hideCardDeleteIcon}
          {...card}
        />
      )
      return draggable && cardDraggable ? <Draggable key={card.id}>{cardToRender}</Draggable> : {cardToRender}
    })

    return (
      <ScrollableLane ref={this.laneDidMount} isDraggingOver={isDraggingOver}>
        <Container
          orientation="vertical"
          groupName={this.groupName}
          dragClass={cardDragClass}
          onDragStart={this.onDragStart}
          onDrop={e => this.onDragEnd(id, e)}
          onDragEnter={() => this.setState({isDraggingOver: true})}
          onDragLeave={() => this.setState({isDraggingOver: false})}
          shouldAcceptDrop={this.shouldAcceptDrop}
          getChildPayload={index => this.props.getCardDetails(id, index)}>
          {cardList}
        </Container>
        {editable && !addCardMode && this.renderAddCardLink()}
        {addCardMode && this.renderNewCard()}
      </ScrollableLane>
    )
  }

  removeLane = () => {
    const {id} = this.props
    this.props.actions.removeLane({laneId: id})
  }

  laneMenu = () => {
    return (
      <Popover className="menu" position="bottom" trigger={<MenuButton>⋮</MenuButton>}>
        <LaneMenuHeader>
          <LaneMenuTitle>Lane actions</LaneMenuTitle>
          <DeleteWrapper>
            <GenDelButton>✖</GenDelButton>
          </DeleteWrapper>
        </LaneMenuHeader>
        <LaneMenuContent>
          <LaneMenuItem onClick={this.removeLane}>Delete Lane...</LaneMenuItem>
        </LaneMenuContent>
      </Popover>
    )
  }

  renderHeader = () => {
    const {customLaneHeader, canAddLanes} = this.props
    if (customLaneHeader) {
      const customLaneElement = React.cloneElement(customLaneHeader, {...this.props})
      return {customLaneElement}
    } else {
      const {title, label, titleStyle, labelStyle} = this.props
      return (
        <LaneHeader onDoubleClick={this.toggleLaneCollapsed}>
          <Title style={titleStyle}>{title}</Title>
          {label && (
            <RightContent>
              {label}
            </RightContent>
          )}
          {canAddLanes && this.laneMenu()}
        </LaneHeader>
      )
    }
  }

  renderFooter = () => {
    const {collapsibleLanes, cards} = this.props
    const {collapsed} = this.state
    if (collapsibleLanes && cards.length > 0) {
      return <LaneFooter onClick={this.toggleLaneCollapsed}>{collapsed ? <ExpandBtn /> : <CollapseBtn />}</LaneFooter>
    }
  }

  toggleLaneCollapsed = () => {
    this.props.collapsibleLanes && this.setState(state => ({collapsed: !state.collapsed}))
  }

  render() {
    const {loading, isDraggingOver} = this.state
    const {id, onLaneClick, onLaneScroll, onCardClick, onCardAdd, onCardDelete, ...otherProps} = this.props
    const allClassNames = classNames('react-trello-board', this.props.className || '')
    return (

 onLaneClick && onLaneClick(id)} draggable={false} className={allClassNames}>
        {this.renderHeader()}
        {this.renderDragContainer(isDraggingOver)}
        {loading && <Loader />}
        {this.renderFooter()}

    )
  }
}

Lane.propTypes = {
  actions: PropTypes.object,
  children: PropTypes.node,
  id: PropTypes.string.isRequired,
  boardId: PropTypes.string,
  title: PropTypes.node,
  index: PropTypes.number,
  laneSortFunction: PropTypes.func,
  style: PropTypes.object,
  cardStyle: PropTypes.object,
  tagStyle: PropTypes.object,
  titleStyle: PropTypes.object,
  labelStyle: PropTypes.object,
  customLaneHeader: PropTypes.element,
  customCardLayout: PropTypes.bool,
  cards: PropTypes.array,
  label: PropTypes.string,
  currentPage: PropTypes.number,
  draggable: PropTypes.bool,
  collapsibleLanes: PropTypes.bool,
  droppable: PropTypes.bool,
  onLaneScroll: PropTypes.func,
  onCardClick: PropTypes.func,
  onCardDelete: PropTypes.func,
  onCardAdd: PropTypes.func,
  onLaneClick: PropTypes.func,
  newCardTemplate: PropTypes.node,
  addCardLink: PropTypes.node,
  addCardTitle: PropTypes.string,
  editable: PropTypes.bool,
  cardDraggable: PropTypes.bool,
  cardDragClass: PropTypes.string,
  canAddLanes: PropTypes.bool
}

Lane.defaultProps = {
  style: {},
  titleStyle: {},
  labelStyle: {},
  label: undefined,
  editable: false,
  onCardAdd: () => {}
}

const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators(laneActions, dispatch)
})

export default connect(
  null,
  mapDispatchToProps
)(Lane)
<commit_msg>Fix for lane styling<commit_after>import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {bindActionCreators} from 'redux'
import {connect} from 'react-redux'
import isEqual from 'lodash/isEqual'
import Container from '../dnd/Container'
import Draggable from '../dnd/Draggable'
import uuidv1 from 'uuid/v1'
import Popover from '@terebentina/react-popover'

import Loader from './Loader'
import Card from './Card'
import NewCard from './NewCard'
import {AddCardLink, LaneFooter, LaneHeader, RightContent, ScrollableLane, Section, Title} from '../styles/Base'

import * as laneActions from '../actions/LaneActions'
import {
  CollapseBtn,
  DeleteWrapper,
  ExpandBtn,
  GenDelButton,
  LaneMenuContent,
  LaneMenuHeader,
  LaneMenuItem,
  LaneMenuTitle,
  MenuButton
} from '../styles/Elements'
import classNames from 'classnames'

class Lane extends Component {
  state = {
    loading: false,
    currentPage: this.props.currentPage,
    addCardMode: false,
    collapsed: false,
    isDraggingOver: false
  }

  handleScroll = evt => {
    const node = evt.target
    const elemScrolPosition = node.scrollHeight - node.scrollTop - node.clientHeight
    const {onLaneScroll} = this.props
    if (elemScrolPosition <= 0 && onLaneScroll && !this.state.loading) {
      const {currentPage} = this.state
      this.setState({loading: true})
      const nextPage = currentPage + 1
      onLaneScroll(nextPage, this.props.id).then(moreCards => {
        if (!moreCards || moreCards.length === 0) {
          // if no cards present, stop retrying until user action
          node.scrollTop = node.scrollTop - 100
        } else {
          this.props.actions.paginateLane({
            laneId: this.props.id,
            newCards: moreCards,
            nextPage: nextPage
          })
        }
        this.setState({loading: false})
      })
    }
  }

  sortCards(cards, sortFunction) {
    if (!cards) return []
    if (!sortFunction) return cards
    return cards.concat().sort(function(card1, card2) {
      return sortFunction(card1, card2)
    })
  }

  laneDidMount = node => {
    if (node) {
      node.addEventListener('scroll', this.handleScroll)
    }
  }

  componentWillReceiveProps(nextProps) {
    if (!isEqual(this.props.cards, nextProps.cards)) {
      this.setState({
        currentPage: nextProps.currentPage
      })
    }
  }

  removeCard = (laneId, cardId) => {
    this.props.actions.removeCard({laneId: laneId, cardId: cardId})
  }

  handleCardClick = (e, card) => {
    const {onCardClick} = this.props
    onCardClick && onCardClick(card.id, card.metadata, card.laneId)
    e.stopPropagation()
  }

  showEditableCard = () => {
    this.setState({addCardMode: true})
  }

  hideEditableCard = () => {
    this.setState({addCardMode: false})
  }

  addNewCard = params => {
    const laneId = this.props.id
    const id = uuidv1()
    this.hideEditableCard()
    let card = {id, ...params}
    this.props.actions.addCard({laneId, card})
    this.props.onCardAdd(card, laneId)
  }

  renderAddCardLink = () => {
    const {addCardLink, addCardTitle} = this.props
    if (addCardLink) {
      return {addCardLink}
    } else {
      return <AddCardLink onClick={this.showEditableCard}>{addCardTitle}</AddCardLink>
    }
  }

  renderNewCard = () => {
    const {newCardTemplate, id} = this.props
    if (newCardTemplate) {
      const newCardWithProps = React.cloneElement(newCardTemplate, {
        onCancel: this.hideEditableCard,
        onAdd: this.addNewCard,
        laneId: id
      })
      return {newCardWithProps}
    } else {
      return <NewCard onCancel={this.hideEditableCard} onAdd={this.addNewCard} />
    }
  }

  onDragStart = ({payload}) => {
    const {handleDragStart} = this.props
    handleDragStart && handleDragStart(payload.id, payload.laneId)
  }

  shouldAcceptDrop = sourceContainerOptions => {
    return this.props.droppable && sourceContainerOptions.groupName === this.groupName
  }

  get groupName() {
    const {boardId} = this.props
    return `TrelloBoard${boardId}Lane`
  }

  onDragEnd = (laneId, result) => {
    const {handleDragEnd} = this.props
    const {addedIndex, payload} = result
    this.setState({isDraggingOver: false})
    if (addedIndex != null) {
      this.props.actions.moveCardAcrossLanes({
        fromLaneId: payload.laneId,
        toLaneId: laneId,
        cardId: payload.id,
        index: addedIndex
      })
      handleDragEnd && handleDragEnd(payload.id, payload.laneId, laneId, addedIndex, payload)
    }
  }

  renderDragContainer = isDraggingOver => {
    const {laneSortFunction, editable, hideCardDeleteIcon, tagStyle, cardStyle, draggable, cardDraggable, cards, cardDragClass, id} = this.props
    const {addCardMode, collapsed} = this.state

    const showableCards = collapsed ? [] : cards

    const cardList = this.sortCards(showableCards, laneSortFunction).map((card, idx) => {
      const cardToRender = (
        <Card
          key={card.id}
          index={idx}
          customCardLayout={this.props.customCardLayout}
          customCard={this.props.children}
          tagStyle={tagStyle}
          cardStyle={cardStyle}
          removeCard={this.removeCard}
          onClick={e => this.handleCardClick(e, card)}
          onDelete={this.props.onCardDelete}
          editable={editable}
          hideCardDeleteIcon={hideCardDeleteIcon}
          {...card}
        />
      )
      return draggable && cardDraggable ? <Draggable key={card.id}>{cardToRender}</Draggable> : {cardToRender}
    })

    return (
      <ScrollableLane ref={this.laneDidMount} isDraggingOver={isDraggingOver}>
        <Container
          orientation="vertical"
          groupName={this.groupName}
          dragClass={cardDragClass}
          onDragStart={this.onDragStart}
          onDrop={e => this.onDragEnd(id, e)}
          onDragEnter={() => this.setState({isDraggingOver: true})}
          onDragLeave={() => this.setState({isDraggingOver: false})}
          shouldAcceptDrop={this.shouldAcceptDrop}
          getChildPayload={index => this.props.getCardDetails(id, index)}>
          {cardList}
        </Container>
        {editable && !addCardMode && this.renderAddCardLink()}
        {addCardMode && this.renderNewCard()}
      </ScrollableLane>
    )
  }

  removeLane = () => {
    const {id} = this.props
    this.props.actions.removeLane({laneId: id})
  }

  laneMenu = () => {
    return (
      <Popover className="menu" position="bottom" trigger={<MenuButton>⋮</MenuButton>}>
        <LaneMenuHeader>
          <LaneMenuTitle>Lane actions</LaneMenuTitle>
          <DeleteWrapper>
            <GenDelButton>✖</GenDelButton>
          </DeleteWrapper>
        </LaneMenuHeader>
        <LaneMenuContent>
          <LaneMenuItem onClick={this.removeLane}>Delete Lane...</LaneMenuItem>
        </LaneMenuContent>
      </Popover>
    )
  }

  renderHeader = () => {
    const {customLaneHeader, canAddLanes} = this.props
    if (customLaneHeader) {
      const customLaneElement = React.cloneElement(customLaneHeader, {...this.props})
      return {customLaneElement}
    } else {
      const {title, label, titleStyle, labelStyle} = this.props
      return (
        <LaneHeader onDoubleClick={this.toggleLaneCollapsed}>
          <Title style={titleStyle}>{title}</Title>
          {label && (
            <RightContent>
              {label}
            </RightContent>
          )}
          {canAddLanes && this.laneMenu()}
        </LaneHeader>
      )
    }
  }

  renderFooter = () => {
    const {collapsibleLanes, cards} = this.props
    const {collapsed} = this.state
    if (collapsibleLanes && cards.length > 0) {
      return <LaneFooter onClick={this.toggleLaneCollapsed}>{collapsed ? <ExpandBtn /> : <CollapseBtn />}</LaneFooter>
    }
  }

  toggleLaneCollapsed = () => {
    this.props.collapsibleLanes && this.setState(state => ({collapsed: !state.collapsed}))
  }

  render() {
    const {loading, isDraggingOver} = this.state
    const {id, onLaneClick, onLaneScroll, onCardClick, onCardAdd, onCardDelete, ...otherProps} = this.props
    const allClassNames = classNames('react-trello-lane', this.props.className || '')
    return (

 onLaneClick && onLaneClick(id)} draggable={false} className={allClassNames}>
        {this.renderHeader()}
        {this.renderDragContainer(isDraggingOver)}
        {loading && <Loader />}
        {this.renderFooter()}

    )
  }
}

Lane.propTypes = {
  actions: PropTypes.object,
  children: PropTypes.node,
  id: PropTypes.string.isRequired,
  boardId: PropTypes.string,
  title: PropTypes.node,
  index: PropTypes.number,
  laneSortFunction: PropTypes.func,
  style: PropTypes.object,
  cardStyle: PropTypes.object,
  tagStyle: PropTypes.object,
  titleStyle: PropTypes.object,
  labelStyle: PropTypes.object,
  customLaneHeader: PropTypes.element,
  customCardLayout: PropTypes.bool,
  cards: PropTypes.array,
  label: PropTypes.string,
  currentPage: PropTypes.number,
  draggable: PropTypes.bool,
  collapsibleLanes: PropTypes.bool,
  droppable: PropTypes.bool,
  onLaneScroll: PropTypes.func,
  onCardClick: PropTypes.func,
  onCardDelete: PropTypes.func,
  onCardAdd: PropTypes.func,
  onLaneClick: PropTypes.func,
  newCardTemplate: PropTypes.node,
  addCardLink: PropTypes.node,
  addCardTitle: PropTypes.string,
  editable: PropTypes.bool,
  cardDraggable: PropTypes.bool,
  cardDragClass: PropTypes.string,
  canAddLanes: PropTypes.bool
}

Lane.defaultProps = {
  style: {},
  titleStyle: {},
  labelStyle: {},
  label: undefined,
  editable: false,
  onCardAdd: () => {}
}

const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators(laneActions, dispatch)
})

export default connect(
  null,
  mapDispatchToProps
)(Lane)
<|endoftext|>


<commit_before>'use strict';

var Backbone = require('../shims/backbone');
var View = Backbone.View;
var templates = require('../lib/templates');
var $ = require('../shims/jquery');
var urlrepl = require('../lib/url-replace');

module.exports = View.extend({
  pageTitle: 'Monica Macovei Presedinte | Scrisoare',
  template: templates.pages.scrisoare,

  events: {
    'click .letter-send': 'sendLetter',
    'click #title-list li a': 'getTitle',
    'click #destination-list li a': 'getDestination'
  },

  render: function () {
    var self = this;
    this.$el.html(this.template());

    return this;
  },

  getTitle: function (elem) {
    this.titleId = $(elem.currentTarget).data('value');
    $('#title-btn').text($(elem.currentTarget).text())
  },

  getDestination: function (elem) {
    this.destinationId = $(elem.currentTarget).data('value');
    $('#destination-btn').text($(elem.currentTarget).text())
  },

  sendLetter: function () {
    var emailRegxp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

    if (emailRegxp.test($('.letter-destination input').val())) {
      $('#warning').removeClass('visible').addClass('hidden');
      this.sendTo = $('.letter-destination input').val();
    } else {
      $('#warning').removeClass('hidden').addClass('visible');
    }

    var letterData = {
      title: this.titleId,
      destination: this.destinationId,
      sendTo: this.sendTo
    };

    $.ajax({
      type: 'POST',
      url: process.env.MAIL_SERVER,
      data: JSON.stringify(letterData),
      contentType: 'Application/json',
      crossDomain: true,
      success: function() {
        $('#negative').removeClass('visible').addClass('hidden');
        $('#positive').removeClass('visible').addClass('hidden');
        $('#positive').removeClass('hidden').addClass('visible');
      },
      error: function () {
        $('#positive').removeClass('visible').addClass('hidden');
        $('#negative').removeClass('visible').addClass('hidden');
        $('#negative').removeClass('hidden').addClass('visible');
      }
    })
  }
});
<commit_msg>change server.<commit_after>'use strict';

var Backbone = require('../shims/backbone');
var View = Backbone.View;
var templates = require('../lib/templates');
var $ = require('../shims/jquery');
var urlrepl = require('../lib/url-replace');

module.exports = View.extend({
  pageTitle: 'Monica Macovei Presedinte | Scrisoare',
  template: templates.pages.scrisoare,

  events: {
    'click .letter-send': 'sendLetter',
    'click #title-list li a': 'getTitle',
    'click #destination-list li a': 'getDestination'
  },

  render: function () {
    var self = this;
    this.$el.html(this.template());

    return this;
  },

  getTitle: function (elem) {
    this.titleId = $(elem.currentTarget).data('value');
    $('#title-btn').text($(elem.currentTarget).text())
  },

  getDestination: function (elem) {
    this.destinationId = $(elem.currentTarget).data('value');
    $('#destination-btn').text($(elem.currentTarget).text())
  },

  sendLetter: function () {
    var emailRegxp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

    if (emailRegxp.test($('.letter-destination input').val())) {
      $('#warning').removeClass('visible').addClass('hidden');
      this.sendTo = $('.letter-destination input').val();
    } else {
      $('#warning').removeClass('hidden').addClass('visible');
    }

    var letterData = {
      title: this.titleId,
      destination: this.destinationId,
      sendTo: this.sendTo
    };

    $.ajax({
      type: 'POST',
      url: 'https://macovei-mail-server.herokuapp.com/send',
      data: JSON.stringify(letterData),
      contentType: 'Application/json',
      crossDomain: true,
      success: function() {
        $('#negative').removeClass('visible').addClass('hidden');
        $('#positive').removeClass('visible').addClass('hidden');
        $('#positive').removeClass('hidden').addClass('visible');
      },
      error: function () {
        $('#positive').removeClass('visible').addClass('hidden');
        $('#negative').removeClass('visible').addClass('hidden');
        $('#negative').removeClass('hidden').addClass('visible');
      }
    })
  }
});
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var path = require('path')
  , Module = require('../module')
  , resolvers = require('../resolvers')
  , utils = require('../utils')
  , debug = require('debug')('jsmt:middleware');

/**
 * Serve JavaScript to browsers in AMD format.
 *
 * @param {String} root
 * @param {Object} options
 * @return {Function}
 * @api public
 */
module.exports = function(root, options) {
  options = options || {};

  var resolve = resolvers[options.resolve || 'amd']({ baseDir: root })
    , transitive = options.transitive || false
    , mime = options.mime || 'text/javascript';

  return function modules(req, res, next) {
    var mid = req.path
      , ext = path.extname(mid);
    if (mid[0] == '/') {
      mid = mid.slice(1);
    }
    mid = mid.slice(0, mid.length - ext.length);

    // Core modules are compiled into a JavaScript engine (ex: Node).  As such,
    // they cannot be resolved to a file and are expected to be included via
    // other mechanisms.
    if (resolve.isBuiltIn(mid)) {
      debug('core module, deferring: ' + mid);
      return next();
    }

    debug('resolving: ' + mid);
    var filename;
    try {
      filename = resolve(mid);
    } catch(e) {
    }
    debug('resolved to: ' + filename);

    // Failed to resolve module.  Proceed to next middleware, which may be able
    // to resolve the module and service the request.  If not, the request will
    // eventually 404.
    if (!filename) { return next(); }

    var mod = Module.get(mid, filename);
    var opts = {};
    utils.merge(opts, options);
    utils.merge(opts, { baseDir: root });
    // Multiple module middleware are typically in use to construct a "virtual"
    // module space.  Allow unresolved modules within any single instance, under
    // the assumption that a different instance will resolve the module.
    utils.merge(opts, { allowAllUnresolved: true });
    // Module IDs must be burned when transporting multiple modules in a single
    // response.
    if (transitive) { utils.merge(opts, { burnID: true }); }

    mod.load(filename, opts, function(err) {
      if (err) { return next(err); }

      var js = '';

      // Traverse the module tree, constructing AMD-compatible JavaScript.  If
      // the `transitive` option is disabled, the tree will consist of just the
      // requested module.
      traverse(mod, function(m) {
        if (!m.filename) { return; }

        var mopts = {};
        utils.merge(mopts, opts);
        if (transitive && !m.parent) {
          // If the module has no parent, burn the ID specified by the client in
          // order to keep state consistent between the client and server.
          //
          // In practice, the only time these would differ is when requesting a
          // top-level Node module in which the main JavaScript file resolves to
          // an internal file inside a lib directory (referenced through the
          // `main` property of package.json).
          utils.merge(mopts, { moduleID: m.id });
        }

        js += m.toAMD(mopts) + '\r\n';
      });

      res.setHeader('Content-Type', mime);
      res.end(js);
    });
  }
}

function traverse(m, fn) {
  m.children.forEach(function(child) {
    traverse(child, fn);
  });
  fn(m);
}

<commit_msg>Optimize Node module resolution.<commit_after>/**
 * Module dependencies.
 */
var path = require('path')
  , fs = require('fs')
  , existsSync = fs.existsSync || path.existsSync
  , Module = require('../module')
  , resolvers = require('../resolvers')
  , utils = require('../utils')
  , debug = require('debug')('jsmt:middleware');

/**
 * Serve JavaScript to browsers in AMD format.
 *
 * @param {String} root
 * @param {Object} options
 * @return {Function}
 * @api public
 */
module.exports = function(root, options) {
  options = options || {};

  var resolve = resolvers[options.resolve || 'amd']({ baseDir: root })
    , transitive = options.transitive || false
    , mime = options.mime || 'text/javascript';

  return function modules(req, res, next) {
    var mid = req.path
      , ext = path.extname(mid);
    if (mid[0] == '/') {
      mid = mid.slice(1);
    }
    mid = mid.slice(0, mid.length - ext.length);

    // Built-in modules are compiled into a JavaScript engine (ex: Node).  As
    // such, they cannot be resolved to a file and are expected to be included
    // via a compatibility layer.
    if (resolve.isBuiltIn(mid)) {
      debug('built-in module, deferring: ' + mid);
      return next();
    }

    debug('resolving: ' + mid);
    var filename;

    if (resolve.__algo == 'node') {
      // When serving Node modules to a browser, dependencies are pre-resolved
      // to their absolute path (by the `denode` transform).  This optimization
      // short-circuits Node resolution for the common case when it was already
      // been performed.
      var pabs = path.resolve(root, mid + '.js');
      if (existsSync(pabs)) {
        filename = pabs;
      }
    }

    if (!filename) {
      try {
        filename = resolve(mid);
      } catch(e) {
      }
    }
    debug('resolved to: ' + filename);

    // Failed to resolve module.  Proceed to next middleware, which may be able
    // to resolve the module and service the request.  If not, the request will
    // eventually 404.
    if (!filename) { return next(); }

    var mod = Module.get(mid, filename);
    var opts = {};
    utils.merge(opts, options);
    utils.merge(opts, { baseDir: root });
    // Multiple module middleware are typically in use to construct a "virtual"
    // module space.  Allow unresolved modules within any single instance, under
    // the assumption that a different instance will resolve the module.
    utils.merge(opts, { allowAllUnresolved: true });
    // Module IDs must be burned when transporting multiple modules in a single
    // response.
    if (transitive) { utils.merge(opts, { burnID: true }); }

    mod.load(filename, opts, function(err) {
      if (err) { return next(err); }

      var js = '';

      // Traverse the module tree, constructing AMD-compatible JavaScript.  If
      // the `transitive` option is disabled, the tree will consist of just the
      // requested module.
      traverse(mod, function(m) {
        if (!m.filename) { return; }

        var mopts = {};
        utils.merge(mopts, opts);
        if (transitive && !m.parent) {
          // If the module has no parent, burn the ID specified by the client in
          // order to keep state consistent between the client and server.
          //
          // In practice, the only time these would differ is when requesting a
          // top-level Node module in which the main JavaScript file resolves to
          // an internal file inside a lib directory (referenced through the
          // `main` property of package.json).
          utils.merge(mopts, { moduleID: m.id });
        }

        js += m.toAMD(mopts) + '\r\n';
      });

      res.setHeader('Content-Type', mime);
      res.end(js);
    });
  }
}

function traverse(m, fn) {
  m.children.forEach(function(child) {
    traverse(child, fn);
  });
  fn(m);
}

<|endoftext|>


<commit_before>"use strict";
var fluid = require("infusion");
var jqUnit = fluid.require("jqUnit");
var request = require('request');

// Spin up an express instance
var express = require('express');
var http = require('http');
var path = require('path');
//var exphbs  = require('express3-handlebars');
var bodyParser = require('body-parser');

var app = express();

var loader = require("../../../configs/lib/config-loader");
var config = loader.loadConfig(require("../../../configs/express/test.json"));

var testUtils = require("../../tests/lib/testUtils")(config);

app.set('port', config.port || process.env.PORT || 4895);
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());

// Mount all named variations on the module
var records = require('../../records')(config);
app.use('/records', records);

var termsConfig = JSON.parse(JSON.stringify(config));
termsConfig.recordType = "general";
var terms = require("../../records")(termsConfig);
app.use('/terms', terms);

var aliasConfig = JSON.parse(JSON.stringify(config));
aliasConfig.recordType = "alias";
var aliases = require("../../records")(aliasConfig);
app.use('/aliases', aliases);

var transformConfig = JSON.parse(JSON.stringify(config));
transformConfig.recordType = "transform";
var transforms = require("../../records")(transformConfig);
app.use('/transforms', transforms);

var translationConfig = JSON.parse(JSON.stringify(config));
translationConfig.recordType = "translation";
var translations = require("../../records")(translationConfig);
app.use('/translations', translations);

var operatorsConfig = JSON.parse(JSON.stringify(config));
operatorsConfig.recordType = "operator";
var operators = require("../../records")(operatorsConfig);
app.use('/operators', operators);

http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
});

jqUnit.module("Records API");

// TODO: We cannot test operators, transforms, or translations until we actually have some stored
// var recordTypeEndPoints = ["terms","aliases","transforms","translations","operators"];

var recordTypeEndPoints = ["terms","aliases"];
var allEndPoints = recordTypeEndPoints.concat(["records"]);

allEndPoints.forEach(function(endPoint){
    jqUnit.asyncTest("Search endpoint '" + endPoint + "' with no arguments", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint, function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                jqUnit.assertEquals("The request for endPoint '" + endPoint + "'should have been successful...", response.statusCode, 200);

                var jsonData = JSON.parse(body);
                jqUnit.assertTrue("The total number of rows returned for endPoint '" + endPoint + "' should be greater than zero...", parseInt(jsonData.total_rows) > 0);

                jqUnit.assertNotNull("There should be actual record data returned for endPoint '" + endPoint + "'...", jsonData.records);

                if (jsonData.records) {
                    jqUnit.assertTrue("The record data for endPoint '" + endPoint + "' should have at least one record...", jsonData.records.length > 0);

                    testUtils.isSaneRecord(jqUnit, jsonData.records[0]);
                }
            });
        });
    }
);

// Test paging by asking for records 1-2 and then records 2-2 and comparing record 2 to itself
recordTypeEndPoints.forEach(function(endPoint){
        jqUnit.asyncTest("Testing paging w/ endpoint '" + endPoint + "' ...", function() {
            var firstRecord, secondRecord;
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?offset=0&limit=2", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                var jsonData = JSON.parse(body);
                jqUnit.assertEquals("The results should include the correct offset...", 0, jsonData.offset);
                jqUnit.assertEquals("The results should include the correct limit...", 2, jsonData.limit);
                jqUnit.assertTrue("The correct number of results should have been returned...", jsonData.records && jsonData.records.length === 2);

                firstRecord = jsonData.records[1];

                jqUnit.stop();

                request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?offset=1&limit=1", function(error, response, body) {
                    jqUnit.start();

                    testUtils.isSaneResponse(jqUnit, error, response, body);

                    var jsonData = JSON.parse(body);
                    jqUnit.assertEquals("The results should include the correct offset...", 1, jsonData.offset);
                    jqUnit.assertEquals("The results should include the correct limit...", 1, jsonData.limit);
                    jqUnit.assertTrue("The correct number of results should have been returned...", jsonData.records && jsonData.records.length === 1);

                    secondRecord = jsonData.records[0];

                    jqUnit.assertDeepEq("The last record in set 0-1 should be the same as the first record in set 1-2...",firstRecord,secondRecord);
                });
            });
        });
    }
);

// Limit by one status, and then limit by two.  There should be more active and deleted records than just active records
recordTypeEndPoints.forEach(function(endPoint){
        jqUnit.asyncTest("Testing filtering by status w/ endpoint '" + endPoint + "' ...", function() {
            var firstRecordCount, secondRecordCount;
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?status=active", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                var jsonData = JSON.parse(body);
                jqUnit.assertDeepEq("The results should include the status filter information passed in the query...", ["active"], jsonData.params.statuses);

                firstRecordCount = jsonData.records.length;

                jqUnit.stop();

                request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?status=active&status=unreviewed&status=deleted", function(error, response, body) {
                    jqUnit.start();

                    testUtils.isSaneResponse(jqUnit, error, response, body);

                    var jsonData = JSON.parse(body);
                    jqUnit.assertDeepEq("The results should include the status filter information passed in the query...", ["active", "unreviewed", "deleted"], jsonData.params.statuses);

                    secondRecordCount = jsonData.records.length;

                    jqUnit.assertTrue("There should be more 'active' and 'deleted' records than 'active' records...", firstRecordCount < secondRecordCount);
                });
            });
        });
    }
);

// There should be records updated since the year 2000
recordTypeEndPoints.forEach(function(endPoint){
        jqUnit.asyncTest("Filter endpoint '" + endPoint + "' by future date...", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?updated=2000-01-01", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                var jsonData = JSON.parse(body);
                jqUnit.assertTrue("The results should include the date filter information passed in the query...", jsonData.params.updated);
                jqUnit.assertTrue("Limiting records by a date in the past should have returned results...", jsonData.records && jsonData.records.length > 0);
            });
        });
    }
);

// There should be no records updated in the year 3000
recordTypeEndPoints.forEach(function(endPoint){
        jqUnit.asyncTest("Filter endpoint '" + endPoint + "' by future date...", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?updated=3000-01-01", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                var jsonData = JSON.parse(body);
                jqUnit.assertTrue("The results should include the date filter information passed in the query...", jsonData.params.updated);
                jqUnit.assertTrue("Limiting records by a far future date should not have returned anything...", jsonData.records && jsonData.records.length === 0);
            });
        });
    }
);

// Test that modules other than "records" do not support the recordType option
recordTypeEndPoints.forEach(function(endPoint){
    jqUnit.asyncTest("Query endpoint '" + endPoint + " with no arguments...", function() {
        jqUnit.start();
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?recordType=general", function(error, response, body) {

                testUtils.isSaneResponse(jqUnit, error, response, body);

                jqUnit.assertNotEquals("Asking the '" + endPoint + "' end point to return a specific record type should not have been successful...", response.statusCode, 200);
            });
        });
    }
);

// TODO:  Test "versions" functionality

// The output from "terms" and "records" should not include children with the "children" option set to false
["records","terms"].forEach(function(endPoint){
        jqUnit.asyncTest("Query endpoint '" + endPoint + " with the 'children' argument set to false...", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?children=false", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);
                var jsonData = JSON.parse(body);

                jqUnit.assertTrue("There should have been records returned...", jsonData.records);
                if (jsonData.records) {
                    jsonData.records.forEach(function(record) {
                        jqUnit.assertUndefined("Record '" + record.uniqueId + "' should not have contained any children", record.aliases);
                    });
                }
            });
        });
    }
);

// The output from "terms" and "records" should include children when the "children" option is set to true
["records","terms"].forEach(function(endPoint){
        jqUnit.asyncTest("Query endpoint '" + endPoint + " with the 'children' argument set to true...", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?children=true", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);
                var jsonData = JSON.parse(body);

                jqUnit.assertTrue("There should have been records returned...", jsonData.records);
                if (jsonData.records) {
                    var aliasesFound = false;
                    jsonData.records.forEach(function(record) {
                        if (record.aliases) { aliasesFound = true; }
                    });

                    jqUnit.assertTrue("There should have been at least one record with 'aliases' data...",aliasesFound);
                }
            });
        });
    }
);

// Test that modules other than "records" and "terms" do not support the "children" option
recordTypeEndPoints.forEach(function(endPoint){
        // skip "terms", which should support "children"
        if (endPoint !== "terms") {
            jqUnit.asyncTest("Query endpoint '" + endPoint + " with the 'children' argument set to true (should complain)...", function() {
                request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?children=true", function(error, response, body) {
                    jqUnit.start();

                    testUtils.isSaneResponse(jqUnit, error, response, body);

                    jqUnit.assertNotEquals("Asking the '" + endPoint + "' end point to return children should not have been successful...", response.statusCode, 200);
                });
            });
        }
    }
);

jqUnit.onAllTestsDone.addListener(function() {
    // Shut down express (seems to happen implicitly, so commented out)
//    http.server.close();
});<commit_msg>Added additional tests to cover glitches that came up in manual testing.<commit_after>"use strict";
var fluid = require("infusion");
var jqUnit = fluid.require("jqUnit");
var request = require('request');

// Spin up an express instance
var express = require('express');
var http = require('http');
var path = require('path');
//var exphbs  = require('express3-handlebars');
var bodyParser = require('body-parser');

var app = express();

var loader = require("../../../configs/lib/config-loader");
var config = loader.loadConfig(require("../../../configs/express/test.json"));

var testUtils = require("../../tests/lib/testUtils")(config);

app.set('port', config.port || process.env.PORT || 4895);
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());

// Mount all named variations on the module
var records = require('../../records')(config);
app.use('/records', records);

var termsConfig = JSON.parse(JSON.stringify(config));
termsConfig.recordType = "general";
var terms = require("../../records")(termsConfig);
app.use('/terms', terms);

var aliasConfig = JSON.parse(JSON.stringify(config));
aliasConfig.recordType = "alias";
var aliases = require("../../records")(aliasConfig);
app.use('/aliases', aliases);

var transformConfig = JSON.parse(JSON.stringify(config));
transformConfig.recordType = "transform";
var transforms = require("../../records")(transformConfig);
app.use('/transforms', transforms);

var translationConfig = JSON.parse(JSON.stringify(config));
translationConfig.recordType = "translation";
var translations = require("../../records")(translationConfig);
app.use('/translations', translations);

var operatorsConfig = JSON.parse(JSON.stringify(config));
operatorsConfig.recordType = "operator";
var operators = require("../../records")(operatorsConfig);
app.use('/operators', operators);

http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
});

jqUnit.module("Records API");

// TODO: We cannot test operators, transforms, or translations until we actually have some stored
// var recordTypeEndPoints = ["terms","aliases","transforms","translations","operators"];

var recordTypeEndPoints = ["terms","aliases"];
var allEndPoints = recordTypeEndPoints.concat(["records"]);

var recordTypesByEndpoint = {"terms": "general", "aliases": "alias", "operators": "operator", "transforms": "transform", "translations": "translation"};

allEndPoints.forEach(function(endPoint){
    jqUnit.asyncTest("Load endpoint '" + endPoint + "' with no arguments", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint, function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                jqUnit.assertEquals("The request for endPoint '" + endPoint + "'should have been successful...", response.statusCode, 200);

                var jsonData = JSON.parse(body);
                jqUnit.assertTrue("The total number of rows returned for endPoint '" + endPoint + "' should be greater than zero...", parseInt(jsonData.total_rows) > 0);

                jqUnit.assertNotNull("There should be actual record data returned for endPoint '" + endPoint + "'...", jsonData.records);

                if (jsonData.records) {
                    jqUnit.assertTrue("The record data for endPoint '" + endPoint + "' should have at least one record...", jsonData.records.length > 0);

                    testUtils.isSaneRecord(jqUnit, jsonData.records[0]);
                }
            });
        });
    }
);

// Make sure that "total_rows" is meaningful
allEndPoints.forEach(function(endPoint){
        jqUnit.asyncTest("Sanity check total_rows for endpoint '" + endPoint + "'...", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?limit=-1", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                jqUnit.assertEquals("The request for endPoint '" + endPoint + "'should have been successful...", response.statusCode, 200);

                var jsonData = JSON.parse(body);

                jqUnit.assertNotNull("There should be actual record data returned for endPoint '" + endPoint + "'...", jsonData.records);

                if (jsonData.records) {
                    jqUnit.assertEquals("The record data for endPoint '" + endPoint + "' should have total_rows records...", jsonData.records.length, jsonData.total_rows);

                    testUtils.isSaneRecord(jqUnit, jsonData.records[0]);
                }
            });
        });
    }
);

// Test paging by asking for records 1-2 and then records 2-2 and comparing record 2 to itself
recordTypeEndPoints.forEach(function(endPoint){
        jqUnit.asyncTest("Testing paging w/ endpoint '" + endPoint + "' ...", function() {
            var firstRecord, secondRecord;
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?offset=0&limit=2", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                var jsonData = JSON.parse(body);
                jqUnit.assertEquals("The results should include the correct offset...", 0, jsonData.offset);
                jqUnit.assertEquals("The results should include the correct limit...", 2, jsonData.limit);
                jqUnit.assertTrue("The correct number of results should have been returned...", jsonData.records && jsonData.records.length === 2);

                firstRecord = jsonData.records[1];

                jqUnit.stop();

                request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?offset=1&limit=1", function(error, response, body) {
                    jqUnit.start();

                    testUtils.isSaneResponse(jqUnit, error, response, body);

                    var jsonData = JSON.parse(body);
                    jqUnit.assertEquals("The results should include the correct offset...", 1, jsonData.offset);
                    jqUnit.assertEquals("The results should include the correct limit...", 1, jsonData.limit);
                    jqUnit.assertTrue("The correct number of results should have been returned...", jsonData.records && jsonData.records.length === 1);

                    secondRecord = jsonData.records[0];

                    jqUnit.assertDeepEq("The last record in set 0-1 should be the same as the first record in set 1-2...",firstRecord,secondRecord);
                });
            });
        });
    }
);

// Limit by one status, and then limit by two.  There should be more active and deleted records than just active records
recordTypeEndPoints.forEach(function(endPoint){
        jqUnit.asyncTest("Testing filtering by status w/ endpoint '" + endPoint + "' ...", function() {
            var firstRecordCount, secondRecordCount;
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?status=active", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                var jsonData = JSON.parse(body);
                jqUnit.assertDeepEq("The results should include the status filter information passed in the query...", ["active"], jsonData.params.statuses);

                firstRecordCount = jsonData.records.length;

                jqUnit.stop();

                request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?status=active&status=unreviewed&status=deleted", function(error, response, body) {
                    jqUnit.start();

                    testUtils.isSaneResponse(jqUnit, error, response, body);

                    var jsonData = JSON.parse(body);
                    jqUnit.assertDeepEq("The results should include the status filter information passed in the query...", ["active", "unreviewed", "deleted"], jsonData.params.statuses);

                    secondRecordCount = jsonData.records.length;

                    jqUnit.assertTrue("There should be more 'active' and 'deleted' records than 'active' records...", firstRecordCount < secondRecordCount);
                });
            });
        });
    }
);

// There should be records updated since the year 2000
recordTypeEndPoints.forEach(function(endPoint){
        jqUnit.asyncTest("Filter endpoint '" + endPoint + "' by future date...", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?updated=2000-01-01", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                var jsonData = JSON.parse(body);
                jqUnit.assertTrue("The results should include the date filter information passed in the query...", jsonData.params.updated);
                jqUnit.assertTrue("Limiting records by a date in the past should have returned results...", jsonData.records && jsonData.records.length > 0);
            });
        });
    }
);

// Confirm that /api/records?recordType=term returns the same number of records as /api/terms
recordTypeEndPoints.forEach(function(endPoint) {
    var recordType = recordTypesByEndpoint[endPoint];
    jqUnit.asyncTest("Testing endpoint '" + endPoint + "' versus records?recordType=" + recordType + "...", function() {
        var firstRecordCount, secondRecordCount, firstTotalRows, secondTotalRows;
        request.get("http://localhost:" + app.get('port') + "/records?recordType=" + recordType, function(error, response, body) {
            jqUnit.start();

            testUtils.isSaneResponse(jqUnit, error, response, body);

            var jsonData = JSON.parse(body);
            firstRecordCount = jsonData.records ? jsonData.records.length : 0;
            firstTotalRows = jsonData.total_rows;

            jqUnit.stop();

            request.get("http://localhost:" + app.get('port') + "/" + endPoint, function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                var jsonData = JSON.parse(body);
                secondRecordCount = jsonData.records ? jsonData.records.length : 0;
                secondTotalRows = jsonData.total_rows;

                jqUnit.assertEquals("There should be the same number of records returned for both records?recordType=" + recordType + " and /api/" + endPoint + "...", firstRecordCount, secondRecordCount);

                jqUnit.assertEquals("total_rows should be the same for both records?recordType=" + recordType + " and /api/" + endPoint + "...", firstTotalRows, secondTotalRows);
            });
        });
    });
});

// Confirm that the same number of terms are returned with and without the "children" option
jqUnit.asyncTest("Testing terms with and without children...", function() {
    var firstRecordCount, secondRecordCount, firstTotalRows, secondTotalRows;
    request.get("http://localhost:" + app.get('port') + "/terms", function(error, response, body) {
        jqUnit.start();

        testUtils.isSaneResponse(jqUnit, error, response, body);

        var jsonData = JSON.parse(body);
        firstRecordCount = jsonData.records ? jsonData.records.length : 0;
        firstTotalRows = jsonData.total_rows;

        jqUnit.stop();

        request.get("http://localhost:" + app.get('port') + "/terms?children=true" , function(error, response, body) {
            jqUnit.start();

            testUtils.isSaneResponse(jqUnit, error, response, body);

            var jsonData = JSON.parse(body);
            secondRecordCount = jsonData.records ? jsonData.records.length : 0;
            secondTotalRows = jsonData.total_rows;

            jqUnit.assertEquals("There should be the same number of records returned with and without children...", firstRecordCount, secondRecordCount);

            jqUnit.assertEquals("There should be the same total_rows returned with and without children......", firstTotalRows, secondTotalRows);
        });
    });
});

// There should be no records updated in the year 3000
recordTypeEndPoints.forEach(function(endPoint){
        jqUnit.asyncTest("Filter endpoint '" + endPoint + "' by future date...", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?updated=3000-01-01", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);

                var jsonData = JSON.parse(body);
                jqUnit.assertTrue("The results should include the date filter information passed in the query...", jsonData.params.updated);
                jqUnit.assertTrue("Limiting records by a far future date should not have returned anything...", jsonData.records && jsonData.records.length === 0);
            });
        });
    }
);

// Test that modules other than "records" do not support the recordType option
recordTypeEndPoints.forEach(function(endPoint){
    jqUnit.asyncTest("Query endpoint '" + endPoint + " with no arguments...", function() {
        jqUnit.start();
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?recordType=general", function(error, response, body) {

                testUtils.isSaneResponse(jqUnit, error, response, body);

                jqUnit.assertNotEquals("Asking the '" + endPoint + "' end point to return a specific record type should not have been successful...", response.statusCode, 200);
            });
        });
    }
);

// TODO:  Test "versions" functionality

// The output from "terms" and "records" should not include children with the "children" option set to false
["records","terms"].forEach(function(endPoint){
        jqUnit.asyncTest("Query endpoint '" + endPoint + " with the 'children' argument set to false...", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?children=false", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);
                var jsonData = JSON.parse(body);

                jqUnit.assertTrue("There should have been records returned...", jsonData.records);
                if (jsonData.records) {
                    jsonData.records.forEach(function(record) {
                        jqUnit.assertUndefined("Record '" + record.uniqueId + "' should not have contained any children", record.aliases);
                    });
                }
            });
        });
    }
);

// The output from "terms" and "records" should include children when the "children" option is set to true
["records","terms"].forEach(function(endPoint){
        jqUnit.asyncTest("Query endpoint '" + endPoint + " with the 'children' argument set to true...", function() {
            request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?children=true", function(error, response, body) {
                jqUnit.start();

                testUtils.isSaneResponse(jqUnit, error, response, body);
                var jsonData = JSON.parse(body);

                jqUnit.assertTrue("There should have been records returned...", jsonData.records);
                if (jsonData.records) {
                    var aliasesFound = false;
                    jsonData.records.forEach(function(record) {
                        if (record.aliases) { aliasesFound = true; }
                    });

                    jqUnit.assertTrue("There should have been at least one record with 'aliases' data...",aliasesFound);
                }
            });
        });
    }
);

// Test that modules other than "records" and "terms" do not support the "children" option
recordTypeEndPoints.forEach(function(endPoint){
        // skip "terms", which should support "children"
        if (endPoint !== "terms") {
            jqUnit.asyncTest("Query endpoint '" + endPoint + " with the 'children' argument set to true (should complain)...", function() {
                request.get("http://localhost:" + app.get('port') + "/" + endPoint + "?children=true", function(error, response, body) {
                    jqUnit.start();

                    testUtils.isSaneResponse(jqUnit, error, response, body);

                    jqUnit.assertNotEquals("Asking the '" + endPoint + "' end point to return children should not have been successful...", response.statusCode, 200);
                });
            });
        }
    }
);

jqUnit.onAllTestsDone.addListener(function() {
    // Shut down express (seems to happen implicitly, so commented out)
//    http.server.close();
});<|endoftext|>