<commit_before>/******************************************
 * Form Handlers and page                 *
 * generators for TSSAA WebApp Fat Client *
 *****************************************/
$.fn.serializeObject = function () {
	var o = {};
	var a = this.serializeArray();

	$.each(a, function() {
		if (o[this.name] !== undefined) {
			if (!o[this.name].push) {
				o[this.name] = [o[this.name]];
			}
			o[this.name].push(this.value || '');
		} else {
			o[this.name] = this.value || '';
		}
	});
	return o;
};

function login_call(user_name, password) {
	var nonce = generateNonce(16);
	var created = getW3CDate(new Date());
	var digest = b64_sha1(created + password + nonce);

	var nonce64 = base64encode(nonce);

	var x_wsse_header =
		"UsernameToken Username=\""
			+ user_name + "\", PasswordDigest=\""
			+ digest + "\", Nonce=\""
			+ nonce64 + "\", Created=\""
			+ created + "\"\n";

	$.ajax("app_dev.php/login_check", {
		type: "POST",
		beforeSend: function (xhr) {xhr.setRequestHeader("KS-WSSE", "AH MAI GAWD ID'S HEDURS");},
		success: loginSuccess,
	});

	return false;
}

/**
 * AJAX convenience wrapper
 * @param uri target uri for request
 * @param args object comprised of args for ajax call
 */
function service_call(uri, args) {
	$.ajax(uri, {
		type: args.hasOwnProperty("request_params") ? "POST" : "GET",
		// JSON.stringify will return undefined if args.request_params is undef
		data: JSON.stringify(args.request_params),
		success: on_success,
		error: on_failure,
		complete: on_complete,
	});

	function on_success (response, textStatus, jqXHR) {
		console.log("log: on_success: " + textStatus);

		data = JSON.parse(response);

		if (data.status === "success") {
			// TODO check if payload prop
			args.on_success(data.payload);
		} else {
			// TODO exception definitions
			args.on_failure(textStatus, data.exception);
		}
	}

	function on_failure (jqXHR, textStatus, errorThrown) {
		console.log("log: on_failure: " + textStatus);

		if (args.on_failure) {
			args.on_failure(textStatus, errorThrown);
		} else {
			// Do nothing
		}
	}

	function on_complete (jqXHR, textStatus) {
		console.log("log: on_complete: " + textStatus);

		if (args.on_complete) {
			args.on_complete(jqXHR, textStatus);
		} else {
			// Do nothing
		}
	}
	return false;
}

/**
 * Login form ajax callback
 * TODO session management handled here?
 */
function loginSuccess(login_payload) {
	$("h2#options_welcome_banner strong").text(login_payload);
    $.mobile.changePage($("#options_page"), {
            transition: "slideup",
            reverse: true,
        });
}

/**
 * DB Dialog ajax success callback
 */
function popDBDialog(response) {
	$("#response").text("Success! New school added!");
    $.mobile.changePage("#db_confirm_dialog");
}

/**
 * School List response handler
 * generates ul of schools returned from DB
 */
function generateSchoolList(school_data) {
    var schools_html = [];

    for (school in school_data) {
        school = school_data[school];
        var button = 'Edit This School';

        var block = '

' +
            school.name + '

Phone: ' +
            school.phone + '

Address: ' +
            school.address + '
' + button + '
';
        schools_html.push(block);
    }

    $('div#school_list').html(schools_html.join(''));

    $('div#school_list').on('click', 'a.edit_school', function (e) {
                var index = $(this).attr("ks_school_id");
                var school = school_data[index];
                $.each($("form#edit_school_form input"), function() {
                        var key = $(this).attr("name");
                        $(this).attr("value", school[key]);
                    });
                editSchoolEntity(school);
            });

    $.mobile.changePage($("#school_list_page"));
};

function editSchoolEntity(school) {
    $("#edit_school_form").on("submit", function (e) {
		var form_data = $("#edit_school_form").serializeObject();
		if( !form_data.id){
			form_data.id = school.id;
		}

		service_call("app_dev.php/update_school", {
			request_params: form_data,
			on_success: function () {$.mobile.changePage("#school_list_page")}
		});

		return false;
	});

    $.mobile.changePage("#edit_school_dialog", {
            transistion: "pop"
            });

}

$(document).on("pageinit", function(e, obj) {
    /**
     * Login form handler
     */
    $("#login_page").on("submit", function(e, obj) {
		var user_name = $("#login_input").val();
		var password = $("#pass_input").val();

		login_call(user_name, password);

        return false;
    });

    /**
     * Add school form ajax handler
     */
    $('#add_school_submit').on('click', function(e, obj) {
        var  formData = $('#add_school_form').serializeObject();

		service_call("app_dev.php/add_school", {
			request_params: formData,
			on_success: popDBDialog
		});

        return false;
    });
});

/**
 * Get school list ajax handler
 */
$(document).on("pagebeforechange", function(e, obj) {
    var url= $.mobile.path.parseUrl(obj.toPage);

    if ( url.hash  === "#school_list_page") {
		service_call("app_dev.php/get_school_list", {
			on_success: generateSchoolList
		});

        e.preventDefault();
    };
});

<commit_msg>set lowercase x-wsse header<commit_after>/******************************************
 * Form Handlers and page                 *
 * generators for TSSAA WebApp Fat Client *
 *****************************************/
$.fn.serializeObject = function () {
	var o = {};
	var a = this.serializeArray();

	$.each(a, function() {
		if (o[this.name] !== undefined) {
			if (!o[this.name].push) {
				o[this.name] = [o[this.name]];
			}
			o[this.name].push(this.value || '');
		} else {
			o[this.name] = this.value || '';
		}
	});
	return o;
};

function login_call(user_name, password) {
	var nonce = generateNonce(16);
	var created = getW3CDate(new Date());
	var digest = b64_sha1(created + password + nonce);

	var nonce64 = base64encode(nonce);

	var x_wsse_header =
		"UsernameToken Username=\""
			+ user_name + "\", PasswordDigest=\""
			+ digest + "\", Nonce=\""
			+ nonce64 + "\", Created=\""
			+ created + "\"\n";

	$.ajax("app_dev.php/login_check", {
		type: "POST",
		beforeSend: function (xhr) {xhr.setRequestHeader("x-wsse", "AH MAI GAWD ID'S HEDURS");},
		success: loginSuccess,
	});

	return false;
}

/**
 * AJAX convenience wrapper
 * @param uri target uri for request
 * @param args object comprised of args for ajax call
 */
function service_call(uri, args) {
	$.ajax(uri, {
		type: args.hasOwnProperty("request_params") ? "POST" : "GET",
		// JSON.stringify will return undefined if args.request_params is undef
		data: JSON.stringify(args.request_params),
		success: on_success,
		error: on_failure,
		complete: on_complete,
	});

	function on_success (response, textStatus, jqXHR) {
		console.log("log: on_success: " + textStatus);

		data = JSON.parse(response);

		if (data.status === "success") {
			// TODO check if payload prop
			args.on_success(data.payload);
		} else {
			// TODO exception definitions
			args.on_failure(textStatus, data.exception);
		}
	}

	function on_failure (jqXHR, textStatus, errorThrown) {
		console.log("log: on_failure: " + textStatus);

		if (args.on_failure) {
			args.on_failure(textStatus, errorThrown);
		} else {
			// Do nothing
		}
	}

	function on_complete (jqXHR, textStatus) {
		console.log("log: on_complete: " + textStatus);

		if (args.on_complete) {
			args.on_complete(jqXHR, textStatus);
		} else {
			// Do nothing
		}
	}
	return false;
}

/**
 * Login form ajax callback
 * TODO session management handled here?
 */
function loginSuccess(login_payload) {
	$("h2#options_welcome_banner strong").text(login_payload);
    $.mobile.changePage($("#options_page"), {
            transition: "slideup",
            reverse: true,
        });
}

/**
 * DB Dialog ajax success callback
 */
function popDBDialog(response) {
	$("#response").text("Success! New school added!");
    $.mobile.changePage("#db_confirm_dialog");
}

/**
 * School List response handler
 * generates ul of schools returned from DB
 */
function generateSchoolList(school_data) {
    var schools_html = [];

    for (school in school_data) {
        school = school_data[school];
        var button = 'Edit This School';

        var block = '

' +
            school.name + '

Phone: ' +
            school.phone + '

Address: ' +
            school.address + '
' + button + '
';
        schools_html.push(block);
    }

    $('div#school_list').html(schools_html.join(''));

    $('div#school_list').on('click', 'a.edit_school', function (e) {
                var index = $(this).attr("ks_school_id");
                var school = school_data[index];
                $.each($("form#edit_school_form input"), function() {
                        var key = $(this).attr("name");
                        $(this).attr("value", school[key]);
                    });
                editSchoolEntity(school);
            });

    $.mobile.changePage($("#school_list_page"));
};

function editSchoolEntity(school) {
    $("#edit_school_form").on("submit", function (e) {
		var form_data = $("#edit_school_form").serializeObject();
		if( !form_data.id){
			form_data.id = school.id;
		}

		service_call("app_dev.php/update_school", {
			request_params: form_data,
			on_success: function () {$.mobile.changePage("#school_list_page")}
		});

		return false;
	});

    $.mobile.changePage("#edit_school_dialog", {
            transistion: "pop"
            });

}

$(document).on("pageinit", function(e, obj) {
    /**
     * Login form handler
     */
    $("#login_page").on("submit", function(e, obj) {
		var user_name = $("#login_input").val();
		var password = $("#pass_input").val();

		login_call(user_name, password);

        return false;
    });

    /**
     * Add school form ajax handler
     */
    $('#add_school_submit').on('click', function(e, obj) {
        var  formData = $('#add_school_form').serializeObject();

		service_call("app_dev.php/add_school", {
			request_params: formData,
			on_success: popDBDialog
		});

        return false;
    });
});

/**
 * Get school list ajax handler
 */
$(document).on("pagebeforechange", function(e, obj) {
    var url= $.mobile.path.parseUrl(obj.toPage);

    if ( url.hash  === "#school_list_page") {
		service_call("app_dev.php/get_school_list", {
			on_success: generateSchoolList
		});

        e.preventDefault();
    };
});

<|endoftext|>


<commit_before>const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const path = require('path');
const log = require('beautiful-logs')();

const app = express();
const server = http.Server(app);
const io = socketIO(server);

log.info('simple-chat is starting...');

// Exposes the folder frontend
app.use(express.static(path.join(__dirname, 'frontend', 'dist')));

io.on('connection', function(socket) {

  log.debug(`New user connected from IP Address: ${socket.request.connection.remoteAddress}`);

  // Prompt user for username clientside
  // Welcome user in chat with name
  socket.on('name', name => {

    log.debug(`User from ip address: ${socket.request.connection.remoteAddress} assigned a name: ${name}`);

    // Save the username and join timestamp
    socket.meta = {
      username: name,
      joinedAt: Date.now()
    };

    // Emit a join event
    io.emit('join', {
      user: socket.meta.username,
      time: socket.meta.joinedAt
    });

    //New message
    socket.on('msg', msg => {

      log.debug(`${name} (${socket.request.connection.remoteAddress}) has sent a new message: ${msg}`);

      const timestamp = Date.now();
      // Send the message to all users
      io.emit('msg', {
        user: socket.meta.username,
        msg: msg,
        time: timestamp
      });
    });

    // Handle disconnect
    socket.on('disconnect', reason => {

      log.debug(`${name} (${socket.request.connection.remoteAddress}) has been disconnected. Reason: ${reason}`);

      const timestamp = Date.now();
      // Emit a leave event
      io.emit('leave', {
        user: socket.meta.username,
        time: timestamp,
        duration: timestamp - socket.meta.joinedAt
      });
    });
  });
});

server.on('error', error => {
  log.err(`Error while starting the server`, error);
});

server.listen(process.env.PORT || 80, () => {
  log.info(`Server is listening on port: ${server.address().port}`);
});
<commit_msg>Clean up code<commit_after>const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const path = require('path');
const log = require('beautiful-logs')();

const app = express();
const server = http.Server(app);
const io = socketIO(server);

log.info('simple-chat is starting...');

// Expose the frontend
app.use(express.static(path.join(__dirname, 'frontend', 'dist')));

io.on('connection', socket => {
  log.debug(`New user connected from IP Address: ${socket.request.connection.remoteAddress}`);

  // Prompt user for username clientside
  // Welcome user in chat with name
  socket.on('name', name => {
    log.debug(`User from ip address: ${socket.request.connection.remoteAddress} assigned a name: ${name}`);

    // Save the username and join timestamp
    socket.meta = {
      username: name,
      joinedAt: Date.now()
    };

    // Emit a join event
    io.emit('join', {
      user: socket.meta.username,
      time: socket.meta.joinedAt
    });

    // New message
    socket.on('msg', msg => {
      log.debug(`${name} (${socket.request.connection.remoteAddress}) has sent a new message: ${msg}`);

      const timestamp = Date.now();
      // Send the message to all users
      io.emit('msg', {
        user: socket.meta.username,
        msg: msg,
        time: timestamp
      });
    });

    // Handle disconnect
    socket.on('disconnect', reason => {
      log.debug(`${name} (${socket.request.connection.remoteAddress}) has been disconnected. Reason: ${reason}`);

      const timestamp = Date.now();
      // Emit a leave event
      io.emit('leave', {
        user: socket.meta.username,
        time: timestamp,
        duration: timestamp - socket.meta.joinedAt
      });
    });
  });
});

server.on('error', error => log.err(`Error while starting the server`, error));
server.listen(process.env.PORT || 80, () => log.info(`Server is listening on port: ${server.address().port}`));
<|endoftext|>


<commit_before>// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
// License: New BSD License
// Reference: http://dev.w3.org/html5/websockets/
// Reference: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10

(function() {

  if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) return;

  var logger;
  if (window.WEB_SOCKET_LOGGER) {
    logger = WEB_SOCKET_LOGGER;
  } else if (window.console && window.console.log && window.console.error) {
    // In some environment, console is defined but console.log or console.error is missing.
    logger = window.console;
  } else {
    logger = {log: function(){ }, error: function(){ }};
  }

  // swfobject.hasFlashPlayerVersion("10.0.0") doesn't work with Gnash.
  if (swfobject.getFlashPlayerVersion().major < 10) {
    logger.error("Flash Player >= 10.0.0 is required.");
    return;
  }
  if (location.protocol == "file:") {
    logger.error(
      "WARNING: web-socket-js doesn't work in file:///... URL " +
      "unless you set Flash Security Settings properly. " +
      "Open the page via Web server i.e. http://...");
  }

  /**
   * This class represents a faux web socket.
   * @param {string} url
   * @param {array or string} protocols
   * @param {string} proxyHost
   * @param {int} proxyPort
   * @param {string} headers
   */
  WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
    var self = this;
    self.__id = WebSocket.__nextId++;
    WebSocket.__instances[self.__id] = self;
    self.readyState = WebSocket.CONNECTING;
    self.bufferedAmount = 0;
    self.__events = {};
    if (!protocols) {
      protocols = [];
    } else if (typeof protocols == "string") {
      protocols = [protocols];
    }
    // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
    // Otherwise, when onopen fires immediately, onopen is called before it is set.
    self.__createTask = setTimeout(function() {
      WebSocket.__addTask(function() {
        self.__createTask = null;
        WebSocket.__flash.create(
            self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
      });
    }, 0);
  };

  /**
   * Send data to the web socket.
   * @param {string} data  The data to send to the socket.
   * @return {boolean}  True for success, false for failure.
   */
  WebSocket.prototype.send = function(data) {
    if (this.readyState == WebSocket.CONNECTING) {
      throw "INVALID_STATE_ERR: Web Socket connection has not been established";
    }
    // We use encodeURIComponent() here, because FABridge doesn't work if
    // the argument includes some characters. We don't use escape() here
    // because of this:
    // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
    // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
    // preserve all Unicode characters either e.g. "\uffff" in Firefox.
    // Note by wtritch: Hopefully this will not be necessary using ExternalInterface.  Will require
    // additional testing.
    var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
    if (result < 0) { // success
      return true;
    } else {
      this.bufferedAmount += result;
      return false;
    }
  };

  /**
   * Close this web socket gracefully.
   */
  WebSocket.prototype.close = function() {
    if (this.__createTask) {
        clearTimeout(this.__createTask);
        this.__createTask = null;
        this.readyState = WebSocket.CLOSED;
        return;
    }
    if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
      return;
    }
    this.readyState = WebSocket.CLOSING;
    WebSocket.__flash.close(this.__id);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture
   * @return void
   */
  WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
    if (!(type in this.__events)) {
      this.__events[type] = [];
    }
    this.__events[type].push(listener);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture
   * @return void
   */
  WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
    if (!(type in this.__events)) return;
    var events = this.__events[type];
    for (var i = events.length - 1; i >= 0; --i) {
      if (events[i] === listener) {
        events.splice(i, 1);
        break;
      }
    }
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {Event} event
   * @return void
   */
  WebSocket.prototype.dispatchEvent = function(event) {
    var events = this.__events[event.type] || [];
    for (var i = 0; i < events.length; ++i) {
      events[i](event);
    }
    var handler = this["on" + event.type];
    if (handler) handler.apply(this, [event]);
  };

  /**
   * Handles an event from Flash.
   * @param {Object} flashEvent
   */
  WebSocket.prototype.__handleEvent = function(flashEvent) {

    if ("readyState" in flashEvent) {
      this.readyState = flashEvent.readyState;
    }
    if ("protocol" in flashEvent) {
      this.protocol = flashEvent.protocol;
    }

    var jsEvent;
    if (flashEvent.type == "open" || flashEvent.type == "error") {
      jsEvent = this.__createSimpleEvent(flashEvent.type);
    } else if (flashEvent.type == "close") {
      jsEvent = this.__createSimpleEvent("close");
      jsEvent.wasClean = flashEvent.wasClean ? true : false;
      jsEvent.code = flashEvent.code;
      jsEvent.reason = flashEvent.reason;
    } else if (flashEvent.type == "message") {
      var data = decodeURIComponent(flashEvent.message);
      jsEvent = this.__createMessageEvent("message", data);
    } else {
      throw "unknown event type: " + flashEvent.type;
    }

    this.dispatchEvent(jsEvent);

  };

  WebSocket.prototype.__createSimpleEvent = function(type) {
    if (document.createEvent && window.Event) {
      var event = document.createEvent("Event");
      event.initEvent(type, false, false);
      return event;
    } else {
      return {type: type, bubbles: false, cancelable: false};
    }
  };

  WebSocket.prototype.__createMessageEvent = function(type, data) {
    if (document.createEvent && window.MessageEvent && !window.opera) {
      var event = document.createEvent("MessageEvent");
      event.initMessageEvent("message", false, false, data, null, null, window, null);
      return event;
    } else {
      // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
      return {type: type, data: data, bubbles: false, cancelable: false};
    }
  };

  /**
   * Define the WebSocket readyState enumeration.
   */
  WebSocket.CONNECTING = 0;
  WebSocket.OPEN = 1;
  WebSocket.CLOSING = 2;
  WebSocket.CLOSED = 3;

  WebSocket.__flash = null;
  WebSocket.__instances = {};
  WebSocket.__tasks = [];
  WebSocket.__nextId = 0;

  /**
   * Load a new flash security policy file.
   * @param {string} url
   */
  WebSocket.loadFlashPolicyFile = function(url){
    WebSocket.__addTask(function() {
      WebSocket.__flash.loadManualPolicyFile(url);
    });
  };

  /**
   * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
   */
  WebSocket.__initialize = function() {
    if (WebSocket.__flash) return;

    if (WebSocket.__swfLocation) {
      // For backword compatibility.
      window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
    }
    if (!window.WEB_SOCKET_SWF_LOCATION) {
      logger.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
      return;
    }
    if (!window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR &&
        !WEB_SOCKET_SWF_LOCATION.match(/(^|\/)WebSocketMainInsecure\.swf(\?.*)?$/) &&
        WEB_SOCKET_SWF_LOCATION.match(/^\w+:\/\/([^\/]+)/)) {
      var swfHost = RegExp.$1;
      if (location.host != swfHost) {
        logger.error(
            "[WebSocket] You must host HTML and WebSocketMain.swf in the same host " +
            "('" + location.host + "' != '" + swfHost + "'). " +
            "See also 'How to host HTML file and SWF file in different domains' section " +
            "in README.md. If you use WebSocketMainInsecure.swf, you can suppress this message " +
            "by WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;");
      }
    }
    var container = document.createElement("div");
    container.id = "webSocketContainer";
    // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
    // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
    // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
    // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
    // the best we can do as far as we know now.
    container.style.position = "absolute";
    if (WebSocket.__isFlashLite()) {
      container.style.left = "0px";
      container.style.top = "0px";
    } else {
      container.style.left = "-100px";
      container.style.top = "-100px";
    }
    var holder = document.createElement("div");
    holder.id = "webSocketFlash";
    container.appendChild(holder);
    document.body.appendChild(container);
    // See this article for hasPriority:
    // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
    swfobject.embedSWF(
      WEB_SOCKET_SWF_LOCATION,
      "webSocketFlash",
      "1" /* width */,
      "1" /* height */,
      "10.0.0" /* SWF version */,
      null,
      null,
      {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
      null,
      function(e) {
        if (!e.success) {
          logger.error("[WebSocket] swfobject.embedSWF failed");
        }
      });
  };

  /**
   * Called by Flash to notify JS that it's fully loaded and ready
   * for communication.
   */
  WebSocket.__onFlashInitialized = function() {
    // We need to set a timeout here to avoid round-trip calls
    // to flash during the initialization process.
    setTimeout(function() {
      WebSocket.__flash = document.getElementById("webSocketFlash");
      WebSocket.__flash.setCallerUrl(location.href);
      WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
      for (var i = 0; i < WebSocket.__tasks.length; ++i) {
        WebSocket.__tasks[i]();
      }
      WebSocket.__tasks = [];
    }, 0);
  };

  /**
   * Called by Flash to notify WebSockets events are fired.
   */
  WebSocket.__onFlashEvent = function() {
    setTimeout(function() {
      try {
        // Gets events using receiveEvents() instead of getting it from event object
        // of Flash event. This is to make sure to keep message order.
        // It seems sometimes Flash events don't arrive in the same order as they are sent.
        var events = WebSocket.__flash.receiveEvents();
        for (var i = 0; i < events.length; ++i) {
          WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
        }
      } catch (e) {
        logger.error(e);
      }
    }, 0);
    return true;
  };

  // Called by Flash.
  WebSocket.__log = function(message) {
    logger.log(decodeURIComponent(message));
  };

  // Called by Flash.
  WebSocket.__error = function(message) {
    logger.error(decodeURIComponent(message));
  };

  WebSocket.__addTask = function(task) {
    if (WebSocket.__flash) {
      task();
    } else {
      WebSocket.__tasks.push(task);
    }
  };

  /**
   * Test if the browser is running flash lite.
   * @return {boolean} True if flash lite is running, false otherwise.
   */
  WebSocket.__isFlashLite = function() {
    if (!window.navigator || !window.navigator.mimeTypes) {
      return false;
    }
    var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
    if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
      return false;
    }
    return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
  };

  if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
    if (window.addEventListener) {
      window.addEventListener("load", function(){
        WebSocket.__initialize();
      }, false);
    } else {
      window.attachEvent("onload", function(){
        WebSocket.__initialize();
      });
    }
  }

})();
<commit_msg>Initializing automatically when web_socket.js is dynamically loaded. Using DOMContentLoaded to initialize earlier when available.<commit_after>// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
// License: New BSD License
// Reference: http://dev.w3.org/html5/websockets/
// Reference: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10

(function() {

  if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) return;

  var logger;
  if (window.WEB_SOCKET_LOGGER) {
    logger = WEB_SOCKET_LOGGER;
  } else if (window.console && window.console.log && window.console.error) {
    // In some environment, console is defined but console.log or console.error is missing.
    logger = window.console;
  } else {
    logger = {log: function(){ }, error: function(){ }};
  }

  // swfobject.hasFlashPlayerVersion("10.0.0") doesn't work with Gnash.
  if (swfobject.getFlashPlayerVersion().major < 10) {
    logger.error("Flash Player >= 10.0.0 is required.");
    return;
  }
  if (location.protocol == "file:") {
    logger.error(
      "WARNING: web-socket-js doesn't work in file:///... URL " +
      "unless you set Flash Security Settings properly. " +
      "Open the page via Web server i.e. http://...");
  }

  /**
   * This class represents a faux web socket.
   * @param {string} url
   * @param {array or string} protocols
   * @param {string} proxyHost
   * @param {int} proxyPort
   * @param {string} headers
   */
  WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
    var self = this;
    self.__id = WebSocket.__nextId++;
    WebSocket.__instances[self.__id] = self;
    self.readyState = WebSocket.CONNECTING;
    self.bufferedAmount = 0;
    self.__events = {};
    if (!protocols) {
      protocols = [];
    } else if (typeof protocols == "string") {
      protocols = [protocols];
    }
    // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
    // Otherwise, when onopen fires immediately, onopen is called before it is set.
    self.__createTask = setTimeout(function() {
      WebSocket.__addTask(function() {
        self.__createTask = null;
        WebSocket.__flash.create(
            self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
      });
    }, 0);
  };

  /**
   * Send data to the web socket.
   * @param {string} data  The data to send to the socket.
   * @return {boolean}  True for success, false for failure.
   */
  WebSocket.prototype.send = function(data) {
    if (this.readyState == WebSocket.CONNECTING) {
      throw "INVALID_STATE_ERR: Web Socket connection has not been established";
    }
    // We use encodeURIComponent() here, because FABridge doesn't work if
    // the argument includes some characters. We don't use escape() here
    // because of this:
    // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
    // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
    // preserve all Unicode characters either e.g. "\uffff" in Firefox.
    // Note by wtritch: Hopefully this will not be necessary using ExternalInterface.  Will require
    // additional testing.
    var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
    if (result < 0) { // success
      return true;
    } else {
      this.bufferedAmount += result;
      return false;
    }
  };

  /**
   * Close this web socket gracefully.
   */
  WebSocket.prototype.close = function() {
    if (this.__createTask) {
        clearTimeout(this.__createTask);
        this.__createTask = null;
        this.readyState = WebSocket.CLOSED;
        return;
    }
    if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
      return;
    }
    this.readyState = WebSocket.CLOSING;
    WebSocket.__flash.close(this.__id);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture
   * @return void
   */
  WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
    if (!(type in this.__events)) {
      this.__events[type] = [];
    }
    this.__events[type].push(listener);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture
   * @return void
   */
  WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
    if (!(type in this.__events)) return;
    var events = this.__events[type];
    for (var i = events.length - 1; i >= 0; --i) {
      if (events[i] === listener) {
        events.splice(i, 1);
        break;
      }
    }
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {Event} event
   * @return void
   */
  WebSocket.prototype.dispatchEvent = function(event) {
    var events = this.__events[event.type] || [];
    for (var i = 0; i < events.length; ++i) {
      events[i](event);
    }
    var handler = this["on" + event.type];
    if (handler) handler.apply(this, [event]);
  };

  /**
   * Handles an event from Flash.
   * @param {Object} flashEvent
   */
  WebSocket.prototype.__handleEvent = function(flashEvent) {

    if ("readyState" in flashEvent) {
      this.readyState = flashEvent.readyState;
    }
    if ("protocol" in flashEvent) {
      this.protocol = flashEvent.protocol;
    }

    var jsEvent;
    if (flashEvent.type == "open" || flashEvent.type == "error") {
      jsEvent = this.__createSimpleEvent(flashEvent.type);
    } else if (flashEvent.type == "close") {
      jsEvent = this.__createSimpleEvent("close");
      jsEvent.wasClean = flashEvent.wasClean ? true : false;
      jsEvent.code = flashEvent.code;
      jsEvent.reason = flashEvent.reason;
    } else if (flashEvent.type == "message") {
      var data = decodeURIComponent(flashEvent.message);
      jsEvent = this.__createMessageEvent("message", data);
    } else {
      throw "unknown event type: " + flashEvent.type;
    }

    this.dispatchEvent(jsEvent);

  };

  WebSocket.prototype.__createSimpleEvent = function(type) {
    if (document.createEvent && window.Event) {
      var event = document.createEvent("Event");
      event.initEvent(type, false, false);
      return event;
    } else {
      return {type: type, bubbles: false, cancelable: false};
    }
  };

  WebSocket.prototype.__createMessageEvent = function(type, data) {
    if (document.createEvent && window.MessageEvent && !window.opera) {
      var event = document.createEvent("MessageEvent");
      event.initMessageEvent("message", false, false, data, null, null, window, null);
      return event;
    } else {
      // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
      return {type: type, data: data, bubbles: false, cancelable: false};
    }
  };

  /**
   * Define the WebSocket readyState enumeration.
   */
  WebSocket.CONNECTING = 0;
  WebSocket.OPEN = 1;
  WebSocket.CLOSING = 2;
  WebSocket.CLOSED = 3;

  WebSocket.__initialized = false;
  WebSocket.__flash = null;
  WebSocket.__instances = {};
  WebSocket.__tasks = [];
  WebSocket.__nextId = 0;

  /**
   * Load a new flash security policy file.
   * @param {string} url
   */
  WebSocket.loadFlashPolicyFile = function(url){
    WebSocket.__addTask(function() {
      WebSocket.__flash.loadManualPolicyFile(url);
    });
  };

  /**
   * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
   */
  WebSocket.__initialize = function() {

    if (WebSocket.__initialized) return;
    WebSocket.__initialized = true;

    if (WebSocket.__swfLocation) {
      // For backword compatibility.
      window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
    }
    if (!window.WEB_SOCKET_SWF_LOCATION) {
      logger.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
      return;
    }
    if (!window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR &&
        !WEB_SOCKET_SWF_LOCATION.match(/(^|\/)WebSocketMainInsecure\.swf(\?.*)?$/) &&
        WEB_SOCKET_SWF_LOCATION.match(/^\w+:\/\/([^\/]+)/)) {
      var swfHost = RegExp.$1;
      if (location.host != swfHost) {
        logger.error(
            "[WebSocket] You must host HTML and WebSocketMain.swf in the same host " +
            "('" + location.host + "' != '" + swfHost + "'). " +
            "See also 'How to host HTML file and SWF file in different domains' section " +
            "in README.md. If you use WebSocketMainInsecure.swf, you can suppress this message " +
            "by WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;");
      }
    }
    var container = document.createElement("div");
    container.id = "webSocketContainer";
    // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
    // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
    // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
    // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
    // the best we can do as far as we know now.
    container.style.position = "absolute";
    if (WebSocket.__isFlashLite()) {
      container.style.left = "0px";
      container.style.top = "0px";
    } else {
      container.style.left = "-100px";
      container.style.top = "-100px";
    }
    var holder = document.createElement("div");
    holder.id = "webSocketFlash";
    container.appendChild(holder);
    document.body.appendChild(container);
    // See this article for hasPriority:
    // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
    swfobject.embedSWF(
      WEB_SOCKET_SWF_LOCATION,
      "webSocketFlash",
      "1" /* width */,
      "1" /* height */,
      "10.0.0" /* SWF version */,
      null,
      null,
      {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
      null,
      function(e) {
        if (!e.success) {
          logger.error("[WebSocket] swfobject.embedSWF failed");
        }
      }
    );

  };

  /**
   * Called by Flash to notify JS that it's fully loaded and ready
   * for communication.
   */
  WebSocket.__onFlashInitialized = function() {
    // We need to set a timeout here to avoid round-trip calls
    // to flash during the initialization process.
    setTimeout(function() {
      WebSocket.__flash = document.getElementById("webSocketFlash");
      WebSocket.__flash.setCallerUrl(location.href);
      WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
      for (var i = 0; i < WebSocket.__tasks.length; ++i) {
        WebSocket.__tasks[i]();
      }
      WebSocket.__tasks = [];
    }, 0);
  };

  /**
   * Called by Flash to notify WebSockets events are fired.
   */
  WebSocket.__onFlashEvent = function() {
    setTimeout(function() {
      try {
        // Gets events using receiveEvents() instead of getting it from event object
        // of Flash event. This is to make sure to keep message order.
        // It seems sometimes Flash events don't arrive in the same order as they are sent.
        var events = WebSocket.__flash.receiveEvents();
        for (var i = 0; i < events.length; ++i) {
          WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
        }
      } catch (e) {
        logger.error(e);
      }
    }, 0);
    return true;
  };

  // Called by Flash.
  WebSocket.__log = function(message) {
    logger.log(decodeURIComponent(message));
  };

  // Called by Flash.
  WebSocket.__error = function(message) {
    logger.error(decodeURIComponent(message));
  };

  WebSocket.__addTask = function(task) {
    if (WebSocket.__flash) {
      task();
    } else {
      WebSocket.__tasks.push(task);
    }
  };

  /**
   * Test if the browser is running flash lite.
   * @return {boolean} True if flash lite is running, false otherwise.
   */
  WebSocket.__isFlashLite = function() {
    if (!window.navigator || !window.navigator.mimeTypes) {
      return false;
    }
    var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
    if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
      return false;
    }
    return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
  };

  if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
    var init = function(){
      WebSocket.__initialize();
    };
    if (document.readyState == "complete") {
      // Document is already loaded.
      init();
    } else if (window.addEventListener) {
      // This fires earlier but is not supported by all browsers.
      document.addEventListener("DOMContentLoaded", init, false);
      // This is supported by all browsers.
      window.addEventListener("load", init, false);
    } else {
      window.attachEvent("onload", init);
    }
  }

})();
<|endoftext|>


<commit_before>(function () {
    var streaming = {};

    _.extend(streaming, {
        subscriptions: {},
        callbacks: {},

        setUser: function (user_id) {
            this.user_id = user_id;
        },

        setup: function setup(socket) {
            this.socket = socket;

            this.user_id = 0;
            this.db = new PouchDB('streaming.io', {auto_compaction: true});
            this.db.allDocs({include_docs: true}, _.bind(function (err, response) {
                var deletes = [];

                if (!err && response) {
                    var now = Date.now();
                    _.each(response.rows, function (row) {
                        if (row.doc.expire && row.doc.expire > now) {
                            return;
                        }
                        row.doc._deleted = true;
                        deletes.push(row.doc);
                    });
                }

                this.db.bulkDocs({
                    docs: deletes
                }, _.bind(function () {
                    this.db.compact();
                }, this));
            }, this));

            socket.on('connect', _.bind(function() {
                this.connect(socket);
            }, this));

            socket.on('disconnect', _.bind(function () {
                this.disconnect();
            }, this));

            socket.on('stream', _.bind(function (message) {
                this.sync(message);
            }, this));
        },

        sync: function sync(message) {
            var item = this.subscriptions[message.url];
            var data = this.uncompress(message.data);
            item.cache = data;
            this.apply(data, item.clients);

            this.db.put({
                _id: message.url,
                _rev: item.revision,
                hash: message.hash,
                data: message.data,
                user_id: this.user_id,
                expire: new Date(new Date().getTime() + 2 * 60 * 60 * 1000)
            });
        },

        apply: function apply(data, items) {
            _.each(items, function (model) {
                if (!model.streaming) {
                    return;
                }

                var initial = model.streaming.options.initial;
                model.streaming.options.initial = false;

                if (model.models.length > 0) {
                    var idAttribute = model.models[0].idAttribute;
                    var equals = false;
                    do {
                        if (initial === true) {
                            break;
                        }

                        if (model.models.length != data.length) {
                            break;
                        }

                        var local = _.pluck(model.models, "id");
                        var remote = _.pluck(data, idAttribute)

                        var i = 0, n = model.models.length;
                        for (;i !=n; ++i) {
                            if (local[i] != remote[i]) {
                                break;
                            }
                        }
                        if (i != n) {
                            break;
                        }
                        equals = true;
                    } while (0);
                    if (equals) {
                        model.forEach(function (current, index) {
                            current.set(current.parse(data[index]));
                        });
                        model.trigger('sync', model, data, {});
                    } else {
                        model.reset(model.parse(data));
                    }

                } else {
                    model.reset(model.parse(data));
                }
            });
        },

        emit: function emit(url, item) {
            item.updating = true;

            var message = {
                url: url
            };

            this.db.get(url, _.bind(function (err, doc) {
                if (!err && doc) {
                    message.hash = doc.hash;
                    item.revision = doc._rev;

                    if ((doc.user_id == this.user_id) && item.options.precache) {
                        item.cache = this.uncompress(doc.data);
                        this.apply(item.cache, item.clients);
                    }
                }

                this.send("stream", message, _.bind(function (err, response) {
                    delete item.updating;

                    if (err) {
                        return;
                    }

                    var data;
                    if (response.hash == message.hash) {
                        var limit = new Date().getTime() + 1 * 60 * 60 * 1000;
                        if (doc.expire < limit || (doc.user_id != this.user_id)) {
                            this.db.put({
                                _id: url,
                                _rev: item.revision,
                                hash: message.hash,
                                data: doc.data,
                                user_id: this.user_id,
                                expire: new Date(new Date().getTime() + 2 * 60 * 60 * 1000)
                            });
                        }

                        if (!item.cache) {
                            item.cache = data = this.uncompress(doc.data);
                        }
                    } else {
                        item.cache = data = this.uncompress(response.data);
                        this.db.put({
                            _id: url,
                            _rev: item.revision,
                            hash: response.hash,
                            data: response.data,
                            user_id: this.user_id,
                            expire: new Date(new Date().getTime() + 2 * 60 * 60 * 1000)
                        });
                    }

                    if (data) {
                        this.apply(data, item.clients);
                    }
                }, this));

            }, this));
        },

        connect: function (socket) {
            this.socket = socket;

            _.each(this.subscriptions, function (item, url) {
                this.emit(url, item);
            }, this);
        },

        disconnect: function () {
            _.each(this.subscriptions, function (item) {
                delete item.cache;
                if (item.timeout) {
                    clearTimeout(item.timeout);
                    delete item.timeout;
                }
            });

            _.each(this.callbacks, function (callback, id) {
                callback("Disconnected");
            });
            this.callbacks = {};

            delete this.socket;
        },

        add: function (target, options) {
            var url = target.url();
            if (target.streaming) {
                return;
            }

            options = options ? _.clone(options) : {};
            _.defaults(options, {
                "precache": target.hasOwnProperty("precache") && !!target.precache,
                "initial": true
            });

            var item = this.subscriptions[url];
            if (!_.isUndefined(item)) {
                if (item.timeout) {
                    clearTimeout(item.timeout);
                    delete item.timeout;
                }

                target.streaming = { url: url, options: options };
                item.clients[target.cid] = target;

                if (item.cache) {
                    this.apply(item.cache, [target]);
                }
                return;
            } else {
                item = { clients: {}, options: options };
                item.clients[target.cid] = target;

                target.streaming = { url: url, options: options };
                this.subscriptions[url] = item;
            }

            if (_.isUndefined(this.socket)) {
                return;
            }

            this.emit(url, item);
        },

        remove: function (target) {
            if (target.streaming) {
                var url = target.streaming.url;
                var item = this.subscriptions[url];

                delete item.clients[target.cid];
                if (_.keys(item.clients).length == 0) {
                    item.timeout = setTimeout(_.bind(function () {
                        this.socket.emit("unstream", { url: url }, function (err) {});
                        delete this.subscriptions[url];
                    }, this), 5000);
                }

                delete target.streaming;
            }
        },

        send: function (type, message, callback) {
            if (!this.socket) {
                _.defer(function () {
                    callback("No connection");
                });
                return;
            }

            var id = _.uniqueId('cb');
            this.callbacks[id] = callback;

            this.socket.emit(type, message, _.bind(function (err, response) {
                delete this.callbacks[id];
                callback(err, this.uncompress(response));
            }, this));
        },

        uncompress: function (data) {
            if (!_.isObject(data)) {
                return data;
            }

            var objectKeys = _.keys(data);

            if ((objectKeys.length != 2) || (_.without(objectKeys, 'keys', 'rows').length != 0)) {
                return data;
            }

            var keys = data.keys;
            var uncompressed = _.map(data.rows, function (row) {
                return _.object(keys, row);
            });

            return uncompressed;
        }
    });

    var sync = function (method, model, options) {
        var message = {
            method: method,
            url: model.url(),
            cid: model.cid,
            data: options.arguments || model.toJSON() || {},
            emit: options.emit
        };

        streaming.send("sync", message, function (err, response) {
            if (err) {
                options.error(err);
            } else {
                options.success(response);
            }
        });
    };

    streaming.Model = Backbone.Model.extend({
        stream: function () {
            console.trace();
            alert("Streaming models is not currently supported");
        },

        unstream: function () {},

        incrementVersion: function () {
            var versionName = this.versionAttribute;
            if (!_.isUndefined(versionName)) {
                this.set(versionName, this.parseVersionNumber(this.get(versionName)) + 1, {silent: true});
            }
        },

        parseVersionNumber: function (versionNumber) {
            return _.isFinite(versionNumber) ? versionNumber : 0;
        },

        parse: function (resp) {
            var versionName = this.versionAttribute;
            if (_.isObject(resp) && !_.isUndefined(versionName)) {
                var localVersion = this.parseVersionNumber(this.get(versionName));
                var remoteVersion = this.parseVersionNumber(resp[versionName]);

                if (localVersion > remoteVersion) {
                    return {};
                }
            }
            return resp;
        },

        emit: function(method, args, options) {
            if (_.isUndefined(options)) {
                options = args ? _.clone(args) : {};
                args = undefined;
            } else {
                options = options ? _.clone(options) : {};
            }

            var model = this;

            var triggerEmit = _.bind(function() {
                model.trigger('emit emit:' + method, model, options);
            }, this);

            options.emit = method;
            options.arguments = args;

            var success = options.success;
            options.success = function (resp) {
                if (success) success(model, resp, options);
                if (options.wait) triggerEmit();
            };
            var error = options.error;
            options.error = function (resp) {
                if (error) error(model, resp, options);
                model.trigger('error', model, resp, options);
            }

            var xhr = this.sync('emit', this, options);
            if (!options.wait) triggerEmit();
            return xhr;
        },

        sync: sync
    });

    streaming.Collection = Backbone.Collection.extend({
        stream: function (options) {
            options = options || {};
            if (_.isUndefined(this.cid)) {
                this.cid = _.uniqueId('coll');
            }

            _.defer(_.bind(function () {
                streaming.add(this, options);
            }, this));
        },

        unstream: function () {
            streaming.remove(this);
        },

        emit: function (method, args, options) {
            if (_.isUndefined(options)) {
                options = args ? _.clone(args) : {};
                args = undefined;
            } else {
                options = options ? _.clone(options) : {};
            }

            var model = this;

            var triggerEmit = _.bind(function() {
                model.trigger('emit emit:' + method, model, options);
            }, this);

            options.emit = method;
            options.arguments = args;

            var success = options.success;
            options.success = function (resp) {
                if (success) success(model, resp, options);
                if (options.wait) triggerEmit();
            };
            var error = options.error;
            options.error = function (resp) {
                if (error) error(model, resp, options);
                model.trigger('error', model, resp, options);
            }

            var xhr = this.sync('emit', this, options);
            if (!options.wait) triggerEmit();
            return xhr;
        },

        sync: sync
    });

    window.Streaming = streaming;
})();

<commit_msg>New document revision is now properly stored back in item (removes document update conflict exception)<commit_after>(function () {
    var streaming = {};

    _.extend(streaming, {
        subscriptions: {},
        callbacks: {},

        setUser: function (user_id) {
            this.user_id = user_id;
        },

        setup: function setup(socket) {
            this.socket = socket;

            this.user_id = 0;
            this.db = new PouchDB('streaming.io', {auto_compaction: true});
            this.db.allDocs({include_docs: true}, _.bind(function (err, response) {
                var deletes = [];

                if (!err && response) {
                    var now = Date.now();
                    _.each(response.rows, function (row) {
                        if (row.doc.expire && row.doc.expire > now) {
                            return;
                        }
                        row.doc._deleted = true;
                        deletes.push(row.doc);
                    });
                }

                this.db.bulkDocs({
                    docs: deletes
                }, _.bind(function () {
                    this.db.compact();
                }, this));
            }, this));

            socket.on('connect', _.bind(function() {
                this.connect(socket);
            }, this));

            socket.on('disconnect', _.bind(function () {
                this.disconnect();
            }, this));

            socket.on('stream', _.bind(function (message) {
                this.sync(message);
            }, this));
        },

        sync: function sync(message) {
            var item = this.subscriptions[message.url];
            var data = this.uncompress(message.data);
            item.cache = data;
            this.apply(data, item.clients);

            this.db.put({
                _id: message.url,
                _rev: item.revision,
                hash: message.hash,
                data: message.data,
                user_id: this.user_id,
                expire: new Date(new Date().getTime() + 2 * 60 * 60 * 1000)
            }).then(function (response) {
                item.revision = response.rev;
            });
        },

        apply: function apply(data, items) {
            _.each(items, function (model) {
                if (!model.streaming) {
                    return;
                }

                var initial = model.streaming.options.initial;
                model.streaming.options.initial = false;

                if (model.models.length > 0) {
                    var idAttribute = model.models[0].idAttribute;
                    var equals = false;
                    do {
                        if (initial === true) {
                            break;
                        }

                        if (model.models.length != data.length) {
                            break;
                        }

                        var local = _.pluck(model.models, "id");
                        var remote = _.pluck(data, idAttribute)

                        var i = 0, n = model.models.length;
                        for (;i !=n; ++i) {
                            if (local[i] != remote[i]) {
                                break;
                            }
                        }
                        if (i != n) {
                            break;
                        }
                        equals = true;
                    } while (0);
                    if (equals) {
                        model.forEach(function (current, index) {
                            current.set(current.parse(data[index]));
                        });
                        model.trigger('sync', model, data, {});
                    } else {
                        model.reset(model.parse(data));
                    }

                } else {
                    model.reset(model.parse(data));
                }
            });
        },

        emit: function emit(url, item) {
            item.updating = true;

            var message = {
                url: url
            };

            this.db.get(url, _.bind(function (err, doc) {
                if (!err && doc) {
                    message.hash = doc.hash;
                    item.revision = doc._rev;

                    if ((doc.user_id == this.user_id) && item.options.precache) {
                        item.cache = this.uncompress(doc.data);
                        this.apply(item.cache, item.clients);
                    }
                }

                this.send("stream", message, _.bind(function (err, response) {
                    delete item.updating;

                    if (err) {
                        return;
                    }

                    var data;
                    if (response.hash == message.hash) {
                        var limit = new Date().getTime() + 1 * 60 * 60 * 1000;
                        if (doc.expire < limit || (doc.user_id != this.user_id)) {
                            this.db.put({
                                _id: url,
                                _rev: item.revision,
                                hash: message.hash,
                                data: doc.data,
                                user_id: this.user_id,
                                expire: new Date(new Date().getTime() + 2 * 60 * 60 * 1000)
                            }).then(function (response) {
                                item.revision = response.rev;
                            });
                        }

                        if (!item.cache) {
                            item.cache = data = this.uncompress(doc.data);
                        }
                    } else {
                        item.cache = data = this.uncompress(response.data);
                        this.db.put({
                            _id: url,
                            _rev: item.revision,
                            hash: response.hash,
                            data: response.data,
                            user_id: this.user_id,
                            expire: new Date(new Date().getTime() + 2 * 60 * 60 * 1000)
                        }).then(function (response) {
                            item.revision = response.rev;
                        });
                    }

                    if (data) {
                        this.apply(data, item.clients);
                    }
                }, this));

            }, this));
        },

        connect: function (socket) {
            this.socket = socket;

            _.each(this.subscriptions, function (item, url) {
                this.emit(url, item);
            }, this);
        },

        disconnect: function () {
            _.each(this.subscriptions, function (item) {
                delete item.cache;
                if (item.timeout) {
                    clearTimeout(item.timeout);
                    delete item.timeout;
                }
            });

            _.each(this.callbacks, function (callback, id) {
                callback("Disconnected");
            });
            this.callbacks = {};

            delete this.socket;
        },

        add: function (target, options) {
            var url = target.url();
            if (target.streaming) {
                return;
            }

            options = options ? _.clone(options) : {};
            _.defaults(options, {
                "precache": target.hasOwnProperty("precache") && !!target.precache,
                "initial": true
            });

            var item = this.subscriptions[url];
            if (!_.isUndefined(item)) {
                if (item.timeout) {
                    clearTimeout(item.timeout);
                    delete item.timeout;
                }

                target.streaming = { url: url, options: options };
                item.clients[target.cid] = target;

                if (item.cache) {
                    this.apply(item.cache, [target]);
                }
                return;
            } else {
                item = { clients: {}, options: options };
                item.clients[target.cid] = target;

                target.streaming = { url: url, options: options };
                this.subscriptions[url] = item;
            }

            if (_.isUndefined(this.socket)) {
                return;
            }

            this.emit(url, item);
        },

        remove: function (target) {
            if (target.streaming) {
                var url = target.streaming.url;
                var item = this.subscriptions[url];

                delete item.clients[target.cid];
                if (_.keys(item.clients).length == 0) {
                    item.timeout = setTimeout(_.bind(function () {
                        this.socket.emit("unstream", { url: url }, function (err) {});
                        delete this.subscriptions[url];
                    }, this), 5000);
                }

                delete target.streaming;
            }
        },

        send: function (type, message, callback) {
            if (!this.socket) {
                _.defer(function () {
                    callback("No connection");
                });
                return;
            }

            var id = _.uniqueId('cb');
            this.callbacks[id] = callback;

            this.socket.emit(type, message, _.bind(function (err, response) {
                delete this.callbacks[id];
                callback(err, this.uncompress(response));
            }, this));
        },

        uncompress: function (data) {
            if (!_.isObject(data)) {
                return data;
            }

            var objectKeys = _.keys(data);

            if ((objectKeys.length != 2) || (_.without(objectKeys, 'keys', 'rows').length != 0)) {
                return data;
            }

            var keys = data.keys;
            var uncompressed = _.map(data.rows, function (row) {
                return _.object(keys, row);
            });

            return uncompressed;
        }
    });

    var sync = function (method, model, options) {
        var message = {
            method: method,
            url: model.url(),
            cid: model.cid,
            data: options.arguments || model.toJSON() || {},
            emit: options.emit
        };

        streaming.send("sync", message, function (err, response) {
            if (err) {
                options.error(err);
            } else {
                options.success(response);
            }
        });
    };

    streaming.Model = Backbone.Model.extend({
        stream: function () {
            console.trace();
            alert("Streaming models is not currently supported");
        },

        unstream: function () {},

        incrementVersion: function () {
            var versionName = this.versionAttribute;
            if (!_.isUndefined(versionName)) {
                this.set(versionName, this.parseVersionNumber(this.get(versionName)) + 1, {silent: true});
            }
        },

        parseVersionNumber: function (versionNumber) {
            return _.isFinite(versionNumber) ? versionNumber : 0;
        },

        parse: function (resp) {
            var versionName = this.versionAttribute;
            if (_.isObject(resp) && !_.isUndefined(versionName)) {
                var localVersion = this.parseVersionNumber(this.get(versionName));
                var remoteVersion = this.parseVersionNumber(resp[versionName]);

                if (localVersion > remoteVersion) {
                    return {};
                }
            }
            return resp;
        },

        emit: function(method, args, options) {
            if (_.isUndefined(options)) {
                options = args ? _.clone(args) : {};
                args = undefined;
            } else {
                options = options ? _.clone(options) : {};
            }

            var model = this;

            var triggerEmit = _.bind(function() {
                model.trigger('emit emit:' + method, model, options);
            }, this);

            options.emit = method;
            options.arguments = args;

            var success = options.success;
            options.success = function (resp) {
                if (success) success(model, resp, options);
                if (options.wait) triggerEmit();
            };
            var error = options.error;
            options.error = function (resp) {
                if (error) error(model, resp, options);
                model.trigger('error', model, resp, options);
            }

            var xhr = this.sync('emit', this, options);
            if (!options.wait) triggerEmit();
            return xhr;
        },

        sync: sync
    });

    streaming.Collection = Backbone.Collection.extend({
        stream: function (options) {
            options = options || {};
            if (_.isUndefined(this.cid)) {
                this.cid = _.uniqueId('coll');
            }

            _.defer(_.bind(function () {
                streaming.add(this, options);
            }, this));
        },

        unstream: function () {
            streaming.remove(this);
        },

        emit: function (method, args, options) {
            if (_.isUndefined(options)) {
                options = args ? _.clone(args) : {};
                args = undefined;
            } else {
                options = options ? _.clone(options) : {};
            }

            var model = this;

            var triggerEmit = _.bind(function() {
                model.trigger('emit emit:' + method, model, options);
            }, this);

            options.emit = method;
            options.arguments = args;

            var success = options.success;
            options.success = function (resp) {
                if (success) success(model, resp, options);
                if (options.wait) triggerEmit();
            };
            var error = options.error;
            options.error = function (resp) {
                if (error) error(model, resp, options);
                model.trigger('error', model, resp, options);
            }

            var xhr = this.sync('emit', this, options);
            if (!options.wait) triggerEmit();
            return xhr;
        },

        sync: sync
    });

    window.Streaming = streaming;
})();

<|endoftext|>


<commit_before>export class Request {
  static UNSET = 0;
  static OPENED = 1;
  static HEADERS_RECEIVED = 2;
  static LOADING = 3;
  static DONE = 4;

  static OK = 200;

  constructor(params, resolve, reject) {
    let contentType = params.contentType || 'application/json';

    this.readyState = Request.UNSET;
    this.responseText = null;
    this.responseJSON = null;
    this.responseType = null;
    this.status = null;

    this.alive = true;

    let xhr = new XMLHttpRequest();
    this.xhr = xhr;
    xhr.open(params.method || 'GET', params.url);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.setRequestHeader('Accept', 'application/json; charset=utf-8');
    xhr.setRequestHeader('Content-Type', contentType);
    Object.keys(params.headers || {}).forEach(key => {
      xhr.setRequestHeader(key, params.headers[key]);
    });
    xhr.send(params.data ? JSON.stringify(params.data) : null);

    xhr.onreadystatechange = () => {
      this.readyState = this.xhr.readyState;
      this.status = this.xhr.status;
      if (this.readyState === Request.DONE) {
        let responseData = this.processResponseText(xhr);
        if (xhr.status === Request.OK) {
          resolve(responseData, xhr);
        } else {
          reject(new Error(xhr.statusText), responseData, xhr);
        }
      }
    };
  }

  processResponseText(xhr) {
    if (xhr.getResponseHeader('content-type').split(';')[0].split('/')[1] === 'json') {
      try {
        return JSON.parse(xhr.responseText);
      } catch (ex) {
        console.error(ex);
      }
    }
    return xhr.responseText;
  }

  cancel() {
    this.alive = false;
    this.xhr.abort();
  }
}

/**
 * Converts input parameters to API-compatible query arguments
 * @param params
 */
export function paramsToQueryArgs(params) {
  return params.itemIds
    ? {id: params.itemIds} // items matching array of itemids
    : params.query
      ? {query: params.query} // items matching search query
      : undefined; // all items
}

export class Client {
  constructor(options) {
    if (options === undefined) {
      options = {};
    }
    this.baseUrl = options.baseUrl || '/api';
    this.activeRequests = {};
  }

  uniqueId() {
    let s4 = () => {
      return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
    };
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
  }

  clear() {
    for (let id in this.activeRequests) {
      this.activeRequests[id].cancel();
    }
  }

  request(path, options = {}) {
    let query = window.encodeURIComponent(options.query || '');
    let method = options.method || (options.data ? 'POST' : 'GET');
    let data = options.data;
    let id = this.uniqueId();

    if (data !== undefined && method !== 'GET') {
      data = JSON.stringify(data);
    }

    let fullUrl;
    if (path.indexOf(this.baseUrl) === -1) {
      fullUrl = this.baseUrl + path;
    } else {
      fullUrl = path;
    }
    if (query) {
      if (fullUrl.indexOf('?') !== -1) {
        fullUrl += '&' + query;
      } else {
        fullUrl += '?' + query;
      }
    }

    return new Promise((resolve, reject) => {
      let request = new Request(
        {
          url: fullUrl,
          method: method,
          data: data
        },
        resolve,
        reject
      );
      this.activeRequests[id] = request;
    });
  }

  get(path, options = {}) {
    return this.request(path, {
      method: 'GET',
      ...options
    });
  }

  post(path, options = {}) {
    return this.request(path, {
      method: 'POST',
      ...options
    });
  }

  delete(path, options = {}) {
    return this.request(path, {
      method: 'DELETE',
      ...options
    });
  }

  put(path, options = {}) {
    return this.request(path, {
      method: 'PUT',
      ...options
    });
  }
}

export default new Client();
<commit_msg>unused code<commit_after>export class Request {
  static UNSET = 0;
  static OPENED = 1;
  static HEADERS_RECEIVED = 2;
  static LOADING = 3;
  static DONE = 4;

  static OK = 200;

  constructor(params, resolve, reject) {
    let contentType = params.contentType || 'application/json';

    this.alive = true;

    let xhr = new XMLHttpRequest();

    // bind xhr so we can abort later
    this.xhr = xhr;

    xhr.open(params.method || 'GET', params.url);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.setRequestHeader('Accept', 'application/json; charset=utf-8');
    xhr.setRequestHeader('Content-Type', contentType);
    Object.keys(params.headers || {}).forEach(key => {
      xhr.setRequestHeader(key, params.headers[key]);
    });
    xhr.send(params.data ? JSON.stringify(params.data) : null);

    xhr.onreadystatechange = () => {
      if (xhr.readyState === Request.DONE) {
        let responseData = this.processResponseText(xhr);
        if (xhr.status === Request.OK) {
          resolve(responseData, xhr);
        } else {
          reject(new Error(xhr.statusText), responseData, xhr);
        }
      }
    };
  }

  processResponseText(xhr) {
    if (xhr.getResponseHeader('content-type').split(';')[0].split('/')[1] === 'json') {
      try {
        return JSON.parse(xhr.responseText);
      } catch (ex) {
        console.error(ex);
      }
    }
    return xhr.responseText;
  }

  cancel() {
    this.alive = false;
    this.xhr.abort();
  }
}

/**
 * Converts input parameters to API-compatible query arguments
 * @param params
 */
export function paramsToQueryArgs(params) {
  return params.itemIds
    ? {id: params.itemIds} // items matching array of itemids
    : params.query
      ? {query: params.query} // items matching search query
      : undefined; // all items
}

export class Client {
  constructor(options) {
    if (options === undefined) {
      options = {};
    }
    this.baseUrl = options.baseUrl || '/api';
    this.activeRequests = {};
  }

  uniqueId() {
    let s4 = () => {
      return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
    };
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
  }

  clear() {
    for (let id in this.activeRequests) {
      this.activeRequests[id].cancel();
    }
  }

  request(path, options = {}) {
    let query = window.encodeURIComponent(options.query || '');
    let method = options.method || (options.data ? 'POST' : 'GET');
    let data = options.data;
    let id = this.uniqueId();

    if (data !== undefined && method !== 'GET') {
      data = JSON.stringify(data);
    }

    let fullUrl;
    if (path.indexOf(this.baseUrl) === -1) {
      fullUrl = this.baseUrl + path;
    } else {
      fullUrl = path;
    }
    if (query) {
      if (fullUrl.indexOf('?') !== -1) {
        fullUrl += '&' + query;
      } else {
        fullUrl += '?' + query;
      }
    }

    return new Promise((resolve, reject) => {
      let request = new Request(
        {
          url: fullUrl,
          method: method,
          data: data
        },
        resolve,
        reject
      );
      this.activeRequests[id] = request;
    });
  }

  get(path, options = {}) {
    return this.request(path, {
      method: 'GET',
      ...options
    });
  }

  post(path, options = {}) {
    return this.request(path, {
      method: 'POST',
      ...options
    });
  }

  delete(path, options = {}) {
    return this.request(path, {
      method: 'DELETE',
      ...options
    });
  }

  put(path, options = {}) {
    return this.request(path, {
      method: 'PUT',
      ...options
    });
  }
}

export default new Client();
<|endoftext|>


<commit_before>var _ = require("lodash");

/*
 * This function generates an empty symbol table as JSON object
 * */
var get_scope_list = function(parse_tree){
    var scope_map = {};
    scope_map["global"] = {
        "type": "global",
        "start": {
            "row": null,
            "col": null
        },
        "end": {
            "row": null,
            "col": null
        },
        "contains": {}
    };

    //var is_function_definition = function(subtree){
        //if(subtree.parent.title === "direct_declarator"){
            //if(subtree.parent.parent.title === "declarator"){
                //if(subtree.parent.parent.parent.title === "function_definition"){
                    //return true;
                //}
                //else return false;
            //}
            //else return false;
        //}
        //else return false;
    //};

    //var traverse = function(subtree, scope){
        //if(subtree.tokenClass){
            //if(!scope_map["global"].start.row && !scope_map["global"].start.col){
               //scope_map["global"].start.row = subtree.row;
               //scope_map["global"].start.col = subtree.col;
            //}
            //scope_map["global"].end.row = subtree.row;
            //scope_map["global"].end.col = subtree.col;
        //}

        //if((subtree === null) || (subtree.title === "EPSILON") || (subtree.children === null)){
            //return;
        //}
        //else if((subtree.tokenClass) && (subtree.tokenClass === "IDENTIFIER")){
            //if(is_function_definition(subtree)){
                //scope_map[subtree.lexeme] = {
                    //"start": {
                        //"row": null,
                        //"col": null
                    //},
                    //"end": {
                        //"row": null,
                        //"col": null
                    //},
                    //"contains": []
                //};
                //var compound_stmt = subtree.parent.parent.parent.children[2];
                //var o_brace = compound_stmt.children[0];
                //var e_brace = compound_stmt.children[compound_stmt.children.length - 1];
                //scope_map[subtree.lexeme].start.row = o_brace.row;
                //scope_map[subtree.lexeme].start.col = o_brace.col;
                //scope_map[subtree.lexeme].end.row = e_brace.row;
                //scope_map[subtree.lexeme].end.col = e_brace.col;
            //}
            //for(var i = 0; i < subtree.children.length; i++){
                //traverse(subtree.children[i], scope);
            //}
        //}
    //};

    /*
     *   Returns name of the function from function definition sub-parsetree
     * */
    var get_function_id_token = function(function_definition){
        var declarator, direct_declarator, func_id_token;
        for(var i = 0 ; i < function_definition.children.length; i++){
            if(function_definition.children[i].title === "declarator"){
                declarator = function_definition.children[i];
                break;
            }
        }
        for(var i = 0 ; i < declarator.children.length; i++){
            if(declarator.children[i].title === "direct_declarator"){
                direct_declarator = declarator.children[i];
                break;
            }
        }
        for(var i = 0 ; i < direct_declarator.children.length; i++){
            if(direct_declarator.children[i].tokenClass && (direct_declarator.children[i].tokenClass === "IDENTIFIER")){
                func_id_token = direct_declarator.children[i];
                break;
            }
        }
        return func_id_token.lexeme;
    };

    var traverse = function(subtree, scope){
        if(subtree.tokenClass){
            if(!scope_map["global"].start.row && !scope_map["global"].start.col){
               scope_map["global"].start.row = subtree.row;
               scope_map["global"].start.col = subtree.col;
            }
            scope_map["global"].end.row = subtree.row;
            scope_map["global"].end.col = subtree.col;
        }

        if((subtree === null) || (subtree.title === "EPSILON") || (subtree.children === null)){
            return;
        }
        else if(subtree.title === "function_definition"){
            var function_name = get_function_id_token(subtree);
            var current_scope = scope;
            var new_scope = function_name;
            scope_map[current_scope]["contains"][function_name] = null;

            scope_map[new_scope] = {
                "type": "function",
                "start": {
                    "row": null,
                    "col": null
                },
                "end": {
                    "row": null,
                    "col": null
                },
                "contains": {}
            };

            /* Following section determines the span of newly discovered scope */
            var compound_stmt;
            for(var i = 0 ; i < subtree.children.length; i++){
                if(subtree.children[i].title === "compound_stmt"){
                    compound_stmt = subtree.children[i];
                    break;
                }
            }
            var o_brace = compound_stmt.children[0];
            var e_brace = compound_stmt.children[compound_stmt.children.length - 1];
            scope_map[new_scope].start.row = o_brace.row;
            scope_map[new_scope].start.col = o_brace.col;
            scope_map[new_scope].end.row = e_brace.row;
            scope_map[new_scope].end.col = e_brace.col;

            /* Traverse child subtrees under new scope */
            for(var i = 0; i < subtree.children.length; i++){
                traverse(subtree.children[i], new_scope);
            }
        }
        else if(subtree.title === "declaration"){
            for(var i = 0; i < subtree.children.length; i++){
                traverse(subtree.children[i], scope);
            }
        }
        else{
            for(var i = 0; i < subtree.children.length; i++){
                traverse(subtree.children[i], scope);
            }
        }
    };
    traverse(parse_tree, "global");
    return scope_map;
};

var get_symbol_table = function(parse_tree){
    var add_parent_edges = require("./utility").add_parent_edges;
    add_parent_edges(parse_tree);
    var symbol_table = get_scope_list(parse_tree);
    console.log(symbol_table);
};
module.exports.get_symbol_table = get_symbol_table;
<commit_msg>Populating symbol table with variables of different scope ongoing<commit_after>var _ = require("lodash");

/*
 * This function generates an empty symbol table as JSON object
 * */
var get_scope_list = function(parse_tree){
    var scope_map = {};
    scope_map["global"] = {
        "type": "global",
        "start": {
            "row": null,
            "col": null
        },
        "end": {
            "row": null,
            "col": null
        },
        "contains": {}
    };

    /*
     *   Returns name of the function from function definition sub-parsetree
     * */
    var get_function_id_token = function(function_definition){
        var declarator, direct_declarator, func_id_token;
        for(var i = 0 ; i < function_definition.children.length; i++){
            if(function_definition.children[i].title === "declarator"){
                declarator = function_definition.children[i];
                break;
            }
        }
        for(var i = 0 ; i < declarator.children.length; i++){
            if(declarator.children[i].title === "direct_declarator"){
                direct_declarator = declarator.children[i];
                break;
            }
        }
        for(var i = 0 ; i < direct_declarator.children.length; i++){
            if(direct_declarator.children[i].tokenClass && (direct_declarator.children[i].tokenClass === "IDENTIFIER")){
                func_id_token = direct_declarator.children[i];
                break;
            }
        }
        return func_id_token.lexeme;
    };

    /* Given a declaration subtree it return true or false
     * depending on whether the declaration is a variable declaration or function declaration
     * */
    var is_function_declaration = function(declaration){
        var direct_declarator, direct_declarator_p;

        var traverse = function(subtree){
            if((subtree === null) || (subtree.title === "EPSILON") || (subtree.children === null)){
                return;
            }
            else{
                if(subtree.title === "direct_declarator"){
                    direct_declarator = subtree;
                    return;
                }
                else{
                    for(var i = 0; i < subtree.children.length; i++){
                        traverse(subtree.children[i]);
                    }
                }
            }
        };

        traverse(declaration);
        if(direct_declarator.children[0].tokenClass === "(") return true;
        else{
            var direct_declarator_p = direct_declarator.children[1];
            if(direct_declarator_p.children[0].tokenClass === "(") return true;
            else return false;
        }
    };

    var handle_var_declaration = function(declaration, scope){
        var direct_declarator, direct_declarator_p;

        var traverse = function(subtree){
            if((subtree === null) || (subtree.title === "EPSILON") || (subtree.children === null)){
                return;
            }
            else{
                if(subtree.title === "direct_declarator"){
                    scope_map[scope].contains[subtree.children[0].lexeme] = null;
                    return;
                }
                else{
                    for(var i = 0; i < subtree.children.length; i++){
                        traverse(subtree.children[i]);
                    }
                }
            }
        };
    };

    var traverse = function(subtree, scope){
        if(subtree.tokenClass){
            if(!scope_map["global"].start.row && !scope_map["global"].start.col){
               scope_map["global"].start.row = subtree.row;
               scope_map["global"].start.col = subtree.col;
            }
            scope_map["global"].end.row = subtree.row;
            scope_map["global"].end.col = subtree.col;
        }

        if((subtree === null) || (subtree.title === "EPSILON") || (subtree.children === null)){
            return;
        }
        else if(subtree.title === "function_definition"){
            var function_name = get_function_id_token(subtree);
            var current_scope = scope;
            var new_scope = function_name;
            scope_map[current_scope]["contains"][function_name] = null;

            scope_map[new_scope] = {
                "type": "function",
                "start": {
                    "row": null,
                    "col": null
                },
                "end": {
                    "row": null,
                    "col": null
                },
                "contains": {}
            };

            /* Following section determines the span of newly discovered scope */
            var compound_stmt;
            for(var i = 0 ; i < subtree.children.length; i++){
                if(subtree.children[i].title === "compound_stmt"){
                    compound_stmt = subtree.children[i];
                    break;
                }
            }
            var o_brace = compound_stmt.children[0];
            var e_brace = compound_stmt.children[compound_stmt.children.length - 1];
            scope_map[new_scope].start.row = o_brace.row;
            scope_map[new_scope].start.col = o_brace.col;
            scope_map[new_scope].end.row = e_brace.row;
            scope_map[new_scope].end.col = e_brace.col;

            /* Traverse child subtrees under new scope */
            for(var i = 0; i < subtree.children.length; i++){
                traverse(subtree.children[i], new_scope);
            }
        }
        else if(subtree.title === "declaration"){
            if(is_function_declaration(subtree)){
                return;
            }
            else{
                handle_var_declaration(subtree, scope);
                return;
            }
        }
        else{
            for(var i = 0; i < subtree.children.length; i++){
                traverse(subtree.children[i], scope);
            }
        }
    };
    traverse(parse_tree, "global");
    return scope_map;
};

var get_symbol_table = function(parse_tree){
    var add_parent_edges = require("./utility").add_parent_edges;
    add_parent_edges(parse_tree);
    var symbol_table = get_scope_list(parse_tree);
    console.log(symbol_table);
};
module.exports.get_symbol_table = get_symbol_table;
<|endoftext|>