<commit_before>
import KDBush from 'kdbush';

const defaultOptions = {
    minZoom: 0,   // min zoom to generate clusters on
    maxZoom: 16,  // max zoom level to cluster the points on
    radius: 40,   // cluster radius in pixels
    extent: 512,  // tile extent (radius is calculated relative to it)
    nodeSize: 64, // size of the KD-tree leaf node, affects performance
    log: false,   // whether to log timing info

    // a reduce function for calculating custom cluster properties
    reduce: null, // (accumulated, props) => { accumulated.sum += props.sum; }

    // properties to use for individual points when running the reducer
    map: props => props // props => ({sum: props.my_value})
};

export default class Supercluster {
    constructor(options) {
        this.options = extend(Object.create(defaultOptions), options);
        this.trees = new Array(this.options.maxZoom + 1);
    }

    load(points) {
        const {log, minZoom, maxZoom, nodeSize} = this.options;

        if (log) console.time('total time');

        const timerId = `prepare ${  points.length  } points`;
        if (log) console.time(timerId);

        this.points = points;

        // generate a cluster object for each point and index input points into a KD-tree
        let clusters = [];
        for (let i = 0; i < points.length; i++) {
            if (!points[i].geometry) continue;
            clusters.push(createPointCluster(points[i], i));
        }
        this.trees[maxZoom + 1] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);

        if (log) console.timeEnd(timerId);

        // cluster points on max zoom, then cluster the results on previous zoom, etc.;
        // results in a cluster hierarchy across zoom levels
        for (let z = maxZoom; z >= minZoom; z--) {
            const now = +Date.now();

            // create a new set of clusters for the zoom and index them with a KD-tree
            clusters = this._cluster(clusters, z);
            this.trees[z] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);

            if (log) console.log('z%d: %d clusters in %dms', z, clusters.length, +Date.now() - now);
        }

        if (log) console.timeEnd('total time');

        return this;
    }

    getClusters(bbox, zoom) {
        let minLng = ((bbox[0] + 180) % 360 + 360) % 360 - 180;
        const minLat = Math.max(-90, Math.min(90, bbox[1]));
        let maxLng = bbox[2] === 180 ? 180 : ((bbox[2] + 180) % 360 + 360) % 360 - 180;
        const maxLat = Math.max(-90, Math.min(90, bbox[3]));

        if (bbox[2] - bbox[0] >= 360) {
            minLng = -180;
            maxLng = 180;
        } else if (minLng > maxLng) {
            const easternHem = this.getClusters([minLng, minLat, 180, maxLat], zoom);
            const westernHem = this.getClusters([-180, minLat, maxLng, maxLat], zoom);
            return easternHem.concat(westernHem);
        }

        const tree = this.trees[this._limitZoom(zoom)];
        const ids = tree.range(lngX(minLng), latY(maxLat), lngX(maxLng), latY(minLat));
        const clusters = [];
        for (const id of ids) {
            const c = tree.points[id];
            clusters.push(c.numPoints ? getClusterJSON(c) : this.points[c.index]);
        }
        return clusters;
    }

    getChildren(clusterId) {
        const originId = clusterId >> 5;
        const originZoom = clusterId % 32;
        const errorMsg = 'No cluster with the specified id.';

        const index = this.trees[originZoom];
        if (!index) throw new Error(errorMsg);

        const origin = index.points[originId];
        if (!origin) throw new Error(errorMsg);

        const r = this.options.radius / (this.options.extent * Math.pow(2, originZoom - 1));
        const ids = index.within(origin.x, origin.y, r);
        const children = [];
        for (const id of ids) {
            const c = index.points[id];
            if (c.parentId === clusterId) {
                children.push(c.numPoints ? getClusterJSON(c) : this.points[c.index]);
            }
        }

        if (children.length === 0) throw new Error(errorMsg);

        return children;
    }

    getLeaves(clusterId, limit, offset) {
        limit = limit || 10;
        offset = offset || 0;

        const leaves = [];
        this._appendLeaves(leaves, clusterId, limit, offset, 0);

        return leaves;
    }

    getTile(z, x, y) {
        const tree = this.trees[this._limitZoom(z)];
        const z2 = Math.pow(2, z);
        const {extent, radius} = this.options;
        const p = radius / extent;
        const top = (y - p) / z2;
        const bottom = (y + 1 + p) / z2;

        const tile = {
            features: []
        };

        this._addTileFeatures(
            tree.range((x - p) / z2, top, (x + 1 + p) / z2, bottom),
            tree.points, x, y, z2, tile);

        if (x === 0) {
            this._addTileFeatures(
                tree.range(1 - p / z2, top, 1, bottom),
                tree.points, z2, y, z2, tile);
        }
        if (x === z2 - 1) {
            this._addTileFeatures(
                tree.range(0, top, p / z2, bottom),
                tree.points, -1, y, z2, tile);
        }

        return tile.features.length ? tile : null;
    }

    getClusterExpansionZoom(clusterId) {
        let clusterZoom = (clusterId % 32) - 1;
        while (clusterZoom <= this.options.maxZoom) {
            const children = this.getChildren(clusterId);
            clusterZoom++;
            if (children.length !== 1) break;
            clusterId = children[0].properties.cluster_id;
        }
        return clusterZoom;
    }

    _appendLeaves(result, clusterId, limit, offset, skipped) {
        const children = this.getChildren(clusterId);

        for (const child of children) {
            const props = child.properties;

            if (props && props.cluster) {
                if (skipped + props.point_count <= offset) {
                    // skip the whole cluster
                    skipped += props.point_count;
                } else {
                    // enter the cluster
                    skipped = this._appendLeaves(result, props.cluster_id, limit, offset, skipped);
                    // exit the cluster
                }
            } else if (skipped < offset) {
                // skip a single point
                skipped++;
            } else {
                // add a single point
                result.push(child);
            }
            if (result.length === limit) break;
        }

        return skipped;
    }

    _addTileFeatures(ids, points, x, y, z2, tile) {
        for (const i of ids) {
            const c = points[i];
            const f = {
                type: 1,
                geometry: [[
                    Math.round(this.options.extent * (c.x * z2 - x)),
                    Math.round(this.options.extent * (c.y * z2 - y))
                ]],
                tags: c.numPoints ? getClusterProperties(c) : this.points[c.index].properties
            };
            const id = c.numPoints ? c.id : this.points[c.index].id;
            if (id !== undefined) {
                f.id = id;
            }
            tile.features.push(f);
        }
    }

    _limitZoom(z) {
        return Math.max(this.options.minZoom, Math.min(z, this.options.maxZoom + 1));
    }

    _cluster(points, zoom) {
        const clusters = [];
        const {radius, extent, reduce} = this.options;
        const r = radius / (extent * Math.pow(2, zoom));

        // loop through each point
        for (let i = 0; i < points.length; i++) {
            const p = points[i];
            // if we've already visited the point at this zoom level, skip it
            if (p.zoom <= zoom) continue;
            p.zoom = zoom;

            // find all nearby points
            const tree = this.trees[zoom + 1];
            const neighborIds = tree.within(p.x, p.y, r);

            let numPoints = p.numPoints || 1;
            let wx = p.x * numPoints;
            let wy = p.y * numPoints;

            const clusterProperties = reduce ? this._map(p, true) : null;

            // encode both zoom and point index on which the cluster originated
            const id = (i << 5) + (zoom + 1);

            for (const neighborId of neighborIds) {
                const b = tree.points[neighborId];
                // filter out neighbors that are already processed
                if (b.zoom <= zoom) continue;
                b.zoom = zoom; // save the zoom (so it doesn't get processed twice)

                const numPoints2 = b.numPoints || 1;
                wx += b.x * numPoints2; // accumulate coordinates for calculating weighted center
                wy += b.y * numPoints2;

                numPoints += numPoints2;
                b.parentId = id;

                if (reduce) {
                    reduce(clusterProperties, this._map(b));
                }
            }

            if (numPoints === 1) {
                clusters.push(p);
            } else {
                p.parentId = id;
                clusters.push(createCluster(wx / numPoints, wy / numPoints, id, numPoints, clusterProperties));
            }
        }

        return clusters;
    }

    _map(point, clone) {
        if (point.numPoints) {
            return clone ? extend({}, point.properties) : point.properties;
        }
        const original = this.points[point.index].properties;
        const result = this.options.map(original);
        return clone && result === original ? extend({}, result) : result;
    }
}

function createCluster(x, y, id, numPoints, properties) {
    return {
        x, // weighted cluster center
        y,
        zoom: Infinity, // the last zoom the cluster was processed at
        id, // encodes index of the first child of the cluster and its zoom level
        parentId: -1, // parent cluster id
        numPoints,
        properties
    };
}

function createPointCluster(p, id) {
    const [x, y] = p.geometry.coordinates;
    return {
        x: lngX(x), // projected point coordinates
        y: latY(y),
        zoom: Infinity, // the last zoom the point was processed at
        index: id, // index of the source feature in the original input array,
        parentId: -1 // parent cluster id
    };
}

function getClusterJSON(cluster) {
    return {
        type: 'Feature',
        id: cluster.id,
        properties: getClusterProperties(cluster),
        geometry: {
            type: 'Point',
            coordinates: [xLng(cluster.x), yLat(cluster.y)]
        }
    };
}

function getClusterProperties(cluster) {
    const count = cluster.numPoints;
    const abbrev =
        count >= 10000 ? `${Math.round(count / 1000)  }k` :
        count >= 1000 ? `${Math.round(count / 100) / 10  }k` : count;
    return extend(extend({}, cluster.properties), {
        cluster: true,
        cluster_id: cluster.id,
        point_count: count,
        point_count_abbreviated: abbrev
    });
}

// longitude/latitude to spherical mercator in [0..1] range
function lngX(lng) {
    return lng / 360 + 0.5;
}
function latY(lat) {
    const sin = Math.sin(lat * Math.PI / 180);
    const y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);
    return y < 0 ? 0 : y > 1 ? 1 : y;
}

// spherical mercator to longitude/latitude
function xLng(x) {
    return (x - 0.5) * 360;
}
function yLat(y) {
    const y2 = (180 - y * 360) * Math.PI / 180;
    return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
}

function extend(dest, src) {
    for (const id in src) dest[id] = src[id];
    return dest;
}

function getX(p) {
    return p.x;
}
function getY(p) {
    return p.y;
}
<commit_msg>avoid redundant map calls on reduce (#131)<commit_after>
import KDBush from 'kdbush';

const defaultOptions = {
    minZoom: 0,   // min zoom to generate clusters on
    maxZoom: 16,  // max zoom level to cluster the points on
    radius: 40,   // cluster radius in pixels
    extent: 512,  // tile extent (radius is calculated relative to it)
    nodeSize: 64, // size of the KD-tree leaf node, affects performance
    log: false,   // whether to log timing info

    // a reduce function for calculating custom cluster properties
    reduce: null, // (accumulated, props) => { accumulated.sum += props.sum; }

    // properties to use for individual points when running the reducer
    map: props => props // props => ({sum: props.my_value})
};

export default class Supercluster {
    constructor(options) {
        this.options = extend(Object.create(defaultOptions), options);
        this.trees = new Array(this.options.maxZoom + 1);
    }

    load(points) {
        const {log, minZoom, maxZoom, nodeSize} = this.options;

        if (log) console.time('total time');

        const timerId = `prepare ${  points.length  } points`;
        if (log) console.time(timerId);

        this.points = points;

        // generate a cluster object for each point and index input points into a KD-tree
        let clusters = [];
        for (let i = 0; i < points.length; i++) {
            if (!points[i].geometry) continue;
            clusters.push(createPointCluster(points[i], i));
        }
        this.trees[maxZoom + 1] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);

        if (log) console.timeEnd(timerId);

        // cluster points on max zoom, then cluster the results on previous zoom, etc.;
        // results in a cluster hierarchy across zoom levels
        for (let z = maxZoom; z >= minZoom; z--) {
            const now = +Date.now();

            // create a new set of clusters for the zoom and index them with a KD-tree
            clusters = this._cluster(clusters, z);
            this.trees[z] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);

            if (log) console.log('z%d: %d clusters in %dms', z, clusters.length, +Date.now() - now);
        }

        if (log) console.timeEnd('total time');

        return this;
    }

    getClusters(bbox, zoom) {
        let minLng = ((bbox[0] + 180) % 360 + 360) % 360 - 180;
        const minLat = Math.max(-90, Math.min(90, bbox[1]));
        let maxLng = bbox[2] === 180 ? 180 : ((bbox[2] + 180) % 360 + 360) % 360 - 180;
        const maxLat = Math.max(-90, Math.min(90, bbox[3]));

        if (bbox[2] - bbox[0] >= 360) {
            minLng = -180;
            maxLng = 180;
        } else if (minLng > maxLng) {
            const easternHem = this.getClusters([minLng, minLat, 180, maxLat], zoom);
            const westernHem = this.getClusters([-180, minLat, maxLng, maxLat], zoom);
            return easternHem.concat(westernHem);
        }

        const tree = this.trees[this._limitZoom(zoom)];
        const ids = tree.range(lngX(minLng), latY(maxLat), lngX(maxLng), latY(minLat));
        const clusters = [];
        for (const id of ids) {
            const c = tree.points[id];
            clusters.push(c.numPoints ? getClusterJSON(c) : this.points[c.index]);
        }
        return clusters;
    }

    getChildren(clusterId) {
        const originId = clusterId >> 5;
        const originZoom = clusterId % 32;
        const errorMsg = 'No cluster with the specified id.';

        const index = this.trees[originZoom];
        if (!index) throw new Error(errorMsg);

        const origin = index.points[originId];
        if (!origin) throw new Error(errorMsg);

        const r = this.options.radius / (this.options.extent * Math.pow(2, originZoom - 1));
        const ids = index.within(origin.x, origin.y, r);
        const children = [];
        for (const id of ids) {
            const c = index.points[id];
            if (c.parentId === clusterId) {
                children.push(c.numPoints ? getClusterJSON(c) : this.points[c.index]);
            }
        }

        if (children.length === 0) throw new Error(errorMsg);

        return children;
    }

    getLeaves(clusterId, limit, offset) {
        limit = limit || 10;
        offset = offset || 0;

        const leaves = [];
        this._appendLeaves(leaves, clusterId, limit, offset, 0);

        return leaves;
    }

    getTile(z, x, y) {
        const tree = this.trees[this._limitZoom(z)];
        const z2 = Math.pow(2, z);
        const {extent, radius} = this.options;
        const p = radius / extent;
        const top = (y - p) / z2;
        const bottom = (y + 1 + p) / z2;

        const tile = {
            features: []
        };

        this._addTileFeatures(
            tree.range((x - p) / z2, top, (x + 1 + p) / z2, bottom),
            tree.points, x, y, z2, tile);

        if (x === 0) {
            this._addTileFeatures(
                tree.range(1 - p / z2, top, 1, bottom),
                tree.points, z2, y, z2, tile);
        }
        if (x === z2 - 1) {
            this._addTileFeatures(
                tree.range(0, top, p / z2, bottom),
                tree.points, -1, y, z2, tile);
        }

        return tile.features.length ? tile : null;
    }

    getClusterExpansionZoom(clusterId) {
        let clusterZoom = (clusterId % 32) - 1;
        while (clusterZoom <= this.options.maxZoom) {
            const children = this.getChildren(clusterId);
            clusterZoom++;
            if (children.length !== 1) break;
            clusterId = children[0].properties.cluster_id;
        }
        return clusterZoom;
    }

    _appendLeaves(result, clusterId, limit, offset, skipped) {
        const children = this.getChildren(clusterId);

        for (const child of children) {
            const props = child.properties;

            if (props && props.cluster) {
                if (skipped + props.point_count <= offset) {
                    // skip the whole cluster
                    skipped += props.point_count;
                } else {
                    // enter the cluster
                    skipped = this._appendLeaves(result, props.cluster_id, limit, offset, skipped);
                    // exit the cluster
                }
            } else if (skipped < offset) {
                // skip a single point
                skipped++;
            } else {
                // add a single point
                result.push(child);
            }
            if (result.length === limit) break;
        }

        return skipped;
    }

    _addTileFeatures(ids, points, x, y, z2, tile) {
        for (const i of ids) {
            const c = points[i];
            const f = {
                type: 1,
                geometry: [[
                    Math.round(this.options.extent * (c.x * z2 - x)),
                    Math.round(this.options.extent * (c.y * z2 - y))
                ]],
                tags: c.numPoints ? getClusterProperties(c) : this.points[c.index].properties
            };
            const id = c.numPoints ? c.id : this.points[c.index].id;
            if (id !== undefined) {
                f.id = id;
            }
            tile.features.push(f);
        }
    }

    _limitZoom(z) {
        return Math.max(this.options.minZoom, Math.min(z, this.options.maxZoom + 1));
    }

    _cluster(points, zoom) {
        const clusters = [];
        const {radius, extent, reduce} = this.options;
        const r = radius / (extent * Math.pow(2, zoom));

        // loop through each point
        for (let i = 0; i < points.length; i++) {
            const p = points[i];
            // if we've already visited the point at this zoom level, skip it
            if (p.zoom <= zoom) continue;
            p.zoom = zoom;

            // find all nearby points
            const tree = this.trees[zoom + 1];
            const neighborIds = tree.within(p.x, p.y, r);

            let numPoints = p.numPoints || 1;
            let wx = p.x * numPoints;
            let wy = p.y * numPoints;

            let clusterProperties = reduce && numPoints > 1 ? this._map(p, true) : null;

            // encode both zoom and point index on which the cluster originated
            const id = (i << 5) + (zoom + 1);

            for (const neighborId of neighborIds) {
                const b = tree.points[neighborId];
                // filter out neighbors that are already processed
                if (b.zoom <= zoom) continue;
                b.zoom = zoom; // save the zoom (so it doesn't get processed twice)

                const numPoints2 = b.numPoints || 1;
                wx += b.x * numPoints2; // accumulate coordinates for calculating weighted center
                wy += b.y * numPoints2;

                numPoints += numPoints2;
                b.parentId = id;

                if (reduce) {
                    if (!clusterProperties) clusterProperties = this._map(p, true);
                    reduce(clusterProperties, this._map(b));
                }
            }

            if (numPoints === 1) {
                clusters.push(p);
            } else {
                p.parentId = id;
                clusters.push(createCluster(wx / numPoints, wy / numPoints, id, numPoints, clusterProperties));
            }
        }

        return clusters;
    }

    _map(point, clone) {
        if (point.numPoints) {
            return clone ? extend({}, point.properties) : point.properties;
        }
        const original = this.points[point.index].properties;
        const result = this.options.map(original);
        return clone && result === original ? extend({}, result) : result;
    }
}

function createCluster(x, y, id, numPoints, properties) {
    return {
        x, // weighted cluster center
        y,
        zoom: Infinity, // the last zoom the cluster was processed at
        id, // encodes index of the first child of the cluster and its zoom level
        parentId: -1, // parent cluster id
        numPoints,
        properties
    };
}

function createPointCluster(p, id) {
    const [x, y] = p.geometry.coordinates;
    return {
        x: lngX(x), // projected point coordinates
        y: latY(y),
        zoom: Infinity, // the last zoom the point was processed at
        index: id, // index of the source feature in the original input array,
        parentId: -1 // parent cluster id
    };
}

function getClusterJSON(cluster) {
    return {
        type: 'Feature',
        id: cluster.id,
        properties: getClusterProperties(cluster),
        geometry: {
            type: 'Point',
            coordinates: [xLng(cluster.x), yLat(cluster.y)]
        }
    };
}

function getClusterProperties(cluster) {
    const count = cluster.numPoints;
    const abbrev =
        count >= 10000 ? `${Math.round(count / 1000)  }k` :
        count >= 1000 ? `${Math.round(count / 100) / 10  }k` : count;
    return extend(extend({}, cluster.properties), {
        cluster: true,
        cluster_id: cluster.id,
        point_count: count,
        point_count_abbreviated: abbrev
    });
}

// longitude/latitude to spherical mercator in [0..1] range
function lngX(lng) {
    return lng / 360 + 0.5;
}
function latY(lat) {
    const sin = Math.sin(lat * Math.PI / 180);
    const y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);
    return y < 0 ? 0 : y > 1 ? 1 : y;
}

// spherical mercator to longitude/latitude
function xLng(x) {
    return (x - 0.5) * 360;
}
function yLat(y) {
    const y2 = (180 - y * 360) * Math.PI / 180;
    return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
}

function extend(dest, src) {
    for (const id in src) dest[id] = src[id];
    return dest;
}

function getX(p) {
    return p.x;
}
function getY(p) {
    return p.y;
}
<|endoftext|>


<commit_before>exports.create = function(req, res, next){
	var order = req.body;
	req.models.Order.create(order, function(err, savedOrder){
		if (err) return next(err);

		res.json(savedOrder);
	});
};

exports.find = function(req, res, next){
	var id = req.params.id;
	req.models.Order.findById(id, function(err, order){
		if(err) return next(err);

		res.json(order);
	});
};

exports.del = function(req, res, next){
	var id = req.params.id;
	req.models.Order.findByIdAndRemove(id, function(err){
		if (err) return next(err);

		res.sendStatus(200);
	});
};

exports.list = function(req, res, next){
	req.models.Order.find(function(err, orders){
		if (err) return next(err);

		res.json(orders);
	});
};

exports.update = function(req, res, next){
	var id = req.params.id;
	req.models.Order.findByIdAndUpdate(id, {$set: req.body}, function(err, order){
		if (err) return next(err);

		res.json(order);
	});
};<commit_msg>Removed _id in /orders/:id PUT route.<commit_after>exports.create = function(req, res, next){
	var order = req.body;
	req.models.Order.create(order, function(err, savedOrder){
		if (err) return next(err);

		res.json(savedOrder);
	});
};

exports.find = function(req, res, next){
	var id = req.params.id;
	req.models.Order.findById(id, function(err, order){
		if(err) return next(err);

		res.json(order);
	});
};

exports.del = function(req, res, next){
	var id = req.params.id;
	req.models.Order.findByIdAndRemove(id, function(err){
		if (err) return next(err);

		res.sendStatus(200);
	});
};

exports.list = function(req, res, next){
	req.models.Order.find(function(err, orders){
		if (err) return next(err);

		res.json(orders);
	});
};

exports.update = function(req, res, next){
	var id = req.params.id;
	if(req.body._id){
		delete req.body._id;
	}
	req.models.Order.findByIdAndUpdate(id, {$set: req.body}, function(err, order){
		if (err) return next(err);

		res.json(order);
	});
};
<|endoftext|>


<commit_before>// __Dependencies__
var es = require('event-stream');

  // __Module Definition__
var plugin = module.exports = function () {
	var baucis = this;

 	// __Private Methods__
	function getCsvHeaders1(obj) {
		var res = new Array();
		for (prop in obj) {
			if (obj.hasOwnProperty(prop)) {
				res.unshift(prop);
			}
		}
		return res;
	}

	function getCsvHeaders2(model) {
		var res = new Array();
		for (propName in model.properties) {
			res.unshift(propName);
		}
		return res;
	}

	function isNumber(n) {
	  return !isNaN(parseFloat(n)) && isFinite(n);
	}
	function isObjectId(obj) {
	  return (typeof(obj) == 'object' && obj._bsontype == 'ObjectID');
	}
	function toPascalName(name) {
		 var pascalModel = name.replace(/(\w)(\w*)/g, function(g0,g1,g2){
			return g1.toUpperCase() + g2.toLowerCase();
		});
	}

	function csvEncode(data) {
		var text;
		if (data === null) {
			return '';
		}
		if (isObjectId(data)) {
			return data.toString();
		}
		text = data.toString();

		if ( (text.indexOf(',') >= 0) ||
		     (text.indexOf('.') >= 0) ||
			 (text.indexOf(' ') >= 0) )
		{
			return '"' + text + '"';
		}
		return text;
	}

	function csvEncodeObject(obj, props) {
		var res = '';
		var prefix ='';
		for (prop in props) {
			res += prefix + csvEncode(obj[props[prop]]);
			prefix= ',';
		}
		return res + '\r\n';
	}
	function csvHeaderToString(headers) {
		//build csv headers---
		var prefix='';
		var text = '';
		for (i in headers) {
		    text += prefix + csvEncode(headers[i]);
			prefix=',';
		}
		return text + '\r\n';
	}

	// Default formatter  emit a single CSV object or an array of them.
	function csvFormatter (alwaysArray) {
	var first = false;
	var multiple = false;
	var csvHeaders = [];
	var prefix='';

	return es.through(function (doc) {
	    // Start building the output.  If this is the first document,
	    // store it for a moment.
	    if (!first) {
	      first = doc;
	      return;
	    }
	    // If this is the second document, output array opening and the two documents
	    if (!multiple) {
	      multiple = true;
 		  csvHeaders = getCsvHeaders1(doc._doc);
	      this.emit('data', csvHeaderToString(csvHeaders));
	      this.emit('data', csvEncodeObject(first._doc, csvHeaders));
	      this.emit('data', csvEncodeObject(doc._doc, csvHeaders));
	      return;
	    }
	    this.emit('data', csvEncodeObject(doc._doc, csvHeaders));
	  },
	  function () {
	    // If no documents, simply send header and end the stream.
	    if (!first) {
 		    csvHeaders = getCsvHeaders2(controller.swagger.models[toPascalName(this.query.model)]);
	        this.emit('data', csvHeaderToString(csvHeaders));
			return this.emit('end');
	    }
	    // If only one document emit it unwrapped, unless always returning an array.
	    if (!multiple && alwaysArray) { this.emit('data',''); }
	    if (!multiple)  { this.emit('data', csvEncodeObject(first._doc, csvHeaders)); }
	    // For greater than one document, emit the closing array.
	    else { this.emit('data',''); }
	    if (!multiple && alwaysArray) { this.emit('data',''); }
	    // Done.  End the stream.
	    this.emit('end');
	  });
	}

  // Add a CSV formatter.
  baucis.setFormatter('text/csv', csvFormatter);
};<commit_msg>Cleaned code.<commit_after>'use strict';

// __Dependencies__
var es = require('event-stream');

// __Module Definition__
var plugin = module.exports = function () {
    var baucis = this;

    // __Private Methods__
    function getCsvHeaders1(obj) {
        var res = [], prop;
        for (prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                res.unshift(prop);
            }
        }
        return res;
    }
    function getCsvHeaders2(model) {
        var res = [], propName;
        for (propName in model.properties) {
            res.unshift(propName);
        }
        return res;
    }
    function isNumber(n) {
        return !isNaN(parseFloat(n)) && isFinite(n);
    }
    function isObjectId(obj) {
        return (typeof obj === 'object' && obj._bsontype === 'ObjectID');
    }
    function toPascalName(name) {
        var pascalName = name.replace(/(\w)(\w*)/g, function (g0, g1, g2) {
            return g1.toUpperCase() + g2.toLowerCase();
        });
        return pascalName;
    }
    function csvEncode(data) {
        var text;
        if (data === null) {
            return '';
        }
        if (isObjectId(data)) {
            return data.toString();
        }
        text = data.toString();

        if ((text.indexOf(',') >= 0) || (text.indexOf('.') >= 0) || (text.indexOf(' ') >= 0)) {
            return '"' + text + '"';
        }
        return text;
    }
    function csvEncodeObject(obj, props) {
        var res = '', prefix ='', prop;
        for (prop in props) {
            res += prefix + csvEncode(obj[props[prop]]);
            prefix= ',';
        }
        return res + '\r\n';
    }
    function csvHeaderToString(headers) {
        //build csv headers---
        var prefix='', text = '', i;
        for (i in headers) {
            text += prefix + csvEncode(headers[i]);
            prefix=',';
        }
        return text + '\r\n';
    }

    // Default formatter  emit a single CSV object or an array of them.
    function csvFormatter (alwaysArray) {
        var first = false;
        var multiple = false;
        var csvHeaders = [];
        var prefix='';

        //todo: missing info here to gather the model meta-data when there is no real data and emit csvHeaders
        //this.emit('data', csvHeaderToString(csvHeaders));

        return es.through(function write(doc) {
            // First document
            if (!first) {
                first = doc;
                csvHeaders = getCsvHeaders1(doc._doc);
                this.emit('data', csvHeaderToString(csvHeaders));
                this.emit('data', csvEncodeObject(first._doc, csvHeaders));
                return;
            }
            // Second document
            if (!multiple) {
                multiple = true;
            }
            //emit second and rest of them
            this.emit('data', csvEncodeObject(doc._doc, csvHeaders));
        },
        function end() {
            // Done.  End the stream.
            this.emit('end');
        });
    }
    // Add as CSV formatter.
    baucis.setFormatter('text/csv', csvFormatter);
};<|endoftext|>


<commit_before>'use strict'

const dns = require('dns')
const	util = require('util');
const async = require('async');
const fs = require('fs');
const path = require('path')
const os = require("os");

// Send DNS requests for current subdomain
const probeDNS = (subdomain, tld, cb) => {

	// Build the domain name
	const domain = `${subdomain}.${tld}`;

	// Run the resolve request
	dns.resolve(domain, 'A', err => {
		cb(err, domain);
	});
}

/**
 * Return the default DNS servers
 * @return {array} An array of DNS used by the module
 */
exports.getDefaultResolvers = function() {
	return fs.readFileSync(
		path.join(__dirname, 'resolvers.txt')
	).toString().trim().split(os.EOL)
}

// Check whether a dns server is valid.
exports.isValidDnsServer = function(dnsServer, timeout, cb) {
	// Ensure arguments are good
	if( typeof timeout === 'function' ) {
		cb = timeout
		timeout = 4000
	}

	// Set custom callback handler
	let called = false
	let dnsCallback = (err) => {
		clearTimeout(timeoutPromise);
		if(called) { return }
		called = true
		cb(err)
	};

	// Force to use this dns server
	dns.setServers([dnsServer]);

	// Set a custom timeout for DNS request
	let timeoutPromise = setTimeout(_ => {
		dnsCallback(new Error('Request timeout exceeded!'))
	}, timeout);

	// Try to resolve google.com
	dns.resolve4('www.google.com', dnsCallback);
}

/**
 * Get the best resolver in the following order:
 * 1. User supplied.
 * 2. From our list.
 * @param  {string} server The DNS server address as string
 * @param  {function} callback The callback to run once has done
 */
exports.getResolvers = function(server, callback){
	// Results array
	let dnsServers = exports.getDefaultResolvers();

	// Run callback if first variable is empty or undefined
	if (!server) {
		callback(dnsServers);
		return;
	}

	// Handle the first arg as callback if no server is specified.
	if (typeof server !== 'function') {

		// Validate custom DNS server than add to resolvers list
		exports.isValidDnsServer(server, 4000, (err) => {
			if(err === null) {
				dnsServers.unshift(server)
			}
			callback(dnsServers)
		});

	} else{
		callback = server;
		callback(dnsServers)
	}

}

/**
 * Get the dictionary files names
 * @return {array} Array of file names
 */
exports.getDictionaryNames = function(){
	return fs.readdirSync(path.join(__dirname, 'dictionary'));
}

// Send requests to a DNS resolver and find valid sub-domains
exports.getSubDomains = function(options, callback = () => {}) {
	// Default subdomain scan options
	let defaults = {
		dictionary: 'top_50'
	};

	// Clean undefined options
	Object.keys(options).forEach(key => options[key] === undefined && delete options[key]);

	// Extend default options with user defined ones
	options = Object.assign({}, defaults, options);

	// Exit if no host option
	if(!options.host)  {
		callback(new Error('The host property is missing.'))
		return;
	};

	// Optionally run a bing search
	if(options.bingSearch === true){
		var bingSearch = require('./lib/bingSearch.js');
		return bingSearch.find(options.host, callback)
	}

  // Get the resolvers list
	exports.getResolvers(options.dnsServer, (servers) => {

		// Set new servers list for the requests
		dns.setServers(servers);

    // Init dictionary array
    var dictionary;

    try {

      // Get dictionary lines
      dictionary = fs.readFileSync(
        path.join(__dirname, `dictionary/${options.dictionary}.txt`)
      );

    } catch (e) {
      callback(new Error(`The dictionary ${options.dictionary} was not found, make sure it exists in the dictionary folder.`));
      return;
    }

    // Get dictionary content and split lines in array rows
    dictionary.toString().trim().split(os.EOL);

		// Probe each subdomain
		async.mapSeries(dictionary, (subdomain, cb) => {
			probeDNS(subdomain, options.host, (err, res) => {
				cb(null, err ? null : res)
			})
		}, (err, results) => {
			// Filter from any empty result
			results = results.filter(v => v)
			callback(null, results);
		})

	})
}
<commit_msg>Fix missed assignment<commit_after>'use strict'

const dns = require('dns')
const	util = require('util');
const async = require('async');
const fs = require('fs');
const path = require('path')
const os = require("os");

// Send DNS requests for current subdomain
const probeDNS = (subdomain, tld, cb) => {

	// Build the domain name
	const domain = `${subdomain}.${tld}`;

	// Run the resolve request
	dns.resolve(domain, 'A', err => {
		cb(err, domain);
	});
}

/**
 * Return the default DNS servers
 * @return {array} An array of DNS used by the module
 */
exports.getDefaultResolvers = function() {
	return fs.readFileSync(
		path.join(__dirname, 'resolvers.txt')
	).toString().trim().split(os.EOL)
}

// Check whether a dns server is valid.
exports.isValidDnsServer = function(dnsServer, timeout, cb) {
	// Ensure arguments are good
	if( typeof timeout === 'function' ) {
		cb = timeout
		timeout = 4000
	}

	// Set custom callback handler
	let called = false
	let dnsCallback = (err) => {
		clearTimeout(timeoutPromise);
		if(called) { return }
		called = true
		cb(err)
	};

	// Force to use this dns server
	dns.setServers([dnsServer]);

	// Set a custom timeout for DNS request
	let timeoutPromise = setTimeout(_ => {
		dnsCallback(new Error('Request timeout exceeded!'))
	}, timeout);

	// Try to resolve google.com
	dns.resolve4('www.google.com', dnsCallback);
}

/**
 * Get the best resolver in the following order:
 * 1. User supplied.
 * 2. From our list.
 * @param  {string} server The DNS server address as string
 * @param  {function} callback The callback to run once has done
 */
exports.getResolvers = function(server, callback){
	// Results array
	let dnsServers = exports.getDefaultResolvers();

	// Run callback if first variable is empty or undefined
	if (!server) {
		callback(dnsServers);
		return;
	}

	// Handle the first arg as callback if no server is specified.
	if (typeof server !== 'function') {

		// Validate custom DNS server than add to resolvers list
		exports.isValidDnsServer(server, 4000, (err) => {
			if(err === null) {
				dnsServers.unshift(server)
			}
			callback(dnsServers)
		});

	} else{
		callback = server;
		callback(dnsServers)
	}

}

/**
 * Get the dictionary files names
 * @return {array} Array of file names
 */
exports.getDictionaryNames = function(){
	return fs.readdirSync(path.join(__dirname, 'dictionary'));
}

// Send requests to a DNS resolver and find valid sub-domains
exports.getSubDomains = function(options, callback = () => {}) {
	// Default subdomain scan options
	let defaults = {
		dictionary: 'top_50'
	};

	// Clean undefined options
	Object.keys(options).forEach(key => options[key] === undefined && delete options[key]);

	// Extend default options with user defined ones
	options = Object.assign({}, defaults, options);

	// Exit if no host option
	if(!options.host)  {
		callback(new Error('The host property is missing.'))
		return;
	};

	// Optionally run a bing search
	if(options.bingSearch === true){
		var bingSearch = require('./lib/bingSearch.js');
		return bingSearch.find(options.host, callback)
	}

  // Get the resolvers list
	exports.getResolvers(options.dnsServer, (servers) => {

		// Set new servers list for the requests
		dns.setServers(servers);

    // Init dictionary array
    var dictionary;

    try {

      // Get dictionary lines
      dictionary = fs.readFileSync(
        path.join(__dirname, `dictionary/${options.dictionary}.txt`)
      );

    } catch (e) {
      callback(new Error(`The dictionary ${options.dictionary} was not found, make sure it exists in the dictionary folder.`));
      return;
    }

    // Get dictionary content and split lines in array rows
    dictionary = dictionary.toString().trim().split(os.EOL);

		// Probe each subdomain
		async.mapSeries(dictionary, (subdomain, cb) => {
			probeDNS(subdomain, options.host, (err, res) => {
				cb(null, err ? null : res)
			})
		}, (err, results) => {
			// Filter from any empty result
			results = results.filter(v => v)
			callback(null, results);
		})

	})
}
<|endoftext|>


<commit_before>var connect = require('connect');
var faker = require('faker');
var serveStatic = require('serve-static');
var WebSocketServer = require('ws').Server;

connect().use(serveStatic(__dirname)).listen(8080);

var wss = new WebSocketServer({port: 6639});
wss.broadcast = function (data) {
  wss.clients.forEach(function (client) {
    client.send(data);
  });
};

wss.on('connection', function (ws) {
  var username = faker.internet.userName();
  wss.broadcast(username + ' joined!');
  ws.on('message', function (message) {
    wss.broadcast(username + ': ' + message);
  });
});
<commit_msg>Handle Ctrl+C cleanly in the server.<commit_after>var connect = require('connect');
var faker = require('faker');
var serveStatic = require('serve-static');
var WebSocketServer = require('ws').Server;

connect().use(serveStatic(__dirname)).listen(8080);

var wss = new WebSocketServer({port: 6639});
wss.broadcast = function (data) {
  wss.clients.forEach(function (client) {
    client.send(data);
  });
};

wss.on('connection', function (ws) {
  var username = faker.internet.userName();
  wss.broadcast(username + ' joined!');
  ws.on('message', function (message) {
    wss.broadcast(username + ': ' + message);
  });
});

process.on('SIGINT', function() {
  wss.broadcast('Server going down NOW!');
  setTimeout(function () {
    process.exit();
  }, 100);
});
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var superagent = require('superagent');
var debug = require('debug')('wpcom-xhr-request');

/**
 * Export a single `request` function.
 */

module.exports = request;

/**
 * WordPress.com REST API base endpoint.
 */

var proxyOrigin = 'https://public-api.wordpress.com';

/**
 * WordPress.com v1 REST API URL.
 */

var apiUrl = proxyOrigin + '/rest/v1';

/**
 * Performs an XMLHttpRequest against the WordPress.com REST API.
 *
 * @param {Object|String} params
 * @param {Function} fn
 * @api public
 */

function request (params, fn) {

  if ('string' == typeof params) {
    params = { path: params };
  }

  var method = (params.method || 'GET').toLowerCase();
  debug('API HTTP Method:', method);
  delete params.method;

  var url = apiUrl + params.path;
  debug('API URL:', url);
  delete params.path;

  // create HTTP Request object
  var req = superagent[method](url);

  if (params.authToken) {
    req.set('Authorization', 'Bearer ' + params.authToken);
    delete params.authToken;
  }

  debug('API params:', params);
  req.send(params);

  // start the request
  req.end(function (err, res){
    if (err) return fn(err);
    var body = res.body;
    var statusCode = res.status;
    debug('%s -> %s status code', url, statusCode);

    if (2 === Math.floor(statusCode / 100)) {
      // 2xx status code, success
      fn(null, body);
    } else {
      // any other status code is a failure
      err = new Error();
      err.statusCode = statusCode;
      for (var i in body) err[i] = body[i];
      if (body.error) err.name = toTitle(body.error) + 'Error';
      fn(err);
    }
  });
}

function toTitle (str) {
  if (!str || 'string' !== typeof str) return '';
  return str.replace(/((^|_)[a-z])/g, function ($1) {
    return $1.toUpperCase().replace('_', '');
  });
}
<commit_msg>core: add %s for Strings in debug lines<commit_after>
/**
 * Module dependencies.
 */

var superagent = require('superagent');
var debug = require('debug')('wpcom-xhr-request');

/**
 * Export a single `request` function.
 */

module.exports = request;

/**
 * WordPress.com REST API base endpoint.
 */

var proxyOrigin = 'https://public-api.wordpress.com';

/**
 * WordPress.com v1 REST API URL.
 */

var apiUrl = proxyOrigin + '/rest/v1';

/**
 * Performs an XMLHttpRequest against the WordPress.com REST API.
 *
 * @param {Object|String} params
 * @param {Function} fn
 * @api public
 */

function request (params, fn) {

  if ('string' == typeof params) {
    params = { path: params };
  }

  var method = (params.method || 'GET').toLowerCase();
  debug('API HTTP Method: `%s`', method);
  delete params.method;

  var url = apiUrl + params.path;
  debug('API URL: `%s`', url);
  delete params.path;

  // create HTTP Request object
  var req = superagent[method](url);

  if (params.authToken) {
    req.set('Authorization', 'Bearer ' + params.authToken);
    delete params.authToken;
  }

  debug('API params: ', params);
  req.send(params);

  // start the request
  req.end(function (err, res){
    if (err) return fn(err);
    var body = res.body;
    var statusCode = res.status;
    debug('%s -> %s status code', url, statusCode);

    if (2 === Math.floor(statusCode / 100)) {
      // 2xx status code, success
      fn(null, body);
    } else {
      // any other status code is a failure
      err = new Error();
      err.statusCode = statusCode;
      for (var i in body) err[i] = body[i];
      if (body.error) err.name = toTitle(body.error) + 'Error';
      fn(err);
    }
  });
}

function toTitle (str) {
  if (!str || 'string' !== typeof str) return '';
  return str.replace(/((^|_)[a-z])/g, function ($1) {
    return $1.toUpperCase().replace('_', '');
  });
}
<|endoftext|>


<commit_before>/**
 * Created by achim on 31.07.2017.
 */
/*jslint node: true, es6: true, white: true */
/*jshint esversion: 6 */

"use strict";

const NodePromise = require("promise");
const https = require("https");
const url = require("url");
const querystring = require("querystring");
const fs = require("fs");
const crypto = require("crypto");

//parameter files:
const auth = require("./auth.json");
const config = require("./config.json");
if (config.targetPath.charAt(config.targetPath.length -1) !== "/") {
    config.targetPath += "/";
}

function debug(...msgs) {
    if (config.debugging) {
        console.log(...msgs);
    }
}

//denodifications:
const readFilePromise = NodePromise.denodeify(fs.readFile);
const writeFilePromise = NodePromise.denodeify(fs.writeFile);

let authHeader;
let refreshToken;
function requestPromise(options, postData, decode = true, retry = 0) {
    //add auth header.
    if (authHeader) {
        if (options.headers) {
            options.headers.Authorization = authHeader;
        } else {
            options.headers = {"Authorization": authHeader};
        }
    }
    let promise = new NodePromise(function resolver(resolve, reject) {
        //debug("Sending request", options);
        let req = https.request(options, function callback(res) {
            let data = "";
            res.setEncoding("utf8");
            //debug("Headers:", res.headers);
            res.on("data", function (chunk) { data += chunk; });
            res.on("end", function () {
                //debug("Body: ", data);
                if (res.statusCode >= 200 && res.statusCode < 300) {
                    if (decode) {
                        resolve(JSON.parse(data));
                    } else {
                        resolve(data);
                    }
                } else if (res.statusCode === 401 && !retry) {
                    //need to refresh token.
                    let innerPromise = refreshToken(true);
                    innerPromise = innerPromise.then(function retryRequest() { //retry request.
                        return requestPromise(options, postData, decode, retry + 1);
                    });
                    resolve(innerPromise);
                } else {
                    reject({msg: "Status code not 200: " + res.statusCode, data: data});
                }
            });
        });
        req.on("error", (err) => reject(err));
        //debug("Writing:", postData);
        req.end(postData);
    });

    return promise;
}

//request from metadata server
function requestMetadata(path, jsonData, decode) {
    let options = url.parse(auth.metadataUrl + path);
    let postData;
    if (jsonData) {
        postData = JSON.stringify(jsonData);
        options.headers = {"Content-Length": Buffer.byteLength(postData)};
        options.method = "POST";
    }
    return requestPromise(options, postData, decode);
}
//request from content server
function requestContent(path, decode) {
    let options = url.parse(auth.contentUrl + path);
    return requestPromise(options, undefined, decode);
}
//handle all token stuff. will also update authorization header.
refreshToken = function(realRefresh) {
    let promise;
    authHeader = "";
    if (!realRefresh) {
        promise = readFilePromise(config.accessTokenPath, "utf8");

        promise = promise.then(function gotToken(data) {
            let token = JSON.parse(data);
            debug("Got token from file");
            authHeader = "Bearer " + token.access_token;
            return token;
        }, function needToRefresh() {
            debug("No token file. Get new token.");
            return refreshToken(true);
        });
    } else {
        let options = url.parse(config.refreshProxyUrl);
        options.method = "POST";
        let postData = querystring.stringify({refresh_token: auth.refresh_token});
        options.headers = {"Content-Length": Buffer.byteLength(postData)};

        promise = requestPromise(options, postData, true);

        promise = promise.then(function storeToken(token) {
            debug("Got token from refresh.");
            authHeader = "Bearer " + token.access_token;
            return writeFilePromise(config.accessTokenPath, JSON.stringify(token, null, 4), "utf8");
        });
    }
    return promise;
};

function nodesFromData(data) {
    if (data.data.length >= 0) {
        return data.data;
    }
    if (data.length >= 0) {
        return data;
    }
    throw "No nodes found in data.";
}

function createFolder(parentNode, name) {
    debug("Creating " + name + " in " + (parentNode.name || "root"));
    let createUrl = "nodes?localId=GarfonsoImageSync";
    let jsonData = {
        name: name,
        kind: "FOLDER",
        parents: [parentNode.id]
    };
    return requestMetadata(createUrl, jsonData);
}

function listChildren(node, filter, children = [], nextToken = undefined) {
    let childrenUrl = "nodes/" + node.id + "/children";
    if (filter) {
        childrenUrl += "?filters=" + filter;
    }
    if (nextToken) {
        if (!filter) {
            childrenUrl += "?";
        } else {
            childrenUrl += "&";
        }
        childrenUrl += "startToken=" + nextToken;
    }
    let promise = requestMetadata(childrenUrl);

    promise = promise.then(function (res) {
        children = children.concat(nodesFromData(res));
        //debug("Got children: ", children);
        if (res.nextToken) {
            return listChildren(node, filter, children, res.nextToken);
        } else {
            return children;
        }
    });

    return promise;
}

//first get access_token:
let promise = refreshToken();

/*promise = promise.then(function getRootNode() {
    let options = "";
    //requestPromise()
});*/

promise = promise.then(function allgood(result) {
    console.log("All good:", result);
}, function haderror(err) {
    console.log("Had error:", err);
});
<commit_msg>first steps for sync.<commit_after>/**
 * Created by achim on 31.07.2017.
 */
/*jslint node: true, es6: true, white: true */
/*jshint esversion: 6 */

"use strict";

const NodePromise = require("promise");
const https = require("https");
const url = require("url");
const querystring = require("querystring");
const fs = require("fs");
const crypto = require("crypto");

//parameter files:
const auth = require("./auth.json");
const config = require("./config.json");
if (config.targetPath.charAt(config.targetPath.length -1) !== "/") {
    config.targetPath += "/";
}

function debug(...msgs) {
    if (config.debugging) {
        console.log(...msgs);
    }
}

//denodifications:
const readFilePromise = NodePromise.denodeify(fs.readFile);
const writeFilePromise = NodePromise.denodeify(fs.writeFile);

let authHeader;
let refreshToken;
function requestPromise(options, postData, decode = true, retry = 0) {
    //add auth header.
    if (authHeader) {
        if (options.headers) {
            options.headers.Authorization = authHeader;
        } else {
            options.headers = {"Authorization": authHeader};
        }
    }
    let promise = new NodePromise(function resolver(resolve, reject) {
        //debug("Sending request", options);
        let req = https.request(options, function callback(res) {
            let data = "";
            res.setEncoding("utf8");
            //debug("Headers:", res.headers);
            res.on("data", function (chunk) { data += chunk; });
            res.on("end", function () {
                //debug("Body: ", data);
                if (res.statusCode >= 200 && res.statusCode < 300) {
                    if (decode) {
                        resolve(JSON.parse(data));
                    } else {
                        resolve(data);
                    }
                } else if (res.statusCode === 401 && !retry) {
                    //need to refresh token.
                    let innerPromise = refreshToken(true);
                    innerPromise = innerPromise.then(function retryRequest() { //retry request.
                        return requestPromise(options, postData, decode, retry + 1);
                    });
                    resolve(innerPromise);
                } else {
                    reject({msg: "Status code not 200: " + res.statusCode, data: data});
                }
            });
        });
        req.on("error", (err) => reject(err));
        //debug("Writing:", postData);
        req.end(postData);
    });

    return promise;
}

//request from metadata server
function requestMetadata(path, jsonData, decode) {
    let options = url.parse(auth.metadataUrl + path);
    let postData;
    if (jsonData) {
        postData = JSON.stringify(jsonData);
        options.headers = {"Content-Length": Buffer.byteLength(postData)};
        options.method = "POST";
    }
    return requestPromise(options, postData, decode);
}
//request from content server
function requestContent(path, decode) {
    let options = url.parse(auth.contentUrl + path);
    return requestPromise(options, undefined, decode);
}
//handle all token stuff. will also update authorization header.
refreshToken = function(realRefresh) {
    let promise;
    authHeader = "";
    if (!realRefresh) {
        promise = readFilePromise(config.accessTokenPath, "utf8");

        promise = promise.then(function gotToken(data) {
            let token = JSON.parse(data);
            debug("Got token from file");
            authHeader = "Bearer " + token.access_token;
            return token;
        }, function needToRefresh() {
            debug("No token file. Get new token.");
            return refreshToken(true);
        });
    } else {
        let options = url.parse(config.refreshProxyUrl);
        options.method = "POST";
        let postData = querystring.stringify({refresh_token: auth.refresh_token});
        options.headers = {"Content-Length": Buffer.byteLength(postData)};

        promise = requestPromise(options, postData, true);

        promise = promise.then(function storeToken(token) {
            debug("Got token from refresh.");
            authHeader = "Bearer " + token.access_token;
            return writeFilePromise(config.accessTokenPath, JSON.stringify(token, null, 4), "utf8");
        });
    }
    return promise;
};

function nodesFromData(data) {
    if (data.data.length >= 0) {
        return data.data;
    }
    if (data.length >= 0) {
        return data;
    }
    throw "No nodes found in data.";
}

function createFolder(parentNode, name) {
    debug("Creating " + name + " in " + (parentNode.name || "root"));
    let createUrl = "nodes?localId=GarfonsoImageSync";
    let jsonData = {
        name: name,
        kind: "FOLDER",
        parents: [parentNode.id]
    };
    return requestMetadata(createUrl, jsonData);
}

function listChildren(node, filter, children = [], nextToken = undefined) {
    let childrenUrl = "nodes/" + node.id + "/children";
    if (filter) {
        childrenUrl += "?filters=" + filter;
    }
    if (nextToken) {
        if (!filter) {
            childrenUrl += "?";
        } else {
            childrenUrl += "&";
        }
        childrenUrl += "startToken=" + nextToken;
    }
    let promise = requestMetadata(childrenUrl);

    promise = promise.then(function (res) {
        children = children.concat(nodesFromData(res));
        //debug("Got children: ", children);
        if (res.nextToken) {
            return listChildren(node, filter, children, res.nextToken);
        } else {
            return children;
        }
    });

    return promise;
}

//first get access_token:
let promise = refreshToken();

promise = promise.then(function getRootNode() {
    return requestMetadata("nodes?filters=isRoot:true");
});

promise = promise.then(function hangleToTargetPath(data) {
    let root = nodesFromData(data)[0]; //can we have multiple root nodes?
    let currentNode = root;
    let currentPath = "/";
    let remainingPathItems = config.targetPath.split("/");
    remainingPathItems.pop();
    remainingPathItems.shift();

    function getDown() {
        //debug("remainingPath: ", remainingPathItems);
        if (remainingPathItems.length === 0) {
            if (currentPath !== config.targetPath) {
                throw currentPath + " != " + config.targetPath + ". Somehow path hangling went wrong.";
            }
            return currentNode;
        }
        let innerPromise = listChildren(currentNode, "kind:FOLDER");
        innerPromise = innerPromise.then(function (children) {
            let found = false;
            children.forEach(function (child) {
                if (child.name === remainingPathItems[0]) {
                    //debug("Found next part: ", child);
                    currentNode = child;
                    currentPath += child.name + "/";
                    found = true;
                }
            });
            if (!found) {
                return createFolder(currentNode, remainingPathItems[0]);
            }
            remainingPathItems.shift();
            return getDown();
        });

        return innerPromise;
    }

    return getDown();
});

promise = promise.then(function allgood(result) {
    console.log("All good:", result);
}, function haderror(err) {
    console.log("Had error:", err);
});
<|endoftext|>


<commit_before>'use strict';

const controller = require('./controller'),
      handshake = require('./handshake');

module.exports = function(client){
  this.emit('connection', client);

  client.socket.on('data', function(data){
    if (client.shaking) client.socket.end('Ayy lmao');
    else {
      if (!client.shook) handshake(client, data);
      else controller(client, data);
    }
  });

  client.socket.on('end', () => {
    this.clients.slice(client.id, 1);
    client.socket.destroy();
  });
};
<commit_msg>Add disconnection events<commit_after>'use strict';

const controller = require('./controller'),
      handshake = require('./handshake');

module.exports = function(client){
  this.emit('connection', client);

  client.socket.on('data', function(data){
    if (client.shaking) client.socket.end('Ayy lmao');
    else {
      if (!client.shook) handshake(client, data);
      else controller(client, data);
    }
  });

  client.socket.on('close', () => {
    client.emit('disconnect');
    this.emit('disconnection');
    this.clients.slice(client.id, 1);
    client.socket.destroy();
  });
};
<|endoftext|>


<commit_before>/**
 *  queue.js
 */

/**
 *  deps
 */
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;

/**
 *  export class
 */
module.exports = Queue;

/**
 *  constructor
 */
function Queue(options) {
  if (!(this instanceof Queue))
    return new Queue(options);

  EventEmitter.call(this);
  options = options || {};
  this.concurrency = options.concurrency || Infinity;
  this.timeout = options.timeout || 0;
  this.pending = 0;
  this.session = 0;
  this.running = false;
  this.jobs = [];
}
inherits(Queue, EventEmitter);

/**
 *  expose selected array methods
 */
var arrayMethods = [
  'push',
  'unshift',
  'splice',
  'pop',
  'shift',
  'slice',
  'reverse',
  'indexOf',
  'lastIndexOf'
];

for (var method in arrayMethods) (function(method) {
  Queue.prototype[method] = function() {
    return Array.prototype[method].apply(this.jobs, arguments);
  };
})(arrayMethods[method]);

/**
 *  expose array.length
 */
Object.defineProperty(Queue.prototype, 'length', { get: function() {
  return this.pending + this.jobs.length;
}});

/**
 *  start processing the queue
 */
Queue.prototype.start = function() {
  if (this.pending === this.concurrency) {
    return;
  }

  if (this.jobs.length === 0) {
    if (this.pending === 0) {
      done.call(this);
    }
    return;
  }

  var job = this.jobs.shift();
  var self = this;
  var once = true;
  var session = this.session;
  var timeoutId = null;
  var didTimeout = false;

  var next = function(err, result) {
    if (once && self.session === session) {
      once = false;
      self.pending--;
      if (timeoutId !== null) {
        clearTimeout(timeoutId);
      }

      if (err) {
        self.emit('error', err, job);
      } else if (didTimeout === false) {
        self.emit('success', result, job);
      }

      if (self.session === session) {
        if (self.pending === 0 && self.jobs.length === 0) {
          done.call(self);
        } else if (self.running) {
          self.start();
        }
      }
    }
  };

  if (this.timeout) {
    timeoutId = setTimeout(function() {
      didTimeout = true;
      if (self.listeners('timeout').length > 0) {
        self.emit('timeout', next, job);
      } else {
        next();
      }
    }, this.timeout);
  }

  this.pending++;
  this.running = true;
  job(next);

  if (this.jobs.length > 0) {
    this.start();
  }
};

/**
 *  stop / pause
 */
Queue.prototype.stop = function() {
  this.running = false;
};

/**
 *  clear the queue including any running jobs
 */
Queue.prototype.end = function(err) {
  if (this.jobs.length || this.pending) {
    this.jobs = [];
    this.pending = 0;
    this.session++;
    done.call(this, err);
  }
};

/**
 *  all done
 */
function done(err) {
  this.session++;
  this.running = false;
  this.emit('end', err);
};
<commit_msg>allow start to accept a callback<commit_after>/**
 *  queue.js
 */

/**
 *  deps
 */
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;

/**
 *  export class
 */
module.exports = Queue;

/**
 *  constructor
 */
function Queue(options) {
  if (!(this instanceof Queue))
    return new Queue(options);

  EventEmitter.call(this);
  options = options || {};
  this.concurrency = options.concurrency || Infinity;
  this.timeout = options.timeout || 0;
  this.pending = 0;
  this.session = 0;
  this.running = false;
  this.jobs = [];
}
inherits(Queue, EventEmitter);

/**
 *  expose selected array methods
 */
var arrayMethods = [
  'push',
  'unshift',
  'splice',
  'pop',
  'shift',
  'slice',
  'reverse',
  'indexOf',
  'lastIndexOf'
];

for (var method in arrayMethods) (function(method) {
  Queue.prototype[method] = function() {
    return Array.prototype[method].apply(this.jobs, arguments);
  };
})(arrayMethods[method]);

/**
 *  expose array.length
 */
Object.defineProperty(Queue.prototype, 'length', { get: function() {
  return this.pending + this.jobs.length;
}});

/**
 *  start processing the queue
 */
Queue.prototype.start = function(cb) {
  if (cb) {
    this.on('error', this.end.bind(this));
    this.on('end', function(err) {
      cb(err);
    });
  }

  if (this.pending === this.concurrency) {
    if (cb) cb();
    return;
  }

  if (this.jobs.length === 0) {
    if (this.pending === 0) {
      done.call(this);
    }
    return;
  }

  var job = this.jobs.shift();
  var self = this;
  var once = true;
  var session = this.session;
  var timeoutId = null;
  var didTimeout = false;

  var next = function(err, result) {
    if (once && self.session === session) {
      once = false;
      self.pending--;
      if (timeoutId !== null) {
        clearTimeout(timeoutId);
      }

      if (err) {
        self.emit('error', err, job);
      } else if (didTimeout === false) {
        self.emit('success', result, job);
      }

      if (self.session === session) {
        if (self.pending === 0 && self.jobs.length === 0) {
          done.call(self);
        } else if (self.running) {
          self.start();
        }
      }
    }
  };

  if (this.timeout) {
    timeoutId = setTimeout(function() {
      didTimeout = true;
      if (self.listeners('timeout').length > 0) {
        self.emit('timeout', next, job);
      } else {
        next();
      }
    }, this.timeout);
  }

  this.pending++;
  this.running = true;
  job(next);

  if (this.jobs.length > 0) {
    this.start();
  }
};

/**
 *  stop / pause
 */
Queue.prototype.stop = function() {
  this.running = false;
};

/**
 *  clear the queue including any running jobs
 */
Queue.prototype.end = function(err) {
  if (this.jobs.length || this.pending) {
    this.jobs = [];
    this.pending = 0;
    this.session++;
    done.call(this, err);
  }
};

/**
 *  all done
 */
function done(err) {
  this.session++;
  this.running = false;
  this.emit('end', err);
};
<|endoftext|>


<commit_before>'use strict';

var debug = require('debug')('bed');
var methods = require('methods');
var request = require('superagent');

module.exports = Bed;

function Bed() {
  this.baseUrl = '';
  this.headers = {};
  this.qs = {};
}
Bed.prototype.base = function(url) {
  this.baseUrl = url;
  return this;
};
Bed.prototype.auth = function(type, token) {
  if (type === 'basic' && arguments.length === 3) {
    token = new Buffer([arguments[1], arguments[2]].join(':'), 'utf8').toString('base64');
  }
  return this.set('Authorization', [type, token].join(' '));
};
Bed.prototype.type = function(type) {
  return this.set('Content-Type', type);
};
Bed.prototype.accept = function(accept) {
  return this.set('Accept', accept);
};
Bed.prototype.set = addTo('headers');
Bed.prototype.query = addTo('qs');
methods.forEach(function(method) {
  Bed.prototype[method] = function(path) {
    return new Builder(this, method, path);
  };
});

function Builder(bed, method, path) {
  this.bed = bed;
  this.path = new Path(path);
  this.method = method;
  this.qs = {};
  this.accept = null;
  this.headers = {};
  this.body = false;
  this.formatter = function(res) { return res; };
}
Builder.prototype.set = addTo('headers');
Builder.prototype.query = addTo('qs');
Builder.prototype.format = function(fn) {
  this.formatter = fn;
  return this;
};
Builder.prototype.make = function() {
  var builder = this;
  return function(/* params..., body, query */) {
    // TODO parse/validate the arguments
    var args = [].slice.call(arguments);
    var path = builder.path.path;
    var params = [];
    var body = null;
    var query = {};

    // query is the last option
    var last = args[args.length-1];
    if (typeof last === 'object') {
      query = args.pop();
    }

    // params must be the first arguments
    if (builder.path.has.params) {
      params = args.splice(0, builder.path.has.params);
      path = builder.path.populate(params);
    }

    // body is the rest...
    if (args.length) {
      body = args.length === 1 ? args.pop() : args;
    }

    // reject if it doesn't have all the required arguments
    var missing = params.slice(0, builder.path.has.required);
    if (missing.length < builder.path.has.required) {
      var err = new Error('missing required params ' + missing.join(', '));
      return Promise.reject(err);
    }

    debug('%s(%j, %j)', builder.method, path, params);

    return new Promise(function(resolve, reject) {
      var req = request[builder.method](builder.bed.baseUrl + path);
      req.query(merge(builder.bed.qs, builder.qs, query));
      req.set(merge(builder.bed.headers, builder.headers));
      req.send(body);
      req.end(function(err, res) {
        if (err) {
          reject(err);
        } else {
          try {
            res = builder.formatter(res);
          } catch(e) {
            reject(e);
          }
          resolve(res);
        }
      });
    });
  };
};

function Path(path) {
  this.path = path;
  this.regexp = null;
  this.fields = [];
  this.has = {
    params: 0,
    required: 0,
    optional: 0
  };
  this.parse();
}
Path.prototype.parse = function() {
  // required
  var has = this.has;
  var index = 0;
  var fields = [];
  var position = 0;
  var regexp = this.path.replace(/<([^>]+)>|\[([^\]]+)\]/g, function(match, r, o, i, path){
    fields.push({part: path.slice(position, i)});
    fields.push({name: r || o});
    has.required += r ? 1 : 0;
    has.optional += o ? 1 : 0;
    has.params += 1;
    position = i + match.length;
    return r ? '(<[^>]+>)' : '(\\[[^\\]]+\\])';
  });
  fields.push({part: this.path.slice(position)});
  this.regexp = new RegExp('^' + regexp.replace(/\//g, '\\/') + '$');
  this.fields = fields;
};
Path.prototype.valid = function(path) {
  return this.regexp.test(path);
};
Path.prototype.populate = function(params) {
  debug('populate(%j)', params);
  var i = 0;
  return this.fields.map(function(field) {
    if (field.part) {
      return field.part;
    } else  {
      return params[i++];
    }
  }).join('');
};

function merge() {
  var o = {};
  for(var i = 0; i < arguments.length; i++) {
    var a = arguments[i];
    if (a) {
      for(var k in a) {
        o[k] = a[k];
      }
    }
  }
  return o;
}

function addTo(name) {
  return function add(key, value) {
    if (typeof key === 'object') {
      for(var k in key) {
        add.call(this, k, key[k]);
      }
    } else {
      this[name][key] = value;
    }
    return this;
  };
}<commit_msg>Added type(), accept() and body() to Builder<commit_after>'use strict';

var debug = require('debug')('bed');
var methods = require('methods');
var request = require('superagent');

module.exports = Bed;

function Bed() {
  this.baseUrl = '';
  this.headers = {};
  this.qs = {};
}
Bed.prototype.base = function(url) {
  this.baseUrl = url;
  return this;
};
Bed.prototype.auth = function(type, token) {
  if (type === 'basic' && arguments.length === 3) {
    token = new Buffer([arguments[1], arguments[2]].join(':'), 'utf8').toString('base64');
  }
  return this.set('Authorization', [type, token].join(' '));
};
Bed.prototype.type = function(type) {
  return this.set('Content-Type', type);
};
Bed.prototype.accept = function(accept) {
  return this.set('Accept', accept);
};
Bed.prototype.set = addTo('headers');
Bed.prototype.query = addTo('qs');
methods.forEach(function(method) {
  Bed.prototype[method] = function(path) {
    return new Builder(this, method, path);
  };
});

function Builder(bed, method, path) {
  this.bed = bed;
  this.path = new Path(path);
  this.method = method;
  this.qs = {};
  this.accept = null;
  this.headers = {};
  this.formatter = function(res) { return res; };
}
Builder.prototype.type = function(type) {
  return this.set('Content-Type', type);
};
Builder.prototype.accept = function(accept) {
  return this.set('Accept', accept);
};
Builder.prototype.set = addTo('headers');
Builder.prototype.query = addTo('qs');
Builder.prototype.format = function(fn) {
  this.formatter = fn;
  return this;
};
Builder.prototype.body = function(body) {
  this.withBody = body;
  return this;
};
Builder.prototype.make = function() {
  var builder = this;
  return function(/* params..., body, query */) {
    var args = [].slice.call(arguments);
    var path = builder.path.path;
    var params = [];
    var body = builder.withBody;
    var query = {};

    // query is the last option
    var last = args[args.length - 1];
    if (typeof last === 'object') {
      query = args.pop();
    }

    // params must be the first arguments
    if (builder.path.has.params) {
      params = args.splice(0, builder.path.has.params);
      path = builder.path.populate(params);
    }

    // body is the rest, unless already set...
    if (!body && args.length) {
      body = args.length === 1 ? args.pop() : args;
    }

    // reject if it doesn't have all the required arguments
    var missing = params.slice(0, builder.path.has.required);
    if (missing.length < builder.path.has.required) {
      var e = new Error('missing required params ' + missing.join(', '));
      return Promise.reject(e);
    }

    debug('%s(%j, %j)', builder.method, path, params);

    return new Promise(function(resolve, reject) {
      var req = request[builder.method](builder.bed.baseUrl + path);
      req.query(merge(builder.bed.qs, builder.qs, query));
      req.set(merge(builder.bed.headers, builder.headers));
      req.send(body);
      req.end(function(err, res) {
        if (err) {
          reject(err);
        } else {
          try {
            res = builder.formatter(res);
          } catch(e) {
            reject(e);
          }
          resolve(res);
        }
      });
    });
  };
};

function Path(path) {
  this.path = path;
  this.regexp = null;
  this.fields = [];
  this.has = {
    params: 0,
    required: 0,
    optional: 0
  };
  this.parse();
}
Path.prototype.parse = function() {
  // required
  var has = this.has;
  var fields = [];
  var position = 0;
  var regexp = this.path.replace(/<([^>]+)>|\[([^\]]+)\]/g, function(match, r, o, i, path){
    fields.push({part: path.slice(position, i)});
    fields.push({name: r || o});
    has.required += r ? 1 : 0;
    has.optional += o ? 1 : 0;
    has.params += 1;
    position = i + match.length;
    return r ? '(<[^>]+>)' : '(\\[[^\\]]+\\])';
  });
  fields.push({part: this.path.slice(position)});
  this.regexp = new RegExp('^' + regexp.replace(/\//g, '\\/') + '$');
  this.fields = fields;
};
Path.prototype.valid = function(path) {
  return this.regexp.test(path);
};
Path.prototype.populate = function(params) {
  debug('populate(%j)', params);
  var i = 0;
  return this.fields.map(function(field) {
    if (field.part) {
      return field.part;
    } else {
      return params[i++];
    }
  }).join('');
};

function merge() {
  var o = {};
  for(var i = 0; i < arguments.length; i++) {
    var a = arguments[i];
    if (a) {
      for(var k in a) {
        o[k] = a[k];
      }
    }
  }
  return o;
}

function addTo(name) {
  return function add(key, value) {
    if (typeof key === 'object') {
      for(var k in key) {
        add.call(this, k, key[k]);
      }
    } else {
      this[name][key] = value;
    }
    return this;
  };
}
<|endoftext|>


<commit_before>/*

server.js
=========

Testem's server. Serves up the HTML, JS, and CSS required for
running the tests in a browser.

*/

var Express = require('express')
  , SocketIO = require('socket.io')
  , BrowserRunner = require('../browser_runner')
  , fs = require('fs')
  , path = require('path')
  , util = require('util')
  , async = require('async')
  , glob = require('glob')
  , isa = require('../isa')
  , log = require('npmlog')
  , EventEmitter = require('events').EventEmitter
  , Backbone = require('backbone')
  , path = require('path')
  , Mustache = require('consolidate').mustache
  , http = require('http')
  , httpProxy = require('http-proxy')
  //, log = new (require('log'))('info', fs.createWriteStream('testem.log2'))

require('./socket.io.patch')

function Server(config){
  this.config = config
  this.ieCompatMode = null
}
Server.prototype = {
  __proto__: EventEmitter.prototype
  , start: function(callback){
    callback = callback || function(){}
    this.createExpress()
    // Start the server!
    // Create socket.io sockets
    this.server = http.createServer(this.express)
    this.io = SocketIO.listen(this.server)
    this.io.sockets.on('connection', this.onClientConnected.bind(this))
    this.server.on('listening', function() {
      callback(null)
      this.emit('server-start')
    }.bind(this));
    this.server.on('error', function(e) {
      var err = new Error('Testem Server Error: ' + e.message)
      callback(err)
      this.emit('server-error', err)
    }.bind(this));
    this.server.listen(this.config.get('port'))
  }
  , stop: function(callback){
    this.server.close(callback)
  }
  , createExpress: function(){
    var self = this
    var app = this.express = Express()

    this.configureExpress(app)

    this.configureProxy(app)

    app.get('/', function(req, res){
      self.serveHomePage(req, res)
    })

    app.get(/\/([0-9]+)$/, function(req, res){
      self.serveHomePage(req, res)
    })

    app.get('/testem.js', function(req, res){
      self.serveTestemClientJs(req, res)
    })

    app.get(/^\/(?:[0-9]+)(\/.+)$/, serveStaticFile)
    app.post(/^\/(?:[0-9]+)(\/.+)$/, serveStaticFile)
    app.get(/^(.+)$/, serveStaticFile)
    app.post(/^(.+)$/, serveStaticFile)

    function serveStaticFile(req, res){
      self.serveStaticFile(req.params[0], req, res)
    }
  }
  , configureExpress: function(app){
    var self = this

    app.configure(function(){
      app.engine('mustache', Mustache)
      app.set("view options", {layout: false})
      app.use(function(req, res, next){
        if (self.ieCompatMode)
          res.setHeader('X-UA-Compatible', 'IE=' + self.ieCompatMode)
        next()
      })
      app.use(Express.static(__dirname + '/../../public'))
    })
  }
  , configureProxy: function(app) {
    var proxies = this.config.get('proxies');
    var self = this;
    if (proxies) {
        self.proxy = new httpProxy.RoutingProxy({changeOrigin: true})

        for (var proxy in proxies) {
            app.all(proxy + '/*', function(req, res) {
                self.proxy.proxyRequest(req, res, {
                    host: proxies[proxy].host,
                    port: proxies[proxy].port
                  })
            })
        }
    }
  }

  , renderRunnerPage: function(err, files, res){
    var config = this.config
    var framework = config.get('framework') || 'jasmine'
    var css_files = config.get('css_files')
    var templateFile = {
      jasmine: 'jasminerunner'
      , jasmine2: 'jasmine2runner'
      , qunit: 'qunitrunner'
      , mocha: 'mocharunner'
      , 'mocha+chai': 'mochachairunner'
      , buster: 'busterrunner'
      , custom: 'customrunner'
      , tap: 'taprunner'
    }[framework] + '.mustache'
    res.render(__dirname + '/../../views/' + templateFile, {
      scripts: files,
      styles: css_files
    })
  }
  , renderDefaultTestPage: function(req, res){
    res.header('Cache-Control', 'No-cache')
    res.header('Pragma', 'No-cache')

    var self = this
    var config = this.config
    var test_page = config.get('test_page')

    if (test_page){
      if (test_page[0] === "/") {
        test_page = encodeURIComponent(test_page)
      }
      var base = req.path === '/' ?
        req.path : req.path + '/'
      var url = base + test_page
      res.redirect(url)
    } else {
      config.getServeFiles(function(err, files){
        self.renderRunnerPage(err, files, res)
      })
    }
  }
  , serveHomePage: function(req, res){
    var config = this.config
    var routes = config.get('routes') || config.get('route') || {}
    if (routes['/']){
      this.serveStaticFile('/', req, res)
    }else{
      this.renderDefaultTestPage(req, res)
    }
  }
  , serveTestemClientJs: function(req, res){
    res.setHeader('Content-Type', 'text/javascript')

    res.write(';(function(){')
    var files = [
      'socket.io.js'
      , 'json2.js'
      , 'jasmine_adapter.js'
      , 'jasmine2_adapter.js'
      , 'qunit_adapter.js'
      , 'mocha_adapter.js'
      , 'buster_adapter.js'
      , 'testem_client.js'
    ]
    async.forEachSeries(files, function(file, done){
      file = __dirname + '/../../public/testem/' + file
      fs.readFile(file, function(err, data){
        if (err){
          res.write('// Error reading ' + file + ': ' + err)
        }else{
          res.write('\n//============== ' + path.basename(file) + ' ==================\n\n')
          res.write(data)
        }
        done()
      })
    }, function(){
      res.write('}());')
      res.end()
    })

  }
  , killTheCache: function killTheCache(req, res){
    res.setHeader('Cache-Control', 'No-cache')
    res.setHeader('Pragma', 'No-cache')
    delete req.headers['if-modified-since']
    delete req.headers['if-none-match']
  }
  , route: function route(uri){
    var config = this.config
    var routes = config.get('routes') || config.get('route') || {}
    var bestMatchLength = 0
    var bestMatch = null
    for (var prefix in routes){
      if (uri.substring(0, prefix.length) === prefix){
        if (bestMatchLength < prefix.length){
          bestMatch = routes[prefix] + '/' + uri.substring(prefix.length)
          bestMatchLength = prefix.length
        }
      }
    }
    return {
      routed: !!bestMatch
      , uri: bestMatch || uri.substring(1)
    }
  }
  , serveStaticFile: function(uri, req, res){
    var self = this
    var config = this.config
    var routeRes = this.route(uri)
    uri = routeRes.uri
    var wasRouted = routeRes.routed
    this.killTheCache(req, res)
    var allowUnsafeDirs = config.get('unsafe_file_serving')
    var filePath = path.resolve(config.resolvePath(uri))
    var ext = path.extname(filePath)
    var isPathPermitted = filePath.indexOf(config.cwd()) !== -1
    if (!wasRouted && !allowUnsafeDirs && !isPathPermitted) {
      res.status(403)
      res.write('403 Forbidden')
      res.end()
    } else if (ext === '.mustache') {
      config.getTemplateData(function(err, data){
        res.render(filePath, data)
        self.emit('file-requested', filePath)
      })
    } else {
      fs.stat(filePath, function(err, stat){
        self.emit('file-requested', filePath)
        if (err) return res.sendfile(filePath)
        if (stat.isDirectory()){
          fs.readdir(filePath, function(err, files){
            var dirListingPage = __dirname + '/../../views/directorylisting.mustache'
            res.render(dirListingPage, {files: files})
          })
        }else{
          res.sendfile(filePath)
        }
      })
    }
  }
  , onClientConnected: function(client){
    var self = this
    client.once('browser-login', function(browserName, id){
      log.info('New client connected: ' + browserName + ' ' + id)
      self.emit('browser-login', browserName, id, client)
    })
  }
}

module.exports = Server
<commit_msg>Add middleware configuration<commit_after>/*

server.js
=========

Testem's server. Serves up the HTML, JS, and CSS required for
running the tests in a browser.

*/

var Express = require('express')
  , SocketIO = require('socket.io')
  , BrowserRunner = require('../browser_runner')
  , fs = require('fs')
  , path = require('path')
  , util = require('util')
  , async = require('async')
  , glob = require('glob')
  , isa = require('../isa')
  , log = require('npmlog')
  , EventEmitter = require('events').EventEmitter
  , Backbone = require('backbone')
  , path = require('path')
  , Mustache = require('consolidate').mustache
  , http = require('http')
  , httpProxy = require('http-proxy')
  //, log = new (require('log'))('info', fs.createWriteStream('testem.log2'))

require('./socket.io.patch')

function Server(config){
  this.config = config
  this.ieCompatMode = null
}
Server.prototype = {
  __proto__: EventEmitter.prototype
  , start: function(callback){
    callback = callback || function(){}
    this.createExpress()
    // Start the server!
    // Create socket.io sockets
    this.server = http.createServer(this.express)
    this.io = SocketIO.listen(this.server)
    this.io.sockets.on('connection', this.onClientConnected.bind(this))
    this.server.on('listening', function() {
      callback(null)
      this.emit('server-start')
    }.bind(this));
    this.server.on('error', function(e) {
      var err = new Error('Testem Server Error: ' + e.message)
      callback(err)
      this.emit('server-error', err)
    }.bind(this));
    this.server.listen(this.config.get('port'))
  }
  , stop: function(callback){
    this.server.close(callback)
  }
  , createExpress: function(){
    var self = this
    var app = this.express = Express()

    this.configureExpress(app)

    this.injectMiddleware(app)

    this.configureProxy(app)

    app.get('/', function(req, res){
      self.serveHomePage(req, res)
    })

    app.get(/\/([0-9]+)$/, function(req, res){
      self.serveHomePage(req, res)
    })

    app.get('/testem.js', function(req, res){
      self.serveTestemClientJs(req, res)
    })

    app.get(/^\/(?:[0-9]+)(\/.+)$/, serveStaticFile)
    app.post(/^\/(?:[0-9]+)(\/.+)$/, serveStaticFile)
    app.get(/^(.+)$/, serveStaticFile)
    app.post(/^(.+)$/, serveStaticFile)

    function serveStaticFile(req, res){
      self.serveStaticFile(req.params[0], req, res)
    }
  }
  , configureExpress: function(app){
    var self = this

    app.configure(function(){
      app.engine('mustache', Mustache)
      app.set("view options", {layout: false})
      app.use(function(req, res, next){
        if (self.ieCompatMode)
          res.setHeader('X-UA-Compatible', 'IE=' + self.ieCompatMode)
        next()
      })
      app.use(Express.static(__dirname + '/../../public'))
    })
  }
  , injectMiddleware: function(app) {
    var middlewares = this.config.get('middleware')
    if (middlewares) {
      middlewares.forEach(function(middleware) {
        middleware(app);
      })
    }
  }
  , configureProxy: function(app) {
    var proxies = this.config.get('proxies');
    var self = this;
    if (proxies) {
        self.proxy = new httpProxy.RoutingProxy({changeOrigin: true})

        for (var proxy in proxies) {
            app.all(proxy + '/*', function(req, res) {
                self.proxy.proxyRequest(req, res, {
                    host: proxies[proxy].host,
                    port: proxies[proxy].port
                  })
            })
        }
    }
  }

  , renderRunnerPage: function(err, files, res){
    var config = this.config
    var framework = config.get('framework') || 'jasmine'
    var css_files = config.get('css_files')
    var templateFile = {
      jasmine: 'jasminerunner'
      , jasmine2: 'jasmine2runner'
      , qunit: 'qunitrunner'
      , mocha: 'mocharunner'
      , 'mocha+chai': 'mochachairunner'
      , buster: 'busterrunner'
      , custom: 'customrunner'
      , tap: 'taprunner'
    }[framework] + '.mustache'
    res.render(__dirname + '/../../views/' + templateFile, {
      scripts: files,
      styles: css_files
    })
  }
  , renderDefaultTestPage: function(req, res){
    res.header('Cache-Control', 'No-cache')
    res.header('Pragma', 'No-cache')

    var self = this
    var config = this.config
    var test_page = config.get('test_page')

    if (test_page){
      if (test_page[0] === "/") {
        test_page = encodeURIComponent(test_page)
      }
      var base = req.path === '/' ?
        req.path : req.path + '/'
      var url = base + test_page
      res.redirect(url)
    } else {
      config.getServeFiles(function(err, files){
        self.renderRunnerPage(err, files, res)
      })
    }
  }
  , serveHomePage: function(req, res){
    var config = this.config
    var routes = config.get('routes') || config.get('route') || {}
    if (routes['/']){
      this.serveStaticFile('/', req, res)
    }else{
      this.renderDefaultTestPage(req, res)
    }
  }
  , serveTestemClientJs: function(req, res){
    res.setHeader('Content-Type', 'text/javascript')

    res.write(';(function(){')
    var files = [
      'socket.io.js'
      , 'json2.js'
      , 'jasmine_adapter.js'
      , 'jasmine2_adapter.js'
      , 'qunit_adapter.js'
      , 'mocha_adapter.js'
      , 'buster_adapter.js'
      , 'testem_client.js'
    ]
    async.forEachSeries(files, function(file, done){
      file = __dirname + '/../../public/testem/' + file
      fs.readFile(file, function(err, data){
        if (err){
          res.write('// Error reading ' + file + ': ' + err)
        }else{
          res.write('\n//============== ' + path.basename(file) + ' ==================\n\n')
          res.write(data)
        }
        done()
      })
    }, function(){
      res.write('}());')
      res.end()
    })

  }
  , killTheCache: function killTheCache(req, res){
    res.setHeader('Cache-Control', 'No-cache')
    res.setHeader('Pragma', 'No-cache')
    delete req.headers['if-modified-since']
    delete req.headers['if-none-match']
  }
  , route: function route(uri){
    var config = this.config
    var routes = config.get('routes') || config.get('route') || {}
    var bestMatchLength = 0
    var bestMatch = null
    for (var prefix in routes){
      if (uri.substring(0, prefix.length) === prefix){
        if (bestMatchLength < prefix.length){
          bestMatch = routes[prefix] + '/' + uri.substring(prefix.length)
          bestMatchLength = prefix.length
        }
      }
    }
    return {
      routed: !!bestMatch
      , uri: bestMatch || uri.substring(1)
    }
  }
  , serveStaticFile: function(uri, req, res){
    var self = this
    var config = this.config
    var routeRes = this.route(uri)
    uri = routeRes.uri
    var wasRouted = routeRes.routed
    this.killTheCache(req, res)
    var allowUnsafeDirs = config.get('unsafe_file_serving')
    var filePath = path.resolve(config.resolvePath(uri))
    var ext = path.extname(filePath)
    var isPathPermitted = filePath.indexOf(config.cwd()) !== -1
    if (!wasRouted && !allowUnsafeDirs && !isPathPermitted) {
      res.status(403)
      res.write('403 Forbidden')
      res.end()
    } else if (ext === '.mustache') {
      config.getTemplateData(function(err, data){
        res.render(filePath, data)
        self.emit('file-requested', filePath)
      })
    } else {
      fs.stat(filePath, function(err, stat){
        self.emit('file-requested', filePath)
        if (err) return res.sendfile(filePath)
        if (stat.isDirectory()){
          fs.readdir(filePath, function(err, files){
            var dirListingPage = __dirname + '/../../views/directorylisting.mustache'
            res.render(dirListingPage, {files: files})
          })
        }else{
          res.sendfile(filePath)
        }
      })
    }
  }
  , onClientConnected: function(client){
    var self = this
    client.once('browser-login', function(browserName, id){
      log.info('New client connected: ' + browserName + ' ' + id)
      self.emit('browser-login', browserName, id, client)
    })
  }
}

module.exports = Server
<|endoftext|>