single param callbacks
199496
function paramCallback(err) {
                var fn = paramCallbacks[paramIndex++];
                if (err || !fn) return param(err);
                fn(req, res, paramCallback, paramVal, key.name);
            }
813289
function(name) {
      // Parse once
      if(!_data) _data = _parse(_args);

      // Fallback to defaults
      var param = _data[name] || _definition[name];

      // False for not provided
      return (!param) ? false : param.value();
    }
1153264
function(event /* params */) {

            var listeners;
            var that = this;
            var params = _.toArray(arguments).slice(1);

            listeners = this.__getEventListeners(event);

            _.each(listeners, function(listener) {
                listener.apply(that, params);
            });

            listeners = this.__getEventListeners('event.emit');

            _.each(listeners, function(listener) {
                listener.call(that, event, params);
            });

            return this;
        }
468531
function(methodDef, callback, params, payload) {
        // check required params
        for (var index in methodDef.required_params) {
            var requiredParamName = methodDef.required_params[index];
            if (!params.hasOwnProperty(requiredParamName)) {
                callback(requiredParamName +' param is required');
                return false;
            }
        }
        // check unattended params
        if (methodDef.unattended_params === false) {
            for (var param in params) {
                if (methodDef.optional_params.indexOf(param) == -1
                    && methodDef.required_params.indexOf(param) == -1) {
                    callback('unattended param '+ param);
                    return false;
                }
            }
        }
        // TODO: optional_payload is also on spore specification
        if (!payload && methodDef.required_payload === true) {
            callback("payload is required");
            return false;
        }
        return true;
    }
815893
function bindCallbacks( o, callbacks, args ) {
		var prop = QUnit.objectType( o );
		if ( prop ) {
			if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
				return callbacks[ prop ].apply( callbacks, args );
			} else {
				return callbacks[ prop ]; // or undefined
			}
		}
	}
1197997
function callee(method, href, params, opt, cb, userData){
		cb = cb || ((err)=>{
			if (err) console.error(method, href, params, opt, userData, err)
		})
		if (!href) return cb('url not defined')
		opt=opt||{}

		const urlobj = url.parse(href)
		let protocol

		switch(urlobj.protocol){
		case 'http:': protocol=http; break
		case 'https:': protocol=https; break
		default:
			if (opt.socketPath){
				protocol=http
				urlobj.protocol = 'http:'
				urlobj.socketPath = opt.socketPath
				break
			}
			fs.readFile(href, 'utf8', (err, data)=>{
				cb(err, 4, data, userData)
			}); return
		}

		const isGet = 'GET' === (urlobj.method = method.toUpperCase())
		let body = Array.isArray(params) ? pObj.extends({}, params, {tidy:1, mergeArr:1}) : params || ''

		if (isGet){
			urlobj.path += body ? '?' + qs.stringify(body) : body
			urlobj.headers = opt.headers||{}
		}else{
			urlobj.headers = Object.assign({
				'Content-Type': 'application/x-www-form-urlencoded'
			},opt.headers||{})
			switch(urlobj.headers['Content-Type']){
			case 'application/json': body = JSON.stringify(body); break
			case 'plain/text': body = body.toString(); break
			default: body = qs.stringify(body); break
			}
		}

		const req = protocol.request(urlobj, res => {
			const st=res.statusCode
			const loc=res.headers.location
			if (st>=300 && st<400 && loc) return callee(method,loc,params,opt,cb,userData)
			res.setEncoding('utf8')
			const err=(300>st || !st) ? null : {error:res.statusMessage,code:st,params:arguments}
			cb(err, 2, null, userData)
			let data = ''
			res.on('data', (chunk)=>{
				data += chunk
				cb(err, 3, data, userData)
			})
			res.on('end', ()=>{
				cb(err, 4, data, userData)
			})
		})

		req.setTimeout(opt.timeout||0, err => {
			cb({error:err.message,code:599,src:err,params:arguments}, 4, null, userData)
		})
		req.on('error', err => {
			cb({error:err.message,code:500,src:err,params:arguments}, 4, null, userData)
		})

		if (isGet) req.end()
		else req.end(body)
		return req
	}
290596
def _param_updated(self, pk):
        """"""
        if self._useV2:
            var_id = struct.unpack('<H', pk.data[:2])[0]
        else:
            var_id = pk.data[0]
        element = self.toc.get_element_by_id(var_id)
        if element:
            if self._useV2:
                s = struct.unpack(element.pytype, pk.data[2:])[0]
            else:
                s = struct.unpack(element.pytype, pk.data[1:])[0]
            s = s.__str__()
            complete_name = '%s.%s' % (element.group, element.name)

            # Save the value for synchronous access
            if element.group not in self.values:
                self.values[element.group] = {}
            self.values[element.group][element.name] = s

            logger.debug('Updated parameter [%s]' % complete_name)
            if complete_name in self.param_update_callbacks:
                self.param_update_callbacks[complete_name].call(
                    complete_name, s)
            if element.group in self.group_update_callbacks:
                self.group_update_callbacks[element.group].call(
                    complete_name, s)
            self.all_update_callback.call(complete_name, s)

            # Once all the parameters are updated call the
            # callback for "everything updated" (after all the param
            # updated callbacks)
            if self._check_if_all_updated() and not self.is_updated:
                self.is_updated = True
                self.all_updated.call()
        else:
            logger.debug('Variable id [%d] not found in TOC', var_id)
604000
def execute_callback(callback, *args)
      (callback.arity == 2 ? callback.call(*args[0, 2]) : callback.call(*args)) if callback
    end
996603
public function param( $param_name, $callback )
	{
		if( is_callable($callback) )
		{
			$this->_params[$param_name] = $callback( new request() );
		}
		else
		{
			$this->_params[$param_name] = $callback;
		}
	}
1334950
function paramCallback(err) {
    var fn = paramCallbacks[paramIndex++];

    // store updated value
    paramCalled.value = req.params[key.name];

    if (err) {
      // store error
      paramCalled.error = err;
      param(err);
      return;
    }

    if (!fn) return param();

    try {
      fn(req, res, paramCallback, paramVal, key.name);
    } catch (e) {
      paramCallback(e);
    }
  }
1350117
private function processCallback($callback, $value, $params = [])
    {
        if ($callback) {
            if (is_string($callback)) {
                $callback = [$this->parent, $callback];
            }

            array_unshift($params, $value);
            $value = call_user_func_array($callback, $params);
        }

        return $value;
    }
1140052
function params(p) {

  var result = "";
  _.each(p, function (val) {
    result = result + spliter + val;
  });

  return result;
}
881058
function callNormalizedCallback (callback, arg) {
        callback.fn.call(callback.scope, arg, callback.args);
    }
867937
function( object, callback, args ) {
		var name, i = 0, length = object.length;

		if ( args ) {
			if ( length === undefined ) {
				for ( name in object )
					if ( callback.apply( object[ name ], args ) === false )
						break;
			} else
				for ( ; i < length; )
					if ( callback.apply( object[ i++ ], args ) === false )
						break;

		// A special, fast, case for the most common use of each
		} else {
			if ( length === undefined ) {
				for ( name in object )
					if ( callback.call( object[ name ], name, object[ name ] ) === false )
						break;
			} else
				for ( var value = object[0];
					i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
		}

		return object;
	}
178722
function LocalStorage (params) {
  events.EventEmitter.call(this);

  if (!params || typeof params === 'string') {
    params = {
      ns: params || ''
    };
  }

  this.ns = params.ns || '';

  if (typeof this.ns !== 'string') {
    throw new Error('Namespace must be a string.');
  }

  this.preSave = params.preSave || defProcessor;
  this.postLoad = params.postLoad || defProcessor;

  if (this.preSave && typeof this.preSave !== 'function') {
    throw new Error('preSave option must be a function');
  }

  if (this.postLoad && typeof this.postLoad !== 'function') {
    throw new Error('postLoad option must be a function');
  }

  this.EVENTS = EVENTS;
}
223163
function(params, callback) {
      var t = this;
      if (params === '.break' && t.shellCmd) {
        t.shellCmd.kill();
      }
      if (NEW_REPL) {
        t.stream.emit('data', params + "\n");
      } else {
        t.stream.emit('data', params);
      }
      return callback(null);
    }
61928
function(params, callback) {
                var sendMessageParams = {
                        chatMessageVOType: chatMessageVOTypes.GET_HISTORY,
                        typeCode: params.typeCode,
                        content: {},
                        subjectId: params.threadId
                    },
                    whereClause = {},
                    offset = (parseInt(params.offset) > 0) ? parseInt(params.offset) : 0,
                    count = (parseInt(params.count) > 0) ? parseInt(params.count) : config.getHistoryCount,
                    order = (typeof params.order != 'undefined') ? (params.order).toLowerCase() : 'desc',
                    cacheResult = {},
                    serverResult = {},
                    cacheFirstMessage,
                    cacheLastMessage,
                    messages,
                    returnCache,
                    dynamicHistoryCount = (params.dynamicHistoryCount && typeof params.dynamicHistoryCount === 'boolean')
                        ? params.dynamicHistoryCount
                        : false,
                    sendingQueue = (params.queues && typeof params.queues.sending === 'boolean')
                        ? params.queues.sending
                        : true,
                    failedQueue = (params.queues && typeof params.queues.failed === 'boolean')
                        ? params.queues.failed
                        : true,
                    uploadingQueue = (params.queues && typeof params.queues.uploading === 'boolean')
                        ? params.queues.uploading
                        : true,
                    sendingQueueMessages = [],
                    failedQueueMessages = [],
                    uploadingQueueMessages = [];

                if (sendingQueue) {
                    getChatSendQueue(parseInt(params.threadId), function(sendQueueMessages) {
                        for (var i = 0; i < sendQueueMessages.length; i++) {
                            var decryptedEnqueuedMessage = Utility.jsonParser(chatDecrypt(sendQueueMessages[i].message, cacheSecret));
                            sendQueueMessages[i] = formatDataToMakeMessage(sendQueueMessages[i].threadId, {
                                uniqueId: decryptedEnqueuedMessage.uniqueId,
                                ownerId: userInfo.id,
                                message: decryptedEnqueuedMessage.content,
                                metadata: decryptedEnqueuedMessage.metadata,
                                systemMetadata: decryptedEnqueuedMessage.systemMetadata,
                                replyInfo: decryptedEnqueuedMessage.replyInfo,
                                forwardInfo: decryptedEnqueuedMessage.forwardInfo
                            });
                        }

                        sendingQueueMessages = sendQueueMessages;
                    });
                }

                if (uploadingQueue) {
                    getChatUploadQueue(parseInt(params.threadId), function(uploadQueueMessages) {
                        uploadingQueueMessages = uploadQueueMessages;
                    });
                }

                getChatWaitQueue(parseInt(params.threadId), failedQueue, function(waitQueueMessages) {
                    for (var i = 0; i < waitQueueMessages.length; i++) {
                        var decryptedEnqueuedMessage = Utility.jsonParser(chatDecrypt(waitQueueMessages[i].message, cacheSecret));
                        waitQueueMessages[i] = formatDataToMakeMessage(waitQueueMessages[i].threadId,
                            {
                                uniqueId: decryptedEnqueuedMessage.uniqueId,
                                ownerId: userInfo.id,
                                message: decryptedEnqueuedMessage.content,
                                metadata: decryptedEnqueuedMessage.metadata,
                                systemMetadata: decryptedEnqueuedMessage.systemMetadata,
                                replyInfo: decryptedEnqueuedMessage.replyInfo,
                                forwardInfo: decryptedEnqueuedMessage.forwardInfo
                            });
                    }

                    failedQueueMessages = waitQueueMessages;

                    if (dynamicHistoryCount) {
                        var tempCount = count - (sendingQueueMessages.length + failedQueueMessages.length + uploadingQueueMessages.length);
                        sendMessageParams.content.count = (tempCount > 0) ? tempCount : 0;
                    }
                    else {
                        sendMessageParams.content.count = count;
                    }

                    sendMessageParams.content.offset = offset;
                    sendMessageParams.content.order = order;

                    if (parseInt(params.id) > 0) {
                        sendMessageParams.content.id = whereClause.id = params.id;
                    }

                    if (Array.isArray(params.uniqueIds)) {
                        sendMessageParams.content.uniqueIds = params.uniqueIds;
                    }

                    if (parseInt(params.fromTimeFull) > 0 && params.fromTimeFull.toString().length == 19) {
                        sendMessageParams.content.fromTime = whereClause.fromTime = parseInt(params.fromTimeFull.toString()
                            .substring(0, 13));
                        sendMessageParams.content.fromTimeNanos = whereClause.fromTimeNanos = parseInt(params.fromTimeFull.toString()
                            .substring(10, 19));
                    }
                    else {
                        if (parseInt(params.fromTime) > 0 && arseInt(params.fromTime) < 9999999999999) {
                            sendMessageParams.content.fromTime = whereClause.fromTime = parseInt(params.fromTime);
                        }

                        if (parseInt(params.fromTimeNanos) > 0 && parseInt(params.fromTimeNanos) < 999999999) {
                            sendMessageParams.content.fromTimeNanos = whereClause.fromTimeNanos = parseInt(params.fromTimeNanos);
                        }
                    }

                    if (parseInt(params.toTimeFull) > 0 && params.toTimeFull.toString().length == 19) {
                        sendMessageParams.content.toTime = whereClause.toTime = parseInt(params.toTimeFull.toString()
                            .substring(0, 13));
                        sendMessageParams.content.toTimeNanos = whereClause.toTimeNanos = parseInt(params.toTimeFull.toString()
                            .substring(10, 19));
                    }
                    else {
                        if (parseInt(params.toTime) > 0 && parseInt(params.toTime) < 9999999999999) {
                            sendMessageParams.content.toTime = whereClause.toTime = parseInt(params.toTime);
                        }

                        if (parseInt(params.toTimeNanos) > 0 && parseInt(params.toTimeNanos) < 999999999) {
                            sendMessageParams.content.toTimeNanos = whereClause.toTimeNanos = parseInt(params.toTimeNanos);
                        }
                    }

                    if (typeof params.query != 'undefined') {
                        sendMessageParams.content.query = whereClause.query = params.query;
                    }

                    if (typeof params.metadataCriteria == 'object' && params.metadataCriteria.hasOwnProperty('field')) {
                        sendMessageParams.content.metadataCriteria = whereClause.metadataCriteria = params.metadataCriteria;
                    }

                    /**
                     * Get Thread Messages from cache
                     *
                     * Because we are not applying metadataCriteria search
                     * on cached data, if this attribute has been set, we
                     * should not return any results from cache
                     */
                    if (canUseCache && !whereClause.hasOwnProperty('metadataCriteria')) {
                        if (db) {
                            var table = db.messages,
                                collection;
                            returnCache = true;

                            if (whereClause.hasOwnProperty('id') && whereClause.id > 0) {
                                collection = table.where('id')
                                    .equals(params.id)
                                    .and(function(message) {
                                        return message.owner == userInfo.id;
                                    })
                                    .reverse();
                            }
                            else {
                                collection = table.where('[threadId+owner+time]')
                                    .between([parseInt(params.threadId), parseInt(userInfo.id), minIntegerValue],
                                        [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000])
                                    .reverse();
                            }

                            collection.toArray()
                                .then(function(resultMessages) {
                                    messages = resultMessages.sort(Utility.dynamicSort('time', !(order === 'asc')));

                                    if (whereClause.hasOwnProperty('fromTime')) {
                                        var fromTime = (whereClause.hasOwnProperty('fromTimeNanos'))
                                            ? (Math.floor(whereClause.fromTime / 1000) * 1000000000) + whereClause.fromTimeNanos
                                            : whereClause.fromTime * 1000000;
                                        messages = messages.filter(function(message) {
                                            return message.time >= fromTime;
                                        });
                                    }

                                    if (whereClause.hasOwnProperty('toTime')) {
                                        var toTime = (whereClause.hasOwnProperty('toTimeNanos'))
                                            ? ((Math.floor(whereClause.toTime / 1000) + 1) * 1000000000) + whereClause.toTimeNanos
                                            : (whereClause.toTime + 1) * 1000000;
                                        messages = messages.filter(function(message) {
                                            return message.time <= toTime;
                                        });
                                    }

                                    if (whereClause.hasOwnProperty('query') && typeof whereClause.query == 'string') {
                                        messages = messages.filter(function(message) {
                                            var reg = new RegExp(whereClause.query);
                                            return reg.test(chatDecrypt(message.message, cacheSecret, message.salt));
                                        });
                                    }

                                    /**
                                     * We should check to see if message[offset-1] has
                                     * GAP on cache or not? if yes, we should not return
                                     * any value from cache, because there is a gap between
                                     */
                                    if (offset > 0) {
                                        if (typeof messages[offset - 1] == 'object' && messages[offset - 1].hasGap) {
                                            returnCache = false;
                                        }
                                    }

                                    if (returnCache) {
                                        messages = messages.slice(offset, offset + count);

                                        if (messages.length == 0) {
                                            returnCache = false;
                                        }

                                        cacheFirstMessage = messages[0];
                                        cacheLastMessage = messages[messages.length - 1];

                                        if (returnCache) {
                                            collection.count()
                                                .then(function(contentCount) {
                                                    var cacheData = [];

                                                    for (var i = 0; i < messages.length; i++) {
                                                        /**
                                                         * If any of messages between first and last message of cache response
                                                         * has a GAP before them, we shouldn't return cache's result and
                                                         * wait for server's response to hit in
                                                         */
                                                        if (i != 0 && i != messages.length - 1 && messages[i].hasGap) {
                                                            returnCache = false;
                                                            break;
                                                        }

                                                        try {
                                                            var tempData = {},
                                                                salt = messages[i].salt;

                                                            var tempMessage = formatDataToMakeMessage(messages[i].threadId, JSON.parse(chatDecrypt(messages[i].data, cacheSecret, messages[i].salt)));
                                                            cacheData.push(tempMessage);

                                                            cacheResult[tempMessage.id] = {
                                                                index: i,
                                                                messageId: tempMessage.id,
                                                                threadId: tempMessage.threadId,
                                                                data: Utility.MD5(JSON.stringify([
                                                                    tempMessage.id,
                                                                    tempMessage.message,
                                                                    tempMessage.edited,
                                                                    tempMessage.delivered,
                                                                    tempMessage.seen,
                                                                    tempMessage.metadata,
                                                                    tempMessage.systemMetadata]))
                                                            };
                                                        }
                                                        catch (error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        }
                                                    }

                                                    /**
                                                     * If there is a GAP between messages of cache result
                                                     * WE should not return data from cache, cause it is not valid!
                                                     * Therefore we wait for server's response and edit cache afterwards
                                                     */
                                                    if (returnCache) {
                                                        var returnData = {
                                                            hasError: false,
                                                            cache: true,
                                                            errorCode: 0,
                                                            errorMessage: '',
                                                            result: {
                                                                history: cacheData,
                                                                contentCount: contentCount,
                                                                hasNext: (offset + count < contentCount && messages.length > 0),
                                                                nextOffset: offset + messages.length
                                                            }
                                                        };

                                                        if (sendingQueue) {
                                                            returnData.result.sending = sendingQueueMessages;
                                                        }
                                                        if (uploadingQueue) {
                                                            returnData.result.uploading = uploadingQueueMessages;
                                                        }
                                                        if (failedQueue) {
                                                            returnData.result.failed = failedQueueMessages;
                                                        }

                                                        callback && callback(returnData);
                                                        callback = undefined;
                                                    }
                                                })
                                                .catch(function(error) {
                                                    fireEvent('error', {
                                                        code: error.code,
                                                        message: error.message,
                                                        error: error
                                                    });
                                                });
                                        }
                                    }
                                })
                                .catch(function(error) {
                                    fireEvent('error', {
                                        code: error.code,
                                        message: error.message,
                                        error: error
                                    });
                                });
                        }
                        else {
                            fireEvent('error', {
                                code: 6601,
                                message: CHAT_ERRORS[6601],
                                error: null
                            });
                        }
                    }

                    /**
                     * Get Thread Messages From Server
                     */
                    return sendMessage(sendMessageParams, {
                        onResult: function(result) {
                            var returnData = {
                                    hasError: result.hasError,
                                    cache: false,
                                    errorMessage: result.errorMessage,
                                    errorCode: result.errorCode
                                },
                                resultMessagesId = [];

                            if (!returnData.hasError) {
                                var messageContent = result.result,
                                    messageLength = messageContent.length;

                                var history = reformatThreadHistory(params.threadId, messageContent);

                                if (messageLength > 0) {
                                    /**
                                     * Calculating First and Last Messages of result
                                     */
                                    var lastMessage = history[messageContent.length - 1],
                                        firstMessage = history[0];

                                    /**
                                     * Sending Delivery for Last Message of Thread
                                     */
                                    if (lastMessage.id > 0) {
                                        deliver({
                                            messageId: lastMessage.id,
                                            ownerId: lastMessage.participant.id
                                        });
                                    }
                                }

                                /**
                                 * Add Thread Messages into cache database
                                 * and remove deleted messages from cache database
                                 */
                                if (canUseCache) {
                                    if (db) {

                                        /**
                                         * Cache Synchronization
                                         *
                                         * If there are some results in cache
                                         * Database, we have to check if they need
                                         * to be deleted or not?
                                         *
                                         * To do so, first of all we should make
                                         * sure that metadataCriteria has not been
                                         * set, cuz we are not applying it on the
                                         * cache results, besides the results from
                                         * cache should not be empty, otherwise
                                         * there is no need to sync cache
                                         */
                                        if (Object.keys(cacheResult).length > 0 && !whereClause.hasOwnProperty('metadataCriteria')) {

                                            /**
                                             * Check if a condition has been
                                             * applied on query or not, if there is
                                             * none, the only limitations on
                                             * results are count and offset
                                             *
                                             * whereClause == []
                                             */
                                            if (!whereClause || Object.keys(whereClause).length == 0) {

                                                /**
                                                 * There is no condition applied on
                                                 * query and result is [], so there
                                                 * are no messages in this thread
                                                 * after this offset, and we should
                                                 * delete those messages from cache
                                                 * too
                                                 *
                                                 * result   []
                                                 */
                                                if (messageLength == 0) {

                                                    /**
                                                     * Order is ASC, so if the server result is empty we
                                                     * should delete everything from cache which has bigger
                                                     * time than first item of cache results for this query
                                                     */
                                                    if (order == 'asc') {
                                                        var finalMessageTime = cacheFirstMessage.time;

                                                        db.messages.where('[threadId+owner+time]')
                                                            .between([parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime],
                                                                [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000], true, false)
                                                            .delete()
                                                            .catch(function(error) {
                                                                fireEvent('error', {
                                                                    code: error.code,
                                                                    message: error.message,
                                                                    error: error
                                                                });
                                                            });
                                                    }

                                                    /**
                                                     * Order is DESC, so if the
                                                     * server result is empty we
                                                     * should delete everything
                                                     * from cache which has smaller
                                                     * time than first item of
                                                     * cache results for this query
                                                     */
                                                    else {
                                                        var finalMessageTime = cacheFirstMessage.time;

                                                        db.messages.where('[threadId+owner+time]')
                                                            .between([parseInt(params.threadId), parseInt(userInfo.id), 0],
                                                                [parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime], true, true)
                                                            .delete()
                                                            .catch(function(error) {
                                                                fireEvent('error', {
                                                                    code: error.code,
                                                                    message: error.message,
                                                                    error: error
                                                                });
                                                            });
                                                    }
                                                }

                                                /**
                                                 * Result is not Empty or doesn't
                                                 * have just one single record, so
                                                 * we should remove everything
                                                 * which are between firstMessage
                                                 * and lastMessage of this result
                                                 * from cache database and insert
                                                 * the new result into cache, so
                                                 * the deleted ones would be
                                                 * deleted
                                                 *
                                                 * result   [..., n-1, n, n+1, ...]
                                                 */
                                                else {

                                                    /**
                                                     * We should check for last message's previouseId if it
                                                     * is undefined, so it is the first message of thread and
                                                     * we should delete everything before it from cache
                                                     */
                                                    if (firstMessage.previousId == undefined || lastMessage.previousId == undefined) {
                                                        var finalMessageTime = (lastMessage.previousId == undefined)
                                                            ? lastMessage.time
                                                            : firstMessage.time;

                                                        db.messages.where('[threadId+owner+time]')
                                                            .between([parseInt(params.threadId), parseInt(userInfo.id), 0],
                                                                [parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime], true, false)
                                                            .delete()
                                                            .catch(function(error) {
                                                                fireEvent('error', {
                                                                    code: error.code,
                                                                    message: error.message,
                                                                    error: error
                                                                });
                                                            });
                                                    }

                                                    /**
                                                     * Offset has been set as 0 so this result is either the
                                                     * very beginning part of thread or the very last
                                                     * Depending on the sort order
                                                     *
                                                     * offset == 0
                                                     */
                                                    if (offset == 0) {

                                                        /**
                                                         * Results are sorted ASC, and the offset is 0 so
                                                         * the first Message of this result is first
                                                         * Message of thread, everything in cache
                                                         * database which has smaller time than this
                                                         * one should be removed
                                                         *
                                                         * order    ASC
                                                         * result   [0, 1, 2, ...]
                                                         */
                                                        if (order === 'asc') {
                                                            var finalMessageTime = firstMessage.time;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), 0],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime], true, false)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }

                                                        /**
                                                         * Results are sorted DESC and the offset is 0 so
                                                         * the last Message of this result is the last
                                                         * Message of the thread, everything in cache
                                                         * database which has bigger time than this
                                                         * one should be removed from cache
                                                         *
                                                         * order    DESC
                                                         * result   [..., n-2, n-1, n]
                                                         */
                                                        else {
                                                            var finalMessageTime = firstMessage.time;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000], false, true)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }
                                                    }

                                                    /**
                                                     * Server result is not Empty, so we should remove
                                                     * everything which are between firstMessage and lastMessage
                                                     * of this result from cache database and insert the new
                                                     * result into cache, so the deleted ones would be deleted
                                                     *
                                                     * result   [..., n-1, n, n+1, ...]
                                                     */
                                                    var boundryStartMessageTime = (firstMessage.time < lastMessage.time)
                                                            ? firstMessage.time
                                                            : lastMessage.time,
                                                        boundryEndMessageTime = (firstMessage.time > lastMessage.time)
                                                            ? firstMessage.time
                                                            : lastMessage.time;

                                                    db.messages.where('[threadId+owner+time]')
                                                        .between([parseInt(params.threadId), parseInt(userInfo.id), boundryStartMessageTime],
                                                            [parseInt(params.threadId), parseInt(userInfo.id), boundryEndMessageTime], true, true)
                                                        .delete()
                                                        .catch(function(error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        });
                                                }
                                            }

                                            /**
                                             * whereClasue is not empty and we
                                             * should check for every single one of
                                             * the conditions to update the cache
                                             * properly
                                             *
                                             * whereClause != []
                                             */
                                            else {

                                                /**
                                                 * When user ordered a message with
                                                 * exact ID and server returns []
                                                 * but there is something in cache
                                                 * database, we should delete that
                                                 * row from cache, because it has
                                                 * been deleted
                                                 */
                                                if (whereClause.hasOwnProperty('id') && whereClause.id > 0) {
                                                    db.messages.where('id')
                                                        .equals(whereClause.id)
                                                        .and(function(message) {
                                                            return message.owner == userInfo.id;
                                                        })
                                                        .delete()
                                                        .catch(function(error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        });
                                                }

                                                /**
                                                 * When user sets a query to search
                                                 * on messages we should delete all
                                                 * the results came from cache and
                                                 * insert new results instead,
                                                 * because those messages would be
                                                 * either removed or updated
                                                 */
                                                if (whereClause.hasOwnProperty('query') && typeof whereClause.query == 'string') {
                                                    db.messages.where('[threadId+owner+time]')
                                                        .between([parseInt(params.threadId), parseInt(userInfo.id), minIntegerValue],
                                                            [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000])
                                                        .and(function(message) {
                                                            var reg = new RegExp(whereClause.query);
                                                            return reg.test(chatDecrypt(message.message, cacheSecret, message.salt));
                                                        })
                                                        .delete()
                                                        .catch(function(error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        });
                                                }

                                                /**
                                                 * Users sets fromTime or toTime or
                                                 * both of them
                                                 */
                                                if (whereClause.hasOwnProperty('fromTime') || whereClause.hasOwnProperty('toTime')) {

                                                    /**
                                                     * Server response is Empty []
                                                     */
                                                    if (messageLength == 0) {

                                                        /**
                                                         * User set both fromTime and toTime, so we have a
                                                         * boundary restriction in this case. if server
                                                         * result is empty, we should delete all messages from cache
                                                         * which are between fromTime and toTime. if
                                                         * there are any messages on server in this
                                                         * boundary, we should delete all messages
                                                         * which are between time of first and last
                                                         * message of the server result, from cache and
                                                         * insert new result into cache.
                                                         */
                                                        if (whereClause.hasOwnProperty('fromTime') && whereClause.hasOwnProperty('toTime')) {

                                                            /**
                                                             * Server response is Empty []
                                                             */
                                                            var fromTime = (whereClause.hasOwnProperty('fromTimeNanos'))
                                                                    ? ((whereClause.fromTime / 1000) * 1000000000) + whereClause.fromTimeNanos
                                                                    : whereClause.fromTime * 1000000,
                                                                toTime = (whereClause.hasOwnProperty('toTimeNanos'))
                                                                    ? (((whereClause.toTime / 1000) + 1) * 1000000000) + whereClause.toTimeNanos
                                                                    : (whereClause.toTime + 1) * 1000000;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), fromTime],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), toTime], true, true)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }

                                                        /**
                                                         * User only set fromTime
                                                         */
                                                        else if (whereClause.hasOwnProperty('fromTime')) {

                                                            /**
                                                             * Server response is Empty []
                                                             */
                                                            var fromTime = (whereClause.hasOwnProperty('fromTimeNanos'))
                                                                ? ((whereClause.fromTime / 1000) * 1000000000) + whereClause.fromTimeNanos
                                                                : whereClause.fromTime * 1000000;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), fromTime],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000], true, false)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }

                                                        /**
                                                         * User only set toTime
                                                         */
                                                        else {

                                                            /**
                                                             * Server response is Empty []
                                                             */
                                                            var toTime = (whereClause.hasOwnProperty('toTimeNanos'))
                                                                ? (((whereClause.toTime / 1000) + 1) * 1000000000) + whereClause.toTimeNanos
                                                                : (whereClause.toTime + 1) * 1000000;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), minIntegerValue],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), toTime], true, true)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }
                                                    }

                                                    /**
                                                     * Server response is not Empty
                                                     * [..., n-1, n, n+1, ...]
                                                     */
                                                    else {

                                                        /**
                                                         * Server response is not Empty
                                                         * [..., n-1, n, n+1, ...]
                                                         */
                                                        var boundryStartMessageTime = (firstMessage.time < lastMessage.time)
                                                                ? firstMessage.time
                                                                : lastMessage.time,
                                                            boundryEndMessageTime = (firstMessage.time > lastMessage.time)
                                                                ? firstMessage.time
                                                                : lastMessage.time;

                                                        db.messages.where('[threadId+owner+time]')
                                                            .between([parseInt(params.threadId), parseInt(userInfo.id), boundryStartMessageTime],
                                                                [parseInt(params.threadId), parseInt(userInfo.id), boundryEndMessageTime], true, true)
                                                            .delete()
                                                            .catch(function(error) {
                                                                fireEvent('error', {
                                                                    code: error.code,
                                                                    message: error.message,
                                                                    error: error
                                                                });
                                                            });
                                                    }
                                                }
                                            }
                                        }

                                        /**
                                         * Insert new messages into cache database
                                         * after deleting old messages from cache
                                         */
                                        var cacheData = [];

                                        for (var i = 0; i < history.length; i++) {
                                            serverResult[history[i].id] = {
                                                index: i,
                                                data: Utility.MD5(JSON.stringify([
                                                    history[i].id,
                                                    history[i].message,
                                                    history[i].edited,
                                                    history[i].delivered,
                                                    history[i].seen,
                                                    history[i].metadata,
                                                    history[i].systemMetadata]))
                                            };
                                            try {
                                                var tempData = {},
                                                    salt = Utility.generateUUID();
                                                tempData.id = parseInt(history[i].id);
                                                tempData.owner = parseInt(userInfo.id);
                                                tempData.threadId = parseInt(history[i].threadId);
                                                tempData.time = history[i].time;
                                                tempData.message = Utility.crypt(history[i].message, cacheSecret, salt);
                                                tempData.data = Utility.crypt(JSON.stringify(unsetNotSeenDuration(history[i])), cacheSecret, salt);
                                                tempData.salt = salt;
                                                tempData.sendStatus = 'sent';
                                                tempData.hasGap = false;

                                                cacheData.push(tempData);
                                                resultMessagesId.push(history[i].id);
                                            }
                                            catch (error) {
                                                fireEvent('error', {
                                                    code: error.code,
                                                    message: error.message,
                                                    error: error
                                                });
                                            }
                                        }

                                        db.messages.bulkPut(cacheData)
                                            .then(function() {
                                                if (lastMessage.id > 0 && lastMessage.previousId > 0) {
                                                    /**
                                                     * Check to see if there is a Gap in cache before
                                                     * lastMessage or not?
                                                     * To do this, we should check existence of message
                                                     * with the ID of lastMessage's previousId field
                                                     */
                                                    db.messages
                                                        .where('[owner+id]')
                                                        .between([userInfo.id, lastMessage.previousId], [userInfo.id, lastMessage.previousId], true, true)
                                                        .toArray()
                                                        .then(function(messages) {
                                                            if (messages.length == 0) {
                                                                /**
                                                                 * Previous Message of last message is not in cache database
                                                                 * so there is a GAP in cache database for this thread before
                                                                 * the last message.
                                                                 * We should insert this GAP in messageGaps database
                                                                 */
                                                                db.messageGaps
                                                                    .put({
                                                                        id: parseInt(lastMessage.id),
                                                                        owner: parseInt(userInfo.id),
                                                                        waitsFor: parseInt(lastMessage.previousId),
                                                                        threadId: parseInt(lastMessage.threadId),
                                                                        time: lastMessage.time
                                                                    })
                                                                    .then(function() {
                                                                        db.messages
                                                                            .update([userInfo.id, lastMessage.id], {hasGap: true})
                                                                            .catch(function(error) {
                                                                                fireEvent('error', {
                                                                                    code: error.code,
                                                                                    message: error.message,
                                                                                    error: error
                                                                                });
                                                                            });
                                                                    })
                                                                    .catch(function(error) {
                                                                        fireEvent('error', {
                                                                            code: error.code,
                                                                            message: error.message,
                                                                            error: error
                                                                        });
                                                                    });
                                                            }
                                                        })
                                                        .catch(function(error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        });
                                                }

                                                /**
                                                 * Some new messages have been added into cache,
                                                 * We should check to see if any GAPs have been
                                                 * filled with these messages or not?
                                                 */
                                                db.messageGaps
                                                    .where('waitsFor')
                                                    .anyOf(resultMessagesId)
                                                    .and(function(messages) {
                                                        return messages.owner == userInfo.id;
                                                    })
                                                    .delete()
                                                    .catch(function(error) {
                                                        fireEvent('error', {
                                                            code: error.code,
                                                            message: error.message,
                                                            error: error
                                                        });
                                                    });
                                            })
                                            .catch(function(error) {
                                                fireEvent('error', {
                                                    code: error.code,
                                                    message: error.message,
                                                    error: error
                                                });
                                            });
                                    }
                                    else {
                                        fireEvent('error', {
                                            code: 6601,
                                            message: CHAT_ERRORS[6601],
                                            error: null
                                        });
                                    }
                                }

                                var resultData = {
                                    history: history,
                                    contentCount: result.contentCount,
                                    hasNext: (sendMessageParams.content.offset + sendMessageParams.content.count < result.contentCount && messageLength > 0),
                                    nextOffset: sendMessageParams.content.offset + messageLength
                                };

                                returnData.result = resultData;

                                if (sendingQueue) {
                                    returnData.result.sending = sendingQueueMessages;
                                }
                                if (uploadingQueue) {
                                    returnData.result.uploading = uploadingQueueMessages;
                                }
                                if (failedQueue) {
                                    returnData.result.failed = failedQueueMessages;
                                }

                                /**
                                 * Check Differences between Cache and Server response
                                 */
                                if (returnCache) {
                                    /**
                                     * If there are some messages in cache but they
                                     * are not in server's response, we can assume
                                     * that they have been removed from server, so
                                     * we should call MESSAGE_DELETE event for them
                                     */
                                    for (var key in cacheResult) {
                                        if (!serverResult.hasOwnProperty(key)) {
                                            fireEvent('messageEvents', {
                                                type: 'MESSAGE_DELETE',
                                                result: {
                                                    message: {
                                                        id: cacheResult[key].messageId,
                                                        threadId: cacheResult[key].threadId
                                                    }
                                                }
                                            });
                                        }
                                    }

                                    for (var key in serverResult) {
                                        if (cacheResult.hasOwnProperty(key)) {
                                            /**
                                             * Check digest of cache and server response, if
                                             * they are not the same, we should emit
                                             */
                                            if (cacheResult[key].data != serverResult[key].data) {

                                                /**
                                                 * This message is already on cache, but it's
                                                 * content has been changed, so we emit a
                                                 * message edit event to inform client
                                                 */
                                                fireEvent('messageEvents', {
                                                    type: 'MESSAGE_EDIT',
                                                    result: {
                                                        message: history[serverResult[key].index]
                                                    }
                                                });
                                            }
                                        }
                                        else {
                                            /**
                                             * This Message has not found on cache but it has
                                             * came from server, so we emit it as a new message
                                             */
                                            fireEvent('messageEvents', {
                                                type: 'MESSAGE_NEW',
                                                result: {
                                                    message: history[serverResult[key].index]
                                                }
                                            });
                                        }
                                    }
                                }
                                else {
                                    callback && callback(returnData);
                                    callback = undefined;
                                }
                            }
                        }
                    });
                });
            }