<commit_before>/*************************************************************************************************************************************************
/	Export to Table or CSV
/	- Create an html table
/	- Create a csv file
/************************************************************************************************************************************************/

// Create a html table or a csv file from a single layer
function ExportSingleLayer(exportLayer, outputType, outputSet) {
	var exportFeatures;

	if (exportLayer.CLASS_NAME == 'OpenLayers.Layer.Vector') {
		if (outputSet == "all")
			exportFeatures = exportLayer.features;
		else if (outputSet == "selected")
			exportFeatures = exportLayer.selectedFeatures;

		if (exportFeatures.length == 0)
			alert("There are no features selected.");
		else {
			if (outputType == "html")
				ExportHTML(exportLayer, exportFeatures);
			else if (outputType == "csv")
				ExportCSV(exportLayer, exportFeatures);
		}
	}
	else
		alert("Can only export data layers.");
}

// Create a html table or a csv file from multiple layers
function ExportMultipleLayers(outputType, outputSet) {

	// Determine how many vector layers are checked
	var exportLayers = [];
	var lyrs = map.layers;
	for (var i = 0; i < lyrs.length; i++) {
		if (lyrs[i].CLASS_NAME == 'OpenLayers.Layer.Vector' && lyrs[i].visibility == true) {
			exportLayers.push(lyrs[i]);
		}
	}

	// Create the list of features to be exported
	var exportFeatures = [];
	if (exportLayers.length == 0)
		alert("Check at least one data layer.");
	else {
		if (outputSet == "all"){
			for (var i=0; i < exportLayers.length; i++)
				exportFeatures = exportFeatures.concat(exportLayers[i].features);
		}
		else if (outputSet == "selected") {
			for (var i=0; i < exportLayers.length; i++)
				exportFeatures = exportFeatures.concat(exportLayers[i].selectedFeatures);
		}

		if (exportFeatures.length == 0)
			alert("There are no features selected.");
		else {
			// If there is only one layer to be exported
			if (exportLayers.length == 1)
				exportLayer = exportLayers[0];
			// If there are mulitple layers to be exported get the layer to be used for column headings
			else
				exportLayer = GetPrimaryLayer(exportLayers);

			if (exportLayer != null) {
				if (outputType == "html")
					ExportHTML(exportLayer, exportFeatures);
				else if (outputType == "csv")
					ExportCSV(exportLayer, exportFeatures);
			}
		}
	}
}

// Get the layer to be used for the column headings
function GetPrimaryLayer(exportLayers) {
	var exportLayer;

	// If the feature types match just use the first layer for the headings
	if (MatchingFeatureTypes(exportLayers)) {
		exportLayer = exportLayers[0];
	}
	// Otherwise get the layer set as the active (highlighted) layer
	else {
		if (activeLayer != undefined) {
			// If the active (highlighted) layer is one of the checked layers
			if (IsIn(exportLayers, activeLayer) == true) {
				// If the feature types of the checked layers do NOT match
				if (MatchingFeatureTypes(exportLayers) == false) {
					if (confirm("Warning! Feature type MISMATCH!\nColumn headings will be taken from: " + activeLayer.name + "\n\nContinue?") == true)
						exportLayer = activeLayer;
					else
						exportLayer = null;
				}
				// If the feature types of the checked layers match
				else
					exportLayer = exportLayers[0];
			}
			// If the active (highlighted) layer is NOT one of the checked layers
			else {
				if (MatchingFeatureTypes(exportLayers) == false) {
					if (confirm("Warning! Feature type MISMATCH!\nColumn headings will be taken from: " + activeLayer.name + "\n\nContinue?") == true)
						exportLayer = activeLayer;
					else
						exportLayer = null;
				}
				else {
					if (confirm("Warning!\nColumn headings will be taken from: " + activeLayer.name + "\n\nContinue?") == true)
						exportLayer = activeLayer;
					else
						exportLayer = null;
				}
			}
		}
		// If no layer is set as the active (highlighted) layer
		else {
			alert("More than one layer is checked.\nClick the name of the layer whose attributes you would like to use for the column headings, highlighting the layer name in blue.");
			exportLayer = null;
		}
	}

	return exportLayer;
}

// Check for matching feature types of multiple layers
function MatchingFeatureTypes(exportLayers) {
	for (var i=0; i < exportLayers.length - 1; i++) {
		for (var j=i+1; j < exportLayers.length; j++) {
			if (exportLayers[i].protocol.featureType != exportLayers[j].protocol.featureType)
				return false;
		}
	}
	return true;
}

// Export the data as an HTML table
function ExportHTML(exportLayer, exportFeatures) {

	var output = "<title>" + exportLayer.name + "</title>";
	output += "";
	output += "

";

	output = WriteHTMLHeaders(exportLayer, output);
	output = WriteHTMLRows(exportFeatures, output);
	output += "
";

	// Write the html to a new window
	var htmlWin = window.open("","myWindow");
	htmlWin.document.write(output);
	htmlWin.document.close();

}

// Write the headers of the HTML table
function WriteHTMLHeaders(exportLayer, output) {
	// Set all attributes for the active layer
	GetAttributes(exportLayer.protocol);

	output += "Layer Name	";
	// Write the attributes to an html table as the column headings
	for (var i=0; i < layerAttributes.length; i++) {
		//console.log(layerAttributes[i].name);
		output += "" + layerAttributes[i].name + "	";
	}
	output += "
";

	return output;
}

// Write the rows of the HTML table
function WriteHTMLRows(exportFeatures, output) {

	for (var i=0; i < exportFeatures.length; i++) {
		output += "
" + exportFeatures[i].layer.name + "	";
		for (var j=0; j < layerAttributes.length; j++) {
			var curColName = layerAttributes[j].name;
			var curRowData = exportFeatures[i].data;
			if ((curRowData[curColName]) == undefined)
				output += "	";
			else {
				// Make a HTML link for any Url within the text
				replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
				replacedText = curRowData[curColName].replace(replacePattern1, '$1');
				output += "" + replacedText + "	";
			}
		}
		output += "
";
	}

	return output;
}

// Export the data as a CSV file
function ExportCSV(exportLayer, exportFeatures) {

	var output = "";
	output = WriteCSVHeaders(exportLayer, output);
	output = WriteCSVRows(exportFeatures, output);

	try {
		var xmlhttp;
		if (window.XMLHttpRequest)
		  // code for IE7+, Firefox, Chrome, Opera, Safari
		  xmlhttp = new XMLHttpRequest();
		else
		  // code for IE6, IE5
		  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

		// Tell the server to create a csv file with the string output
		xmlhttp.open("POST", "/csv", false);
		xmlhttp.send(output);

		// Open the csv
		window.open('/files/data.csv', '_blank');
	}
	catch (e) {
		alert("Unable to download the CSV file.");
	}
}

// Write the headers of the CSV table
function WriteCSVHeaders(exportLayer, output) {
	// Set all attributes for the active layer
	GetAttributes(exportLayer.protocol);

	output += "\"Layer Name\"";
	// Write the attributes to a string for a csv as the column headings
	for (var i=0; i < layerAttributes.length; i++) {
		//console.log(layerAttributes[i].name);
		output += ",\""+layerAttributes[i].name+"\"";
	}
	output += "\n";

	return output;
}

// Write the rows of the CSV table
function WriteCSVRows(exportFeatures, output) {
	for (var i=0; i < exportFeatures.length; i++) {
		output += "\"" + exportFeatures[i].layer.name + "\"";
		for (var j=0; j < layerAttributes.length; j++) {
			var curColName = layerAttributes[j].name;
			var curRowData = exportFeatures[i].data;
			if ((curRowData[curColName]) == undefined)
				output += ",";
			else
				output += ",\"" + curRowData[curColName] + "\"";
		}
		output += "\n";
	}

	return output;
}

// Call DescribeFeatureType to get list of attributes for the active layer
function GetAttributes(protocol){
	var baseUrl = protocol.url;
	OpenLayers.Request.GET({
		url: baseUrl+'?SERVICE=WFS&version=1.1.0&REQUEST=DescribeFeatureType&namespace=wfs'+'&typeName='+protocol.featureType,
		async: false,
		success: function(resp) {
			// Format the response as WFS Capabilities
			var DesFormat = new OpenLayers.Format.WFSDescribeFeatureType();
			var des = DesFormat.read(resp.responseText);

			// Get the number of attributes and the attributes themselves
			layerAttributes = des.featureTypes[0].properties;
		}
	});
}<commit_msg>Escape embedded double quote characters for CSV<commit_after>/*************************************************************************************************************************************************
/	Export to Table or CSV
/	- Create an html table
/	- Create a csv file
/************************************************************************************************************************************************/

// Create a html table or a csv file from a single layer
function ExportSingleLayer(exportLayer, outputType, outputSet) {
	var exportFeatures;

	if (exportLayer.CLASS_NAME == 'OpenLayers.Layer.Vector') {
		if (outputSet == "all")
			exportFeatures = exportLayer.features;
		else if (outputSet == "selected")
			exportFeatures = exportLayer.selectedFeatures;

		if (exportFeatures.length == 0)
			alert("There are no features selected.");
		else {
			if (outputType == "html")
				ExportHTML(exportLayer, exportFeatures);
			else if (outputType == "csv")
				ExportCSV(exportLayer, exportFeatures);
		}
	}
	else
		alert("Can only export data layers.");
}

// Create a html table or a csv file from multiple layers
function ExportMultipleLayers(outputType, outputSet) {

	// Determine how many vector layers are checked
	var exportLayers = [];
	var lyrs = map.layers;
	for (var i = 0; i < lyrs.length; i++) {
		if (lyrs[i].CLASS_NAME == 'OpenLayers.Layer.Vector' && lyrs[i].visibility == true) {
			exportLayers.push(lyrs[i]);
		}
	}

	// Create the list of features to be exported
	var exportFeatures = [];
	if (exportLayers.length == 0)
		alert("Check at least one data layer.");
	else {
		if (outputSet == "all"){
			for (var i=0; i < exportLayers.length; i++)
				exportFeatures = exportFeatures.concat(exportLayers[i].features);
		}
		else if (outputSet == "selected") {
			for (var i=0; i < exportLayers.length; i++)
				exportFeatures = exportFeatures.concat(exportLayers[i].selectedFeatures);
		}

		if (exportFeatures.length == 0)
			alert("There are no features selected.");
		else {
			// If there is only one layer to be exported
			if (exportLayers.length == 1)
				exportLayer = exportLayers[0];
			// If there are mulitple layers to be exported get the layer to be used for column headings
			else
				exportLayer = GetPrimaryLayer(exportLayers);

			if (exportLayer != null) {
				if (outputType == "html")
					ExportHTML(exportLayer, exportFeatures);
				else if (outputType == "csv")
					ExportCSV(exportLayer, exportFeatures);
			}
		}
	}
}

// Get the layer to be used for the column headings
function GetPrimaryLayer(exportLayers) {
	var exportLayer;

	// If the feature types match just use the first layer for the headings
	if (MatchingFeatureTypes(exportLayers)) {
		exportLayer = exportLayers[0];
	}
	// Otherwise get the layer set as the active (highlighted) layer
	else {
		if (activeLayer != undefined) {
			// If the active (highlighted) layer is one of the checked layers
			if (IsIn(exportLayers, activeLayer) == true) {
				// If the feature types of the checked layers do NOT match
				if (MatchingFeatureTypes(exportLayers) == false) {
					if (confirm("Warning! Feature type MISMATCH!\nColumn headings will be taken from: " + activeLayer.name + "\n\nContinue?") == true)
						exportLayer = activeLayer;
					else
						exportLayer = null;
				}
				// If the feature types of the checked layers match
				else
					exportLayer = exportLayers[0];
			}
			// If the active (highlighted) layer is NOT one of the checked layers
			else {
				if (MatchingFeatureTypes(exportLayers) == false) {
					if (confirm("Warning! Feature type MISMATCH!\nColumn headings will be taken from: " + activeLayer.name + "\n\nContinue?") == true)
						exportLayer = activeLayer;
					else
						exportLayer = null;
				}
				else {
					if (confirm("Warning!\nColumn headings will be taken from: " + activeLayer.name + "\n\nContinue?") == true)
						exportLayer = activeLayer;
					else
						exportLayer = null;
				}
			}
		}
		// If no layer is set as the active (highlighted) layer
		else {
			alert("More than one layer is checked.\nClick the name of the layer whose attributes you would like to use for the column headings, highlighting the layer name in blue.");
			exportLayer = null;
		}
	}

	return exportLayer;
}

// Check for matching feature types of multiple layers
function MatchingFeatureTypes(exportLayers) {
	for (var i=0; i < exportLayers.length - 1; i++) {
		for (var j=i+1; j < exportLayers.length; j++) {
			if (exportLayers[i].protocol.featureType != exportLayers[j].protocol.featureType)
				return false;
		}
	}
	return true;
}

// Export the data as an HTML table
function ExportHTML(exportLayer, exportFeatures) {

	var output = "<title>" + exportLayer.name + "</title>";
	output += "";
	output += "

";

	output = WriteHTMLHeaders(exportLayer, output);
	output = WriteHTMLRows(exportFeatures, output);
	output += "
";

	// Write the html to a new window
	var htmlWin = window.open("","myWindow");
	htmlWin.document.write(output);
	htmlWin.document.close();

}

// Write the headers of the HTML table
function WriteHTMLHeaders(exportLayer, output) {
	// Set all attributes for the active layer
	GetAttributes(exportLayer.protocol);

	output += "Layer Name	";
	// Write the attributes to an html table as the column headings
	for (var i=0; i < layerAttributes.length; i++) {
		//console.log(layerAttributes[i].name);
		output += "" + layerAttributes[i].name + "	";
	}
	output += "
";

	return output;
}

// Write the rows of the HTML table
function WriteHTMLRows(exportFeatures, output) {

	for (var i=0; i < exportFeatures.length; i++) {
		output += "
" + exportFeatures[i].layer.name + "	";
		for (var j=0; j < layerAttributes.length; j++) {
			var curColName = layerAttributes[j].name;
			var curRowData = exportFeatures[i].data;
			if ((curRowData[curColName]) == undefined)
				output += "	";
			else {
				// Make a HTML link for any Url within the text
				replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
				replacedText = curRowData[curColName].replace(replacePattern1, '$1');
				output += "" + replacedText + "	";
			}
		}
		output += "
";
	}

	return output;
}

// Export the data as a CSV file
function ExportCSV(exportLayer, exportFeatures) {

	var output = "";
	output = WriteCSVHeaders(exportLayer, output);
	output = WriteCSVRows(exportFeatures, output);

	try {
		var xmlhttp;
		if (window.XMLHttpRequest)
		  // code for IE7+, Firefox, Chrome, Opera, Safari
		  xmlhttp = new XMLHttpRequest();
		else
		  // code for IE6, IE5
		  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

		// Tell the server to create a csv file with the string output
		xmlhttp.open("POST", "/csv", false);
		xmlhttp.send(output);

		// Open the csv
		window.open('/files/data.csv', '_blank');
	}
	catch (e) {
		alert("Unable to download the CSV file.");
	}
}

// Write the headers of the CSV table
function WriteCSVHeaders(exportLayer, output) {
	// Set all attributes for the active layer
	GetAttributes(exportLayer.protocol);

	output += "\"Layer Name\"";
	// Write the attributes to a string for a csv as the column headings
	for (var i=0; i < layerAttributes.length; i++) {
		//console.log(layerAttributes[i].name);
		output += ",\""+layerAttributes[i].name+"\"";
	}
	output += "\n";

	return output;
}

// Write the rows of the CSV table
function WriteCSVRows(exportFeatures, output) {
	for (var i=0; i < exportFeatures.length; i++) {
		output += "\"" + exportFeatures[i].layer.name + "\"";
		for (var j=0; j < layerAttributes.length; j++) {
			var curColName = layerAttributes[j].name;
			var curRowData = exportFeatures[i].data;
			if ((curRowData[curColName]) == undefined)
				output += ",";
			else{
				// Escape embedded double quote characters with another double quote for CSV
				output += ",\"" + curRowData[curColName].replace(/\"/gi,"\"\"") + "\"";
			}
		}
		output += "\n";
	}
	return output;
}

// Call DescribeFeatureType to get list of attributes for the active layer
function GetAttributes(protocol){
	var baseUrl = protocol.url;
	OpenLayers.Request.GET({
		url: baseUrl+'?SERVICE=WFS&version=1.1.0&REQUEST=DescribeFeatureType&namespace=wfs'+'&typeName='+protocol.featureType,
		async: false,
		success: function(resp) {
			// Format the response as WFS Capabilities
			var DesFormat = new OpenLayers.Format.WFSDescribeFeatureType();
			var des = DesFormat.read(resp.responseText);

			// Get the number of attributes and the attributes themselves
			layerAttributes = des.featureTypes[0].properties;
		}
	});
}<|endoftext|>


<commit_before>import React, { Component } from "react";
import { Container, Button } from "reactstrap";

const creditList = [
  {
    header: "Created By:",
    content: "Alex Anderson 🚀"
  },
  {
    header: "Inspiration",
    content: "Victor Williamson 🎓"
  },
  {
    header: "Conceptual Design",
    content: "Matt Ricks 🤔"
  },
  {
    header: "Technical Consultant",
    content: "Brent Anderson 🤓"
  },
  {
    header: "Documentation & Training",
    content: "Crystal Anderson 💎"
  },
  {
    header: "Curve Frame Design",
    content: "BJ Warner 🎨 & Todd Rasband 🖌"
  },
  {
    header: "Glass Frame Design",
    content: "Nathan King 👑"
  },
  {
    header: "Bug Reports & Feature Suggestions",
    content: (

Ryan Anderson

Alex DeBirk

Nathan King

Parriss King

Daniel Kirpatrick

Isaac Ostler

Matt Ricks

          aBlueShadow

          J-F1

          kimballfrank

    )
  },
  {
    header: "Donors",
    content: (

          Thomas Delclite{" "}

            🇧🇪

          Chuck Smith{" "}

            🇺🇸

          The Lion's Gate Center{" "}

            🦁

          Brent Anderson{" "}

            🇺🇸

          Maeson Busk{" "}

            🇺🇸

          The Christa McAuliffe Space Education Center{" "}

            🛰

          Victor Williamson

            👽

          Ryan Anderson

            🔭

    )
  },
  {
    header: "Docking & System Images (Endless Sky)",
    content: (

Maximilian Korber (CC-BY-SA-4.0)

Iaz Poolar (CC-BY-SA-4.0)

Michael Zahniser (CC-BY-SA-4.0)

    )
  },
  {
    header: "Card Icons",
    content: (

jet engine by Arthur Shlain from the Noun Project

Coolant Temperature by Ben Johnson from the Noun Project

sensor by Bakunetsu Kaito from the Noun Project

Gyroscope by Arthur Shlain from the Noun Project

Radar by Oliviu Stoian from the Noun Project

Feather Icon Pack

Font Awesome

    )
  }
];

class Credits extends Component {
  state = { debug: false, scroll: 0 };
  toggleDebug = () => {
    this.setState({
      debug: !this.state.debug
    });
  };
  changeClientId = evt => {
    evt.preventDefault();
    const newClientId = prompt("What is the new client ID?");
    if (newClientId) {
      this.props.updateClientId(newClientId);
    }
  };
  render() {
    const { clientId, flight = {}, simulator = {}, station = {} } = this.props;
    if (this.refs.scroll) {
      this.refs.scroll.scrollTop = this.state.scroll;
    }
    return (

        <Container>

Thorium

          {this.state.debug ? (

                <Button color="info" onClick={this.changeClientId}>
                  Client ID: {clientId}
                </Button>

Flight: {flight ? flight.name : "Not Assigned"}

Simulator: {simulator ? simulator.name : "Not Assigned"}

Station: {station ? station.name : "Not Assigned"}

Download the client app:

                    Mac

                    Windows

                    Linux

          ) : (

                {creditList.map(c => (

{c.header}

{c.content}

                ))}

          )}
        </Container>

    );
  }
}

export default Credits;
<commit_msg>Update credits<commit_after>import React, { Component } from "react";
import { Container, Button } from "reactstrap";

const creditList = [
  {
    header: "Created By",
    content: "Alex Anderson 🚀"
  },
  {
    header: "Inspiration",
    content: "Victor Williamson 🎓"
  },
  {
    header: "Conceptual Design",
    content: "Matt Ricks 🤔"
  },
  {
    header: "Technical Consultant",
    content: "Brent Anderson 🤓"
  },
  {
    header: "Documentation & Training",
    content: "Crystal Anderson 💎"
  },
  {
    header: "Curve Frame Design",
    content: "BJ Warner 🎨 & Todd Rasband 🖌"
  },
  {
    header: "Glass Frame Design",
    content: "Nathan King 👑"
  },
  {
    header: "Code Contributors",
    content: (

          G33kX

          emrix

          aBlueShadow

          jrobe

          J-F1

    )
  },
  {
    header: "Bug Reports & Feature Suggestions",
    content: (

Ryan Anderson

Alex DeBirk

Nathan King

Parriss King

Daniel Kirpatrick

Isaac Ostler

Matt Ricks

          kimballfrank

    )
  },
  {
    header: "Donors",
    content: (

          Thomas Delclite{" "}

            🇧🇪

          Chuck Smith{" "}

            🇺🇸

          The Lion's Gate Center{" "}

            🦁

          Brent Anderson{" "}

            🇺🇸

          Maeson Busk{" "}

            🇺🇸

          The Christa McAuliffe Space Education Center{" "}

            🛰

          Victor Williamson

            👽

          Ryan Anderson

            🔭

    )
  },
  {
    header: "Docking & System Images (Endless Sky)",
    content: (

Maximilian Korber (CC-BY-SA-4.0)

Iaz Poolar (CC-BY-SA-4.0)

Michael Zahniser (CC-BY-SA-4.0)

    )
  },
  {
    header: "Card Icons",
    content: (

jet engine by Arthur Shlain from the Noun Project

Coolant Temperature by Ben Johnson from the Noun Project

sensor by Bakunetsu Kaito from the Noun Project

Gyroscope by Arthur Shlain from the Noun Project

Radar by Oliviu Stoian from the Noun Project

Feather Icon Pack

Font Awesome

    )
  }
];

class Credits extends Component {
  state = { debug: false, scroll: 0 };
  toggleDebug = () => {
    this.setState({
      debug: !this.state.debug
    });
  };
  changeClientId = evt => {
    evt.preventDefault();
    const newClientId = prompt("What is the new client ID?");
    if (newClientId) {
      this.props.updateClientId(newClientId);
    }
  };
  render() {
    const { clientId, flight = {}, simulator = {}, station = {} } = this.props;
    if (this.refs.scroll) {
      this.refs.scroll.scrollTop = this.state.scroll;
    }
    return (

        <Container>

Thorium

          {this.state.debug ? (

                <Button color="info" onClick={this.changeClientId}>
                  Client ID: {clientId}
                </Button>

Flight: {flight ? flight.name : "Not Assigned"}

Simulator: {simulator ? simulator.name : "Not Assigned"}

Station: {station ? station.name : "Not Assigned"}

Download the client app:

                    Mac

                    Windows

                    Linux

          ) : (

                {creditList.map(c => (

{c.header}

{c.content}

                ))}

          )}
        </Container>

    );
  }
}

export default Credits;
<|endoftext|>


<commit_before>import _ from 'lodash';
import assert from 'assert';
import { Deserializer } from '../src';
import { test, Vector, decode } from '../build';

describe('TestSchema', function() {
    let deserializer;

    afterEach(() => {
        deserializer = null;
    });

    it('should decode any type', function() {
        assert(decode(test.BoolTrue.encode()).serialize().equals(test.BoolTrue.encode()));
    });

    it('should not allow unexpected properties', function() {
        assert.throws(function() {
            new test.UserStatus({
                online: true,
                a: 1
            });
        });
    });

    it('should support bool = true param', function() {
        const userStatus = test.UserStatus.decode(new Deserializer(test.UserStatus.encode({
            online: true
        })));

        assert.equal(userStatus.online, true);
    });

    it('should support bool = true param', function() {
        const userStatus = test.UserStatus.decode(new Deserializer(test.UserStatus.encode({
            online: false
        })));

        assert.equal(userStatus.online, false);
    });

    describe('Vector', function() {
        it('should deserialize vectors', function() {
            const vector = new Vector({
                type: 'int',
                items: [1,2,3,4,5,6,7]
            });
            const bytes = vector.serialize();

            assert(Vector.encode(vector).equals(bytes));
        });

        it('should support direct pointing to a constructor', function() {
            const vector = new Vector({
                type: 'test.account',
                items: [new test.Account({
                    id: 100,
                    email: 'a@b.c',
                    username: '1234567'
                })]
            });

            assert(Vector.decode({
                type: 'test.account',
                buffer: vector.serialize()
            }).serialize().equals(vector.serialize()));
        });

        it('should handle empty vectors', function() {
            const vector = new Vector({
                type: 'test.Account',
                items: []
            });

            assert.ok(Vector.decode({
                type: 'test.Account',
                buffer: vector.serialize()
            }).serialize().equals(vector.serialize()));
        });

        describe('toJSON()', function() {
            it('should transform Vector<int> to JSON', function() {
                assert.equal(JSON.stringify(new Vector({
                    type: 'int',
                    items: [1,2,3,4]
                })), '[1,2,3,4]');
            });

            it('should transform Vector<test.Account> into JSON', function() {
                const vector = new Vector({
                    type: 'test.Account',
                    items: [new test.Account({
                        id: 100,
                        email: 'a@b.c',
                        username: '1234567'
                    })]
                });

                assert.equal(JSON.stringify(vector), JSON.stringify([{
                    id: 100,
                    username: '1234567',
                    email: 'a@b.c'
                }]));
            });
        });
    });

    describe('toJSON()', function() {
        it('should transform into plain object', function() {
            const account = new test.Account({
                id: 100,
                email: 'a@b.c.',
                username: '1234567'
            });
            assert.deepEqual(account.toJSON(), {
                id: 100,
                email: 'a@b.c.',
                username: '1234567'
            });

            assert.equal(JSON.stringify(account), JSON.stringify({
                id: 100,
                username: '1234567',
                email: 'a@b.c.'
            }));
        });
    });

    describe('serialize()', function() {
        it('should serialize constructor properties into buffer', function() {
            const bytes = new test.Account({
                id: 100,
                email: 'victor@nice.com',
                username: 'victorqueiroz'
            }).serialize();
        });
    });

    describe('static: encode()', function() {
        it('should encode simple constructors', function() {
            const bytes = test.Account.encode({
                id: 100,
                username: 'victorqueiroz',
                email: 'queiroz@messenger.im'
            });

            deserializer = new Deserializer(bytes);

            assert.equal(test.Account._header.readUInt32LE(0), deserializer._readBytes(4).readUInt32LE(0));
            assert.equal(100, deserializer.readInt());
            assert.equal('victorqueiroz', deserializer.readString());
            assert.equal('queiroz@messenger.im', deserializer.readString());
            assert.equal(deserializer.offset, deserializer.buffer.byteLength);
        });

        it('should encode complex constructors', function() {
            const bytes = test.Post.encode({
                id: 20,
                body: 'xxxx',
                author: test.Account.encode({
                    id: 100,
                    username: 'xxxx',
                    email: 'xxxx@xxxx.xxxx',
                })
            });

            deserializer = new Deserializer(bytes);

            assert.equal(test.Post._header.readUInt32LE(0), deserializer._readBytes(4).readUInt32LE(0));
            assert.equal(20, deserializer.readInt());

            // attr: author
            assert.equal(test.Account._header.readUInt32LE(0), deserializer._readBytes(4).readUInt32LE(0));
            assert.equal(100, deserializer.readInt());
            assert.equal('xxxx', deserializer.readString());
            assert.equal('xxxx@xxxx.xxxx', deserializer.readString());

            // attr: body
            assert.equal('xxxx', deserializer.readString());
        });

        it('should decode vector inside constructors', function() {
            const bytes = test.players.PlayersList.encode({
                players: Vector.encode({
                    type: 'test.players.Player',
                    items: [test.players.Player.encode({
                        id: 100
                    })]
                })
            });

            const result = test.players.PlayersList.decode(new Deserializer(bytes));

            result.players.forEach(player => {
                assert.equal(player.id, 100);
            });
        });

        it('should validate vector type using schema prefix for non-generic types', function() {
            new test.players.PlayersList({
                players: new Vector({
                    type: 'test.players.Player',
                    items: [new test.players.Player({
                        id: 31848
                    })]
                })
            });
        });

        it('should throw if invalid vector type is given', function() {
            assert.throws(function() {
                new test.players.PlayersList({
                    players: new Vector({
                        type: 'test.players.player',
                        items: []
                    })
                });
            }, /invalid vector type for param players. expected test.players.Player but got test.players.player instead/);
        });

        it('should throw for invalid bool type', function() {
            assert.throws(function() {
                new test.UserStatus({
                    online: 0
                });
            }, /Invalid type for param \"online\"\. expected type boolean but got number instead. Check constructor test\.userStatus/);
        });
    });

    describe('static: decode()', function() {
        it('should decode simple constructors', function() {
            const bytes = test.Account.encode({
                id: 100,
                username: 'victorqueiroz',
                email: 'queiroz@messenger.im'
            });

            const account = test.Account.decode(new Deserializer(bytes));

            assert.equal(account.id, 100);
            assert.equal(account.username, 'victorqueiroz',);
            assert.equal(account.email, 'queiroz@messenger.im');
        });

        it('should decode complex constructors', function() {
            const bytes = test.Post.encode({
                id: 20,
                body: 'xxxx',
                author: test.Account.encode({
                    id: 100,
                    username: 'xxxx',
                    email: 'xxxx@xxxx.xxxx',
                })
            });

            const post = test.Post.decode(new Deserializer(bytes));

            assert.equal(post.id, 20);
            assert.equal(post.body, 'xxxx');

            _.forEach({
                id: 100,
                email: 'xxxx@xxxx.xxxx',
                username: 'xxxx'
            }, function(value, key) {
                assert.equal(post.author[key], value);
            });
        });
    });

    it('should encode Vector<double>', function() {
        const vector = Vector.decode({
            type: 'double',
            buffer: Vector.encode({
                type: 'double',
                items: [
                    -33.398824,
                    12.31388
                ]
            })
        });

        assert.deepEqual(vector.items, [-33.398824, 12.31388]);
    });

    it('should encode Vector<players.Player>', function() {
        const bytes = Vector.encode({
            type: 'test.players.Player',
            items: [test.players.Player.encode({
                id: 100
            })]
        });

        deserializer = new Deserializer(bytes);
        assert.equal(Vector._id, deserializer._readBytes(4).readUInt32LE(0));
        assert.equal(1, deserializer.readUInt());
        assert.equal(test.players.Player._id, deserializer._readBytes(4).readUInt32LE(0));
        assert.equal(100, deserializer.readInt());
    });

    it('should decode Vector<players.Player>', function() {
        const bytes = Vector.encode({
            type: 'test.players.Player',
            items: [test.players.Player.encode({
                id: 100
            })]
        });

        const result = Vector.decode({
            type: 'test.players.Player',
            buffer: bytes
        });

        result.forEach(item => {
            assert.equal(item.id, 100);
        });
    });

    it('should encode Vector<int>', function() {
        const bytes = Vector.encode({
            type: 'int',
            items: [1,2,3,4,5]
        });

        deserializer = new Deserializer(bytes);
        assert.ok(Vector._id, deserializer._readBytes(4).readUInt32LE(0));
        assert.equal(5, deserializer.readUInt());
        assert.equal(1, deserializer.readInt());
        assert.equal(2, deserializer.readInt());
        assert.equal(3, deserializer.readInt());
        assert.equal(4, deserializer.readInt());
        assert.equal(5, deserializer.readInt());
    });

    it('should decode Vector<int>', function() {
        const items = [1,2,3,4,5];
        const bytes = Vector.encode({
            type: 'int',
            items: items
        });

        const vector = Vector.decode({
            type: 'int',
            buffer: bytes
        });

        items.forEach((n, i) => {
            assert.equal(vector.nth(i), n);
        });
    });

    it('should encode Vector<long>', function() {
        const vector = new Vector({
            type: 'long',
            items: [255, -255, -64]
        });

        assert(vector.serialize().equals(Vector.decode({
            type: 'long',
            buffer: vector.serialize()
        }).serialize()));
    });

    it('should encode Vector<string>', function() {
        const bytes = Vector.encode({
            type: 'string',
            items: ['a', 'b', 'c', 'd', 'e']
        });

        deserializer = new Deserializer(bytes);
        assert.equal(Vector._id, deserializer._readBytes(4).readUInt32LE(0));
        assert.equal(5, deserializer.readUInt());
        assert.equal('a', deserializer.readString());
        assert.equal('b', deserializer.readString());
        assert.equal('c', deserializer.readString());
        assert.equal('d', deserializer.readString());
        assert.equal('e', deserializer.readString());
    });

    it('should encode Vector<test.Post> using serialize()', function() {
        const vector = new Vector({
            type: 'test.Post',
            items: [new test.Post({
                id: 100,
                body: '',
                author: new test.Account({
                    id: 100,
                    email: '100@100.100',
                    username: '100'
                })
            }),
            new test.Post({
                id: 200,
                body: '',
                author: new test.Account({
                    id: 200,
                    email: '200@200.200',
                    username: '200'
                })
            })]
        });

        assert(vector.serialize().equals(Vector.encode({
            type: 'test.Post',
            items: [test.Post.encode({
                id: 100,
                body: '',
                author: test.Account.encode({
                    id: 100,
                    email: '100@100.100',
                    username: '100'
                })
            }),
            test.Post.encode({
                id: 200,
                body: '',
                author: test.Account.encode({
                    id: 200,
                    email: '200@200.200',
                    username: '200'
                })
            })]
        })));
    });

    it('should decode Vector<string>', function() {
        const items = ['a', 'b', 'c', 'd', 'e'];
        const bytes = Vector.encode({
            type: 'string',
            items: items
        });

        const vector = Vector.decode({
            type: 'string',
            buffer: bytes
        });

        items.forEach((item, i) => {
            assert.equal(vector.nth(i), item);
        });
    });

    it('should throw an error if you instantiate a constructor with a missing param', function() {
        assert.throws(function() {
            new test.Account({

            });
        }, /missing property \"id\" for \"test.account\" constructor/);
    });

    it('should throw if found a invalid header for non-generic param type', function() {
        const bytes = test.Post.encode({
            id: 100,
            author: test.Account.encode({
                id: 100,
                username: 'xxxxxx',
                email: 'xxxxx'
            }),
            body: ''
        });

        assert.equal(bytes.readUInt32LE(8), test.Account._id);
        bytes.writeUInt32LE(Vector._id, 8);

        assert.throws(function() {
            test.Post.decode(new Deserializer(bytes));
        }, /invalid header for param \"author\". expected 186715902 but got 460212315 instead/);
    });

    it('should throw if give an invalid param type is given', function() {
        assert.throws(function() {
            new test.players.CreatePlayer({
                online: new test.players.CreatePlayer({
                    online: new test.BoolTrue()
                })
            });
        }, /invalid type for param "online". expected test.Bool but got test.players.CreatePlayerResponse instead/);
    });

    it('should support direct linking to constructor', function(){
        const book = new test.Book({
            id: 23771,
            author: new test.players.Player({
                id: 3881
            })
        });
        const bytes = book.serialize();

        assert(test.Book.decode(new Deserializer(bytes)).serialize().equals(bytes));
    });

    it('should throw if a different than the expected constructor is given', function() {
        assert.throws(function() {
            new test.Book({
                id: 3881,
                author: new test.BoolTrue()
            });
        }, /invalid constructor for param "author". expected test.players.player but got test.boolTrue instead/);

        assert.throws(function() {
            test.Book.decode(new Deserializer(test.Book.encode({
                id: 37731,
                author: test.BoolTrue.encode()
            })));
        }, new RegExp(`invalid header for param \"author\". expected ${test.players.Player._id} but got ${test.BoolTrue._id} instead`));
    });
});
<commit_msg>test/test-schema.js: update constructor header identifier<commit_after>import _ from 'lodash';
import assert from 'assert';
import { Deserializer } from '../src';
import { test, Vector, decode } from '../build';

describe('TestSchema', function() {
    let deserializer;

    afterEach(() => {
        deserializer = null;
    });

    it('should decode any type', function() {
        assert(decode(test.BoolTrue.encode()).serialize().equals(test.BoolTrue.encode()));
    });

    it('should not allow unexpected properties', function() {
        assert.throws(function() {
            new test.UserStatus({
                online: true,
                a: 1
            });
        });
    });

    it('should support bool = true param', function() {
        const userStatus = test.UserStatus.decode(new Deserializer(test.UserStatus.encode({
            online: true
        })));

        assert.equal(userStatus.online, true);
    });

    it('should support bool = true param', function() {
        const userStatus = test.UserStatus.decode(new Deserializer(test.UserStatus.encode({
            online: false
        })));

        assert.equal(userStatus.online, false);
    });

    describe('Vector', function() {
        it('should deserialize vectors', function() {
            const vector = new Vector({
                type: 'int',
                items: [1,2,3,4,5,6,7]
            });
            const bytes = vector.serialize();

            assert(Vector.encode(vector).equals(bytes));
        });

        it('should support direct pointing to a constructor', function() {
            const vector = new Vector({
                type: 'test.account',
                items: [new test.Account({
                    id: 100,
                    email: 'a@b.c',
                    username: '1234567'
                })]
            });

            assert(Vector.decode({
                type: 'test.account',
                buffer: vector.serialize()
            }).serialize().equals(vector.serialize()));
        });

        it('should handle empty vectors', function() {
            const vector = new Vector({
                type: 'test.Account',
                items: []
            });

            assert.ok(Vector.decode({
                type: 'test.Account',
                buffer: vector.serialize()
            }).serialize().equals(vector.serialize()));
        });

        describe('toJSON()', function() {
            it('should transform Vector<int> to JSON', function() {
                assert.equal(JSON.stringify(new Vector({
                    type: 'int',
                    items: [1,2,3,4]
                })), '[1,2,3,4]');
            });

            it('should transform Vector<test.Account> into JSON', function() {
                const vector = new Vector({
                    type: 'test.Account',
                    items: [new test.Account({
                        id: 100,
                        email: 'a@b.c',
                        username: '1234567'
                    })]
                });

                assert.equal(JSON.stringify(vector), JSON.stringify([{
                    id: 100,
                    username: '1234567',
                    email: 'a@b.c'
                }]));
            });
        });
    });

    describe('toJSON()', function() {
        it('should transform into plain object', function() {
            const account = new test.Account({
                id: 100,
                email: 'a@b.c.',
                username: '1234567'
            });
            assert.deepEqual(account.toJSON(), {
                id: 100,
                email: 'a@b.c.',
                username: '1234567'
            });

            assert.equal(JSON.stringify(account), JSON.stringify({
                id: 100,
                username: '1234567',
                email: 'a@b.c.'
            }));
        });
    });

    describe('serialize()', function() {
        it('should serialize constructor properties into buffer', function() {
            const bytes = new test.Account({
                id: 100,
                email: 'victor@nice.com',
                username: 'victorqueiroz'
            }).serialize();
        });
    });

    describe('static: encode()', function() {
        it('should encode simple constructors', function() {
            const bytes = test.Account.encode({
                id: 100,
                username: 'victorqueiroz',
                email: 'queiroz@messenger.im'
            });

            deserializer = new Deserializer(bytes);

            assert.equal(test.Account._header.readUInt32LE(0), deserializer._readBytes(4).readUInt32LE(0));
            assert.equal(100, deserializer.readInt());
            assert.equal('victorqueiroz', deserializer.readString());
            assert.equal('queiroz@messenger.im', deserializer.readString());
            assert.equal(deserializer.offset, deserializer.buffer.byteLength);
        });

        it('should encode complex constructors', function() {
            const bytes = test.Post.encode({
                id: 20,
                body: 'xxxx',
                author: test.Account.encode({
                    id: 100,
                    username: 'xxxx',
                    email: 'xxxx@xxxx.xxxx',
                })
            });

            deserializer = new Deserializer(bytes);

            assert.equal(test.Post._header.readUInt32LE(0), deserializer._readBytes(4).readUInt32LE(0));
            assert.equal(20, deserializer.readInt());

            // attr: author
            assert.equal(test.Account._header.readUInt32LE(0), deserializer._readBytes(4).readUInt32LE(0));
            assert.equal(100, deserializer.readInt());
            assert.equal('xxxx', deserializer.readString());
            assert.equal('xxxx@xxxx.xxxx', deserializer.readString());

            // attr: body
            assert.equal('xxxx', deserializer.readString());
        });

        it('should decode vector inside constructors', function() {
            const bytes = test.players.PlayersList.encode({
                players: Vector.encode({
                    type: 'test.players.Player',
                    items: [test.players.Player.encode({
                        id: 100
                    })]
                })
            });

            const result = test.players.PlayersList.decode(new Deserializer(bytes));

            result.players.forEach(player => {
                assert.equal(player.id, 100);
            });
        });

        it('should validate vector type using schema prefix for non-generic types', function() {
            new test.players.PlayersList({
                players: new Vector({
                    type: 'test.players.Player',
                    items: [new test.players.Player({
                        id: 31848
                    })]
                })
            });
        });

        it('should throw if invalid vector type is given', function() {
            assert.throws(function() {
                new test.players.PlayersList({
                    players: new Vector({
                        type: 'test.players.player',
                        items: []
                    })
                });
            }, /invalid vector type for param players. expected test.players.Player but got test.players.player instead/);
        });

        it('should throw for invalid bool type', function() {
            assert.throws(function() {
                new test.UserStatus({
                    online: 0
                });
            }, /Invalid type for param \"online\"\. expected type boolean but got number instead. Check constructor test\.userStatus/);
        });
    });

    describe('static: decode()', function() {
        it('should decode simple constructors', function() {
            const bytes = test.Account.encode({
                id: 100,
                username: 'victorqueiroz',
                email: 'queiroz@messenger.im'
            });

            const account = test.Account.decode(new Deserializer(bytes));

            assert.equal(account.id, 100);
            assert.equal(account.username, 'victorqueiroz',);
            assert.equal(account.email, 'queiroz@messenger.im');
        });

        it('should decode complex constructors', function() {
            const bytes = test.Post.encode({
                id: 20,
                body: 'xxxx',
                author: test.Account.encode({
                    id: 100,
                    username: 'xxxx',
                    email: 'xxxx@xxxx.xxxx',
                })
            });

            const post = test.Post.decode(new Deserializer(bytes));

            assert.equal(post.id, 20);
            assert.equal(post.body, 'xxxx');

            _.forEach({
                id: 100,
                email: 'xxxx@xxxx.xxxx',
                username: 'xxxx'
            }, function(value, key) {
                assert.equal(post.author[key], value);
            });
        });
    });

    it('should encode Vector<double>', function() {
        const vector = Vector.decode({
            type: 'double',
            buffer: Vector.encode({
                type: 'double',
                items: [
                    -33.398824,
                    12.31388
                ]
            })
        });

        assert.deepEqual(vector.items, [-33.398824, 12.31388]);
    });

    it('should encode Vector<players.Player>', function() {
        const bytes = Vector.encode({
            type: 'test.players.Player',
            items: [test.players.Player.encode({
                id: 100
            })]
        });

        deserializer = new Deserializer(bytes);
        assert.equal(Vector._id, deserializer._readBytes(4).readUInt32LE(0));
        assert.equal(1, deserializer.readUInt());
        assert.equal(test.players.Player._id, deserializer._readBytes(4).readUInt32LE(0));
        assert.equal(100, deserializer.readInt());
    });

    it('should decode Vector<players.Player>', function() {
        const bytes = Vector.encode({
            type: 'test.players.Player',
            items: [test.players.Player.encode({
                id: 100
            })]
        });

        const result = Vector.decode({
            type: 'test.players.Player',
            buffer: bytes
        });

        result.forEach(item => {
            assert.equal(item.id, 100);
        });
    });

    it('should encode Vector<int>', function() {
        const bytes = Vector.encode({
            type: 'int',
            items: [1,2,3,4,5]
        });

        deserializer = new Deserializer(bytes);
        assert.ok(Vector._id, deserializer._readBytes(4).readUInt32LE(0));
        assert.equal(5, deserializer.readUInt());
        assert.equal(1, deserializer.readInt());
        assert.equal(2, deserializer.readInt());
        assert.equal(3, deserializer.readInt());
        assert.equal(4, deserializer.readInt());
        assert.equal(5, deserializer.readInt());
    });

    it('should decode Vector<int>', function() {
        const items = [1,2,3,4,5];
        const bytes = Vector.encode({
            type: 'int',
            items: items
        });

        const vector = Vector.decode({
            type: 'int',
            buffer: bytes
        });

        items.forEach((n, i) => {
            assert.equal(vector.nth(i), n);
        });
    });

    it('should encode Vector<long>', function() {
        const vector = new Vector({
            type: 'long',
            items: [255, -255, -64]
        });

        assert(vector.serialize().equals(Vector.decode({
            type: 'long',
            buffer: vector.serialize()
        }).serialize()));
    });

    it('should encode Vector<string>', function() {
        const bytes = Vector.encode({
            type: 'string',
            items: ['a', 'b', 'c', 'd', 'e']
        });

        deserializer = new Deserializer(bytes);
        assert.equal(Vector._id, deserializer._readBytes(4).readUInt32LE(0));
        assert.equal(5, deserializer.readUInt());
        assert.equal('a', deserializer.readString());
        assert.equal('b', deserializer.readString());
        assert.equal('c', deserializer.readString());
        assert.equal('d', deserializer.readString());
        assert.equal('e', deserializer.readString());
    });

    it('should encode Vector<test.Post> using serialize()', function() {
        const vector = new Vector({
            type: 'test.Post',
            items: [new test.Post({
                id: 100,
                body: '',
                author: new test.Account({
                    id: 100,
                    email: '100@100.100',
                    username: '100'
                })
            }),
            new test.Post({
                id: 200,
                body: '',
                author: new test.Account({
                    id: 200,
                    email: '200@200.200',
                    username: '200'
                })
            })]
        });

        assert(vector.serialize().equals(Vector.encode({
            type: 'test.Post',
            items: [test.Post.encode({
                id: 100,
                body: '',
                author: test.Account.encode({
                    id: 100,
                    email: '100@100.100',
                    username: '100'
                })
            }),
            test.Post.encode({
                id: 200,
                body: '',
                author: test.Account.encode({
                    id: 200,
                    email: '200@200.200',
                    username: '200'
                })
            })]
        })));
    });

    it('should decode Vector<string>', function() {
        const items = ['a', 'b', 'c', 'd', 'e'];
        const bytes = Vector.encode({
            type: 'string',
            items: items
        });

        const vector = Vector.decode({
            type: 'string',
            buffer: bytes
        });

        items.forEach((item, i) => {
            assert.equal(vector.nth(i), item);
        });
    });

    it('should throw an error if you instantiate a constructor with a missing param', function() {
        assert.throws(function() {
            new test.Account({

            });
        }, /missing property \"id\" for \"test.account\" constructor/);
    });

    it('should throw if found a invalid header for non-generic param type', function() {
        const bytes = test.Post.encode({
            id: 100,
            author: test.Account.encode({
                id: 100,
                username: 'xxxxxx',
                email: 'xxxxx'
            }),
            body: ''
        });

        assert.equal(bytes.readUInt32LE(8), test.Account._id);
        bytes.writeUInt32LE(Vector._id, 8);

        assert.throws(function() {
            test.Post.decode(new Deserializer(bytes));
        }, /invalid header for param \"author\". expected 956573801 but got 460212315 instead/);
    });

    it('should throw if give an invalid param type is given', function() {
        assert.throws(function() {
            new test.players.CreatePlayer({
                online: new test.players.CreatePlayer({
                    online: new test.BoolTrue()
                })
            });
        }, /invalid type for param "online". expected test.Bool but got test.players.CreatePlayerResponse instead/);
    });

    it('should support direct linking to constructor', function(){
        const book = new test.Book({
            id: 23771,
            author: new test.players.Player({
                id: 3881
            })
        });
        const bytes = book.serialize();

        assert(test.Book.decode(new Deserializer(bytes)).serialize().equals(bytes));
    });

    it('should throw if a different than the expected constructor is given', function() {
        assert.throws(function() {
            new test.Book({
                id: 3881,
                author: new test.BoolTrue()
            });
        }, /invalid constructor for param "author". expected test.players.player but got test.boolTrue instead/);

        assert.throws(function() {
            test.Book.decode(new Deserializer(test.Book.encode({
                id: 37731,
                author: test.BoolTrue.encode()
            })));
        }, new RegExp(`invalid header for param \"author\". expected ${test.players.Player._id} but got ${test.BoolTrue._id} instead`));
    });
});
<|endoftext|>


<commit_before>// Forked from Anvil's http host and other modules
// Copyright Alex Robson 2011
// MIT License - http://opensource.org/licenses/MIT

var http = require( 'http' ),
	ServerResponse = require( 'http' ).ServerResponse,
	express = require( 'express' ),
	path = require( 'path' ),
	fs = require( 'fs' ),
	url = require( 'url' ),
	net = require ( 'net' ),
	_ = require( 'lodash' ),
	mkdirp = require( 'mkdirp' ),
	Monologue = require( 'monologue.js' )( _ ),
	watchTree = require( 'fs-watch-tree' ).watchTree,
	metrics = require( 'cluster-metrics' );

module.exports = function( config ) {
	var PREFIX = 'autohost';

	var Host = function() {
		this.clients = [];
		this.clients.lookup = {};
		this.compilers = {};
		this.middleware = {};
		this.config = config || {};
		this.topics = {};
		this.resources = {};
		this.actions = {};
		this.metrics = metrics;
		this.appName = this.config.appName || 'autohost';
		_.bindAll( this );
	};

	Host.prototype.addCompiler = function( extension, callback ) {
		this.compilers[ extension ] = callback;
		if( this.app ) {
			this.app.engine( extension, callback );
		}
	};

	Host.prototype.addMiddleware = function( filter, middleware ) {
		this.middleware[ filter ] = middleware;
		if( this.app ) {
			this.app.use( filter, middleware );
		}
	};

	Host.prototype.buildPath = function( pathSpec ) {
		var hasLocalPrefix;
		pathSpec = pathSpec || '';
		if( _.isArray( pathSpec ) ) {
			hasLocalPrefix = pathSpec[0].match( /^[.]\// );
			pathSpec = path.join.apply( {}, pathSpec );
		}
		pathSpec = pathSpec.replace( /^~/, process.env.HOME );
		return hasLocalPrefix ? './' + pathSpec : pathSpec;
	};

	// yay, Jim Cowart to the rescue with this bit
	Host.prototype.buildUrl = function() {
		var idx = 0,
			cleaned = [];
		while( idx < arguments.length ) {
			var segment = arguments[ idx ];
			if( segment.substr( 0, 1 ) === '/' ) {
				segment = segment.substr( 1 );
			}
			if( segment.substr( segment.length-1, 1 ) === '/' ) {
				segment = segment.substring( 0, segment.length - 1 );
			}
			if( !_.isEmpty( segment ) ) {
				cleaned.push( segment );
			}
			idx++;
		}
		return '/' + cleaned.join( '/' );
	};

	Host.prototype.handleRoute = function( url, verb, resource, handle, action ) {
		this.registerRoute( url, verb, function( req, res ) {
			var respond = function() {
				var envelope = {
					data: req.body,
					path: req.url,
					headers: req.headers,
					params: {},
					files: req.files,
					user: req.user,
					reply: function( envelope ) {
						var code = envelope.statusCode || 200;
						res.send( code, envelope.data );
					},
					replyWithFile: function(envelope, contentType, sendFileName, sendStream) {
						res.set({
							"Content-Disposition": 'attachment; filename="'+sendFileName+'"',
							"Content-Type": contentType
						});
						sendStream.pipe(res);
					}
				};
				for( var key in req.params ) {
					var val = req.params[ key ];
					if( !envelope.data[ key ] ) {
						envelope.data[ key ] = val;
					}
					envelope.params[ key ] = val;
				}
				for( var key in req.query ) {
					var val = req.query[ key ];
					if( !envelope.data[ key ] ) {
						envelope.data[ key ] = val;
					}
					envelope.params[ key ] = val;
				}
				handle.apply( resource, [ envelope ] );
			};

			if( this.authorizer ) {
				this.authorizer.getRolesFor( action, function( err, roles ) {
					roles = err ? [] : roles;

					if( roles.length > 0 && _.intersection( roles, req.user.roles ) == 0 ) {
						res.send( 403, "User lacks sufficient permissions" );
					} else {
						respond();
					}

				} );
			} else {
				respond();
			}
		}.bind( this ) );
	};

	Host.prototype.handleTopic = function( topic, resource, handle, action ) {
		this.registerTopic( topic, function( message, socket ) {
			var respond = function() {
				var envelope = {
					data: message.data || message,
					headers: message.headers || [],
					socket: socket,
					user: socket.user,
					path: message.topic,
					reply: function( envelope ) {
						socket.publish( message.replyTo, envelope );
					}
				};
				handle.apply( resource, [ envelope ] );
			};

			if( this.authorizer ) {
				this.authorizer.getRolesFor( action, function( err, roles ) {
					roles = err ? [] : roles;
					if( roles.length > 0 && _.intersection( roles, socket.user.roles ) == 0 ) {
						socket.publish( 'NoPe', 'User lacks sufficient permissions' );
					} else {
						respond();
					}
				} );
			} else {
				respond();
			}
		}.bind( this ) );
	};

	Host.prototype.init = function( config ) {
		if( config ) {
			this.config = _.merge( this.config, config );
		}
		var self = this,
			cwd = process.cwd(),
			tmp = path.resolve( cwd, ( this.config.temp || './tmp' ) ),
			public = path.resolve( cwd, ( this.config.static || './public' ) ),
			resources = path.resolve( cwd, ( this.config.resources || './resource' ) );

		mkdirp( tmp );

		this.app = express();
		this.app.use( '/api', function( req, res, next ) {
			if( req.method == 'OPTIONS' || req.method == 'options' ) {
				res.send( 200, this.resources );
			} else {
				next();
			}
		}.bind( this ) );
		this.app.use( express.cookieParser() );
		this.app.use( express.bodyParser( {
			uploadDir: tmp,
			keepExtensions: true
		} ) );
		this.app.use( express.session( { secret: 'authostthing' } ) );

		this.app.use( function( req, res, next ) {
			res.header( 'Access-Control-Allow-Origin', '*' );
			res.header( 'Access-Control-Allow-Headers', 'X-Requested-With' );
			next();
		} );

		this.addAuthentication();

		_.each( this.middleware, function( op, path ) {
			self.app.use( path, op );
		} );

		this.app.use( this.app.router );
		this.registerPath( '/', public );
		this.loadResources( resources ).done(function () {
			this.processResource( 'api', require( './_autohost/resource.js' )( this ), path.resolve( __dirname, './_autohost' ) );
			if( this.authorizer ) {
				var list = [];
				_.each( this.actions, function( actions, resource ) {
					_.each( actions, function( action ) {
						list.push( { name: action, resource: resource } );
					} );
				} );
				this.authorizer.actionList( list, function() {} );
			}
		}.bind(this));

		this.server = http.createServer( this.app ).listen( this.config.port || 8800 );
		this.configureWebsockets();
		this.configureSocketIO();
		console.log( 'autohost listening on port ', ( this.config.port || 8800 ) );
	};

	Host.prototype.registerRoute = function( url, verb, callback ) {
		verb = verb.toLowerCase();
		var routes = this.app.routes[ verb ],
			timer = [ PREFIX, url, verb, 'timer' ].join( '.' ),
			errors = [ PREFIX, url, verb, 'errors' ].join( '.' );
		if( routes ) {
			var index = routes.indexOf( url );
			if( index >= 0 )
			{
				console.log( 'remove duplicate route for ', url, verb );
				this.app.routes[ verb ].splice( index, 1 );
			}
		}
		if( this.app ) {
			this.app[ verb ]( url, function( req, res ) {
				try {
					metrics.timer( timer ).start();
					callback( req, res );
					metrics.timer( timer ).record();
				} catch ( err ) {
					metrics.meter( errors ).record();
					console.log( 'error on route, "' + url + '" verb "' + verb + '"', err );
				}
			} );
		}
	};

	Host.prototype.registerPath = function( url, filePath ) {
		if( this.app ) {
			this.app.use( url, express[ 'static' ]( path.resolve( filePath ) ) );
		}
	};

	Host.prototype.registerTopic = function( topic, callback ) {
		var timer = [ PREFIX, topic, 'timer' ].join( '.' ),
			errors = [ PREFIX, topic, 'errors' ].join( '.' );
		this.topics[ topic ] = callback;
		_.each( this.clients, function( client ) {
			client.removeAllListeners( topic );
			client.on( topic, function( data ) {
				try {
					metrics.timer( timer ).start();
					callback( data, client );
					metrics.timer( timer ).record();
				} catch ( err ) {
					metrics.meter( errors ).record();
					console.log( 'error on topic, "' + topic + '"', err );
				}
			} );
		} );
	};

	Host.prototype.watch = function( filePath ) {
		var self = this;
		if( !fs.existsSync( filePath ) )
			return;
		return watchTree( filePath,
			_.debounce( function( event ) {
				if( !event.isDirectory() ) {
					self.loadModule( event.name );
				}
			}, 500, true )
		);
	};

	require( './passport.js' )( Host );
	require( './resource.js' )( Host );
	require( './websockets.js' )( Host );
	require( './socketio.js' )( Host );

	Monologue.mixin( Host );
	_.bindAll( Host );
	return new Host();
};<commit_msg>make sure authorizer actionList has completed before starting server and returning from init<commit_after>// Forked from Anvil's http host and other modules
// Copyright Alex Robson 2011
// MIT License - http://opensource.org/licenses/MIT

var http = require( 'http' ),
	ServerResponse = require( 'http' ).ServerResponse,
	express = require( 'express' ),
	path = require( 'path' ),
	fs = require( 'fs' ),
	url = require( 'url' ),
	net = require ( 'net' ),
	_ = require( 'lodash' ),
	mkdirp = require( 'mkdirp' ),
	Monologue = require( 'monologue.js' )( _ ),
	watchTree = require( 'fs-watch-tree' ).watchTree,
	metrics = require( 'cluster-metrics' );

module.exports = function( config ) {
	var PREFIX = 'autohost';

	var Host = function() {
		this.clients = [];
		this.clients.lookup = {};
		this.compilers = {};
		this.middleware = {};
		this.config = config || {};
		this.topics = {};
		this.resources = {};
		this.actions = {};
		this.metrics = metrics;
		this.appName = this.config.appName || 'autohost';
		_.bindAll( this );
	};

	Host.prototype.addCompiler = function( extension, callback ) {
		this.compilers[ extension ] = callback;
		if( this.app ) {
			this.app.engine( extension, callback );
		}
	};

	Host.prototype.addMiddleware = function( filter, middleware ) {
		this.middleware[ filter ] = middleware;
		if( this.app ) {
			this.app.use( filter, middleware );
		}
	};

	Host.prototype.buildPath = function( pathSpec ) {
		var hasLocalPrefix;
		pathSpec = pathSpec || '';
		if( _.isArray( pathSpec ) ) {
			hasLocalPrefix = pathSpec[0].match( /^[.]\// );
			pathSpec = path.join.apply( {}, pathSpec );
		}
		pathSpec = pathSpec.replace( /^~/, process.env.HOME );
		return hasLocalPrefix ? './' + pathSpec : pathSpec;
	};

	// yay, Jim Cowart to the rescue with this bit
	Host.prototype.buildUrl = function() {
		var idx = 0,
			cleaned = [];
		while( idx < arguments.length ) {
			var segment = arguments[ idx ];
			if( segment.substr( 0, 1 ) === '/' ) {
				segment = segment.substr( 1 );
			}
			if( segment.substr( segment.length-1, 1 ) === '/' ) {
				segment = segment.substring( 0, segment.length - 1 );
			}
			if( !_.isEmpty( segment ) ) {
				cleaned.push( segment );
			}
			idx++;
		}
		return '/' + cleaned.join( '/' );
	};

	Host.prototype.handleRoute = function( url, verb, resource, handle, action ) {
		this.registerRoute( url, verb, function( req, res ) {
			var respond = function() {
				var envelope = {
					data: req.body,
					path: req.url,
					headers: req.headers,
					params: {},
					files: req.files,
					user: req.user,
					reply: function( envelope ) {
						var code = envelope.statusCode || 200;
						res.send( code, envelope.data );
					},
					replyWithFile: function(envelope, contentType, sendFileName, sendStream) {
						res.set({
							"Content-Disposition": 'attachment; filename="'+sendFileName+'"',
							"Content-Type": contentType
						});
						sendStream.pipe(res);
					}
				};
				for( var key in req.params ) {
					var val = req.params[ key ];
					if( !envelope.data[ key ] ) {
						envelope.data[ key ] = val;
					}
					envelope.params[ key ] = val;
				}
				for( var key in req.query ) {
					var val = req.query[ key ];
					if( !envelope.data[ key ] ) {
						envelope.data[ key ] = val;
					}
					envelope.params[ key ] = val;
				}
				handle.apply( resource, [ envelope ] );
			};

			if( this.authorizer ) {
				this.authorizer.getRolesFor( action, function( err, roles ) {
					roles = err ? [] : roles;

					if( roles.length > 0 && _.intersection( roles, req.user.roles ) == 0 ) {
						res.send( 403, "User lacks sufficient permissions" );
					} else {
						respond();
					}

				} );
			} else {
				respond();
			}
		}.bind( this ) );
	};

	Host.prototype.handleTopic = function( topic, resource, handle, action ) {
		this.registerTopic( topic, function( message, socket ) {
			var respond = function() {
				var envelope = {
					data: message.data || message,
					headers: message.headers || [],
					socket: socket,
					user: socket.user,
					path: message.topic,
					reply: function( envelope ) {
						socket.publish( message.replyTo, envelope );
					}
				};
				handle.apply( resource, [ envelope ] );
			};

			if( this.authorizer ) {
				this.authorizer.getRolesFor( action, function( err, roles ) {
					roles = err ? [] : roles;
					if( roles.length > 0 && _.intersection( roles, socket.user.roles ) == 0 ) {
						socket.publish( 'NoPe', 'User lacks sufficient permissions' );
					} else {
						respond();
					}
				} );
			} else {
				respond();
			}
		}.bind( this ) );
	};

	Host.prototype.init = function( config, done ) {
		if( config ) {
			this.config = _.merge( this.config, config );
		}
		var self = this,
			cwd = process.cwd(),
			tmp = path.resolve( cwd, ( this.config.temp || './tmp' ) ),
			public = path.resolve( cwd, ( this.config.static || './public' ) ),
			resources = path.resolve( cwd, ( this.config.resources || './resource' ) );

		mkdirp( tmp );

		this.app = express();
		this.app.use( '/api', function( req, res, next ) {
			if( req.method == 'OPTIONS' || req.method == 'options' ) {
				res.send( 200, this.resources );
			} else {
				next();
			}
		}.bind( this ) );
		this.app.use( express.cookieParser() );
		this.app.use( express.bodyParser( {
			uploadDir: tmp,
			keepExtensions: true
		} ) );
		this.app.use( express.session( { secret: 'authostthing' } ) );

		this.app.use( function( req, res, next ) {
			res.header( 'Access-Control-Allow-Origin', '*' );
			res.header( 'Access-Control-Allow-Headers', 'X-Requested-With' );
			next();
		} );

		this.addAuthentication();

		_.each( this.middleware, function( op, path ) {
			self.app.use( path, op );
		} );

		var startServer = function() {
			this.server = http.createServer( this.app ).listen( this.config.port || 8800 );
			this.configureWebsockets();
			this.configureSocketIO();
			console.log( 'autohost listening on port ', ( this.config.port || 8800 ) );
			if (done) done();
		}.bind(this);

		this.app.use( this.app.router );
		this.registerPath( '/', public );
		this.loadResources( resources ).done(function () {
			this.processResource( 'api', require( './_autohost/resource.js' )( this ), path.resolve( __dirname, './_autohost' ) );
			if( this.authorizer ) {
				var list = [];
				_.each( this.actions, function( actions, resource ) {
					_.each( actions, function( action ) {
						list.push( { name: action, resource: resource } );
					} );
				} );
				this.authorizer.actionList( list, function() {
					startServer();
				} );
			} else {
				startServer();
			}
		}.bind(this));

	};

	Host.prototype.registerRoute = function( url, verb, callback ) {
		verb = verb.toLowerCase();
		var routes = this.app.routes[ verb ],
			timer = [ PREFIX, url, verb, 'timer' ].join( '.' ),
			errors = [ PREFIX, url, verb, 'errors' ].join( '.' );
		if( routes ) {
			var index = routes.indexOf( url );
			if( index >= 0 )
			{
				console.log( 'remove duplicate route for ', url, verb );
				this.app.routes[ verb ].splice( index, 1 );
			}
		}
		if( this.app ) {
			this.app[ verb ]( url, function( req, res ) {
				try {
					metrics.timer( timer ).start();
					callback( req, res );
					metrics.timer( timer ).record();
				} catch ( err ) {
					metrics.meter( errors ).record();
					console.log( 'error on route, "' + url + '" verb "' + verb + '"', err );
				}
			} );
		}
	};

	Host.prototype.registerPath = function( url, filePath ) {
		if( this.app ) {
			this.app.use( url, express[ 'static' ]( path.resolve( filePath ) ) );
		}
	};

	Host.prototype.registerTopic = function( topic, callback ) {
		var timer = [ PREFIX, topic, 'timer' ].join( '.' ),
			errors = [ PREFIX, topic, 'errors' ].join( '.' );
		this.topics[ topic ] = callback;
		_.each( this.clients, function( client ) {
			client.removeAllListeners( topic );
			client.on( topic, function( data ) {
				try {
					metrics.timer( timer ).start();
					callback( data, client );
					metrics.timer( timer ).record();
				} catch ( err ) {
					metrics.meter( errors ).record();
					console.log( 'error on topic, "' + topic + '"', err );
				}
			} );
		} );
	};

	Host.prototype.watch = function( filePath ) {
		var self = this;
		if( !fs.existsSync( filePath ) )
			return;
		return watchTree( filePath,
			_.debounce( function( event ) {
				if( !event.isDirectory() ) {
					self.loadModule( event.name );
				}
			}, 500, true )
		);
	};

	require( './passport.js' )( Host );
	require( './resource.js' )( Host );
	require( './websockets.js' )( Host );
	require( './socketio.js' )( Host );

	Monologue.mixin( Host );
	_.bindAll( Host );
	return new Host();
};<|endoftext|>


<commit_before>module.exports = {
	useYarn: true,
	scenarios: [
		{
			name: 'ember-lts-2.16',
			npm: {
				devDependencies: {
					'ember-source': '~2.16.0'
				}
			}
		},
		{
			name: 'ember-release',
			bower: {
				dependencies: {
					ember: 'components/ember#release'
				},
				resolutions: {
					ember: 'release'
				}
			},
			npm: {
				devDependencies: {
					'ember-source': null
				}
			}
		},
		{
			name: 'ember-beta',
			bower: {
				dependencies: {
					ember: 'components/ember#beta'
				},
				resolutions: {
					ember: 'beta'
				}
			},
			npm: {
				devDependencies: {
					'ember-source': null
				}
			}
		},
		{
			name: 'ember-canary',
			bower: {
				dependencies: {
					ember: 'components/ember#canary'
				},
				resolutions: {
					ember: 'canary'
				}
			},
			npm: {
				devDependencies: {
					'ember-source': null
				}
			}
		},
		{
			name: 'ember-default',
			npm: {
				devDependencies: {}
			}
		}
	]
}
<commit_msg>Test multiple d3 releases<commit_after>module.exports = {
  useYarn: true,
  scenarios: [
    {
      name: 'ember-lts-2.16',
      npm: {
        devDependencies: {
          'ember-source': '~2.16.0',
          d3: '4.0.0'
        }
      }
    },

    {
      name: 'ember-2.18-d3-4.1',
      npm: {
        devDependencies: {
          'ember-source': '~2.18.0',
          d3: '4.1.0'
        }
      }
    },

    {
      name: 'ember-2.18-d3-4.2',
      npm: {
        devDependencies: {
          'ember-source': '~2.18.0',
          d3: '4.2.0'
        }
      }
    },

    {
      name: 'ember-2.18-d3-4.7',
      npm: {
        devDependencies: {
          'ember-source': '~2.18.0',
          d3: '4.7.0'
        }
      }
    },

    {
      name: 'ember-2.18-d3-4.4.13',
      npm: {
        devDependencies: {
          'ember-source': '~2.18.0',
          d3: '4.13.0'
        }
      }
    },
    {
      name: 'ember-default',
      npm: {
        devDependencies: {}
      }
    }
  ]
}
<|endoftext|>