TODO: update hod client to use Java8 time
776326
private DateTime zonedDateTimeToJodaTime(final ChronoZonedDateTime<?> date) {
        return date == null ? null : new DateTime(date.toInstant().toEpochMilli(), DateTimeZone.UTC);
    }
811340
private void marshalUpdatedTimestamp() {
    PropertyMetadata updatedTimestampMetadata = entityMetadata.getUpdatedTimestampMetadata();
    if (updatedTimestampMetadata != null) {
      applyAutoTimestamp(updatedTimestampMetadata, System.currentTimeMillis());
    }
  }
1319159
function IbtRealTimeSJ() {

    /***********************************************************
    * @attributes
    ***********************************************************/

    var appKey;                     // application key
    var authToken;                  // authentication token
    var clusterUrl;                 // cluster URL to connect
    var waitingClusterResponse;     // indicates whether is waiting for a cluster response
    var connectionTimeout;          // connection timeout in milliseconds
    var messageMaxSize;             // message maximum size in bytes
    var channelMaxSize;             // channel maximum size in bytes
    var channelsMaxSize             // maximum of channels for batchSend
    var messagesBuffer;             // buffer to hold the message parts
    var id;                         // object identifier
    var isConnected;                // indicates whether the client object is connected
    var isConnecting;               // indicates whether the client object is connecting
    var alreadyConnectedFirstTime;  // indicates whether the client already connected for the first time
    var stopReconnecting;           // indicates whether the user disconnected (stop the reconnecting proccess)
    var ortc;                       // represents the object itself
    var sockjs;                     // socket connected to
    var url;                        // URL to connect
    var userPerms;                  // user permissions
    var connectionMetadata;         // connection metadata used to identify the client
    var announcementSubChannel;     // announcement subchannel
    var subscribedChannels;         // subscribed/subscribing channels
    var lastKeepAlive;              // holds the time of the last keep alive received
    var invalidConnection;          // indicates whether the connection is valid
    var reconnectIntervalId;        // id used for the reconnect interval
    var reconnectStartedAt;         // the time which the reconnect started
    var validatedTimeoutId;         // id used for the validated timeout
    var validatedArrived;           // indicates whether the validated message arrived
    var retryingWithSsl;            // indicates whether the connection is being retried with SSL
    var protocol;                   // protocol to use
    var sslSessionCookieName;       // the SSL session cookie name
    var sessionCookieName;          // the session cookie name
    var sessionId;                  // the session ID
    var registrationId;             // browser device token for push notifications
    var pushPlatform;                   // push notifications platform
    var pendingPublishMessages;     // hash with the messages pending publish acknowledge from server
    var publishTimeout;             // Publish method timeout in miliseconds

    /***********************************************************
    * @attributes initialization
    ***********************************************************/

    sslSessionCookieName = 'ortcssl';
    sessionCookieName = 'ortcsession-';

    connectionTimeout = 5000;
    messageMaxSize = 800;
    channelMaxSize = 100;
    connectionMetadataMaxSize = 256;
    channelsMaxSize=50;

    // Time in seconds
    var heartbeatDefaultTime = 15; // Heartbeat default interval time
    var heartbeatDefaultFails = 3; // Heartbeat default max fails

    var heartbeatMaxTime = 60;
    var heartbeatMinTime = 10;

    var heartbeatMaxFails = 6;
    var heartbeatMinFails = 1;

    var heartbeatTime = heartbeatDefaultTime; // Heartbeat interval time
    var heartbeatFails = heartbeatDefaultFails; // Heartbeat max fails

    var heartbeatInterval = null; // Heartbeat interval

    var heartbeatActive = false;

    messagesBuffer = {};
    subscribedChannels = {};
    pendingPublishMessages = {};

    isConnected = false;
    isConnecting = false;
    alreadyConnectedFirstTime = false;
    invalidConnection = false;
    waitingClusterResponse = false;
    validatedArrived = false;
    retryingWithSsl = false;

    ortc = this;
    lastKeepAlive = null;
    userPerms = null;
    reconnectStartedAt = null;

    protocol = undefined;
    pushPlatform = 'GCM';

    publishTimeout = 5000;


    /***********************************************************
    * @properties
    ***********************************************************/

    this.getId = function () { return id; };
    this.setId = function (newId) { id = newId; };

    this.getUrl = function () { return url; };
    this.setUrl = function (newUrl) { url = newUrl; clusterUrl = null; };

    this.getClusterUrl = function () { return clusterUrl; };
    this.setClusterUrl = function (newUrl) { clusterUrl = newUrl; url = null; };

    this.getConnectionTimeout = function () { return connectionTimeout; };
    this.setConnectionTimeout = function (newTimeout) { connectionTimeout = newTimeout; };

    this.getIsConnected = function () { return isConnected && ortc.sockjs != null; };

    this.getConnectionMetadata = function () { return connectionMetadata; };
    this.setConnectionMetadata = function (newConnectionMetadata) { connectionMetadata = newConnectionMetadata; };

    this.getAnnouncementSubChannel = function () { return announcementSubChannel; };
    this.setAnnouncementSubChannel = function (newAnnouncementSubChannel) { announcementSubChannel = newAnnouncementSubChannel; };

    this.getProtocol = function () { return protocol; };
    this.setProtocol = function (newProtocol) { protocol = newProtocol; };

    this.getSessionId = function () { return sessionId; };

    /*
    *  Get heartbeat interval.
    */
    this.getHeartbeatTime = function () { return heartbeatTime; };

    /*
    *  Set heartbeat interval.
    */
    this.setHeartbeatTime = function (newHeartbeatTime) {
        if(newHeartbeatTime && !isNaN(newHeartbeatTime)){
            if(newHeartbeatTime > heartbeatMaxTime || newHeartbeatTime < heartbeatMinTime){
                delegateExceptionCallback(ortc, 'Heartbeat time is out of limits - Min: ' + heartbeatMinTime + ' | Max: ' + heartbeatMaxTime);
            }else{
                heartbeatTime = newHeartbeatTime;
            }
        }else{
            delegateExceptionCallback(ortc, 'Invalid heartbeat time ' + newHeartbeatTime);
        }
    };

    /*
    * Get how many times can the client fail the heartbeat.
    */
    this.getHeartbeatFails = function () { return heartbeatFails; };

    /*
    * Set heartbeat fails. Defines how many times can the client fail the heartbeat.
    */
    this.setHeartbeatFails = function (newHeartbeatFails) {
        if(newHeartbeatFails && !isNaN(newHeartbeatFails)){
            if(newHeartbeatFails > heartbeatMaxFails || newHeartbeatFails < heartbeatMinFails){
                delegateExceptionCallback(ortc, 'Heartbeat fails is out of limits - Min: ' + heartbeatMinFails + ' | Max: ' + heartbeatMaxFails);
            }else{
                heartbeatFails = newHeartbeatFails;
            }
        }else{
            delegateExceptionCallback(ortc, 'Invalid heartbeat fails ' + newHeartbeatFails);
        }
    };

    /*
    * Get heart beat active.
    */
    this.getHeartbeatActive = function(){
        return heartbeatActive;
    }

    /*
    * Set heart beat active. Heart beat provides better accuracy for presence data.
    */
    this.setHeartbeatActive = function(active){
        heartbeatActive = active;
    }

    this.getPublishTimeout = function () { return publishTimeout; };
    this.setPublishTimeout = function (newTimeout) { publishTimeout = newTimeout; };

    /***********************************************************
    * @events
    ***********************************************************/

    this.onConnected = null;
    this.onDisconnected = null;
    this.onSubscribed = null;
    this.onUnsubscribed = null;
    this.onException = null;
    this.onReconnecting = null;
    this.onReconnected = null;

    /***********************************************************
    * @public methods
    ***********************************************************/

    /*
    * Connects to the gateway with the application key and authentication token.
    */
    this.connect = function (appKey, authToken) {
        /*
        Sanity Checks
        */
        if (isConnected) {
            delegateExceptionCallback(ortc, 'Already connected');
        }
        else if (!url && !clusterUrl) {
            delegateExceptionCallback(ortc, 'URL and Cluster URL are null or empty');
        }
        else if (!appKey) {
            delegateExceptionCallback(ortc, 'Application Key is null or empty');
        }
        else if (!authToken) {
            delegateExceptionCallback(ortc, 'Authentication Token is null or empty');
        }
        else if (url && !ortcIsValidUrl(url)) {
            delegateExceptionCallback(ortc, 'Invalid URL');
        }
        else if (clusterUrl && !ortcIsValidUrl(clusterUrl)) {
            delegateExceptionCallback(ortc, 'Invalid Cluster URL');
        }
        else if (!ortcIsValidInput(appKey)) {
            delegateExceptionCallback(ortc, 'Application Key has invalid characters');
        }
        else if (!ortcIsValidInput(authToken)) {
            delegateExceptionCallback(ortc, 'Authentication Token has invalid characters');
        }
        else if (!ortcIsValidInput(announcementSubChannel)) {
            delegateExceptionCallback(ortc, 'Announcement Subchannel has invalid characters');
        }
        else if (connectionMetadata && connectionMetadata.length > connectionMetadataMaxSize) {
            delegateExceptionCallback(ortc, 'Connection metadata size exceeds the limit of ' + connectionMetadataMaxSize + ' characters');
        }
        else {
            ortc.appKey = appKey;
            ortc.authToken = authToken;

            isConnecting = true;
            stopReconnecting = false;
            validatedArrived = false;

            clearValidatedTimeout(self);

            // Read SSL session cookie
            //var sslConn = readCookie(sslSessionCookieName);
            var sslConn = false;

            if (sslConn) {
                changeUrlSsl();
            }

            if (clusterUrl && clusterUrl != null) {
                clusterUrl = clusterUrl.ortcTreatUrl();
                clusterConnection();
            }
            else {
                url = url.ortcTreatUrl();

                ortc.sockjs = createSocketConnection(url);
            }

            //If ssl connection increase connection timeout
            if ((clusterUrl && clusterUrl != null && (clusterUrl.indexOf('/ssl') >= 0)) || (url && (url.indexOf('https') >= 0))) {
                if(!retryingWithSsl){
                    ortc.setConnectionTimeout(30 * 1000);
                }else{
                    if(ortc.getConnectionTimeout() < 300 * 1000){
                        if(ortc.getConnectionTimeout() < 30 * 1000){
                            ortc.setConnectionTimeout(30 * 1000);
                        }else{
                            ortc.setConnectionTimeout((ortc.getConnectionTimeout() + 10) * 1000);
                        }
                    }else{
                        stopReconnecting = true;
                        clearReconnectInterval();
                    }
                }
            }

            if (!ortc.reconnectIntervalId && !stopReconnecting) {
                // Interval to reconnect
                ortc.reconnectIntervalId = setInterval(function () {
                    if (stopReconnecting) {
                        clearReconnectInterval();
                    }
                    else {
                        var currentDateTime = new Date();

                        if (ortc.sockjs == null && !waitingClusterResponse) {
                            reconnectSocket();
                        }

                        // 35 seconds
                        if (lastKeepAlive != null && (lastKeepAlive + 35000 < new Date().getTime())) {
                            lastKeepAlive = null;

                            // Server went down
                            if (isConnected) {
                                disconnectSocket();
                            }
                        }
                    }
                }, ortc.getConnectionTimeout());
            }
        }
    };


    this.setNotificationConfig = function(config){
        config.cmd = 'config';
        this.sendMessageToServiceWorker(config);
    };

    this.showNotification = function(notification){
        notification.cmd = 'notification';
        this.sendMessageToServiceWorker(notification);
    };

    this.sendMessageToServiceWorker = function(message) {
        return new Promise(function(resolve, reject) {
          var messageChannel = new MessageChannel();
          messageChannel.port1.onmessage = function(event) {
            if (event.data.error) {
              reject(event.data.error);
            } else {
              resolve(event.data);
            }
          };
          navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
        });
    }




    /*
    * Subscribes to the channel so the client object can receive all messages sent to it by other clients with Notifications.
    */
    this.subscribeWithNotifications = function(channel, subscribeOnReconnected, regId, onMessageCallback){
        ortc.registrationId = regId;
        this._subscribe(channel, subscribeOnReconnected, regId, null, onMessageCallback);        
    }

    /*
    * Subscribes to the channel so the client object can receive all messages sent that are valid according to the given filter
    */
    this.subscribeWithFilter = function(channel, subscribeOnReconnected, filter, onMessageCallback){
        this._subscribe(channel, subscribeOnReconnected, null, filter, onMessageCallback);        
    }

    /*
    * Subscribes to the channel so the client object can receive all messages sent to it by other clients.
    */
    this.subscribe = function (channel, subscribeOnReconnected, onMessageCallback){
        this._subscribe(channel, subscribeOnReconnected, null, null, onMessageCallback);
    };

    /*
    * Subscribes to the channel using at-least-once delivery mode (buffered messages)
    */
    this.subscribeWithBuffer = function(channel, subscriberId, onMessageWithBufferCallback){
        if(subscriberId) {
            var options = {
                channel: channel,
                subscribeOnReconnected: true,
                subscriberId: subscriberId
            }

            this.subscribeWithOptions(options, function(ortc, msgOptions) {
                onMessageWithBufferCallback(ortc, msgOptions.channel, msgOptions.seqId, msgOptions.message);
            });
        } else {
            delegateExceptionCallback(ortc, 'subscribeWithBuffer called with no subscriberId');
        }        
    }

    /*
    * Subscribes to the channel with multiple options
    */
    this.subscribeWithOptions = function (options, onMessageWithOptionsCallback){
        if(options) {
            this._subscribeOptions(options.channel, options.subscribeOnReconnected, options.regId, options.filter, options.subscriberId, onMessageWithOptionsCallback);
        } else {
            delegateExceptionCallback(ortc, 'subscribeWithOptions called with no options');
        }
    };


    this._subscribe = function(channel, subscribeOnReconnected, regId, filter, onMessageCallback) {
        /*
        Sanity Checks
        */
        if (!isConnected) {
            delegateExceptionCallback(ortc, 'Not connected');
        }
        else if (!channel) {
            delegateExceptionCallback(ortc, 'Channel is null or empty');
        }
        else if (!ortcIsValidInput(channel)) {
            delegateExceptionCallback(ortc, 'Channel has invalid characters');
        }
        else if (subscribedChannels[channel] && subscribedChannels[channel].isSubscribing) {
            delegateExceptionCallback(ortc, 'Already subscribing to the channel \'' + channel + '\'');
        }
        else if (subscribedChannels[channel] && subscribedChannels[channel].isSubscribed) {
            delegateExceptionCallback(ortc, 'Already subscribed to the channel \'' + channel + '\'');
        }
        else if (channel.length > channelMaxSize) {
            delegateExceptionCallback(ortc, 'Channel size exceeds the limit of ' + channelMaxSize + ' characters');
        }
        else if (!ortcIsValidBoolean(subscribeOnReconnected)) {
            delegateExceptionCallback(ortc, 'The argument \'subscribeOnReconnected\' must be a boolean');
        }
        else if (!ortcIsFunction(onMessageCallback)) {
            delegateExceptionCallback(ortc, 'The argument \'onMessageCallback\' must be a function');
        }
        else {
            if (ortc.sockjs != null) {
                var domainChannelCharacterIndex = channel.indexOf(':');
                var channelToValidate = channel;
                var hashPerm = null;

                if (domainChannelCharacterIndex > 0) {
                    channelToValidate = channel.substring(0, domainChannelCharacterIndex + 1) + '*';
                }

                if (userPerms && userPerms != null) {
                    hashPerm = userPerms[channelToValidate] ? userPerms[channelToValidate] : userPerms[channel];
                }

                if (userPerms && userPerms != null && !hashPerm) {
                    delegateExceptionCallback(ortc, 'No permission found to subscribe to the channel \'' + channel + '\'');
                }
                else {
                    if (subscribedChannels[channel]) {
                        subscribedChannels[channel].isSubscribing = true;
                        subscribedChannels[channel].isSubscribed = false;
                        subscribedChannels[channel].subscribeOnReconnected = subscribeOnReconnected;
                        subscribedChannels[channel].onMessageCallback = onMessageCallback;
                        subscribedChannels[channel].filter = filter;
                    }
                    else {
                        subscribedChannels[channel] = { 'isSubscribing': true, 'isSubscribed': false, 'subscribeOnReconnected': subscribeOnReconnected, 'onMessageCallback': onMessageCallback, 'filter': filter };
                    }
                    if (regId) {
                        subscribedChannels[channel].withNotifications = true;
                        ortc.sockjs.send('subscribe;' + ortc.appKey + ';' + ortc.authToken + ';' + channel + ';' + hashPerm  + ';' + regId + ';' + pushPlatform);
                    }else{
                        subscribedChannels[channel].withNotifications = false;

                        if(filter) {
                            ortc.sockjs.send('subscribefilter;' + ortc.appKey + ';' + ortc.authToken + ';' + channel + ';' + hashPerm + ';' + filter);
                        } else {
                            ortc.sockjs.send('subscribe;' + ortc.appKey + ';' + ortc.authToken + ';' + channel + ';' + hashPerm);
                        }
                    }
                }
            }
        }
    };

    this._subscribeOptions = function(channel, subscribeOnReconnected, regId, filter, subscriberId, onMessageCallback) {
        /*
        Sanity Checks
        */
        if (!isConnected) {
            delegateExceptionCallback(ortc, 'Not connected');
        }
        else if (!channel) {
            delegateExceptionCallback(ortc, 'Channel is null or empty');
        }
        else if (!ortcIsValidInput(channel)) {
            delegateExceptionCallback(ortc, 'Channel has invalid characters');
        }
        else if (!ortcIsValidInput(subscriberId)) {
            delegateExceptionCallback(ortc, 'subscriberId has invalid characters');
        }
        else if (subscribedChannels[channel] && subscribedChannels[channel].isSubscribing) {
            delegateExceptionCallback(ortc, 'Already subscribing to the channel \'' + channel + '\'');
        }
        else if (subscribedChannels[channel] && subscribedChannels[channel].isSubscribed) {
            delegateExceptionCallback(ortc, 'Already subscribed to the channel \'' + channel + '\'');
        }
        else if (channel.length > channelMaxSize) {
            delegateExceptionCallback(ortc, 'Channel size exceeds the limit of ' + channelMaxSize + ' characters');
        }
        else if (!ortcIsFunction(onMessageCallback)) {
            delegateExceptionCallback(ortc, 'The argument \'onMessageCallback\' must be a function');
        }
        else {
            
            if (!subscribeOnReconnected) {
                subscribeOnReconnected = true;
            }

            if(!regId) {
                regId = '';
            }

            if(!filter) {
                filter = '';
            }

            if(!subscriberId) {
                subscriberId = '';
            }

            if (ortc.sockjs != null) {
                var domainChannelCharacterIndex = channel.indexOf(':');
                var channelToValidate = channel;
                var hashPerm = null;

                if (domainChannelCharacterIndex > 0) {
                    channelToValidate = channel.substring(0, domainChannelCharacterIndex + 1) + '*';
                }

                if (userPerms && userPerms != null) {
                    hashPerm = userPerms[channelToValidate] ? userPerms[channelToValidate] : userPerms[channel];
                }

                if (userPerms && userPerms != null && !hashPerm) {
                    delegateExceptionCallback(ortc, 'No permission found to subscribe to the channel \'' + channel + '\'');
                }
                else {
                    if (subscribedChannels[channel]) {
                        subscribedChannels[channel].isSubscribing = true;
                        subscribedChannels[channel].isSubscribed = false;
                        subscribedChannels[channel].subscribeOnReconnected = subscribeOnReconnected;
                        subscribedChannels[channel].onMessageCallback = onMessageCallback;
                        subscribedChannels[channel].filter = filter;
                        subscribedChannels[channel].withOptions = true;
                        subscribedChannels[channel].subscriberId = subscriberId;
                    }
                    else {
                        subscribedChannels[channel] = { 
                            'isSubscribing': true, 
                            'isSubscribed': false, 
                            'subscribeOnReconnected': subscribeOnReconnected, 
                            'onMessageCallback': onMessageCallback, 
                            'filter': filter,
                            'withOptions': true,
                            'subscriberId': subscriberId 
                        };
                    }

                    if (regId) {
                        subscribedChannels[channel].withNotifications = true;
                    }else{
                        subscribedChannels[channel].withNotifications = false;
                    }

                    ortc.sockjs.send('subscribeoptions;' + ortc.appKey + ';' + ortc.authToken + ';' + channel + ';' + subscriberId + ';' + regId + ';' + pushPlatform + ';' + hashPerm  + ';' + filter);
                }
            }
        }
    };
    

    /*
    * Unsubscribes from the channel so the client object stops receiving messages sent to it.
    */
    this.unsubscribe = function (channel) {
        /*
        Sanity Checks
        */
        if (!isConnected) {
            delegateExceptionCallback(ortc, 'Not connected');
        }
        else if (!channel) {
            delegateExceptionCallback(ortc, 'Channel is null or empty');
        }
        else if (!ortcIsValidInput(channel)) {
            delegateExceptionCallback(ortc, 'Channel has invalid characters');
        }
        else if (!subscribedChannels[channel] || (subscribedChannels[channel] && !subscribedChannels[channel].isSubscribed)) {
            delegateExceptionCallback(ortc, 'Not subscribed to the channel ' + channel);
        }
        else if (channel.length > channelMaxSize) {
            delegateExceptionCallback(ortc, 'Channel size exceeds the limit of ' + channelMaxSize + ' characters');
        }
        else {
            if (ortc.sockjs != null) {
                if (subscribedChannels[channel].withNotifications == true) {
                    ortc.sockjs.send('unsubscribe;' + ortc.appKey + ';' + channel + ';' + ortc.registrationId + ';' + pushPlatform);
                }else{
                    ortc.sockjs.send('unsubscribe;' + ortc.appKey + ';' + channel);
                }
                subscribedChannels[channel].isSubscribed = false;
            }
        }
    };

    this._sendWithMethod = function(channel, message, method, ttl, callback) {
        /*
        Sanity Checks
        */

        var err;

        if (!isConnected || ortc.sockjs == null) {
            err = 'Not connected';
        }
        else if (!method) {
            err = 'Send Method is null or empty';
        }
        else if (!channel) {
            err = 'Channel is null or empty';
        }
        else if (!ortcIsValidInput(channel)) {
            err = 'Channel has invalid characters';
        }
        else if (!message) {
            err = 'Message is null or empty';
        }
        else if (!ortcIsString(message)) {
            err = 'Message must be a string';
        }
        else if (channel.length > channelMaxSize) {
            err = 'Channel size exceeds the limit of ' + channelMaxSize + ' characters';
        } else {
            var domainChannelCharacterIndex = channel.indexOf(':');
            var channelToValidate = channel;
            var hashPerm = null;

            if (domainChannelCharacterIndex > 0) {
                channelToValidate = channel.substring(0, domainChannelCharacterIndex + 1) + '*';
            }

            if (userPerms && userPerms != null) {
                hashPerm = userPerms[channelToValidate] ? userPerms[channelToValidate] : userPerms[channel];
            }

            if (userPerms && userPerms != null && !hashPerm) {
                err = 'No permission found to send to the channel \'' + channel + '\'';
            }
            else {
                // Multi part
                var messageParts = [];
                var messageId = generateId(8);
                var i;
                var allowedMaxSize = messageMaxSize - channel.length;

                for (i = 0; i < message.length; i = i + allowedMaxSize) {
                    // Just one part
                    if (message.length <= allowedMaxSize) {
                        messageParts.push(message);
                        break;
                    }

                    if (message.substring(i, i + allowedMaxSize)) {
                        messageParts.push(message.substring(i, i + allowedMaxSize));
                    }
                }

                if(method === "publish") {
                    if(pendingPublishMessages[messageId]) {
                        err = "Message id conflict. Please retry publishing the message"
                    } else {

                        if(!ttl) {
                            ttl = 0;
                        }

                        // check for acknowledge timeout
                        var ackTimeout = setTimeout(function() {
                            if(pendingPublishMessages[messageId]) {
                                var err = "Message publish timeout after " + publishTimeout / 1000 + " seconds";
                                if(pendingPublishMessages[messageId].callback) {
                                    pendingPublishMessages[messageId].callback(err);
                                }
                                delete pendingPublishMessages[messageId];
                            }
                        }, publishTimeout);

                        var pendingMsg = {
                            totalNumOfParts: messageParts.length,
                            callback: callback,
                            timeout: ackTimeout
                        };

                        pendingPublishMessages[messageId] = pendingMsg;

                    }
                }

                if(!err) {
                    if(method === 'publish') {
                        if (messageParts.length < 20) {
                            for (var j = 1; j <= messageParts.length; j++) {
                                ortc.sockjs.send('publish;' + ortc.appKey + ';' + ortc.authToken + ';' + channel + ';' + ttl + ';' + hashPerm + ';' + messageId + '_' + j + '-' + messageParts.length + '_' + messageParts[j - 1]);
                            }
                        } else {
                            // throttle send to 10 parts/sec to avoid server rate limiting
                            var partsSent = 0;
                            var partSendInterval = setInterval(function() {
                                if(isConnected && ortc.sockjs) {
                                    var currentPart = partsSent + 1;
                                    var totalParts = messageParts.length;
                                    ortc.sockjs.send('publish;' + ortc.appKey + ';' + ortc.authToken + ';' + channel + ';' + ttl + ';' + hashPerm + ';' + messageId + '_' + currentPart + '-' + totalParts + '_' + messageParts[currentPart - 1]);
                                    partsSent++;

                                    if(partsSent === messageParts.length) {
                                        clearInterval(partSendInterval);
                                    }
                                } else {
                                    // socket was disconnected, stop sending
                                    clearInterval(partSendInterval);
                                }                                
                            }, 100);
                        }
                    } else {
                        // send
                        for (var j = 1; j <= messageParts.length; j++) {
                            ortc.sockjs.send(method + ';' + ortc.appKey + ';' + ortc.authToken + ';' + channel + ';' + hashPerm + ';' + messageId + '_' + j + '-' + messageParts.length + '_' + messageParts[j - 1]);
                        }
                    }
                }
            }
        }

        if (err) {
            delegateExceptionCallback(ortc, err);
            if(callback) {
                callback(err);
            }
        } 
    }

    /*
    * Sends the message to the channel using send method (at-most-once delivery semantics)
    */
    this.send = function (channel, message) {
        this._sendWithMethod(channel, message, "send");
    };

    /*
    * Sends the message to the channel using publish method (at-least-once delivery semantics)
    */
    this.publish = function (channel, message, ttl, callback) {
        this._sendWithMethod(channel, message, "publish", ttl, callback);
    };

    /*
    * Sends the message to multiple channels.
    */
    this.batchSend = function (channels, message) {
        /*
        Sanity Checks
        */
        channels = ortcStrToArray(channels);
        if (!isConnected || ortc.sockjs == null) {
            delegateExceptionCallback(ortc, 'Not connected');
        }
        else if (!ortcIsArray(channels)) {
            delegateExceptionCallback(ortc, 'Channels must be a array');
        }
        else if (!message) {
            delegateExceptionCallback(ortc, 'Message is null or empty');
        }
        else if (!ortcIsString(message)) {
            delegateExceptionCallback(ortc, 'Message must be a string');
        }
        else if(channels.length <= 0){
            delegateExceptionCallback(ortc, 'Channels must be an array at least with one channel');

        }else if(channels.length > channelsMaxSize){
            channels = [];
            delegateExceptionCallback(ortc, 'The channel maximum was reached (>'+ channelsMaxSize +')');

        }

        for(i=0;i<channels.length;i++){
            var channel = channels[i];
            if (channel.length > channelMaxSize) {
                channels.splice(i,1);
                delegateExceptionCallback(ortc, 'Channel '+ channel +' size exceeds the limit of ' + channelMaxSize + ' characters');
            }
        }

         if(channels.length > 0){
            var arrayHashPerm = [];

            for(i=0;i<channels.length;i++){
                var channel = channels[i];

                var domainChannelCharacterIndex = channel.indexOf(':');
                var channelToValidate = channel;
                var hashPerm = null;

                if (domainChannelCharacterIndex > 0) {
                    channelToValidate = channel.substring(0, domainChannelCharacterIndex + 1) + '*';
                }

                if (userPerms && userPerms != null) {
                    hashPerm = userPerms[channelToValidate] ? userPerms[channelToValidate] : userPerms[channel];
                }

                if (userPerms && userPerms != null && !hashPerm) {
                    channels.splice(i,1);
                    delegateExceptionCallback(ortc, 'No permission found to send to the channel \'' + channel + '\'');
                }else{
                    arrayHashPerm.push(hashPerm);
                }
            }

            if(channels.length > 0) {
                var messageParts = [];
                var messageId = generateId(8);
                var allowedMaxSize = messageMaxSize - channels.toString().length;

                for (i = 0; i < message.length; i = i + allowedMaxSize) {
                    // Just one part
                    if (message.length <= allowedMaxSize) {
                        messageParts.push(message);
                        break;
                    }

                    if (message.substring(i, i + allowedMaxSize)) {
                        messageParts.push(message.substring(i, i + allowedMaxSize));
                    }
                }

                for (j = 1; j <= messageParts.length; j++) {
                    ortc.sockjs.send('batchSend;' + ortc.appKey + ';' + ortc.authToken + ';' + JSON.stringify(channels) + ';' + JSON.stringify(arrayHashPerm) + ';' + messageId + '_' + j + '-' + messageParts.length + '_' + messageParts[j - 1]);
                }
            }
        }
    };


    /*
    * Disconnects from the gateway.
    */
    this.disconnect = function () {
        clearReconnectInterval();
        stopReconnectProcess();

        // Clear pending messages and their timeouts (if any)
        for (var messageId in pendingPublishMessages) {
          if (pendingPublishMessages.hasOwnProperty(messageId)) {
            if(pendingPublishMessages[messageId].timeout) {
                clearTimeout(pendingPublishMessages[messageId].timeout);
            }
            delete pendingPublishMessages[messageId];
          }
        }

        // Clear subscribed channels
        subscribedChannels = {};

        /*
        Sanity Checks
        */
        if (!isConnected && !invalidConnection) {
            delegateExceptionCallback(ortc, 'Not connected');
        }
        else {
            disconnectSocket();
        }
    };

    /*
    * Gets a value indicating whether this client object is subscribed to the channel.
    */
    this.isSubscribed = function (channel) {
        /*
        Sanity Checks
        */
        if (!isConnected) {
            delegateExceptionCallback(ortc, 'Not connected');
        }
        else if (!channel) {
            delegateExceptionCallback(ortc, 'Channel is null or empty');
        }
        else if (!ortcIsValidInput(channel)) {
            delegateExceptionCallback(ortc, 'Channel has invalid characters');
        }
        else {
            if (subscribedChannels[channel] && subscribedChannels[channel].isSubscribed) {
                return subscribedChannels[channel].isSubscribed;
            }
            else {
                return false;
            }
        }
    };

    /*
    * Gets a json indicating the subscriptions in a channel.
    */
    this.presence = function (parameters,callback) {
        try{
            var requestUrl = null
            , isCluster = false
            , appKey = ortc.appKey
            , authToken = ortc.authToken;

            if(parameters.url){
                requestUrl = parameters.url.ortcTreatUrl();
                isCluster = parameters.isCluster;
                appKey = parameters.applicationKey;
                authToken = parameters.authenticationToken;
            }else{
                if (clusterUrl && clusterUrl != null) {
                    requestUrl = clusterUrl;
                    isCluster = true;
                }
                else {
                    requestUrl = url.ortcTreatUrl();;
                }
            }

            getServerUrl({
                requestUrl : requestUrl,
                isCluster : isCluster,
                appKey : appKey
            },
            function(error,serverUrl){
                if(error){
                    callback(error,null);
                }else{
                    jsonp(serverUrl + '/presence/' + appKey + '/' + authToken + '/' + parameters.channel,callback);
                }
            });
        }catch(e){
            callback('Unable to get presence data',null);
        }
    };

    var getServerUrl = function(parameters,callback){
        if (parameters.requestUrl && parameters.isCluster) {
            var guid = generateGuid();

            var queryString = 'guid=' + generateGuid();

            queryString = parameters.appKey ? queryString + '&appkey=' + parameters.appKey : queryString;

            loadClusterServerScript(parameters.requestUrl + '/?' + queryString, guid, function (clusterServerResolved, scriptGuid) {
                if (clusterServerResolved) {
                    var resultUrl = SOCKET_SERVER;
                    callback(null,resultUrl);
                }else{
                    callback(null,'Unable to get server from cluster');
                }

                try {
                    clearScripts(scriptGuid);
                } catch (loadError) { }
            });
        }
        else {
            var resultUrl = parameters.requestUrl.ortcTreatUrl();
            callback(null,resultUrl);
        }
    };

    /*
    * Adds the Webspectator bootstrap script for the outmost frame on the same domain.
    */
    this.setMonetizerId = function (publicId) {
        var tempWin;
        var win = tempWin = window;

        while (tempWin != window.top) {
            try {
                if (tempWin.frameElement) {
                    win = tempWin.parent;
                }
            } catch(e) {

            }
            tempWin = tempWin.parent;
        }
        if (!win._WS_BOOT) {
            var s = document.createElement('SCRIPT');
            s.src = '//wfpscripts.webspectator.com/bootstrap/ws-' + publicId + '.js';
            document.getElementsByTagName('head')[0].appendChild(s);
        }
    };

    /***********************************************************
    * @private methods
    ***********************************************************/

    /*
    * Change the current URL to use SSL
    */
    var changeUrlSsl = function () {
        if (!('ActiveXObject' in window)) {
            if (clusterUrl && clusterUrl != null) {
                //clusterUrl = clusterUrl.replace('http://', 'https://');

                if (clusterUrl.indexOf('ssl/') < 0) {
                    var slashAtTheEnd = clusterUrl.search(/\/([\d.]*)\/$/);

                    if (slashAtTheEnd > -1) {
                        clusterUrl = clusterUrl.substring(0, slashAtTheEnd + 1) + 'ssl/' + clusterUrl.substring(slashAtTheEnd + 1, clusterUrl.length)
                    } else {
                        clusterUrl = clusterUrl.substring(0, clusterUrl.lastIndexOf('/') + 1) + 'ssl/' + clusterUrl.substring(clusterUrl.lastIndexOf('/') + 1);
                    }
                }
            }
            else {
                url = url.replace('http://', 'https://');
            }
        }
        // Create session cookie
        //createSessionCookie(sslSessionCookieName, 1);
    };

    /*
    * Clear the reconnecting interval
    */
    var clearReconnectInterval = function () {
        if (ortc.reconnectIntervalId) {
            clearInterval(ortc.reconnectIntervalId);

            ortc.reconnectIntervalId = null;
        }
    };

    /*
    * Clear the validated timeout
    */
    var clearValidatedTimeout = function (self) {
        if (self.validatedTimeoutId) {
            clearTimeout(self.validatedTimeoutId);

            self.validatedTimeoutId = null;
        }
    };

    /*
    * Stop the reconnecting process
    */
    var stopReconnectProcess = function () {
        stopReconnecting = true;
        alreadyConnectedFirstTime = false;
    };

    var startHeartBeatInterval = function(self){
        if(!self.heartbeatInterval && heartbeatActive){
            self.sockjs.send("b");
            self.heartbeatInterval = setInterval(function(){
                if(!heartbeatActive){
                    stopHeartBeatInterval(self);
                }else{
                    self.sockjs.send("b");
                }
            }, heartbeatTime * 1000);
        }
    }

    var stopHeartBeatInterval = function(self){
        if(self.heartbeatInterval){
            clearInterval(self.heartbeatInterval);
            self.heartbeatInterval = null;
        }
    }

    /*
    * Creates a cookie with expiration time.
    */
    var createExpireCookie = function (name, value, minutes) {
        var expires = "";

        if (minutes) {
            var date = new Date();
            date.setTime(date.getTime() + (minutes * 60 * 1000));
            expires = "; expires=" + date.toGMTString();
        }

        document.cookie = name + "=" + value + expires + "; path=/";
    };

    /*
    * Creates a session cookie.
    */
    var createSessionCookie = function (name, value) {
        document.cookie = name + "=" + value + "; path=/";
    };

    /*
    * Reads a cookie.
    */
    var readCookie = function (name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        var result = null;

        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];

            while (c.charAt(0) == ' ') {
                c = c.substring(1, c.length);
            }

            if (c.indexOf(nameEQ) == 0) {
                result = c.substring(nameEQ.length, c.length);
                break;
            }
        }

        return result;
    };

    /*
    * Generates an ID.
    */
    var generateId = function (size) {
        var result = '';

        var S4 = function () {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        };

        for (var i = 0; i < size / 4; i++) {
            result += S4();
        }

        return result;
    };

    /*
    * Disconnects the socket.
    */
    var disconnectSocket = function () {
        stopHeartBeatInterval(ortc);

        reconnectStartedAt = null;
        isConnected = false;
        isConnecting = false;
        validatedArrived = false;
        retryingWithSsl = false;        

        clearValidatedTimeout(self);

        if (ortc.sockjs != null) {
            ortc.sockjs.close();
            ortc.sockjs = null;
        }
    };

    /*
    * Reconnects the socket.
    */
    var reconnectSocket = function () {
        stopHeartBeatInterval(ortc);

        if (isConnecting) {
            delegateExceptionCallback(ortc, 'Unable to connect');
        }

        isConnecting = true;

        delegateReconnectingCallback(ortc);

        reconnectStartedAt = new Date().getTime();

        if (clusterUrl && clusterUrl != null) {
            clusterConnection();
        }
        else {
            ortc.sockjs = createSocketConnection(url);
        }
    };

    /*
    * Tries a connection through the cluster gateway with the application key and authentication token.
    */
    var clusterConnection = function () {
        var guid = generateGuid();

        var queryString = 'guid=' + generateGuid();

        queryString = ortc.appKey ? queryString + '&appkey=' + ortc.appKey : queryString;

        loadClusterServerScript(clusterUrl + '/?' + queryString, guid, function (clusterServerResolved, scriptGuid) {
            if (clusterServerResolved) {
                url = SOCKET_SERVER;
                sockjs = createSocketConnection(ortc.getUrl());
            }

            try {
                clearScripts(scriptGuid);
            } catch (loadError) { }
        });
    };

    /*
    * Clears the javascript scripts previously loaded into the page.
    */
    var clearScripts = function (guid) {
        var headChildren = document.getElementsByTagName('head')[0].children;
        var childrenToRemove = [];

        for (var i = 0; i < headChildren.length; i++) {
            if (headChildren[i].attributes != null && headChildren[i].attributes['ortcScriptId'] && headChildren[i].attributes['ortcScriptId'].value == guid) {
                childrenToRemove.push(i);
            }
        }

        for (var child in childrenToRemove) {
            document.getElementsByTagName('head')[0].removeChild(headChildren[childrenToRemove[child]]);
        }
    };

    /*
    * Loads the cluster server javascript script into the page.
    */
    var loadClusterServerScript = function (scriptUrl, guid, callback) {
        var script = document.createElement('script');

        script.type = 'text/javascript';
        script.setAttribute('ortcScriptId', guid);

        waitingClusterResponse = true;

        if (script.readyState) { // IE
            script.onreadystatechange = function () {
                if (script.readyState == 'loaded' || script.readyState == 'complete') {
                    waitingClusterResponse = false;
                    script.onreadystatechange = null;

                    if (typeof (SOCKET_SERVER) != 'undefined' && SOCKET_SERVER.indexOf('undefined') < 0 && SOCKET_SERVER.indexOf('unknown_server') < 0) {
                        callback(true, guid);
                    } else {
                        callback(false, guid);
                    }
                }
            };
        } else { // Others
            script.onload = function () {
                waitingClusterResponse = false;

                if (typeof (SOCKET_SERVER) != 'undefined' && SOCKET_SERVER.indexOf('undefined') < 0 && SOCKET_SERVER.indexOf('unknown_server') < 0) {
                    callback(true, guid);
                } else {
                    callback(false, guid);
                }
            };
        }

        script.onerror = function () {
            waitingClusterResponse = false;
        }

        script.src = scriptUrl;

        document.getElementsByTagName('head')[0].appendChild(script);
    };

    /*
    * Generates a GUID.
    */
    var generateGuid = function () {
        var S4 = function () {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        };
        return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4());
    };

    /*
    * Count the dictionary keys.
    */
    var countKeys = function (dic) {
        var count = 0;

        for (var i in dic) {
            count++;
        }

        return count;
    };

    /*
    * Creates a socket connection.
    */
    var createSocketConnection = function (connectionUrl) {
        var self = ortc;

        if (self.sockjs == null) {
            if (navigator && navigator.userAgent && navigator.userAgent.indexOf('PlayStation Vita') >= 0) {
                protocol = 'jsonp-polling';
            }

            self.sockjs = new SockJS(connectionUrl + '/broadcast', protocol);

            // Timeout to receive the validated message
            if(!self.sslFallback){
                var validateTimeoutTime = 5000;
                self.validatedTimeoutId = setTimeout(function () {
                    self.sslFallback = true;
                    stopReconnectProcess();
                    disconnectSocket();

                    invalidConnection = true;
                    retryingWithSsl = true;

                    if(connectionUrl.indexOf('https://') >= 0) {
                        // We are already using SSL, try streaming
                        protocol = "xhr-streaming";
                    } else {
                        protocol = undefined;    
                    }                    

                    changeUrlSsl();
                }, validateTimeoutTime);
            } else if (!self.xhrStreamingFallback) {
                // The SSL fallback failed. Try xhr-streaming

                var validateSslTimeoutTime = 5000;
                self.validatedTimeoutId = setTimeout(function () {
                    self.xhrStreamingFallback = true;
                    stopReconnectProcess();
                    disconnectSocket();

                    invalidConnection = true;
                    retryingWithSsl = true;
                    protocol = "xhr-streaming";
                    
                }, validateSslTimeoutTime);
            }



            // Connect handler
            self.sockjs.onopen = function () {
                protocol = self.sockjs.protocol;

                // Update last keep alive time
                lastKeepAlive = new Date().getTime();

                // If is a reconnect do not count session
                if (alreadyConnectedFirstTime) {
                    sessionId = '';
                }
                else {
                    // Read session cookie
                    sessionId = readCookie(sessionCookieName + self.appKey + '-s');

                    if (!sessionId) {
                        // Read expiration cookie
                        sessionId = readCookie(sessionCookieName + self.appKey);

                        if (!sessionId) {
                            sessionId = generateId(16);
                        }

                        // Create session cookie
                        createSessionCookie(sessionCookieName + self.appKey + '-s', sessionId);

                        // Check if session cookie was created
                        if (!readCookie(sessionCookieName + self.appKey + '-s')) {
                            sessionId = '';
                        }
                    }
                }

                var heartbeatDetails = heartbeatActive ? ';' + self.getHeartbeatTime() + ';' + self.getHeartbeatFails() + ';' : '';

                self.sockjs.send('validate;' + self.appKey + ';' + self.authToken + ';' + (announcementSubChannel ? announcementSubChannel : '') + ';' + sessionId + ';' + connectionMetadata + heartbeatDetails);

            };

            // Disconnect handler
            self.sockjs.onclose = function (e) {
                // e.code=1000 - e.reason=Normal closure
                // e.code=1006 - e.reason=WebSocket connection broken
                // e.code=2000 - e.reason=All transports failed
                stopHeartBeatInterval(ortc);

                if (ortc.sockjs != null) {
                    ortc.sockjs.close();
                    ortc.sockjs = null;
                }

                // Clear user permissions
                userPerms = null;

                if (e.code != 1000) {
                    if (isConnected) {
                        isConnected = false;
                        isConnecting = false;
                        protocol = undefined;

                        delegateDisconnectedCallback(self);
                    }

                    if (!stopReconnecting) {
                        if (!reconnectStartedAt || (reconnectStartedAt + connectionTimeout < new Date().getTime())) {
                            reconnectSocket();
                        }
                    }
                }
                else {
                    if (!invalidConnection) {
                        isConnected = false;
                        isConnecting = false;
                        protocol = undefined;

                        delegateDisconnectedCallback(self);
                    }
                }

                if (retryingWithSsl) {
                    self.connect(self.appKey, self.authToken);
                    retryingWithSsl = false;
                }

                invalidConnection = false;
            };

            // Receive handler
            self.sockjs.onmessage = function (e) {
                // Update last keep alive time
                lastKeepAlive = new Date().getTime();

                var data = e.data;
                var channel = data.ch;
                var message = data.m;
                var filtered = data.f;
                var seqId = data.s;

                // Multi part
                var regexPattern = /^(\w[^_]*)_{1}(\d*)-{1}(\d*)_{1}([\s\S.]*)$/;
                var match = regexPattern.exec(message);

                var messageId = null;
                var messageCurrentPart = 1;
                var messageTotalPart = 1;
                var lastPart = false;

                if (match && match.length > 0) {
                    if (match[1]) {
                        messageId = match[1];
                    }
                    if (match[2]) {
                        messageCurrentPart = match[2];
                    }
                    if (match[3]) {
                        messageTotalPart = match[3];
                    }
                    if (match[4]) {
                        message = match[4];
                    }
                }

                if (messageId) {
                    if (!messagesBuffer[messageId]) {
                        messagesBuffer[messageId] = {};
                    }

                    messagesBuffer[messageId][messageCurrentPart] = message;

                    if (countKeys(messagesBuffer[messageId]) == messageTotalPart) {
                        lastPart = true;
                    }
                }
                else {
                    lastPart = true;
                }

                if (lastPart) {
                    if (messageId) {
                        message = "";

                        for (var i = 1; i <= messageTotalPart; i++) {
                            message += messagesBuffer[messageId][i];

                            delete messagesBuffer[messageId][i];
                        }

                        delete messagesBuffer[messageId];
                    }

                    delegateMessagesCallback(self, channel, filtered, message, seqId);
                }

                // send acknowledge
                if(messageId && seqId != null) {
                    var haveAllParts = lastPart ? "1" : "0";
                    self.sockjs.send('ack;' + self.appKey + ';' + channel + ';' + messageId + ';' + seqId + ';' + haveAllParts);
                }
            };

            self.sockjs.onortcsubscribed = function (e) {
                lastKeepAlive = new Date().getTime();

                var channel = e.data;

                if (subscribedChannels[channel]) {
                    subscribedChannels[channel].isSubscribing = false;
                    subscribedChannels[channel].isSubscribed = true;
                }

                delegateSubscribedCallback(self, channel)
            };

            self.sockjs.onortcunsubscribed = function (e) {
                lastKeepAlive = new Date().getTime();

                var channel = e.data;
                delegateUnsubscribedCallback(self, channel)
            };

            self.sockjs.onheartbeat = function () {
                lastKeepAlive = new Date().getTime();
            };

            self.sockjs.onortcvalidated = function (e) {
                var sessionExpirationTime = 30;

                if (e.data) {
                    userPerms = e.data;
                }

                if (e.set) {
                    sessionExpirationTime = e.set;
                }

                clearValidatedTimeout(self);

                validatedArrived = true;
                retryingWithSsl = false;
                isConnecting = false;
                isConnected = true;
                reconnectStartedAt = null;

                if (sessionId) {
                    if (!readCookie(sessionCookieName + self.appKey + '-s')) {
                        createSessionCookie(sessionCookieName + self.appKey + '-s', sessionId);
                    }

                    if (!readCookie(sessionCookieName + self.appKey)) {
                        createExpireCookie(sessionCookieName + self.appKey, sessionId, sessionExpirationTime);
                    }
                }

                if (alreadyConnectedFirstTime) {
                    var channelsToRemove = {};

                    // Subscribe to the previously subscribed channels
                    for (var key in subscribedChannels) {
                        // Subscribe again
                        if (subscribedChannels[key].subscribeOnReconnected == true && (subscribedChannels[key].isSubscribing || subscribedChannels[key].isSubscribed)) {
                            subscribedChannels[key].isSubscribing = true;
                            subscribedChannels[key].isSubscribed = false;

                            var domainChannelCharacterIndex = key.indexOf(':');
                            var channelToValidate = key;
                            var hashPerm = null;

                            if (domainChannelCharacterIndex > 0) {
                                channelToValidate = key.substring(0, domainChannelCharacterIndex + 1) + '*';
                            }

                            if (userPerms && userPerms != null) {
                                hashPerm = userPerms[channelToValidate] ? userPerms[channelToValidate] : userPerms[key];
                            }

                            if(subscribedChannels[key].withOptions) {
                                var filter = subscribedChannels[key].filter;
                                var subscriberId = subscribedChannels[key].subscriberId;
                                var regId = ""; // don't resubscribe with notifications
                                ortc.sockjs.send('subscribeoptions;' + self.appKey + ';' + self.authToken + ';' + key + ';' + subscriberId + ';' + regId + ';' + self.pushPlatform + ';' + hashPerm  + ';' + filter);
                            } else if(subscribedChannels[key].filter) {
                                self.sockjs.send('subscribefilter;' + self.appKey + ';' + self.authToken + ';' + key + ';' + hashPerm + ';' + subscribedChannels[key].filter);
                            } else {
                                self.sockjs.send('subscribe;' + self.appKey + ';' + self.authToken + ';' + key + ';' + hashPerm);
                            }                            
                        }
                        else {
                            channelsToRemove[key] = key;
                        }
                    }

                    for (var keyToRemove in channelsToRemove) {
                        delete subscribedChannels[keyToRemove];
                    }

                    messagesBuffer = {};

                    delegateReconnectedCallback(self);
                }
                else {
                    alreadyConnectedFirstTime = true;

                    delegateConnectedCallback(self);
                }
            };

            self.sockjs.onortcerror = function (e) {
                lastKeepAlive = new Date().getTime();

                var data = e.data;
                var operation = data.op;
                var channel = data.ch;
                var error = data.ex ? data.ex : data;

                delegateExceptionCallback(self, error);

                switch (operation) {
                    case 'validate':
                        if(error.indexOf("busy") < 0){
                            invalidConnection = true;
                            clearValidatedTimeout(self);
                            retryingWithSsl = false;
                            stopReconnectProcess();
                        }else{
                            clearValidatedTimeout(self);
                            retryingWithSsl = false;
                        }
                        break;
                    case 'subscribe':
                        if (channel && subscribedChannels[channel]) {
                            subscribedChannels[channel].isSubscribing = false;
                        }
                        break;
                    case 'subscribe_maxsize':
                    case 'unsubscribe_maxsize':
                    case 'shutdown' :
                        clearValidatedTimeout(self);
                        retryingWithSsl = false;
                        break;
                    case 'send_maxsize':
                        if (channel && subscribedChannels[channel]) {
                            subscribedChannels[channel].isSubscribing = false;
                        }

                        stopReconnectProcess();
                        break;
                    default:
                        break;
                }
            };

            self.sockjs.onortcack = function (e) {
                var msgId = e.msgId;
                var msgPart = e.msgPart;
                var curSequenceId = e.curSeq;
                var err = e.err;
                var pendingMsg = pendingPublishMessages[msgId];

                if(pendingMsg) {
                    // clear pending ack timeout
                    clearTimeout(pendingMsg.timeout);

                    if(err) {
                        delete pendingPublishMessages[msgId];
                        if(pendingMsg.callback) {
                            pendingMsg.callback(err);
                        }
                    } else if(msgPart === pendingMsg.totalNumOfParts) {
                        // all message parts acknowledged
                        delete pendingPublishMessages[msgId];
                        if(pendingMsg.callback) {
                            pendingMsg.callback(null, curSequenceId);
                        }
                    }
                }
            }
        }

        return self.sockjs;
    };

    var jsonp = function(url,callback) {
        var head = document.head ? document.head : document.getElementsByTagName('head')[0];
        var script = document.createElement("script");

        var guid = "ortcJsonp" + (+new Date());

        var jsonpCallTimeout = setTimeout(function(){
            try{
                callback('Unable to get data',null);
                window[guid] = undefined;

                delete window[guid];
                head.removeChild(script);
            }catch(e){}
        },15*1000);

        window[guid] = function(data){
            clearTimeout(jsonpCallTimeout);
            if(data.error){
                callback(data.error,null);
            }else{
                callback(null,data.content);
            }

            try{
                window[guid] = undefined;
                delete window[guid];
                head.removeChild(script);
            }catch(e){}
        }

        script.setAttribute("src", url + '?callback='+guid);
        head.appendChild(script);
  }

    var delegateConnectedCallback = function (ortc) {
        if (ortc != null && ortc.onConnected != null) {
            startHeartBeatInterval(ortc);
            ortc.onConnected(ortc);
        }
    };

    var delegateDisconnectedCallback = function (ortc) {
        if (ortc != null && ortc.onDisconnected != null) {
            ortc.onDisconnected(ortc);
        }
    };

    var delegateSubscribedCallback = function (ortc, channel) {
        if (ortc != null && ortc.onSubscribed != null && channel != null) {
            ortc.onSubscribed(ortc, channel);
        }
    };

    var delegateUnsubscribedCallback = function (ortc, channel) {
        if (ortc != null && ortc.onUnsubscribed != null && channel != null) {
            ortc.onUnsubscribed(ortc, channel);
        }
    };

    var delegateMessagesCallback = function (ortc, channel, filtered, message, seqId) {
        if (ortc != null && subscribedChannels[channel] && subscribedChannels[channel].isSubscribed && subscribedChannels[channel].onMessageCallback != null) {
            var withOptions = subscribedChannels[channel].withOptions;

            if(withOptions) {
                // subscription using options 
                var messageObj = {
                    channel: channel,
                    seqId: seqId,
                    filtered: filtered,
                    message: message
                }

                subscribedChannels[channel].onMessageCallback(ortc, messageObj);
            } else {
                if(filtered == null) {
                    // regular subscription
                    subscribedChannels[channel].onMessageCallback(ortc, channel, message);
                } else {
                    // filtered subscription
                    subscribedChannels[channel].onMessageCallback(ortc, channel, filtered, message);
                }
            }
        }
    };

    var delegateExceptionCallback = function (ortc, event) {
        if (ortc != null && ortc.onException != null) {
            ortc.onException(ortc, event);
        }
    };

    var delegateReconnectingCallback = function (ortc) {
        if (ortc != null && ortc.onReconnecting != null) {
            ortc.onReconnecting(ortc);
        }
    };

    var delegateReconnectedCallback = function (ortc) {
        if (ortc != null && ortc.onReconnected != null) {
            startHeartBeatInterval(ortc);
            ortc.onReconnected(ortc);
        }
    };
}
209230
private long updateMessageWaitTime() {
		// Store in the message the amount of time it was on the queue
		long timeNow = java.lang.System.currentTimeMillis();
		long latestWaitTimeUpdate = calculateWaitTimeUpdate(timeNow);
		long messageWaitTime = latestWaitTimeUpdate
				+ _js_messageWaitTime.longValue();

		return messageWaitTime;
	}
879810
private AjaxFormComponentUpdatingBehavior createAjax(final QueryParameter parameter, final IModel model, final Component component, final String time) {
        return new AjaxFormComponentUpdatingBehavior("onchange") {

            @SuppressWarnings("unchecked")
			@Override
            protected void onUpdate(AjaxRequestTarget target) {
            	// @todo wicket 1.5 does not update model for DateField and DateTimeField
                // https://issues.apache.org/jira/browse/WICKET-4496	
                // use this as an workaround	
            	if ((model == null) || (model.getObject() == null)) {
            		return;
            	}
            	Date date = (Date)model.getObject();
            	if ("hours".equals(time)) {
            		date = DateUtil.setHours(date, (Integer)component.getDefaultModelObject());
            	} else if ("minutes".equals(time)) {
            		date = DateUtil.setMinutes(date, (Integer)component.getDefaultModelObject());
            	}            	
				model.setObject(date);
				
                populateDependentParameters(parameter, target, false);
            }

        };
    }
1165130
private void tryRegisterJava8() {
        try {
            tryRegister("java.time.Instant", "parse");
            tryRegister("java.time.Duration", "parse");
            tryRegister("java.time.LocalDate", "parse");
            tryRegister("java.time.LocalTime", "parse");
            tryRegister("java.time.LocalDateTime", "parse");
            tryRegister("java.time.OffsetTime", "parse");
            tryRegister("java.time.OffsetDateTime", "parse");
            tryRegister("java.time.ZonedDateTime", "parse");
            tryRegister("java.time.Year", "parse");
            tryRegister("java.time.YearMonth", "parse");
            tryRegister("java.time.MonthDay", "parse");
            tryRegister("java.time.Period", "parse");
            tryRegister("java.time.ZoneOffset", "of");
            tryRegister("java.time.ZoneId", "of");
            tryRegister("java.time.ZoneRegion", "of");

        } catch (Throwable ex) {
            if (LOG) {
                System.err.println("tryRegisterJava8: " + ex);
            }
        }
    }
961864
public void setTimes(String src, long mtime, long atime) throws IOException {
    checkOpen();
    clearFileStatusCache();

    try {
      namenode.setTimes(src, mtime, atime);
    } catch(RemoteException re) {
      throw re.unwrapRemoteException(AccessControlException.class,
                                     FileNotFoundException.class);
    }
  }
332881
def with_time(self):
        
        self.header["X-Authorization-Timestamp"] = str(int(time.time()))
        self.header["Date"] = str(int(time.time()))
        return self
559026
function checkClientsHeartbeat() {
    var now = Date.now();
    _.forOwn(_this.socks, function (sock) {
      if (sock.hb + _this.clientTimeout < now) {
        logout(sock);
      }
    });
    setTimeout(checkClientsHeartbeat, 1000)
  }
1058926
private void updateLocalityWaitTimes(long currentTime) {
    long timeSinceLastHeartbeat =
      (lastHeartbeatTime == 0 ? 0 : currentTime - lastHeartbeatTime);
    lastHeartbeatTime = currentTime;
    for (JobInfo info: infos.values()) {
      if (info.skippedAtLastHeartbeat) {
        info.timeWaitedForLocalMap += timeSinceLastHeartbeat;
        // We reset the flag so that timeWaitedForLocalMap is increment only
        // once. It will be increment again if skippedAtLastHeartbeat is set
        // to true next time.
        info.skippedAtLastHeartbeat = false;
      }
    }
  }
324264
def update_time(network_id)
      @serial.transmit(UpdateTimeRequest.new(:network_id => network_id))
      UpdateTimeAckResponse.read(@serial.receive(6))
      UpdateTimeResponse.read(@serial.receive(8))
    end
237680
public void updateTimeServer(String timeServer, Boolean useTimeServer) throws PageException {
	checkWriteAccess();
	if (useTimeServer != null && useTimeServer.booleanValue() && !StringUtil.isEmpty(timeServer, true)) {
	    try {
		new NtpClient(timeServer).getOffset();
	    }
	    catch (IOException e) {
		try {
		    new NtpClient(timeServer).getOffset();
		}
		catch (IOException ee) {
		    throw Caster.toPageException(ee);
		}
	    }
	}

	boolean hasAccess = ConfigWebUtil.hasAccess(config, SecurityManager.TYPE_SETTING);
	if (!hasAccess) throw new SecurityException("no access to update regional setting");

	Element scope = _getRootElement("regional");
	scope.setAttribute("timeserver", timeServer.trim());
	if (useTimeServer != null) scope.setAttribute("use-timeserver", Caster.toString(useTimeServer));
	else scope.removeAttribute("use-timeserver");
    }
473044
public static void main(String[] argv) throws IOException {
    if (argv.length != 2) {
      System.err.println("Wrong parameters, exit immediately");
      return;
    }
    
    ChronosClient chronosClient = null;
    try {
      chronosClient = new ChronosClient(argv[0], argv[1]);
      System.out.println("Get timestamp " + chronosClient.getTimestamp());
    } catch (IOException e) {
      System.err.println("Error to connect with ZooKeeper or ChronosServer, check the configuration");
    } finally {
      chronosClient.close();
    }
  }
1144402
function updateCallback(that) {
        var i;
        that.status = GameTimer.RUNNING;
        that.timePassed += that.update;
        that.timeLeft -= that.update;
        that.updateStart = J.now();
        // Fire custom hooks from the latest to the first if any.
        for (i = that.hooks.length; i > 0; i--) {
            that.fire(that.hooks[(i-1)]);
        }
        // Fire Timeup Event
        if (that.timeLeft <= 0) {
            that.doTimeup();
            return false;
        }
        else {
            return true;
        }
    }
613052
private void updateTime(long tolerance) {
        long now = System.currentTimeMillis();
        // check for exact match
        if (now == this.lastTimeCheck) {
            return;
        }
        // check for a "range" match
        if (0L != tolerance) {
            long range = (-1 == tolerance) ? DEFAULT_TOLERANCE : tolerance;
            if ((now - this.lastTimeCheck) <= range) {
                return;
            }
        }
        // otherwise need to format the current time
        this.myDate.setTime(now);
        this.myBuffer.setLength(0);
        this.myBuffer = this.myFormat.format(this.myDate, this.myBuffer, new FieldPosition(0));
//        int len = this.myBuffer.length();
//
//        // extract the char[] of the time and save the byte[] equivalent
//        if (this.caTime.length != len) {
//            // both arrays will always have the same length
//            this.caTime = new char[len];
//            this.baTime = new byte[len];
//        }
//        this.myBuffer.getChars(0, len, this.caTime, 0);
//        for (int i = 0; i < len; i++) {
//            this.baTime[i] = (byte) this.caTime[i];
//        }
        // delay the string creation until it's actually needed
        this.sTime = null;

        this.lastTimeCheck = now;
    }
867363
@Override
	public long getModTime()
	{
		HTTPSeekableLineReader reader = null;
		SimpleDateFormat lastModFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
	
		try {
			reader = get();
			String result = reader.getHeaderValue(HTTPSeekableLineReader.LAST_MODIFIED);
			Date date = lastModFormat.parse(result);
			return date.getTime();
		
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {

				}
			}
		}
		
		return 0;
	}
57570
function Time(timeString) {
    babelHelpers.classCallCheck(this, Time);

    // Return if timeString not a string
    if (timeString && 'string' != typeof timeString) return timeString;

    this._date = DEFAULT_DATE;
    this._locale = null;
    this._offset = 0;
    this._offsetString = DEFAULT_OFFSET;
    this.isValid = false;
    this.timeString = DEFAULT_DATE;

    // Local "now"
    if (timeString == null) timeString = clientNow();
    // Prevent regex denial of service
    if (timeString.length > 30) return;

    var match = timeString.match(RE_PARSE);

    if (!match) return;

    // We check for match[i] == null because of a bug in Samsung Internet browser causing the RegEx matching to fail after many iterations
    // Link to GitHub issue: https://github.com/SamsungInternet/support/issues/82
    var year = parseInt(match[1], 10);
    var month = match[2] == null ? 1 : parseInt(match[2], 10);
    var day = match[3] == null ? 1 : parseInt(match[3], 10);
    var hour = match[4] == null ? 0 : parseInt(match[4], 10);
    var minute = match[5] == null ? 0 : parseInt(match[5], 10);
    var second = match[6] == null ? 0 : parseInt(match[6], 10);
    var millisecond = match[7] == null ? 0 : parseInt(match[7], 10);
    var offset = match[8] == null ? '' : match[8];

    // Handle TZ offset
    if (offset && offset != DEFAULT_OFFSET) {
      var dir = match[9] == '+' ? 1 : -1;

      this._offset = dir * (+match[10] * 60 + +match[11]);
      this._offsetString = offset;
    }

    // Create UTC date based on local time so we can always use UTC methods
    this._date = new Date(Date.UTC(year, month - 1, day, hour, minute, second, millisecond));
    this.isValid = isValid(this._date);
    this.timeString = this.toString();
  }