<commit_before>/**
 * eBus is a JavaScript Event Pub Sub Bus
 * - Entities can attach a listener to an event
 * - Entities can publish events
 * - Entities can listen to events that happened in the past
 */

import EventClass from './models/event';
import ListenerClass from './models/listener';
import Logger from './logger';

class eBus {
    constructor(options) {
        this._eventListenerMap = new Map();
        this._eventTriggeredFlag = new Map();
    }

    /**
     * Attaches a listener to the eBus
     *
     * @param listenerPayload {object} Payload which will be needed to attach a listener to the eBus
     * listenerPayload : {
     *      name : <string>[Required] Uniquely Identify's a listener, which could be used while removing the listener,
     *      event : <Array>[Required] List of events which needs to be listened to,
     *      routine : <function> [Required] Routine that needs to be executing on event trigger,
     *      context : <object> [Optional] Context which can be passed on to the routine at the time of execution,
     *      options : <object> [Optional]
     * }
     * options : {
     *      once : <boolean> Makes the function to get executed only once on trigger,
     *      rememberPast: <boolean>, [ Pending ]
     *      throttle : <timestamp>, [ Pending ]
     *      target : <string>
     * }
     *
     * @return <Array> Returns an array of listenerId's
     */
    addListener(listenerPayload) {
        let listenerIdsList = [];
        if (!(listenerPayload instanceof Array)) {
            listenerPayload = [listenerPayload];
        }

        for (let payloadObj of listenerPayload) {
            let eventList = (payloadObj.event instanceof Array) ? payloadObj.event : [payloadObj.event];
            let listenerObj = new ListenerClass(payloadObj.name, payloadObj.routine, payloadObj.context, payloadObj.options);
            listenerIdsList.push(payloadObj.name);
            for (let event of eventList) {
                this._eventListenerMap.has(event) ? this._eventListenerMap.get(event).push(listenerObj) : this._eventListenerMap.set(event, [listenerObj]);
                Logger.log(payloadObj.name, 'listener is attached with', event);
            }
        }
        return listenerIdsList;
    }

    /**
     * Removes a listeners from the eBus
     *
     * @param listenerName {string}[Required] Uuid of the listner attaching context who want's to remove this listener.
     * @param eventName {string}[Required] Name of the event that need not to be listened any more.
     */
    removeListener(listenerName, eventName) {
        let listenersList = this._eventListenerMap.get(eventName);
        let updatedListnersList = [];

        for (let listener of listenersList) {
            if (listener.listenerUid != listenerName) {
                updatedListnersList.push(listener);
            }
        }
        this._eventListenerMap.set(eventName, updatedListnersList);
    }

    /**
     * Triggers an event on the eBus making all the sideEffects to be executed for such event
     *
     * @param event {string} [Required] Name of the event that is published
     * @param target {string} [Optional] The Uuid of the publisher who is publishing the event.
     * @param payload {Array} [Optional] The payload that the event publisher would want to be passed to all the side effects.
     */
    trigger(event, target, ...payload) {
        let listenersList = this._eventListenerMap.get(event);
        this._eventTriggeredFlag.set(event, {executed: true, payload: payload});
        for (let listener of listenersList) {
            listener.execute.apply(listener, [target, payload]);
        }
    }
}

export default eBus;<commit_msg>Added support for listening to events that occurred in the past<commit_after>/**
 * eBus is a JavaScript Event Pub Sub Bus
 * - Entities can attach a listener to an event
 * - Entities can publish events
 * - Entities can listen to events that happened in the past
 */

import EventClass from './models/event';
import ListenerClass from './models/listener';
import Logger from './logger';

function executeListenerRoutine(listener, target, payload) {
    listener.execute.apply(listener, [target, payload]);
}

class eBus {
    constructor(options) {
        this._eventListenerMap = new Map();
        this._eventTriggeredMap = new Map();
    }

    /**
     * Attaches a listener to the eBus
     *
     * @param listenerPayload {object} Payload which will be needed to attach a listener to the eBus
     * listenerPayload : {
     *      name : <string>[Required] Uniquely Identify's a listener, which could be used while removing the listener,
     *      event : <Array>[Required] List of events which needs to be listened to,
     *      routine : <function> [Required] Routine that needs to be executing on event trigger,
     *      context : <object> [Optional] Context which can be passed on to the routine at the time of execution,
     *      options : <object> [Optional]
     * }
     * options : {
     *      once : <boolean> Makes the function to get executed only once on trigger,
     *      rememberPast: <boolean>, [ Pending ]
     *      throttle : <timestamp>, [ Pending ]
     *      target : <string>
     * }
     *
     * @return <Array> Returns an array of listenerId's
     */
    addListener(listenerPayload) {
        let listenerIdsList = [];
        if (!(listenerPayload instanceof Array)) {
            listenerPayload = [listenerPayload];
        }

        for (let payloadObj of listenerPayload) {
            let eventList = (payloadObj.event instanceof Array) ? payloadObj.event : [payloadObj.event],
                listenerObj = new ListenerClass(payloadObj.name, payloadObj.routine, payloadObj.context, payloadObj.options),
                isListenToPastEvents = (payloadObj.options && payloadObj.options.rememberPast) || false;

            listenerIdsList.push(payloadObj.name);

            for (let event of eventList) {
                this._eventListenerMap.has(event) ? this._eventListenerMap.get(event).push(listenerObj) : this._eventListenerMap.set(event, [listenerObj]);
                Logger.log(payloadObj.name, 'listener is attached with', event);

                /**
                 * Executing the listener routine in case the listener wants to listen to events that happened in the past
                 */
                if(isListenToPastEvents){
                    let isEventTriggeredInPast = this._eventTriggeredMap.has(event) ? true : false,
                        lastEventPayload = isEventTriggeredInPast ? this._eventTriggeredMap.get(event) : void 0;

                    isEventTriggeredInPast ? executeListenerRoutine(listenerObj, lastEventPayload.target, lastEventPayload.payload) : void 0;
                }
            }
        }
        return listenerIdsList;
    }

    /**
     * Removes a listeners from the eBus
     *
     * @param listenerName {string}[Required] Uuid of the listner attaching context who want's to remove this listener.
     * @param eventName {string}[Required] Name of the event that need not to be listened any more.
     */
    removeListener(listenerName, eventName) {
        let listenersList = this._eventListenerMap.get(eventName) || [];
        let updatedListnersList = [];

        for (let listener of listenersList) {
            if (listener.listenerUid != listenerName) {
                updatedListnersList.push(listener);
            }
        }
        this._eventListenerMap.set(eventName, updatedListnersList);
    }

    /**
     * Triggers an event on the eBus making all the sideEffects to be executed for such event
     *
     * @param event {string} [Required] Name of the event that is published
     * @param target {string} [Optional] The Uuid of the publisher who is publishing the event.
     * @param payload {Array} [Optional] The payload that the event publisher would want to be passed to all the side effects.
     */
    trigger(event, target, ...payload) {
        let listenersList = this._eventListenerMap.get(event) || [];
        this._eventTriggeredMap.set(event, {executed: true, payload: payload, target: target});
        for (let listener of listenersList) {
            // listener.execute.apply(listener, [target, payload]);
            executeListenerRoutine(listener, target, payload);
        }
    }
}

export default eBus;<|endoftext|>


<commit_before>var BotKit = require('botkit');
var teamID;
module.exports = Ears;

var Bot = BotKit.slackbot({
  debug: false,
  storage: undefined
});

function Ears(token) {
  this.scopes = [
    'direct_mention',
    'direct_message',
    'mention'
  ];
  this.token = token;
}

Ears.prototype.listen = function(db) {
  console.log('TOKEN: ' + this.token);
  this.bot = Bot.spawn({
    token: this.token
  }).startRTM();

           this.bot.api.team.info((error, response) => {
              teamID = response.id;
            });

    // @ https://api.slack.com/methods/users.list
    this.bot.api.users.list({}, function (err, response) {
        if (response.hasOwnProperty('members') && response.ok) {
            var total = response.members.length;
            for (var i = 0; i < total; i++) {
                var member = response.members[i];
                var id = db.saveSync(teamID, {name: member.name, id: member.id});
                //fullTeamList.push({name: member.name, id: member.id});
            }
        }
    });
  return this;
}

Ears.prototype.hear = function(pattern, callback) {
  Bot.hears(pattern, this.scopes, callback);
  return this;
};
<commit_msg>Update ears.js<commit_after>var BotKit = require('botkit');
var teamID;
module.exports = Ears;

var Bot = BotKit.slackbot({
  debug: false,
  storage: undefined
});

function Ears(token) {
  this.scopes = [
    'direct_mention',
    'direct_message',
    'mention'
  ];
  this.token = token;
}

Ears.prototype.listen = function(db) {
  console.log('TOKEN: ' + this.token);
  this.bot = Bot.spawn({
    token: this.token
  }).startRTM();

           this.bot.api.team.info((error, response) => {
              teamID = response.id;
             console.log(teamID);
            });

    // @ https://api.slack.com/methods/users.list
    this.bot.api.users.list({}, function (err, response) {
        if (response.hasOwnProperty('members') && response.ok) {
            var total = response.members.length;
            for (var i = 0; i < total; i++) {
                var member = response.members[i];
                console.log(teamID);
                var id = db.saveSync(teamID, {name: member.name, id: member.id});
                //fullTeamList.push({name: member.name, id: member.id});
            }
        }
    });
  return this;
}

Ears.prototype.hear = function(pattern, callback) {
  Bot.hears(pattern, this.scopes, callback);
  return this;
};
<|endoftext|>


<commit_before>var send;
var shares = {};

if (!window.console) {
    var stub = function() { };
    window.console = { log: stub, warn: stub, error: stub };
}

function humanSize(size) {
    var units = ['T', 'G', 'M', 'K'];
    var unit = '';
    while(size >= 1024 && units.length > 0) {
	size /= 1024;
	unit = units.pop();
    }
    return (Math.round(size * 10) / 10) + ' ' +
	unit + 'B';
}

function Share(file, shareInfo) {
    var that = this;

    this.id = shareInfo.id;
    this.file = file;
    this.name = shareInfo.name;

    var div = $('

 ×

');
    div.find('.name').text(shareInfo.name);
    div.find('.name').attr('href', document.location.pathname + '/f' + this.id);
    div.find('.size').text(humanSize(shareInfo.size));
    div.find('a.remove').click(function(ev) {
	ev.preventDefault();
	that.remove();
    });
    div.hide();
    $('#shares').append(div);
    div.slideDown(500);
    this.div = div;
}

Share.prototype.remove = function() {
    var div = this.div;
    div.slideUp(250, function() {
	div.remove();
    });

    send({ unshare: { id: this.id } });
    delete shares[this.id];
    delete fileCache[this.name];
};

Share.prototype.upload = function(token, by) {
    var that = this;

    var up = new UploadProgress(this.div, by);
    var shut = function() {
	console.log({shut:arguments});
	up.end();
    };
    var reader = new FileReader();
    reader.onload = function() {
	console.log('read '+reader.result.length);

	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange = function() {
console.log('readyState: '+xhr.readyState);
	    if (xhr.readyState === 4)  // DONE
		shut();
	};
	xhr.onabort = shut;
	xhr.ontimeout = shut;
	xhr.onerror = shut;
	up.trackXHR(xhr);
console.log('post to '+document.location.pathname + '/f' + that.id + '/' + token);
	xhr.open("POST",
		 document.location.pathname + '/f' + that.id + '/' + token);
	if (xhr.sendAsBinary) {
	    xhr.setRequestHeader('Content-Type', 'application/octet-stream');
	    xhr.sendAsBinary(reader.result);
	} else {
	    xhr.setRequestHeader('Content-Type', 'application/base64');
	    xhr.send(window.btoa(reader.result));
	}
    };
    reader.onabort = shut;
    reader.onerror = shut;

    // give some time to render UploadProgress
    window.setTimeout(function() {
	console.log({reader:that.file});
	reader.readAsBinaryString(that.file);
    }, 10);
};

function UploadProgress(parent, by) {
    var p = $('
<canvas width="160" height="16"></canvas>
');
    this.p = p;
    parent.append(p);

    if (by)
	p.find('.by').text(by);

    this.progress = -1;
    this.draw();
}

UploadProgress.prototype.draw = function() {
    if (!this.canvas)
	this.canvas = this.p.find('canvas')[0];
    var ctx = this.canvas.getContext('2d');
    var w = this.canvas.width, h = this.canvas.height;

    ctx.clearRect(0, 0, w, h);

    ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
    ctx.lineWidth = 1;
    var line = function(x1, y1, x2, y2) {
	ctx.moveTo(x1, y1);
	ctx.lineTo(x2, y2);
	ctx.stroke();
    };

    /*line(0, 1, 0, h - 2);  // left
    line(1, 0, w - 2, 0);  // top
    line(1, h - 1, w - 2, h - 1);  // bottom
    line(w - 1, 1, w - 1, h - 2);  // right*/

    if (this.progress < 0) {
	ctx.globalAlpha = 0.2;
	ctx.fillStyle = '#800000';
	ctx.fillRect(1, 1, w - 2, h - 2);
    } else {
	ctx.globalAlpha = 0.8;
	ctx.fillStyle = '#AA0000';
	ctx.fillRect(1, 1, this.progress * (w - 2), h - 2);
    }
};

UploadProgress.prototype.trackXHR = function(xhr, by) {
    var that = this;

    if (!xhr.upload) {
	console.error('not receiving upload notifications');
	this.end();
	return;
    }

    xhr.upload.onloadstart = function() {
	that.progress = 0;
	that.draw();
    };
    xhr.upload.onprogress = function(ev) {
	that.progress = ev.loaded / ev.total;
	that.draw();
    };
    xhr.upload.onloadend = function() {
	console.log('onloadend');
	that.progress = 1;
	that.end();
    };
};

UploadProgress.prototype.end = function() {
console.log('up end');
    var p = this.p;
    p.fadeOut(1000, function() {
console.log('up remove');
	p.remove();
console.log('up removed');
    });
    this.draw();
};

function RemoteShare(shareInfo) {
    var li = $('

');
    var a = li.find('a');
    a.text(shareInfo.name);
    a.attr('href', document.location.pathname + '/f' + shareInfo.id);
    var size = li.find('.size');
    size.text(humanSize(shareInfo.size));
    if (shareInfo.by) {
	var by = $('');
	by.text(shareInfo.by);
	li.find('.meta').append(' by ').append(by);
    }

    li.hide();
    $('#remote').append(li);
    li.slideDown(500);

    this.li = li;
    this.id = shareInfo.id;
}

RemoteShare.prototype.remove = function() {
    var li = this.li;
    li.slideUp(500, function() {
	li.remove();
    });
    delete shares[this.id];
};

var fileCache = {};

function fileChosen(ev) {
    var files = $('#file')[0].files;
    for(var i = 0; i < files.length; i++) {
	var file = files.item(i);
	fileCache[file.name] = file;

	send({ share: { name: file.name,
			size: file.size,
			type: file.type } });
    }
    $('#file')[0].value = null;
};

// after reconnect:
function restoreFiles() {
    var delay = 0;
    for(var name in fileCache)
	if (fileCache.hasOwnProperty(name))
	    // call immediately, just to have scope for file
	    // independent of name
	    (function(file) {
		 delay += Math.floor(100 + Math.random() * 1000);
		 window.setTimeout(function() {
		     send({ share: { name: file.name,
				     size: file.size,
				     type: file.type } });
		 }, delay);
	     })(fileCache[name]);
}

function checkCompatibility() {
    var features = ["window.XMLHttpRequest",
		    "window.FileReader",
		    "window.btoa"];
    var missing = [];

    for(var i = 0; i < features.length; i++) {
	var feature = features[i];
	var present = false;
	try {
	    present = (eval(feature) !== undefined);
	} catch (x) {
	}
	if (!present)
	    missing.push(feature);
    }

    if (missing.length === 0) {
	return true;
    } else {
	return false;
    }
}

var socket = null;

function connect() {
    if (socket !== null)
	return;

    socket = new io.Socket(null,
			   { transports: ['websocket', 'htmlfile',
			                  'xhr-multipart', 'xhr-polling']
			   });
    var currentSocket = socket;
    var connectTimeout = window.setTimeout(function() {
	socket.disconnect();
	reconnect();
    }, 10000);
    socket.connect();

    send = function(json) {
	socket.send(JSON.stringify(json));
    };

    socket.on('connect', function(){
	send({ join: document.location.pathname });
	window.clearTimeout(connectTimeout);
	$('#loading').hide();
	$('#dashboard').show();

	if (checkCompatibility() === false) {
	    $('.left').find('h2').text('Sorry');
	    $('.left').find('.box').last().remove();
	    $('.left').append('

Sorry, your browser lacks some important features to share files. We recommend upgrading to Firefox 3.6 or 4.0 & Chromium 6 or 7.

');
	}

	$('#remote').find('li').remove();
	$('.left').find('.share').remove();
	restoreFiles();
    });
    socket.on('message', function(data){
console.log(data);
	var json;
	try {
	    json = JSON.parse(data);
	} catch (x) {
	    console.error("Cannot parse: " + data);
	    return;
	}

	if (json.shared && json.shared.id !== null) {
	    // Own share confirmed
	    if (fileCache[json.shared.name]) {
		shares[json.shared.id] = new Share(fileCache[json.shared.name], json.shared);
	    } else {
		send({ unshare: { id: json.shared.id } });
	    }
	}
	if (json.share && json.share.id) {
	    // New remote share
	    shares[json.share.id] = new RemoteShare(json.share);
	}
	if (json.transfer) {
	    // TODO: implement long path for error case
	    shares[json.transfer.id].upload(json.transfer.token, json.transfer.by);
	}
	if (json.unshare &&
	    json.unshare.id &&
	    shares.hasOwnProperty(json.unshare.id)) {
	    // already removes itself from shares & the DOM
	    shares[json.unshare.id].remove();
	}
    });

    var reconnect = function() {
	$('#dashboard').hide();
	$('#loading').show();

	if (socket === currentSocket)
	    socket = null;
	window.setTimeout(connect, Math.ceil((0.5 + 3 * Math.random()) * 1000));
    };
    socket.on('disconnect', reconnect);
}

$(document).ready(function() {
    connect();

    /* New file */
    $('#file').bind('change', fileChosen);
});

<commit_msg>checkCompatibility(): XMLHttpRequest.upload<commit_after>var send;
var shares = {};

if (!window.console) {
    var stub = function() { };
    window.console = { log: stub, warn: stub, error: stub };
}

function humanSize(size) {
    var units = ['T', 'G', 'M', 'K'];
    var unit = '';
    while(size >= 1024 && units.length > 0) {
	size /= 1024;
	unit = units.pop();
    }
    return (Math.round(size * 10) / 10) + ' ' +
	unit + 'B';
}

function Share(file, shareInfo) {
    var that = this;

    this.id = shareInfo.id;
    this.file = file;
    this.name = shareInfo.name;

    var div = $('

 ×

');
    div.find('.name').text(shareInfo.name);
    div.find('.name').attr('href', document.location.pathname + '/f' + this.id);
    div.find('.size').text(humanSize(shareInfo.size));
    div.find('a.remove').click(function(ev) {
	ev.preventDefault();
	that.remove();
    });
    div.hide();
    $('#shares').append(div);
    div.slideDown(500);
    this.div = div;
}

Share.prototype.remove = function() {
    var div = this.div;
    div.slideUp(250, function() {
	div.remove();
    });

    send({ unshare: { id: this.id } });
    delete shares[this.id];
    delete fileCache[this.name];
};

Share.prototype.upload = function(token, by) {
    var that = this;

    var up = new UploadProgress(this.div, by);
    var shut = function() {
	console.log({shut:arguments});
	up.end();
    };
    var reader = new FileReader();
    reader.onload = function() {
	console.log('read '+reader.result.length);

	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange = function() {
console.log('readyState: '+xhr.readyState);
	    if (xhr.readyState === 4)  // DONE
		shut();
	};
	xhr.onabort = shut;
	xhr.ontimeout = shut;
	xhr.onerror = shut;
	up.trackXHR(xhr);
console.log('post to '+document.location.pathname + '/f' + that.id + '/' + token);
	xhr.open("POST",
		 document.location.pathname + '/f' + that.id + '/' + token);
	if (xhr.sendAsBinary) {
	    xhr.setRequestHeader('Content-Type', 'application/octet-stream');
	    xhr.sendAsBinary(reader.result);
	} else {
	    xhr.setRequestHeader('Content-Type', 'application/base64');
	    xhr.send(window.btoa(reader.result));
	}
    };
    reader.onabort = shut;
    reader.onerror = shut;

    // give some time to render UploadProgress
    window.setTimeout(function() {
	console.log({reader:that.file});
	reader.readAsBinaryString(that.file);
    }, 10);
};

function UploadProgress(parent, by) {
    var p = $('
<canvas width="160" height="16"></canvas>
');
    this.p = p;
    parent.append(p);

    if (by)
	p.find('.by').text(by);

    this.progress = -1;
    this.draw();
}

UploadProgress.prototype.draw = function() {
    if (!this.canvas)
	this.canvas = this.p.find('canvas')[0];
    var ctx = this.canvas.getContext('2d');
    var w = this.canvas.width, h = this.canvas.height;

    ctx.clearRect(0, 0, w, h);

    ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
    ctx.lineWidth = 1;
    var line = function(x1, y1, x2, y2) {
	ctx.moveTo(x1, y1);
	ctx.lineTo(x2, y2);
	ctx.stroke();
    };

    /*line(0, 1, 0, h - 2);  // left
    line(1, 0, w - 2, 0);  // top
    line(1, h - 1, w - 2, h - 1);  // bottom
    line(w - 1, 1, w - 1, h - 2);  // right*/

    if (this.progress < 0) {
	ctx.globalAlpha = 0.2;
	ctx.fillStyle = '#800000';
	ctx.fillRect(1, 1, w - 2, h - 2);
    } else {
	ctx.globalAlpha = 0.8;
	ctx.fillStyle = '#AA0000';
	ctx.fillRect(1, 1, this.progress * (w - 2), h - 2);
    }
};

UploadProgress.prototype.trackXHR = function(xhr, by) {
    var that = this;

    if (!xhr.upload) {
	console.error('not receiving upload notifications');
	this.end();
	return;
    }

    xhr.upload.onloadstart = function() {
	that.progress = 0;
	that.draw();
    };
    xhr.upload.onprogress = function(ev) {
	that.progress = ev.loaded / ev.total;
	that.draw();
    };
    xhr.upload.onloadend = function() {
	console.log('onloadend');
	that.progress = 1;
	that.end();
    };
};

UploadProgress.prototype.end = function() {
console.log('up end');
    var p = this.p;
    p.fadeOut(1000, function() {
console.log('up remove');
	p.remove();
console.log('up removed');
    });
    this.draw();
};

function RemoteShare(shareInfo) {
    var li = $('

');
    var a = li.find('a');
    a.text(shareInfo.name);
    a.attr('href', document.location.pathname + '/f' + shareInfo.id);
    var size = li.find('.size');
    size.text(humanSize(shareInfo.size));
    if (shareInfo.by) {
	var by = $('');
	by.text(shareInfo.by);
	li.find('.meta').append(' by ').append(by);
    }

    li.hide();
    $('#remote').append(li);
    li.slideDown(500);

    this.li = li;
    this.id = shareInfo.id;
}

RemoteShare.prototype.remove = function() {
    var li = this.li;
    li.slideUp(500, function() {
	li.remove();
    });
    delete shares[this.id];
};

var fileCache = {};

function fileChosen(ev) {
    var files = $('#file')[0].files;
    for(var i = 0; i < files.length; i++) {
	var file = files.item(i);
	fileCache[file.name] = file;

	send({ share: { name: file.name,
			size: file.size,
			type: file.type } });
    }
    $('#file')[0].value = null;
};

// after reconnect:
function restoreFiles() {
    var delay = 0;
    for(var name in fileCache)
	if (fileCache.hasOwnProperty(name))
	    // call immediately, just to have scope for file
	    // independent of name
	    (function(file) {
		 delay += Math.floor(100 + Math.random() * 1000);
		 window.setTimeout(function() {
		     send({ share: { name: file.name,
				     size: file.size,
				     type: file.type } });
		 }, delay);
	     })(fileCache[name]);
}

function checkCompatibility() {
    var features = ["window.XMLHttpRequest",
		    "(new XMLHttpRequest()).upload",
		    "window.FileReader",
		    "window.btoa"];
    var missing = [];

    for(var i = 0; i < features.length; i++) {
	var feature = features[i];
	var present = false;
	try {
	    present = (eval(feature) !== undefined);
	} catch (x) {
	}
	if (!present)
	    missing.push(feature);
    }

    if (missing.length === 0) {
	return true;
    } else {
	return false;
    }
}

var socket = null;

function connect() {
    if (socket !== null)
	return;

    socket = new io.Socket(null,
			   { transports: ['websocket', 'htmlfile',
			                  'xhr-multipart', 'xhr-polling']
			   });
    var currentSocket = socket;
    var connectTimeout = window.setTimeout(function() {
	socket.disconnect();
	reconnect();
    }, 10000);
    socket.connect();

    send = function(json) {
	socket.send(JSON.stringify(json));
    };

    socket.on('connect', function(){
	send({ join: document.location.pathname });
	window.clearTimeout(connectTimeout);
	$('#loading').hide();
	$('#dashboard').show();

	if (checkCompatibility() === false) {
	    $('.left').find('h2').text('Sorry');
	    $('.left').find('.box').last().remove();
	    $('.left').append('

Sorry, your browser lacks some important features to share files. We recommend upgrading to Firefox 3.6 or 4.0 & Chromium 6 or 7.

');
	}

	$('#remote').find('li').remove();
	$('.left').find('.share').remove();
	restoreFiles();
    });
    socket.on('message', function(data){
console.log(data);
	var json;
	try {
	    json = JSON.parse(data);
	} catch (x) {
	    console.error("Cannot parse: " + data);
	    return;
	}

	if (json.shared && json.shared.id !== null) {
	    // Own share confirmed
	    if (fileCache[json.shared.name]) {
		shares[json.shared.id] = new Share(fileCache[json.shared.name], json.shared);
	    } else {
		send({ unshare: { id: json.shared.id } });
	    }
	}
	if (json.share && json.share.id) {
	    // New remote share
	    shares[json.share.id] = new RemoteShare(json.share);
	}
	if (json.transfer) {
	    // TODO: implement long path for error case
	    shares[json.transfer.id].upload(json.transfer.token, json.transfer.by);
	}
	if (json.unshare &&
	    json.unshare.id &&
	    shares.hasOwnProperty(json.unshare.id)) {
	    // already removes itself from shares & the DOM
	    shares[json.unshare.id].remove();
	}
    });

    var reconnect = function() {
	$('#dashboard').hide();
	$('#loading').show();

	if (socket === currentSocket)
	    socket = null;
	window.setTimeout(connect, Math.ceil((0.5 + 3 * Math.random()) * 1000));
    };
    socket.on('disconnect', reconnect);
}

$(document).ready(function() {
    connect();

    /* New file */
    $('#file').bind('change', fileChosen);
});

<|endoftext|>


<commit_before>var Common = require('./common');
var _ = require('./utils');
var Components = require('./component');
var state = require('./state');
var registerWebComponent = require('./webcomponent').registerWebComponent;
var Stringifier = require('./stringify');
var Dispatcher = require('./events');

exports.svgNS = "http://www.w3.org/2000/svg";

function styleToString(attrs) {
  if (_.isUndefined(attrs)) return '';
  var attrsArray = _.map(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (key === 'className') {
      keyName = 'class';
    }
    var value = attrs[key];
    if (!_.isUndefined(value) && _.isFunction(value)) {
      value = value();
    }
    if (!_.isUndefined(value)) {
      return keyName + ': ' + value + ';';
    } else {
      return undefined;
    }
  });
  attrsArray = _.filter(attrsArray, function(item) {
    return !_.isUndefined(item);
  });
  return attrsArray.join(' ');
}

function classToArray(attrs) { /* Handle class as object with boolean values */
  if (_.isUndefined(attrs)) return [];
  var attrsArray = _.map(_.keys(attrs), function(key) {
    var value = attrs[key];
    if (!_.isUndefined(value) && value === true) {
      return _.dasherize(key);
    } else {
      return undefined;
    }
  });
  attrsArray = _.filter(attrsArray, function(item) {
    return !_.isUndefined(item);
  });
  return attrsArray;
}

function wrapChildren(children) {
  if (children === 0) {
    return children;
  } else if (children === '') {
    return [];
  }
  return children || [];
}

function buildRef(id) {
  return {
    getDOMNode: function() {
      return _.findNode('[data-nodeid="' + id + '"]');
    }
  };
}

function extractEventHandlers(attrs, nodeId, context) {
  _.each(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (_.startsWith(keyName, 'on')) {
      if (context && context.waitingHandlers) {
        context.waitingHandlers.push({
          root: context.root,
          id: nodeId,
          event: keyName,
          callback: attrs[key]
        });
      }
    }
    if (keyName === 'ref' && context && context.refs) context.refs[attrs[key]] = buildRef(nodeId);
  });
}

function asAttribute(key, value) {
  return {
    key: key,
    value: value
  };
}

function attributesToArray(attrs) {
  if (_.isUndefined(attrs)) return [];
  var attrsArray = [];
  _.each(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (key === 'className') {
      keyName = 'class';
    }
    if (!_.startsWith(keyName, 'on') && keyName !== 'ref') {
      var value = attrs[key];
      if (!_.isUndefined(value) && _.isFunction(value)) {
        value = value();
      }
      if (!_.isUndefined(value)) {
        if (_.isObject(value) && keyName === 'style') {
          attrsArray.push(asAttribute('style', styleToString(value)));
        } else if (_.isArray(value) && keyName === 'class') {
          attrsArray.push(asAttribute(keyName, value.join(' ')));
        } else if (_.isObject(value) && keyName === 'class') {
          attrsArray.push(asAttribute(keyName, classToArray(value).join(' ')));
        } else {
          attrsArray.push(asAttribute(keyName, value));
        }
      }
    }
  });
  return attrsArray;
}

function el(name, attrs, children) {
  var svg = attrs.namespace;
  delete attrs.namespace;
  var nodeId = _.uniqueId('node_');
  if (_.isUndefined(children) && !_.isUndefined(attrs) && !attrs.__isAttrs) {
    children = attrs;
    attrs = {};
  }
  if (arguments.length > 3) {
    name = arguments[0];
    if (!attrs.isElement) {
      attrs = arguments[1];
    } else {
      attrs = {};
    }
    children = [].concat(arguments);
    children.shift();
    children.shift();
  }
  name = _.escape(name) || 'unknown';
  attrs = attrs || {};
  children = wrapChildren(children);
  if (_.isRegExp(children) || _.isUndefined(children) || _.isNull(children)) children = [];
  if (_.isArray(children)) {
    children = _.chain(children).map(function(child) {
      if (_.isFunction(child)) {
        return child();
      } else {
        return child;
      }
    }).filter(function(item) {
      return !_.isUndefined(item);
    }).value();
  }
  var selfCloseTag = _.contains(Common.voidElements, name.toUpperCase()) && (_.isNull(children) || _.isUndefined(children) || (_.isArray(children) && children.length === 0));
  var attrsArray = attributesToArray(attrs);
  attrsArray.push(asAttribute('data-nodeid', _.escape(nodeId)));
  if (Common.debug) attrsArray.push(asAttribute('title', _.escape(nodeId)));
  return {
    name: name,
    attrs: attrs,
    children: children,
    isElement: true,
    nodeId: nodeId,
    toJsonString: function(pretty) {
      if (pretty) return JSON.stringify(this, null, 2);
      return JSON.stringify(this);
    },
    toHtmlNode: function(doc, context) {
      var elemName = this.name;
      extractEventHandlers(attrs, nodeId, context);
      var element = undefined;
      if (svg) {
        element = doc.createElementNS(svg, _.escape(name));
      } else {
        element = doc.createElement(_.escape(name));
      }
      _.each(attrsArray, function(item) {
        if (elemName && elemName === 'input' && item.key === 'value') {
          element.value = item.value;
        } else {
          element.setAttribute(item.key, item.value);
        }
      });

      function appendSingleNode(__children, __element) {
        if (_.isNumber(__children)) {
          __element.appendChild(doc.createTextNode(__children + ''));
        } else if (_.isString(__children)) {
          __element.appendChild(doc.createTextNode(__children));
        } else if (_.isBoolean(__children)) {
          __element.appendChild(doc.createTextNode(__children + ''));
        } else if (_.isObject(__children) && __children.isElement) {
          __element.appendChild(__children.toHtmlNode(doc, context));
        } else if (_.isObject(__children) && __children.__asHtml) {
          __element.innerHTML = __children.__asHtml;
        } else if (__children.__componentFactory) {
          var compId = _.escape(_.uniqueId('component_'));
          var span = doc.createElement('span');
          span.setAttribute('data-componentid', compId);
          __element.appendChild(span);
          context.__innerComponents.push('[data-componentid="' + compId + '"]');
          __children.renderTo('[data-componentid="' + compId + '"]', true);
        } else {
          __element.appendChild(doc.createTextNode(__children.toString()));
        }
      }
      if (!selfCloseTag) {
        if (_.isArray(children)) {
          _.each(children, function(child) {
            appendSingleNode(child, element);
          });
        } else {
          appendSingleNode(children, element);
        }
      }
      return element;
    }
  };
}

function renderToNode(el, doc, context) {
  if (_.isFunction(el)) el = el((context || {
    props: {}
  }).props)
  if (!_.isUndefined(el)) {
    if (_.isArray(el)) {
      return _.chain(el).map(function(item) {
        if (_.isFunction(item)) {
          return item();
        } else {
          return item;
        }
      }).filter(function(item) {
        return !_.isUndefined(item);
      }).map(function(item) {
        return item.toHtmlNode(doc, context);
      }).value();
    } else {
      return [el.toHtmlNode(doc, context)];
    }
  } else {
    return [];
  }
}

exports.renderToString = function(el, context) {
  Common.markStart('Elem.renderToString');
  var str = _.map(renderToNode(el, Stringifier(context)), function(n) {
    return n.toHtmlString();
  }).join('');
  Common.markStop('Elem.renderToString');
  return str;
};

exports.renderToStaticHtml = function(el) {
  Common.markStart('Elem.renderToStaticHtml');
  var str = _.map(renderToNode(el, Stringifier({
    __noDataId: true
  })), function(n) {
    return n.toHtmlString();
  }).join('');
  Common.markStop('Elem.renderToStaticHtml');
  return str;
}

exports.el = el;

exports.jsx = function(name, attrs, children) {
  return attrs === null ? vel(name, children) : el(name, attrs, children);
}

exports.sel = function(name, children) {
  return el(name, {}, children);
}; // simple node sel(name, children)

exports.vel = function(name, attrs) {
  return el(name, attrs, []);
}; // void node, cel(name, attrs)

exports.svg = function(name, attrs, children) {
  attrs.namespace = exports.svgNS;
  if (!children) {
    return el(name, {}, attrs);
  }
  return el(name, attrs, children);
};

exports.vsvg = function(name, attrs) {
  attrs.namespace = exports.svgNS;
  return el(name, attrs, []);
};

exports.nbsp = function(times) {
  return el('span', {
    __asHtml: _.times(times || 1, function() {
      return ' ';
    })
  });
};

exports.text = function(text) {
  return el('span', {}, text);
};

exports.render = function(el, node, context) {
  Common.markStart('Elem.render');
  var waitingHandlers = (context || {}).waitingHandlers || [];
  var refs = (context || {}).refs || {};
  var props = (context || {}).props || {};
  var __innerComponents = (context || {}).__innerComponents || [];
  var doc = document;
  if (node.ownerDocument) {
    doc = node.ownerDocument;
  }
  if (_.isString(node)) {
    node = doc.querySelector(node);
  }
  if (!_.isUndefined(node) && !_.isNull(node)) {
    var htmlNode = renderToNode(el, doc, {
      root: node,
      waitingHandlers: waitingHandlers,
      refs: refs,
      props: props,
      __innerComponents: __innerComponents
    });
    while (!_.isUndefined(node) && !_.isNull(node) && node.firstChild) {
      node.removeChild(node.firstChild);
    }
    _.each(htmlNode, function(n) {
      if (!_.isUndefined(node) && !_.isNull(node)) node.appendChild(n);
    });
    if (!(context && context.__rootListener)) { // external listener here
      _.each(waitingHandlers, function(handler) { // handler on each concerned node
        _.on('[data-nodeid="' + handler.id + '"]', [handler.event.replace('on', '')], function() {
          handler.callback.apply({}, arguments);
        });
      });
    }
  }
  Common.markStop('Elem.render');
};
exports.unmountComponent = Components.unmountComponent;
exports.component = Components.component;
exports.componentToString = Components.componentToString;
exports.state = state;
exports.Utils = _;
exports.registerWebComponent = registerWebComponent;
exports.dispatcher = Dispatcher;
exports.Perf = {
  start: function() {
    Common.perfs = true;
  },
  stop: function() {
    Common.stop = false;
  },
  markStart: Common.markStart,
  markStop: Common.markStop,
  collectMeasures: Common.collectMeasures,
  printMeasures: Common.printMeasures
};
exports.defer = Common.defer;
exports.predicate = function(predicate, what) {
  if (_.isFunction(predicate)) {
    if (predicate() === true) {
      return what;
    } else {
      return undefined;
    }
  } else {
    if (predicate === true) {
      return what;
    } else {
      return undefined;
    }
  }
};
exports.style = function(obj) {
  var result = {};
  var keys = _.keys(obj);
  _.each(keys, function(key) {
    var clazz = obj[key];
    if (_.isObject(clazz)) {
      result[key] = _.extend({}, {
        extend: function(o) {
          return _.extend({}, o, clazz);
        }
      }, clazz);
    }
  });
  result.extend = _.extend({}, {
    extend: function(o) {
      return _.extend({}, o, obj);
    }
  }, obj);
  return result;
};

Common.__internalAccess.api = exports;

if (typeof define === 'function' && define.amd) {
  define('elem', [], function() {
    return module.exports;
  });
}
<commit_msg>Fix ...children es6 syntax :)<commit_after>var Common = require('./common');
var _ = require('./utils');
var Components = require('./component');
var state = require('./state');
var registerWebComponent = require('./webcomponent').registerWebComponent;
var Stringifier = require('./stringify');
var Dispatcher = require('./events');

exports.svgNS = "http://www.w3.org/2000/svg";

function styleToString(attrs) {
  if (_.isUndefined(attrs)) return '';
  var attrsArray = _.map(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (key === 'className') {
      keyName = 'class';
    }
    var value = attrs[key];
    if (!_.isUndefined(value) && _.isFunction(value)) {
      value = value();
    }
    if (!_.isUndefined(value)) {
      return keyName + ': ' + value + ';';
    } else {
      return undefined;
    }
  });
  attrsArray = _.filter(attrsArray, function(item) {
    return !_.isUndefined(item);
  });
  return attrsArray.join(' ');
}

function classToArray(attrs) { /* Handle class as object with boolean values */
  if (_.isUndefined(attrs)) return [];
  var attrsArray = _.map(_.keys(attrs), function(key) {
    var value = attrs[key];
    if (!_.isUndefined(value) && value === true) {
      return _.dasherize(key);
    } else {
      return undefined;
    }
  });
  attrsArray = _.filter(attrsArray, function(item) {
    return !_.isUndefined(item);
  });
  return attrsArray;
}

function wrapChildren(children) {
  if (children === 0) {
    return children;
  } else if (children === '') {
    return [];
  }
  return children || [];
}

function buildRef(id) {
  return {
    getDOMNode: function() {
      return _.findNode('[data-nodeid="' + id + '"]');
    }
  };
}

function extractEventHandlers(attrs, nodeId, context) {
  _.each(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (_.startsWith(keyName, 'on')) {
      if (context && context.waitingHandlers) {
        context.waitingHandlers.push({
          root: context.root,
          id: nodeId,
          event: keyName,
          callback: attrs[key]
        });
      }
    }
    if (keyName === 'ref' && context && context.refs) context.refs[attrs[key]] = buildRef(nodeId);
  });
}

function asAttribute(key, value) {
  return {
    key: key,
    value: value
  };
}

function attributesToArray(attrs) {
  if (_.isUndefined(attrs)) return [];
  var attrsArray = [];
  _.each(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (key === 'className') {
      keyName = 'class';
    }
    if (!_.startsWith(keyName, 'on') && keyName !== 'ref') {
      var value = attrs[key];
      if (!_.isUndefined(value) && _.isFunction(value)) {
        value = value();
      }
      if (!_.isUndefined(value)) {
        if (_.isObject(value) && keyName === 'style') {
          attrsArray.push(asAttribute('style', styleToString(value)));
        } else if (_.isArray(value) && keyName === 'class') {
          attrsArray.push(asAttribute(keyName, value.join(' ')));
        } else if (_.isObject(value) && keyName === 'class') {
          attrsArray.push(asAttribute(keyName, classToArray(value).join(' ')));
        } else {
          attrsArray.push(asAttribute(keyName, value));
        }
      }
    }
  });
  return attrsArray;
}

function el(name, attrs, children) {
  var svg = attrs.namespace;
  delete attrs.namespace;
  var nodeId = _.uniqueId('node_');
  if (_.isUndefined(children) && !_.isUndefined(attrs) && !attrs.__isAttrs) {
    children = attrs;
    attrs = {};
  }
  if (arguments.length > 3) {
    name = arguments[0];
    if (!attrs.isElement) {
      attrs = arguments[1];
    } else {
      attrs = {};
    }
    children = [].concat(arguments);
    children.shift();
    children.shift();
  }
  name = _.escape(name) || 'unknown';
  attrs = attrs || {};
  children = wrapChildren(children);
  if (_.isRegExp(children) || _.isUndefined(children) || _.isNull(children)) children = [];
  if (_.isArray(children)) {
    children = _.chain(children).map(function(child) {
      if (_.isFunction(child)) {
        return child();
      } else {
        return child;
      }
    }).filter(function(item) {
      return !_.isUndefined(item);
    }).value();
  }
  var selfCloseTag = _.contains(Common.voidElements, name.toUpperCase()) && (_.isNull(children) || _.isUndefined(children) || (_.isArray(children) && children.length === 0));
  var attrsArray = attributesToArray(attrs);
  attrsArray.push(asAttribute('data-nodeid', _.escape(nodeId)));
  if (Common.debug) attrsArray.push(asAttribute('title', _.escape(nodeId)));
  return {
    name: name,
    attrs: attrs,
    children: children,
    isElement: true,
    nodeId: nodeId,
    toJsonString: function(pretty) {
      if (pretty) return JSON.stringify(this, null, 2);
      return JSON.stringify(this);
    },
    toHtmlNode: function(doc, context) {
      var elemName = this.name;
      extractEventHandlers(attrs, nodeId, context);
      var element = undefined;
      if (svg) {
        element = doc.createElementNS(svg, _.escape(name));
      } else {
        element = doc.createElement(_.escape(name));
      }
      _.each(attrsArray, function(item) {
        if (elemName && elemName === 'input' && item.key === 'value') {
          element.value = item.value;
        } else {
          element.setAttribute(item.key, item.value);
        }
      });

      function appendSingleNode(__children, __element) {
        if (_.isNumber(__children)) {
          __element.appendChild(doc.createTextNode(__children + ''));
        } else if (_.isString(__children)) {
          __element.appendChild(doc.createTextNode(__children));
        } else if (_.isBoolean(__children)) {
          __element.appendChild(doc.createTextNode(__children + ''));
        } else if (_.isObject(__children) && __children.isElement) {
          __element.appendChild(__children.toHtmlNode(doc, context));
        } else if (_.isObject(__children) && __children.__asHtml) {
          __element.innerHTML = __children.__asHtml;
        } else if (__children.__componentFactory) {
          var compId = _.escape(_.uniqueId('component_'));
          var span = doc.createElement('span');
          span.setAttribute('data-componentid', compId);
          __element.appendChild(span);
          context.__innerComponents.push('[data-componentid="' + compId + '"]');
          __children.renderTo('[data-componentid="' + compId + '"]', true);
        } else {
          __element.appendChild(doc.createTextNode(__children.toString()));
        }
      }
      if (!selfCloseTag) {
        if (_.isArray(children)) {
          _.each(children, function(child) {
            appendSingleNode(child, element);
          });
        } else {
          appendSingleNode(children, element);
        }
      }
      return element;
    }
  };
}

function renderToNode(el, doc, context) {
  if (_.isFunction(el)) el = el((context || {
    props: {}
  }).props)
  if (!_.isUndefined(el)) {
    if (_.isArray(el)) {
      return _.chain(el).map(function(item) {
        if (_.isFunction(item)) {
          return item();
        } else {
          return item;
        }
      }).filter(function(item) {
        return !_.isUndefined(item);
      }).map(function(item) {
        return item.toHtmlNode(doc, context);
      }).value();
    } else {
      return [el.toHtmlNode(doc, context)];
    }
  } else {
    return [];
  }
}

exports.renderToString = function(el, context) {
  Common.markStart('Elem.renderToString');
  var str = _.map(renderToNode(el, Stringifier(context)), function(n) {
    return n.toHtmlString();
  }).join('');
  Common.markStop('Elem.renderToString');
  return str;
};

exports.renderToStaticHtml = function(el) {
  Common.markStart('Elem.renderToStaticHtml');
  var str = _.map(renderToNode(el, Stringifier({
    __noDataId: true
  })), function(n) {
    return n.toHtmlString();
  }).join('');
  Common.markStop('Elem.renderToStaticHtml');
  return str;
}

exports.el = el;

exports.jsx = function(name, attrs) {
  for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
    children[_key - 2] = arguments[_key];
  }
  return attrs === null ? vel(name, children) : el(name, attrs, children);
}

exports.sel = function(name, children) {
  return el(name, {}, children);
}; // simple node sel(name, children)

exports.vel = function(name, attrs) {
  return el(name, attrs, []);
}; // void node, cel(name, attrs)

exports.svg = function(name, attrs, children) {
  attrs.namespace = exports.svgNS;
  if (!children) {
    return el(name, {}, attrs);
  }
  return el(name, attrs, children);
};

exports.vsvg = function(name, attrs) {
  attrs.namespace = exports.svgNS;
  return el(name, attrs, []);
};

exports.nbsp = function(times) {
  return el('span', {
    __asHtml: _.times(times || 1, function() {
      return ' ';
    })
  });
};

exports.text = function(text) {
  return el('span', {}, text);
};

exports.render = function(el, node, context) {
  Common.markStart('Elem.render');
  var waitingHandlers = (context || {}).waitingHandlers || [];
  var refs = (context || {}).refs || {};
  var props = (context || {}).props || {};
  var __innerComponents = (context || {}).__innerComponents || [];
  var doc = document;
  if (node.ownerDocument) {
    doc = node.ownerDocument;
  }
  if (_.isString(node)) {
    node = doc.querySelector(node);
  }
  if (!_.isUndefined(node) && !_.isNull(node)) {
    var htmlNode = renderToNode(el, doc, {
      root: node,
      waitingHandlers: waitingHandlers,
      refs: refs,
      props: props,
      __innerComponents: __innerComponents
    });
    while (!_.isUndefined(node) && !_.isNull(node) && node.firstChild) {
      node.removeChild(node.firstChild);
    }
    _.each(htmlNode, function(n) {
      if (!_.isUndefined(node) && !_.isNull(node)) node.appendChild(n);
    });
    if (!(context && context.__rootListener)) { // external listener here
      _.each(waitingHandlers, function(handler) { // handler on each concerned node
        _.on('[data-nodeid="' + handler.id + '"]', [handler.event.replace('on', '')], function() {
          handler.callback.apply({}, arguments);
        });
      });
    }
  }
  Common.markStop('Elem.render');
};
exports.unmountComponent = Components.unmountComponent;
exports.component = Components.component;
exports.componentToString = Components.componentToString;
exports.state = state;
exports.Utils = _;
exports.registerWebComponent = registerWebComponent;
exports.dispatcher = Dispatcher;
exports.Perf = {
  start: function() {
    Common.perfs = true;
  },
  stop: function() {
    Common.stop = false;
  },
  markStart: Common.markStart,
  markStop: Common.markStop,
  collectMeasures: Common.collectMeasures,
  printMeasures: Common.printMeasures
};
exports.defer = Common.defer;
exports.predicate = function(predicate, what) {
  if (_.isFunction(predicate)) {
    if (predicate() === true) {
      return what;
    } else {
      return undefined;
    }
  } else {
    if (predicate === true) {
      return what;
    } else {
      return undefined;
    }
  }
};
exports.style = function(obj) {
  var result = {};
  var keys = _.keys(obj);
  _.each(keys, function(key) {
    var clazz = obj[key];
    if (_.isObject(clazz)) {
      result[key] = _.extend({}, {
        extend: function(o) {
          return _.extend({}, o, clazz);
        }
      }, clazz);
    }
  });
  result.extend = _.extend({}, {
    extend: function(o) {
      return _.extend({}, o, obj);
    }
  }, obj);
  return result;
};

Common.__internalAccess.api = exports;

if (typeof define === 'function' && define.amd) {
  define('elem', [], function() {
    return module.exports;
  });
}
<|endoftext|>


<commit_before>var Common = require('./common');
var _ = require('./utils');
var Components = require('./component');
var state = require('./state');
var registerWebComponent = require('./webcomponent').registerWebComponent;
var Stringifier = require('./stringify');
var Dispatcher = require('./events');

exports.svgNS = "http://www.w3.org/2000/svg";

function styleToString(attrs) {
  if (_.isUndefined(attrs)) return '';
  var attrsArray = _.map(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (key === 'className') {
      keyName = 'class';
    }
    var value = attrs[key];
    if (!_.isUndefined(value) && _.isFunction(value)) {
      value = value();
    }
    if (!_.isUndefined(value)) {
      return keyName + ': ' + value + ';';
    } else {
      return undefined;
    }
  });
  attrsArray = _.filter(attrsArray, function(item) {
    return !_.isUndefined(item);
  });
  return attrsArray.join(' ');
}

function classToArray(attrs) { /* Handle class as object with boolean values */
  if (_.isUndefined(attrs)) return [];
  var attrsArray = _.map(_.keys(attrs), function(key) {
    var value = attrs[key];
    if (!_.isUndefined(value) && value === true) {
      return _.dasherize(key);
    } else {
      return undefined;
    }
  });
  attrsArray = _.filter(attrsArray, function(item) {
    return !_.isUndefined(item);
  });
  return attrsArray;
}

function wrapChildren(children) {
  if (children === 0) {
    return children;
  } else if (children === '') {
    return [];
  }
  return children || [];
}

function buildRef(id) {
  return {
    getDOMNode: function() {
      return _.findNode('[data-nodeid="' + id + '"]');
    }
  };
}

function extractEventHandlers(attrs, nodeId, context) {
  _.each(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (_.startsWith(keyName, 'on')) {
      if (context && context.waitingHandlers) {
        context.waitingHandlers.push({
          root: context.root,
          id: nodeId,
          event: keyName.toLowerCase(),
          callback: attrs[key]
        });
      }
    }
    if (keyName === 'ref' && context && context.refs) context.refs[attrs[key]] = buildRef(nodeId);
  });
}

function asAttribute(key, value) {
  return {
    key: key,
    value: value
  };
}

function attributesToArray(attrs) {
  if (_.isUndefined(attrs)) return [];
  var attrsArray = [];
  _.each(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (key === 'className') {
      keyName = 'class';
    }
    if (!_.startsWith(keyName, 'on') && keyName !== 'ref') {
      var value = attrs[key];
      if (!_.isUndefined(value) && _.isFunction(value)) {
        value = value();
      }
      if (!_.isUndefined(value)) {
        if (_.isObject(value) && keyName === 'style') {
          attrsArray.push(asAttribute('style', styleToString(value)));
        } else if (_.isArray(value) && keyName === 'class') {
          attrsArray.push(asAttribute(keyName, value.join(' ')));
        } else if (_.isObject(value) && keyName === 'class') {
          attrsArray.push(asAttribute(keyName, classToArray(value).join(' ')));
        } else {
          attrsArray.push(asAttribute(keyName, value));
        }
      }
    }
  });
  return attrsArray;
}

function el(name, attrs, children) {
  var svg = attrs.namespace;
  delete attrs.namespace;
  var nodeId = _.uniqueId('node_');
  if (_.isUndefined(children) && !_.isUndefined(attrs) && !attrs.__isAttrs) {
    children = attrs;
    attrs = {};
  }
  if (arguments.length > 3) {
    name = arguments[0];
    if (!attrs.isElement) {
      attrs = arguments[1];
    } else {
      attrs = {};
    }
    children = [].concat(arguments);
    children.shift();
    children.shift();
  }
  name = _.escape(name) || 'unknown';
  attrs = attrs || {};
  children = wrapChildren(children);
  if (_.isRegExp(children) || _.isUndefined(children) || _.isNull(children)) children = [];
  if (_.isArray(children)) {
    children = _.chain(children).map(function(child) {
      if (_.isFunction(child)) {
        return child();
      } else {
        return child;
      }
    }).filter(function(item) {
      return !_.isUndefined(item);
    }).value();
  }
  var selfCloseTag = _.contains(Common.voidElements, name.toUpperCase()) && (_.isNull(children) || _.isUndefined(children) || (_.isArray(children) && children.length === 0));
  var attrsArray = attributesToArray(attrs);
  attrsArray.push(asAttribute('data-nodeid', _.escape(nodeId)));
  if (Common.debug) attrsArray.push(asAttribute('title', _.escape(nodeId)));
  return {
    name: name,
    attrs: attrs,
    children: children,
    isElement: true,
    nodeId: nodeId,
    toJsonString: function(pretty) {
      if (pretty) return JSON.stringify(this, null, 2);
      return JSON.stringify(this);
    },
    toHtmlNode: function(doc, context) {
      var elemName = this.name;
      extractEventHandlers(attrs, nodeId, context);
      var element = undefined;
      if (svg) {
        element = doc.createElementNS(svg, _.escape(name));
      } else {
        element = doc.createElement(_.escape(name));
      }
      _.each(attrsArray, function(item) {
        if (elemName && elemName === 'input' && item.key === 'value') {
          element.value = item.value;
        } else {
          element.setAttribute(item.key, item.value);
        }
      });

      function appendSingleNode(__children, __element) {
        if (_.isNumber(__children)) {
          __element.appendChild(doc.createTextNode(__children + ''));
        } else if (_.isString(__children)) {
          __element.appendChild(doc.createTextNode(__children));
        } else if (_.isBoolean(__children)) {
          __element.appendChild(doc.createTextNode(__children + ''));
        } else if (_.isObject(__children) && __children.isElement) {
          __element.appendChild(__children.toHtmlNode(doc, context));
        } else if (_.isObject(__children) && __children.__asHtml) {
          __element.innerHTML = __children.__asHtml;
        } else if (__children.__componentFactory) {
          var compId = _.escape(_.uniqueId('component_'));
          var span = doc.createElement('span');
          span.setAttribute('data-componentid', compId);
          __element.appendChild(span);
          context.__innerComponents.push('[data-componentid="' + compId + '"]');
          __children.renderTo('[data-componentid="' + compId + '"]', true);
        } else {
          __element.appendChild(doc.createTextNode(__children.toString()));
        }
      }
      if (!selfCloseTag) {
        if (_.isArray(children)) {
          _.each(children, function(child) {
            appendSingleNode(child, element);
          });
        } else {
          appendSingleNode(children, element);
        }
      }
      return element;
    }
  };
}

function renderToNode(el, doc, context) {
  if (_.isFunction(el)) el = el((context || {
    props: {}
  }).props)
  if (!_.isUndefined(el)) {
    if (_.isArray(el)) {
      return _.chain(el).map(function(item) {
        if (_.isFunction(item)) {
          return item();
        } else {
          return item;
        }
      }).filter(function(item) {
        return !_.isUndefined(item);
      }).map(function(item) {
        return item.toHtmlNode(doc, context);
      }).value();
    } else {
      return [el.toHtmlNode(doc, context)];
    }
  } else {
    return [];
  }
}

exports.renderToString = function(el, context) {
  Common.markStart('Elem.renderToString');
  var str = _.map(renderToNode(el, Stringifier(context)), function(n) {
    return n.toHtmlString();
  }).join('');
  Common.markStop('Elem.renderToString');
  return str;
};

exports.renderToStaticHtml = function(el) {
  Common.markStart('Elem.renderToStaticHtml');
  var str = _.map(renderToNode(el, Stringifier({
    __noDataId: true
  })), function(n) {
    return n.toHtmlString();
  }).join('');
  Common.markStop('Elem.renderToStaticHtml');
  return str;
}

exports.el = el;

exports.jsx = function(name, attrs) {
  for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
    children[_key - 2] = arguments[_key];
  }
  return attrs === null ? vel(name, children) : el(name, attrs, children);
}

exports.sel = function(name, children) {
  return el(name, {}, children);
}; // simple node sel(name, children)

exports.vel = function(name, attrs) {
  return el(name, attrs, []);
}; // void node, cel(name, attrs)

exports.svg = function(name, attrs, children) {
  attrs.namespace = exports.svgNS;
  if (!children) {
    return el(name, {}, attrs);
  }
  return el(name, attrs, children);
};

exports.vsvg = function(name, attrs) {
  attrs.namespace = exports.svgNS;
  return el(name, attrs, []);
};

exports.nbsp = function(times) {
  return el('span', {
    __asHtml: _.times(times || 1, function() {
      return ' ';
    })
  });
};

exports.text = function(text) {
  return el('span', {}, text);
};

exports.render = function(el, node, context) {
  Common.markStart('Elem.render');
  var waitingHandlers = (context || {}).waitingHandlers || [];
  var refs = (context || {}).refs || {};
  var props = (context || {}).props || {};
  var __innerComponents = (context || {}).__innerComponents || [];
  var doc = document;
  if (node.ownerDocument) {
    doc = node.ownerDocument;
  }
  if (_.isString(node)) {
    node = doc.querySelector(node);
  }
  if (!_.isUndefined(node) && !_.isNull(node)) {
    var htmlNode = renderToNode(el, doc, {
      root: node,
      waitingHandlers: waitingHandlers,
      refs: refs,
      props: props,
      __innerComponents: __innerComponents
    });
    while (!_.isUndefined(node) && !_.isNull(node) && node.firstChild) {
      node.removeChild(node.firstChild);
    }
    _.each(htmlNode, function(n) {
      if (!_.isUndefined(node) && !_.isNull(node)) node.appendChild(n);
    });
    if (!(context && context.__rootListener)) { // external listener here
      _.each(waitingHandlers, function(handler) { // handler on each concerned node
        _.on('[data-nodeid="' + handler.id + '"]', [handler.event.replace('on', '')], function() {
          handler.callback.apply({}, arguments);
        });
      });
    }
  }
  Common.markStop('Elem.render');
};
exports.unmountComponent = Components.unmountComponent;
exports.component = Components.component;
exports.componentToString = Components.componentToString;
exports.state = state;
exports.Utils = _;
exports.registerWebComponent = registerWebComponent;
exports.dispatcher = Dispatcher;
exports.Perf = {
  start: function() {
    Common.perfs = true;
  },
  stop: function() {
    Common.stop = false;
  },
  markStart: Common.markStart,
  markStop: Common.markStop,
  collectMeasures: Common.collectMeasures,
  printMeasures: Common.printMeasures
};
exports.defer = Common.defer;
exports.predicate = function(predicate, what) {
  if (_.isFunction(predicate)) {
    if (predicate() === true) {
      return what;
    } else {
      return undefined;
    }
  } else {
    if (predicate === true) {
      return what;
    } else {
      return undefined;
    }
  }
};
exports.style = function(obj) {
  var result = {};
  var keys = _.keys(obj);
  _.each(keys, function(key) {
    var clazz = obj[key];
    if (_.isObject(clazz)) {
      result[key] = _.extend({}, {
        extend: function(o) {
          return _.extend({}, o, clazz);
        }
      }, clazz);
    }
  });
  result.extend = _.extend({}, {
    extend: function(o) {
      return _.extend({}, o, obj);
    }
  }, obj);
  return result;
};

Common.__internalAccess.api = exports;

if (typeof define === 'function' && define.amd) {
  define('elem', [], function() {
    return module.exports;
  });
}
<commit_msg>Fix jsx case of children is an array of array<commit_after>var Common = require('./common');
var _ = require('./utils');
var Components = require('./component');
var state = require('./state');
var registerWebComponent = require('./webcomponent').registerWebComponent;
var Stringifier = require('./stringify');
var Dispatcher = require('./events');

exports.svgNS = "http://www.w3.org/2000/svg";

function styleToString(attrs) {
  if (_.isUndefined(attrs)) return '';
  var attrsArray = _.map(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (key === 'className') {
      keyName = 'class';
    }
    var value = attrs[key];
    if (!_.isUndefined(value) && _.isFunction(value)) {
      value = value();
    }
    if (!_.isUndefined(value)) {
      return keyName + ': ' + value + ';';
    } else {
      return undefined;
    }
  });
  attrsArray = _.filter(attrsArray, function(item) {
    return !_.isUndefined(item);
  });
  return attrsArray.join(' ');
}

function classToArray(attrs) { /* Handle class as object with boolean values */
  if (_.isUndefined(attrs)) return [];
  var attrsArray = _.map(_.keys(attrs), function(key) {
    var value = attrs[key];
    if (!_.isUndefined(value) && value === true) {
      return _.dasherize(key);
    } else {
      return undefined;
    }
  });
  attrsArray = _.filter(attrsArray, function(item) {
    return !_.isUndefined(item);
  });
  return attrsArray;
}

function wrapChildren(children) {
  if (children === 0) {
    return children;
  } else if (children === '') {
    return [];
  }
  return children || [];
}

function buildRef(id) {
  return {
    getDOMNode: function() {
      return _.findNode('[data-nodeid="' + id + '"]');
    }
  };
}

function extractEventHandlers(attrs, nodeId, context) {
  _.each(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (_.startsWith(keyName, 'on')) {
      if (context && context.waitingHandlers) {
        context.waitingHandlers.push({
          root: context.root,
          id: nodeId,
          event: keyName.toLowerCase(),
          callback: attrs[key]
        });
      }
    }
    if (keyName === 'ref' && context && context.refs) context.refs[attrs[key]] = buildRef(nodeId);
  });
}

function asAttribute(key, value) {
  return {
    key: key,
    value: value
  };
}

function attributesToArray(attrs) {
  if (_.isUndefined(attrs)) return [];
  var attrsArray = [];
  _.each(_.keys(attrs), function(key) {
    var keyName = _.dasherize(key);
    if (key === 'className') {
      keyName = 'class';
    }
    if (!_.startsWith(keyName, 'on') && keyName !== 'ref') {
      var value = attrs[key];
      if (!_.isUndefined(value) && _.isFunction(value)) {
        value = value();
      }
      if (!_.isUndefined(value)) {
        if (_.isObject(value) && keyName === 'style') {
          attrsArray.push(asAttribute('style', styleToString(value)));
        } else if (_.isArray(value) && keyName === 'class') {
          attrsArray.push(asAttribute(keyName, value.join(' ')));
        } else if (_.isObject(value) && keyName === 'class') {
          attrsArray.push(asAttribute(keyName, classToArray(value).join(' ')));
        } else {
          attrsArray.push(asAttribute(keyName, value));
        }
      }
    }
  });
  return attrsArray;
}

function el(name, attrs, children) {
  var svg = attrs.namespace;
  delete attrs.namespace;
  var nodeId = _.uniqueId('node_');
  if (_.isUndefined(children) && !_.isUndefined(attrs) && !attrs.__isAttrs) {
    children = attrs;
    attrs = {};
  }
  if (arguments.length > 3) {
    name = arguments[0];
    if (!attrs.isElement) {
      attrs = arguments[1];
    } else {
      attrs = {};
    }
    children = [].concat(arguments);
    children.shift();
    children.shift();
  }
  name = _.escape(name) || 'unknown';
  attrs = attrs || {};
  children = wrapChildren(children);
  if (_.isRegExp(children) || _.isUndefined(children) || _.isNull(children)) children = [];
  if (_.isArray(children)) {
    children = _.chain(children).map(function(child) {
      if (_.isFunction(child)) {
        return child();
      } else {
        return child;
      }
    }).filter(function(item) {
      return !_.isUndefined(item);
    }).value();
  }
  var selfCloseTag = _.contains(Common.voidElements, name.toUpperCase()) && (_.isNull(children) || _.isUndefined(children) || (_.isArray(children) && children.length === 0));
  var attrsArray = attributesToArray(attrs);
  attrsArray.push(asAttribute('data-nodeid', _.escape(nodeId)));
  if (Common.debug) attrsArray.push(asAttribute('title', _.escape(nodeId)));
  return {
    name: name,
    attrs: attrs,
    children: children,
    isElement: true,
    nodeId: nodeId,
    toJsonString: function(pretty) {
      if (pretty) return JSON.stringify(this, null, 2);
      return JSON.stringify(this);
    },
    toHtmlNode: function(doc, context) {
      var elemName = this.name;
      extractEventHandlers(attrs, nodeId, context);
      var element = undefined;
      if (svg) {
        element = doc.createElementNS(svg, _.escape(name));
      } else {
        element = doc.createElement(_.escape(name));
      }
      _.each(attrsArray, function(item) {
        if (elemName && elemName === 'input' && item.key === 'value') {
          element.value = item.value;
        } else {
          element.setAttribute(item.key, item.value);
        }
      });

      function appendSingleNode(__children, __element) {
        if (_.isNumber(__children)) {
          __element.appendChild(doc.createTextNode(__children + ''));
        } else if (_.isString(__children)) {
          __element.appendChild(doc.createTextNode(__children));
        } else if (_.isBoolean(__children)) {
          __element.appendChild(doc.createTextNode(__children + ''));
        } else if (_.isObject(__children) && __children.isElement) {
          __element.appendChild(__children.toHtmlNode(doc, context));
        } else if (_.isObject(__children) && __children.__asHtml) {
          __element.innerHTML = __children.__asHtml;
        } else if (__children.__componentFactory) {
          var compId = _.escape(_.uniqueId('component_'));
          var span = doc.createElement('span');
          span.setAttribute('data-componentid', compId);
          __element.appendChild(span);
          context.__innerComponents.push('[data-componentid="' + compId + '"]');
          __children.renderTo('[data-componentid="' + compId + '"]', true);
        } else {
          __element.appendChild(doc.createTextNode(__children.toString()));
        }
      }
      if (!selfCloseTag) {
        if (_.isArray(children)) {
          _.each(children, function(child) {
            appendSingleNode(child, element);
          });
        } else {
          appendSingleNode(children, element);
        }
      }
      return element;
    }
  };
}

function renderToNode(el, doc, context) {
  if (_.isFunction(el)) el = el((context || {
    props: {}
  }).props)
  if (!_.isUndefined(el)) {
    if (_.isArray(el)) {
      return _.chain(el).map(function(item) {
        if (_.isFunction(item)) {
          return item();
        } else {
          return item;
        }
      }).filter(function(item) {
        return !_.isUndefined(item);
      }).map(function(item) {
        return item.toHtmlNode(doc, context);
      }).value();
    } else {
      return [el.toHtmlNode(doc, context)];
    }
  } else {
    return [];
  }
}

exports.renderToString = function(el, context) {
  Common.markStart('Elem.renderToString');
  var str = _.map(renderToNode(el, Stringifier(context)), function(n) {
    return n.toHtmlString();
  }).join('');
  Common.markStop('Elem.renderToString');
  return str;
};

exports.renderToStaticHtml = function(el) {
  Common.markStart('Elem.renderToStaticHtml');
  var str = _.map(renderToNode(el, Stringifier({
    __noDataId: true
  })), function(n) {
    return n.toHtmlString();
  }).join('');
  Common.markStop('Elem.renderToStaticHtml');
  return str;
}

exports.el = el;

exports.jsx = function(name, attrs) {
  for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
    children[_key - 2] = arguments[_key];
  }

  var flatChildren = children;
  if (children !== undefined && children.length === 1) {
      flatChildren = children[0];
  }
  return attrs === null ? vel(name, flatChildren) : el(name, attrs, flatChildren);
}

exports.sel = function(name, children) {
  return el(name, {}, children);
}; // simple node sel(name, children)

exports.vel = function(name, attrs) {
  return el(name, attrs, []);
}; // void node, cel(name, attrs)

exports.svg = function(name, attrs, children) {
  attrs.namespace = exports.svgNS;
  if (!children) {
    return el(name, {}, attrs);
  }
  return el(name, attrs, children);
};

exports.vsvg = function(name, attrs) {
  attrs.namespace = exports.svgNS;
  return el(name, attrs, []);
};

exports.nbsp = function(times) {
  return el('span', {
    __asHtml: _.times(times || 1, function() {
      return ' ';
    })
  });
};

exports.text = function(text) {
  return el('span', {}, text);
};

exports.render = function(el, node, context) {
  Common.markStart('Elem.render');
  var waitingHandlers = (context || {}).waitingHandlers || [];
  var refs = (context || {}).refs || {};
  var props = (context || {}).props || {};
  var __innerComponents = (context || {}).__innerComponents || [];
  var doc = document;
  if (node.ownerDocument) {
    doc = node.ownerDocument;
  }
  if (_.isString(node)) {
    node = doc.querySelector(node);
  }
  if (!_.isUndefined(node) && !_.isNull(node)) {
    var htmlNode = renderToNode(el, doc, {
      root: node,
      waitingHandlers: waitingHandlers,
      refs: refs,
      props: props,
      __innerComponents: __innerComponents
    });
    while (!_.isUndefined(node) && !_.isNull(node) && node.firstChild) {
      node.removeChild(node.firstChild);
    }
    _.each(htmlNode, function(n) {
      if (!_.isUndefined(node) && !_.isNull(node)) node.appendChild(n);
    });
    if (!(context && context.__rootListener)) { // external listener here
      _.each(waitingHandlers, function(handler) { // handler on each concerned node
        _.on('[data-nodeid="' + handler.id + '"]', [handler.event.replace('on', '')], function() {
          handler.callback.apply({}, arguments);
        });
      });
    }
  }
  Common.markStop('Elem.render');
};
exports.unmountComponent = Components.unmountComponent;
exports.component = Components.component;
exports.componentToString = Components.componentToString;
exports.state = state;
exports.Utils = _;
exports.registerWebComponent = registerWebComponent;
exports.dispatcher = Dispatcher;
exports.Perf = {
  start: function() {
    Common.perfs = true;
  },
  stop: function() {
    Common.stop = false;
  },
  markStart: Common.markStart,
  markStop: Common.markStop,
  collectMeasures: Common.collectMeasures,
  printMeasures: Common.printMeasures
};
exports.defer = Common.defer;
exports.predicate = function(predicate, what) {
  if (_.isFunction(predicate)) {
    if (predicate() === true) {
      return what;
    } else {
      return undefined;
    }
  } else {
    if (predicate === true) {
      return what;
    } else {
      return undefined;
    }
  }
};
exports.style = function(obj) {
  var result = {};
  var keys = _.keys(obj);
  _.each(keys, function(key) {
    var clazz = obj[key];
    if (_.isObject(clazz)) {
      result[key] = _.extend({}, {
        extend: function(o) {
          return _.extend({}, o, clazz);
        }
      }, clazz);
    }
  });
  result.extend = _.extend({}, {
    extend: function(o) {
      return _.extend({}, o, obj);
    }
  }, obj);
  return result;
};

Common.__internalAccess.api = exports;

if (typeof define === 'function' && define.amd) {
  define('elem', [], function() {
    return module.exports;
  });
}
<|endoftext|>


<commit_before>'use strict';

var fs     = require('fs');          // File system
var mkdirp = require('mkdirp');      // mkdir -p
var rimraf = require('rimraf');      // rm -rf
var ncp    = require('ncp');         // cp -r
var Q      = require('q');           // Promises
var path   = require('path');        // Path
var marked = require('marked');      // Markdown parser
var _      = require('lodash');      // Lo-Dash

var parser = require('./parser');
var utils  = require('./utils');
var logger = require('./log');

ncp.limit = 16;

exports = module.exports = {

  /**
   * Folder API
   */
  folder: {
    /**
     * Store project base directory.
     */
    base: '',

    /**
     * Read a folder
     * @see {@link http://nodejs.org/api/fs.html#fs_fs_readdir_path_callback}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    read: Q.denodeify(fs.readdir),

    /**
     * Create a folder
     * @see {@link https://github.com/substack/node-mkdirp}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    create: Q.denodeify(mkdirp),

    /**
     * Copy a folder
     * @see {@link https://github.com/AvianFlu/ncp}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    copy: Q.denodeify(ncp),

    /**
     * Remove a folder
     * @see {@link https://github.com/isaacs/rimraf}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    remove: Q.denodeify(rimraf),

    /**
     * Remove then create a folder
     * @param  {String} folder
     * @return {Q.Promise}
     */
    refresh: function (folder) {
      return exports.folder.remove(folder).then(function () {
        logger.log('Folder `' + folder + '` successfully removed.');
        return exports.folder.create(folder);
      }, function () {
        return exports.folder.create(folder);
      });
    },

    /**
     * Parse a folder
     * @param  {String} folder
     * @return {Q.Promise}
     */
    parse: function (folder) {
      return exports.folder.read(folder).then(function (files) {
        var path,
            promises = [],
            data = [];

        files.forEach(function (file) {
          path = folder + '/' + file;

          // Folder
          if (exports.isDirectory(path)) {
            promises.push(exports.folder.parse(path).then(function (response) {
              data = data.concat(response);
            }));
          }

          // SCSS file
          else if (utils.getExtension(path) === 'scss') {
            promises.push(exports.file.process(path).then(function (response) {
              if (Object.keys(response).length > 0) {
                data = data.concat(response);
              }
            }));
          }

          // Else
          else {
            logger.log('File `' + path + '` is not a `.scss` file. Omitted.');
          }
        });

        return Q.all(promises).then(function () {
          return data;
        });

      }, function (err) {
        throw new Error(err);
      });
    }
  },

  /**
   * File API
   */
  file: {
    /**
     * Read a file
     * @see {@link http://nodejs.org/api/fs.html#fs_fs_readfile_filename_options_callback}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    read: Q.denodeify(fs.readFile),

    /**
     * Create a file
     * @see {@link http://nodejs.org/api/fs.html#fs_fs_writefile_filename_data_options_callback}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    create: Q.denodeify(fs.writeFile),

    /**
     * Remove a file
     * @see {@link http://nodejs.org/api/fs.html#fs_fs_unlink_path_callback}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    remove: Q.denodeify(fs.unlink),

    /**
     * Process a file
     * @param  {String} file
     * @return {Q.Promise}
     */
    process: function (file) {
      return exports.file.read(file, 'utf-8').then(function (code) {
        var data = parser.parse(code);

        // Merge in from which file the comments where loaded.
        Object.keys(data).forEach(function (key) {
          data[key].forEach(function (item) {
            item.file = {
              path: path.relative(exports.folder.base, file),
              name: path.basename(file, '.scss')
            };
          });
        });

        return data;
      });
    }
  },

  /**
   * Test if path is a directory
   * @param  {String}  path
   * @return {Boolean}
   */
  isDirectory: function (path) {
    return fs.lstatSync(path).isDirectory();
  },

  /**
   * Dump CSS
   * @param  {String} destination
   * @return {Q.Promise}
   */
  dumpAssets: function (destination) {
    return exports.folder.copy(__dirname + '/../view/assets', destination + '/assets');
  },

  /**
   * Get data
   * @param {String} folder - folder path
   */
  getData: function (folder) {
    exports.folder.base = folder;

    return exports.folder.parse(folder).then(function (response) {
      response = response || [];

      var indexByTypeName = {};
      var flat = [];

      response.forEach(function (obj) {
        Object.keys(obj).forEach(function (type) {
          // Ignore unkown context
          if (type === 'unknown') { return; }

          // Iterate over all items for this type
          obj[type].forEach(function (item) {

            // Add in default access
            item.access = item.access || ['public'];

            // Add in default group
            item.group = item.group || ['ungrouped'];

            // Save raw description in rawDescription
            item.rawDescription = item.description;

            // Parse the description as merkedown (as per #115)
            item.description = marked(item.description);

            // Build up an like `mixin_name`
            indexByTypeName[item.context.type + '_' + item.context.name] = item;

            flat.push(item);
          });
        });
      });

      // Resovle alias and requires
      Object.keys(indexByTypeName).forEach(function (key) {
        var item = indexByTypeName[key];

        // Alias
        if (utils.isset(item.alias)) {
          item.alias.forEach(function (alias) {
            var lookupKey = item.context.type + '_' + alias; // Alias has to be from same type
            if (utils.isset(indexByTypeName[lookupKey])) {

              if (!Array.isArray(indexByTypeName[lookupKey].aliased)) {
                indexByTypeName[lookupKey].aliased = [];
              }

              indexByTypeName[lookupKey].aliased.push(item.context.name);
            }

            else {
              logger.log('Item `' + item.context.name + '` is an alias of `' + alias + '` but this item doesn\'t exist.');
            }
          });
        }

        // Requires
        if (utils.isset(item.requires)) {
          item.requires = item.requires.map(function (req) {
            if ( req.external === true ) {
              return req;
            } // Just return itself

            var lookupKey = req.type + '_' + req.name;

            if (utils.isset(indexByTypeName[lookupKey])) {
              var reqItem = indexByTypeName[lookupKey];

              if (!Array.isArray(reqItem.usedBy)) {
                reqItem.usedBy = [];
              }

              reqItem.usedBy.push(item);
              req.item = reqItem;
            }

            else {
              logger.log('Item `' + item.context.name + '` requires `' + req.name + '` from type `' + req.type + '` but this item doesn\'t exist.');
            }

            return req;

          }).filter(function (item) {
            return utils.isset(item);
          });
        }

        // See
        if (utils.isset(item.see)) {
          item.see = item.see.map(function (see) {
            var lookupKey = see.type + '_' + see.name;

            if (utils.isset(indexByTypeName[lookupKey])) {
              return indexByTypeName[lookupKey];
            }

            else {
              logger.log('Item `' + item.context.name + '` refers to `' + see.name + '` from type `' + see.type + '` but this item doesn\'t exist.');
            }
          }).filter(function (item) {
            return utils.isset(item);
          });
        }
      });

      var groupByType = function (item) {
        return item.context.type;
      };

      var byType = _.groupBy(flat, groupByType);

      var byGroupAndType = _.mapValues(_.groupBy(flat, function (item) {
        return item.group[0]; // Just one layer for now.
      }), function (items) {
        return _.groupBy(items, groupByType);
      });

      var groups = _.uniq(_.map(flat, function (item) {
        return item.group;
      })).sort(function (a, b) {
          if(a < b) {
            return -1;
          }
          if(a > b) {
            return 1;
          }
          return 0;
      });

      return {
        groups          : groups,
        byType          : byType,
        byGroupAndType  : byGroupAndType
      };

    });
  }
};
<commit_msg>Fix group issue. SassDoc/sassdoc#29<commit_after>'use strict';

var fs     = require('fs');          // File system
var mkdirp = require('mkdirp');      // mkdir -p
var rimraf = require('rimraf');      // rm -rf
var ncp    = require('ncp');         // cp -r
var Q      = require('q');           // Promises
var path   = require('path');        // Path
var marked = require('marked');      // Markdown parser
var _      = require('lodash');      // Lo-Dash

var parser = require('./parser');
var utils  = require('./utils');
var logger = require('./log');

ncp.limit = 16;

exports = module.exports = {

  /**
   * Folder API
   */
  folder: {
    /**
     * Store project base directory.
     */
    base: '',

    /**
     * Read a folder
     * @see {@link http://nodejs.org/api/fs.html#fs_fs_readdir_path_callback}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    read: Q.denodeify(fs.readdir),

    /**
     * Create a folder
     * @see {@link https://github.com/substack/node-mkdirp}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    create: Q.denodeify(mkdirp),

    /**
     * Copy a folder
     * @see {@link https://github.com/AvianFlu/ncp}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    copy: Q.denodeify(ncp),

    /**
     * Remove a folder
     * @see {@link https://github.com/isaacs/rimraf}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    remove: Q.denodeify(rimraf),

    /**
     * Remove then create a folder
     * @param  {String} folder
     * @return {Q.Promise}
     */
    refresh: function (folder) {
      return exports.folder.remove(folder).then(function () {
        logger.log('Folder `' + folder + '` successfully removed.');
        return exports.folder.create(folder);
      }, function () {
        return exports.folder.create(folder);
      });
    },

    /**
     * Parse a folder
     * @param  {String} folder
     * @return {Q.Promise}
     */
    parse: function (folder) {
      return exports.folder.read(folder).then(function (files) {
        var path,
            promises = [],
            data = [];

        files.forEach(function (file) {
          path = folder + '/' + file;

          // Folder
          if (exports.isDirectory(path)) {
            promises.push(exports.folder.parse(path).then(function (response) {
              data = data.concat(response);
            }));
          }

          // SCSS file
          else if (utils.getExtension(path) === 'scss') {
            promises.push(exports.file.process(path).then(function (response) {
              if (Object.keys(response).length > 0) {
                data = data.concat(response);
              }
            }));
          }

          // Else
          else {
            logger.log('File `' + path + '` is not a `.scss` file. Omitted.');
          }
        });

        return Q.all(promises).then(function () {
          return data;
        });

      }, function (err) {
        throw new Error(err);
      });
    }
  },

  /**
   * File API
   */
  file: {
    /**
     * Read a file
     * @see {@link http://nodejs.org/api/fs.html#fs_fs_readfile_filename_options_callback}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    read: Q.denodeify(fs.readFile),

    /**
     * Create a file
     * @see {@link http://nodejs.org/api/fs.html#fs_fs_writefile_filename_data_options_callback}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    create: Q.denodeify(fs.writeFile),

    /**
     * Remove a file
     * @see {@link http://nodejs.org/api/fs.html#fs_fs_unlink_path_callback}
     * @see {@link https://github.com/kriskowal/q/wiki/API-Reference#interfacing-with-nodejs-callbacks}
     */
    remove: Q.denodeify(fs.unlink),

    /**
     * Process a file
     * @param  {String} file
     * @return {Q.Promise}
     */
    process: function (file) {
      return exports.file.read(file, 'utf-8').then(function (code) {
        var data = parser.parse(code);

        // Merge in from which file the comments where loaded.
        Object.keys(data).forEach(function (key) {
          data[key].forEach(function (item) {
            item.file = {
              path: path.relative(exports.folder.base, file),
              name: path.basename(file, '.scss')
            };
          });
        });

        return data;
      });
    }
  },

  /**
   * Test if path is a directory
   * @param  {String}  path
   * @return {Boolean}
   */
  isDirectory: function (path) {
    return fs.lstatSync(path).isDirectory();
  },

  /**
   * Dump CSS
   * @param  {String} destination
   * @return {Q.Promise}
   */
  dumpAssets: function (destination) {
    return exports.folder.copy(__dirname + '/../view/assets', destination + '/assets');
  },

  /**
   * Get data
   * @param {String} folder - folder path
   */
  getData: function (folder) {
    exports.folder.base = folder;

    return exports.folder.parse(folder).then(function (response) {
      response = response || [];

      var indexByTypeName = {};
      var flat = [];

      response.forEach(function (obj) {
        Object.keys(obj).forEach(function (type) {
          // Ignore unkown context
          if (type === 'unknown') { return; }

          // Iterate over all items for this type
          obj[type].forEach(function (item) {

            // Add in default access
            item.access = item.access || ['public'];

            // Add in default group
            item.group = item.group || ['ungrouped'];

            // Save raw description in rawDescription
            item.rawDescription = item.description;

            // Parse the description as merkedown (as per #115)
            item.description = marked(item.description);

            // Build up an like `mixin_name`
            indexByTypeName[item.context.type + '_' + item.context.name] = item;

            flat.push(item);
          });
        });
      });

      // Resovle alias and requires
      Object.keys(indexByTypeName).forEach(function (key) {
        var item = indexByTypeName[key];

        // Alias
        if (utils.isset(item.alias)) {
          item.alias.forEach(function (alias) {
            var lookupKey = item.context.type + '_' + alias; // Alias has to be from same type
            if (utils.isset(indexByTypeName[lookupKey])) {

              if (!Array.isArray(indexByTypeName[lookupKey].aliased)) {
                indexByTypeName[lookupKey].aliased = [];
              }

              indexByTypeName[lookupKey].aliased.push(item.context.name);
            }

            else {
              logger.log('Item `' + item.context.name + '` is an alias of `' + alias + '` but this item doesn\'t exist.');
            }
          });
        }

        // Requires
        if (utils.isset(item.requires)) {
          item.requires = item.requires.map(function (req) {
            if ( req.external === true ) {
              return req;
            } // Just return itself

            var lookupKey = req.type + '_' + req.name;

            if (utils.isset(indexByTypeName[lookupKey])) {
              var reqItem = indexByTypeName[lookupKey];

              if (!Array.isArray(reqItem.usedBy)) {
                reqItem.usedBy = [];
              }

              reqItem.usedBy.push(item);
              req.item = reqItem;
            }

            else {
              logger.log('Item `' + item.context.name + '` requires `' + req.name + '` from type `' + req.type + '` but this item doesn\'t exist.');
            }

            return req;

          }).filter(function (item) {
            return utils.isset(item);
          });
        }

        // See
        if (utils.isset(item.see)) {
          item.see = item.see.map(function (see) {
            var lookupKey = see.type + '_' + see.name;

            if (utils.isset(indexByTypeName[lookupKey])) {
              return indexByTypeName[lookupKey];
            }

            else {
              logger.log('Item `' + item.context.name + '` refers to `' + see.name + '` from type `' + see.type + '` but this item doesn\'t exist.');
            }
          }).filter(function (item) {
            return utils.isset(item);
          });
        }
      });

      var groupByType = function (item) {
        return item.context.type;
      };

      var byType = _.groupBy(flat, groupByType);

      var byGroupAndType = _.mapValues(_.groupBy(flat, function (item) {
        return item.group[0]; // Just one layer for now.
      }), function (items) {
        return _.groupBy(items, groupByType);
      });

      var groups = _.uniq(_.map(flat, function (item) {
        return item.group[0]; // Just one layer for now.
      })).sort(function (a, b) {
          if(a < b) {
            return -1;
          }
          if(a > b) {
            return 1;
          }
          return 0;
      });

      return {
        groups          : groups,
        byType          : byType,
        byGroupAndType  : byGroupAndType
      };

    });
  }
};
<|endoftext|>