<commit_before>//definisco un costruttore di tattiche
function tattica(nome,difensori,mediani,centrocampisti,trequartisti,attaccanti)
{
	this.nome=nome;
	this.difensori=difensori;
	this.mediani=mediani;
	this.centrocampisti=centrocampisti;
	this.trequartisti=trequartisti;
	this.attaccanti=attaccanti;
}

//definisco un costruttore di calciatore
function calciatore(contratto,nomeCognome,ruolo,selezionato)
{
	this.contratto=contratto;
	this.nomeCognome=nomeCognome;
	this.ruolo=ruolo;
	this.selezionato=selezionato;
}
//istanzio array dei calciatori e di moduli
var calciatori=new Array();
var tattiche=new Array();

//funzione che caricherà i calciatori presenti nel database convocati per la partita
function caricaCalciatori()
{
	var xmlhttp = new XMLHttpRequest();

	xmlhttp.onreadystatechange = function()
	{
		if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
		{
			var jsonRisposta=xmlhttp.responseText;
			jsonRisposta=JSON.parse(jsonRisposta);

			for (var i=0; i<jsonRisposta.calciatori.length; i++)
			{
				calciatori.push(new calciatore(jsonRisposta.calciatori[i].contratto,jsonRisposta.calciatori[i].nomeCognome,jsonRisposta.calciatori[i].ruoli,false));
			}
		}

	};

	xmlhttp.open("GET", "http://localhost/yourteam/web/app_dev.php/formazione/allenatore/ottieniCalciatori", false);
	xmlhttp.send();

}

//funzione che carica la tattica selezionata nella comboBox
function caricaTattica()
{
	var xmlhttp = new XMLHttpRequest();

	xmlhttp.onreadystatechange = function()
	{
		if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
		{
			var jsonRisposta=xmlhttp.responseText;
			jsonRisposta=JSON.parse(jsonRisposta);

			for (var i=0 ; i<jsonRisposta.modulo.length ; i++)
			{
				tattiche.push(new tattica(jsonRisposta.modulo[i].nome,jsonRisposta.modulo[i].difensori,jsonRisposta.modulo[i].mediani,jsonRisposta.modulo[i].centrocampisti,jsonRisposta.modulo[i].trequartisti,jsonRisposta.modulo[i].attaccanti));
			}
		}

	};

	xmlhttp.open("GET", "http://localhost/yourteam/web/app_dev.php/formazione/allenatore/cambiaTattica", false);
	xmlhttp.send();

}<commit_msg>fix bug richieste ajax<commit_after>//definisco un costruttore di tattiche
function tattica(nome,difensori,mediani,centrocampisti,trequartisti,attaccanti)
{
	this.nome=nome;
	this.difensori=difensori;
	this.mediani=mediani;
	this.centrocampisti=centrocampisti;
	this.trequartisti=trequartisti;
	this.attaccanti=attaccanti;
}

//definisco un costruttore di calciatore
function calciatore(contratto,nomeCognome,ruolo,selezionato)
{
	this.contratto=contratto;
	this.nomeCognome=nomeCognome;
	this.ruolo=ruolo;
	this.selezionato=selezionato;
}
//istanzio array dei calciatori e di moduli
var calciatori=new Array();
var tattiche=new Array();

//funzione che caricherà i calciatori presenti nel database convocati per la partita
function caricaCalciatori()
{
	var xmlhttp = new XMLHttpRequest();

	xmlhttp.onreadystatechange = function()
	{
		if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
		{
			var jsonRisposta=xmlhttp.responseText;
			jsonRisposta=JSON.parse(jsonRisposta);

			for (var i=0; i<jsonRisposta.calciatori.length; i++)
			{
				calciatori.push(new calciatore(jsonRisposta.calciatori[i].contratto,jsonRisposta.calciatori[i].nomeCognome,jsonRisposta.calciatori[i].ruoli,false));
			}
		}

	};

	xmlhttp.open("GET", "{{ path('ottieniCalciatori') }}", false);
	xmlhttp.send();

}

//funzione che carica la tattica selezionata nella comboBox
function caricaTattica()
{
	var xmlhttp = new XMLHttpRequest();

	xmlhttp.onreadystatechange = function()
	{
		if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
		{
			var jsonRisposta=xmlhttp.responseText;
			jsonRisposta=JSON.parse(jsonRisposta);

			for (var i=0 ; i<jsonRisposta.modulo.length ; i++)
			{
				tattiche.push(new tattica(jsonRisposta.modulo[i].nome,jsonRisposta.modulo[i].difensori,jsonRisposta.modulo[i].mediani,jsonRisposta.modulo[i].centrocampisti,jsonRisposta.modulo[i].trequartisti,jsonRisposta.modulo[i].attaccanti));
			}
		}

	};

	xmlhttp.open("GET", "{{ path('cambiaTattica') }}", false);
	xmlhttp.send();

}<|endoftext|>


<commit_before>/**
 * This model is used to store the state of a search query, and implements the
 * search filtering logic.
 */
cinema.models.SearchModel = Backbone.Model.extend({
    constructor: function (settings) {
        Backbone.Model.apply(this, arguments);

        this.layerModel = settings.layerModel;
        this.visModel = settings.visModel;
        this.query = settings.query || {};
    },

    /**
     * Convert a query string into a query object that can be used to filter
     * results in this model.
     */
    parseQuery: function (str) {
        try {
            //str = '{' + str.trim() + '}';
            console.log(str);
            var parse_tree = jsep(str);
            console.log(parse_tree);
            return $.parseJSON(str.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":'));
        } catch (e) {
            return null;
        }
    },

    /**
     * This method computes all matching search results, and triggers
     * a 'c:done' event when it has finished.
     */
    compute: function () {
        this.results = [];

        var i;
        for (i = 0; i < this.visModel.imageCount(); i += 1) {
            var viewpoint = this.visModel.ordinalToObject(i);

            if (this._filter(viewpoint)) {
                this.results.push(viewpoint);
            }
        }
        // TODO sort results

        this.trigger('c:done');
    },

    /**
     * Filter a single result based on the current query. Return true if it is a
     * match, false if not.
     */
    _filter: function (viewpoint) {
        return _.every(['phi', 'theta', 'time'], function (field) {
            if (!_.has(this.query, field)) {
                return true;
            }
            return this.query[field].toString() === viewpoint[field];
        }, this);
    }
});
<commit_msg>partial traverse of parse tree.<commit_after>/**
 * This model is used to store the state of a search query, and implements the
 * search filtering logic.
 */
cinema.models.SearchModel = Backbone.Model.extend({
    constructor: function (settings) {
        Backbone.Model.apply(this, arguments);

        this.layerModel = settings.layerModel;
        this.visModel = settings.visModel;
        this.query = settings.query || {};
    },

    /**
     * Convert a query string into a query object that can be used to filter
     * results in this model.
     */
    parseQuery: function (str) {
        try {
            var parse_tree = jsep(str);
            this.traverseParseTree(parse_tree);
        } catch (e) {
            return null;
        }
    },

    traverseParseTree: function (tree) {
        var str = "";
        console.log(tree.left, tree.right);
        if (tree.right.right) {
            this.traverseParseTree(tree.right);
        }
        else {
            if (tree.left.type === "Identifier" ) {
                str = str + tree.left.name;
            }
            console.log(tree.left.value,tree.operator,tree.right.value);
        }
    },

    /**
     * This method computes all matching search results, and triggers
     * a 'c:done' event when it has finished.
     */
    compute: function () {
        this.results = [];

        var i;
        for (i = 0; i < this.visModel.imageCount(); i += 1) {
            var viewpoint = this.visModel.ordinalToObject(i);

            if (this._filter(viewpoint)) {
                this.results.push(viewpoint);
            }
        }
        // TODO sort results

        this.trigger('c:done');
    },

    /**
     * Filter a single result based on the current query. Return true if it is a
     * match, false if not.
     */
    _filter: function (viewpoint) {
        return _.every(['phi', 'theta', 'time'], function (field) {
            if (!_.has(this.query, field)) {
                return true;
            }
            return this.query[field].toString() === viewpoint[field];
        }, this);
    }
});
<|endoftext|>


<commit_before>/* global d3 */
histomicstk.views.Visualization = girder.View.extend({
    initialize: function () {
        // rendered annotation layers
        this._annotations = {};

        // the map object
        this._map = null;

        // the rendered map layers
        this._layers = [];

        // control model for file widget
        this._controlModel = histomicstk.dialogs.image.model;

        this._annotationList = new histomicstk.views.AnnotationSelectorWidget({
            parentView: this
        });

        // extra scaling factor to handle images that are not powers of 2 in size
        this._unitsPerPixel = 1;

        // prebind the onResize method so we can remove it on destroy
        this._onResize = _.bind(this._onResize, this);

        // create a debounced rerender method to delay rendering
        // until after user navigation is completed
        this._debouncedRender = _.debounce(_.bind(this._syncViewport, this), 300);

        // shared viewport object for annotation layers
        this.viewport = new girder.annotation.Viewport();
        this._onResize();
        $(window).resize(this._onResize);

        this.listenTo(this._controlModel, 'change:value', function (model) {
            if (!model.get('value')) {
                return;
            }

            var id = model.get('value').id;
            girder.restRequest({
                path: 'item/' + id
            })
            .then(_.bind(function (item) {
                this._controlModel.get('value').set(item);
                histomicstk.router.setQuery('image', id);
                return this.addItem(this._controlModel.get('value'));
            }, this))
            .fail(_.bind(function () {
                var info = {
                    text: 'Could not render item as an image',
                    type: 'danger',
                    timeout: 5000,
                    icon: 'attention'
                };
                girder.events.trigger('g:alert', info);
                histomicstk.router.setQuery('image', null, {replace: true});
            }, this));
        });

        this.listenTo(histomicstk.events, 'query:image', function (image) {
            var currentImage = this._controlModel.get('value') || {};
            if (image && currentImage.id !== image) {
                this._controlModel.set('value', new girder.models.ItemModel({_id: image}));
            } else if (!image) {
                this.removeItem();
                this._controlModel.set('value', null);
            }
        });

        // Set image bounds on URL query parameter change
        this.listenTo(histomicstk.events, 'query:bounds', this._boundsFromQuery);

        // fallback to canvas renderer rather than dom
        geo.gl.vglRenderer.fallback = function () {return 'canvas';};
    },

    /**
     * Set the displayed image bounds according to the given query string.
     */
    _boundsFromQuery: function (query) {
        if (!this._map || !query) {
            return;
        }
        var bounds = query.split(',').map(function (v) { return +v; });
        this._map.rotation(bounds[4] * Math.PI / 180);
        this._map.bounds({
            left: bounds[0],
            top: -bounds[1],
            right: bounds[2],
            bottom: -bounds[3]
        }, null);
    },

    /**
     * Create a map object with the given global bounds.
     */
    _createMap: function (bounds) {
        if (this._map) {
            // reset bounds query parameter on map exit
            histomicstk.router.setQuery('bounds', null, {replace: true, trigger: false});
            this._map.exit();
        }
        bounds.left = bounds.left || 0;
        bounds.top = bounds.top || 0;
        var w = bounds.right - bounds.left;
        var h = bounds.bottom - bounds.top;
        var interactor = geo.mapInteractor({
            zoomAnimation: false
        });

        this._map = geo.map({
            node: '
',
            width: this.$el.width() || 100,
            height: this.$el.height() || 100,
            ingcs: '+proj=longlat +axis=esu',
            gcs: '+proj=longlat +axis=enu',
            maxBounds: bounds,
            clampBoundsX: false,
            clampBoundsY: false,
            center: {x: w / 2, y: h / 2},
            zoom: 0,
            discreteZoom: false,
            interactor: interactor
        });

        this._boundsFromQuery(histomicstk.router.getQuery('bounds'));
        this._syncViewport();
        this._map.geoOn(geo.event.pan, _.bind(this._onMouseNavigate, this));
        this.$('.h-visualization-body').empty().append(this._map.node());
    },

    renderAnnotationList: function (item) {
        if (this._annotationList.collection) {
            this.stopListening(this._annotationList);
        }
        this._annotationList
            .setItem(item)
            .setElement(this.$('.h-annotation-panel'))
            .render()
            .$el.removeClass('hidden');

        this.listenTo(this._annotationList.collection, 'change:displayed', this._toggleAnnotation);
    },

    /**
     * Add a map layer from a girder item object.  The girder item should contain a
     * single image file (the first encountered will be used) or be registered
     * as a tiled image via the large_image plugin.
     *
     * This method is async, errors encountered will trigger an error event and
     * reject the returned promise.  The promise is resolved with the added map
     * layer.
     *
     * @TODO: How do we pass in bounds?
     * @TODO: Allow multiple layers (don't reset map on add).
     */
    addItem: function (item) {
        var promise;

        this.resetAnnotations();
        this.renderAnnotationList(item);

        // first check if it is a tiled image
        if (item.id === 'test' || item.has('largeImage')) {
            promise = girder.restRequest({
                path: 'item/' + item.id + '/tiles'
            })
            .then(_.bind(function (tiles) {
                // It is a tile item
                return this.addTileLayer(
                    {
                        url: girder.apiRoot + '/item/' + item.id + '/tiles/zxy/{z}/{x}/{y}',
                        maxLevel: tiles.levels,
                        tileWidth: tiles.tileWidth,
                        tileHeight: tiles.tileHeight,
                        sizeX: tiles.sizeX,
                        sizeY: tiles.sizeY
                    }
                );
            }, this));
        } else { // check for an image file
            promise = girder.restRequest({
                path: 'item/' + item.id + '/files',
                limit: 1 // we *could* look through all the files,
            })
            .then(_.bind(function (files) {
                var img = null, defer, imgElement;

                _.each(files, function (file) {
                    if ((file.mimeType || '').startsWith('image/')) {
                        img = new girder.models.FileModel(file);
                    }
                });

                if (!img) {
                    // no image is present, so return a reject promise
                    return new $.Deferred().reject('No renderable image file found').promise();
                }

                // Download the file to get the image size
                defer = new $.Deferred();
                imgElement = new Image();
                imgElement.onload = function () {
                    defer.resolve(imgElement);
                };
                imgElement.onerror = function () {
                    defer.reject('Could not load image');
                };
                imgElement.src = girder.apiRoot + '/file/' + img.id + '/download';
                return defer.promise();
            }))
            .then(_.bind(function (img) {
                // Inspect the image and add it to the map
                return this.addImageLayer(
                    img.src,
                    {
                        right: img.width,
                        bottom: img.height
                    }
                );
            }, this));
        }

        return promise;
    },

    /**
     * Add a single image as a quad feature on the viewer from an image url.
     *
     * @param {string} url The url of the image
     * @param {object} bounds
     *  The coordinate bounds of the image (left, right, top, bottom).
     */
    addImageLayer: function (url, bounds) {
        this._createMap(bounds);
        var layer = this._map.createLayer('feature', {renderer: 'vgl'});
        var quad = layer.createFeature('quad');
        quad.data([
            {
                ll: {x: bounds.left || 0, y: -bounds.bottom},
                ur: {x: bounds.right, y: bounds.top || 0},
                image: url
            }
        ]);
        this._layers.push(layer);
        this._map.draw();
        return quad;
    },

    removeItem: function () {
        this.resetAnnotations();
        this._annotationList.render().$el.addClass('hidden');
        if (this._map) {
            this._map.exit();
            this._map = null;
            this.$('.h-visualization-body').empty();
        }
    },

    /**
     * Add a tiled image as a tileLayer on the view from an options object.
     * The options object takes options supported by geojs's tileLayer:
     *
     *   https://github.com/OpenGeoscience/geojs/blob/master/src/tileLayer.js
     *
     * @param {object} opts Tile layer required options
     * @param {string|function} opts.url
     */
    addTileLayer: function (opts) {
        var layer;
        if (!_.has(opts, 'url')) {
            throw new Error('`url` parameter required.');
        }

        _.defaults(opts, {
            useCredentials: true,
            maxLevel: 10,
            wrapX: false,
            wrapY: false,
            tileOffset: function () {
                return {x: 0, y: 0};
            },
            attribution: '',
            tileWidth: 256,
            tileHeight: 256,
            tileRounding: Math.ceil
        });

        // estimate the global bounds if not provided
        if (!opts.sizeX) {
            opts.sizeX = Math.pow(2, opts.maxLevel) * opts.tileWidth;
        }
        if (!opts.sizeY) {
            opts.sizeY = Math.pow(2, opts.maxLevel) * opts.tileHeight;
        }

        this._createMap({
            right: opts.sizeX - 1,
            bottom: opts.sizeY - 1
        });
        layer = this._map.createLayer('osm', opts);
        this._unitsPerPixel = this._map.unitsPerPixel(opts.maxLevel - 1);
        this._layers.push(layer);
        this._map.draw();
        return layer;
    },

    addAnnotationLayer: function (annotation) {
        var el = d3.select(this.el)
                .select('.h-annotation-layers')
                .append('svg')
                .node();

        this._onResize();
        var settings = $.extend({
            el: el,
            viewport: this.viewport
        }, annotation.annotation);

        this._annotations[annotation._id] = new girder.annotation.Annotation(settings).render();
        return this;
    },

    removeAnnotationLayer: function (id) {
        if (_.has(this._annotations, id)) {
            this._annotations[id].remove();
            delete this._annotations[id];
        }
        return this;
    },

    resetAnnotations: function () {
        _.each(_.keys(this._annotations), _.bind(this.removeAnnotationLayer, this));
        return this;
    },

    render: function () {

        this.$el.html(histomicstk.templates.visualization());
        return this;
    },

    destroy: function () {
        $(window).off('resize', this._onResize);
        this._map.exit();
        this.$el.empty();
        this._controlModel.destroy();
        girder.View.prototype.destroy.apply(this, arguments);
    },

    /**
     * Resize the viewport according to the size of the container.
     */
    _onResize: function () {
        var width = this.$el.width() || 100;
        var height = this.$el.height() || 100;
        var layers = this.$('.h-annotation-layers > svg');

        this.viewport.set({
            width: width,
            height: height
        });
        layers.attr('width', width);
        layers.attr('height', height);
        this._syncViewport();
    },

    /**
     * Respond to fast firing mouse navigation events by applying transforms
     * to the svg element so we can debounce the slow rerenders.
     */
    _onMouseNavigate: function () {
        var ul, dz;
        if (!this._lastCorner) {
            // do a full rerender if we haven't synced the viewport yet
            this._syncViewport();
            return;
        }

        ul = this._map.gcsToDisplay({
            x: this._lastCorner.x,
            y: this._lastCorner.y
        });

        dz = Math.pow(2, this._map.zoom() - this._lastZoom);

        this.$('.h-annotation-layers')
            .css(
                'transform',
                'translate(' + ul.x + 'px,' + ul.y + 'px)scale(' + dz + ')'
            );

        // schedule a debounced rerender
        this._debouncedRender();

        // Update the bounds in the query string
        var bounds = this._map.bounds(undefined, null);
        histomicstk.router.setQuery(
            'bounds',
            [
                this._formatNumber(bounds.left),
                this._formatNumber(-bounds.top),
                this._formatNumber(bounds.right),
                this._formatNumber(-bounds.bottom),
                this._formatNumber(this._map.rotation() * 180 / Math.PI)
            ].join(','),
            {
                replace: true,
                trigger: false
            }
        );
    },

    _formatNumber: function (num) {
        return (Math.round(num * 100) / 100).toString()
    },

    _syncViewport: function () {
        var bds;
        if (!this._map) {
            return;
        }

        this.$('.h-annotation-layers')
            .css('transform', '');

        bds = this._map.bounds(undefined, null);
        this._lastCorner = this._map.displayToGcs({
            x: 0,
            y: 0
        });
        this._lastZoom = this._map.zoom();

        this.viewport.set({
            scale: (bds.right - bds.left) / (this.viewport.get('width') * this._unitsPerPixel)
        });
        this.viewport.set({
            top: -bds.top / this._unitsPerPixel,
            left: bds.left / this._unitsPerPixel
        });
    },

    _toggleAnnotation: function (model) {
        if (model.get('displayed') && !_.has(this._annotations, model.id)) {
            girder.restRequest({
                path: 'annotation/' + model.id
            }).then(_.bind(this.addAnnotationLayer, this));
        } else if (!model.get('displayed') && _.has(this._annotations, model.id)) {
            this.removeAnnotationLayer(model.id);
        }
    }
});

histomicstk.dialogs.image = new histomicstk.views.ItemSelectorWidget({
    parentView: null,
    model: new histomicstk.models.Widget({
        type: 'file'
    })
});
<commit_msg>Crop images on the right and bottom so that only valid portions of the image are shown.<commit_after>/* global d3 */
histomicstk.views.Visualization = girder.View.extend({
    initialize: function () {
        // rendered annotation layers
        this._annotations = {};

        // the map object
        this._map = null;

        // the rendered map layers
        this._layers = [];

        // control model for file widget
        this._controlModel = histomicstk.dialogs.image.model;

        this._annotationList = new histomicstk.views.AnnotationSelectorWidget({
            parentView: this
        });

        // extra scaling factor to handle images that are not powers of 2 in size
        this._unitsPerPixel = 1;

        // prebind the onResize method so we can remove it on destroy
        this._onResize = _.bind(this._onResize, this);

        // create a debounced rerender method to delay rendering
        // until after user navigation is completed
        this._debouncedRender = _.debounce(_.bind(this._syncViewport, this), 300);

        // shared viewport object for annotation layers
        this.viewport = new girder.annotation.Viewport();
        this._onResize();
        $(window).resize(this._onResize);

        this.listenTo(this._controlModel, 'change:value', function (model) {
            if (!model.get('value')) {
                return;
            }

            var id = model.get('value').id;
            girder.restRequest({
                path: 'item/' + id
            })
            .then(_.bind(function (item) {
                this._controlModel.get('value').set(item);
                histomicstk.router.setQuery('image', id);
                return this.addItem(this._controlModel.get('value'));
            }, this))
            .fail(_.bind(function () {
                var info = {
                    text: 'Could not render item as an image',
                    type: 'danger',
                    timeout: 5000,
                    icon: 'attention'
                };
                girder.events.trigger('g:alert', info);
                histomicstk.router.setQuery('image', null, {replace: true});
            }, this));
        });

        this.listenTo(histomicstk.events, 'query:image', function (image) {
            var currentImage = this._controlModel.get('value') || {};
            if (image && currentImage.id !== image) {
                this._controlModel.set('value', new girder.models.ItemModel({_id: image}));
            } else if (!image) {
                this.removeItem();
                this._controlModel.set('value', null);
            }
        });

        // Set image bounds on URL query parameter change
        this.listenTo(histomicstk.events, 'query:bounds', this._boundsFromQuery);

        // fallback to canvas renderer rather than dom
        geo.gl.vglRenderer.fallback = function () {return 'canvas';};
    },

    /**
     * Set the displayed image bounds according to the given query string.
     */
    _boundsFromQuery: function (query) {
        if (!this._map || !query) {
            return;
        }
        var bounds = query.split(',').map(function (v) { return +v; });
        this._map.rotation(bounds[4] * Math.PI / 180);
        this._map.bounds({
            left: bounds[0],
            top: -bounds[1],
            right: bounds[2],
            bottom: -bounds[3]
        }, null);
    },

    /**
     * Create a map object with the given global bounds.
     */
    _createMap: function (bounds) {
        if (this._map) {
            // reset bounds query parameter on map exit
            histomicstk.router.setQuery('bounds', null, {replace: true, trigger: false});
            this._map.exit();
        }
        bounds.left = bounds.left || 0;
        bounds.top = bounds.top || 0;
        var interactor = geo.mapInteractor({
            zoomAnimation: false
        });

        this._map = geo.map({
            node: '
',
            width: this.$el.width() || 100,
            height: this.$el.height() || 100,
            ingcs: '+proj=longlat +axis=esu',
            gcs: '+proj=longlat +axis=enu',
            maxBounds: bounds,
            // to appropriate set min and max, we need to know the tile size
            // (using a single image may require the ability to zoom out).
            clampBoundsX: false,
            clampBoundsY: false,
            center: {x: (bounds.left + bounds.right) / 2,
                     y: (bounds.top + bounds.bottom) / 2},
            zoom: 0,
            discreteZoom: false,
            interactor: interactor
        });

        this._boundsFromQuery(histomicstk.router.getQuery('bounds'));
        this._syncViewport();
        this._map.geoOn(geo.event.pan, _.bind(this._onMouseNavigate, this));
        this.$('.h-visualization-body').empty().append(this._map.node());
    },

    renderAnnotationList: function (item) {
        if (this._annotationList.collection) {
            this.stopListening(this._annotationList);
        }
        this._annotationList
            .setItem(item)
            .setElement(this.$('.h-annotation-panel'))
            .render()
            .$el.removeClass('hidden');

        this.listenTo(this._annotationList.collection, 'change:displayed', this._toggleAnnotation);
    },

    /**
     * Add a map layer from a girder item object.  The girder item should contain a
     * single image file (the first encountered will be used) or be registered
     * as a tiled image via the large_image plugin.
     *
     * This method is async, errors encountered will trigger an error event and
     * reject the returned promise.  The promise is resolved with the added map
     * layer.
     *
     * @TODO: How do we pass in bounds?
     * @TODO: Allow multiple layers (don't reset map on add).
     */
    addItem: function (item) {
        var promise;

        this.resetAnnotations();
        this.renderAnnotationList(item);

        // first check if it is a tiled image
        if (item.id === 'test' || item.has('largeImage')) {
            promise = girder.restRequest({
                path: 'item/' + item.id + '/tiles'
            })
            .then(_.bind(function (tiles) {
                // It is a tile item
                return this.addTileLayer(
                    {
                        url: girder.apiRoot + '/item/' + item.id + '/tiles/zxy/{z}/{x}/{y}',
                        maxLevel: tiles.levels - 1,
                        tileWidth: tiles.tileWidth,
                        tileHeight: tiles.tileHeight,
                        sizeX: tiles.sizeX,
                        sizeY: tiles.sizeY
                    }
                );
            }, this));
        } else { // check for an image file
            promise = girder.restRequest({
                path: 'item/' + item.id + '/files',
                limit: 1 // we *could* look through all the files,
            })
            .then(_.bind(function (files) {
                var img = null, defer, imgElement;

                _.each(files, function (file) {
                    if ((file.mimeType || '').startsWith('image/')) {
                        img = new girder.models.FileModel(file);
                    }
                });

                if (!img) {
                    // no image is present, so return a reject promise
                    return new $.Deferred().reject('No renderable image file found').promise();
                }

                // Download the file to get the image size
                defer = new $.Deferred();
                imgElement = new Image();
                imgElement.onload = function () {
                    defer.resolve(imgElement);
                };
                imgElement.onerror = function () {
                    defer.reject('Could not load image');
                };
                imgElement.src = girder.apiRoot + '/file/' + img.id + '/download';
                return defer.promise();
            }))
            .then(_.bind(function (img) {
                // Inspect the image and add it to the map
                return this.addImageLayer(
                    img.src,
                    {
                        right: img.width,
                        bottom: img.height
                    }
                );
            }, this));
        }

        return promise;
    },

    /**
     * Add a single image as a quad feature on the viewer from an image url.
     *
     * @param {string} url The url of the image
     * @param {object} bounds
     *  The coordinate bounds of the image (left, right, top, bottom).
     */
    addImageLayer: function (url, bounds) {
        this._createMap(bounds);
        var layer = this._map.createLayer('feature', {renderer: 'vgl'});
        var quad = layer.createFeature('quad');
        quad.data([
            {
                ll: {x: bounds.left || 0, y: -bounds.bottom},
                ur: {x: bounds.right, y: bounds.top || 0},
                image: url
            }
        ]);
        this._layers.push(layer);
        this._map.draw();
        return quad;
    },

    removeItem: function () {
        this.resetAnnotations();
        this._annotationList.render().$el.addClass('hidden');
        if (this._map) {
            this._map.exit();
            this._map = null;
            this.$('.h-visualization-body').empty();
        }
    },

    /**
     * Add a tiled image as a tileLayer on the view from an options object.
     * The options object takes options supported by geojs's tileLayer:
     *
     *   https://github.com/OpenGeoscience/geojs/blob/master/src/tileLayer.js
     *
     * @param {object} opts Tile layer required options
     * @param {string|function} opts.url
     */
    addTileLayer: function (opts) {
        var layer;
        if (!_.has(opts, 'url')) {
            throw new Error('`url` parameter required.');
        }

        _.defaults(opts, {
            useCredentials: true,
            maxLevel: 10,
            wrapX: false,
            wrapY: false,
            tileOffset: function () {
                return {x: 0, y: 0};
            },
            attribution: '',
            tileWidth: 256,
            tileHeight: 256,
            tileRounding: Math.ceil,
            tilesAtZoom: function (level) {
                var scale = Math.pow(2, opts.maxLevel - level);
                return {
                    x: Math.ceil(opts.sizeX / opts.tileWidth / scale),
                    y: Math.ceil(opts.sizeY / opts.tileHeight / scale)
                };
            },
            tilesMaxBounds: function (level) {
                var scale = Math.pow(2, opts.maxLevel - level);
                return {
                    x: Math.floor(opts.sizeX / scale),
                    y: Math.floor(opts.sizeY / scale)
                };
            }
        });

        // estimate the global bounds if not provided
        if (!opts.sizeX) {
            opts.sizeX = Math.pow(2, opts.maxLevel) * opts.tileWidth;
        }
        if (!opts.sizeY) {
            opts.sizeY = Math.pow(2, opts.maxLevel) * opts.tileHeight;
        }

        this._createMap({
            right: opts.sizeX,
            bottom: opts.sizeY
        });
        layer = this._map.createLayer('osm', opts);
        this._unitsPerPixel = this._map.unitsPerPixel(opts.maxLevel - 1);
        this._layers.push(layer);
        this._map.draw();
        return layer;
    },

    addAnnotationLayer: function (annotation) {
        var el = d3.select(this.el)
                .select('.h-annotation-layers')
                .append('svg')
                .node();

        this._onResize();
        var settings = $.extend({
            el: el,
            viewport: this.viewport
        }, annotation.annotation);

        this._annotations[annotation._id] = new girder.annotation.Annotation(settings).render();
        return this;
    },

    removeAnnotationLayer: function (id) {
        if (_.has(this._annotations, id)) {
            this._annotations[id].remove();
            delete this._annotations[id];
        }
        return this;
    },

    resetAnnotations: function () {
        _.each(_.keys(this._annotations), _.bind(this.removeAnnotationLayer, this));
        return this;
    },

    render: function () {

        this.$el.html(histomicstk.templates.visualization());
        return this;
    },

    destroy: function () {
        $(window).off('resize', this._onResize);
        this._map.exit();
        this.$el.empty();
        this._controlModel.destroy();
        girder.View.prototype.destroy.apply(this, arguments);
    },

    /**
     * Resize the viewport according to the size of the container.
     */
    _onResize: function () {
        var width = this.$el.width() || 100;
        var height = this.$el.height() || 100;
        var layers = this.$('.h-annotation-layers > svg');

        this.viewport.set({
            width: width,
            height: height
        });
        layers.attr('width', width);
        layers.attr('height', height);
        this._syncViewport();
    },

    /**
     * Respond to fast firing mouse navigation events by applying transforms
     * to the svg element so we can debounce the slow rerenders.
     */
    _onMouseNavigate: function () {
        var ul, dz;
        if (!this._lastCorner) {
            // do a full rerender if we haven't synced the viewport yet
            this._syncViewport();
            return;
        }

        ul = this._map.gcsToDisplay({
            x: this._lastCorner.x,
            y: this._lastCorner.y
        });

        dz = Math.pow(2, this._map.zoom() - this._lastZoom);

        this.$('.h-annotation-layers')
            .css(
                'transform',
                'translate(' + ul.x + 'px,' + ul.y + 'px)scale(' + dz + ')'
            );

        // schedule a debounced rerender
        this._debouncedRender();

        // Update the bounds in the query string
        var bounds = this._map.bounds(undefined, null);
        histomicstk.router.setQuery(
            'bounds',
            [
                this._formatNumber(bounds.left),
                this._formatNumber(-bounds.top),
                this._formatNumber(bounds.right),
                this._formatNumber(-bounds.bottom),
                this._formatNumber(this._map.rotation() * 180 / Math.PI)
            ].join(','),
            {
                replace: true,
                trigger: false
            }
        );
    },

    _formatNumber: function (num) {
        return (Math.round(num * 100) / 100).toString()
    },

    _syncViewport: function () {
        var bds;
        if (!this._map) {
            return;
        }

        this.$('.h-annotation-layers')
            .css('transform', '');

        bds = this._map.bounds(undefined, null);
        this._lastCorner = this._map.displayToGcs({
            x: 0,
            y: 0
        });
        this._lastZoom = this._map.zoom();

        this.viewport.set({
            scale: (bds.right - bds.left) / (this.viewport.get('width') * this._unitsPerPixel)
        });
        this.viewport.set({
            top: -bds.top / this._unitsPerPixel,
            left: bds.left / this._unitsPerPixel
        });
    },

    _toggleAnnotation: function (model) {
        if (model.get('displayed') && !_.has(this._annotations, model.id)) {
            girder.restRequest({
                path: 'annotation/' + model.id
            }).then(_.bind(this.addAnnotationLayer, this));
        } else if (!model.get('displayed') && _.has(this._annotations, model.id)) {
            this.removeAnnotationLayer(model.id);
        }
    }
});

histomicstk.dialogs.image = new histomicstk.views.ItemSelectorWidget({
    parentView: null,
    model: new histomicstk.models.Widget({
        type: 'file'
    })
});
<|endoftext|>


<commit_before>/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow

 Press Cmd+R to reload,{'\n'}
 Cmd+D or shake for dev menu
 */

import React, { Component, PropTypes } from 'react';
import {
  AppRegistry,
  StyleSheet,
  NavigatorIOS,
  Platform,
  Switch,
  Text,
  TextInput,
  ScrollView,
  View,
  PROVIDER_GOOGLE,
  PROVIDER_DEFAULT,
  MapView,
  Image,
  TouchableOpacity
} from 'react-native';

import axios from 'axios';

export default class WhereInTheWorldiOS extends Component {
  constructor(props) {
    super(props);
    this.checkIn = this.checkIn.bind(this)
    this.getLocationData = this.getLocationData.bind(this)
    this.changeView = this.changeView.bind(this)
    this.state = {
      loggedIn: true,
      username: '',
      view: 'home',
      lastPosition: {},
      placeData: []
      }

  }

  watchID: ?number = null;

  //get all the places feed
  componentDidMount() {
    this.getLocationData()
  }

  getLocationData(){
      console.log("this is hitting")
      var state = this.state;
      var self  = this;
      axios.get('http://localhost:9393/place')
      .then(function(response){
        state.placeData =response.data;
        self.setState(state)
      })

  //     navigator.geolocation.getCurrentPosition(
  //       (position) => {
  //         var initialPosition = JSON.stringify(position);
  //         this.setState({initialPosition});
  //       },
  //       (error) => alert(JSON.stringify(error)),
  //       {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
  //       );

  //       state = self.state

  //       this.watchID = navigator.geolocation.watchPosition((position) => {
  //       state.lastPosition.latitude = position.coords.latitude;
  //       state.lastPosition.longitude = position.coords.longitude;
  //       this.setState(state);
  //       console.log(state, "geooo")

  //   });

  }
  componentWillUnmount() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  //post the lat and long
  checkIn() {

      var state = this.state;
      var self  = this;

        axios.post('http://localhost:9393/place', {
          latitude: self.state.lastPosition.latitude ,
          longitude: self.state.lastPosition.longitude
        })
        .then(function (response) {
          console.log(response, "POST RESPONSE");
          self.getLocationData();
        })
        .catch(function (error) {
          console.log(error,"errrrrrrrr");
        })
    }

    changeView = (component) =>{

      var state = this.state
      state.view = 'map'
      this.setState(state);
    }

    renderView(component) {
            var self = this;
            console.log(this.state)
            if(component == 'home') {
            return <HomeFeed changeView={this.changeView} placeData={self.state.placeData} checkIn={self.checkIn}/>
          } else if(component == 'map') {
            return <Map changeView={this.changeView} placeData={self.state.placeData}/>
          }
      }

  render() {

    return (
      <View style={styles.container}>
        {this.renderView(this.state.view)}
      </View>
    );
  }
}

/**
*HOME COMPONENT
*        <Map placeData={self.state.placeData} />
*        <HomeFeed placeData={self.state.placeData} checkIn={self.checkIn} />
*/
class HomeFeed extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    console.log(this.props.placeData, "home")
    var placeInfo = this.props.placeData.map((place, i) =>{
      return <View key={i}><Text style={styles.placeText}>{place.user_id}: {place.time} {"\n"} {place.latitude} {place.longitude}</Text></View>
    })

    return(
      <View >
        <TouchableOpacity onPress={this.props.checkIn} activeOpacity={.5}>
            <View style={styles.button}>
              <Text style={styles.buttonText}>Yo Check In</Text>
            </View>
        </TouchableOpacity>
        <TouchableOpacity onPress={() => this.props.changeView('map') } activeOpacity={.5}>
                <View style={styles.button}>
              <Text style={styles.buttonText}>MAP YO</Text>
            </View>
        </TouchableOpacity>
          <ScrollView
            scrollEventThrottle={200}
            automaticallyAdjustContentInsets={false}
            bounces={true}>
            <View style={styles.places}>
              {placeInfo.reverse()}
            </View>
          </ScrollView>
      </View>
      )
  }
}

/**
*MAP COMPONENT
*< <TouchableOpacity activeOpacity={.5}>
            <View style={styles.button}>
              <Text style={styles.buttonText}>map map map</Text>
            </View>
        </TouchableOpacity>

    console.log(nextProps, ' nextProps')

*/
class Map extends Component {
  constructor(props) {
    super(props);
    this.state = {
      markers: []
    }
    this.createMarkers()
  }

  createMarkers() {
    this.props.placeData.map((place, i) =>{

      if(isNaN(parseInt(place.latitude)) === false ||  isNaN(parseInt(place.longitude)) === false){
            var obj = {};
            obj.latitude = parseInt(place.latitude)
            obj.longitude = parseInt(place.longitude)
            obj.title = place.time
            this.state.markers.push(obj)
            console.log(obj);
      }
    })
  }

  componentWillReceiveProps(nextProps) {

  }
  render() {
debugger
    return (
      <MapView
        style={styles.map}
        showsUserLocation={true}
        annotations={this.state.markers}
        >

        </MapView>
    );
  }
}

/**
*SIGN IN COMPONENT
*/
class SignIn extends Component{
  constructor(props) {
    super(props);
    this.state = { usernameValue: '', passwordValue: '' }
  }

  render(){
    return(
      <View style={styles.container}>
      <View style={styles.container} />
        <View style={styles.wrapper}>
          <View style={styles.inputWrap}>
            <TextInput
              placeholder="Username"
              style={styles.input}
            />
          </View>
          <View style={styles.inputWrap}>
            <TextInput
              placeholder="Password"
              secureTextEntry
              style={styles.input}
            />
          </View>
          <TouchableOpacity activeOpacity={.5}>
            <View style={styles.button}>
              <Text style={styles.buttonText}>Sign In</Text>
            </View>
          </TouchableOpacity>
           <TouchableOpacity activeOpacity={.5}>
            <View>
              <Text style={styles.registerText}>Create Account</Text>
            </View>
          </TouchableOpacity>
        </View>
        <View style={styles.container} />
        </View>
      );
  }
}

/**
*SIGN UP COMPONENT
*/
class SignUp extends Component{
  constructor(props) {
    super(props);
    this.state = { usernameValue: '', passwordValue: '' }
  }

  render(){
    return(
      <View style={styles.container}>
      <View style={styles.container} />
        <View style={styles.wrapper}>
          <View style={styles.inputWrap}>
            <TextInput
              placeholder="Username"
              style={styles.input}
            />
          </View>
          <View style={styles.inputWrap}>
            <TextInput
              placeholder="Password"
              secureTextEntry
              style={styles.input}
            />
          </View>
          <TouchableOpacity activeOpacity={.5}>
            <View style={styles.button}>
              <Text style={styles.buttonText}>Sign Up</Text>
            </View>
          </TouchableOpacity>
           <TouchableOpacity activeOpacity={.5}>
            <View>
              <Text style={styles.registerText}>Already have an account?</Text>
            </View>
          </TouchableOpacity>
        </View>
        <View style={styles.container} />
        </View>
      );
  }
}

/**
*STYLES
*/
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#a9a9a9'
  },

  background: {
    width: null,
    height: null
  },

  map: {
    ...StyleSheet.absoluteFillObject,
  },

  wrapper: {
    paddingHorizontal: 15
  },

  inputWrap: {
    flexDirection: "row",
    marginVertical: 10,
    height: 40,
    backgroundColor: "transparent"
  },

  input: {
    flex: 1,
    paddingHorizontal: 10,
    backgroundColor: '#FFF'
  },

  button: {
    backgroundColor: '#1e90ff',
    paddingVertical: 15,
    paddingHorizontal: 15,
    marginVertical: 15,
    alignItems: "center",
    justifyContent: "center"
  },

  buttonText: {
    fontSize: 18
  },

  places: {
    paddingVertical: 15,
    marginVertical: 15,
  },

  placeText: {
    color: '#FFF',
    textAlign: "center",
    fontSize: 20
  },

  registerText: {
    color: '#FFF',
    backgroundColor: "transparent",
    textAlign: "center"
  }
});

AppRegistry.registerComponent('WhereInTheWorldiOS', () => WhereInTheWorldiOS);
<commit_msg>every work<commit_after>/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow

 Press Cmd+R to reload,{'\n'}
 Cmd+D or shake for dev menu
 */

import React, { Component, PropTypes } from 'react';
import {
  AppRegistry,
  StyleSheet,
  NavigatorIOS,
  Platform,
  Switch,
  Text,
  TextInput,
  ScrollView,
  View,
  PROVIDER_GOOGLE,
  PROVIDER_DEFAULT,
  MapView,
  Image,
  TouchableOpacity
} from 'react-native';

import axios from 'axios';

export default class WhereInTheWorldiOS extends Component {
  constructor(props) {
    super(props);
    this.checkIn = this.checkIn.bind(this)
    // this.getLocationData = this.getLocationData.bind(this)
    this.changeView = this.changeView.bind(this)
    this.state = {
      loggedIn: true,
      username: '',
      view: 'home',
      lastPosition: {},
      placeData: [],
      inc: 0
      }

  }

  watchID: ?number = null;

  //get all the places feed
  componentDidMount() {
  //   this.getLocationData()
  // }

  // getLocationData(){
      console.log("this is hitting")
        var self  = this;
      axios.get('http://localhost:9393/place')
      .then(function(response){
         var state = self.state;
        console.log(state, ' state in cb')
        state.placeData =response.data;
        self.setState(state)
      })

      navigator.geolocation.getCurrentPosition(
        (position) => {
          var initialPosition = JSON.stringify(position);

          // this.setState({initialPosition});
        },
        (error) => alert(JSON.stringify(error)),
        {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
        );

        this.watchID = navigator.geolocation.watchPosition((position) => {

        var state = this.state;
        console.log(state, ' compo did mount')
        state.lastPosition.latitude = position.coords.latitude;
        state.lastPosition.longitude = position.coords.longitude;
        this.setState(state);
        // console.log(state, "geooo")

    });

  }
  componentWillUnmount() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  //post the lat and long
  checkIn() {

      var state = this.state;
      var self  = this;

        axios.post('http://localhost:9393/place', {
          latitude: self.state.lastPosition.latitude ,
          longitude: self.state.lastPosition.longitude
        })
        .then(function (response) {
          console.log(response, "POST RESPONSE");
          self.getLocationData();
        })
        .catch(function (error) {
          console.log(error,"errrrrrrrr");
        })
    }

    changeView() {

      var state = this.state
      state.inc = state.inc + 1
      state.view = 'map'
      this.setState(state);
    }

    renderView(component) {
            console.log(component, ' this is componetn')
            var self = this;
            console.log(this.state, ' thi is state in render')
            if(component == 'home') {
            return <HomeFeed changeView={this.changeView} placeData={this.state.placeData} checkIn={self.checkIn}/>
          } else if(component == 'map') {
            return <Map  placeData={self.state.placeData}/>
          }
      }

  render() {

    console.log(' render home component being called', this.state)
    return (
      <View style={styles.container}>
        {this.renderView(this.state.view)}
      </View>
    );
  }
}

/**
*HOME COMPONENT
*        <Map placeData={self.state.placeData} />
*        <HomeFeed placeData={self.state.placeData} checkIn={self.checkIn} />
*/
class HomeFeed extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    console.log(this.props.placeData, "home")
    var placeInfo = this.props.placeData.map((place, i) =>{
      return <View key={i}><Text style={styles.placeText}>{place.user_id}: {place.time} {"\n"} {place.latitude} {place.longitude}</Text></View>
    })

    return(
      <View >
        <TouchableOpacity onPress={this.props.checkIn} activeOpacity={.5}>
            <View style={styles.button}>
              <Text style={styles.buttonText}>Yo Check In</Text>
            </View>
        </TouchableOpacity>
        <TouchableOpacity onPress={() => this.props.changeView('map') } activeOpacity={.5}>
                <View style={styles.button}>
                   <Text style={styles.buttonText}>MAP YO</Text>
                </View>
        </TouchableOpacity>
          <ScrollView
            scrollEventThrottle={200}
            automaticallyAdjustContentInsets={false}
            bounces={true}>
            <View style={styles.places}>
              {placeInfo.reverse()}
            </View>
          </ScrollView>
      </View>
      )
  }
}

/**
*MAP COMPONENT
*
*/
class Map extends Component {
  constructor(props) {
    super(props);
    this.state = {
      markers: []
    }
    this.createMarkers()
  }

  createMarkers() {

    this.props.placeData.map((place, i) =>{

      if(isNaN(parseInt(place.latitude)) === false ||  isNaN(parseInt(place.longitude)) === false){
            var obj = {};
            obj.latitude = parseInt(place.latitude)
            obj.longitude = parseInt(place.longitude)
            obj.title = place.time
            this.state.markers.push(obj)
            console.log(obj);
      }
    })
  }

  render() {
    return (

      <MapView
        style={styles.map}
        showsUserLocation={true}
        annotations={this.state.markers}
        >

        </MapView>
    );
  }
}

/**
*SIGN IN COMPONENT
*/
class SignIn extends Component{
  constructor(props) {
    super(props);
    this.state = { usernameValue: '', passwordValue: '' }
  }

  render(){
    return(
      <View style={styles.container}>
      <View style={styles.container} />
        <View style={styles.wrapper}>
          <View style={styles.inputWrap}>
            <TextInput
              placeholder="Username"
              style={styles.input}
            />
          </View>
          <View style={styles.inputWrap}>
            <TextInput
              placeholder="Password"
              secureTextEntry
              style={styles.input}
            />
          </View>
          <TouchableOpacity activeOpacity={.5}>
            <View style={styles.button}>
              <Text style={styles.buttonText}>Sign In</Text>
            </View>
          </TouchableOpacity>
           <TouchableOpacity activeOpacity={.5}>
            <View>
              <Text style={styles.registerText}>Create Account</Text>
            </View>
          </TouchableOpacity>
        </View>
        <View style={styles.container} />
        </View>
      );
  }
}

/**
*SIGN UP COMPONENT
*/
class SignUp extends Component{
  constructor(props) {
    super(props);
    this.state = { usernameValue: '', passwordValue: '' }
  }

  render(){
    return(
      <View style={styles.container}>
      <View style={styles.container} />
        <View style={styles.wrapper}>
          <View style={styles.inputWrap}>
            <TextInput
              placeholder="Username"
              style={styles.input}
            />
          </View>
          <View style={styles.inputWrap}>
            <TextInput
              placeholder="Password"
              secureTextEntry
              style={styles.input}
            />
          </View>
          <TouchableOpacity activeOpacity={.5}>
            <View style={styles.button}>
              <Text style={styles.buttonText}>Sign Up</Text>
            </View>
          </TouchableOpacity>
           <TouchableOpacity activeOpacity={.5}>
            <View>
              <Text style={styles.registerText}>Already have an account?</Text>
            </View>
          </TouchableOpacity>
        </View>
        <View style={styles.container} />
        </View>
      );
  }
}

/**
*STYLES
*/
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#a9a9a9'
  },

  background: {
    width: null,
    height: null
  },

  map: {
    ...StyleSheet.absoluteFillObject,
  },

  wrapper: {
    paddingHorizontal: 15
  },

  inputWrap: {
    flexDirection: "row",
    marginVertical: 10,
    height: 40,
    backgroundColor: "transparent"
  },

  input: {
    flex: 1,
    paddingHorizontal: 10,
    backgroundColor: '#FFF'
  },

  button: {
    backgroundColor: '#1e90ff',
    paddingVertical: 15,
    paddingHorizontal: 15,
    marginVertical: 15,
    alignItems: "center",
    justifyContent: "center"
  },

  buttonText: {
    fontSize: 18
  },

  places: {
    paddingVertical: 15,
    marginVertical: 15,
  },

  placeText: {
    color: '#FFF',
    textAlign: "center",
    fontSize: 20
  },

  registerText: {
    color: '#FFF',
    backgroundColor: "transparent",
    textAlign: "center"
  }
});

AppRegistry.registerComponent('WhereInTheWorldiOS', () => WhereInTheWorldiOS);
<|endoftext|>


<commit_before>/* Copyright 2019 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// TODO(applmak): Make this work.

const register = require('register');
const ModuleInterface = require('lib/module_interface');

// TODO(applmak): Take care of this lint error for real.
/*jshint loopfunc: true */
const Rectangle = require('lib/rectangle');
const Noise = require('noisejs');
const assert = require('lib/assert');
const wallGeometry = require('wallGeometry');
const debug = require('debug');
const network = require('network');

var MAX_PARTICLES_PER_CLIENT = 100;

class ParticlesServer extends ModuleInterface.Server {
  makeParticle(time) {
    var x = Math.random() * wallGeometry.extents.w;
    var y = Math.random() * wallGeometry.extents.h;
    var winteryColors = [
      {r: 254, g: 254, b: 254, a: 254},
      {r: 40, g: 150, b: 254, a: 254},
      {r: 0, g: 30, b: 127, a: 254},
      {r: 150, g: 254, b: 254, a: 254},
    ];
    var chosenColor = _.sample(winteryColors);
    var newParticle = {
      eventualColor: chosenColor,
      x: x,
      y: y,
      vx: 300 * (Math.random()-0.5),
      vy: 300 * (Math.random()-0.5),
      r: 254,
      g: 254,
      b: 254,
      a: 0,
      s: 15,
      t0: time,
      l: 20000
    };
    return newParticle;
  }
  tick(time, delta) {
    for (var c = 0; c < 10; ++c) {
      var newParticle = this.makeParticle(time);
      var r = Rectangle.centeredAt(newParticle.x, newParticle.y, 0, 0);
      network.getClientsInRect(r).forEach((client) => {
        client.socket.emit('newParticle', newParticle);
      });
    }
  }
}

function swap(arr, a, b) {
  var i = arr[a];
  arr[a] = arr[b];
  arr[b] = i;
}

function lerp(alpha, a, b) {
  return alpha * b + (1-alpha) * a;
}

function linear(x, x1, x2, y1, y2) {
  return x <= x1 ? y1 :
         x >= x2 ? y2 :
         lerp((x - x1)/(x2 - x1), y1, y2);
}

class ParticleEmitter {
  constructor() {
    // Big block of CPU-particle data. We need:
    // 2 floats for (x,y) position
    // 2 floats for (vx,vy) velocity
    // 1 uint32 for (r,g,b,a) color
    // 1 float for (s) scalar size.
    // 1 float for (t0) scalar start time
    // 1 float for (l) scalar lifetime
    // We choose to pack this for GPU-efficiency & reduced overhead from
    // the Buffer object:
    // 4 floats for (x,y,vx,vy) position/velocity
    // 4 floats for (rgba, s, t0, l)
    // We expect this to increase our vertex buffer throughput, as we'll use
    // fewer temporary registers (this is always the goal with particles). This
    // will, however, require us to manually encode our uint32 as a float, and
    // then back. Encoding into a float is surprisingly easy in JS, and
    // incredibly performant. However, the GPU case requires a big ol' copy
    // and paste from an authoritive source.
    var posVel = new Float32Array(MAX_PARTICLES_PER_CLIENT * 4);
    var misc = new Float32Array(MAX_PARTICLES_PER_CLIENT * 4);

    // While we are here, also allocate memory in the GPU for these.
    var posVelBuffer = new Three.BufferAttribute(posVel, 4).setDynamic(true);
    var miscBuffer = new Three.BufferAttribute(misc, 4).setDynamic(true);

    this.geometry = new Three.BufferGeometry();
    this.geometry.setDrawRange(0, 0);
    this.geometry.addAttribute('posVel', posVelBuffer);
    this.geometry.addAttribute('misc', miscBuffer);

    // Store the Three versions of those attribute buffers for later mutation.
    this.posVelBuffer_ = this.geometry.getAttribute('posVel');
    this.miscBuffer_ = this.geometry.getAttribute('misc');

    // Provide an aliased buffer over the misc buffer so we can address the
    // color field.
    this.color_ = new Uint8Array(this.miscBuffer_.array.buffer);

    // We don't always have a fixed number of active particles. We'll use an
    // index buffer to mention the particles we want to change.
    var indices = new Uint16Array(MAX_PARTICLES_PER_CLIENT);
    this.geometry.setIndex(new Three.BufferAttribute(indices, 1).setDynamic(true));
    this.indexBuffer_ = this.geometry.getIndex();
    // We'll fill out the index buffer with our reset index -1, indicating that
    // we have no particle here just as of yet.
    for (var i = 0; i < MAX_PARTICLES_PER_CLIENT; ++i) {
      this.indexBuffer_.array[i] = -1;
    }

    // Because we want to avoid looking through the indexBuffer for particles
    // that are available, we'll track this via a pool of unused indices.
    // Initially, all particles are dead.
    this.deadParticles_ = Array.from({length: MAX_PARTICLES_PER_CLIENT}).map((_, index) => index);

    // We'll also track where each index is in the index buffer. Whew!
    this.indexIndexes_ = Array.from({length: MAX_PARTICLES_PER_CLIENT}).map((_) => -1);
  }

  // Adds a particle to the emitter. All initial values must be well-specified.
  // If there are no particles, returns -1. No data is flushed to the GPU.
  addParticle(x, y, vx, vy, r, g, b, a, s, t0, l) {
    if (this.deadParticles_.length === 0) {
      // Can't handle any more particles!
      return -1;
    }

    // What is the index of our new particle?
    var index = this.deadParticles_.pop();

    // Assign the values into the buffers:
    // Enable this particle in the index buffer. We calculate the next available
    // index by remembering that MAX_PARTICLES_PER_CLIENT = dead + live, and
    // solving for live (with the +1 due to the pop).
    this.indexIndexes_[index] = this.numLiveParticles() - 1;
    this.indexBuffer_.array[this.numLiveParticles() - 1] = index;
    // Add position and velocity. Stride is 4 here, because there are 4 floats.
    this.posVelBuffer_.array[4 * index + 0] = x;
    this.posVelBuffer_.array[4 * index + 1] = y;
    this.posVelBuffer_.array[4 * index + 2] = vx;
    this.posVelBuffer_.array[4 * index + 3] = vy;
    // Add color, size, start time, lifetime. Stride is 4 here, too.
    this.color_[4*(4 * index + 0) + 0] = a;
    this.color_[4*(4 * index + 0) + 1] = b;
    this.color_[4*(4 * index + 0) + 2] = g;
    this.color_[4*(4 * index + 0) + 3] = r;

    this.miscBuffer_.array[4 * index + 1] = s;
    this.miscBuffer_.array[4 * index + 2] = t0;
    this.miscBuffer_.array[4 * index + 3] = l;

    this.indexBuffer_.needsUpdate = true;
    this.posVelBuffer_.needsUpdate = true;
    this.miscBuffer_.needsUpdate = true;

    // Update the indices we will draw:
    this.geometry.setDrawRange(0, this.numLiveParticles());

    // All done!
    return index;
  }

  numLiveParticles() {
    return MAX_PARTICLES_PER_CLIENT - this.deadParticles_.length;
  }

  removeParticle(index) {
    var lastParticleIndex = this.numLiveParticles() - 1;

    // Add a hole in the index buffer, because this index is invalid.
    this.indexBuffer_.array[this.indexIndexes_[index]] = -1;
    // But also, don't leave it there!
    var swappedLiveParticleIndex = this.indexBuffer_.array[lastParticleIndex];
    swap(this.indexBuffer_.array, this.indexIndexes_[index], lastParticleIndex);
    // Update our reverse index map, too:
    this.indexIndexes_[swappedLiveParticleIndex] = this.indexIndexes_[index];
    this.indexIndexes_[index] = -1;

    this.deadParticles_.push(index);
    this.indexBuffer_.needsUpdate = true;

    this.geometry.setDrawRange(0, this.numLiveParticles());
  }

  updateParticle(cb, index, opt_obj) {
    var particle = opt_obj || {x:0, y:0, vx:0, vy:0, r:0, g:0, b:0, a:0, s:0, t0:0, l:0};

    // copy to object
    particle.x = this.posVelBuffer_.array[4 * index + 0];
    particle.y = this.posVelBuffer_.array[4 * index + 1];
    particle.vx = this.posVelBuffer_.array[4 * index + 2];
    particle.vy = this.posVelBuffer_.array[4 * index + 3];

    particle.a = this.color_[4*(4 * index + 0) + 0];
    particle.b = this.color_[4*(4 * index + 0) + 1];
    particle.g = this.color_[4*(4 * index + 0) + 2];
    particle.r = this.color_[4*(4 * index + 0) + 3];

    particle.s = this.miscBuffer_.array[4 * index + 1];
    particle.t0 = this.miscBuffer_.array[4 * index + 2];
    particle.l = this.miscBuffer_.array[4 * index + 3];

    cb(particle, index);

    // copy back to buffer.
    this.posVelBuffer_.array[4 * index + 0] = particle.x;
    this.posVelBuffer_.array[4 * index + 1] = particle.y;
    this.posVelBuffer_.array[4 * index + 2] = particle.vx;
    this.posVelBuffer_.array[4 * index + 3] = particle.vy;

    this.color_[4*(4 * index + 0) + 0] = Math.floor(particle.a);
    this.color_[4*(4 * index + 0) + 1] = Math.floor(particle.b);
    this.color_[4*(4 * index + 0) + 2] = Math.floor(particle.g);
    this.color_[4*(4 * index + 0) + 3] = Math.floor(particle.r);

    this.miscBuffer_.array[4 * index + 1] = particle.s;
    this.miscBuffer_.array[4 * index + 2] = particle.t0;
    this.miscBuffer_.array[4 * index + 3] = particle.l;
  }

  markBuffersDirty() {
    this.posVelBuffer_.needsUpdate = true;
    this.miscBuffer_.needsUpdate = true;
  }

  // Updates particle state by calling cb with decoded data for each particle.
  // Remove & add are safe to call during this method.
  updateParticles(cb) {
    var N = this.numLiveParticles();
    var particle = {
      x:0, y:0, vx:0, vy:0, r:0, g:0, b:0, a:0, s:0, t0:0, l:0
    };
    for (var i = 0; i < N; ++i) {
      var index = this.indexBuffer_.array[i];
      this.updateParticle(cb, index, particle);
    }

    this.markBuffersDirty();
  }
  // Expensive sanity checks:
  sanityChecks() {
    // First, check that our reverse index map and index map agree.
    this.indexIndexes_.forEach((reverseIndex, index) => {
      if (reverseIndex !== -1) {
        assert(this.indexBuffer_.array[reverseIndex] === index,
            'Bad index found!', index, reverseIndex, this.indexBuffer_.array[reverseIndex]);
      }
    });

    // Next, check that each particle at every valid index has a + lifetime.
    for (var i = 0; i < this.numLiveParticles(); ++i) {
      var index = this.indexBuffer_.array[i];
      assert(this.miscBuffer_.array[4 * index + 3] > 0, 'Bad lifetime!');
    }
  }
}

class ParticlesClient extends ModuleInterface.Client {
  willBeShownSoon(container, deadline) {
    const Three = require('three-full');
    this.noise = new Noise(deadline % 1);
    const ThreeJsSurface = require('client/surface/threejs_surface');
    this.surface = new ThreeJsSurface(container, wallGeometry);
    const CanvasSurface = require('client/surface/canvas_surface');
    this.debugCanvas = new CanvasSurface(container, wallGeometry);
    this.debugCanvas.canvas.addEventListener('click', (e) => {
      this.persistence_.addData({
        x: 100,
        y: this.surface.virtualRect.h/2,
        vx: 100,
        vy: 0,
        r: 254,
        g: 254,
        b: 254,
        a: 254,
        s: 10,
        t0: 0,
        l: 1000000
      });
    });
    this.debugCanvas.canvas.style.zIndex = '1000';
    this.peer_ = null;
    this.emitter = new ParticleEmitter();

    var mat = new Three.ShaderMaterial({
      transparent: true,
      depthWrite: false,
      uniforms: {},
      blending: Three.AdditiveBlending,
      vertexShader: `
        precision highp float;
        #define FLOAT_MAX  1.70141184e38
        #define FLOAT_MIN  1.17549435e-38
        lowp vec4 decodeFloat(highp float v) {
          highp float av = abs(v);
          if (av < FLOAT_MIN) {
            return vec4(0.0, 0.0, 0.0, 0.0);
          } else if (v > FLOAT_MAX) {
            return vec4(127.0, 128.0, 0.0, 0.0) / 255.0;
          } else if (v < -FLOAT_MAX) {
            return vec4(255.0, 128.0, 0.0, 0.0) / 255.0;
          }
          highp vec4 c = vec4(0.0, 0.0, 0.0, 0.0);

          // Exponent & mantissa:
          highp float e = floor(log2(av));
          highp float m = av * pow(2.0, -e) - 1.0;

          // Unpack mantissa:
          c[1] = floor(128.0 * m);
          m -= c[1] / 128.0;
          c[2] = floor(32768.0 * m);
          m -= c[2] / 32768.0;
          c[3] = floor(8388608.0 * m);

          // Unpack exponent:
          highp float ebias = e + 127.0;
          c[0] = floor(ebias / 2.0);
          ebias -= c[0] * 2.0;
          c[1] += floor(ebias) * 128.0;

          // Unpack sign:
          c[0] += 128.0 * step(0.0, -v);

          // Scale to [0,1]:
          return c / 255.0;
        }

        attribute vec4 posVel;
        attribute vec4 misc;

        varying vec4 vColor;

        void main() {
          // We store color in x as a uint32_t
          vColor = decodeFloat(misc.x);
          // Point size is in y.
          gl_PointSize = misc.y;
          gl_Position = projectionMatrix * modelViewMatrix * vec4(posVel.xy, 0.0, 1.0);
        }
      `,
      fragmentShader: `
        varying vec4 vColor;

        void main() {
          gl_FragColor = vColor;
        }
      `
    });

    this.points = new Three.Points(this.emitter.geometry, mat);
    this.points.frustumCulled = false;
    this.surface.scene.add(this.points);

    this.surface.camera = new Three.OrthographicCamera(
        this.surface.virtualRect.x, this.surface.virtualRect.x+this.surface.virtualRect.w,
        this.surface.virtualRect.y, this.surface.virtualRect.y+this.surface.virtualRect.h,
        -1, 1);
    this.surface.camera.updateProjectionMatrix();

    this.idToIndex_ = {};
    return peerNetwork.open(deadline).then((peer) => {
      debug('Connected to peer network.');
      this.peer_ = peer;
      const NeighborPersistence = require('client/network/neighbor_persistence');
      this.persistence_ = new NeighborPersistence(this.surface.virtualRectNoBezel, peer);
      network.on('newParticle', (newParticle) => {
        // When the server sends us something, it's definitely relevant.
        this.persistence_.addData(newParticle);
      });
    });
  }
  finishFadeOut() {
    if (this.surface) {
      this.surface.destroy();
    }
    if (this.peer_) {
      this.peer_.close();
      this.peer_ = null;
    }
  }
  draw(time, delta) {
    if (delta < 0) {
      return;
    }
    this.persistence_.update((data) => {
      assert(!(data._id in this.idToIndex_), 'Id ' + data._id + ' already in index map!');
      // New data should be added to the emitter.
      var index = this.emitter.addParticle(
        data.x, data.y, data.vx, data.vy,
        data.r, data.g, data.b, data.a,
        data.s, data.t0, data.l
      );
      if (index == -1) {
        // Our emitter is full! Just drop this particle.
        debug('Emitter is full!', data._id);
        return false;
      }

      // Remember this data in our particle map.
      this.idToIndex_[data._id] = index;
      return true;
    }, (data) => {
      // Shared data
      assert(data._id in this.idToIndex_, 'Updating a shared particle ' + data._id + ' that isn\'t in the index map!');
      var index = this.idToIndex_[data._id];
      this.emitter.updateParticle((p) => {
        // In this case, we want to copy data to p. We copy _ fields, too, but
        // no big deal, the emitter ignores them.
        _.extend(p, data);
      }, index);

      return data.l >= 0;
    }, (data) => {
      assert(data._id in this.idToIndex_, 'Updating an owned particle ' + data._id + ' that isn\'t in the index map!');
      // We should move this particle, because we are the authority of it!
      var age = time - data.t0;
      // The wind walks a slow circle around 0,0
      var windSampleX = Math.cos(2*Math.PI * time / 100000);
      var windSampleY = Math.sin(2*Math.PI * time / 100000);
      var windX = 10000*this.noise.perlin3(windSampleX, windSampleY, 0.1);
      var windY = 10000*this.noise.perlin3(windSampleX, windSampleY, 0.6);

      var m = data.s + 0.1;
      var Fx = windX;
      var Fy = windY + 200;

      // Add perturbation:
      Fx += 10000*this.noise.perlin3(data.x, data.y, 0.13);
      Fy += 10000*this.noise.perlin3(data.x, data.y, 0.47);

      var ax = Fx / m;
      var ay = Fy / m;

      data.vx += ax * delta/1000;
      data.vy += ay * delta/1000;
      data.x += data.vx * delta/1000;
      data.y += data.vy * delta/1000;
      data.r = linear(age, 1000, 2000, 254, data.eventualColor.r);
      data.g = linear(age, 1000, 2000, 254, data.eventualColor.g);
      data.b = linear(age, 1000, 2000, 254, data.eventualColor.b);
      if (age > 1000) {
        data.a = linear(age, 1000, age+data.l, 254, 0);
      } else {
        data.a = linear(age, 0, 1000, 0, 254);
      }
      data.s = linear(age, 0, age+data.l, 20, 0.1);
      data.l -= delta;

      var index = this.idToIndex_[data._id];
      this.emitter.updateParticle((p) => {
        // We copy over p with the new data.
        _.extend(p, data);
      }, index);

      if (data.l < 0) {
        // Don't continue to persist.
        return false;
      }
      return true;
    }, (data) => {
      debug('Removing particle ' + data._id);
      // When we delete a particle, we should remove it from our emitter.
      assert(data._id in this.idToIndex_, 'Attempting to remove a particle ' + data._id + ' that isn\'t in the index map!');
      var index = this.idToIndex_[data._id];
      this.emitter.removeParticle(index);
      delete this.idToIndex_[data._id];
    });

    this.emitter.markBuffersDirty();

    this.surface.render();

    // Generate debug info.
    // C: x, y, connection.id
    if (false) {
      var debugText = [(time/1000).toFixed(2)];

      debugText = debugText.concat(this.persistence_.clients.map((client) => {
        return ['C:', client.x + ',' + client.y, client.conn.id].join(' ');
      }));

      // P: index x,y,_index oldStatus newStatus
      debugText = debugText.concat(
        _(this.persistence_.data_)
            .sortBy((data) => data.l, true)
            .map((data) => {
          var x = (data.x >= 0 ? '+' : '') + data.x.toFixed(2);
          var y = (data.y >= 0 ? '+' : '') + data.y.toFixed(2);
          var l = (data.l >= 0 ? '+' : '') + data.l.toFixed(2);
          return ['P:', data._id, x + ',' + y, l, this.idToIndex_[data._id], data._status].join(' ');
        }));

      this.drawDebugText(_.flatten(debugText));
    }
  }
  drawDebugText(linesOfText) {
    this.debugCanvas.context.clearRect(
        0, 0, this.surface.virtualRect.w, this.surface.virtualRect.h);
    this.debugCanvas.context.fillStyle = 'white';
    this.debugCanvas.context.textAlign = 'left';
    var fontHeight = 32;
    this.debugCanvas.context.font = fontHeight + 'px monospace';
    this.debugCanvas.context.textBaseline = 'top';
    linesOfText.forEach((line, index) => {
      this.debugCanvas.context.fillText(line, 10, 10 + index * fontHeight);
    });
  }
}

register(ParticlesServer, ParticlesClient);
<commit_msg>RIP particles. ;( - Couldn't get it to work.<commit_after><|endoftext|>


<commit_before>import React from 'react';

// MATERIAL DESIGN
import Divider from '../../node_modules/material-ui/lib/divider';
import ListItem from '../../node_modules/material-ui/lib/lists/list-item';
import Avatar from '../../node_modules/material-ui/lib/avatar';
import PlayCircleOutline from 'material-ui/lib/svg-icons/av/play-circle-outline';

class StreamEntry extends React.Component {
  render() {
    console.log(this.props.stream)
    return (

        <ListItem
          onClick={this.props.goToStream.bind(this)}
          primaryText={this.props.stream.name}
          secondaryText={this.props.stream.broadcaster}
          leftAvatar={<Avatar src={this.props.stream.image} />}
          rightIcon={<PlayCircleOutline />} />
        <Divider />

    )
  }
}

export default StreamEntry;<commit_msg>Removed old diagnostic code.<commit_after>import React from 'react';

// MATERIAL DESIGN
import Divider from '../../node_modules/material-ui/lib/divider';
import ListItem from '../../node_modules/material-ui/lib/lists/list-item';
import Avatar from '../../node_modules/material-ui/lib/avatar';
import PlayCircleOutline from 'material-ui/lib/svg-icons/av/play-circle-outline';

class StreamEntry extends React.Component {
  render() {
    return (

        <ListItem
          onClick={this.props.goToStream.bind(this)}
          primaryText={this.props.stream.name}
          secondaryText={this.props.stream.broadcaster}
          leftAvatar={<Avatar src={this.props.stream.image} />}
          rightIcon={<PlayCircleOutline />} />
        <Divider />

    )
  }
}

export default StreamEntry;<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';

import APINotLoaded from 'es6!display/not_loaded';
import SectionHeader from 'es6!display/section_header';
import { AjaxError } from 'es6!display/errors';
import { ChangesPage, APINotLoadedPage } from 'es6!display/page_chrome';
import { Grid, GridRow } from 'es6!display/grid';
import { Tabs, MenuUtils } from 'es6!display/menus';
import { TestDetails } from 'es6!display/changes/test_details';

import InteractiveData from 'es6!pages/helpers/interactive_data';

import * as api from 'es6!server/api';

import * as utils from 'es6!utils/utils';

var BuildTestsPage = React.createClass({

  menuItems: [
    'Sharding',
    'Not Passing Tests',
    'Slow Tests',
    'Retries'
  ],

  getInitialState: function() {
    return {
      selectedItem: null, // set in componentWillMount

      // Not Passing tab
      expandedTests: {},  // expand for more details
      uncheckedResults: {},  // checkboxes to filter by statuses

      // Retries tab
      expandedRetryTests: {},
    }
  },

  componentWillMount: function() {
    var selectedItemFromHash = MenuUtils.selectItemFromHash(
      window.location.hash, this.menuItems);

    // when we first came to this page, which tab was shown? Used by the
    // initial data fetching within tabs
    this.initialTab = selectedItemFromHash || 'Not Passing Tests';

    this.setState({ selectedItem: this.initialTab });

    this.setState({
      slowTests : InteractiveData(this,
        'slowTests',
        `/api/0/builds/${this.props.buildID}/tests/?sort=duration`),

      retries : InteractiveData(this,
        'retries',
        `/api/0/builds/${this.props.buildID}/tests/?sort=retries`),
    });
  },

  componentDidMount: function() {
    _.each([['slowTests', 'Slow Tests'], ['retries', 'Retries']], tabs => {
      var [stateKey, tabName] = tabs;
      var params = {};
      if (this.initialTab === tabName) {
        var params = InteractiveData.getParamsFromWindowUrl();
      }
      this.state[stateKey].initialize(params);
    });

    api.fetch(this, {
      buildInfo: `/api/0/builds/${this.props.buildID}`,
      failedTests: `/api/0/builds/${this.props.buildID}/tests/failures`
    });
  },

  render: function() {
    if (!api.isLoaded(this.state.buildInfo)) {
      return <APINotLoadedPage calls={this.state.buildInfo} />;
    }
    var buildInfo = this.state.buildInfo.getReturnedData();

    var title = `Tests for ${buildInfo.project.name} Build`
    utils.setPageTitle(title);

    // render menu
    var selectedItem = this.state.selectedItem;

    var menu = <Tabs
      items={this.menuItems}
      selectedItem={selectedItem}
      onClick={MenuUtils.onClick(this, selectedItem)}
    />;

    var content = null;
    switch (selectedItem) {
      case 'Sharding':
        content = <ShardingTab build={buildInfo} />;
        break;
      case 'Not Passing Tests':
        content = this.renderFailed();
        break;
      case 'Slow Tests':
        content = this.renderSlow();
        break;
      case 'Retries':
        content = this.renderRetries();
        break;
      default:
        throw 'unreachable';
    }

    return <ChangesPage highlight="Projects">
      <SectionHeader>{title}</SectionHeader>
      {menu}

{content}

    </ChangesPage>;
  },

  renderFailed: function() {
    if (!api.isLoaded(this.state.failedTests)) {
      return <APINotLoaded state={this.state.failedTests} />;
    }
    var failedTests = this.state.failedTests.getReturnedData();

    if (!failedTests) {
      return
No tests failed
;
    }

    var project_id = this.state.buildInfo.getReturnedData().project.id;

    var rows = [];
    _.each(failedTests, test => {
      // skip 'quarantined_passed' tests
      if (test.result.indexOf('passed') >= 0) {
        return;
      } else if (this.state.uncheckedResults[test.result]) {
        return;
      }

      var href = `/v2/project_test/${project_id}/${test.hash}`;

      var onClick = __ => {
        this.setState(
          utils.update_key_in_state_dict('expandedTests',
            test.test_id,
            !this.state.expandedTests[test.test_id])
        );
      };

      var expandLabel = !this.state.expandedTests[test.test_id] ?
        'Expand' : 'Collapse';

      var markup =

        {test.shortName} {expandLabel}

{test.name}

;

      var capitalizedResult = test.result.charAt(0).toUpperCase() +
        test.result.slice(1);

      var color = 'bluishGray';
      if (test.result.indexOf('failed') >= 0) {
        color = 'red';
      }

      rows.push([
        markup,
        {capitalizedResult},
        History,
      ]);

      if (this.state.expandedTests[test.test_id]) {
        rows.push(GridRow.oneItem(
          <TestDetails testID={test.test_id} />
        ));
      }
    });

    var tests_by_result = _.groupBy(failedTests, t => t.result);
    var result_markup = _.map(tests_by_result, (tests, result) => {
      // as above, skip 'quarantined_passed' tests
      if (result.indexOf('passed') >= 0) {
        return;
      }

      var sentence = utils.plural(tests.length, "test(s) " + result);
      // render the number ourselves
      var rest_of_words = _.rest(sentence.split(" ")).join(" ");

      var onClick = evt => {
        this.setState(
          utils.update_key_in_state_dict(
            'uncheckedResults',
            result,
            !this.state.uncheckedResults[result]
          )
        );
      };

      var isChecked = !this.state.uncheckedResults[result];

      return

          <input type="checkbox" checked={isChecked} onClick={onClick} />
          {tests.length}
          {" "}
          {rest_of_words}

;
    });

    return

      {result_markup}
      <Grid
        colnum={3}
        className="marginBottomM marginTopM"
        cellClasses={['wide', 'nowrap', 'nowrap']}
        data={rows}
        headers={['Name', 'Result', 'Links']}
      />

;
  },

  renderSlow: function() {
    var slowTestsInteractive = this.state.slowTests;

    // we want to update the window url whenever the user switches tabs
    slowTestsInteractive.updateWindowUrl();

    if (slowTestsInteractive.hasNotLoadedInitialData()) {
      return <APINotLoaded calls={slowTestsInteractive.getDataToShow()} />;
    }

    var slowTests = slowTestsInteractive.getDataToShow().getReturnedData();

    var rows = [];
    _.each(slowTests, test => {
      rows.push([
        test.name,
        test.duration
      ]);
    });

    var errorMessage = null;
    if (slowTestsInteractive.failedToLoadUpdatedData()) {
      errorMessage = <AjaxError response={slowTestsInteractive.getDataForErrorMessage().response} />;
    }
    var style = slowTestsInteractive.isLoadingUpdatedData() ? {opacity: 0.5} : null;

    var pagingLinks = slowTestsInteractive.getPagingLinks();

    return

      {errorMessage}
      <Grid
        colnum={2}
        className="marginBottomM marginTopM"
        data={rows}
        headers={['Name', 'Duration (ms)']}
      />

        {pagingLinks}

;
  },

  renderRetries: function() {
    var retriesInteractive = this.state.retries;

    // we want to update the window url whenever the user switches tabs
    retriesInteractive.updateWindowUrl();

    if (retriesInteractive.hasNotLoadedInitialData()) {
      return <APINotLoaded calls={retriesInteractive.getDataToShow()} />;
    }

    var retries = retriesInteractive.getDataToShow().getReturnedData();

    var rows = [];
    _.each(retries, test => {
      var onClick = __ => {
        this.setState(
          utils.update_key_in_state_dict('expandedRetryTests',
            test.id,
            !this.state.expandedRetryTests[test.id])
        );
      };

      var expandLabel = !this.state.expandedRetryTests[test.id] ?
        'Expand' : 'Collapse';

      var markup =

        {test.shortName} {expandLabel}

{test.name}

;

      rows.push([
        markup,
        test.numRetries
      ]);

      if (this.state.expandedRetryTests[test.id]) {
        if (!api.isLoaded(this.state.expandedRetryTestsData[test.id])) {
          rows.push(GridRow.oneItem(
            <TestDetails testID={test.id} />
          ));
        }
      }
    });

    var errorMessage = null;
    if (retriesInteractive.failedToLoadUpdatedData()) {
      errorMessage = <AjaxError response={retriesInteractive.getDataForErrorMessage().response} />;
    }
    var style = retriesInteractive.isLoadingUpdatedData() ? {opacity: 0.5} : null;

    var pagingLinks = retriesInteractive.getPagingLinks();

    return

      {errorMessage}
      <Grid
        colnum={2}
        className="marginBottomM marginTopM"
        data={rows}
        headers={['Name', 'Retries']}
      />

        {pagingLinks}

;
  },
});

var ShardingTab = React.createClass({

  getInitialState: function() {
    var jobPhases = {};
    _.each(this.props.build.jobs, j => {
      jobPhases[j.id] = null;
    });

    return {
      jobPhases: jobPhases,
      // TODO: move to parent...
      expandedShards: {}
    };
  },

  componentDidMount: function() {
    // phases/jobsteps info
    var jobIDs = _.map(this.props.build.jobs, j => j.id);

    var endpoint_map = {};
    _.each(jobIDs, id => {
      endpoint_map[id] = `/api/0/jobs/${id}/phases?test_counts=1`;
    });

    // TODO: don't refetch every time (cache on parent)
    api.fetchMap(this, 'jobPhases', endpoint_map);
  },

  render: function() {
    var build = this.props.build;
    var jobIDs = _.map(build.jobs, j => j.id);

    var phasesCalls = _.chain(this.state.jobPhases)
      .pick(jobIDs)
      .values().value();

    if (!api.allLoaded(phasesCalls)) {
      return <APINotLoaded calls={phasesCalls} />;
    }

    var markup = [];
    _.each(jobIDs, jobID => {
      var job = _.filter(build.jobs, j => j.id === jobID)[0];
      markup.push(<SectionHeader>{job.name}</SectionHeader>);
      var rows = [];
      _.each(this.state.jobPhases[jobID].getReturnedData(), phase => {
        _.each(phase.steps, step => {
          if (!step.data.weight) {
            return;
          }

          var onClick = evt => {
            this.setState(utils.update_key_in_state_dict(
              'expandedShards',
              step.node.name,
              !this.state.expandedShards[step.node.name]
            ));
          };

          var expandLabel = !this.state.expandedShards[step.node.name] ?
            'See Raw Data' : 'Collapse';

          rows.push([
            step.node && step.node.name,
            step.data.weight,
            step.data.tests.length,
            {expandLabel}
          ]);

          if (this.state.expandedShards[step.node.name]) {
            rows.push(GridRow.oneItem(

                {JSON.stringify(step.data, null, 2)}

            ));
          }

          rows.push(GridRow.oneItem(

              Files:

{step.data.tests.join("\n")}

          ));
        });
      });
      markup.push(
        <Grid
          colnum={4}
          headers={['Node', 'Shard Weight', 'File Count', 'Links']}
          cellClasses={['wide', 'nowrap', 'nowrap', 'nowrap']}
          data={rows}
        />
      );
    });

    return

        This is very much a work-in-progress

      {markup}

;
  }
});

export default BuildTestsPage;
<commit_msg>fix retry dashboard<commit_after>import React, { PropTypes } from 'react';

import APINotLoaded from 'es6!display/not_loaded';
import SectionHeader from 'es6!display/section_header';
import { AjaxError } from 'es6!display/errors';
import { ChangesPage, APINotLoadedPage } from 'es6!display/page_chrome';
import { Grid, GridRow } from 'es6!display/grid';
import { Tabs, MenuUtils } from 'es6!display/menus';
import { TestDetails } from 'es6!display/changes/test_details';

import InteractiveData from 'es6!pages/helpers/interactive_data';

import * as api from 'es6!server/api';

import * as utils from 'es6!utils/utils';

var BuildTestsPage = React.createClass({

  menuItems: [
    'Sharding',
    'Not Passing Tests',
    'Slow Tests',
    'Retries'
  ],

  getInitialState: function() {
    return {
      selectedItem: null, // set in componentWillMount

      // Not Passing tab
      expandedTests: {},  // expand for more details
      uncheckedResults: {},  // checkboxes to filter by statuses

      // Retries tab
      expandedRetryTests: {},
    }
  },

  componentWillMount: function() {
    var selectedItemFromHash = MenuUtils.selectItemFromHash(
      window.location.hash, this.menuItems);

    // when we first came to this page, which tab was shown? Used by the
    // initial data fetching within tabs
    this.initialTab = selectedItemFromHash || 'Not Passing Tests';

    this.setState({ selectedItem: this.initialTab });

    this.setState({
      slowTests : InteractiveData(this,
        'slowTests',
        `/api/0/builds/${this.props.buildID}/tests/?sort=duration`),

      retries : InteractiveData(this,
        'retries',
        `/api/0/builds/${this.props.buildID}/tests/?sort=retries`),
    });
  },

  componentDidMount: function() {
    _.each([['slowTests', 'Slow Tests'], ['retries', 'Retries']], tabs => {
      var [stateKey, tabName] = tabs;
      var params = {};
      if (this.initialTab === tabName) {
        var params = InteractiveData.getParamsFromWindowUrl();
      }
      this.state[stateKey].initialize(params);
    });

    api.fetch(this, {
      buildInfo: `/api/0/builds/${this.props.buildID}`,
      failedTests: `/api/0/builds/${this.props.buildID}/tests/failures`
    });
  },

  render: function() {
    if (!api.isLoaded(this.state.buildInfo)) {
      return <APINotLoadedPage calls={this.state.buildInfo} />;
    }
    var buildInfo = this.state.buildInfo.getReturnedData();

    var title = `Tests for ${buildInfo.project.name} Build`
    utils.setPageTitle(title);

    // render menu
    var selectedItem = this.state.selectedItem;

    var menu = <Tabs
      items={this.menuItems}
      selectedItem={selectedItem}
      onClick={MenuUtils.onClick(this, selectedItem)}
    />;

    var content = null;
    switch (selectedItem) {
      case 'Sharding':
        content = <ShardingTab build={buildInfo} />;
        break;
      case 'Not Passing Tests':
        content = this.renderFailed();
        break;
      case 'Slow Tests':
        content = this.renderSlow();
        break;
      case 'Retries':
        content = this.renderRetries();
        break;
      default:
        throw 'unreachable';
    }

    return <ChangesPage highlight="Projects">
      <SectionHeader>{title}</SectionHeader>
      {menu}

{content}

    </ChangesPage>;
  },

  renderFailed: function() {
    if (!api.isLoaded(this.state.failedTests)) {
      return <APINotLoaded state={this.state.failedTests} />;
    }
    var failedTests = this.state.failedTests.getReturnedData();

    if (!failedTests) {
      return
No tests failed
;
    }

    var project_id = this.state.buildInfo.getReturnedData().project.id;

    var rows = [];
    _.each(failedTests, test => {
      // skip 'quarantined_passed' tests
      if (test.result.indexOf('passed') >= 0) {
        return;
      } else if (this.state.uncheckedResults[test.result]) {
        return;
      }

      var href = `/v2/project_test/${project_id}/${test.hash}`;

      var onClick = __ => {
        this.setState(
          utils.update_key_in_state_dict('expandedTests',
            test.test_id,
            !this.state.expandedTests[test.test_id])
        );
      };

      var expandLabel = !this.state.expandedTests[test.test_id] ?
        'Expand' : 'Collapse';

      var markup =

        {test.shortName} {expandLabel}

{test.name}

;

      var capitalizedResult = test.result.charAt(0).toUpperCase() +
        test.result.slice(1);

      var color = 'bluishGray';
      if (test.result.indexOf('failed') >= 0) {
        color = 'red';
      }

      rows.push([
        markup,
        {capitalizedResult},
        History,
      ]);

      if (this.state.expandedTests[test.test_id]) {
        rows.push(GridRow.oneItem(
          <TestDetails testID={test.test_id} />
        ));
      }
    });

    var tests_by_result = _.groupBy(failedTests, t => t.result);
    var result_markup = _.map(tests_by_result, (tests, result) => {
      // as above, skip 'quarantined_passed' tests
      if (result.indexOf('passed') >= 0) {
        return;
      }

      var sentence = utils.plural(tests.length, "test(s) " + result);
      // render the number ourselves
      var rest_of_words = _.rest(sentence.split(" ")).join(" ");

      var onClick = evt => {
        this.setState(
          utils.update_key_in_state_dict(
            'uncheckedResults',
            result,
            !this.state.uncheckedResults[result]
          )
        );
      };

      var isChecked = !this.state.uncheckedResults[result];

      return

          <input type="checkbox" checked={isChecked} onClick={onClick} />
          {tests.length}
          {" "}
          {rest_of_words}

;
    });

    return

      {result_markup}
      <Grid
        colnum={3}
        className="marginBottomM marginTopM"
        cellClasses={['wide', 'nowrap', 'nowrap']}
        data={rows}
        headers={['Name', 'Result', 'Links']}
      />

;
  },

  renderSlow: function() {
    var slowTestsInteractive = this.state.slowTests;

    // we want to update the window url whenever the user switches tabs
    slowTestsInteractive.updateWindowUrl();

    if (slowTestsInteractive.hasNotLoadedInitialData()) {
      return <APINotLoaded calls={slowTestsInteractive.getDataToShow()} />;
    }

    var slowTests = slowTestsInteractive.getDataToShow().getReturnedData();

    var rows = [];
    _.each(slowTests, test => {
      rows.push([
        test.name,
        test.duration
      ]);
    });

    var errorMessage = null;
    if (slowTestsInteractive.failedToLoadUpdatedData()) {
      errorMessage = <AjaxError response={slowTestsInteractive.getDataForErrorMessage().response} />;
    }
    var style = slowTestsInteractive.isLoadingUpdatedData() ? {opacity: 0.5} : null;

    var pagingLinks = slowTestsInteractive.getPagingLinks();

    return

      {errorMessage}
      <Grid
        colnum={2}
        className="marginBottomM marginTopM"
        data={rows}
        headers={['Name', 'Duration (ms)']}
      />

        {pagingLinks}

;
  },

  renderRetries: function() {
    var retriesInteractive = this.state.retries;

    // we want to update the window url whenever the user switches tabs
    retriesInteractive.updateWindowUrl();

    if (retriesInteractive.hasNotLoadedInitialData()) {
      return <APINotLoaded calls={retriesInteractive.getDataToShow()} />;
    }

    var retries = retriesInteractive.getDataToShow().getReturnedData();

    var rows = [];
    _.each(retries, test => {
      var onClick = __ => {
        this.setState(
          utils.update_key_in_state_dict('expandedRetryTests',
            test.id,
            !this.state.expandedRetryTests[test.id])
        );
      };

      var expandLabel = !this.state.expandedRetryTests[test.id] ?
        'Expand' : 'Collapse';

      var markup =

        {test.shortName} {expandLabel}

{test.name}

;

      rows.push([
        markup,
        test.numRetries
      ]);

      if (this.state.expandedRetryTests[test.id]) {
        rows.push(GridRow.oneItem(
          <TestDetails testID={test.id} />
        ));
      }
    });

    var errorMessage = null;
    if (retriesInteractive.failedToLoadUpdatedData()) {
      errorMessage = <AjaxError response={retriesInteractive.getDataForErrorMessage().response} />;
    }
    var style = retriesInteractive.isLoadingUpdatedData() ? {opacity: 0.5} : null;

    var pagingLinks = retriesInteractive.getPagingLinks();

    return

      {errorMessage}
      <Grid
        colnum={2}
        className="marginBottomM marginTopM"
        data={rows}
        headers={['Name', 'Retries']}
      />

        {pagingLinks}

;
  },
});

var ShardingTab = React.createClass({

  getInitialState: function() {
    var jobPhases = {};
    _.each(this.props.build.jobs, j => {
      jobPhases[j.id] = null;
    });

    return {
      jobPhases: jobPhases,
      // TODO: move to parent...
      expandedShards: {}
    };
  },

  componentDidMount: function() {
    // phases/jobsteps info
    var jobIDs = _.map(this.props.build.jobs, j => j.id);

    var endpoint_map = {};
    _.each(jobIDs, id => {
      endpoint_map[id] = `/api/0/jobs/${id}/phases?test_counts=1`;
    });

    // TODO: don't refetch every time (cache on parent)
    api.fetchMap(this, 'jobPhases', endpoint_map);
  },

  render: function() {
    var build = this.props.build;
    var jobIDs = _.map(build.jobs, j => j.id);

    var phasesCalls = _.chain(this.state.jobPhases)
      .pick(jobIDs)
      .values().value();

    if (!api.allLoaded(phasesCalls)) {
      return <APINotLoaded calls={phasesCalls} />;
    }

    var markup = [];
    _.each(jobIDs, jobID => {
      var job = _.filter(build.jobs, j => j.id === jobID)[0];
      markup.push(<SectionHeader>{job.name}</SectionHeader>);
      var rows = [];
      _.each(this.state.jobPhases[jobID].getReturnedData(), phase => {
        _.each(phase.steps, step => {
          if (!step.data.weight) {
            return;
          }

          var onClick = evt => {
            this.setState(utils.update_key_in_state_dict(
              'expandedShards',
              step.node.name,
              !this.state.expandedShards[step.node.name]
            ));
          };

          var expandLabel = !this.state.expandedShards[step.node.name] ?
            'See Raw Data' : 'Collapse';

          rows.push([
            step.node && step.node.name,
            step.data.weight,
            step.data.tests.length,
            {expandLabel}
          ]);

          if (this.state.expandedShards[step.node.name]) {
            rows.push(GridRow.oneItem(

                {JSON.stringify(step.data, null, 2)}

            ));
          }

          rows.push(GridRow.oneItem(

              Files:

{step.data.tests.join("\n")}

          ));
        });
      });
      markup.push(
        <Grid
          colnum={4}
          headers={['Node', 'Shard Weight', 'File Count', 'Links']}
          cellClasses={['wide', 'nowrap', 'nowrap', 'nowrap']}
          data={rows}
        />
      );
    });

    return

        This is very much a work-in-progress

      {markup}

;
  }
});

export default BuildTestsPage;
<|endoftext|>