<commit_before>const pool = require('../connection/mysqlConn')
const dbBase = require('./dbBase')

function Table(tableName) {
    if (!tableName || typeof tableName !== 'string' || !tableName.trim())
        throw new Error('error table name.')
    else this.tableName = tableName
}
const proto = Table.prototype

proto.add = function (data) {
    let insert = data ? 'SET' : ''
    if (data) {
        for (let key in data) {
            let value = data[key]
            if (value) {
                let set = ` ${key}='${value}',`
                insert += set
            }
        }
        if (insert.lastIndexOf(',') === insert.length - 1) insert = insert.substr(0, insert.length - 1)
    }

    let sqlStr = `INSERT INTO ${this.tableName} ${insert}`
    return dbBase.execute(sqlStr)
}

proto.find = function (query) {
    let where = query ? 'WHERE' : ''
    let whereArr = []
    if (query) {
        for (let key in query) {
            let value = query[key]
            if (!value.length) {
                let condition = ` ${key}='${value}'`
                whereArr.push(condition)
            } else {
                let condition = ` ${key} in ('${value.join("','")}')`
                whereArr.push(condition)
            }
        }
    }
    where += whereArr.join(' and ')
    let sqlStr = `SELECT * FROM ${this.tableName} ${where}`;
    return dbBase.execute(sqlStr);
}
proto.like = function (query) {
    let where = query ? 'WHERE' : ''
    let whereArr = []
    if (query) {
        for (let key in query) {
            let value = query[key]
            let condition = ` ${key} like '%${value}%%'`
            whereArr.push(condition)
        }
    }
    where += whereArr.join(' and ')
    let sqlStr = `SELECT * FROM ${this.tableName} ${where}`;
    return dbBase.execute(sqlStr);
}
proto.findOne = function (query) {
    let where = query ? 'WHERE' : ''
    if (query) {
        for (let key in query) {
            let value = query[key]
            let condition = ` ${key}='${value}'`
            where += condition
        }
    }

    let sqlStr = `SELECT * FROM ${this.tableName} ${where} LIMIT 1`;
    return dbBase.execute(sqlStr).then(data => {
        return new Promise(resolve => {
            resolve(data[0])
        })
    }).catch(error => {
        return new Promise((resolve, reject) => {
            reject(error)
        })
    });
}

proto.update = function (query, updateData) {
    let where = query ? 'WHERE' : ''
    if (query) {
        for (let key in query) {
            let value = query[key]
            let condition = ` ${key}='${value}'`
            where += condition
        }
    }
    let updateStrArr = []
    if (updateData) {
        for (let key in updateData) {
            let value = updateData[key]
            let condition = ` ${key}='${value}'`
            updateStrArr.push(condition)
        }
    }
    let updateStr = updateStrArr.join(',')
    let sqlStr = `UPDATE ${this.tableName} SET ${updateStr} ${where}`;
    return dbBase.execute(sqlStr);
    /**
     * UPDATE [LOW_PRIORITY] [IGNORE] tbl_name
     * SET col_name1=expr1 [, col_name2=expr2 ...]
     * [WHERE where_definition]
     * [ORDER BY ...]
     * [LIMIT row_count]
     */
}

proto.remove = function (query) {
    let where = query ? 'WHERE' : ''
    let whereArr = []
    if (query) {
        for (let key in query) {
            let value = query[key]
            if (!value.length) {
                let condition = ` ${key}='${value}'`
                whereArr.push(condition)
            } else {
                let condition = ` ${key} in ('${value.join("','")}')`
                whereArr.push(condition)
            }
        }
    }
    where += whereArr.join(' and ')
    let sqlStr = `DELETE FROM ${this.tableName} ${where}`;
    return dbBase.execute(sqlStr);
}

proto.save = function () {
    let sqlStr = '';
    return dbBase.execute(sqlStr);
}

proto.query = function () {
    let sqlStr = '';
    return dbBase.execute(sqlStr);
}

module.exports = Table<commit_msg>修改：数组判断方式<commit_after>const pool = require('../connection/mysqlConn')
const dbBase = require('./dbBase')

function Table(tableName) {
    if (!tableName || typeof tableName !== 'string' || !tableName.trim())
        throw new Error('error table name.')
    else this.tableName = tableName
}
const proto = Table.prototype

proto.add = function (data) {
    let insert = data ? 'SET' : ''
    if (data) {
        for (let key in data) {
            let value = data[key]
            if (value) {
                let set = ` ${key}='${value}',`
                insert += set
            }
        }
        if (insert.lastIndexOf(',') === insert.length - 1) insert = insert.substr(0, insert.length - 1)
    }

    let sqlStr = `INSERT INTO ${this.tableName} ${insert}`
    return dbBase.execute(sqlStr)
}

proto.find = function (query) {
    let where = query ? 'WHERE' : ''
    let whereArr = []
    if (query) {
        for (let key in query) {
            let value = query[key]
            if (Object.prototype.toString.call(value) !== '[object Array]') {
                let condition = ` ${key}='${value}'`
                whereArr.push(condition)
            } else {
                let condition = ` ${key} in ('${value.join("','")}')`
                whereArr.push(condition)
            }
        }
    }
    where += whereArr.join(' and ')
    let sqlStr = `SELECT * FROM ${this.tableName} ${where}`;
    return dbBase.execute(sqlStr);
}
proto.like = function (query) {
    let where = query ? 'WHERE' : ''
    let whereArr = []
    if (query) {
        for (let key in query) {
            let value = query[key]
            let condition = ` ${key} like '%${value}%%'`
            whereArr.push(condition)
        }
    }
    where += whereArr.join(' and ')
    let sqlStr = `SELECT * FROM ${this.tableName} ${where}`;
    return dbBase.execute(sqlStr);
}
proto.findOne = function (query) {
    let where = query ? 'WHERE' : ''
    if (query) {
        for (let key in query) {
            let value = query[key]
            let condition = ` ${key}='${value}'`
            where += condition
        }
    }

    let sqlStr = `SELECT * FROM ${this.tableName} ${where} LIMIT 1`;
    return dbBase.execute(sqlStr).then(data => {
        return new Promise(resolve => {
            resolve(data[0])
        })
    }).catch(error => {
        return new Promise((resolve, reject) => {
            reject(error)
        })
    });
}

proto.update = function (query, updateData) {
    let where = query ? 'WHERE' : ''
    if (query) {
        for (let key in query) {
            let value = query[key]
            let condition = ` ${key}='${value}'`
            where += condition
        }
    }
    let updateStrArr = []
    if (updateData) {
        for (let key in updateData) {
            let value = updateData[key]
            let condition = ` ${key}='${value}'`
            updateStrArr.push(condition)
        }
    }
    let updateStr = updateStrArr.join(',')
    let sqlStr = `UPDATE ${this.tableName} SET ${updateStr} ${where}`;
    return dbBase.execute(sqlStr);
    /**
     * UPDATE [LOW_PRIORITY] [IGNORE] tbl_name
     * SET col_name1=expr1 [, col_name2=expr2 ...]
     * [WHERE where_definition]
     * [ORDER BY ...]
     * [LIMIT row_count]
     */
}

proto.remove = function (query) {
    let where = query ? 'WHERE' : ''
    let whereArr = []
    if (query) {
        for (let key in query) {
            let value = query[key]
            if (Object.prototype.toString.call(value) !== '[object Array]') {
                let condition = ` ${key}='${value}'`
                whereArr.push(condition)
            } else {
                let condition = ` ${key} in ('${value.join("','")}')`
                whereArr.push(condition)
            }
        }
    }
    where += whereArr.join(' and ')
    let sqlStr = `DELETE FROM ${this.tableName} ${where}`;
    return dbBase.execute(sqlStr);
}

proto.save = function () {
    let sqlStr = '';
    return dbBase.execute(sqlStr);
}

proto.query = function () {
    let sqlStr = '';
    return dbBase.execute(sqlStr);
}

module.exports = Table<|endoftext|>


<commit_before>(function(define) {
    define(function(rq$, ex$, module) {
//the Ceylon language module
//#METAMODEL

//#COMPILE core_functions.js,is-op.js,exists-nonempty.js,Anything.js,Object,Null,Identifiable,Callable,callables.js,dynamic_functions.js
//#COMPILE comprehensions.js,Basic,Throwable,printStackTrace,Exception,Comparison,identityHash,impl/rethrow,impl/bases
//#Anything
//#COMPILE Iterable,Correspondence,Finished,Sequential,Sequence,Empty
//#native Boolean
//#native Callable
//#COMPILE Binary,Usable,Destroyable,Obtainable,Comparable,Invertible,Summable,Ordinal,Enumerable,Numeric,Exponentiable,Integral,Scalable,Number,numbers.js,OverflowException,InitializationError,Resource,Ranged,Iterator,Collection,Category,List,Array,sequences.js,ArraySequence,Tuple,ChainedIterator,CycledIterator,Entry,Byte
//#Number
//#COMPILE Set,Range,Span,Measure,Singleton,AssertionError,Map,String,strings.js,Character,StringBuilder
//#COMPILE any,byDecreasing,byIncreasing,byItem,byKey,count,emptyOrSingleton,curry,apply,comparing,functions
//#COMPILE every,forItem,forKey,concatenate,expand,interleave,corresponding,loop,largest,max,min,smallest,sum,product,pairs,zip,unzip,print,nothing
//#COMPILE identical,compose,shuffle,flatten,unflatten,plus,times,sort,and,or,not,arrayOfSize
//#metamodel
//#COMPILE Annotated,Annotation,ConstrainedAnnotation,OptionalAnnotation,SequencedAnnotation
//#COMPILE meta/annotations,meta/metamodel,meta/optionalAnnotation,meta/sequencedAnnotations,modules.js,meta/modules
//#COMPILE meta/model/ValueModel,meta/model/ClassOrInterface,ClassOrInterface_addons.js,meta/model/ClassModel,meta/model/Class,meta/model/FunctionModel,meta/model/Function,meta/model/Method,meta/model/InterfaceModel,meta/model/Interface,meta/model/IntersectionType,meta/model/Member,Member_addons.js,meta/model/MemberClass,meta/model/MemberInterface,meta/model/Attribute,meta/model/Model,meta/model/Type,meta/model/UnionType,meta/model/Value,meta/model/nothingType,meta/model/TypeApplicationException,meta/model/InvocationException,meta/model/MutationException,meta/model/IncompatibleTypeException,meta/model/Generic,meta/model/Applicable
//#COMPILE meta/model/Constructor,meta/model/ConstructorModel,meta/model/Qualified,meta/model/Declared,meta/model/Functional,meta/model/MemberClassConstructor,jsint/AppliedConstructor,jsint/AppliedMemberConstructor
//#COMPILE meta/declaration/Declaration,meta/declaration/AnnotatedDeclaration,annotated_declaration.js,meta/declaration/NestableDeclaration,NestableDeclaration_addons.js,meta/declaration/GenericDeclaration,GenericDeclaration_addons.js,meta/declaration/ClassOrInterfaceDeclaration,meta/declaration/FunctionalDeclaration,declaration_addons.js,meta/declaration/FunctionOrValueDeclaration,meta/declaration/ValueDeclaration,meta/declaration/ClassDeclaration,meta/declaration/FunctionDeclaration,meta/declaration/InterfaceDeclaration,meta/declaration/ModuleAndPackage,meta/declaration/OpenIntersection,meta/declaration/OpenClassOrInterfaceType,meta/declaration/OpenClassType,meta/declaration/OpenInterfaceType,meta/declaration/OpenType,meta/declaration/OpenTypeVariable,meta/declaration/OpenUnion,meta/declaration/SetterDeclaration,meta/declaration/TypeParameter,meta/declaration/TypedDeclaration,meta/declaration/nothingType,meta/declaration/AliasDeclaration,meta/declaration/Variance,meta/declaration/ConstructorDeclaration,meta/declaration/Contained
//#COMPILE jsint/Importa,jsint/Paquete,jsint/Modulo,jsint/FreeUnion,jsint/FreeIntersection,jsint/OpenTvar,jsint/OpenTypeParam,jsint/OpenAlias,jsint/AppliedUnionType,jsint/AppliedIntersectionType,jsint/OpenClass,jsint/OpenInterface,jsint/OpenConstructor
//#COMPILE annotations
//#COMPILE Boolean.js,jsint/TpMap,tuples.js,metamodel_functions1.js,metamodel_functions2.js,jsint/JsResource,jsint/AppliedClass,jsint/AppliedMemberClass,jsint/AppliedInterface,jsint/AppliedMemberInterface,jsint/AppliedFunction,jsint/AppliedValue,jsint/AppliedMethod,AppliedAttribute.js,metamodel_functions3.js,metamodel_functions4.js,jsint/FreeClass,jsint/FreeInterface,OpenFunction.js,jsint/OpenValue,OpenSetter.js,FunParamDecl.js,ValParamDecl.js,metamodel_functions5.js
//#COMPILE module,package,meta/package,meta/model/package,meta/declaration/package
//#COMPILE process.js,process,language,system,operatingSystem,runtime,parseInteger,parseFloat,formatInteger,parseBoolean,className
//Serialization
//#COMPILE serialization/package,serialization/Deconstructed,serialization/Deconstructor,serialization/DeserializableReference,serialization/DeserializationContext,serialization/RealizableReference,serialization/Reference,serialization/SerializableReference,serialization/SerializationContext,serialization/serialization,serialization/deserialization,jsint/JsSerCtxt,jsint/JsDeserCtxt,jsint/DeserRefImpl,jsint/SerRefImpl

function NatErr(e) {
    var that = new NatErr.$$;
    var msg;
    if (typeof e === 'string') {
        msg = e;
    } else if (e) {
        msg = e.toString();
    } else {
        msg = "Native JavaScript Error";
    }
    Throwable(msg,null,that);
    return that;
}
initTypeProto(NatErr, 'ceylon.language::NativeError', $init$Throwable());
NatErr.$crtmm$=function(){return{nm:'NativeError',mt:'c',ps:[{$t:{t:Throwable},nm:'src',mt:'prm'}],pa:1,mod:$CCMM$,d:['$','Throwable']};}
ex$.Nothing=Nothing;
ex$.getTrue=getTrue;
ex$.getFalse=getFalse;
ex$.NatErr=NatErr;
    });
}(typeof define==='function' && define.amd ?
    define : function (factory) {
    if (typeof exports!=='undefined') {
        factory(require, exports, module);
    } else {
        throw "no module loader";
    }
}));
<commit_msg>placeholder for ceylon/ceylon-js#489<commit_after>(function(define) {
    define(function(rq$, ex$, module) {
//the Ceylon language module
//#METAMODEL

//#COMPILE core_functions.js,is-op.js,exists-nonempty.js,Anything.js,Object,Null,Identifiable,Callable,callables.js,dynamic_functions.js
//#COMPILE comprehensions.js,Basic,Throwable,printStackTrace,Exception,Comparison,identityHash,impl/rethrow,impl/bases
//#Anything
//#COMPILE Iterable,Correspondence,Finished,Sequential,Sequence,Empty
//#native Boolean
//#native Callable
//#COMPILE Binary,Usable,Destroyable,Obtainable,Comparable,Invertible,Summable,Ordinal,Enumerable,Numeric,Exponentiable,Integral,Scalable,Number,numbers.js,OverflowException,InitializationError,Resource,Ranged,Iterator,Collection,Category,List,Array,sequences.js,ArraySequence,Tuple,ChainedIterator,CycledIterator,Entry,Byte
//#Number
//#COMPILE Set,Range,Span,Measure,Singleton,AssertionError,Map,String,strings.js,Character,StringBuilder
//#COMPILE any,byDecreasing,byIncreasing,byItem,byKey,count,emptyOrSingleton,curry,apply,comparing,functions
//#COMPILE every,forItem,forKey,concatenate,expand,interleave,corresponding,loop,largest,max,min,smallest,sum,product,pairs,zip,unzip,print,nothing
//#COMPILE identical,compose,shuffle,flatten,unflatten,plus,times,sort,and,or,not,arrayOfSize
//#metamodel
//#COMPILE Annotated,Annotation,ConstrainedAnnotation,OptionalAnnotation,SequencedAnnotation
//#COMPILE meta/annotations,meta/metamodel,meta/optionalAnnotation,meta/sequencedAnnotations,modules.js,meta/modules
//#COMPILE meta/model/ValueModel,meta/model/ClassOrInterface,ClassOrInterface_addons.js,meta/model/ClassModel,meta/model/Class,meta/model/FunctionModel,meta/model/Function,meta/model/Method,meta/model/InterfaceModel,meta/model/Interface,meta/model/IntersectionType,meta/model/Member,Member_addons.js,meta/model/MemberClass,meta/model/MemberInterface,meta/model/Attribute,meta/model/Model,meta/model/Type,meta/model/UnionType,meta/model/Value,meta/model/nothingType,meta/model/TypeApplicationException,meta/model/InvocationException,meta/model/MutationException,meta/model/IncompatibleTypeException,meta/model/Generic,meta/model/Applicable
//#COMPILE meta/model/Constructor,meta/model/ConstructorModel,meta/model/Qualified,meta/model/Declared,meta/model/Functional,meta/model/MemberClassConstructor,jsint/AppliedConstructor,jsint/AppliedMemberConstructor
//#COMPILE meta/declaration/Declaration,meta/declaration/AnnotatedDeclaration,annotated_declaration.js,meta/declaration/NestableDeclaration,NestableDeclaration_addons.js,meta/declaration/GenericDeclaration,GenericDeclaration_addons.js,meta/declaration/ClassOrInterfaceDeclaration,meta/declaration/FunctionalDeclaration,declaration_addons.js,meta/declaration/FunctionOrValueDeclaration,meta/declaration/ValueDeclaration,meta/declaration/ClassDeclaration,meta/declaration/FunctionDeclaration,meta/declaration/InterfaceDeclaration,meta/declaration/ModuleAndPackage,meta/declaration/OpenIntersection,meta/declaration/OpenClassOrInterfaceType,meta/declaration/OpenClassType,meta/declaration/OpenInterfaceType,meta/declaration/OpenType,meta/declaration/OpenTypeVariable,meta/declaration/OpenUnion,meta/declaration/SetterDeclaration,meta/declaration/TypeParameter,meta/declaration/TypedDeclaration,meta/declaration/nothingType,meta/declaration/AliasDeclaration,meta/declaration/Variance,meta/declaration/ConstructorDeclaration,meta/declaration/Contained
//#COMPILE jsint/Importa,jsint/Paquete,jsint/Modulo,jsint/FreeUnion,jsint/FreeIntersection,jsint/OpenTvar,jsint/OpenTypeParam,jsint/OpenAlias,jsint/AppliedUnionType,jsint/AppliedIntersectionType,jsint/OpenClass,jsint/OpenInterface,jsint/OpenConstructor
//#COMPILE annotations
//#COMPILE Boolean.js,jsint/TpMap,tuples.js,metamodel_functions1.js,metamodel_functions2.js,jsint/JsResource,jsint/AppliedClass,jsint/AppliedMemberClass,jsint/AppliedInterface,jsint/AppliedMemberInterface,jsint/AppliedFunction,jsint/AppliedValue,jsint/AppliedMethod,AppliedAttribute.js,metamodel_functions3.js,metamodel_functions4.js,jsint/FreeClass,jsint/FreeInterface,OpenFunction.js,jsint/OpenValue,OpenSetter.js,FunParamDecl.js,ValParamDecl.js,metamodel_functions5.js
//#COMPILE module,package,meta/package,meta/model/package,meta/declaration/package
//#COMPILE process.js,process,language,system,operatingSystem,runtime,parseInteger,parseFloat,formatInteger,parseBoolean,className
//Serialization
//#COMPILE serialization/package,serialization/Deconstructed,serialization/Deconstructor,serialization/DeserializableReference,serialization/DeserializationContext,serialization/RealizableReference,serialization/Reference,serialization/SerializableReference,serialization/SerializationContext,serialization/serialization,serialization/deserialization,jsint/JsSerCtxt,jsint/JsDeserCtxt,jsint/DeserRefImpl,jsint/SerRefImpl

function NatErr(e) {
    var that = new NatErr.$$;
    var msg;
    if (typeof e === 'string') {
        msg = e;
    } else if (e) {
        msg = e.toString();
    } else {
        msg = "Native JavaScript Error";
    }
    Throwable(msg,null,that);
    return that;
}
initTypeProto(NatErr, 'ceylon.language::NativeError', $init$Throwable());
NatErr.$crtmm$=function(){return{nm:'NativeError',mt:'c',ps:[{$t:{t:Throwable},nm:'src',mt:'prm'}],pa:1,mod:$CCMM$,d:['$','Throwable']};}
ex$.Nothing=Nothing;
ex$.getTrue=getTrue;
ex$.getFalse=getFalse;
ex$.NatErr=NatErr;
//#UNSHARED
});
}(typeof define==='function' && define.amd ?
    define : function (factory) {
    if (typeof exports!=='undefined') {
        factory(require, exports, module);
    } else {
        throw "no module loader";
    }
}));
<|endoftext|>


<commit_before>var username = "";
var room = "";
var socket = io.connect();
var title = "";

$("#changeRoom").modal({
	keyboard: false,
	backdrop: "static"
});

$("#changeTitle").modal({
	keyboard: false,
	backdrop: "static"
});
$("#changeTitle").modal("hide");

$("#changeRoom").modal("show");
$("#urlAlert").hide();
$("#changeRoomFormAlert").hide();

$("#changeRoomButton").click(function()
{
	location.reload();
});

$("#joinRoomButton").click(function()
{
	tmpUsername = $("#usernameField").val();
	tmpRoom = parseInt($("#roomNumberField").val());
	if ( tmpUsername != "" && tmpRoom )
	{
		$("#chatBody").html("");
		username = tmpUsername
		room = tmpRoom;
		$("#roomNumber").html(room);
		$("#changeRoom").modal("hide");
		$("#changeRoomFormAlert").hide();
		socket.emit("resync");
	}
	else
	{
		if ( !tmpRoom )
			$("#changeRoomFormAlert").html("Please enter a number in the room field.");
		if ( tmpUsername == "" )
			$("#changeRoomFormAlert").html("Please fill out the name field.");
		$("#changeRoomFormAlert").show();
	}
});

$("#urlSubmitButton").click(function()
{
	url = $("#urlInputField").val();
	prefix = url.split(":")[0];
	if ( prefix != "http" && prefix != "https" )
	{
		$("#urlAlert").show();
		return;
	}
	socket.emit("link", {room:room, username:username, linkTitle:url, url:url, customTitle:title});
	$("#urlInputField").val("");
	$("#urlAlert").hide();
});

$("#urlInfoButton").click(function()
{
	$("#changeTitle").modal("show");
});

$("#setTitleButton").click(function()
{
	title = $.trim($("#urlTitleField").val());
	$("#urlTitleField").val("");

	if ( title == "" )
		$("#urlInfoButton").html("Set Title");
	else
		$("#urlInfoButton").html(title);
	$("#changeTitle").modal("hide");
	barResize();
});

$("#changeTitleBackButton").click(function()
{
	$("#changeTitle").modal("hide");
});

$('#urlInputField').keypress(function(e)
{
    if(e.which == 13) {
		url = $("#urlInputField").val();
		prefix = url.split(":")[0];
		if ( prefix != "http" && prefix != "https" )
		{
			$("#urlAlert").show();
			return;
		}
		socket.emit("link", {room:room, username:username, linkTitle:url, url:url, customTitle:title});
		$("#urlInputField").val("");
		$("#urlAlert").hide();
    }
});

function appendLink(user, urlName, url, customTitle)
{
	$("#urlInfoButton").html("Set Title");
	title = '';
	barResize();

	if ( customTitle == "" ){
		data = createElement('p');
		insertElementAt(createElement('strong', null, user), data);
		insertElementAt(createText(' posted a link to '), data);
		insertElementAt(createElement('a', {'href':url}, url), data);
		$("#chatBody").prepend(data)
	}
	else{
		data = createElement('p');
		insertElementAt(createElement('strong', null, user), data);
		insertElementAt(createText(" posted a link for " + customTitle + " - "), data);
		insertElementAt(createElement('a', {'href':url}, url), data);
		$("#chatBody").prepend(data)
	}
		//chatBody = ""+user+" posted a link for "+customTitle+" - "+urlName+"

"+chatBody;
	//$("#chatBody").html(chatBody);

}

function barResize(){
	var barSize = $('#chatBody').outerWidth();
	var setButtonSize = $('#urlInfoButton').outerWidth();
	var sendButtonSize = $('#urlSubmitButton').outerWidth();

	$('#urlInputField').outerWidth(barSize-setButtonSize-sendButtonSize);

}
$(document).ready(function() {
  barResize();
});
$(window).resize(barResize);

socket.on("link", function(data)
{
	if ( data.room == room )
		appendLink(data.username, data.linkTitle, data.url, data.customTitle);
});<commit_msg>Fixed display of URL title<commit_after>var username = "";
var room = "";
var socket = io.connect();
var title = "";

$("#changeRoom").modal({
	keyboard: false,
	backdrop: "static"
});

$("#changeTitle").modal({
	keyboard: false,
	backdrop: "static"
});
$("#changeTitle").modal("hide");

$("#changeRoom").modal("show");
$("#urlAlert").hide();
$("#changeRoomFormAlert").hide();

$("#changeRoomButton").click(function()
{
	location.reload();
});

$("#joinRoomButton").click(function()
{
	tmpUsername = $("#usernameField").val();
	tmpRoom = parseInt($("#roomNumberField").val());
	if ( tmpUsername != "" && tmpRoom )
	{
		$("#chatBody").html("");
		username = tmpUsername
		room = tmpRoom;
		$("#roomNumber").html(room);
		$("#changeRoom").modal("hide");
		$("#changeRoomFormAlert").hide();
		socket.emit("resync");
	}
	else
	{
		if ( !tmpRoom )
			$("#changeRoomFormAlert").html("Please enter a number in the room field.");
		if ( tmpUsername == "" )
			$("#changeRoomFormAlert").html("Please fill out the name field.");
		$("#changeRoomFormAlert").show();
	}
});

$("#urlSubmitButton").click(function()
{
	url = $("#urlInputField").val();
	prefix = url.split(":")[0];
	if ( prefix != "http" && prefix != "https" )
	{
		$("#urlAlert").show();
		return;
	}
	socket.emit("link", {room:room, username:username, linkTitle:url, url:url, customTitle:title});
	$("#urlInputField").val("");
	$("#urlAlert").hide();
});

$("#urlInfoButton").click(function()
{
	$("#changeTitle").modal("show");
});

$("#setTitleButton").click(function()
{
	title = $.trim($("#urlTitleField").val());
	$("#urlTitleField").val("");

	if ( title == "" )
		$("#urlInfoButton").html("Set Title");
	else
		$("#urlInfoButton").html(title);
	$("#changeTitle").modal("hide");
	barResize();
});

$("#changeTitleBackButton").click(function()
{
	$("#changeTitle").modal("hide");
});

$('#urlInputField').keypress(function(e)
{
    if(e.which == 13) {
		url = $("#urlInputField").val();
		prefix = url.split(":")[0];
		if ( prefix != "http" && prefix != "https" )
		{
			$("#urlAlert").show();
			return;
		}
		socket.emit("link", {room:room, username:username, linkTitle:url, url:url, customTitle:title});
		$("#urlInputField").val("");
		$("#urlAlert").hide();
    }
});

function appendLink(user, urlName, url, customTitle)
{
	$("#urlInfoButton").html("Set Title");
	title = '';
	barResize();

	if ( customTitle == "" ){
		data = createElement('p');
		insertElementAt(createElement('strong', null, user), data);
		insertElementAt(createText(' posted a link to '), data);
		insertElementAt(createElement('a', {'href':url}, urlName), data);
		$("#chatBody").prepend(data)
	}
	else{
		data = createElement('p');
		insertElementAt(createElement('strong', null, user), data);
		insertElementAt(createText(" posted a link for " + customTitle + " - "), data);
		insertElementAt(createElement('a', {'href':url}, urlName), data);
		$("#chatBody").prepend(data)
	}
}

function barResize(){
	var barSize = $('#chatBody').outerWidth();
	var setButtonSize = $('#urlInfoButton').outerWidth();
	var sendButtonSize = $('#urlSubmitButton').outerWidth();

	$('#urlInputField').outerWidth(barSize-setButtonSize-sendButtonSize);

}
$(document).ready(function() {
  barResize();
});
$(window).resize(barResize);

socket.on("link", function(data)
{
	if ( data.room == room )
		appendLink(data.username, data.linkTitle, data.url, data.customTitle);
});<|endoftext|>


<commit_before>(function () { /*global _: false, Backbone: false */
    // Generate four random hex digits.
    function S4() {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    }

    // Generate a pseudo-GUID by concatenating random hexadecimal.
    function guid() {
        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
    }

    // Naming is a mess!
    var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB ;
    var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction; // No prefix in moz
    var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange; // No prefix in moz

    /* Horrible Hack to prevent ' Expected an identifier and instead saw 'continue' (a reserved word).'*/
    if (window.indexedDB) {
         indexedDB.prototype._continue =  indexedDB.prototype.continue;
    } else if (window.webkitIDBRequest) {
        webkitIDBRequest.prototype._continue = webkitIDBRequest.prototype.continue;
    } else if(window.mozIndexedDB) {
        mozIndexedDB.prototype._continue = mozIndexedDB.prototype.continue;
    }

    // Driver object
    // That's the interesting part.
    // There is a driver for each schema provided. The schema is a te combination of name (for the database), a version as well as migrations to reach that
    // version of the database.
    function Driver(schema, ready) {
        this.schema         = schema;
        this.ready          = ready;
        this.error          = null;
        this.transactions   = []; // Used to list all transactions and keep track of active ones.
        this.db             = null;
        this.dbRequest      = indexedDB.open(this.schema.id, this.schema.description || "");

        this.dbRequest.onsuccess = function (e) {
            this.db = e.target.result; // Attach the connection ot the queue.

            if (this.db.version === _.last(this.schema.migrations).version) {
                // No migration to perform!
                this.ready();
            } else if (this.db.version < _.last(this.schema.migrations).version) {
                // We need to migrate up to the current migration defined in the database
                this.migrate(this.schema.migrations, this.db.version, {
                    success: function () {
                        this.ready();
                    }.bind(this),
                    error: function () {
                        this.error = "Database not up to date. " + this.db.version + " expected was " + _.last(this.schema.migrations).version;
                    }.bind(this)
                });
            } else {
                // Looks like the IndexedDB is at a higher version than the current driver schema.
                this.error = "Database version is greater than current code " + this.db.version + " expected was " + _.last(this.schema.migrations).version;
            }
        }.bind(this);

        this.dbRequest.onerror = function (e) {
            // Failed to open the database
            this.error = "Couldn't not connect to the database"
        }.bind(this);

        this.dbRequest.onabort = function (e) {
            // Failed to open the database
            this.error = "Connection to the database aborted"
        }.bind(this);
    }

    function debug_log(str) {
        if (typeof window.console !== "undefined" && typeof window.console.log !== "undefined") {
            window.console.log(str);
        }
    }

    // Driver Prototype
    Driver.prototype = {

        // Tracks transactions. Mostly for debugging purposes. TO-IMPROVE
        _track_transaction: function(transaction) {
            this.transactions.push(transaction);
            function removeIt() {
                var idx = this.transactions.indexOf(transaction);
                if (idx !== -1) {this.transactions.splice(idx); }
            };
            transaction.oncomplete = removeIt.bind(this);
            transaction.onabort = removeIt.bind(this);
            transaction.onerror = removeIt.bind(this);
        },

        // Performs all the migrations to reach the right version of the database.
        migrate: function (migrations, version, options) {
            debug_log("Starting migrations from " + version);
            this._migrate_next(migrations, version, options);
        },

        // Performs the next migrations. This method is private and should probably not be called.
        _migrate_next: function (migrations, version, options) {
            var that = this;
            var migration = migrations.shift();
            if (migration) {
                if (!version || version < migration.version) {
                    // We need to apply this migration-
                    if (typeof migration.before == "undefined") {
                        migration.before = function (next) {
                            next();
                        };
                    }
                    if (typeof migration.after == "undefined") {
                        migration.after = function (next) {
                            next();
                        };
                    }
                    // First, let's run the before script
                    migration.before(function () {
                        var versionRequest = this.db.setVersion(migration.version);
                        versionRequest.onsuccess = function (e) {
                            var transaction = versionRequest.result;

                            //last modification occurred, need finish
                            if(migrations.length ==0) {
                                transaction.oncomplete = function() {

                                    debug_log("Done migrating");
                                    // No more migration
                                    options.success();
                                }
                            }

                            migration.migrate(this.db, versionRequest, function () {
                                // Migration successfully appliedn let's go to the next one!
                                migration.after(function () {
                                    debug_log("Migrated to " + migration.version);
                                    that._migrate_next(migrations, version, options);
                                });
                            });
                        }.bind(this);
                    }.bind(this));
                } else {
                    // No need to apply this migration
                    debug_log("Skipping migration " + migration.version);
                    this._migrate_next(migrations, version, options);
                }
            }
        },

        // This is the main method, called by the ExecutionQueue when the driver is ready (database open and migration performed)
        execute: function (storeName, method, object, options) {
            switch (method) {
            case "create":
                this.write(storeName, object, options);
                break;
            case "read":
                if (object instanceof Backbone.Collection) {
                    this.query(storeName, object, options); // It's a collection
                } else {
                    this.read(storeName, object, options); // It's a model
                }
                break;
            case "update":
                this.write(storeName, object, options); // We may want to check that this is not a collection. TOFIX
                break;
            case "delete":
                this.delete(storeName, object, options); // We may want to check that this is not a collection. TOFIX
                break;
            default:
                // Hum what?
            }
        },

        // Writes the json to the storeName in db.
        // options are just success and error callbacks.
        write: function (storeName, object, options) {
            var writeTransaction = this.db.transaction([storeName], IDBTransaction.READ_WRITE);
            //this._track_transaction(writeTransaction);
            var store = writeTransaction.objectStore(storeName);
            var json = object.toJSON();

            if (!json.id) json.id = guid();

            var writeRequest = store.put(json, json.id);

            writeRequest.onerror = function (e) {
                options.error(e);
            };
            writeRequest.onsuccess = function (e) {
                options.success(json);
            };
        },

        // Reads from storeName in db with json.id if it's there of with any json.xxxx as long as xxx is an index in storeName
        read: function (storeName, object, options) {
            var readTransaction = this.db.transaction([storeName], IDBTransaction.READ_ONLY);
            //this._track_transaction(readTransaction);

            var store = readTransaction.objectStore(storeName);
            var json = object.toJSON();

            var getRequest = null;
            if (json.id) {
                getRequest = store.get(json.id);
            } else {
                // We need to find which index we have
                _.each(store.indexNames, function (key, index) {
                    index = store.index(key);
                    if (json[index.keyPath] && !getRequest) {
                        getRequest = index.get(json[index.keyPath]);
                    }
                });
            }
            if (getRequest) {
                getRequest.onsuccess = function (event) {
                    if (event.target.result) {
                        options.success(event.target.result);
                    } else {
                        options.error("Not Found");
                    }
                };
                getRequest.onerror = function () {
                    options.error("Not Found"); // We couldn't find the record.
                }
            } else {
                options.error("Not Found"); // We couldn't even look for it, as we don't have enough data.
            }
        },

        // Deletes the json.id key and value in storeName from db.
        delete: function (storeName, object, options) {
            var deleteTransaction = this.db.transaction([storeName], IDBTransaction.READ_WRITE);
            //this._track_transaction(deleteTransaction);

            var store = deleteTransaction.objectStore(storeName);
            var json = object.toJSON();

            var deleteRequest = store.delete(json.id);
            deleteRequest.onsuccess = function (event) {
                options.success(null);
            };
            deleteRequest.onerror = function (event) {
                options.error("Not Deleted");
            };
        },

        // Performs a query on storeName in db.
        // options may include :
        // - conditions : value of an index, or range for an index
        // - range : range for the primary key
        // - limit : max number of elements to be yielded
        // - offset : skipped items.
        query: function (storeName, collection, options) {
            var elements = [];
            var skipped = 0, processed = 0;
            var queryTransaction = this.db.transaction([storeName], IDBTransaction.READ_ONLY);
            //this._track_transaction(queryTransaction);

            var readCursor = null;
            var store = queryTransaction.objectStore(storeName);
            var index = null,
                lower = null,
                upper = null,
                bounds = null;

            if (options.conditions) {
                // We have a condition, we need to use it for the cursor
                _.each(store.indexNames, function (key) {
                    if (!readCursor) {
                        index = store.index(key);
                        if (options.conditions[index.keyPath] instanceof Array) {
                            lower = options.conditions[index.keyPath][0] > options.conditions[index.keyPath][1] ? options.conditions[index.keyPath][1] : options.conditions[index.keyPath][0];
                            upper = options.conditions[index.keyPath][0] > options.conditions[index.keyPath][1] ? options.conditions[index.keyPath][0] : options.conditions[index.keyPath][1];
                            bounds = IDBKeyRange.bound(lower, upper, true, true);

                            if (options.conditions[index.keyPath][0] > options.conditions[index.keyPath][1]) {
                                // Looks like we want the DESC order
                                readCursor = index.openCursor(bounds, 2);
                            } else {
                                // We want ASC order
                                readCursor = index.openCursor(bounds, 0);
                            }
                        } else if (options.conditions[index.keyPath]) {
                            bounds = IDBKeyRange.only(options.conditions[index.keyPath]);
                            readCursor = index.openCursor(bounds);
                        }
                    }
                });
            } else {
                // No conditions, use the index
                if (options.range) {
                    lower = options.range[0] > options.range[1] ? options.range[1] : options.range[0];
                    upper = options.range[0] > options.range[1] ? options.range[0] : options.range[1];
                    bounds = IDBKeyRange.bound(lower, upper);
                    if (options.range[0] > options.range[1]) {
                        readCursor = store.openCursor(bounds, 2);
                    } else {
                        readCursor = store.openCursor(bounds, 0);
                    }
                } else {
                    readCursor = store.openCursor();
                }
            }

            if (typeof (readCursor) == "undefined" || !readCursor) {
                options.error("No Cursor");
            } else {
                // Setup a handler for the cursor’s `success` event:
                readCursor.onsuccess = function (e) {
                    var cursor = e.target.result;
                    if (!cursor) {
                        if (options.addIndividually || options.clear) {
                            // nothing!
                            // We need to indicate that we're done. But, how?
                            collection.trigger("reset");
                        } else {
                            options.success(elements); // We're done. No more elements.
                        }
                    }
                    else {
                        // Cursor is not over yet.
                        if (options.limit && processed >= options.limit) {
                            // Yet, we have processed enough elements. So, let's just skip.
                            if (bounds && options.conditions[index.keyPath]) {
                                cursor.continue(options.conditions[index.keyPath][1] + 1); /* We need to 'terminate' the cursor cleany, by moving to the end */
                            } else {
                                cursor.continue(); /* We need to 'terminate' the cursor cleany, by moving to the end */
                            }
                        }
                        else if (options.offset && options.offset > skipped) {
                            skipped++;
                            cursor.continue(options.offset - skipped); /* We need to Moving the cursor forward */
                        } else {
                            // This time, it looks like it's good!
                            if (options.addIndividually) {
                                collection.add(cursor.value);
                            } else if (options.clear) {
                                var deleteRequest = store.delete(cursor.value.id);
                                deleteRequest.onsuccess = function (event) {
                                    elements.push(cursor.value);
                                };
                                deleteRequest.onerror = function (event) {
                                    elements.push(cursor.value);
                                };

                            } else {
                                elements.push(cursor.value);
                            }
                            processed++;
                            cursor.continue();
                        }
                    }
                };
            }
        }
    };

    // ExecutionQueue object
    // The execution queue is an abstraction to buffer up requests to the database.
    // It holds a "driver". When the driver is ready, it just fires up the queue and executes in sync.
    function ExecutionQueue(schema) {
        this.driver     = new Driver(schema, this.ready.bind(this));
        this.started    = false;
        this.stack      = [];
    }

    // ExecutionQueue Prototype
    ExecutionQueue.prototype = {
        // Called when the driver is ready
        // It just loops over the elements in the queue and executes them.
        ready: function () {
            this.started = true;
            _.each(this.stack, function (message) {
                this.execute(message);
            }.bind(this));
        },

        // Executes a given command on the driver. If not started, just stacks up one more element.
        execute: function (message) {
            if (this.started) {
                this.driver.execute(message[1].storeName, message[0], message[1], message[2]); // Upon messages, we execute the query
            } else {
                this.stack.push(message);
            }
        }
    };

    // Method used by Backbone for sync of data with data store. It was initially designed to work with "server side" APIs, This wrapper makes
    // it work with the local indexedDB stuff. It uses the schema attribute provided by the object.
    // The wrapper keeps an active Executuon Queue for each "schema", and executes querues agains it, based on the object type (collection or
    // single model), but also the method... etc.
    // Keeps track of the connections
    var Databases = {};

    Backbone.sync = function (method, object, options) {
        var schema = object.database;
        if (!Databases[schema.id]) {
            Databases[schema.id] = new ExecutionQueue(schema);
        }
        Databases[schema.id].execute([method, object, options]);
    };
})();<commit_msg>bug in offset cursor search, moving forward it's just a continue over an iteration variable, not a parameter of continue method<commit_after>(function () { /*global _: false, Backbone: false */
    // Generate four random hex digits.
    function S4() {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    }

    // Generate a pseudo-GUID by concatenating random hexadecimal.
    function guid() {
        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
    }

    // Naming is a mess!
    var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB ;
    var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction; // No prefix in moz
    var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange; // No prefix in moz

    /* Horrible Hack to prevent ' Expected an identifier and instead saw 'continue' (a reserved word).'*/
    if (window.indexedDB) {
         indexedDB.prototype._continue =  indexedDB.prototype.continue;
    } else if (window.webkitIDBRequest) {
        webkitIDBRequest.prototype._continue = webkitIDBRequest.prototype.continue;
    } else if(window.mozIndexedDB) {
        mozIndexedDB.prototype._continue = mozIndexedDB.prototype.continue;
    }

    // Driver object
    // That's the interesting part.
    // There is a driver for each schema provided. The schema is a te combination of name (for the database), a version as well as migrations to reach that
    // version of the database.
    function Driver(schema, ready) {
        this.schema         = schema;
        this.ready          = ready;
        this.error          = null;
        this.transactions   = []; // Used to list all transactions and keep track of active ones.
        this.db             = null;
        this.dbRequest      = indexedDB.open(this.schema.id, this.schema.description || "");

        this.dbRequest.onsuccess = function (e) {
            this.db = e.target.result; // Attach the connection ot the queue.

            if (this.db.version === _.last(this.schema.migrations).version) {
                // No migration to perform!
                this.ready();
            } else if (this.db.version < _.last(this.schema.migrations).version) {
                // We need to migrate up to the current migration defined in the database
                this.migrate(this.schema.migrations, this.db.version, {
                    success: function () {
                        this.ready();
                    }.bind(this),
                    error: function () {
                        this.error = "Database not up to date. " + this.db.version + " expected was " + _.last(this.schema.migrations).version;
                    }.bind(this)
                });
            } else {
                // Looks like the IndexedDB is at a higher version than the current driver schema.
                this.error = "Database version is greater than current code " + this.db.version + " expected was " + _.last(this.schema.migrations).version;
            }
        }.bind(this);

        this.dbRequest.onerror = function (e) {
            // Failed to open the database
            this.error = "Couldn't not connect to the database"
        }.bind(this);

        this.dbRequest.onabort = function (e) {
            // Failed to open the database
            this.error = "Connection to the database aborted"
        }.bind(this);
    }

    function debug_log(str) {
        if (typeof window.console !== "undefined" && typeof window.console.log !== "undefined") {
            window.console.log(str);
        }
    }

    // Driver Prototype
    Driver.prototype = {

        // Tracks transactions. Mostly for debugging purposes. TO-IMPROVE
        _track_transaction: function(transaction) {
            this.transactions.push(transaction);
            function removeIt() {
                var idx = this.transactions.indexOf(transaction);
                if (idx !== -1) {this.transactions.splice(idx); }
            };
            transaction.oncomplete = removeIt.bind(this);
            transaction.onabort = removeIt.bind(this);
            transaction.onerror = removeIt.bind(this);
        },

        // Performs all the migrations to reach the right version of the database.
        migrate: function (migrations, version, options) {
            debug_log("Starting migrations from " + version);
            this._migrate_next(migrations, version, options);
        },

        // Performs the next migrations. This method is private and should probably not be called.
        _migrate_next: function (migrations, version, options) {
            var that = this;
            var migration = migrations.shift();
            if (migration) {
                if (!version || version < migration.version) {
                    // We need to apply this migration-
                    if (typeof migration.before == "undefined") {
                        migration.before = function (next) {
                            next();
                        };
                    }
                    if (typeof migration.after == "undefined") {
                        migration.after = function (next) {
                            next();
                        };
                    }
                    // First, let's run the before script
                    migration.before(function () {
                        var versionRequest = this.db.setVersion(migration.version);
                        versionRequest.onsuccess = function (e) {
                            var transaction = versionRequest.result;

                            //last modification occurred, need finish
                            if(migrations.length ==0) {
                                transaction.oncomplete = function() {

                                    debug_log("Done migrating");
                                    // No more migration
                                    options.success();
                                }
                            }

                            migration.migrate(this.db, versionRequest, function () {
                                // Migration successfully appliedn let's go to the next one!
                                migration.after(function () {
                                    debug_log("Migrated to " + migration.version);
                                    that._migrate_next(migrations, version, options);
                                });
                            });
                        }.bind(this);
                    }.bind(this));
                } else {
                    // No need to apply this migration
                    debug_log("Skipping migration " + migration.version);
                    this._migrate_next(migrations, version, options);
                }
            }
        },

        // This is the main method, called by the ExecutionQueue when the driver is ready (database open and migration performed)
        execute: function (storeName, method, object, options) {
            switch (method) {
            case "create":
                this.write(storeName, object, options);
                break;
            case "read":
                if (object instanceof Backbone.Collection) {
                    this.query(storeName, object, options); // It's a collection
                } else {
                    this.read(storeName, object, options); // It's a model
                }
                break;
            case "update":
                this.write(storeName, object, options); // We may want to check that this is not a collection. TOFIX
                break;
            case "delete":
                this.delete(storeName, object, options); // We may want to check that this is not a collection. TOFIX
                break;
            default:
                // Hum what?
            }
        },

        // Writes the json to the storeName in db.
        // options are just success and error callbacks.
        write: function (storeName, object, options) {
            var writeTransaction = this.db.transaction([storeName], IDBTransaction.READ_WRITE);
            //this._track_transaction(writeTransaction);
            var store = writeTransaction.objectStore(storeName);
            var json = object.toJSON();

            if (!json.id) json.id = guid();

            var writeRequest = store.put(json, json.id);

            writeRequest.onerror = function (e) {
                options.error(e);
            };
            writeRequest.onsuccess = function (e) {
                options.success(json);
            };
        },

        // Reads from storeName in db with json.id if it's there of with any json.xxxx as long as xxx is an index in storeName
        read: function (storeName, object, options) {
            var readTransaction = this.db.transaction([storeName], IDBTransaction.READ_ONLY);
            //this._track_transaction(readTransaction);

            var store = readTransaction.objectStore(storeName);
            var json = object.toJSON();

            var getRequest = null;
            if (json.id) {
                getRequest = store.get(json.id);
            } else {
                // We need to find which index we have
                _.each(store.indexNames, function (key, index) {
                    index = store.index(key);
                    if (json[index.keyPath] && !getRequest) {
                        getRequest = index.get(json[index.keyPath]);
                    }
                });
            }
            if (getRequest) {
                getRequest.onsuccess = function (event) {
                    if (event.target.result) {
                        options.success(event.target.result);
                    } else {
                        options.error("Not Found");
                    }
                };
                getRequest.onerror = function () {
                    options.error("Not Found"); // We couldn't find the record.
                }
            } else {
                options.error("Not Found"); // We couldn't even look for it, as we don't have enough data.
            }
        },

        // Deletes the json.id key and value in storeName from db.
        delete: function (storeName, object, options) {
            var deleteTransaction = this.db.transaction([storeName], IDBTransaction.READ_WRITE);
            //this._track_transaction(deleteTransaction);

            var store = deleteTransaction.objectStore(storeName);
            var json = object.toJSON();

            var deleteRequest = store.delete(json.id);
            deleteRequest.onsuccess = function (event) {
                options.success(null);
            };
            deleteRequest.onerror = function (event) {
                options.error("Not Deleted");
            };
        },

        // Performs a query on storeName in db.
        // options may include :
        // - conditions : value of an index, or range for an index
        // - range : range for the primary key
        // - limit : max number of elements to be yielded
        // - offset : skipped items.
        query: function (storeName, collection, options) {
            var elements = [];
            var skipped = 0, processed = 0;
            var queryTransaction = this.db.transaction([storeName], IDBTransaction.READ_ONLY);
            //this._track_transaction(queryTransaction);

            var readCursor = null;
            var store = queryTransaction.objectStore(storeName);
            var index = null,
                lower = null,
                upper = null,
                bounds = null;

            if (options.conditions) {
                // We have a condition, we need to use it for the cursor
                _.each(store.indexNames, function (key) {
                    if (!readCursor) {
                        index = store.index(key);
                        if (options.conditions[index.keyPath] instanceof Array) {
                            lower = options.conditions[index.keyPath][0] > options.conditions[index.keyPath][1] ? options.conditions[index.keyPath][1] : options.conditions[index.keyPath][0];
                            upper = options.conditions[index.keyPath][0] > options.conditions[index.keyPath][1] ? options.conditions[index.keyPath][0] : options.conditions[index.keyPath][1];
                            bounds = IDBKeyRange.bound(lower, upper, true, true);

                            if (options.conditions[index.keyPath][0] > options.conditions[index.keyPath][1]) {
                                // Looks like we want the DESC order
                                readCursor = index.openCursor(bounds, 2);
                            } else {
                                // We want ASC order
                                readCursor = index.openCursor(bounds, 0);
                            }
                        } else if (options.conditions[index.keyPath]) {
                            bounds = IDBKeyRange.only(options.conditions[index.keyPath]);
                            readCursor = index.openCursor(bounds);
                        }
                    }
                });
            } else {
                // No conditions, use the index
                if (options.range) {
                    lower = options.range[0] > options.range[1] ? options.range[1] : options.range[0];
                    upper = options.range[0] > options.range[1] ? options.range[0] : options.range[1];
                    bounds = IDBKeyRange.bound(lower, upper);
                    if (options.range[0] > options.range[1]) {
                        readCursor = store.openCursor(bounds, 2);
                    } else {
                        readCursor = store.openCursor(bounds, 0);
                    }
                } else {
                    readCursor = store.openCursor();
                }
            }

            if (typeof (readCursor) == "undefined" || !readCursor) {
                options.error("No Cursor");
            } else {
                // Setup a handler for the cursor’s `success` event:
                readCursor.onsuccess = function (e) {
                    var cursor = e.target.result;
                    if (!cursor) {
                        if (options.addIndividually || options.clear) {
                            // nothing!
                            // We need to indicate that we're done. But, how?
                            collection.trigger("reset");
                        } else {
                            options.success(elements); // We're done. No more elements.
                        }
                    }
                    else {
                        // Cursor is not over yet.
                        if (options.limit && processed >= options.limit) {
                            // Yet, we have processed enough elements. So, let's just skip.
                            if (bounds && options.conditions[index.keyPath]) {
                                cursor.continue(options.conditions[index.keyPath][1] + 1); /* We need to 'terminate' the cursor cleany, by moving to the end */
                            } else {
                                cursor.continue(); /* We need to 'terminate' the cursor cleany, by moving to the end */
                            }
                        }
                        else if (options.offset && options.offset > skipped) {
                            skipped++;
                            cursor.continue(); /* We need to Moving the cursor forward */
                        } else {
                            // This time, it looks like it's good!
                            if (options.addIndividually) {
                                collection.add(cursor.value);
                            } else if (options.clear) {
                                var deleteRequest = store.delete(cursor.value.id);
                                deleteRequest.onsuccess = function (event) {
                                    elements.push(cursor.value);
                                };
                                deleteRequest.onerror = function (event) {
                                    elements.push(cursor.value);
                                };

                            } else {
                                elements.push(cursor.value);
                            }
                            processed++;
                            cursor.continue();
                        }
                    }
                };
            }
        }
    };

    // ExecutionQueue object
    // The execution queue is an abstraction to buffer up requests to the database.
    // It holds a "driver". When the driver is ready, it just fires up the queue and executes in sync.
    function ExecutionQueue(schema) {
        this.driver     = new Driver(schema, this.ready.bind(this));
        this.started    = false;
        this.stack      = [];
    }

    // ExecutionQueue Prototype
    ExecutionQueue.prototype = {
        // Called when the driver is ready
        // It just loops over the elements in the queue and executes them.
        ready: function () {
            this.started = true;
            _.each(this.stack, function (message) {
                this.execute(message);
            }.bind(this));
        },

        // Executes a given command on the driver. If not started, just stacks up one more element.
        execute: function (message) {
            if (this.started) {
                this.driver.execute(message[1].storeName, message[0], message[1], message[2]); // Upon messages, we execute the query
            } else {
                this.stack.push(message);
            }
        }
    };

    // Method used by Backbone for sync of data with data store. It was initially designed to work with "server side" APIs, This wrapper makes
    // it work with the local indexedDB stuff. It uses the schema attribute provided by the object.
    // The wrapper keeps an active Executuon Queue for each "schema", and executes querues agains it, based on the object type (collection or
    // single model), but also the method... etc.
    // Keeps track of the connections
    var Databases = {};

    Backbone.sync = function (method, object, options) {
        var schema = object.database;
        if (!Databases[schema.id]) {
            Databases[schema.id] = new ExecutionQueue(schema);
        }
        Databases[schema.id].execute([method, object, options]);
    };
})();<|endoftext|>


<commit_before>
    // handles interfacing with GIFEncoder
    var MFAnimatedGIF = function(opts) {
        var encoder;

        var _rotate = function(image, rotation) {
            var canvas = document.createElement("canvas");

            canvas.width = image.width;
            canvas.height = image.height;

            var ctx = canvas.getContext('2d');
            ctx.translate(image.width/2, image.height/2);
            ctx.rotate(rotation * Math.PI / 180.0);
            ctx.drawImage(image, -image.width/2, -image.height/2, image.width, image.height);
            ctx.rotate(rotation * Math.PI / 180.0);
            ctx.translate(-image.width/2, -image.height/2);

            return canvas;
        };

        var _initialize = function(opts) {

            var canvas = document.createElement("canvas");
            var context = canvas.getContext('2d');

            encoder = new GIFEncoder();
            encoder.setRepeat(opts.repeat);
            encoder.setDelay(opts.delay);
            canvas.width  = opts.width;
            canvas.height = opts.height;
            encoder.setSize(opts.width, opts.height);
            encoder.setQuality(opts.quality);

            encoder.start();

            for(var i=0; i<opts.images.length; i++) {
                var animframe = opts.images[i];
                var ctx = canvas.getContext('2d');

                ctx.drawImage(animframe, 0, 0, animframe.width, animframe.height, 0, 0, canvas.width, canvas.height);

                encoder.addFrame(ctx);
            }

            encoder.finish();
        };

        var _rawDataURL = function() {
            return $.base64.encode(encoder.stream().getData());
        };

        var _dataURL = function() {
            return 'data:image/gif;base64,' + _rawDataURL();
        };

        var _binaryURL = function() {
            // Convert encoder data to binary format
            var data = encoder.stream().getData();
            var byteArray = new Uint8Array(data.length);
            for (var i = 0; i < data.length; i++) {
                byteArray[i] = data.charCodeAt(i) & 0xff;
            }

            var bb = new BlobBuilder();
            bb.append(byteArray.buffer);
            return window.URL.createObjectURL(bb.getBlob("image/gif"));
        };

        _initialize(opts);

        return {
            dataURL   : _dataURL,
            rawDataURL: _rawDataURL,
            binaryURL : _binaryURL
        };
    };

    var fileList = $("#inimglist");
    var body = $("body");

    var App = {};
    App.MAX_BYTES = 2*1024*1024; // 2MB
    App.initialRate = 300; // 300ms delay in frames
    App.initialQuality = 10; // 10 is supposed to give a good balance
    App.timeline = [];

    App.clear = function() {
        finalImage.attr("src", "about:blank").hide();
        fileList.empty();
        App.timeline = [];
        body.removeClass("hasfiles");
    };
    App.rebuildTimeline = function() {
        App.timeline = fileList.find(".col").map(function() {
            var originalimg = new Image();
            var src = $(this).find("img").attr("src");
            if (src) {
                originalimg.src = src;
                return originalimg;
            }
        }).toArray();
    };

    setupDrag();

    // Bail out if the browser doesn't support required features
    // blobbuilder and a[download] are not required, as there is a fallback
    var support = FileReaderJS.enabled && Modernizr.draganddrop &&
                    document.querySelector && Modernizr.postmessage && window.JSON;
    if (!support) {
        body.addClass("disabled");
        var caniscript = document.createElement('script');
        caniscript.src = 'http://sandbox.thewikies.com/caniuse/json+filereader+draganddrop+querySelector+postmessage.html?callback=canicallback';
        document.body.appendChild(caniscript);
    }

    // drag and drop setup.
    var opts = {
        accept: 'image/*',
        on: {
            beforestart: function(file) {
                if (file.size > App.MAX_BYTES) {
                    return false;
                }
            },
            error: function(file) {
                fileList.append("
Error

");
            },
            skip: function(file) {
                fileList.append("
Skip

");
            },
            load: function(e, file) {
                fileList.append("

");

                var originalimg = new Image();

                if (App.timeline.length === 0){
                    // TODO: do we need this?
                    // App.timeline[0].width seems to work fine when called in groupend
                    originalimg.onload = function(){
                        App.initialWidth    = originalimg.width;
                        App.initialHeight   = originalimg.height;
                        $(window).trigger('firstimage');
                    };
                }

                originalimg.src = e.target.result;
                App.timeline.push(originalimg);
            },
            groupstart: function(group) {
                body.addClass("hasfiles");
            },
            groupend: function(group) {
                // TOOOOOO SLOW
                //buildGif();
            }
        }
    };
    // the library handles most of the dnd bits.
    FileReaderJS.setupDrop(document.body, opts);
    FileReaderJS.setupClipboard(document.body, opts);

    // test to see if we can do cool download or fallback style.
        Modernizr.addTest({
            // BlobBuilder
            "blobbuilder": function() {
                return  !!(window.BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder);
            },
            // Blob URL support
            "bloburls": function() {
                return !!(window.URL && window.URL.createObjectURL || window.webkitURL && window.webkitURL.createObjectURL);
            },
            // download attribute
            "download": function() {
                return "download" in document.createElement("a");
            },
            // FormData
            "formdata": function() {
                return  !!(window.FormData && "append" in window.FormData.prototype);
            }
        });

        if(!Modernizr.download && $('#saveabro')) {
            var iframe = document.createElement("iframe");

            iframe.src = "http://saveasbro.com/gif/";
            iframe.setAttribute("style","position: absolute; visibility: hidden; left: -999em;");
            iframe.id = "saveasbro";
            document.body.appendChild(iframe);
        }

    var finalImage = $("#animresult");
    $(".clear").on('click', function() {
        App.clear();
        return false;
    });

    // kick off GIF generation and download prep
    $('.play').on('click', function(e) {
        buildGif();
        return false;
    });

    function buildGif() {

        if (!App.timeline.length) {
            return;
        }

        var mfAnimatedGIF = new MFAnimatedGIF({
            images: App.timeline,
            delay : App.rate,
            quality : App.quality,
            repeat: 0,

            // use dimensions from first image as default
            height: App.animHeight || App.timeline[0].height,
            width : App.animWidth  || App.timeline[0].width
        });

        $('#animresult').attr('src', mfAnimatedGIF.dataURL()).show();

        //
        // Create the download link
        //
        window.URL = window.webkitURL || window.URL;
        window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;

        var filename = "animated."+((+new Date()) + "").substr(8);

        var a = document.querySelector('#downloadlink');
        a.style.display = "none";

        if(Modernizr.download && Modernizr.bloburls && Modernizr.blobbuilder) {
            a.download = filename + '.gif';
            a.href = mfAnimatedGIF.binaryURL(filename);
            a.style.display = "inline-block";

            a.onclick = function(e) {
              // Need a small delay for the revokeObjectURL to work properly.
              setTimeout(function() {
                window.URL.revokeObjectURL(a.href);
              }, 1500);
            };
        } else {
            window.onmessage = function(e) {
                e = e || window.event;

                var origin = e.origin || e.domain || e.uri;
                if(origin !== "http://saveasbro.com") return;
                a.href = e.data;
                a.style.display = "inline-block";
            };

            var iframe = document.querySelector('#saveasbro');
            iframe.contentWindow.postMessage(JSON.stringify({name:filename, data: mfAnimatedGIF.rawDataURL(), formdata: Modernizr.formdata}),"http://saveasbro.com/gif/");
        }

    }

function canicallback(data){
    $('#dropArea').html(data.html);
}
<commit_msg>Rotate on click.<commit_after>
    // handles interfacing with GIFEncoder
    var MFAnimatedGIF = function(opts) {
        var encoder;

        var _rotate = function(image, rotation) {
            var canvas = document.createElement("canvas");

            canvas.width = image.width;
            canvas.height = image.height;

            var ctx = canvas.getContext('2d');
            ctx.translate(image.width/2, image.height/2);
            ctx.rotate(rotation * Math.PI / 180.0);
            ctx.drawImage(image, -image.width/2, -image.height/2, image.width, image.height);
            ctx.rotate(rotation * Math.PI / 180.0);
            ctx.translate(-image.width/2, -image.height/2);

            return canvas;
        };

        var _initialize = function(opts) {

            var canvas = document.createElement("canvas");
            var context = canvas.getContext('2d');

            encoder = new GIFEncoder();
            encoder.setRepeat(opts.repeat);
            encoder.setDelay(opts.delay);
            canvas.width  = opts.width;
            canvas.height = opts.height;
            encoder.setSize(opts.width, opts.height);
            encoder.setQuality(opts.quality);

            encoder.start();

            for(var i=0; i<opts.images.length; i++) {
                var animframe = (opts.rotations[i] === 0) ? opts.images[i] : _rotate(opts.images[i], opts.rotations[i]);

                var ctx = canvas.getContext('2d');
                ctx.drawImage(animframe, 0, 0, animframe.width, animframe.height, 0, 0, canvas.width, canvas.height);

                encoder.addFrame(ctx);
            }

            encoder.finish();
        };

        var _rawDataURL = function() {
            return $.base64.encode(encoder.stream().getData());
        };

        var _dataURL = function() {
            return 'data:image/gif;base64,' + _rawDataURL();
        };

        var _binaryURL = function() {
            // Convert encoder data to binary format
            var data = encoder.stream().getData();
            var byteArray = new Uint8Array(data.length);
            for (var i = 0; i < data.length; i++) {
                byteArray[i] = data.charCodeAt(i) & 0xff;
            }

            var bb = new BlobBuilder();
            bb.append(byteArray.buffer);
            return window.URL.createObjectURL(bb.getBlob("image/gif"));
        };

        _initialize(opts);

        return {
            dataURL   : _dataURL,
            rawDataURL: _rawDataURL,
            binaryURL : _binaryURL
        };
    };

    var fileList = $("#inimglist");
    var body = $("body");

    var App = {};
    App.MAX_BYTES = 2*1024*1024; // 2MB
    App.initialRate = 300; // 300ms delay in frames
    App.initialQuality = 10; // 10 is supposed to give a good balance
    App.timeline = [];

    App.clear = function() {
        finalImage.attr("src", "about:blank").hide();
        fileList.empty();
        App.timeline = [];
        body.removeClass("hasfiles");
    };
    App.rebuildTimeline = function() {
        App.timeline = fileList.find(".col").map(function() {
            var originalimg = new Image();
            var src = $(this).find("img").attr("src");
            if (src) {
                originalimg.src = src;
                return originalimg;
            }
        }).toArray();
    };

    setupDrag();

    // Bail out if the browser doesn't support required features
    // blobbuilder and a[download] are not required, as there is a fallback
    var support = FileReaderJS.enabled && Modernizr.draganddrop &&
                    document.querySelector && Modernizr.postmessage && window.JSON;
    if (!support) {
        body.addClass("disabled");
        var caniscript = document.createElement('script');
        caniscript.src = 'http://sandbox.thewikies.com/caniuse/json+filereader+draganddrop+querySelector+postmessage.html?callback=canicallback';
        document.body.appendChild(caniscript);
    }

    // drag and drop setup.
    var opts = {
        accept: 'image/*',
        on: {
            beforestart: function(file) {
                if (file.size > App.MAX_BYTES) {
                    return false;
                }
            },
            error: function(file) {
                fileList.append("
Error

");
            },
            skip: function(file) {
                fileList.append("
Skip

");
            },
            load: function(e, file) {
                fileList.append("

");

                var originalimg = new Image();

                if (App.timeline.length === 0){
                    // TODO: do we need this?
                    // App.timeline[0].width seems to work fine when called in groupend
                    originalimg.onload = function(){
                        App.initialWidth    = originalimg.width;
                        App.initialHeight   = originalimg.height;
                        $(window).trigger('firstimage');
                    };
                }

                originalimg.src = e.target.result;
                App.timeline.push(originalimg);
            },
            groupstart: function(group) {
                body.addClass("hasfiles");
            },
            groupend: function(group) {
                // TOOOOOO SLOW
                //buildGif();
            }
        }
    };

    // the library handles most of the dnd bits.
    FileReaderJS.setupDrop(document.body, opts);
    FileReaderJS.setupClipboard(document.body, opts);

    $(document).on('click', '.rotateimg', function(e) {
        var currentRotation = parseInt($(e.currentTarget).attr('data-rotation')) + 90;
        if(currentRotation >= 360) currentRotation = 0;
        $(e.currentTarget).rotate(currentRotation);
        $(e.currentTarget).attr('data-rotation', currentRotation);
    });

    // test to see if we can do cool download or fallback style.
        Modernizr.addTest({
            // BlobBuilder
            "blobbuilder": function() {
                return  !!(window.BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder);
            },
            // Blob URL support
            "bloburls": function() {
                return !!(window.URL && window.URL.createObjectURL || window.webkitURL && window.webkitURL.createObjectURL);
            },
            // download attribute
            "download": function() {
                return "download" in document.createElement("a");
            },
            // FormData
            "formdata": function() {
                return  !!(window.FormData && "append" in window.FormData.prototype);
            }
        });

        if(!Modernizr.download && $('#saveabro')) {
            var iframe = document.createElement("iframe");

            iframe.src = "http://saveasbro.com/gif/";
            iframe.setAttribute("style","position: absolute; visibility: hidden; left: -999em;");
            iframe.id = "saveasbro";
            document.body.appendChild(iframe);
        }

    var finalImage = $("#animresult");
    $(".clear").on('click', function() {
        App.clear();
        return false;
    });

    // kick off GIF generation and download prep
    $('.play').on('click', function(e) {
        buildGif();
        return false;
    });

    function buildGif() {

        if (!App.timeline.length) {
            return;
        }

        var rotations = [];
        $('.rotateimg').each(function(j, el) {
            rotations.push($(el).data('rotation'));
        });

        var mfAnimatedGIF = new MFAnimatedGIF({
            images: App.timeline,
            rotations: rotations,
            delay : App.rate,
            quality : App.quality,
            repeat: 0,

            // use dimensions from first image as default
            height: App.animHeight || App.timeline[0].height,
            width : App.animWidth  || App.timeline[0].width
        });

        $('#animresult').attr('src', mfAnimatedGIF.dataURL());

        //
        // Create the download link
        //
        window.URL = window.webkitURL || window.URL;
        window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;

        var filename = "animated."+((+new Date()) + "").substr(8);

        var a = document.querySelector('#downloadlink');
        a.style.display = "none";

        if(Modernizr.download && Modernizr.bloburls && Modernizr.blobbuilder) {
            a.download = filename + '.gif';
            a.href = mfAnimatedGIF.binaryURL(filename);
            a.style.display = "inline-block";

            a.onclick = function(e) {
              // Need a small delay for the revokeObjectURL to work properly.
              setTimeout(function() {
                window.URL.revokeObjectURL(a.href);
              }, 1500);
            };
        } else {
            window.onmessage = function(e) {
                e = e || window.event;

                var origin = e.origin || e.domain || e.uri;
                if(origin !== "http://saveasbro.com") return;
                a.href = e.data;
                a.style.display = "inline-block";
            };

            var iframe = document.querySelector('#saveasbro');
            iframe.contentWindow.postMessage(JSON.stringify({name:filename, data: mfAnimatedGIF.rawDataURL(), formdata: Modernizr.formdata}),"http://saveasbro.com/gif/");
        }

    }

function canicallback(data){
    $('#dropArea').html(data.html);
}
<|endoftext|>


<commit_before>// grunt-merge-data
// Copyright (c) 2013 - 2014 Shinnosuke Watanabe
// Licensed under the MIT license

module.exports = function (grunt) {
  'use strict';

  var path = require('path');

  function mergeObjects (destObj, srcObj) {
    for (var attrname in srcObj) {
      if (srcObj.hasOwnProperty(attrname)) {
        destObj[attrname] = srcObj[attrname];
      }
    }
  }

  function mergeFileData (sources) {
    var data = {};
    sources.filter(function (filePath) {
      // Warn on and remove invalid source files (if nonull was set)
      if (!grunt.file.exists(filePath)) {
        grunt.log.warn('Source file "' + filePath + '" not found.');
        return false;
      } else {
        return true;
      }

    }).forEach(function (filePath) {
      var basename = path.basename(filePath, path.extname(filePath));
      var ext = path.extname(filePath).toLowerCase();

      if(ext === '.json') {
        data[basename] = grunt.file.readJSON(filePath);
      } else if (ext === '.yml' || ext === '.yaml') {
        data[basename] = grunt.file.readYAML(filePath);
      } else {
        try {
          data[basename] = grunt.file.readJSON(filePath);
        } catch (e) {
          data[basename] = grunt.file.readYAML(filePath);
        }
      }
    });

    return data;
  }

  var mergeDataTask = function () {
    // Merge task-specific and/or target-specific options with these defaults
    var options = this.options({
      data: null,
      space: null,
      asConfig: false
    });

    // Iterate over all specified src/dest file groups
    this.files.forEach(function (file) {
      var data = mergeFileData(file.src);

      if (options.data) {
        if (grunt.util.kindOf(options.data) === 'function') {
          mergeObjects(data, options.data(data));
        } else {
          mergeObjects(data, options.data);
        }
      }

      if (options.asConfig) {
        var targetConfig;
        if (grunt.util.kindOf(options.asConfig) === 'string') {
          targetConfig = options.asConfig;

        // Accept array of property name parts
        } else if (grunt.util.kindOf(options.asConfig) === 'array') {
          targetConfig = options.asConfig.join('.');

        } else if (options.asConfig === true) {
          targetConfig = grunt.task.current.nameArgs
                         .replace(':', '.') +
                         '.context';
        }

        grunt.config(targetConfig, data);
        grunt.log.writeln('Config "' + targetConfig + '" updated.');
      }

      // Write the destination file if 'dest' is specified
      if (file.dest) {
        grunt.file.write(
          file.dest,
          JSON.stringify(data, null, options.space)
        );
        // Print a success message
        grunt.log.writeln('File "' + file.dest + '" created.');

      } else if (!options.asConfig) {
        // when the task doesn't anything
        grunt.log.warn('Neither destination path or config specified.');
      }
    });
  };

  grunt.registerMultiTask(
    'merge_data',
    'Merge multiple data into a file or Grint config.',
    mergeDataTask
  );
};
<commit_msg>remove grunt.util.kindOf<commit_after>// grunt-merge-data
// Copyright (c) 2013 - 2014 Shinnosuke Watanabe
// Licensed under the MIT license

module.exports = function (grunt) {
  'use strict';

  var path = require('path');

  function mergeObjects (destObj, srcObj) {
    for (var attrname in srcObj) {
      if (srcObj.hasOwnProperty(attrname)) {
        destObj[attrname] = srcObj[attrname];
      }
    }
  }

  function mergeFileData (sources) {
    var data = {};
    sources.filter(function (filePath) {
      // Warn on and remove invalid source files (if nonull was set)
      if (!grunt.file.exists(filePath)) {
        grunt.log.warn('Source file "' + filePath + '" not found.');
        return false;
      } else {
        return true;
      }

    }).forEach(function (filePath) {
      var basename = path.basename(filePath, path.extname(filePath));
      var ext = path.extname(filePath).toLowerCase();

      if(ext === '.json') {
        data[basename] = grunt.file.readJSON(filePath);
      } else if (ext === '.yml' || ext === '.yaml') {
        data[basename] = grunt.file.readYAML(filePath);
      } else {
        try {
          data[basename] = grunt.file.readJSON(filePath);
        } catch (e) {
          data[basename] = grunt.file.readYAML(filePath);
        }
      }
    });

    return data;
  }

  var mergeDataTask = function () {
    // Merge task-specific and/or target-specific options with these defaults
    var options = this.options({
      data: null,
      space: null,
      asConfig: false
    });

    // Iterate over all specified src/dest file groups
    this.files.forEach(function (file) {
      var data = mergeFileData(file.src);

      if (options.data) {
        if (typeof options.data === 'function') {
          mergeObjects(data, options.data(data));
        } else {
          mergeObjects(data, options.data);
        }
      }

      if (options.asConfig) {
        var targetConfig;
        if (typeof options.asConfig === 'string') {
          targetConfig = options.asConfig;

        // Accept array of property name parts
        } else if (Array.isArray(options.asConfig)) {
          targetConfig = options.asConfig.join('.');

        } else if (options.asConfig === true) {
          targetConfig = grunt.task.current.nameArgs
                           .replace(':', '.') + '.context';
        }

        grunt.config(targetConfig, data);
        grunt.log.writeln('Config "' + targetConfig + '" updated.');
      }

      // Write the destination file if 'dest' is specified
      if (file.dest) {
        grunt.file.write(
          file.dest,
          JSON.stringify(data, null, options.space)
        );
        // Print a success message
        grunt.log.writeln('File "' + file.dest + '" created.');

      } else if (!options.asConfig) {
        // when the task doesn't anything
        grunt.log.warn('Neither destination path or config specified.');
      }
    });
  };

  grunt.registerMultiTask(
    'merge_data',
    'Merge multiple data into a file or Grint config.',
    mergeDataTask
  );
};
<|endoftext|>